feat(options): make metadata panels collapsible and add summary icons

This commit is contained in:
Dariusz L
2026-07-06 14:51:15 +02:00
parent 5a9e81cc70
commit 8f525044e8
3 changed files with 446 additions and 70 deletions
+260 -2
View File
@@ -6294,6 +6294,69 @@ a.mr-image-preview-resource-name:hover {
color: var(--mr-text);
}
.mr-options-collapse-title {
display: inline-flex;
align-items: center;
gap: 6px;
min-height: 28px;
padding: 0;
border: 0;
border-radius: 0;
box-shadow: none;
background: transparent;
text-align: left;
cursor: pointer;
}
#model-resolver-modal .mr-options-collapse-title {
font-size: 20px;
font-weight: 700;
color: var(--mr-text);
background: transparent;
border: 0;
box-shadow: none;
}
.mr-options-collapse-title:hover {
color: var(--mr-text);
background: transparent;
border: 0;
box-shadow: none;
}
.mr-options-collapse-title:focus-visible {
outline: none;
color: var(--mr-text);
}
.mr-options-collapse-chevron {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 18px;
width: 18px;
height: 18px;
border: 0;
border-radius: 0;
color: var(--mr-text-secondary);
background: transparent;
box-shadow: none;
transition: transform 0.15s ease, color 0.15s ease;
}
.mr-options-collapse-chevron svg {
width: 16px;
height: 16px;
}
.mr-options-collapse-title:hover .mr-options-collapse-chevron {
color: var(--mr-text);
}
.mr-options-collapse-title[aria-expanded="false"] .mr-options-collapse-chevron {
transform: rotate(-90deg);
}
.mr-options-grid {
display: grid;
grid-template-columns: 1fr;
@@ -6345,7 +6408,15 @@ a.mr-image-preview-resource-name:hover {
}
.mr-options-section-fill .mr-options-build-stack {
grid-template-rows: auto auto auto auto auto minmax(0, 1fr);
grid-template-rows: auto auto minmax(0, 1fr);
}
.mr-options-section-fill .mr-options-metadata-size-stack {
grid-template-rows: auto minmax(0, 1fr);
}
.mr-options-section-fill .mr-options-metadata-size-stack.is-controls-collapsed {
grid-template-rows: minmax(0, 1fr);
}
.mr-options-build-stack {
@@ -6353,6 +6424,23 @@ a.mr-image-preview-resource-name:hover {
--mr-tab-active-bg: var(--mr-options-build-surface);
}
.mr-options-metadata-build-controls,
.mr-options-metadata-size-controls {
display: grid;
gap: 0;
min-width: 0;
}
.mr-options-metadata-build-controls[hidden],
.mr-options-metadata-size-controls[hidden] {
display: none;
}
.mr-options-build-stack,
.mr-options-metadata-size-stack {
container-type: inline-size;
}
.mr-options-panel-title {
margin: 0 0 6px 0;
font-size: 16px;
@@ -6405,6 +6493,141 @@ a.mr-image-preview-resource-name:hover {
color: var(--mr-color-error-light);
}
.mr-options-metadata-build-summary,
.mr-options-metadata-size-summary {
gap: 1px;
padding: 1px;
border-color: rgba(255, 255, 255, 0.12);
border-radius: 8px;
overflow: hidden;
background: rgba(255, 255, 255, 0.09);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.mr-options-metadata-build-summary {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
padding: 0;
background: transparent;
}
.mr-options-metadata-size-summary {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
}
.mr-options-db-summary.mr-options-metadata-size-summary {
background: #ffffff00;
}
.mr-options-metadata-build-summary .mr-options-db-row,
.mr-options-metadata-size-summary .mr-options-db-row {
position: relative;
justify-content: flex-start;
min-width: 0;
min-height: 70px;
padding: 6px;
border-top: 0 !important;
background: rgba(18, 18, 18, 0.96);
}
.mr-options-metadata-build-summary .mr-options-db-row::after,
.mr-options-metadata-size-summary .mr-options-db-row::after {
content: none !important;
display: none !important;
}
.mr-options-overview-stat-icon {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 28px;
width: 28px;
height: 28px;
color: rgba(255, 255, 255, 0.9);
}
.mr-options-overview-stat-icon svg {
width: 24px;
height: 24px;
stroke-width: 1.9;
}
.mr-options-overview-stat-copy {
display: grid;
min-width: 0;
gap: 3px;
}
.mr-options-overview-stat-copy span {
overflow-wrap: normal;
word-break: normal;
color: var(--mr-text-secondary);
font-size: 12px;
font-weight: 600;
line-height: 1.2;
}
.mr-options-metadata-build-summary .mr-options-db-row strong,
.mr-options-metadata-size-summary .mr-options-db-row strong {
color: var(--mr-text);
font-size: 20px;
font-weight: 800;
line-height: 1.05;
text-align: left;
}
@container (min-width: 700px) {
.mr-options-metadata-build-summary {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
@container (min-width: 860px) {
.mr-options-metadata-size-summary {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}
@container (max-width: 560px) {
.mr-options-metadata-build-summary,
.mr-options-metadata-size-summary {
grid-template-columns: repeat(2, minmax(0, 1fr));
background: rgba(255, 255, 255, 0.09);
}
.mr-options-metadata-build-summary {
background: transparent;
}
.mr-options-metadata-build-summary .mr-options-db-row,
.mr-options-metadata-size-summary .mr-options-db-row {
min-height: 66px;
padding: 6px;
}
}
@container (max-width: 360px) {
.mr-options-metadata-build-summary,
.mr-options-metadata-size-summary {
grid-template-columns: 1fr;
}
.mr-options-metadata-build-summary {
padding: 0;
}
.mr-options-metadata-size-summary {
padding: 8px;
}
.mr-options-metadata-build-summary .mr-options-db-row,
.mr-options-metadata-size-summary .mr-options-db-row {
min-height: 56px;
padding: 6px;
}
}
.mr-options-aria2-summary .mr-options-db-row {
align-items: flex-start;
}
@@ -6477,6 +6700,10 @@ a.mr-image-preview-resource-name:hover {
--mr-tab-active-bg: var(--mr-options-build-surface);
}
.mr-options-build-stack.is-controls-collapsed .mr-options-build-tabs {
margin-top: 0;
}
.mr-options-build-tabs .mr-options-build-tab {
gap: 5px;
min-width: 94px;
@@ -6526,7 +6753,7 @@ a.mr-image-preview-resource-name:hover {
#mr-options-metadata-build-progress-panel,
#mr-options-metadata-build-history-panel {
grid-row: 6;
grid-row: 3;
grid-column: 1;
min-height: 0;
padding: 10px;
@@ -7808,6 +8035,17 @@ a.mr-image-preview-resource-name:hover {
.mr-options-toggle-row {
gap: 10px;
}
.mr-options-metadata-build-summary,
.mr-options-metadata-size-summary {
grid-template-columns: repeat(2, minmax(0, 1fr));
background: rgba(255, 255, 255, 0.09);
}
.mr-options-metadata-build-summary {
background: transparent;
}
}
@media (max-width: 760px) {
@@ -7838,6 +8076,26 @@ a.mr-image-preview-resource-name:hover {
.mr-options-number-row {
grid-template-columns: 1fr;
}
.mr-options-metadata-build-summary,
.mr-options-metadata-size-summary {
grid-template-columns: 1fr;
}
.mr-options-metadata-build-summary {
padding: 0;
}
.mr-options-metadata-size-summary {
padding: 8px;
}
.mr-options-metadata-build-summary .mr-options-db-row,
.mr-options-metadata-size-summary .mr-options-db-row {
min-height: 56px;
padding: 6px;
}
}
@media (max-width: 640px) {
+177 -68
View File
@@ -744,37 +744,42 @@ export const optionsMethods = {
</section>
<section id="mr-options-section-metadata-audit" class="mr-options-card mr-options-section mr-options-section-fill is-hidden">
<div class="mr-options-section-head">
<h4 class="mr-options-section-title">Metadata Size Audit</h4>
<button id="mr-options-metadata-size-collapse-toggle" type="button" class="mr-options-section-title mr-options-collapse-title" aria-expanded="true" aria-controls="mr-options-metadata-size-controls">
<span>Metadata Size Audit</span>
<span class="mr-options-collapse-chevron" aria-hidden="true">${getSvgIcon('chevronDown')}</span>
</button>
</div>
<div class="mr-options-grid">
<div class="mr-options-panel">
<div class="mr-options-stack">
<div class="mr-options-db-summary">
<div class="mr-options-db-row">
<span>Models scanned</span>
<strong id="mr-options-metadata-size-scanned">0</strong>
<div class="mr-options-stack mr-options-metadata-size-stack">
<div id="mr-options-metadata-size-controls" class="mr-options-metadata-size-controls">
<div class="mr-options-db-summary mr-options-metadata-size-summary">
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('search')}</span>
<span class="mr-options-overview-stat-copy"><span>Models scanned</span><strong id="mr-options-metadata-size-scanned">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('fileCheck')}</span>
<span class="mr-options-overview-stat-copy"><span>Metadata checked</span><strong id="mr-options-metadata-size-checked">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('scale')}</span>
<span class="mr-options-overview-stat-copy"><span>Mismatches</span><strong id="mr-options-metadata-size-mismatches">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('fileQuestion')}</span>
<span class="mr-options-overview-stat-copy"><span>Missing size</span><strong id="mr-options-metadata-size-missing">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('triangleAlert')}</span>
<span class="mr-options-overview-stat-copy"><span>Errors</span><strong id="mr-options-metadata-size-errors">0</strong></span>
</div>
</div>
<div class="mr-options-db-row">
<span>Metadata checked</span>
<strong id="mr-options-metadata-size-checked">0</strong>
</div>
<div class="mr-options-db-row">
<span>Mismatches</span>
<strong id="mr-options-metadata-size-mismatches">0</strong>
</div>
<div class="mr-options-db-row">
<span>Missing size</span>
<strong id="mr-options-metadata-size-missing">0</strong>
</div>
<div class="mr-options-db-row">
<span>Errors</span>
<strong id="mr-options-metadata-size-errors">0</strong>
<div class="mr-options-db-actions">
<button id="mr-options-metadata-size-scan" type="button" class="mr-btn mr-btn-secondary">${getSvgIcon('refreshCw')} Check Metadata Sizes</button>
</div>
<div id="mr-options-metadata-size-status" class="mr-options-db-message">Not checked yet.</div>
</div>
<div class="mr-options-db-actions">
<button id="mr-options-metadata-size-scan" type="button" class="mr-btn mr-btn-secondary">${getSvgIcon('refreshCw')} Check Metadata Sizes</button>
</div>
<div id="mr-options-metadata-size-status" class="mr-options-db-message">Not checked yet.</div>
<div id="mr-options-metadata-size-results" class="mr-options-audit-results" hidden></div>
</div>
</div>
@@ -782,57 +787,62 @@ export const optionsMethods = {
</section>
<section id="mr-options-section-metadata-build" class="mr-options-card mr-options-section mr-options-section-fill is-hidden">
<div class="mr-options-section-head">
<h4 class="mr-options-section-title">Local Metadata Builder</h4>
<button id="mr-options-metadata-build-collapse-toggle" type="button" class="mr-options-section-title mr-options-collapse-title" aria-expanded="true" aria-controls="mr-options-metadata-build-controls">
<span>Local Metadata Builder</span>
<span class="mr-options-collapse-chevron" aria-hidden="true">${getSvgIcon('chevronDown')}</span>
</button>
</div>
<div class="mr-options-grid">
<div class="mr-options-panel">
<div class="mr-options-stack mr-options-build-stack">
<div class="mr-options-db-summary">
<div class="mr-options-db-row">
<span>CPU cores</span>
<strong id="mr-options-metadata-build-cpu">Detecting</strong>
<div id="mr-options-metadata-build-controls" class="mr-options-metadata-build-controls">
<div class="mr-options-db-summary mr-options-metadata-build-summary">
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('cpu')}</span>
<span class="mr-options-overview-stat-copy"><span>CPU cores</span><strong id="mr-options-metadata-build-cpu">Detecting</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('users')}</span>
<span class="mr-options-overview-stat-copy"><span>Workers</span><strong id="mr-options-metadata-build-workers">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('search')}</span>
<span class="mr-options-overview-stat-copy"><span>Models scanned</span><strong id="mr-options-metadata-build-scanned">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('circlePlus')}</span>
<span class="mr-options-overview-stat-copy"><span>Created</span><strong id="mr-options-metadata-build-created">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('pencil')}</span>
<span class="mr-options-overview-stat-copy"><span>Updated</span><strong id="mr-options-metadata-build-updated">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('circleCheckBig')}</span>
<span class="mr-options-overview-stat-copy"><span>Already complete</span><strong id="mr-options-metadata-build-skipped">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('hash')}</span>
<span class="mr-options-overview-stat-copy"><span>Hashes calculated</span><strong id="mr-options-metadata-build-hashes">0</strong></span>
</div>
<div class="mr-options-db-row">
<span class="mr-options-overview-stat-icon" aria-hidden="true">${getSvgIcon('triangleAlert')}</span>
<span class="mr-options-overview-stat-copy"><span>Errors</span><strong id="mr-options-metadata-build-errors">0</strong></span>
</div>
</div>
<div class="mr-options-db-row">
<span>Workers</span>
<strong id="mr-options-metadata-build-workers">0</strong>
<div class="mr-options-number-row mr-options-wide-row">
<div class="mr-options-number-copy">
<span class="mr-options-label">Concurrent hash workers</span>
<span id="mr-options-metadata-build-worker-hint" class="mr-options-db-message mr-options-inline-hint">Loading CPU details...</span>
</div>
<input id="mr-options-metadata-build-worker-count" class="mr-options-input" type="number" min="1" max="64" step="1" value="1">
</div>
<div class="mr-options-db-row">
<span>Models scanned</span>
<strong id="mr-options-metadata-build-scanned">0</strong>
</div>
<div class="mr-options-db-row">
<span>Created</span>
<strong id="mr-options-metadata-build-created">0</strong>
</div>
<div class="mr-options-db-row">
<span>Updated</span>
<strong id="mr-options-metadata-build-updated">0</strong>
</div>
<div class="mr-options-db-row">
<span>Already complete</span>
<strong id="mr-options-metadata-build-skipped">0</strong>
</div>
<div class="mr-options-db-row">
<span>Hashes calculated</span>
<strong id="mr-options-metadata-build-hashes">0</strong>
</div>
<div class="mr-options-db-row">
<span>Errors</span>
<strong id="mr-options-metadata-build-errors">0</strong>
<div class="mr-options-db-actions">
<button id="mr-options-metadata-build-start" type="button" class="mr-btn mr-btn-secondary">${getSvgIcon('fileText')} Build Local Metadata</button>
<button id="mr-options-metadata-build-cancel" type="button" class="mr-btn mr-btn-secondary" hidden>${getSvgIcon('x')} Cancel</button>
</div>
<div id="mr-options-metadata-build-status" class="mr-options-db-message">Not started yet.</div>
</div>
<div class="mr-options-number-row mr-options-wide-row">
<div class="mr-options-number-copy">
<span class="mr-options-label">Concurrent hash workers</span>
<span id="mr-options-metadata-build-worker-hint" class="mr-options-db-message mr-options-inline-hint">Loading CPU details...</span>
</div>
<input id="mr-options-metadata-build-worker-count" class="mr-options-input" type="number" min="1" max="64" step="1" value="1">
</div>
<div class="mr-options-db-actions">
<button id="mr-options-metadata-build-start" type="button" class="mr-btn mr-btn-secondary">${getSvgIcon('fileText')} Build Local Metadata</button>
<button id="mr-options-metadata-build-cancel" type="button" class="mr-btn mr-btn-secondary" hidden>${getSvgIcon('x')} Cancel</button>
</div>
<div id="mr-options-metadata-build-status" class="mr-options-db-message">Not started yet.</div>
<div class="mr-tabs mr-options-build-tabs" role="tablist" aria-label="Metadata builder views">
<button type="button" class="mr-tab mr-options-build-tab mr-tab-active is-active" data-build-tab="progress" role="tab" aria-selected="true">
<span class="mr-tab-label">Progress</span>
@@ -954,6 +964,9 @@ export const optionsMethods = {
const metadataSizeMismatchesEl = this.contentElement.querySelector('#mr-options-metadata-size-mismatches');
const metadataSizeMissingEl = this.contentElement.querySelector('#mr-options-metadata-size-missing');
const metadataSizeErrorsEl = this.contentElement.querySelector('#mr-options-metadata-size-errors');
const metadataSizeCollapseToggle = this.contentElement.querySelector('#mr-options-metadata-size-collapse-toggle');
const metadataSizeControls = this.contentElement.querySelector('#mr-options-metadata-size-controls');
const metadataSizeStack = this.contentElement.querySelector('.mr-options-metadata-size-stack');
const metadataBuildStartBtn = this.contentElement.querySelector('#mr-options-metadata-build-start');
const metadataBuildCancelBtn = this.contentElement.querySelector('#mr-options-metadata-build-cancel');
const metadataBuildStatus = this.contentElement.querySelector('#mr-options-metadata-build-status');
@@ -980,6 +993,9 @@ export const optionsMethods = {
const metadataBuildSkippedEl = this.contentElement.querySelector('#mr-options-metadata-build-skipped');
const metadataBuildHashesEl = this.contentElement.querySelector('#mr-options-metadata-build-hashes');
const metadataBuildErrorsEl = this.contentElement.querySelector('#mr-options-metadata-build-errors');
const metadataBuildCollapseToggle = this.contentElement.querySelector('#mr-options-metadata-build-collapse-toggle');
const metadataBuildControls = this.contentElement.querySelector('#mr-options-metadata-build-controls');
const metadataBuildStack = this.contentElement.querySelector('.mr-options-build-stack');
const optionsMain = this.contentElement.querySelector('.mr-options-main');
const navButtons = Array.from(this.contentElement.querySelectorAll('.mr-options-nav-btn'));
const optionSections = Array.from(this.contentElement.querySelectorAll('.mr-options-section'));
@@ -1151,6 +1167,46 @@ export const optionsMethods = {
setStatusMode(element, mode);
};
const setMetadataSizeControlsCollapsed = (collapsed, persist = true) => {
const isCollapsed = Boolean(collapsed);
this.metadataSizeControlsCollapsed = isCollapsed;
if (metadataSizeControls) {
metadataSizeControls.hidden = isCollapsed;
}
if (metadataSizeStack) {
metadataSizeStack.classList.toggle('is-controls-collapsed', isCollapsed);
}
if (metadataSizeCollapseToggle) {
metadataSizeCollapseToggle.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
this.setTooltip?.(
metadataSizeCollapseToggle,
isCollapsed ? 'Show metadata size audit controls' : 'Hide metadata size audit controls'
);
}
if (persist) {
try {
localStorage.setItem(
this.metadataSizeControlsCollapsedStorageKey || 'model_resolver_metadata_size_controls_collapsed',
isCollapsed ? '1' : '0'
);
} catch (error) {
console.warn('Model Resolver: could not save metadata size audit collapse state:', error);
}
}
};
if (!this.metadataSizeControlsCollapsedStorageKey) {
this.metadataSizeControlsCollapsedStorageKey = 'model_resolver_metadata_size_controls_collapsed';
}
if (typeof this.metadataSizeControlsCollapsed !== 'boolean') {
try {
this.metadataSizeControlsCollapsed = localStorage.getItem(this.metadataSizeControlsCollapsedStorageKey) === '1';
} catch (error) {
this.metadataSizeControlsCollapsed = false;
}
}
setMetadataSizeControlsCollapsed(this.metadataSizeControlsCollapsed, false);
const updateMetadataSizeAuditSummary = (data = {}) => {
const mismatchCount = Number(data.mismatch_count || 0);
const missingSizeCount = Number(data.missing_size || 0);
@@ -1325,6 +1381,47 @@ export const optionsMethods = {
setStatusMode(element, mode);
};
const setMetadataBuildControlsCollapsed = (collapsed, persist = true) => {
const isCollapsed = Boolean(collapsed);
this.metadataBuildControlsCollapsed = isCollapsed;
if (metadataBuildControls) {
metadataBuildControls.hidden = isCollapsed;
}
if (metadataBuildStack) {
metadataBuildStack.classList.toggle('is-controls-collapsed', isCollapsed);
}
if (metadataBuildCollapseToggle) {
metadataBuildCollapseToggle.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
metadataBuildCollapseToggle.classList.toggle('is-collapsed', isCollapsed);
this.setTooltip?.(
metadataBuildCollapseToggle,
isCollapsed ? 'Show metadata builder controls' : 'Hide metadata builder controls'
);
}
if (persist) {
try {
localStorage.setItem(
this.metadataBuildControlsCollapsedStorageKey || 'model_resolver_metadata_build_controls_collapsed',
isCollapsed ? '1' : '0'
);
} catch (error) {
console.warn('Model Resolver: could not save metadata builder collapse state:', error);
}
}
};
if (!this.metadataBuildControlsCollapsedStorageKey) {
this.metadataBuildControlsCollapsedStorageKey = 'model_resolver_metadata_build_controls_collapsed';
}
if (typeof this.metadataBuildControlsCollapsed !== 'boolean') {
try {
this.metadataBuildControlsCollapsed = localStorage.getItem(this.metadataBuildControlsCollapsedStorageKey) === '1';
} catch (error) {
this.metadataBuildControlsCollapsed = false;
}
}
setMetadataBuildControlsCollapsed(this.metadataBuildControlsCollapsed, false);
let scheduleMetadataBuildHistoryRender = () => {};
const setMetadataBuildPanelHidden = (panel, hidden) => {
if (!panel) return;
@@ -3066,6 +3163,18 @@ export const optionsMethods = {
});
}
if (metadataSizeCollapseToggle) {
metadataSizeCollapseToggle.addEventListener('click', () => {
setMetadataSizeControlsCollapsed(!this.metadataSizeControlsCollapsed);
});
}
if (metadataBuildCollapseToggle) {
metadataBuildCollapseToggle.addEventListener('click', () => {
setMetadataBuildControlsCollapsed(!this.metadataBuildControlsCollapsed);
});
}
if (metadataBuildStartBtn) {
metadataBuildStartBtn.addEventListener('click', () => {
runMetadataBuild();
+9
View File
@@ -2,10 +2,19 @@
import { app } from "../../../scripts/app.js";
const SVG_ICONS = {
chevronDown: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>`,
circleCheckBig: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21.801 10A10 10 0 1 1 17 3.335"></path><path d="m9 11 3 3L22 4"></path></svg>`,
circlePlus: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M8 12h8"></path><path d="M12 8v8"></path></svg>`,
file: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path></svg>`,
fileCheck: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path><path d="m9 15 2 2 4-4"></path></svg>`,
fileQuestion: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path><path d="M9.1 9a3 3 0 0 1 5.8 1c0 2-3 2-3 4"></path><path d="M12 17h.01"></path></svg>`,
fileText: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path><path d="M10 9H8"></path><path d="M16 13H8"></path><path d="M16 17H8"></path></svg>`,
hash: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="4" x2="20" y1="9" y2="9"></line><line x1="4" x2="20" y1="15" y2="15"></line><line x1="10" x2="8" y1="3" y2="21"></line><line x1="16" x2="14" y1="3" y2="21"></line></svg>`,
cpu: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="5" y="5" rx="2"></rect><rect width="6" height="6" x="9" y="9" rx="1"></rect><path d="M9 1v4"></path><path d="M15 1v4"></path><path d="M9 19v4"></path><path d="M15 19v4"></path><path d="M1 9h4"></path><path d="M1 15h4"></path><path d="M19 9h4"></path><path d="M19 15h4"></path></svg>`,
pencil: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>`,
triangleAlert: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg>`,
users: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>`,
scale: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"></path><path d="m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z"></path><path d="M7 21h10"></path><path d="M12 3v18"></path><path d="M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2"></path></svg>`,
box: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"></path><path d="m3.3 7 8.7 5 8.7-5"></path><path d="M12 22V12"></path></svg>`,
hardDrive: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 16h.01"></path><path d="M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path><path d="M21.946 12.013H2.054"></path><path d="M6 16h.01"></path></svg>`,
bookType: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13h4"></path><path d="M12 6v7"></path><path d="M16 8V6H8v2"></path><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20"></path></svg>`,