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; }
}