Files
meridian-os/js/apps/chrome.js

168 lines
7.1 KiB
JavaScript

// Chrome spoof — static-but-believable browser UI.
const TABS = [
{ title: 'New Tab', active: true },
{ title: 'Meridian Docs', active: false },
{ title: 'Search', active: false },
];
const SHORTCUTS = [
{ label: 'GitHub', url: 'https://github.com' },
{ label: 'Gmail', url: 'https://mail.google.com' },
{ label: 'YouTube', url: 'https://youtube.com' },
{ label: 'Maps', url: 'https://maps.google.com' },
{ label: 'Drive', url: 'https://drive.google.com' },
{ label: 'Calendar', url: 'https://calendar.google.com' },
{ label: 'Docs', url: 'https://docs.google.com' },
{ label: 'Translate', url: 'https://translate.google.com' },
];
export default {
id: 'chrome',
title: 'Chrome',
render(container, api) {
let activeTab = 0;
let navUrl = '';
const root = document.createElement('div');
root.style.cssText = 'height:100%;display:flex;flex-direction:column;background:var(--bg-1);';
// Tab strip
const tabStrip = document.createElement('div');
tabStrip.style.cssText = 'display:flex;background:var(--bg-2);border-bottom:1px solid var(--border);flex-shrink:0;overflow-x:auto;';
// New tab button
const newTabBtn = document.createElement('button');
newTabBtn.style.cssText = 'padding:8px 12px;font-size:16px;border:none;background:transparent;color:var(--text-dim);cursor:pointer;flex-shrink:0;';
newTabBtn.textContent = '+';
newTabBtn.addEventListener('click', () => {
const newIdx = TABS.length;
TABS.push({ title: 'New Tab', active: true });
TABS.forEach((t) => { t.active = false; });
TABS[newIdx].active = true;
activeTab = newIdx;
navUrl = '';
updateTabBar();
updateBody();
});
function updateTabBar() {
tabStrip.innerHTML = '';
TABS.forEach((tab, i) => {
const btn = document.createElement('button');
btn.style.cssText = 'padding:8px 16px;font-size:12px;border:none;background:transparent;color:' + (tab.active ? 'var(--text)' : 'var(--text-dim)') + ';border-right:1px solid var(--border);cursor:pointer;transition:color 150ms;max-width:180px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;';
btn.textContent = tab.title;
btn.addEventListener('click', () => {
activeTab = i;
navUrl = SHORTCUTS[i] ? SHORTCUTS[i].url : '';
updateTabBar();
updateBody();
});
tabStrip.appendChild(btn);
});
tabStrip.appendChild(newTabBtn);
}
updateTabBar();
root.appendChild(tabStrip);
// Address bar
const addrBar = document.createElement('div');
addrBar.style.cssText = 'display:flex;align-items:center;padding:6px 12px;gap:8px;background:var(--bg-2);border-bottom:1px solid var(--border);flex-shrink:0;';
const urlInput = document.createElement('input');
urlInput.type = 'text';
urlInput.value = navUrl || (SHORTCUTS[activeTab] ? SHORTCUTS[activeTab].url : '');
urlInput.style.cssText = 'flex:1;padding:6px 12px;background:var(--bg-3);border:1px solid var(--border);border-radius:20px;color:var(--text);font-size:13px;outline:none;';
urlInput.placeholder = 'Search or enter web address';
urlInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
const val = urlInput.value.trim();
if (val) {
navUrl = val;
updateBody();
}
}
});
const reloadBtn = document.createElement('button');
reloadBtn.style.cssText = 'padding:4px 8px;background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-size:14px;';
reloadBtn.textContent = '\u{21BB}';
reloadBtn.addEventListener('click', () => { updateBody(); });
addrBar.appendChild(urlInput);
addrBar.appendChild(reloadBtn);
root.appendChild(addrBar);
// Body
const body = document.createElement('div');
body.style.cssText = 'flex:1;overflow-y:auto;padding:40px 20px;background:var(--bg-1);';
function updateBody() {
body.innerHTML = '';
urlInput.value = navUrl || (TABS[activeTab].title === 'New Tab' ? '' : TABS[activeTab].title.toLowerCase().replace(/\s+/g, '-') + '.meridian.dev');
if (activeTab === 0 && !navUrl) {
// New tab page
const titleEl = document.createElement('h2');
titleEl.style.cssText = 'font-size:22px;font-weight:500;color:var(--text);margin-bottom:28px;text-align:center;';
titleEl.textContent = 'Meridian Browser';
body.appendChild(titleEl);
const grid = document.createElement('div');
grid.style.cssText = 'display:grid;grid-template-columns:repeat(4,1fr);gap:12px;max-width:600px;margin:0 auto;';
SHORTCUTS.forEach((sc) => {
const tile = document.createElement('div');
tile.style.cssText = 'padding:16px 12px;background:var(--bg-2);border:1px solid var(--border);border-radius:8px;text-align:center;cursor:pointer;transition:background 150ms;';
tile.addEventListener('mouseenter', () => { tile.style.background = 'var(--bg-3)'; });
tile.addEventListener('mouseleave', () => { tile.style.background = 'var(--bg-2)'; });
tile.addEventListener('click', () => {
navUrl = sc.url;
TABS[0].title = sc.label;
updateTabBar();
updateBody();
});
const tileIcon = document.createElement('div');
tileIcon.style.cssText = 'font-size:18px;font-weight:600;color:var(--accent);margin-bottom:4px;';
tileIcon.textContent = sc.label.charAt(0);
const tileLabel = document.createElement('div');
tileLabel.style.cssText = 'font-size:11px;color:var(--text-dim);';
tileLabel.textContent = sc.label;
tile.appendChild(tileIcon);
tile.appendChild(tileLabel);
grid.appendChild(tile);
});
body.appendChild(grid);
} else {
// Simulated page
const page = document.createElement('div');
page.style.cssText = 'max-width:600px;margin:0 auto;';
const heading = document.createElement('h2');
heading.style.cssText = 'font-size:22px;font-weight:500;color:var(--text);margin-bottom:12px;';
heading.textContent = 'Simulated page for ' + (navUrl || TABS[activeTab].title);
page.appendChild(heading);
const urlDisplay = document.createElement('div');
urlDisplay.style.cssText = 'font-size:12px;color:var(--text-dim);margin-bottom:24px;font-family:monospace;padding:8px 12px;background:var(--bg-2);border:1px solid var(--border);border-radius:4px;';
urlDisplay.textContent = navUrl || TABS[activeTab].title;
page.appendChild(urlDisplay);
const para = document.createElement('p');
para.style.cssText = 'font-size:14px;color:var(--text-dim);line-height:1.7;';
const displayUrl = navUrl || TABS[activeTab].title;
para.textContent = 'This is a simulated page for ' + displayUrl + '. Meridian Browser does not make actual network requests — it is a spoof. Nothing to see here unless you count the aesthetic choices.';
page.appendChild(para);
body.appendChild(page);
}
}
root.appendChild(body);
container.appendChild(root);
updateBody();
},
};