diff --git a/frontend/index.html b/frontend/index.html
index 9cfe985..a71200a 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -57,6 +57,7 @@
image-rendering: auto;
}
+ /* ── Base tab styles ── */
.tab {
display: inline-flex;
align-items: center;
@@ -68,68 +69,71 @@
min-width: 100px;
height: 36px;
transition: background 0.15s;
- /* Default: Firefox inactive tab style */
- border-radius: 4px;
border: none;
- margin: 0 1px;
background: transparent;
}
- .tab:hover {
- background: var(--tab-hover);
- border-radius: 4px;
+ /* ── Linux Firefox (default) ── */
+ /* Inactive: transparent, small margin, rounded */
+ .tab {
+ border-radius: 6px;
+ margin: 0 1px;
}
- /* Firefox selected tab — solid bg, rounded top, connects to content below */
- .browser-firefox .tab-active,
- .browser-firefox .tab-active:hover {
+ /* Hover: pill-shaped background */
+ .tab:hover {
+ background: var(--tab-hover);
+ border-radius: 8px;
+ }
+
+ /* Selected: white bg, rounded top, connects to viewer below */
+ .tab-active,
+ .tab-active:hover {
background: var(--tab-bg);
border-radius: 8px 8px 0 0;
box-shadow: 0 1px 0 0 var(--tab-bg);
}
- /* Chrome / Chromium — inactive tabs: no bg, thin separators between */
+ /* ── Linux Chrome ── */
+ /* Inactive: always inset dimensions, separator via ::before */
.browser-chrome .tab {
- border-radius: 0;
- margin: 0;
- padding: 6px 14px;
- border-right: 1px solid var(--tab-border);
+ border-radius: 8px;
+ margin: 3px 2px;
+ padding: 3px 12px;
+ height: 30px;
+ position: relative;
}
+ .browser-chrome .tab::before {
+ content: "";
+ position: absolute;
+ left: -2px;
+ top: 25%;
+ height: 50%;
+ width: 1px;
+ background: var(--tab-border);
+ }
+
+ /* Hide separator on hover/active tab AND on the tab after hover/active */
+ .browser-chrome .tab:hover::before,
+ .browser-chrome .tab-active::before,
+ .browser-chrome .tab:hover + .tab::before,
+ .browser-chrome .tab-active + .tab::before {
+ background: transparent;
+ }
+
+ /* Hover: just add background (no layout change) */
.browser-chrome .tab:hover {
background: var(--tab-hover);
- border-radius: 8px 8px 0 0;
- border-right: 1px solid transparent;
}
- /* Chrome selected tab — raised, rounded top, solid bg */
+ /* Selected: white bg, subtle shadow */
.browser-chrome .tab-active,
.browser-chrome .tab-active:hover {
background: var(--tab-bg);
- border-radius: 10px 10px 0 0;
- border-right: 1px solid transparent;
box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.1);
}
- /* Safari — flat pill, very minimal */
- .browser-safari .tab {
- border-radius: 6px;
- margin: 0 2px;
- height: 32px;
- padding: 4px 10px;
- }
-
- .browser-safari .tab:hover {
- background: var(--tab-hover);
- }
-
- /* Safari selected tab — solid pill, slightly elevated */
- .browser-safari .tab-active,
- .browser-safari .tab-active:hover {
- background: var(--tab-bg);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
- }
-
.tab-about .tab-title {
font-weight: 600;
}
@@ -181,36 +185,69 @@
100% { transform: translateX(0); }
}
- /* Inline iframe viewer */
+ /* ── Inline iframe viewer ── */
.iframe-viewer {
width: 100%;
height: 75vh;
background: var(--viewer-bg);
- border-top: 2px solid var(--tab-border);
border-bottom: 2px solid var(--tab-border);
}
- .iframe-header {
+ /* Toolbar area (address bar) */
+ .iframe-toolbar {
display: flex;
align-items: center;
gap: 8px;
- padding: 6px 12px;
+ padding: 8px 12px;
background: var(--tab-bg);
}
- .iframe-header .tab-title {
+ /* URL bar — rounded pill, looks like a browser address bar */
+ .iframe-urlbar {
flex: 1;
- font-size: 13px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 16px;
+ background: var(--bg);
+ border-radius: 24px;
+ min-width: 0;
}
- .iframe-header a {
- color: var(--text-muted);
- font-size: 12px;
- text-decoration: none;
+ /* Firefox: more rectangular address bar */
+ .browser-firefox .iframe-urlbar {
+ border-radius: 8px;
}
- .iframe-header a:hover {
+ .iframe-urlbar .tab-icon {
+ flex-shrink: 0;
+ }
+
+ .iframe-urlbar .url-text {
+ font-size: 14px;
+ line-height: 1;
color: var(--text);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-decoration: none;
+ flex-shrink: 0;
+ }
+
+ .iframe-urlbar .url-text:hover {
+ text-decoration: underline;
+ }
+
+ .iframe-urlbar .url-title {
+ font-size: 12px;
+ line-height: 1;
+ color: var(--text-muted);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-align: right;
+ flex: 1;
+ min-width: 0;
}
.iframe-close {
@@ -219,8 +256,9 @@
color: var(--text);
font-size: 16px;
cursor: pointer;
- padding: 2px 6px;
- border-radius: 4px;
+ padding: 4px 8px;
+ border-radius: 50%;
+ line-height: 1;
}
.iframe-close:hover {
@@ -229,7 +267,7 @@
.iframe-viewer iframe {
width: 100%;
- height: calc(75vh - 36px);
+ height: calc(75vh - 56px);
border: none;
background: white;
}
diff --git a/frontend/site.js b/frontend/site.js
index 03d785d..b1dab7f 100644
--- a/frontend/site.js
+++ b/frontend/site.js
@@ -14,16 +14,26 @@ const loadedBundles = new Set();
const container = document.getElementById("tab-container");
const loadingEl = document.getElementById("loading");
-// Detect browser and set class on body for tab styling
+// Detect browser and OS, set classes on body for tab styling
function detectBrowser() {
const ua = navigator.userAgent;
if (ua.includes("Firefox")) return "firefox";
- if (ua.includes("Safari") && !ua.includes("Chrome")) return "safari";
+ if (ua.includes("Edg/")) return "edge";
+ if (ua.includes("Safari") && !ua.includes("Chrome") && !ua.includes("CriOS")) return "safari";
return "chrome"; // Chrome, Edge, Opera, Brave, etc.
}
+function detectOS() {
+ const ua = navigator.userAgent;
+ if (ua.includes("Windows")) return "windows";
+ if (ua.includes("Macintosh") || ua.includes("Mac OS")) return "mac";
+ if (ua.includes("iPhone") || ua.includes("iPad")) return "mac";
+ return "linux"; // Linux, Android, ChromeOS, unknown
+}
const browserName = detectBrowser();
-document.body.classList.add(`browser-${browserName}`);
+const osName = detectOS();
+document.body.classList.add(`browser-${browserName}`, `os-${osName}`);
const isFirefox = browserName === "firefox";
+console.log(`EveryTab: browser=${browserName}, os=${osName}`);
// How many tabs fit in one row?
function tabsPerRow() {
@@ -266,39 +276,47 @@ function openInlineViewer(tabEl, entry, url) {
const viewer = document.createElement("div");
viewer.className = "iframe-viewer";
- const header = document.createElement("div");
- header.className = "iframe-header";
+ // Toolbar (address bar area)
+ const toolbar = document.createElement("div");
+ toolbar.className = "iframe-toolbar";
+
+ // URL bar pill
+ const urlbar = document.createElement("div");
+ urlbar.className = "iframe-urlbar";
if (entry.icon) {
const icon = document.createElement("img");
icon.className = "tab-icon";
icon.src = `data:image/png;base64,${entry.icon}`;
- header.appendChild(icon);
+ urlbar.appendChild(icon);
}
- const title = document.createElement("span");
- title.className = "tab-title";
- title.textContent = entry.title || entry.url;
- header.appendChild(title);
-
const link = document.createElement("a");
+ link.className = "url-text";
link.href = url;
link.target = "_blank";
link.rel = "noopener";
- link.textContent = entry.url + " ↗";
- header.appendChild(link);
+ link.textContent = entry.url;
+ urlbar.appendChild(link);
+
+ const urlTitle = document.createElement("span");
+ urlTitle.className = "url-title";
+ urlTitle.textContent = entry.title || "";
+ urlbar.appendChild(urlTitle);
+
+ toolbar.appendChild(urlbar);
const close = document.createElement("button");
close.className = "iframe-close";
close.textContent = "✕";
close.addEventListener("click", closeInlineViewer);
- header.appendChild(close);
+ toolbar.appendChild(close);
const iframe = document.createElement("iframe");
iframe.sandbox = "allow-scripts allow-same-origin allow-forms";
iframe.src = url;
- viewer.appendChild(header);
+ viewer.appendChild(toolbar);
viewer.appendChild(iframe);
// Insert after the row