diff --git a/web/modules/scan_icons.js b/web/modules/scan_icons.js index 149182d..26788f7 100644 --- a/web/modules/scan_icons.js +++ b/web/modules/scan_icons.js @@ -4,7 +4,7 @@ */ const ICONS = { - radar: '', + scan: '', pick: '', online: '', offline: '', diff --git a/web/modules/ui_scan_page.js b/web/modules/ui_scan_page.js index b8a32ef..10de944 100644 --- a/web/modules/ui_scan_page.js +++ b/web/modules/ui_scan_page.js @@ -6,9 +6,9 @@ * (the full counts unfold). Progress shows under it. Then the models' state as a bar with a chip * per state (not found and not scanned open their list), and a chip for the components a * drawing model loads (VAE, text encoders…), which are not in the counts since many are not on - * Civitai. Then, only when there is something, what needs a look: damaged files, new models that - * look like no drawing model (don't scan them, scan them, see them), models set to "don't scan", - * files in other formats. Then the settings (ui_scan_settings.js) and the last scan in one line. + * Civitai, with quiet links to the models set to "don't scan" and the files in other formats. + * Then, only when there is something, what needs a look: damaged files, new models that look + * like no drawing model (don't scan them, scan them, see them). Then the settings (ui_scan_settings.js) and the last scan in one line. * Lists are pages of their own (ui_scan_lists.js) with a way back. Scans run through * scan_runner.js; the progress box is scan_progress.js's panel, hosted here while the page is shown. */ @@ -166,7 +166,7 @@ function scanCard(owner, panel, summary, busy) { : waiting ? t(options.offline ? 'scanPageScanNewOffline' : 'scanPageScanNew', { count: waiting }) : t('scanPageScanAgain'); const primary = button('anomalous-scan-primary', undefined, () => run(owner, panel)); - primary.append(scanIcon('radar'), el('span', '', label)); + primary.append(scanIcon('scan'), el('span', '', label)); primary.disabled = busy; const pick = button('anomalous-scan-secondary', undefined, () => openScanPicker(options.picked, (next) => { options.picked = next; @@ -197,7 +197,10 @@ function scanCard(owner, panel, summary, busy) { return card; } -/** The models' state: a bar of found / not found / not scanned, a chip for each, and the components' chip. */ +/** + * The models' state: a bar of found / not found / not scanned, a chip for each, the components' + * chip, and under them quiet links to the models left out (set to "don't scan", other formats). + */ function stateRow(summary, open) { const counts = mainCounts(summary); const box = el('section', 'anomalous-scan-state'); @@ -231,6 +234,14 @@ function stateRow(summary, open) { chips.append(node); } box.append(el('h2', 'anomalous-scan-section-title', t('scanStateTitle')), bar, chips); + const notes = el('div', 'anomalous-scan-state-notes'); + for (const [count, icon, key, view] of [[summary.excluded, 'excluded', 'scanPageExcludedNote', 'excluded'], [summary.skipped, 'file', 'scanPageSkippedNote', 'skipped']]) { + if (!count) continue; + const link = button('anomalous-scan-quiet-link', undefined, open(view)); + link.append(scanIcon(icon), el('span', '', t(key, { count }))); + notes.append(link); + } + if (notes.childElementCount) box.append(notes); return box; } @@ -255,8 +266,6 @@ function attention(owner, panel, summary, open) { button('anomalous-pick-link', t('scanPageSeeThem'), open('notdrawing')), ]); } - if (summary.excluded) line('excluded', t('scanPageExcludedNote', { count: summary.excluded }), 'quiet', open('excluded')); - if (summary.skipped) line('file', t('scanPageSkippedNote', { count: summary.skipped }), 'quiet', open('skipped')); if (!rows.length) return null; const box = el('section', 'anomalous-scan-attention'); const list = el('div', 'anomalous-scan-card anomalous-scan-attn-list'); diff --git a/web/styles.css b/web/styles.css index 783af69..9e15696 100644 --- a/web/styles.css +++ b/web/styles.css @@ -16,7 +16,7 @@ @import url("./styles/15-shell-rail.css?v=20261007-theme-2"); @import url("./styles/16-activity.css?v=20261007-theme-2"); @import url("./styles/17-model-types.css?v=20261007-theme-2"); -@import url("./styles/18-scan-page.css?v=20261011-look"); +@import url("./styles/18-scan-page.css?v=20261011-look-3"); @import url("./styles/19-model-doctor.css?v=20261007-theme-2"); @import url("./styles/20-current-node.css?v=20261007-theme-2"); @import url("./styles/21-prompt-studio.css?v=20261007-theme-2"); diff --git a/web/styles/18-scan-page.css b/web/styles/18-scan-page.css index 663dfd5..bc16586 100644 --- a/web/styles/18-scan-page.css +++ b/web/styles/18-scan-page.css @@ -18,6 +18,7 @@ margin: 0 auto; padding: 32px 28px 40px; box-sizing: border-box; + container: scanpage / inline-size; } .anomalous-scan-title { @@ -271,6 +272,29 @@ button.anomalous-scan-state-chip:hover { border-radius: 50%; } +/* Under the chips: the models left out, as quiet links. */ +.anomalous-scan-state-notes { + display: flex; + flex-wrap: wrap; + gap: 4px 16px; +} + +.anomalous-scan-quiet-link { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 0; + border: none; + background: none; + color: var(--amb-text-muted); + font: inherit; + font-size: 12.5px; + cursor: pointer; +} + +.anomalous-scan-quiet-link .anomalous-scan-icon { width: 14px; height: 14px; } +.anomalous-scan-quiet-link:hover { color: var(--amb-text-main); text-decoration: underline dotted; text-underline-offset: 3px; } + /* The components: apart from the counts, dashed, at the end of the row. */ .anomalous-scan-state-chip.anomalous-scan-parts-chip { margin-left: auto; @@ -305,7 +329,6 @@ button.anomalous-scan-attn:hover { background: rgba(var(--amb-ink-rgb), 0.04); } .anomalous-scan-attn-text { flex: 1 1 220px; min-width: 0; line-height: 1.5; } .anomalous-scan-attn > .anomalous-scan-icon:last-child { color: var(--amb-text-muted); } .anomalous-scan-attn.is-danger { color: var(--amb-danger-text); } -.anomalous-scan-attn.is-quiet { color: var(--amb-text-muted); } /* The settings: a tile each, with its icon and switch; the rarer ones folded under them. */ .anomalous-scan-tiles { @@ -366,7 +389,7 @@ label.anomalous-scan-tile:hover { border-color: color-mix(in srgb, var(--amb-lin } .anomalous-scan-more-head::-webkit-details-marker { display: none; } -.anomalous-scan-more-head::before { content: '›'; color: var(--amb-text-muted); transition: transform 0.15s ease; } +.anomalous-scan-more-head::before { content: '›'; display: inline-block; color: var(--amb-text-muted); transition: transform 0.15s ease; } .anomalous-scan-more-settings[open] > .anomalous-scan-more-head::before { transform: rotate(90deg); } .anomalous-scan-more-settings > .anomalous-scan-setting-help { display: block; padding-bottom: 12px; } @@ -392,8 +415,10 @@ label.anomalous-scan-tile:hover { border-color: color-mix(in srgb, var(--amb-lin .anomalous-scan-last-text { flex: 1 1 260px; min-width: 0; } .anomalous-scan-last-line .anomalous-pick-link { margin-left: 0; } -@media (max-width: 560px) { - .anomalous-scan-card.anomalous-scan-hero { flex-direction: column; align-items: center; } +/* Narrow (a phone, or docked in the sidebar): the ring above the rest. */ +@container scanpage (max-width: 560px) { + .anomalous-scan-card.anomalous-scan-hero { flex-direction: column; align-items: stretch; } + .anomalous-scan-ring { align-self: center; } .anomalous-scan-mode { margin-left: 0; } .anomalous-scan-state-chip.anomalous-scan-parts-chip { margin-left: 0; } }