diff --git a/extension/entrypoints/options/App.tsx b/extension/entrypoints/options/App.tsx index 536788e..76e9300 100644 --- a/extension/entrypoints/options/App.tsx +++ b/extension/entrypoints/options/App.tsx @@ -26,11 +26,11 @@ function AturiMark() { ); } -const TABS: { id: TabId; label: string; sub: string }[] = [ - { id: 'defaults', label: 'General', sub: 'Auto-redirect & popup' }, - { id: 'visibility', label: 'Waypoints', sub: 'Hide or show apps' }, - { id: 'custom', label: 'Custom waypoints', sub: 'Add your own sites' }, - { id: 'about', label: 'About', sub: 'Project, credits, feedback' }, +const TABS: { id: TabId; label: string }[] = [ + { id: 'defaults', label: 'General' }, + { id: 'visibility', label: 'Waypoints' }, + { id: 'custom', label: 'Custom' }, + { id: 'about', label: 'About' }, ]; export default function App() { @@ -58,7 +58,7 @@ export default function App() { return (
- +
{tab === 'defaults' && } diff --git a/extension/entrypoints/options/index.html b/extension/entrypoints/options/index.html index c343e2e..fb0515b 100644 --- a/extension/entrypoints/options/index.html +++ b/extension/entrypoints/options/index.html @@ -3,6 +3,13 @@ + + Aturi Settings diff --git a/extension/entrypoints/options/options.css b/extension/entrypoints/options/options.css index 2ff7860..0fe5f96 100644 --- a/extension/entrypoints/options/options.css +++ b/extension/entrypoints/options/options.css @@ -4,36 +4,40 @@ body { } .options-root { - display: grid; - /* `minmax(0, 1fr)` lets the content column actually shrink — a plain `1fr` - uses min-content as its floor, which a long un-breakable URL inside the - custom-waypoint preview can blow past, forcing horizontal scroll. */ - grid-template-columns: 188px minmax(0, 1fr); + display: flex; + flex-direction: column; max-width: 1100px; margin: 0 auto; min-height: 100vh; + /* Prevent intrinsic min-content of nested grids/long URLs from forcing the + whole page to grow horizontally. */ + min-width: 0; } -.options-sidebar { - border-right: 1px solid var(--border-subtle); - padding: 28px 0; - background: var(--bg-secondary); +.options-header { position: sticky; top: 0; - align-self: start; - min-height: 100vh; + z-index: 5; + background: var(--bg-secondary); + border-bottom: 1px solid var(--border-subtle); + padding: 14px 24px 0; + display: flex; + flex-direction: column; + gap: 10px; } .options-brand { - padding: 0 18px 18px; - border-bottom: 1px solid var(--border-subtle); - margin-bottom: 12px; + display: flex; + align-items: center; + gap: 12px; + flex-wrap: wrap; } .options-brand-title { font-family: var(--font-serif); font-weight: 500; font-size: 20px; + line-height: 1; letter-spacing: -0.02em; display: inline-flex; align-items: center; @@ -46,24 +50,24 @@ body { } .options-brand-sub { - font-size: 11px; + font-size: 10px; + line-height: 1; color: var(--text-tertiary); text-transform: uppercase; - letter-spacing: 0.1em; - margin-top: 2px; + letter-spacing: 0.14em; + /* Nudge down so the small caps optically center with the cap-height of + "Aturi" rather than its full ascender-to-descender box. */ + transform: translateY(1px); } .options-nav { display: flex; - flex-direction: column; + flex-wrap: wrap; + gap: 2px; + margin: 0 -6px; } .options-nav-item { - display: flex; - align-items: center; - justify-content: space-between; - padding: 10px 18px; - text-align: left; background: transparent; border: none; color: var(--text-secondary); @@ -71,30 +75,48 @@ body { font-family: var(--font-serif); font-size: 13.5px; font-weight: 400; - border-left: 2px solid transparent; - transition: all 0.2s ease; - position: relative; + padding: 8px 12px 10px; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease; + white-space: nowrap; } .options-nav-item:hover { - background: var(--bg-tertiary); color: var(--text-primary); + background: var(--bg-tertiary); } .options-nav-item.active { - background: var(--bg-tertiary); - border-left-color: var(--text-accent); color: var(--text-primary); + border-bottom-color: var(--text-accent); font-weight: 500; } .options-content { - padding: 32px 36px; + padding: 28px 28px 40px; max-width: 880px; + width: 100%; /* Same reason as .options-root: prevent intrinsic min-content of children from forcing this block to grow beyond its container. */ min-width: 0; overflow-x: hidden; + box-sizing: border-box; +} + +@media (max-width: 560px) { + .options-header { + padding: 12px 16px 0; + } + + .options-content { + padding: 22px 16px 32px; + } + + .options-nav-item { + font-size: 13px; + padding: 8px 10px 10px; + } } .options-h1 { diff --git a/extension/entrypoints/popup/App.tsx b/extension/entrypoints/popup/App.tsx index 40444cf..8be8a72 100644 --- a/extension/entrypoints/popup/App.tsx +++ b/extension/entrypoints/popup/App.tsx @@ -24,6 +24,24 @@ type PopupState = | { phase: 'unsupported'; prefs: Prefs; tabId: number | null; isKnownHost: boolean } | { phase: 'ready'; match: ReverseMatch; prefs: Prefs; tabId: number | null }; +// Open the extension's options page. We prefer browser.runtime.openOptionsPage() +// because it focuses an existing options tab when one is already open. Some +// Chromium-derived browsers (notably Arc) do not implement the chrome://extensions +// surface that hosts embedded options, so the call can silently no-op. If it +// throws or never resolves, fall back to opening options.html in a new tab. +async function openOptionsPage() { + const fallbackUrl = browser.runtime.getURL('/options.html'); + try { + const result = browser.runtime.openOptionsPage(); + if (result && typeof (result as Promise).then === 'function') { + await (result as Promise); + } + } catch { + await browser.tabs.create({ url: fallbackUrl }); + } + window.close(); +} + export default function App() { const [state, setState] = useState({ phase: 'loading' }); const [pendingId, setPendingId] = useState(null); @@ -288,7 +306,7 @@ function NoAtmosphereView({
No destinations are visible. Add waypoints to a group in Settings.
-
@@ -334,7 +352,7 @@ function NoAtmosphereView({ @@ -492,7 +510,7 @@ function Ready({ match, prefs, pendingId, copiedId, onOpen, onCopy }: ReadyProps
-
@@ -581,7 +599,7 @@ function HeaderSettingsButton() {