Interface : structure HTML et styles repris de Logstream

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude BotandClaude Opus 5.5 committed 2026-10-01 12:49:25 +02:00
1 parent 9432a34e30
commit 707962d5e4
2 files changed
+613

No files matched your search

+225
View File
@@ -0,0 +1,225 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Searchgit</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%236366f1'/%3E%3Ccircle cx='14' cy='14' r='6' fill='none' stroke='white' stroke-width='3'/%3E%3Cpath d='m19 19 5 5' stroke='white' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E">
<link rel="stylesheet" href="style.css">
<script>
// Apply the saved theme and language before first paint to avoid a flash.
try {
var t = localStorage.getItem('searchgit.theme');
if (t === 'light' || t === 'dark') document.documentElement.dataset.theme = t;
var l = localStorage.getItem('searchgit.lang');
if (l) document.documentElement.lang = l;
} catch (e) {}
</script>
</head>
<body>
<header class="topbar">
<div class="brand">
<svg viewBox="0 0 32 32" aria-hidden="true"><rect width="32" height="32" rx="8"/><circle cx="14" cy="14" r="6"/><path d="m19 19 5 5"/></svg>
<span>Searchgit</span>
</div>
<form id="searchForm" class="search" role="search">
<svg class="ico" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
<input id="q" type="search" autocomplete="off" spellcheck="false" data-i18n-aria="searchAria" data-i18n-ph="searchPh">
<select id="in" class="chip-select" data-i18n-aria="inAria">
<option value="" data-i18n="inAll">Everywhere</option>
<option value="name" data-i18n="inName">Name</option>
<option value="description" data-i18n="inDesc">Description</option>
<option value="readme" data-i18n="inReadme">README</option>
</select>
</form>
<div class="actions">
<button id="settingsBtn" class="icon-btn" type="button" data-i18n-title="settings" data-i18n-aria="settings">
<!-- Gear icon (Lucide "settings", ISC license) -->
<svg viewBox="0 0 24 24"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button id="themeBtn" class="icon-btn" type="button" data-i18n-title="theme" data-i18n-aria="theme">
<svg class="sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
<svg class="moon" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
</button>
</div>
<div class="progress" aria-hidden="true"></div>
</header>
<section class="filters">
<select id="language" data-i18n-aria="languageAria"><option value="" data-i18n="langAll">All languages</option></select>
<select id="stars" data-i18n-aria="starsAria">
<option value="" data-i18n="starsAll">Any stars</option>
<option value="10">★ ≥ 10</option>
<option value="100">★ ≥ 100</option>
<option value="1000">★ ≥ 1k</option>
<option value="10000">★ ≥ 10k</option>
</select>
<select id="pushed" data-i18n-aria="pushedAria">
<option value="" data-i18n="pushedAll">Any activity</option>
<option value="1m" data-i18n="pushed1m">Pushed &lt; 1 month</option>
<option value="6m" data-i18n="pushed6m">Pushed &lt; 6 months</option>
<option value="1y" data-i18n="pushed1y">Pushed &lt; 1 year</option>
<option value="2y" data-i18n="pushed2y">Pushed &lt; 2 years</option>
</select>
<select id="created" data-i18n-aria="createdAria">
<option value="" data-i18n="createdAll">Any creation date</option>
<option value="1m" data-i18n="created1m">Created &lt; 1 month</option>
<option value="1y" data-i18n="created1y">Created &lt; 1 year</option>
<option value="5y" data-i18n="created5y">Created &lt; 5 years</option>
</select>
<select id="license" data-i18n-aria="licenseAria">
<option value="" data-i18n="licenseAll">Any license</option>
<option value="mit">MIT</option>
<option value="apache-2.0">Apache 2.0</option>
<option value="gpl-3.0">GPL 3.0</option>
<option value="agpl-3.0">AGPL 3.0</option>
<option value="lgpl-3.0">LGPL 3.0</option>
<option value="mpl-2.0">MPL 2.0</option>
<option value="bsd-3-clause">BSD 3-Clause</option>
<option value="bsd-2-clause">BSD 2-Clause</option>
<option value="isc">ISC</option>
<option value="unlicense">Unlicense</option>
</select>
<input id="topic" class="filter-input" type="text" autocomplete="off" spellcheck="false" data-i18n-ph="topicPh" data-i18n-aria="topicAria">
<div class="toggles">
<button id="goodfirst" class="toggle" type="button" aria-pressed="false" data-i18n="goodFirst" data-i18n-title="goodFirstTitle">Good first issues</button>
<button id="forks" class="toggle" type="button" aria-pressed="false" data-i18n="withForks" data-i18n-title="withForksTitle">Forks</button>
<button id="archived" class="toggle" type="button" aria-pressed="false" data-i18n="withArchived" data-i18n-title="withArchivedTitle">Archived</button>
</div>
<button id="resetBtn" class="link-btn" type="button" data-i18n="reset" hidden>Reset</button>
<div class="end">
<span id="count" class="muted"></span>
<select id="sort" data-i18n-aria="sortAria">
<option value="" data-i18n="sortBest">Best match</option>
<option value="stars" data-i18n="sortStars">Most stars</option>
<option value="forks" data-i18n="sortForks">Most forks</option>
<option value="updated" data-i18n="sortUpdated">Recently updated</option>
<option value="help-wanted-issues" data-i18n="sortHelp">Help wanted issues</option>
</select>
<button id="exportBtn" class="btn tool" type="button" data-i18n-title="exportTitle">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3v12M7 10l5 5 5-5M4 17v3h16v-3"/></svg>
<span class="lbl">CSV</span>
</button>
</div>
</section>
<div id="error" class="error-banner" hidden></div>
<main id="list" class="list"></main>
<div id="more" class="more" hidden>
<button id="moreBtn" class="btn" type="button" data-i18n="more">Load more</button>
</div>
<div id="empty" class="empty" hidden>
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
<p><strong data-i18n="emptyTitle">No matching repositories.</strong></p>
<p class="muted" data-i18n="emptyHint">Loosen a filter or change the search words.</p>
</div>
<footer class="status">
<span id="conn" class="conn"></span>
<a id="ghQuery" class="gh-query" target="_blank" rel="noopener" hidden></a>
</footer>
<dialog id="settingsDlg" class="settings" aria-labelledby="settingsTitle">
<div class="dlg">
<header>
<h2 id="settingsTitle" data-i18n="settings">Settings</h2>
<button id="closeSettings" class="icon-btn" type="button" data-i18n-aria="close">
<svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6 6 18"/></svg>
</button>
</header>
<div class="set-body">
<nav id="setNav" class="set-nav" role="tablist" aria-orientation="vertical">
<button type="button" role="tab" data-tab="locale">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg>
<span data-i18n="tabLocale">Localization</span>
</button>
<button type="button" role="tab" data-tab="interface">
<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/></svg>
<span data-i18n="tabInterface">Interface</span>
</button>
<button type="button" role="tab" data-tab="github">
<svg viewBox="0 0 24 24"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="8" r="2.5"/><path d="M6 8.5v7M18 10.5c0 4-6 3-11 5.5"/></svg>
<span>GitHub</span>
</button>
</nav>
<div class="set-panels">
<!-- Localization -->
<div class="set-panel" role="tabpanel" data-panel="locale">
<section class="set-section">
<h3 data-i18n="language">Language</h3>
<div id="langSwitch" class="seg" role="radiogroup" data-i18n-aria="language">
<button type="button" role="radio" data-lang="en">English</button>
<button type="button" role="radio" data-lang="fr">Français</button>
</div>
</section>
</div>
<!-- Interface -->
<div class="set-panel" role="tabpanel" data-panel="interface" hidden>
<section class="set-section">
<h3 data-i18n="themeTitle">Theme</h3>
<div id="themeSwitch" class="seg" role="radiogroup" data-i18n-aria="themeTitle">
<button type="button" role="radio" data-theme-opt="system" data-i18n="themeSystem">System</button>
<button type="button" role="radio" data-theme-opt="light" data-i18n="themeLight">Light</button>
<button type="button" role="radio" data-theme-opt="dark" data-i18n="themeDark">Dark</button>
</div>
<p class="muted small hint" data-i18n="themeHelp"></p>
</section>
<section class="set-section">
<h3 data-i18n="listTitle">Result list</h3>
<div class="field-grid">
<span class="lbl" data-i18n="density">Density</span>
<div id="densitySwitch" class="seg" role="radiogroup" data-i18n-aria="density">
<button type="button" role="radio" data-density="compact" data-i18n="compact">Compact</button>
<button type="button" role="radio" data-density="comfortable" data-i18n="comfortable">Comfortable</button>
</div>
<span class="lbl" data-i18n="perPage">Results per page</span>
<div id="perPageSwitch" class="seg" role="radiogroup" data-i18n-aria="perPage">
<button type="button" role="radio" data-per-page="30">30</button>
<button type="button" role="radio" data-per-page="50">50</button>
<button type="button" role="radio" data-per-page="100">100</button>
</div>
</div>
</section>
</div>
<!-- GitHub -->
<div class="set-panel" role="tabpanel" data-panel="github" hidden>
<section class="set-section">
<h3 data-i18n="tokenTitle">Access token</h3>
<p id="tokenStatus" class="state-line"></p>
<p class="muted small" data-i18n="tokenHelp"></p>
</section>
<section class="set-section">
<h3 data-i18n="quotaTitle">Search quota</h3>
<p id="quotaStatus" class="state-line"></p>
<p class="muted small" data-i18n="quotaHelp"></p>
</section>
<section class="set-section">
<h3 data-i18n="syntaxTitle">Search syntax</h3>
<p class="muted small" data-i18n="syntaxHelp"></p>
<ul class="syntax">
<li><code>user:torvalds</code> <span data-i18n="synUser"></span></li>
<li><code>org:golang</code> <span data-i18n="synOrg"></span></li>
<li><code>topic:cli topic:tui</code> <span data-i18n="synTopics"></span></li>
<li><code>"log viewer"</code> <span data-i18n="synPhrase"></span></li>
<li><code>NOT electron</code> <span data-i18n="synNot"></span></li>
<li><code>size:&lt;5000</code> <span data-i18n="synSize"></span></li>
</ul>
</section>
</div>
</div>
</div>
</div>
</dialog>
<div id="toast" class="toast" hidden></div>
<script src="app.js"></script>
</body>
</html>
+388
View File
@@ -0,0 +1,388 @@
/* Look and feel taken from Logstream: same tokens, top bar, filters, list and settings dialog. */
/* ---------- Theme: everything goes through these variables ---------- */
:root {
--bg: #f6f7f9;
--panel: #ffffff;
--panel-2: #f0f2f5;
--border: #e2e5ea;
--text: #1a1d23;
--muted: #6b7280;
--accent: #6366f1;
--accent-soft: rgba(99, 102, 241, .12);
--row-hover: #f5f6fa;
--shadow: 0 10px 30px rgba(15, 23, 42, .12);
--star: #d97706;
--ok: #0d9488;
--err: #dc2626;
--warn: #d97706;
--mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--radius: 10px;
--row-pad: 12px; /* Settings > Interface > Density */
color-scheme: light;
}
:root[data-theme="dark"] {
--bg: #0f1115;
--panel: #161a20;
--panel-2: #1d222a;
--border: #2a3039;
--text: #e6e8ec;
--muted: #8b93a1;
--accent: #818cf8;
--accent-soft: rgba(129, 140, 248, .16);
--row-hover: #1a1f26;
--shadow: 0 10px 30px rgba(0, 0, 0, .5);
--star: #fbbf24;
--ok: #2dd4bf;
--err: #f87171;
--warn: #fbbf24;
color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg: #0f1115;
--panel: #161a20;
--panel-2: #1d222a;
--border: #2a3039;
--text: #e6e8ec;
--muted: #8b93a1;
--accent: #818cf8;
--accent-soft: rgba(129, 140, 248, .16);
--row-hover: #1a1f26;
--shadow: 0 10px 30px rgba(0, 0, 0, .5);
--star: #fbbf24;
--ok: #2dd4bf;
--err: #f87171;
--warn: #fbbf24;
color-scheme: dark;
}
}
:root[data-density="compact"] { --row-pad: 7px; }
/* ---------- Base ---------- */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font: 14px/1.45 var(--sans);
padding-bottom: 44px;
}
button, input, select { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: inherit; }
svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.muted { color: var(--muted); }
.small { font-size: 12.5px; }
[hidden] { display: none !important; }
/* ---------- Top bar ---------- */
.topbar {
position: sticky; top: 0; z-index: 20;
display: flex; align-items: center; gap: 16px;
padding: 10px 20px;
background: color-mix(in srgb, var(--panel) 88%, transparent);
backdrop-filter: saturate(160%) blur(10px);
-webkit-backdrop-filter: saturate(160%) blur(10px);
border-bottom: 1px solid var(--border);
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 650; font-size: 16px; letter-spacing: -.01em; }
.brand svg { width: 26px; height: 26px; }
.brand svg rect { fill: var(--accent); stroke: none; }
.brand svg circle, .brand svg path { stroke: #fff; stroke-width: 3; }
.search {
flex: 1; max-width: 720px; margin: 0;
display: flex; align-items: center; gap: 8px;
padding: 0 5px 0 12px; height: 38px;
background: var(--panel-2);
border: 1px solid transparent;
border-radius: var(--radius);
transition: border-color .15s, box-shadow .15s;
}
.search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.search .ico { width: 17px; height: 17px; color: var(--muted); flex: none; }
.search input {
flex: 1; min-width: 0; height: 100%;
border: 0; outline: 0; background: transparent;
font-family: var(--mono); font-size: 13px;
}
.search input::-webkit-search-cancel-button { cursor: pointer; }
.chip-select {
flex: none; height: 28px; padding: 0 24px 0 9px;
border: 1px solid var(--border); border-radius: 7px;
background: var(--panel) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b93a1' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 6px center / 12px;
appearance: none; -webkit-appearance: none;
font-size: 12px; font-weight: 600; color: var(--muted);
}
.chip-select.set { color: var(--accent); border-color: var(--accent); background-color: var(--accent-soft); }
.actions { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.icon-btn {
width: 36px; height: 36px; display: grid; place-items: center;
border: 1px solid transparent; background: transparent; border-radius: 9px; color: var(--muted);
}
.icon-btn:hover { background: var(--panel-2); color: var(--text); }
.icon-btn svg { width: 19px; height: 19px; }
/* Sun or moon depending on the effective theme */
#themeBtn .moon { display: none; }
:root[data-theme="dark"] #themeBtn .sun { display: none; }
:root[data-theme="dark"] #themeBtn .moon { display: block; }
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) #themeBtn .sun { display: none; }
:root:not([data-theme="light"]) #themeBtn .moon { display: block; }
}
.btn {
display: inline-flex; align-items: center; gap: 7px;
height: 34px; padding: 0 12px;
border: 1px solid var(--border); border-radius: 9px;
background: var(--panel); font-weight: 550; font-size: 13px; text-decoration: none;
}
.btn:hover { background: var(--panel-2); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.tool { height: 32px; padding: 0 10px; }
.btn.tool svg { width: 16px; height: 16px; }
.link-btn { border: 0; background: none; padding: 0; font-size: 12.5px; font-weight: 550; color: var(--accent); white-space: nowrap; }
.link-btn:hover { text-decoration: underline; }
.progress { position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; overflow: hidden; }
body.busy .progress::after {
content: ""; position: absolute; inset: 0; width: 30%;
background: var(--accent);
animation: slide 1s ease-in-out infinite;
}
@keyframes slide { from { transform: translateX(-100%); } to { transform: translateX(400%); } }
/* ---------- Filters ---------- */
.filters {
display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
padding: 12px 20px 10px;
}
.filters select, .filter-input {
height: 32px; border: 1px solid var(--border); border-radius: 8px;
background-color: var(--panel); font-size: 13px;
}
.filters select {
padding: 0 28px 0 10px; max-width: 220px;
background: var(--panel) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b93a1' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center / 14px;
appearance: none; -webkit-appearance: none;
}
.filter-input { width: 9.5rem; padding: 0 10px; font-family: var(--mono); font-size: 12.5px; outline: 0; }
.filter-input:focus, .filters select:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.filters select.set, .filter-input.set { border-color: var(--accent); background-color: var(--accent-soft); }
.toggles { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.toggle {
height: 32px; padding: 0 11px; border: 1px solid var(--border); border-radius: 8px;
background: var(--panel); font-size: 12.5px; font-weight: 600; color: var(--muted); white-space: nowrap;
}
.toggle:hover { color: var(--text); }
.toggle[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.filters .end { display: flex; align-items: center; gap: 8px; margin-left: auto; }
#count { font-size: 12.5px; font-variant-numeric: tabular-nums; }
/* ---------- Result list ---------- */
.list { margin: 4px 20px 0; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.list:empty { display: none; }
.row {
display: grid;
grid-template-columns: 36px minmax(0, 1fr) auto;
grid-template-areas: "av main meta" "av details details";
gap: 0 14px; align-items: start;
padding: var(--row-pad) 16px var(--row-pad) 14px;
border-bottom: 1px solid var(--border);
cursor: pointer;
}
.row:last-child { border-bottom: 0; }
.row:hover { background: var(--row-hover); }
.row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.row.open { background: var(--row-hover); }
.row .av { grid-area: av; width: 36px; height: 36px; border-radius: 8px; background: var(--panel-2); margin-top: 2px; }
:root[data-density="compact"] .row .av { width: 28px; height: 28px; }
.row .main { grid-area: main; min-width: 0; }
.row .name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.row .name a { font-weight: 650; text-decoration: none; overflow-wrap: anywhere; }
.row .name a .owner { font-weight: 450; color: var(--muted); }
.row .name a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.row .desc { margin: 2px 0 0; color: var(--text); opacity: .85; overflow-wrap: anywhere; }
:root[data-density="compact"] .row .desc { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.badge {
font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
padding: 1px 6px; border-radius: 5px; color: var(--muted); border: 1px solid var(--border);
}
.badge.archived { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.topics { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
:root[data-density="compact"] .topics { display: none; }
.topic {
height: 22px; padding: 0 8px; border: 0; border-radius: 999px;
background: var(--accent-soft); color: var(--accent); font-size: 11.5px; font-weight: 600;
}
.topic:hover { filter: brightness(1.15); text-decoration: underline; }
.meta {
grid-area: meta;
display: grid; grid-template-columns: 7.5rem 4.5rem 4rem 6.5rem; gap: 12px;
align-items: center; padding-top: 2px;
font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.meta > span { display: inline-flex; align-items: center; gap: 5px; overflow: hidden; text-overflow: ellipsis; }
.meta svg { width: 14px; height: 14px; flex: none; }
.meta .stars { color: var(--text); font-weight: 600; }
.meta .stars svg { color: var(--star); fill: var(--star); }
.lang-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--c, var(--muted)); }
.meta .lang[data-act]:hover { color: var(--accent); }
/* Repository details */
.details {
grid-area: details;
margin: 10px 0 2px; padding: 10px 12px;
background: var(--panel-2); border-radius: 8px; cursor: auto; font-size: 12.5px;
}
.details dl { display: grid; grid-template-columns: max-content 1fr; gap: 3px 16px; margin: 0; }
.details dt { color: var(--muted); }
.details dd { margin: 0; word-break: break-all; font-family: var(--mono); }
.details .acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.details .acts .btn { height: 28px; font-size: 12px; }
.more { display: flex; justify-content: center; padding: 14px 20px 4px; }
/* ---------- States ---------- */
.empty { text-align: center; padding: 60px 20px; }
.empty svg { width: 40px; height: 40px; color: var(--muted); opacity: .6; }
.empty p { margin: 6px 0; }
.error-banner {
margin: 4px 20px 8px; padding: 10px 14px;
border: 1px solid color-mix(in srgb, var(--err) 40%, transparent);
background: color-mix(in srgb, var(--err) 10%, transparent);
color: var(--err); border-radius: var(--radius);
font-family: var(--mono); font-size: 12.5px; white-space: pre-wrap;
}
.status {
position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
display: flex; gap: 16px; align-items: center;
padding: 6px 20px; font-size: 12px;
background: var(--panel); border-top: 1px solid var(--border);
font-variant-numeric: tabular-nums;
}
.conn { white-space: nowrap; }
.conn::before { content: "●"; margin-right: 6px; color: var(--muted); }
.conn.ok::before { color: var(--ok); }
.conn.warn::before { color: var(--warn); }
.conn.ko::before { color: var(--err); }
.gh-query {
min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-family: var(--mono); font-size: 11.5px; color: var(--muted); text-decoration: none;
}
.gh-query:hover { color: var(--accent); text-decoration: underline; }
.toast {
position: fixed; bottom: 48px; left: 50%; transform: translateX(-50%); z-index: 50;
background: var(--text); color: var(--bg);
padding: 8px 14px; border-radius: 8px; font-size: 13px; box-shadow: var(--shadow);
}
/* ---------- Settings dialog ---------- */
dialog {
width: min(720px, calc(100vw - 32px)); max-height: calc(100vh - 64px);
padding: 0; border: 1px solid var(--border); border-radius: 14px;
background: var(--panel); color: var(--text); box-shadow: var(--shadow);
}
dialog::backdrop { background: rgba(10, 12, 16, .45); backdrop-filter: blur(2px); }
dialog.settings {
width: min(820px, calc(100vw - 32px));
height: min(560px, calc(100vh - 64px)); max-height: none;
}
.dlg { display: flex; flex-direction: column; height: 100%; }
.dlg > header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 14px 22px; border-bottom: 1px solid var(--border); }
.dlg h2 { margin: 0; font-size: 17px; }
.set-body { flex: 1; min-height: 0; display: grid; grid-template-columns: 200px minmax(0, 1fr); }
.set-nav {
display: flex; flex-direction: column; gap: 2px;
padding: 12px 10px; border-right: 1px solid var(--border);
background: color-mix(in srgb, var(--panel-2) 50%, transparent);
}
.set-nav button {
display: flex; align-items: center; gap: 10px;
height: 38px; padding: 0 12px; border: 0; border-radius: 9px;
background: transparent; color: var(--muted); font-weight: 560; font-size: 13.5px; text-align: left;
white-space: nowrap;
}
.set-nav button:hover { background: var(--panel-2); color: var(--text); }
.set-nav button[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); }
.set-nav svg { width: 18px; height: 18px; flex: none; }
.set-panels { overflow-y: auto; padding: 2px 24px 22px; }
.set-panel > .set-section:first-child { margin-top: 16px; }
.set-section { margin-top: 18px; }
.set-section + .set-section { padding-top: 16px; border-top: 1px solid var(--border); }
.set-section h3 { margin: 0 0 8px; font-size: 13px; font-weight: 650; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.set-section p { margin: 0; }
.hint { margin-top: 8px !important; }
.lbl { font-size: 13px; font-weight: 550; }
.field-grid { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 10px 14px; align-items: center; justify-items: start; }
.state-line { font-size: 13px; margin: 0 0 8px !important; }
.state-line.good::before, .state-line.bad::before, .state-line.warn::before { content: "●"; margin-right: 6px; }
.state-line.good::before { color: var(--ok); }
.state-line.warn::before { color: var(--warn); }
.state-line.bad { color: var(--err); }
.syntax { margin: 10px 0 0; padding: 0; list-style: none; display: grid; gap: 6px; font-size: 12.5px; }
.syntax code {
font: 12px var(--mono); padding: 2px 7px; border-radius: 5px;
background: var(--panel-2); border: 1px solid var(--border); margin-right: 6px;
}
.seg { display: inline-flex; padding: 3px; gap: 3px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px; }
.seg button {
border: 0; background: transparent; border-radius: 7px;
height: 30px; padding: 0 14px; font-size: 13px; font-weight: 600; color: var(--muted);
}
.seg button:hover { color: var(--text); }
.seg button[aria-checked="true"] { background: var(--panel); color: var(--accent); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
/* ---------- Medium screens: the meta columns go under the description ---------- */
@media (max-width: 1100px) {
.row { grid-template-columns: 36px minmax(0, 1fr); grid-template-areas: "av main" "av meta" "av details"; }
.meta { display: flex; flex-wrap: wrap; gap: 4px 16px; padding-top: 6px; }
}
/* ---------- Mobile ---------- */
@media (max-width: 760px) {
body { font-size: 13.5px; }
.topbar { flex-wrap: wrap; padding: 8px 16px; gap: 8px 10px; }
.search { order: 3; flex-basis: 100%; max-width: none; }
.filters { padding: 10px 16px 8px; }
.filters select, .filter-input { flex: 1 1 calc(50% - 8px); max-width: none; min-width: 0; width: auto; }
.toggles { flex: 1 1 100%; }
.toggle { flex: 1; padding: 0 6px; }
.filters .end { flex: 1 1 100%; margin-left: 0; }
#count { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.filters .end select { flex: 0 1 auto; }
.list, .error-banner { margin-left: 16px; margin-right: 16px; }
.row { grid-template-columns: 28px minmax(0, 1fr); gap: 0 10px; padding-left: 12px; padding-right: 12px; }
.row .av { width: 28px; height: 28px; }
.details dl { grid-template-columns: 1fr; }
.details dt { margin-top: 4px; }
.status { padding: 6px 16px; }
.gh-query { display: none; }
dialog.settings { height: calc(100vh - 24px); width: calc(100vw - 16px); }
.set-body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
.set-nav {
display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 6px;
border-right: 0; border-bottom: 1px solid var(--border);
}
.set-nav button {
flex-direction: column; justify-content: center; height: auto; padding: 6px 2px; gap: 3px;
font-size: 11.5px; text-align: center;
}
.set-panels { padding: 0 16px 18px; }
.field-grid { grid-template-columns: 1fr; gap: 6px; }
}