Bookmarks saved to json added
This commit is contained in:
+17
-1
@@ -1 +1,17 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"title": "Google",
|
||||||
|
"url": "https://www.google.com",
|
||||||
|
"icon": "search"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "GitHub",
|
||||||
|
"url": "https://github.com",
|
||||||
|
"icon": "code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "YouTube",
|
||||||
|
"url": "https://www.youtube.com",
|
||||||
|
"icon": "play_arrow"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -375,6 +375,53 @@ ipcMain.on('homepage-changed', (event, url) => {
|
|||||||
console.log('[MAIN] homepage-changed →', url);
|
console.log('[MAIN] homepage-changed →', url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bookmark management
|
||||||
|
ipcMain.handle('load-bookmarks', async () => {
|
||||||
|
try {
|
||||||
|
const bookmarksPath = path.join(__dirname, 'bookmarks.json');
|
||||||
|
if (fs.existsSync(bookmarksPath)) {
|
||||||
|
const data = fs.readFileSync(bookmarksPath, 'utf8');
|
||||||
|
const bookmarks = JSON.parse(data);
|
||||||
|
console.log(`Loaded ${bookmarks.length} bookmarks from file`);
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
console.log('No bookmarks file found, starting with empty array');
|
||||||
|
return [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading bookmarks:', error);
|
||||||
|
// Try to create a backup if the file is corrupted
|
||||||
|
const bookmarksPath = path.join(__dirname, 'bookmarks.json');
|
||||||
|
const backupPath = path.join(__dirname, `bookmarks.backup.${Date.now()}.json`);
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(bookmarksPath)) {
|
||||||
|
fs.copyFileSync(bookmarksPath, backupPath);
|
||||||
|
console.log(`Corrupted bookmarks file backed up to: ${backupPath}`);
|
||||||
|
}
|
||||||
|
} catch (backupError) {
|
||||||
|
console.error('Failed to create backup:', backupError);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('save-bookmarks', async (event, bookmarks) => {
|
||||||
|
try {
|
||||||
|
const bookmarksPath = path.join(__dirname, 'bookmarks.json');
|
||||||
|
|
||||||
|
// Create a backup before saving
|
||||||
|
if (fs.existsSync(bookmarksPath)) {
|
||||||
|
const backupPath = path.join(__dirname, 'bookmarks.backup.json');
|
||||||
|
fs.copyFileSync(bookmarksPath, backupPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(bookmarksPath, JSON.stringify(bookmarks, null, 2));
|
||||||
|
console.log(`Saved ${bookmarks.length} bookmarks to file`);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving bookmarks:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('clear-browser-data', async () => {
|
ipcMain.handle('clear-browser-data', async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ const electronAPI = {
|
|||||||
console.error('IPC send error:', err);
|
console.error('IPC send error:', err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Send message to embedding page (webview host)
|
||||||
|
sendToHost: (ch, ...args) => {
|
||||||
|
try {
|
||||||
|
return ipcRenderer.sendToHost(ch, ...args);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('IPC sendToHost error:', err);
|
||||||
|
}
|
||||||
|
},
|
||||||
invoke: (ch, ...args) => {
|
invoke: (ch, ...args) => {
|
||||||
try {
|
try {
|
||||||
return ipcRenderer.invoke(ch, ...args);
|
return ipcRenderer.invoke(ch, ...args);
|
||||||
|
|||||||
+47
-13
@@ -1,7 +1,5 @@
|
|||||||
import { icons as initialIcons, fetchAllIcons } from './icons.js';
|
import { icons as initialIcons, fetchAllIcons } from './icons.js';
|
||||||
|
|
||||||
const BOOKMARKS_KEY = 'steamos_browser_bookmarks';
|
|
||||||
|
|
||||||
const bookmarkList = document.getElementById('bookmarkList');
|
const bookmarkList = document.getElementById('bookmarkList');
|
||||||
const titleInput = document.getElementById('titleInput');
|
const titleInput = document.getElementById('titleInput');
|
||||||
const urlInput = document.getElementById('urlInput');
|
const urlInput = document.getElementById('urlInput');
|
||||||
@@ -26,18 +24,44 @@ const searchEngines = {
|
|||||||
};
|
};
|
||||||
let selectedSearchEngine = 'google';
|
let selectedSearchEngine = 'google';
|
||||||
|
|
||||||
let bookmarks = JSON.parse(localStorage.getItem(BOOKMARKS_KEY)) || [];
|
let bookmarks = [];
|
||||||
|
|
||||||
function saveBookmarks() {
|
// Load bookmarks from main via Electron IPC
|
||||||
localStorage.setItem(BOOKMARKS_KEY, JSON.stringify(bookmarks));
|
// Load bookmarks via contextBridge API
|
||||||
|
async function loadBookmarks() {
|
||||||
|
try {
|
||||||
|
let data = [];
|
||||||
|
// Use bookmarksAPI if available
|
||||||
|
if (window.bookmarksAPI && typeof window.bookmarksAPI.load === 'function') {
|
||||||
|
data = await window.bookmarksAPI.load();
|
||||||
|
} else if (window.electronAPI && typeof window.electronAPI.invoke === 'function') {
|
||||||
|
data = await window.electronAPI.invoke('load-bookmarks');
|
||||||
|
} else {
|
||||||
|
console.error('No API available to load bookmarks');
|
||||||
|
}
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading bookmarks:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save bookmarks to main process
|
||||||
|
// Save bookmarks via contextBridge API
|
||||||
|
async function saveBookmarks() {
|
||||||
|
try {
|
||||||
|
await window.bookmarksAPI.save(bookmarks);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving bookmarks:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render bookmarks
|
||||||
function renderBookmarks() {
|
function renderBookmarks() {
|
||||||
const list = JSON.parse(localStorage.getItem(BOOKMARKS_KEY) || '[]');
|
|
||||||
bookmarkList.innerHTML = '';
|
bookmarkList.innerHTML = '';
|
||||||
|
|
||||||
// Render each bookmark
|
// Render each bookmark
|
||||||
list.forEach((b, index) => {
|
bookmarks.forEach((b, index) => {
|
||||||
const box = document.createElement('div');
|
const box = document.createElement('div');
|
||||||
box.className = 'bookmark';
|
box.className = 'bookmark';
|
||||||
|
|
||||||
@@ -54,14 +78,21 @@ function renderBookmarks() {
|
|||||||
const close = document.createElement('button');
|
const close = document.createElement('button');
|
||||||
close.textContent = '×';
|
close.textContent = '×';
|
||||||
close.className = 'delete-btn';
|
close.className = 'delete-btn';
|
||||||
close.onclick = (e) => {
|
close.onclick = async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
bookmarks.splice(index, 1);
|
bookmarks.splice(index, 1);
|
||||||
saveBookmarks();
|
await saveBookmarks();
|
||||||
renderBookmarks();
|
renderBookmarks();
|
||||||
};
|
};
|
||||||
|
|
||||||
box.onclick = () => window.location.href = b.url;
|
// Navigate via IPC to host page
|
||||||
|
box.onclick = () => {
|
||||||
|
if (window.electronAPI && typeof window.electronAPI.sendToHost === 'function') {
|
||||||
|
window.electronAPI.sendToHost('navigate', b.url);
|
||||||
|
} else {
|
||||||
|
console.error('Unable to send navigation IPC to host');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
box.appendChild(label);
|
box.appendChild(label);
|
||||||
box.appendChild(close);
|
box.appendChild(close);
|
||||||
@@ -121,14 +152,14 @@ renderIconGrid();
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
saveBookmarkBtn.onclick = () => {
|
saveBookmarkBtn.onclick = async () => {
|
||||||
const title = titleInput.value.trim();
|
const title = titleInput.value.trim();
|
||||||
const url = urlInput.value.trim();
|
const url = urlInput.value.trim();
|
||||||
const icon = selectedIcon;
|
const icon = selectedIcon;
|
||||||
if (!title || !url) return;
|
if (!title || !url) return;
|
||||||
|
|
||||||
bookmarks.push({ title, url, icon });
|
bookmarks.push({ title, url, icon });
|
||||||
saveBookmarks();
|
await saveBookmarks();
|
||||||
renderBookmarks();
|
renderBookmarks();
|
||||||
|
|
||||||
titleInput.value = '';
|
titleInput.value = '';
|
||||||
@@ -181,5 +212,8 @@ searchInput.addEventListener('keydown', e => {
|
|||||||
if (e.key === 'Enter') searchBtn.click();
|
if (e.key === 'Enter') searchBtn.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
// initial render from localStorage
|
// Load and render bookmarks immediately
|
||||||
|
(async () => {
|
||||||
|
bookmarks = await loadBookmarks();
|
||||||
renderBookmarks();
|
renderBookmarks();
|
||||||
|
})();
|
||||||
|
|||||||
+11
-17
@@ -56,25 +56,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="webviews">
|
<div id="webviews" class="hidden"></div>
|
||||||
<webview id="webview" src="https://example.com"></webview>
|
|
||||||
|
<!-- Home page container for direct loading -->
|
||||||
|
<div id="home-container" class="active">
|
||||||
|
<webview id="home-webview"
|
||||||
|
src="home.html"
|
||||||
|
preload="../preload.js"
|
||||||
|
partition="persist:default"
|
||||||
|
allowpopups
|
||||||
|
style="width:100%; height:100%; border:none;">
|
||||||
|
</webview>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
<script>
|
|
||||||
const { ipcRenderer } = require('electron');
|
|
||||||
const webview = document.getElementById('webview');
|
|
||||||
|
|
||||||
webview.addEventListener('did-navigate', (e) => {
|
|
||||||
// save site URL
|
|
||||||
ipcRenderer.invoke('save-site-history', e.url);
|
|
||||||
// extract search query if present
|
|
||||||
const m = /[?&](?:q|query)=([^&]+)/.exec(e.url);
|
|
||||||
if (m && m[1]) {
|
|
||||||
const query = decodeURIComponent(m[1].replace(/\+/g, ' '));
|
|
||||||
ipcRenderer.invoke('save-search-history', query);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+181
-6
@@ -53,6 +53,34 @@ let activeTabId = null;
|
|||||||
const allowedInternalPages = ['settings', 'home'];
|
const allowedInternalPages = ['settings', 'home'];
|
||||||
let bookmarks = [];
|
let bookmarks = [];
|
||||||
|
|
||||||
|
// Load bookmarks on startup
|
||||||
|
async function loadBookmarks() {
|
||||||
|
try {
|
||||||
|
bookmarks = await ipcRenderer.invoke('load-bookmarks');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading bookmarks in main context:', error);
|
||||||
|
bookmarks = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to save bookmarks
|
||||||
|
async function saveBookmarks(newBookmarks) {
|
||||||
|
try {
|
||||||
|
bookmarks = newBookmarks;
|
||||||
|
await ipcRenderer.invoke('save-bookmarks', bookmarks);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving bookmarks in main context:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load bookmarks when the script starts
|
||||||
|
loadBookmarks();
|
||||||
|
|
||||||
|
// Create initial home tab on startup
|
||||||
|
createTab();
|
||||||
|
|
||||||
|
// Remove iframe-based navigation listener (using webview IPC now)
|
||||||
|
|
||||||
// Listen for site history updates from main process
|
// Listen for site history updates from main process
|
||||||
ipcRenderer.on('record-site-history', (event, url) => {
|
ipcRenderer.on('record-site-history', (event, url) => {
|
||||||
console.log('[DEBUG] Received site history update:', url);
|
console.log('[DEBUG] Received site history update:', url);
|
||||||
@@ -63,6 +91,29 @@ function createTab(inputUrl) {
|
|||||||
inputUrl = inputUrl || 'browser://home';
|
inputUrl = inputUrl || 'browser://home';
|
||||||
console.log('[DEBUG] createTab() inputUrl =', inputUrl);
|
console.log('[DEBUG] createTab() inputUrl =', inputUrl);
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
|
|
||||||
|
// Handle home page specially
|
||||||
|
if (inputUrl === 'browser://home') {
|
||||||
|
// Show home container and hide webviews
|
||||||
|
const homeContainer = document.getElementById('home-container');
|
||||||
|
const webviewsEl = document.getElementById('webviews');
|
||||||
|
if (homeContainer) homeContainer.classList.add('active');
|
||||||
|
if (webviewsEl) webviewsEl.classList.add('hidden');
|
||||||
|
const tab = {
|
||||||
|
id,
|
||||||
|
url: inputUrl,
|
||||||
|
title: 'New Tab',
|
||||||
|
favicon: '',
|
||||||
|
history: [inputUrl],
|
||||||
|
historyIndex: 0,
|
||||||
|
isHome: true
|
||||||
|
};
|
||||||
|
tabs.push(tab);
|
||||||
|
setActiveTab(id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For all other URLs, use webview
|
||||||
const resolvedUrl = resolveInternalUrl(inputUrl);
|
const resolvedUrl = resolveInternalUrl(inputUrl);
|
||||||
console.log('[DEBUG] createTab() resolvedUrl =', resolvedUrl);
|
console.log('[DEBUG] createTab() resolvedUrl =', resolvedUrl);
|
||||||
|
|
||||||
@@ -72,6 +123,7 @@ function createTab(inputUrl) {
|
|||||||
webview.src = resolvedUrl;
|
webview.src = resolvedUrl;
|
||||||
webview.setAttribute('allowpopups', '');
|
webview.setAttribute('allowpopups', '');
|
||||||
webview.setAttribute('partition', 'persist:default');
|
webview.setAttribute('partition', 'persist:default');
|
||||||
|
webview.setAttribute('preload', '../preload.js');
|
||||||
webview.classList.add('active');
|
webview.classList.add('active');
|
||||||
|
|
||||||
webview.addEventListener('did-fail-load', handleLoadFail(id));
|
webview.addEventListener('did-fail-load', handleLoadFail(id));
|
||||||
@@ -80,6 +132,20 @@ function createTab(inputUrl) {
|
|||||||
if (e.favicons.length > 0) updateTabMetadata(id, 'favicon', e.favicons[0]);
|
if (e.favicons.length > 0) updateTabMetadata(id, 'favicon', e.favicons[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Send bookmarks to home page when it loads
|
||||||
|
webview.addEventListener('dom-ready', () => {
|
||||||
|
if (inputUrl === 'browser://home') {
|
||||||
|
webview.executeJavaScript(`
|
||||||
|
if (window.receiveBookmarks) {
|
||||||
|
window.receiveBookmarks(${JSON.stringify(bookmarks)});
|
||||||
|
} else {
|
||||||
|
// Store bookmarks for when the page script loads
|
||||||
|
window._pendingBookmarks = ${JSON.stringify(bookmarks)};
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Consolidated navigation recording - only use did-navigate to avoid duplicates
|
// Consolidated navigation recording - only use did-navigate to avoid duplicates
|
||||||
webview.addEventListener('did-navigate', e => {
|
webview.addEventListener('did-navigate', e => {
|
||||||
handleNavigation(id, e.url);
|
handleNavigation(id, e.url);
|
||||||
@@ -169,8 +235,7 @@ function updateTabMetadata(id, key, value) {
|
|||||||
function navigate() {
|
function navigate() {
|
||||||
const input = urlBox.value.trim();
|
const input = urlBox.value.trim();
|
||||||
const tab = tabs.find(t => t.id === activeTabId);
|
const tab = tabs.find(t => t.id === activeTabId);
|
||||||
const webview = document.getElementById(`tab-${activeTabId}`);
|
if (!tab) return;
|
||||||
if (!tab || !webview) return;
|
|
||||||
|
|
||||||
// decide if this is a search query or a URL/internal page
|
// decide if this is a search query or a URL/internal page
|
||||||
const hasProtocol = /^https?:\/\//i.test(input);
|
const hasProtocol = /^https?:\/\//i.test(input);
|
||||||
@@ -183,6 +248,18 @@ function navigate() {
|
|||||||
resolved = resolveInternalUrl(input);
|
resolved = resolveInternalUrl(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If current tab is a home tab and we're navigating to a website,
|
||||||
|
// we need to convert it to a webview tab or create a new one
|
||||||
|
if (tab.isHome && !input.startsWith('browser://')) {
|
||||||
|
// Convert home tab to webview tab
|
||||||
|
convertHomeTabToWebview(tab.id, input, resolved);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For regular webview tabs, just navigate
|
||||||
|
const webview = document.getElementById(`tab-${activeTabId}`);
|
||||||
|
if (!webview) return;
|
||||||
|
|
||||||
// Push to history using the original input
|
// Push to history using the original input
|
||||||
tab.history = tab.history.slice(0, tab.historyIndex + 1);
|
tab.history = tab.history.slice(0, tab.historyIndex + 1);
|
||||||
tab.history.push(input);
|
tab.history.push(input);
|
||||||
@@ -195,6 +272,75 @@ function navigate() {
|
|||||||
updateNavButtons();
|
updateNavButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertHomeTabToWebview(tabId, inputUrl, resolvedUrl) {
|
||||||
|
const tab = tabs.find(t => t.id === tabId);
|
||||||
|
if (!tab) return;
|
||||||
|
|
||||||
|
// Create a new webview for this tab
|
||||||
|
const webview = document.createElement('webview');
|
||||||
|
webview.id = `tab-${tabId}`;
|
||||||
|
webview.src = resolvedUrl;
|
||||||
|
webview.setAttribute('allowpopups', '');
|
||||||
|
webview.setAttribute('partition', 'persist:default');
|
||||||
|
webview.setAttribute('preload', '../preload.js');
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
webview.addEventListener('did-fail-load', handleLoadFail(tabId));
|
||||||
|
webview.addEventListener('page-title-updated', e => updateTabMetadata(tabId, 'title', e.title));
|
||||||
|
webview.addEventListener('page-favicon-updated', e => {
|
||||||
|
if (e.favicons.length > 0) updateTabMetadata(tabId, 'favicon', e.favicons[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
webview.addEventListener('did-navigate', e => {
|
||||||
|
handleNavigation(tabId, e.url);
|
||||||
|
if (e.url.startsWith('http')) {
|
||||||
|
addToSiteHistory(e.url);
|
||||||
|
ipcRenderer.invoke('save-site-history-entry', e.url).catch(err =>
|
||||||
|
console.error('Failed to save to file:', err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
webview.addEventListener('did-navigate-in-page', e => {
|
||||||
|
handleNavigation(tabId, e.url);
|
||||||
|
if (e.url.startsWith('http')) {
|
||||||
|
addToSiteHistory(e.url);
|
||||||
|
ipcRenderer.invoke('save-site-history-entry', e.url).catch(err =>
|
||||||
|
console.error('Failed to save to file:', err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
webview.addEventListener('did-finish-load', () => {
|
||||||
|
const currentUrl = webview.getURL();
|
||||||
|
if (currentUrl.startsWith('http') && !currentUrl.includes('browser://')) {
|
||||||
|
addToSiteHistory(currentUrl);
|
||||||
|
ipcRenderer.invoke('save-site-history-entry', currentUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
webview.addEventListener('new-window', e => {
|
||||||
|
createTab(e.url);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add webview to DOM
|
||||||
|
webviewsEl.appendChild(webview);
|
||||||
|
|
||||||
|
// Update tab properties
|
||||||
|
tab.isHome = false;
|
||||||
|
tab.webview = webview;
|
||||||
|
tab.url = inputUrl;
|
||||||
|
tab.history = [inputUrl];
|
||||||
|
tab.historyIndex = 0;
|
||||||
|
|
||||||
|
// Hide home container and show webview
|
||||||
|
const homeContainer = document.getElementById('home-container');
|
||||||
|
if (homeContainer) homeContainer.classList.remove('active');
|
||||||
|
webview.classList.add('active');
|
||||||
|
|
||||||
|
updateNavButtons();
|
||||||
|
}
|
||||||
|
|
||||||
function handleNavigation(tabId, newUrl) {
|
function handleNavigation(tabId, newUrl) {
|
||||||
const tab = tabs.find(t => t.id === tabId);
|
const tab = tabs.find(t => t.id === tabId);
|
||||||
if (!tab) return;
|
if (!tab) return;
|
||||||
@@ -241,17 +387,30 @@ function handleNavigation(tabId, newUrl) {
|
|||||||
|
|
||||||
|
|
||||||
function setActiveTab(id) {
|
function setActiveTab(id) {
|
||||||
|
// hide all individual webviews
|
||||||
tabs.forEach(t => {
|
tabs.forEach(t => {
|
||||||
const w = document.getElementById(`tab-${t.id}`);
|
const w = document.getElementById(`tab-${t.id}`);
|
||||||
if (w) w.classList.remove('active');
|
if (w) w.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
// toggle containers
|
||||||
|
const homeContainer = document.getElementById('home-container');
|
||||||
|
const webviewsEl = document.getElementById('webviews');
|
||||||
|
|
||||||
|
const tab = tabs.find(t => t.id === id);
|
||||||
|
if (tab) {
|
||||||
|
if (tab.isHome) {
|
||||||
|
homeContainer.classList.add('active');
|
||||||
|
webviewsEl.classList.add('hidden');
|
||||||
|
} else {
|
||||||
|
if (homeContainer) homeContainer.classList.remove('active');
|
||||||
|
webviewsEl.classList.remove('hidden');
|
||||||
const activeWebview = document.getElementById(`tab-${id}`);
|
const activeWebview = document.getElementById(`tab-${id}`);
|
||||||
if (activeWebview) activeWebview.classList.add('active');
|
if (activeWebview) activeWebview.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
activeTabId = id;
|
activeTabId = id;
|
||||||
|
|
||||||
const tab = tabs.find(t => t.id === id);
|
|
||||||
if (tab) {
|
if (tab) {
|
||||||
// If the tab URL represents the home page, keep the URL bar blank.
|
// If the tab URL represents the home page, keep the URL bar blank.
|
||||||
urlBox.value = tab.url === 'browser://home' ? '' : tab.url;
|
urlBox.value = tab.url === 'browser://home' ? '' : tab.url;
|
||||||
@@ -399,6 +558,16 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createTab();
|
createTab();
|
||||||
|
// Listen for navigation IPC messages from home webview
|
||||||
|
const homeWebview = document.getElementById('home-webview');
|
||||||
|
if (homeWebview) {
|
||||||
|
homeWebview.addEventListener('ipc-message', e => {
|
||||||
|
if (e.channel === 'navigate' && e.args[0]) {
|
||||||
|
urlBox.value = e.args[0];
|
||||||
|
navigate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
// only now bind the reload button (guaranteed to exist)
|
// only now bind the reload button (guaranteed to exist)
|
||||||
const reloadBtn = document.getElementById('reload-btn');
|
const reloadBtn = document.getElementById('reload-btn');
|
||||||
reloadBtn.addEventListener('click', reload);
|
reloadBtn.addEventListener('click', reload);
|
||||||
@@ -435,7 +604,7 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// menu‐related code (moved here so #context-menu exists)
|
// menu‐related code (moved here so #context-menu exists)
|
||||||
const items = menu ? menu.querySelectorAll('li') : [];
|
const items = contextMenu ? contextMenu.querySelectorAll('li') : [];
|
||||||
|
|
||||||
function showContextMenu(x, y) {
|
function showContextMenu(x, y) {
|
||||||
if (!menu) return;
|
if (!menu) return;
|
||||||
@@ -531,8 +700,14 @@ function updateZoomUI() {
|
|||||||
function zoomIn() { ipcRenderer.invoke('zoom-in').then(updateZoomUI); }
|
function zoomIn() { ipcRenderer.invoke('zoom-in').then(updateZoomUI); }
|
||||||
function zoomOut() { ipcRenderer.invoke('zoom-out').then(updateZoomUI); }
|
function zoomOut() { ipcRenderer.invoke('zoom-out').then(updateZoomUI); }
|
||||||
|
|
||||||
const fs = require('fs');
|
// Attempt to load Node modules if available for context-menu actions
|
||||||
const { remote } = require('electron');
|
let fs, remote;
|
||||||
|
try {
|
||||||
|
fs = require('fs');
|
||||||
|
remote = require('electron').remote;
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('fs or remote modules unavailable in renderer:', err);
|
||||||
|
}
|
||||||
|
|
||||||
// 4) unify context-menu wiring
|
// 4) unify context-menu wiring
|
||||||
function showContextMenu(x,y) {
|
function showContextMenu(x,y) {
|
||||||
|
|||||||
+32
-2
@@ -130,14 +130,44 @@ html, body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
#webviews.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
#webviews webview {
|
#webviews webview {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: none;
|
|
||||||
border: none;
|
border: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#webviews webview.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
/* When webviews is hidden, collapse its flex size */
|
||||||
|
#webviews.hidden {
|
||||||
|
flex: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webviews webview.active {
|
/* HOME CONTAINER */
|
||||||
|
#home-container {
|
||||||
|
flex: 1;
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-container.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-webview {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
display: none;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
/* Show home webview when container is active */
|
||||||
|
#home-container.active > #home-webview {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -1,10 +1,19 @@
|
|||||||
[
|
[
|
||||||
|
"https://www.youtube.com/",
|
||||||
|
"https://github.com/",
|
||||||
|
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
||||||
|
"https://youtube.com/",
|
||||||
|
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
||||||
|
"https://youtube.com/",
|
||||||
|
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
||||||
|
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
||||||
|
"https://www.google.com/",
|
||||||
|
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
||||||
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
"file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",
|
||||||
"file:///Users/andrewzambazos/Repositories/NebulaBrowser/renderer/index.html",
|
"file:///Users/andrewzambazos/Repositories/NebulaBrowser/renderer/index.html",
|
||||||
"https://inscribe.zambazosmedia.group/renderer/editor.html",
|
"https://inscribe.zambazosmedia.group/renderer/editor.html",
|
||||||
"https://inscribe.zambazosmedia.group/",
|
"https://inscribe.zambazosmedia.group/",
|
||||||
"file:///Users/andrewzambazos/Repositories/NebulaBrowser/renderer/index.html",
|
"file:///Users/andrewzambazos/Repositories/NebulaBrowser/renderer/index.html",
|
||||||
"https://www.youtube.com/",
|
|
||||||
"https://www.youtube.com/watch?v=9FuNtfsnRNo",
|
"https://www.youtube.com/watch?v=9FuNtfsnRNo",
|
||||||
"https://youtube.com/",
|
"https://youtube.com/",
|
||||||
"http://homelab.andrewzambazos.com:8081/",
|
"http://homelab.andrewzambazos.com:8081/",
|
||||||
|
|||||||
Reference in New Issue
Block a user