mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
feat: add semantic color palette and lint guard
This commit is contained in:
1 parent
6cf2a01383
commit
e767316501
14 files changed
+639
-196
No files matched your search
@@ -357,7 +357,7 @@
|
||||
</p>
|
||||
<div
|
||||
id="profileHistoryFeatureBanner"
|
||||
class="card hidden border border-amber-500/40 bg-amber-500/10 px-4 py-3 text-sm text-amber-100"
|
||||
class="card hidden border border-status-warning-border bg-status-warning-surface px-4 py-3 text-sm text-status-warning-on"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
></div>
|
||||
@@ -424,7 +424,8 @@
|
||||
></div>
|
||||
<div
|
||||
id="profileHistorySessionWarning"
|
||||
class="hidden inline-flex items-center gap-2 rounded-full border border-amber-500/50 bg-amber-500/10 px-3 py-1 text-xs font-medium text-amber-100"
|
||||
class="hidden pill"
|
||||
data-variant="warning"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
|
||||
@@ -1049,7 +1049,7 @@
|
||||
<div id="cloudflareUploadSection" class="hidden">
|
||||
<div class="space-y-8">
|
||||
<p
|
||||
class="rounded-md border border-amber-500/40 bg-amber-500/10 p-3 text-sm text-amber-300"
|
||||
class="rounded-md border border-status-warning-border bg-status-warning-surface p-3 text-sm text-status-warning-on"
|
||||
>
|
||||
This feature is experimental and may not be working correctly.
|
||||
</p>
|
||||
|
||||
+75
-7
@@ -637,19 +637,87 @@
|
||||
}
|
||||
|
||||
.badge {
|
||||
@apply inline-flex items-center gap-1 rounded-full bg-panel px-3 py-1 text-xs font-semibold uppercase tracking-wide text-muted-strong;
|
||||
}
|
||||
|
||||
.badge[data-variant="critical"] {
|
||||
@apply bg-critical bg-opacity-20 text-critical-strong;
|
||||
@apply inline-flex items-center gap-1 rounded-full border border-status-neutral-border bg-status-neutral-surface px-3 py-1 text-2xs font-semibold uppercase tracking-extra-wide text-status-neutral-on;
|
||||
}
|
||||
|
||||
.badge[data-variant="info"] {
|
||||
@apply bg-info bg-opacity-20 text-info-strong;
|
||||
@apply border-status-info-border bg-status-info-surface text-status-info-on;
|
||||
}
|
||||
|
||||
.badge[data-variant="success"] {
|
||||
@apply border-status-success-border bg-status-success-surface text-status-success-on;
|
||||
}
|
||||
|
||||
.badge[data-variant="warning"] {
|
||||
@apply border-status-warning-border bg-status-warning-surface text-status-warning-on;
|
||||
}
|
||||
|
||||
.badge[data-variant="critical"] {
|
||||
@apply border-status-danger-border bg-status-danger-surface text-status-danger-on;
|
||||
}
|
||||
|
||||
.badge[data-variant="private"] {
|
||||
@apply border-status-private-border bg-status-private-surface text-status-private-on;
|
||||
}
|
||||
|
||||
.badge[data-variant="neutral"] {
|
||||
@apply bg-border bg-opacity-40 text-muted-strong;
|
||||
@apply border-status-neutral-border bg-status-neutral-surface text-status-neutral-on;
|
||||
}
|
||||
|
||||
.pill {
|
||||
@apply inline-flex items-center gap-2 rounded-full border border-status-neutral-border bg-status-neutral-surface px-3 py-1 text-xs font-medium text-status-neutral-on;
|
||||
}
|
||||
|
||||
.pill[data-size="compact"] {
|
||||
@apply px-2 py-0.5 text-2xs;
|
||||
}
|
||||
|
||||
.pill[data-variant="info"] {
|
||||
@apply border-status-info-border bg-status-info-surface text-status-info-on;
|
||||
}
|
||||
|
||||
.pill[data-variant="success"] {
|
||||
@apply border-status-success-border bg-status-success-surface text-status-success-on;
|
||||
}
|
||||
|
||||
.pill[data-variant="warning"] {
|
||||
@apply border-status-warning-border bg-status-warning-surface text-status-warning-on;
|
||||
}
|
||||
|
||||
.pill[data-variant="critical"] {
|
||||
@apply border-status-danger-border bg-status-danger-surface text-status-danger-on;
|
||||
}
|
||||
|
||||
.pill[data-variant="private"] {
|
||||
@apply border-status-private-border bg-status-private-surface text-status-private-on;
|
||||
}
|
||||
|
||||
.pill[data-variant="neutral"] {
|
||||
@apply border-status-neutral-border bg-status-neutral-surface text-status-neutral-on;
|
||||
}
|
||||
|
||||
.overlay-scrim {
|
||||
background-color: var(--surface-overlay);
|
||||
}
|
||||
|
||||
.overlay-scrim[data-strength="muted"] {
|
||||
background-color: var(--surface-overlay-muted);
|
||||
}
|
||||
|
||||
.overlay-scrim[data-strength="strong"] {
|
||||
background-color: var(--surface-overlay-strong);
|
||||
}
|
||||
|
||||
.overlay-panel {
|
||||
background-color: var(--surface-overlay-panel);
|
||||
}
|
||||
|
||||
.overlay-panel[data-variant="soft"] {
|
||||
background-color: var(--surface-overlay-panel-soft);
|
||||
}
|
||||
|
||||
.overlay-panel[data-variant="glass"] {
|
||||
background-color: var(--surface-overlay-panel-glass);
|
||||
}
|
||||
|
||||
.menu {
|
||||
|
||||
+100
@@ -101,6 +101,88 @@
|
||||
--color-text-frosted: rgb(226 232 240 / 0.9);
|
||||
--color-text-frosted-soft: rgb(226 232 240 / 0.82);
|
||||
|
||||
/* Semantic palette */
|
||||
--surface-base: var(--color-surface);
|
||||
--surface-alt: var(--color-surface-alt);
|
||||
--surface-raised: var(--color-card);
|
||||
--surface-raised-private: var(--color-card-private);
|
||||
--surface-raised-critical: var(--color-card-critical);
|
||||
--surface-panel: var(--color-panel);
|
||||
--surface-panel-hover: var(--color-panel-hover);
|
||||
--surface-sunken: rgb(11 17 32 / 0.92);
|
||||
--surface-muted: rgb(30 41 59 / 0.82);
|
||||
--surface-veil: var(--color-overlay-veil);
|
||||
--surface-inverse: var(--color-page);
|
||||
|
||||
--surface-overlay: var(--color-overlay);
|
||||
--surface-overlay-muted: var(--color-overlay-muted);
|
||||
--surface-overlay-strong: var(--color-overlay-strong);
|
||||
--surface-overlay-darker: var(--color-overlay-darker);
|
||||
--surface-overlay-black: var(--color-overlay-black);
|
||||
--surface-overlay-banner: var(--color-overlay-banner);
|
||||
--surface-overlay-panel: var(--color-overlay-panel);
|
||||
--surface-overlay-panel-soft: var(--color-overlay-panel-soft);
|
||||
--surface-overlay-panel-tint: var(--color-overlay-panel-tint);
|
||||
--surface-overlay-panel-glass: var(--color-overlay-panel-glass);
|
||||
--surface-overlay-panel-glass-soft: var(--color-overlay-panel-glass-soft);
|
||||
--surface-modal-backdrop: var(--color-modal-backdrop);
|
||||
--surface-modal: var(--color-modal-surface);
|
||||
|
||||
--border-default: var(--color-border);
|
||||
--border-subtle: var(--color-border-subtle);
|
||||
--border-strong: var(--color-border-translucent-stronger);
|
||||
--border-overlay: var(--color-border-translucent);
|
||||
--border-overlay-strong: var(--color-border-translucent-strongest);
|
||||
--border-overlay-glow: var(--color-border-translucent-glow);
|
||||
--border-neutral-soft: var(--color-border-neutral-soft);
|
||||
--border-info-soft: var(--color-border-info-soft);
|
||||
--border-sidebar-strong: var(--color-border-sidebar-strong);
|
||||
|
||||
--text-primary: var(--color-text);
|
||||
--text-inverse: var(--color-text-strong);
|
||||
--text-muted: var(--color-text-muted);
|
||||
--text-muted-strong: var(--color-muted-strong);
|
||||
--text-subtle: var(--color-subtle-text);
|
||||
--text-frosted-primary: var(--color-text-frosted);
|
||||
--text-frosted-strong: var(--color-text-frosted-strong);
|
||||
--text-frosted-soft: var(--color-text-frosted-soft);
|
||||
|
||||
--status-info: var(--color-info);
|
||||
--status-info-strong: var(--color-info-strong);
|
||||
--status-info-surface: var(--color-info-glass);
|
||||
--status-info-border: rgb(96 165 250 / 0.4);
|
||||
--status-info-on: rgb(219 234 254);
|
||||
|
||||
--status-success: rgb(34 197 94);
|
||||
--status-success-strong: rgb(22 163 74);
|
||||
--status-success-surface: rgb(22 163 74 / 0.28);
|
||||
--status-success-border: rgb(34 197 94 / 0.4);
|
||||
--status-success-on: rgb(220 252 231);
|
||||
|
||||
--status-warning: var(--color-warning);
|
||||
--status-warning-strong: var(--color-warning-strong);
|
||||
--status-warning-surface: var(--color-warning-surface);
|
||||
--status-warning-border: rgb(217 119 6 / 0.45);
|
||||
--status-warning-on: rgb(254 249 195);
|
||||
|
||||
--status-danger: var(--color-critical);
|
||||
--status-danger-strong: var(--color-critical-strong);
|
||||
--status-danger-surface: rgb(127 29 29 / 0.32);
|
||||
--status-danger-border: rgb(239 68 68 / 0.45);
|
||||
--status-danger-on: rgb(254 202 202);
|
||||
|
||||
--status-private: rgb(168 85 247);
|
||||
--status-private-strong: rgb(147 51 234);
|
||||
--status-private-surface: rgb(91 33 182 / 0.32);
|
||||
--status-private-border: rgb(168 85 247 / 0.45);
|
||||
--status-private-on: rgb(233 213 255);
|
||||
|
||||
--status-neutral: var(--color-muted);
|
||||
--status-neutral-strong: var(--color-muted-strong);
|
||||
--status-neutral-surface: rgb(148 163 184 / 0.25);
|
||||
--status-neutral-border: rgb(148 163 184 / 0.35);
|
||||
--status-neutral-on: rgb(226 232 240);
|
||||
|
||||
/* Layout & stacking */
|
||||
--scrollbar-width: 0.5rem;
|
||||
--scrollbar-track: var(--color-white-soft);
|
||||
@@ -530,6 +612,24 @@
|
||||
--shadow-sidebar-panel: 0 2.25rem 4.5rem -1.85rem rgb(15 23 42 / 0.28);
|
||||
--shadow-sidebar-focus-ring: 0 0 0 0.125rem rgb(59 130 246 / 0.35),
|
||||
0 0 0 0.25rem rgb(59 130 246 / 0.28);
|
||||
|
||||
--surface-sunken: rgb(229 231 235 / 0.85);
|
||||
--surface-muted: rgb(226 232 240 / 0.85);
|
||||
--text-primary: var(--color-text);
|
||||
--text-inverse: var(--color-white);
|
||||
--text-muted: var(--color-text-muted);
|
||||
--text-muted-strong: var(--color-muted-strong);
|
||||
--text-subtle: var(--color-subtle-text);
|
||||
--status-info-border: rgb(59 130 246 / 0.35);
|
||||
--status-success-surface: rgb(34 197 94 / 0.18);
|
||||
--status-success-border: rgb(16 185 129 / 0.32);
|
||||
--status-warning-border: rgb(217 119 6 / 0.35);
|
||||
--status-danger-surface: rgb(220 38 38 / 0.18);
|
||||
--status-danger-border: rgb(220 38 38 / 0.32);
|
||||
--status-private-surface: rgb(147 51 234 / 0.22);
|
||||
--status-private-border: rgb(147 51 234 / 0.32);
|
||||
--status-neutral-surface: rgb(100 116 139 / 0.18);
|
||||
--status-neutral-border: rgb(100 116 139 / 0.3);
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
|
||||
@@ -85,6 +85,22 @@ The blog embed now consumes dedicated typography and spacing tokens alongside Ta
|
||||
|
||||
Templates should reference these tokens (directly or via Tailwind arbitrary values) instead of hard-coded measurements so the embed stays in sync with future blog refreshes.
|
||||
|
||||
## Semantic Palette
|
||||
|
||||
All interactive surfaces now draw from a shared semantic color map exposed through `css/tokens.css` and Tailwind utility aliases. The palette is grouped into text, surface, overlay, and status slots so controllers can swap state styles without reaching for raw Tailwind hues:
|
||||
|
||||
- **Text:** `text-primary`, `text-inverse`, `text-muted`, `text-muted-strong`, and `text-subtle` map to `--text-*` tokens. Use them for copy, helper text, and frosted overlays instead of `text-gray-*`.
|
||||
- **Surfaces:** `bg-surface`, `bg-surface-alt`, `bg-surface-raised`, `bg-surface-muted`, and `bg-overlay-*` wrap cards, modals, and scrims. Pair them with `border-surface`, `border-overlay`, or `border-overlay-strong` when rendering shells.
|
||||
- **Statuses:** `status-*` tokens expose matching text, background, and border slots. Tailwind utilities include `text-status-success`, `bg-status-warning-surface`, `border-status-danger-border`, and chip helpers (`.pill`, `.badge`) that accept `data-variant="info" | "success" | "warning" | "critical" | "private" | "neutral"`.
|
||||
- **Overlays:** `.overlay-scrim` and `.overlay-panel` helpers consume the overlay tier tokens for modals, sheets, and popovers. Adjust the strength via `data-strength`/`data-variant` rather than applying translucent grays.
|
||||
|
||||
### Migration guidance
|
||||
|
||||
- Swap raw Tailwind palette utilities (for example, `text-gray-400`, `bg-amber-500/10`, `border-red-700/70`) for the matching semantic utilities above. The new lint (`npm run lint:tailwind-colors`) fails when legacy color classes appear outside deprecated directories.
|
||||
- Replace ad-hoc chips (`inline-flex ... border-red-700/70 bg-red-900/40`) with `.pill` or `.badge` plus a `data-variant`. These helpers automatically pull the correct status text/border/fill tokens.
|
||||
- Use `text-info`/`hover:text-info-strong` for links that previously relied on `text-blue-400` so anchors adapt in both light and dark modes.
|
||||
- When rendering tinted descriptions or placeholders, prefer `text-muted`, `text-muted-strong`, or `text-subtle` over semi-transparent whites. Token overrides keep the same classes usable across the default and light themes.
|
||||
|
||||
### Blog carousel markup
|
||||
|
||||
The short-notes carousel ships as a semantic wrapper around the `blog-carousel` primitive defined in `css/tailwind.source.css`. The runtime no longer injects inline styles or Splide classes—layout is driven entirely by data attributes that map onto tokenised CSS rules.
|
||||
|
||||
+10
-9
@@ -10,16 +10,17 @@ import { makeR2Client, multipartUpload } from "./storage/r2-s3.js";
|
||||
|
||||
const STORAGE_KEY = "bitvid:quickR2Settings";
|
||||
const STATUS_CLASSNAMES = [
|
||||
"text-gray-400",
|
||||
"text-green-400",
|
||||
"text-red-400",
|
||||
"text-yellow-400",
|
||||
"text-status-neutral",
|
||||
"text-status-info",
|
||||
"text-status-success",
|
||||
"text-status-danger",
|
||||
"text-status-warning",
|
||||
];
|
||||
const STATUS_TONES = {
|
||||
info: "text-gray-400",
|
||||
success: "text-green-400",
|
||||
error: "text-red-400",
|
||||
warning: "text-yellow-400",
|
||||
info: "text-status-info",
|
||||
success: "text-status-success",
|
||||
error: "text-status-danger",
|
||||
warning: "text-status-warning",
|
||||
};
|
||||
|
||||
function sanitizeDomain(value) {
|
||||
@@ -71,7 +72,7 @@ function setStatus(el, message, tone = "info") {
|
||||
return;
|
||||
}
|
||||
STATUS_CLASSNAMES.forEach((cls) => el.classList.remove(cls));
|
||||
const className = STATUS_TONES[tone] || STATUS_TONES.info;
|
||||
const className = STATUS_TONES[tone] || "text-status-neutral";
|
||||
if (className) {
|
||||
el.classList.add(className);
|
||||
}
|
||||
|
||||
+123
-123
@@ -385,7 +385,7 @@ export class RevertModal {
|
||||
|
||||
if (!this.revisions.length) {
|
||||
this.list.innerHTML =
|
||||
'<p class="text-xs text-gray-500">No revisions found.</p>';
|
||||
'<p class="text-xs text-subtle">No revisions found.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -417,36 +417,36 @@ export class RevertModal {
|
||||
"focus:outline-none",
|
||||
"focus:ring-2",
|
||||
"focus:ring-offset-2",
|
||||
"focus:ring-offset-gray-900",
|
||||
"focus:ring-offset-surface",
|
||||
];
|
||||
|
||||
if (isSelected) {
|
||||
classes.push(
|
||||
"border-blue-500",
|
||||
"bg-blue-500/20",
|
||||
"text-blue-100",
|
||||
"focus:ring-blue-500"
|
||||
"border-status-info-border",
|
||||
"bg-status-info-surface",
|
||||
"text-status-info-on",
|
||||
"focus:ring-status-info"
|
||||
);
|
||||
} else if (isCurrent) {
|
||||
classes.push(
|
||||
"border-green-500/60",
|
||||
"bg-green-500/10",
|
||||
"text-green-100",
|
||||
"focus:ring-green-500/80"
|
||||
"border-status-success-border",
|
||||
"bg-status-success-surface",
|
||||
"text-status-success-on",
|
||||
"focus:ring-status-success"
|
||||
);
|
||||
} else if (isDeleted) {
|
||||
classes.push(
|
||||
"border-red-800/70",
|
||||
"bg-red-900/30",
|
||||
"text-red-200/90",
|
||||
"hover:bg-red-900/40"
|
||||
"border-status-danger-border",
|
||||
"bg-status-danger-surface",
|
||||
"text-status-danger-on",
|
||||
"hover:border-status-danger-border"
|
||||
);
|
||||
} else {
|
||||
classes.push(
|
||||
"border-gray-800",
|
||||
"bg-gray-800/60",
|
||||
"hover:bg-gray-700/70",
|
||||
"text-gray-200"
|
||||
"border-overlay",
|
||||
"bg-overlay-panel-soft",
|
||||
"hover:bg-overlay-panel",
|
||||
"text-primary"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -478,8 +478,8 @@ export class RevertModal {
|
||||
}
|
||||
const meta = metaParts.join(" • ");
|
||||
const metaClass = entry.deleted
|
||||
? "text-red-200/80"
|
||||
: "text-gray-400";
|
||||
? "text-status-danger-on"
|
||||
: "text-muted";
|
||||
|
||||
const escape = (value) =>
|
||||
this.escapeHTML ? this.escapeHTML(String(value ?? "")) : String(value ?? "");
|
||||
@@ -488,10 +488,10 @@ export class RevertModal {
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="space-y-1">
|
||||
<p class="font-semibold">${escape(entry.title || "Untitled")}</p>
|
||||
<p class="text-xs text-gray-300">${escape(relative)} • ${escape(absolute)}</p>
|
||||
<p class="text-xs text-subtle">${escape(relative)} • ${escape(absolute)}</p>
|
||||
${meta ? `<p class="text-xs ${metaClass}">${escape(meta)}</p>` : ""}
|
||||
</div>
|
||||
<div class="text-xs uppercase tracking-wide text-gray-400">
|
||||
<div class="text-xs uppercase tracking-wide text-muted">
|
||||
${escape(versionLabel)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -588,7 +588,7 @@ export class RevertModal {
|
||||
: displayMagnet;
|
||||
const label = escape(labelRaw);
|
||||
const caption = isPrivate
|
||||
? '<span class="block text-xs text-purple-200/90 mt-1">Magnet stays visible only to you — private notes keep the raw string local.</span>'
|
||||
? '<span class="block mt-1 text-xs text-status-private-on">Magnet stays visible only to you — private notes keep the raw string local.</span>'
|
||||
: "";
|
||||
magnetHtml = `<div class="break-all">${label}${caption}</div>`;
|
||||
}
|
||||
@@ -599,33 +599,33 @@ export class RevertModal {
|
||||
const conflictingAudienceFlags = nsfwFlag && forKidsFlag;
|
||||
if (version.deleted) {
|
||||
chips.push(
|
||||
'<span class="inline-flex items-center rounded-full border border-red-700/70 bg-red-900/40 px-2 py-0.5 text-xs text-red-200/90">Marked deleted</span>'
|
||||
'<span class="pill" data-size="compact" data-variant="critical">Marked deleted</span>'
|
||||
);
|
||||
}
|
||||
if (isPrivate) {
|
||||
chips.push(
|
||||
'<span class="inline-flex items-center rounded-full border border-purple-600/60 bg-purple-900/40 px-2 py-0.5 text-xs text-purple-200/90">Private</span>'
|
||||
'<span class="pill" data-size="compact" data-variant="private">Private</span>'
|
||||
);
|
||||
}
|
||||
if (conflictingAudienceFlags) {
|
||||
chips.push(
|
||||
'<span class="inline-flex items-center rounded-full border border-amber-700/70 bg-amber-900/40 px-2 py-0.5 text-xs text-amber-200/90">NSFW + For kids conflict</span>'
|
||||
'<span class="pill" data-size="compact" data-variant="warning">NSFW + For kids conflict</span>'
|
||||
);
|
||||
} else {
|
||||
if (nsfwFlag) {
|
||||
chips.push(
|
||||
'<span class="inline-flex items-center rounded-full border border-red-700/70 bg-red-900/40 px-2 py-0.5 text-xs text-red-200/90">Marked NSFW</span>'
|
||||
'<span class="pill" data-size="compact" data-variant="critical">Marked NSFW</span>'
|
||||
);
|
||||
}
|
||||
if (forKidsFlag) {
|
||||
chips.push(
|
||||
'<span class="inline-flex items-center rounded-full border border-emerald-700/70 bg-emerald-900/40 px-2 py-0.5 text-xs text-emerald-200/90">For kids</span>'
|
||||
'<span class="pill" data-size="compact" data-variant="success">For kids</span>'
|
||||
);
|
||||
}
|
||||
}
|
||||
if (version.version !== undefined) {
|
||||
chips.push(
|
||||
`<span class="inline-flex items-center rounded-full border border-gray-700 bg-gray-800/80 px-2 py-0.5 text-xs text-gray-200">Schema v${escape(
|
||||
`<span class="pill" data-size="compact" data-variant="neutral">Schema v${escape(
|
||||
String(version.version)
|
||||
)}</span>`
|
||||
);
|
||||
@@ -637,10 +637,10 @@ export class RevertModal {
|
||||
unspecifiedLabel = "Not specified",
|
||||
} = {}) => {
|
||||
if (value === true) {
|
||||
return `<span class="text-gray-200">${escape(yesLabel)}</span>`;
|
||||
return `<span class="text-primary">${escape(yesLabel)}</span>`;
|
||||
}
|
||||
if (value === false) {
|
||||
return `<span class="text-gray-200">${escape(noLabel)}</span>`;
|
||||
return `<span class="text-primary">${escape(noLabel)}</span>`;
|
||||
}
|
||||
return this.renderPlaceholder(unspecifiedLabel);
|
||||
};
|
||||
@@ -657,12 +657,12 @@ export class RevertModal {
|
||||
});
|
||||
|
||||
const audienceConflictNotice = conflictingAudienceFlags
|
||||
? '<p class="text-xs text-amber-300">Conflicting flags detected — this revision is marked both NSFW and for kids. Review before reverting.</p>'
|
||||
? '<p class="text-xs text-status-warning-on">Conflicting flags detected — this revision is marked both NSFW and for kids. Review before reverting.</p>'
|
||||
: "";
|
||||
|
||||
const descriptionHtml = description
|
||||
? `<p class="whitespace-pre-wrap text-gray-200">${escape(description)}</p>`
|
||||
: '<p class="text-gray-500">No description provided.</p>';
|
||||
? `<p class="whitespace-pre-wrap text-primary">${escape(description)}</p>`
|
||||
: '<p class="text-subtle">No description provided.</p>';
|
||||
|
||||
const rootId =
|
||||
typeof version.videoRootId === "string" ? version.videoRootId : "";
|
||||
@@ -698,17 +698,17 @@ export class RevertModal {
|
||||
: "";
|
||||
const parts = [];
|
||||
if (absoluteLabel) {
|
||||
parts.push(`<span class="text-gray-200">${escape(absoluteLabel)}</span>`);
|
||||
parts.push(`<span class="text-primary">${escape(absoluteLabel)}</span>`);
|
||||
}
|
||||
if (relativeLabel) {
|
||||
parts.push(`<span class="text-gray-400">(${escape(relativeLabel)})</span>`);
|
||||
parts.push(`<span class="text-muted">(${escape(relativeLabel)})</span>`);
|
||||
}
|
||||
if (parts.length) {
|
||||
return parts.join(" ");
|
||||
}
|
||||
}
|
||||
if (raw) {
|
||||
return `<span class="text-gray-200">${escape(raw)}</span>`;
|
||||
return `<span class="text-primary">${escape(raw)}</span>`;
|
||||
}
|
||||
return this.renderPlaceholder();
|
||||
};
|
||||
@@ -717,12 +717,12 @@ export class RevertModal {
|
||||
if (Number.isFinite(seconds)) {
|
||||
const display = this.formatDurationSeconds(seconds);
|
||||
const suffix = seconds === 1 ? "second" : "seconds";
|
||||
return `<span class="text-gray-200">${escape(display)}</span> <span class="text-gray-500">(${escape(
|
||||
return `<span class="text-primary">${escape(display)}</span> <span class="text-subtle">(${escape(
|
||||
`${seconds} ${suffix}`
|
||||
)})</span>`;
|
||||
}
|
||||
if (raw) {
|
||||
return `<span class="text-gray-200">${escape(raw)}</span>`;
|
||||
return `<span class="text-primary">${escape(raw)}</span>`;
|
||||
}
|
||||
return this.renderPlaceholder();
|
||||
};
|
||||
@@ -740,21 +740,21 @@ export class RevertModal {
|
||||
suffix = "video";
|
||||
}
|
||||
}
|
||||
const badge = `<code class="rounded bg-gray-800/80 px-1.5 py-0.5 text-gray-100">kind ${escape(
|
||||
const badge = `<code class="rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary">kind ${escape(
|
||||
label
|
||||
)}</code>`;
|
||||
kindHtml = suffix
|
||||
? `${badge} <span class="text-gray-400">(${escape(suffix)})</span>`
|
||||
? `${badge} <span class="text-muted">(${escape(suffix)})</span>`
|
||||
: badge;
|
||||
}
|
||||
|
||||
const summaryHtml = nip71Metadata.summary
|
||||
? `<p class="whitespace-pre-wrap text-gray-200">${escape(
|
||||
? `<p class="whitespace-pre-wrap text-primary">${escape(
|
||||
nip71Metadata.summary
|
||||
)}</p>`
|
||||
: this.renderPlaceholder("Not provided");
|
||||
const contentWarningHtml = nip71Metadata.contentWarning
|
||||
? `<span class="inline-flex items-center rounded-full border border-amber-700/70 bg-amber-900/40 px-2 py-0.5 text-xs text-amber-200/90">${escape(
|
||||
? `<span class="pill" data-size="compact" data-variant="warning">${escape(
|
||||
nip71Metadata.contentWarning
|
||||
)}</span>`
|
||||
: this.renderPlaceholder("Not provided");
|
||||
@@ -767,14 +767,14 @@ export class RevertModal {
|
||||
nip71Metadata.durationRaw
|
||||
);
|
||||
const altHtml = nip71Metadata.alt
|
||||
? `<p class="whitespace-pre-wrap text-gray-200">${escape(nip71Metadata.alt)}</p>`
|
||||
? `<p class="whitespace-pre-wrap text-primary">${escape(nip71Metadata.alt)}</p>`
|
||||
: this.renderPlaceholder("Not provided");
|
||||
|
||||
const definition = (label, valueHtml, { span = 1 } = {}) => {
|
||||
const colSpan = span > 1 ? "sm:col-span-2" : "";
|
||||
return `
|
||||
<div class="${colSpan}">
|
||||
<dt class="font-semibold text-gray-200">${escape(label)}</dt>
|
||||
<dt class="font-semibold text-primary">${escape(label)}</dt>
|
||||
<dd class="mt-1">${valueHtml}</dd>
|
||||
</div>
|
||||
`;
|
||||
@@ -797,7 +797,7 @@ export class RevertModal {
|
||||
this.details.innerHTML = `
|
||||
<div class="space-y-6">
|
||||
<div class="flex flex-col gap-4 lg:flex-row lg:items-start">
|
||||
<div class="overflow-hidden rounded-md border border-gray-800 bg-black/40 w-full max-w-sm">
|
||||
<div class="overflow-hidden rounded-md border border-overlay bg-overlay-strong w-full max-w-sm">
|
||||
<img
|
||||
src="${thumbnailSrc}"
|
||||
alt="${escape(thumbnailAlt)}"
|
||||
@@ -807,23 +807,23 @@ export class RevertModal {
|
||||
</div>
|
||||
<div class="flex-1 space-y-3">
|
||||
<div class="space-y-1">
|
||||
<h3 class="text-lg font-semibold text-white">${escape(
|
||||
<h3 class="text-lg font-semibold text-primary">${escape(
|
||||
version.title || "Untitled"
|
||||
)}</h3>
|
||||
<p class="text-xs text-gray-400">${timestampHtml}</p>
|
||||
<p class="text-xs text-muted">${timestampHtml}</p>
|
||||
</div>
|
||||
${
|
||||
chips.length
|
||||
? `<div class="flex flex-wrap gap-2">${chips.join("")}</div>`
|
||||
: ""
|
||||
}
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Hosted URL</dt>
|
||||
<dt class="font-semibold text-primary">Hosted URL</dt>
|
||||
<dd class="mt-1">${urlHtml}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Magnet</dt>
|
||||
<dt class="font-semibold text-primary">Magnet</dt>
|
||||
<dd class="mt-1">${magnetHtml}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@@ -831,65 +831,65 @@ export class RevertModal {
|
||||
</div>
|
||||
|
||||
<section class="space-y-2">
|
||||
<h4 class="text-sm font-semibold text-gray-200">Description</h4>
|
||||
<h4 class="text-sm font-semibold text-primary">Description</h4>
|
||||
${descriptionHtml}
|
||||
</section>
|
||||
|
||||
<section class="space-y-2">
|
||||
<h4 class="text-sm font-semibold text-gray-200">Audience flags</h4>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<h4 class="text-sm font-semibold text-primary">Audience flags</h4>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
${audienceRows}
|
||||
</dl>
|
||||
${audienceConflictNotice}
|
||||
</section>
|
||||
|
||||
<section class="space-y-2">
|
||||
<h4 class="text-sm font-semibold text-gray-200">NIP-71 event metadata</h4>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<h4 class="text-sm font-semibold text-primary">NIP-71 event metadata</h4>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
${eventMetadataRows}
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section class="space-y-2">
|
||||
<h4 class="text-sm font-semibold text-gray-200">Note pointers</h4>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<h4 class="text-sm font-semibold text-primary">Note pointers</h4>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Mode</dt>
|
||||
<dt class="font-semibold text-primary">Mode</dt>
|
||||
<dd class="mt-1">${escape(version.mode || "live")}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">d tag</dt>
|
||||
<dt class="font-semibold text-primary">d tag</dt>
|
||||
<dd class="mt-1">
|
||||
${
|
||||
dTagValue
|
||||
? `<code class="rounded bg-gray-800/80 px-1.5 py-0.5">${escape(
|
||||
? `<code class="rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary">${escape(
|
||||
dTagValue
|
||||
)}</code>`
|
||||
: '<span class="text-gray-500">Not provided</span>'
|
||||
: '<span class="text-subtle">Not provided</span>'
|
||||
}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">videoRootId</dt>
|
||||
<dt class="font-semibold text-primary">videoRootId</dt>
|
||||
<dd class="mt-1">
|
||||
${
|
||||
rootDisplay
|
||||
? `<code class="break-all rounded bg-gray-800/80 px-1.5 py-0.5" title="${escape(
|
||||
? `<code class="break-all rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary" title="${escape(
|
||||
rootId
|
||||
)}">${rootDisplay}</code>`
|
||||
: '<span class="text-gray-500">Not provided</span>'
|
||||
: '<span class="text-subtle">Not provided</span>'
|
||||
}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Event ID</dt>
|
||||
<dt class="font-semibold text-primary">Event ID</dt>
|
||||
<dd class="mt-1">
|
||||
${
|
||||
eventDisplay
|
||||
? `<code class="break-all rounded bg-gray-800/80 px-1.5 py-0.5" title="${escape(
|
||||
? `<code class="break-all rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary" title="${escape(
|
||||
version.id || ""
|
||||
)}">${eventDisplay}</code>`
|
||||
: '<span class="text-gray-500">Unknown</span>'
|
||||
: '<span class="text-subtle">Unknown</span>'
|
||||
}
|
||||
</dd>
|
||||
</div>
|
||||
@@ -897,30 +897,30 @@ export class RevertModal {
|
||||
</section>
|
||||
|
||||
<section class="space-y-4">
|
||||
<h4 class="text-sm font-semibold text-gray-200">NIP-71 media metadata</h4>
|
||||
<h4 class="text-sm font-semibold text-primary">NIP-71 media metadata</h4>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Media variants (imeta)</h5>
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-muted">Media variants (imeta)</h5>
|
||||
${this.renderImetaVariants(nip71Metadata.imeta)}
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Caption tracks</h5>
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-muted">Caption tracks</h5>
|
||||
${this.renderTextTracks(nip71Metadata.textTracks)}
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Chapters</h5>
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-muted">Chapters</h5>
|
||||
${this.renderSegments(nip71Metadata.segments)}
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Hashtags</h5>
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-muted">Hashtags</h5>
|
||||
${this.renderHashtags(nip71Metadata.hashtags)}
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Participants</h5>
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-muted">Participants</h5>
|
||||
${this.renderParticipants(nip71Metadata.participants)}
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-gray-400">References</h5>
|
||||
<h5 class="text-xs font-semibold uppercase tracking-wide text-muted">References</h5>
|
||||
${this.renderReferences(nip71Metadata.references)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1123,12 +1123,12 @@ export class RevertModal {
|
||||
|
||||
renderPlaceholder(text = "Not provided") {
|
||||
const escape = this.getEscapeFn();
|
||||
return `<span class="text-gray-500">${escape(text)}</span>`;
|
||||
return `<span class="text-subtle">${escape(text)}</span>`;
|
||||
}
|
||||
|
||||
renderListEmpty(text) {
|
||||
const escape = this.getEscapeFn();
|
||||
return `<p class="text-xs text-gray-500">${escape(text)}</p>`;
|
||||
return `<p class="text-xs text-subtle">${escape(text)}</p>`;
|
||||
}
|
||||
|
||||
buildLinkMarkup(value, { breakAll = true } = {}) {
|
||||
@@ -1150,10 +1150,10 @@ export class RevertModal {
|
||||
const breakClass = breakAll ? " break-all" : " break-words";
|
||||
|
||||
if (/^https?:/i.test(raw)) {
|
||||
return `<a href="${safeValue}" target="_blank" rel="noopener noreferrer" class="text-blue-400 hover:text-blue-300${breakClass}">${safeDisplay}</a>`;
|
||||
return `<a href="${safeValue}" target="_blank" rel="noopener noreferrer" class="text-info hover:text-info-strong${breakClass}">${safeDisplay}</a>`;
|
||||
}
|
||||
|
||||
return `<code class="rounded bg-gray-800/70 px-1.5 py-0.5 text-[0.75rem] text-gray-200${breakClass}">${safeDisplay}</code>`;
|
||||
return `<code class="rounded bg-overlay-panel-soft px-1.5 py-0.5 text-[0.75rem] text-primary${breakClass}">${safeDisplay}</code>`;
|
||||
}
|
||||
|
||||
formatDurationSeconds(seconds) {
|
||||
@@ -1365,19 +1365,19 @@ export class RevertModal {
|
||||
const badges = [];
|
||||
if (variant.autoGenerated) {
|
||||
badges.push(
|
||||
'<span class="inline-flex items-center rounded-full border border-amber-600/70 bg-amber-900/30 px-2 py-0.5 text-4xs uppercase tracking-wide text-amber-200/90">Auto-generated</span>'
|
||||
'<span class="badge" data-variant="warning">Auto-generated</span>'
|
||||
);
|
||||
}
|
||||
|
||||
const variantNumber = `Variant ${index + 1}`;
|
||||
|
||||
const mimeHtml = variant.m
|
||||
? `<code class="rounded bg-gray-800/80 px-1.5 py-0.5 text-gray-100">${escape(
|
||||
? `<code class="rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary">${escape(
|
||||
variant.m
|
||||
)}</code>`
|
||||
: this.renderPlaceholder();
|
||||
const dimHtml = variant.dim
|
||||
? `<code class="rounded bg-gray-800/80 px-1.5 py-0.5 text-gray-100">${escape(
|
||||
? `<code class="rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary">${escape(
|
||||
variant.dim
|
||||
)}</code>`
|
||||
: this.renderPlaceholder();
|
||||
@@ -1385,14 +1385,14 @@ export class RevertModal {
|
||||
? this.buildLinkMarkup(variant.url)
|
||||
: this.renderPlaceholder("No URL");
|
||||
const hashHtml = variant.x
|
||||
? `<code class="break-all rounded bg-gray-800/80 px-1.5 py-0.5 text-gray-100">${escape(
|
||||
? `<code class="break-all rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary">${escape(
|
||||
variant.x
|
||||
)}</code>`
|
||||
: this.renderPlaceholder("Not provided");
|
||||
|
||||
const renderNestedList = (label, values, emptyLabel) => {
|
||||
if (!Array.isArray(values) || values.length === 0) {
|
||||
return `<div><p class="text-2xs uppercase tracking-wide text-gray-500">${escape(
|
||||
return `<div><p class="text-2xs uppercase tracking-wide text-subtle">${escape(
|
||||
label
|
||||
)}</p>${this.renderListEmpty(emptyLabel)}</div>`;
|
||||
}
|
||||
@@ -1403,17 +1403,17 @@ export class RevertModal {
|
||||
.map((markup) => `<li>${markup}</li>`);
|
||||
|
||||
if (!items.length) {
|
||||
return `<div><p class="text-2xs uppercase tracking-wide text-gray-500">${escape(
|
||||
return `<div><p class="text-2xs uppercase tracking-wide text-subtle">${escape(
|
||||
label
|
||||
)}</p>${this.renderListEmpty(emptyLabel)}</div>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div>
|
||||
<p class="text-2xs uppercase tracking-wide text-gray-500">${escape(
|
||||
<p class="text-2xs uppercase tracking-wide text-subtle">${escape(
|
||||
label
|
||||
)}</p>
|
||||
<ul class="mt-1 space-y-1 text-xs text-gray-200">${items.join("")}</ul>
|
||||
<ul class="mt-1 space-y-1 text-xs text-primary">${items.join("")}</ul>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
@@ -1425,30 +1425,30 @@ export class RevertModal {
|
||||
].join("");
|
||||
|
||||
return `
|
||||
<li class="rounded-md border border-gray-800/70 bg-black/30 p-3 space-y-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 text-xs text-gray-400">
|
||||
<span class="font-semibold text-gray-200">${escape(variantNumber)}</span>
|
||||
<li class="rounded-md border border-overlay bg-overlay-muted p-3 space-y-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 text-xs text-muted">
|
||||
<span class="font-semibold text-primary">${escape(variantNumber)}</span>
|
||||
${badges.length ? `<div class="flex flex-wrap gap-2">${badges.join("")}</div>` : ""}
|
||||
</div>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">MIME type</dt>
|
||||
<dt class="font-semibold text-primary">MIME type</dt>
|
||||
<dd class="mt-1">${mimeHtml}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Dimensions</dt>
|
||||
<dt class="font-semibold text-primary">Dimensions</dt>
|
||||
<dd class="mt-1">${dimHtml}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">URL</dt>
|
||||
<dt class="font-semibold text-primary">URL</dt>
|
||||
<dd class="mt-1">${urlHtml}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">Content hash</dt>
|
||||
<dt class="font-semibold text-primary">Content hash</dt>
|
||||
<dd class="mt-1">${hashHtml}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div class="grid gap-3 sm:grid-cols-3 text-xs text-gray-300">
|
||||
<div class="grid gap-3 sm:grid-cols-3 text-xs text-subtle">
|
||||
${nestedSections}
|
||||
</div>
|
||||
</li>
|
||||
@@ -1471,33 +1471,33 @@ export class RevertModal {
|
||||
? this.buildLinkMarkup(track.url)
|
||||
: this.renderPlaceholder("No URL");
|
||||
const typeHtml = track.type
|
||||
? `<code class="rounded bg-gray-800/80 px-1.5 py-0.5 text-gray-100">${escape(
|
||||
? `<code class="rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary">${escape(
|
||||
track.type
|
||||
)}</code>`
|
||||
: this.renderPlaceholder();
|
||||
const languageHtml = track.language
|
||||
? `<span class="inline-flex items-center rounded-full border border-gray-700 bg-gray-800/70 px-2 py-0.5 text-2xs uppercase tracking-wide text-gray-200">${escape(
|
||||
? `<span class="pill" data-size="compact" data-variant="neutral">${escape(
|
||||
track.language
|
||||
)}</span>`
|
||||
: this.renderPlaceholder();
|
||||
|
||||
return `
|
||||
<li class="rounded-md border border-gray-800/70 bg-black/30 p-3 space-y-3">
|
||||
<div class="flex items-center justify-between text-xs text-gray-400">
|
||||
<span class="font-semibold text-gray-200">${escape(headerLabel)}</span>
|
||||
<li class="rounded-md border border-overlay bg-overlay-muted p-3 space-y-3">
|
||||
<div class="flex items-center justify-between text-xs text-muted">
|
||||
<span class="font-semibold text-primary">${escape(headerLabel)}</span>
|
||||
${track.language ? languageHtml : ""}
|
||||
</div>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">URL</dt>
|
||||
<dt class="font-semibold text-primary">URL</dt>
|
||||
<dd class="mt-1">${urlHtml}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Type</dt>
|
||||
<dt class="font-semibold text-primary">Type</dt>
|
||||
<dd class="mt-1">${typeHtml}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Language</dt>
|
||||
<dt class="font-semibold text-primary">Language</dt>
|
||||
<dd class="mt-1">${track.language ? languageHtml : this.renderPlaceholder()}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@@ -1518,12 +1518,12 @@ export class RevertModal {
|
||||
if (Number.isFinite(seconds)) {
|
||||
const display = this.formatDurationSeconds(seconds);
|
||||
const suffix = seconds === 1 ? "second" : "seconds";
|
||||
return `<span class="text-gray-200">${escape(display)}</span> <span class="text-gray-500">(${escape(
|
||||
return `<span class="text-primary">${escape(display)}</span> <span class="text-subtle">(${escape(
|
||||
`${seconds} ${suffix}`
|
||||
)})</span>`;
|
||||
}
|
||||
if (raw) {
|
||||
return `<span class="text-gray-200">${escape(raw)}</span>`;
|
||||
return `<span class="text-primary">${escape(raw)}</span>`;
|
||||
}
|
||||
return this.renderPlaceholder();
|
||||
};
|
||||
@@ -1534,30 +1534,30 @@ export class RevertModal {
|
||||
const startHtml = formatTime(segment.startSeconds, segment.startRaw);
|
||||
const endHtml = formatTime(segment.endSeconds, segment.endRaw);
|
||||
const titleHtml = segment.title
|
||||
? `<p class="whitespace-pre-wrap text-gray-200">${escape(segment.title)}</p>`
|
||||
? `<p class="whitespace-pre-wrap text-primary">${escape(segment.title)}</p>`
|
||||
: this.renderPlaceholder("No title");
|
||||
const thumbnailHtml = segment.thumbnail
|
||||
? this.buildLinkMarkup(segment.thumbnail)
|
||||
: this.renderPlaceholder("No thumbnail");
|
||||
|
||||
return `
|
||||
<li class="rounded-md border border-gray-800/70 bg-black/30 p-3 space-y-3">
|
||||
<div class="text-xs font-semibold text-gray-200">${escape(headerLabel)}</div>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<li class="rounded-md border border-overlay bg-overlay-muted p-3 space-y-3">
|
||||
<div class="text-xs font-semibold text-primary">${escape(headerLabel)}</div>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">Start</dt>
|
||||
<dt class="font-semibold text-primary">Start</dt>
|
||||
<dd class="mt-1">${startHtml}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="font-semibold text-gray-200">End</dt>
|
||||
<dt class="font-semibold text-primary">End</dt>
|
||||
<dd class="mt-1">${endHtml}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">Title</dt>
|
||||
<dt class="font-semibold text-primary">Title</dt>
|
||||
<dd class="mt-1">${titleHtml}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">Thumbnail</dt>
|
||||
<dt class="font-semibold text-primary">Thumbnail</dt>
|
||||
<dd class="mt-1">${thumbnailHtml}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@@ -1576,7 +1576,7 @@ export class RevertModal {
|
||||
|
||||
const chips = hashtags.map((tag) => {
|
||||
const label = tag.startsWith("#") ? tag : `#${tag}`;
|
||||
return `<span class="inline-flex items-center rounded-full border border-gray-700 bg-gray-800/70 px-2 py-0.5 text-xs text-gray-200">${escape(
|
||||
return `<span class="pill" data-size="compact" data-variant="neutral">${escape(
|
||||
label
|
||||
)}</span>`;
|
||||
});
|
||||
@@ -1600,7 +1600,7 @@ export class RevertModal {
|
||||
: participant.pubkey
|
||||
: "";
|
||||
const pubkeyHtml = participant.pubkey
|
||||
? `<code class="break-all rounded bg-gray-800/80 px-1.5 py-0.5 text-gray-100" title="${escape(
|
||||
? `<code class="break-all rounded bg-overlay-panel-soft px-1.5 py-0.5 text-primary" title="${escape(
|
||||
participant.pubkey
|
||||
)}">${escape(displayPubkey)}</code>`
|
||||
: this.renderPlaceholder("No pubkey");
|
||||
@@ -1609,15 +1609,15 @@ export class RevertModal {
|
||||
: this.renderPlaceholder("No relay specified");
|
||||
|
||||
return `
|
||||
<li class="rounded-md border border-gray-800/70 bg-black/30 p-3 space-y-2">
|
||||
<div class="text-xs font-semibold text-gray-200">${escape(label)}</div>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-gray-300">
|
||||
<li class="rounded-md border border-overlay bg-overlay-muted p-3 space-y-2">
|
||||
<div class="text-xs font-semibold text-primary">${escape(label)}</div>
|
||||
<dl class="grid gap-3 sm:grid-cols-2 text-xs text-subtle">
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">Pubkey</dt>
|
||||
<dt class="font-semibold text-primary">Pubkey</dt>
|
||||
<dd class="mt-1">${pubkeyHtml}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="font-semibold text-gray-200">Relay</dt>
|
||||
<dt class="font-semibold text-primary">Relay</dt>
|
||||
<dd class="mt-1">${relayHtml}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@@ -1641,7 +1641,7 @@ export class RevertModal {
|
||||
return this.renderListEmpty("No external references.");
|
||||
}
|
||||
|
||||
return `<ul class="space-y-1 text-xs text-gray-200">${items.join("")}</ul>`;
|
||||
return `<ul class="space-y-1 text-xs text-primary">${items.join("")}</ul>`;
|
||||
}
|
||||
|
||||
extractDTagValue(tags) {
|
||||
|
||||
@@ -322,7 +322,7 @@ export class VideoCard {
|
||||
|
||||
if (this.showUnsupportedTorrentBadge) {
|
||||
const warning = this.createElement("p", {
|
||||
classNames: ["mt-3", "text-xs", "text-amber-300"],
|
||||
classNames: ["mt-3", "text-xs", "text-status-warning-on"],
|
||||
attrs: { title: this.assets.unsupportedBtihMessage || "" },
|
||||
textContent:
|
||||
"WebTorrent fallback unavailable (magnet missing btih info hash)"
|
||||
|
||||
@@ -1275,7 +1275,7 @@ export class ProfileModalController {
|
||||
if (!entriesToRender.length) {
|
||||
listEl.setAttribute("data-profile-switcher-empty", "true");
|
||||
const helper = document.createElement("p");
|
||||
helper.className = "text-sm text-gray-400";
|
||||
helper.className = "text-sm text-muted";
|
||||
helper.textContent = "No other profiles saved yet.";
|
||||
helper.setAttribute("role", "note");
|
||||
listEl.appendChild(helper);
|
||||
@@ -1309,7 +1309,7 @@ export class ProfileModalController {
|
||||
|
||||
const avatarSpan = document.createElement("span");
|
||||
avatarSpan.className =
|
||||
"flex h-12 w-12 flex-shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-slate-500/50 bg-slate-900";
|
||||
"flex h-12 w-12 flex-shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-overlay-strong bg-overlay-panel-soft";
|
||||
const avatarImg = document.createElement("img");
|
||||
avatarImg.className = "h-full w-full object-cover";
|
||||
avatarImg.src = meta.picture || FALLBACK_PROFILE_AVATAR;
|
||||
@@ -1327,23 +1327,23 @@ export class ProfileModalController {
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.className =
|
||||
"text-3xs font-semibold uppercase tracking-extra-wide text-blue-200";
|
||||
"text-3xs font-semibold uppercase tracking-extra-wide text-status-info";
|
||||
label.textContent =
|
||||
entry.authType === "nsec" ? "Direct key" : "Saved profile";
|
||||
|
||||
const action = document.createElement("span");
|
||||
action.className = "text-xs font-medium text-gray-400";
|
||||
action.className = "text-xs font-medium text-muted";
|
||||
action.setAttribute("aria-hidden", "true");
|
||||
action.textContent = isSelected ? "Selected" : "Switch";
|
||||
|
||||
topLine.append(label, action);
|
||||
|
||||
const nameSpan = document.createElement("span");
|
||||
nameSpan.className = "truncate text-sm font-semibold text-white";
|
||||
nameSpan.className = "truncate text-sm font-semibold text-primary";
|
||||
nameSpan.textContent = cardDisplayName;
|
||||
|
||||
const npubSpan = document.createElement("span");
|
||||
npubSpan.className = "break-all font-mono text-xs text-gray-400";
|
||||
npubSpan.className = "break-all font-mono text-xs text-muted";
|
||||
npubSpan.textContent = meta.npub
|
||||
? truncate(meta.npub, 48)
|
||||
: "npub unavailable";
|
||||
@@ -1507,7 +1507,7 @@ export class ProfileModalController {
|
||||
if (!relays.length) {
|
||||
const emptyState = document.createElement("li");
|
||||
emptyState.className =
|
||||
"card border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400";
|
||||
"card border border-dashed border-surface-strong p-4 text-center text-sm text-muted";
|
||||
emptyState.textContent = "No relays configured.";
|
||||
this.relayList.appendChild(emptyState);
|
||||
return;
|
||||
@@ -1522,11 +1522,11 @@ export class ProfileModalController {
|
||||
info.className = "flex-1 min-w-0";
|
||||
|
||||
const urlEl = document.createElement("p");
|
||||
urlEl.className = "text-sm font-medium text-gray-100 break-all";
|
||||
urlEl.className = "text-sm font-medium text-primary break-all";
|
||||
urlEl.textContent = entry.url;
|
||||
|
||||
const statusEl = document.createElement("p");
|
||||
statusEl.className = "mt-1 text-xs text-gray-400";
|
||||
statusEl.className = "mt-1 text-xs text-muted";
|
||||
let modeLabel = "Read & write";
|
||||
if (entry.mode === "read") {
|
||||
modeLabel = "Read only";
|
||||
@@ -1867,7 +1867,7 @@ export class ProfileModalController {
|
||||
info.className = "min-w-0 flex-1";
|
||||
|
||||
const title = document.createElement("p");
|
||||
title.className = "break-all text-sm font-medium text-gray-100";
|
||||
title.className = "break-all text-sm font-medium text-primary";
|
||||
title.textContent = label;
|
||||
|
||||
info.appendChild(title);
|
||||
@@ -2167,13 +2167,19 @@ export class ProfileModalController {
|
||||
|
||||
const element = this.walletStatusText;
|
||||
const variants = {
|
||||
success: "text-green-400",
|
||||
error: "text-red-400",
|
||||
info: "text-gray-400",
|
||||
success: "text-status-success",
|
||||
error: "text-status-danger",
|
||||
info: "text-status-info",
|
||||
neutral: "text-status-neutral",
|
||||
};
|
||||
|
||||
element.classList.remove("text-gray-400", "text-green-400", "text-red-400");
|
||||
const variantClass = variants[variant] || variants.info;
|
||||
element.classList.remove(
|
||||
"text-status-info",
|
||||
"text-status-success",
|
||||
"text-status-danger",
|
||||
"text-status-neutral",
|
||||
);
|
||||
const variantClass = variants[variant] || variants.neutral;
|
||||
element.classList.add(variantClass);
|
||||
element.textContent = message || "";
|
||||
}
|
||||
@@ -2644,7 +2650,7 @@ export class ProfileModalController {
|
||||
"card flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between";
|
||||
|
||||
const label = document.createElement("p");
|
||||
label.className = "break-all text-sm font-medium text-gray-100";
|
||||
label.className = "break-all text-sm font-medium text-primary";
|
||||
label.textContent = npub;
|
||||
item.appendChild(label);
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ export class VideoListView {
|
||||
}
|
||||
this.lastRenderedVideoSignature = EMPTY_VIDEO_LIST_SIGNATURE;
|
||||
this.container.innerHTML = `
|
||||
<p class="flex justify-center items-center h-full w-full text-center text-gray-500">
|
||||
<p class="flex justify-center items-center h-full w-full text-center text-subtle">
|
||||
No public videos available yet. Be the first to upload one!
|
||||
</p>`;
|
||||
return displayVideos;
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ export const viewInitRegistry = {
|
||||
const container = document.getElementById("subscriptionsVideoList");
|
||||
if (container) {
|
||||
container.innerHTML =
|
||||
"<p class='text-gray-500'>Please log in to see your subscriptions.</p>";
|
||||
"<p class='text-muted'>Please log in to see your subscriptions.</p>";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,11 +9,12 @@
|
||||
"build:beacon": "npm run build:beacon:bundle && npm run lint:inline-styles",
|
||||
"ci:beacon": "npm run build:beacon",
|
||||
"format": "prettier --cache --write css/tailwind.source.css css/tokens.css \"docs/**/*.html\" tailwind.config.cjs README.md",
|
||||
"lint": "npm run lint:css && npm run lint:hex && npm run lint:inline-styles && npm run lint:tokens",
|
||||
"lint": "npm run lint:css && npm run lint:hex && npm run lint:inline-styles && npm run lint:tokens && npm run lint:tailwind-colors",
|
||||
"lint:css": "stylelint css/tailwind.source.css css/tokens.css",
|
||||
"lint:hex": "node scripts/check-hex.js",
|
||||
"lint:inline-styles": "node scripts/check-inline-styles.mjs",
|
||||
"lint:tokens": "node scripts/check-design-tokens.mjs",
|
||||
"lint:tailwind-colors": "node scripts/check-tailwind-colors.mjs",
|
||||
"check:css": "npm run build:css && git diff --exit-code -- css/tailwind.generated.css",
|
||||
"test:visual": "npm run build:css && npx playwright test",
|
||||
"test:visual:update": "npm run build:css && cross-env UPDATE_VISUAL_BASELINES=1 npx playwright test",
|
||||
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readdir, readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const repoRoot = path.resolve(__dirname, "..");
|
||||
|
||||
const TARGET_DIRECTORIES = ["components", "js", "views"];
|
||||
const IGNORED_DIRECTORIES = new Set(["ed-legacy", "legacy", "__snapshots__"]);
|
||||
const LEGACY_ALLOWLIST = new Set([
|
||||
"components/ed-/revert-video-modal.html",
|
||||
"components/ed-/profile-modal.html",
|
||||
]);
|
||||
|
||||
const COLOR_PATTERN =
|
||||
/\b(?:text|bg|border|divide|ring|stroke|fill|outline|shadow|accent|placeholder)-(?:slate|gray|zinc|stone|neutral|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)(?:-[\w/]+)?\b/gim;
|
||||
|
||||
function toPosix(relPath) {
|
||||
return relPath.split(path.sep).join("/");
|
||||
}
|
||||
|
||||
async function collectFiles() {
|
||||
const results = new Set();
|
||||
for (const directory of TARGET_DIRECTORIES) {
|
||||
const absolute = path.resolve(repoRoot, directory);
|
||||
await walkDirectory(absolute, results);
|
||||
}
|
||||
return [...results];
|
||||
}
|
||||
|
||||
async function walkDirectory(dir, results) {
|
||||
let entries = [];
|
||||
try {
|
||||
entries = await readdir(dir, { withFileTypes: true });
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (IGNORED_DIRECTORIES.has(entry.name)) {
|
||||
continue;
|
||||
}
|
||||
await walkDirectory(fullPath, results);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entry.isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.add(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
function buildLineIndex(content) {
|
||||
const lines = [0];
|
||||
let index = 0;
|
||||
while ((index = content.indexOf("\n", index)) !== -1) {
|
||||
lines.push(index + 1);
|
||||
index += 1;
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function getLineNumber(indexes, matchIndex) {
|
||||
let low = 0;
|
||||
let high = indexes.length;
|
||||
while (low < high) {
|
||||
const mid = Math.floor((low + high) / 2);
|
||||
if (indexes[mid] <= matchIndex) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const files = await collectFiles();
|
||||
const violations = [];
|
||||
|
||||
for (const filePath of files) {
|
||||
const rel = toPosix(path.relative(repoRoot, filePath));
|
||||
if (LEGACY_ALLOWLIST.has(rel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let content;
|
||||
try {
|
||||
content = await readFile(filePath, "utf8");
|
||||
} catch (error) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const lineIndex = buildLineIndex(content);
|
||||
let match;
|
||||
COLOR_PATTERN.lastIndex = 0;
|
||||
while ((match = COLOR_PATTERN.exec(content))) {
|
||||
const line = getLineNumber(lineIndex, match.index);
|
||||
violations.push({
|
||||
file: rel,
|
||||
line,
|
||||
value: match[0],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (violations.length > 0) {
|
||||
console.error("Tailwind color lint failed: raw palette classes detected.\n");
|
||||
for (const violation of violations) {
|
||||
console.error(`${violation.file}:${violation.line} → ${violation.value}`);
|
||||
}
|
||||
console.error(
|
||||
"\nReplace raw tailwind colors with semantic utilities (text-muted, bg-status-warning-surface, etc.)."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Failed to check Tailwind color usage.");
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
+151
-34
@@ -16,20 +16,31 @@ module.exports = {
|
||||
colors: {
|
||||
page: "var(--color-page)",
|
||||
"page-alt": "var(--color-page-alt)",
|
||||
surface: "var(--color-surface)",
|
||||
"surface-alt": "var(--color-surface-alt)",
|
||||
surface: {
|
||||
DEFAULT: "var(--surface-base)",
|
||||
alt: "var(--surface-alt)",
|
||||
raised: "var(--surface-raised)",
|
||||
"raised-private": "var(--surface-raised-private)",
|
||||
"raised-critical": "var(--surface-raised-critical)",
|
||||
panel: "var(--surface-panel)",
|
||||
"panel-hover": "var(--surface-panel-hover)",
|
||||
sunken: "var(--surface-sunken)",
|
||||
muted: "var(--surface-muted)",
|
||||
inverse: "var(--surface-inverse)",
|
||||
},
|
||||
overlay: {
|
||||
DEFAULT: "var(--color-overlay)",
|
||||
muted: "var(--color-overlay-muted)",
|
||||
strong: "var(--color-overlay-strong)",
|
||||
darker: "var(--color-overlay-darker)",
|
||||
veil: "var(--color-overlay-veil)",
|
||||
banner: "var(--color-overlay-banner)",
|
||||
panel: "var(--color-overlay-panel)",
|
||||
"panel-soft": "var(--color-overlay-panel-soft)",
|
||||
"panel-tint": "var(--color-overlay-panel-tint)",
|
||||
"panel-glass": "var(--color-overlay-panel-glass)",
|
||||
black: "var(--color-overlay-black)"
|
||||
DEFAULT: "var(--surface-overlay)",
|
||||
muted: "var(--surface-overlay-muted)",
|
||||
strong: "var(--surface-overlay-strong)",
|
||||
darker: "var(--surface-overlay-darker)",
|
||||
veil: "var(--surface-veil)",
|
||||
banner: "var(--surface-overlay-banner)",
|
||||
panel: "var(--surface-overlay-panel)",
|
||||
"panel-soft": "var(--surface-overlay-panel-soft)",
|
||||
"panel-tint": "var(--surface-overlay-panel-tint)",
|
||||
"panel-glass": "var(--surface-overlay-panel-glass)",
|
||||
"panel-glass-soft": "var(--surface-overlay-panel-glass-soft)",
|
||||
black: "var(--surface-overlay-black)"
|
||||
},
|
||||
shadow: {
|
||||
intense: "var(--color-shadow-intense)"
|
||||
@@ -37,35 +48,39 @@ module.exports = {
|
||||
primary: "var(--color-primary)",
|
||||
secondary: "var(--color-secondary)",
|
||||
panel: {
|
||||
DEFAULT: "var(--color-panel)",
|
||||
hover: "var(--color-panel-hover)"
|
||||
DEFAULT: "var(--surface-panel)",
|
||||
hover: "var(--surface-panel-hover)"
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "var(--color-card)",
|
||||
private: "var(--color-card-private)",
|
||||
critical: "var(--color-card-critical)"
|
||||
DEFAULT: "var(--surface-raised)",
|
||||
private: "var(--surface-raised-private)",
|
||||
critical: "var(--surface-raised-critical)"
|
||||
},
|
||||
border: {
|
||||
DEFAULT: "var(--color-border)",
|
||||
subtle: "var(--color-border-subtle)",
|
||||
translucent: "var(--color-border-translucent)",
|
||||
DEFAULT: "var(--border-default)",
|
||||
subtle: "var(--border-subtle)",
|
||||
strong: "var(--border-strong)",
|
||||
translucent: "var(--border-overlay)",
|
||||
"translucent-strong": "var(--color-border-translucent-strong)",
|
||||
"translucent-bright": "var(--color-border-translucent-bright)",
|
||||
"translucent-medium": "var(--color-border-translucent-medium)",
|
||||
"translucent-stronger": "var(--color-border-translucent-stronger)",
|
||||
"translucent-strongest": "var(--color-border-translucent-strongest)",
|
||||
"translucent-glow": "var(--color-border-translucent-glow)",
|
||||
"info-soft": "var(--color-border-info-soft)",
|
||||
"neutral-soft": "var(--color-border-neutral-soft)",
|
||||
"sidebar-strong": "var(--color-border-sidebar-strong)"
|
||||
"translucent-glow": "var(--border-overlay-glow)",
|
||||
"info-soft": "var(--border-info-soft)",
|
||||
"neutral-soft": "var(--border-neutral-soft)",
|
||||
"sidebar-strong": "var(--border-sidebar-strong)"
|
||||
},
|
||||
text: {
|
||||
DEFAULT: "var(--color-text)",
|
||||
strong: "var(--color-text-strong)",
|
||||
muted: "var(--color-muted)",
|
||||
frosted: "var(--color-text-frosted)",
|
||||
"frosted-strong": "var(--color-text-frosted-strong)",
|
||||
"frosted-soft": "var(--color-text-frosted-soft)"
|
||||
DEFAULT: "var(--text-primary)",
|
||||
strong: "var(--color-white)",
|
||||
inverse: "var(--text-inverse)",
|
||||
muted: "var(--text-muted)",
|
||||
"muted-strong": "var(--text-muted-strong)",
|
||||
subtle: "var(--text-subtle)",
|
||||
frosted: "var(--text-frosted-primary)",
|
||||
"frosted-strong": "var(--text-frosted-strong)",
|
||||
"frosted-soft": "var(--text-frosted-soft)"
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "var(--color-muted)",
|
||||
@@ -82,9 +97,53 @@ module.exports = {
|
||||
strong: "var(--color-critical-strong)"
|
||||
},
|
||||
warning: {
|
||||
DEFAULT: "var(--color-warning)",
|
||||
strong: "var(--color-warning-strong)",
|
||||
surface: "var(--color-warning-surface)"
|
||||
DEFAULT: "var(--status-warning)",
|
||||
strong: "var(--status-warning-strong)",
|
||||
surface: "var(--status-warning-surface)"
|
||||
},
|
||||
status: {
|
||||
info: {
|
||||
DEFAULT: "var(--status-info)",
|
||||
strong: "var(--status-info-strong)",
|
||||
surface: "var(--status-info-surface)",
|
||||
border: "var(--status-info-border)",
|
||||
on: "var(--status-info-on)"
|
||||
},
|
||||
success: {
|
||||
DEFAULT: "var(--status-success)",
|
||||
strong: "var(--status-success-strong)",
|
||||
surface: "var(--status-success-surface)",
|
||||
border: "var(--status-success-border)",
|
||||
on: "var(--status-success-on)"
|
||||
},
|
||||
warning: {
|
||||
DEFAULT: "var(--status-warning)",
|
||||
strong: "var(--status-warning-strong)",
|
||||
surface: "var(--status-warning-surface)",
|
||||
border: "var(--status-warning-border)",
|
||||
on: "var(--status-warning-on)"
|
||||
},
|
||||
danger: {
|
||||
DEFAULT: "var(--status-danger)",
|
||||
strong: "var(--status-danger-strong)",
|
||||
surface: "var(--status-danger-surface)",
|
||||
border: "var(--status-danger-border)",
|
||||
on: "var(--status-danger-on)"
|
||||
},
|
||||
private: {
|
||||
DEFAULT: "var(--status-private)",
|
||||
strong: "var(--status-private-strong)",
|
||||
surface: "var(--status-private-surface)",
|
||||
border: "var(--status-private-border)",
|
||||
on: "var(--status-private-on)"
|
||||
},
|
||||
neutral: {
|
||||
DEFAULT: "var(--status-neutral)",
|
||||
strong: "var(--status-neutral-strong)",
|
||||
surface: "var(--status-neutral-surface)",
|
||||
border: "var(--status-neutral-border)",
|
||||
on: "var(--status-neutral-on)"
|
||||
}
|
||||
},
|
||||
neutral: {
|
||||
600: "var(--color-neutral-600)",
|
||||
@@ -139,6 +198,64 @@ module.exports = {
|
||||
"neutral-50": "var(--color-blog-neutral-50)"
|
||||
}
|
||||
},
|
||||
textColor: {
|
||||
primary: "var(--text-primary)",
|
||||
inverse: "var(--text-inverse)",
|
||||
muted: "var(--text-muted)",
|
||||
"muted-strong": "var(--text-muted-strong)",
|
||||
subtle: "var(--text-subtle)",
|
||||
"status-info": "var(--status-info)",
|
||||
"status-info-on": "var(--status-info-on)",
|
||||
"status-success": "var(--status-success)",
|
||||
"status-success-on": "var(--status-success-on)",
|
||||
"status-warning": "var(--status-warning)",
|
||||
"status-warning-on": "var(--status-warning-on)",
|
||||
"status-danger": "var(--status-danger)",
|
||||
"status-danger-on": "var(--status-danger-on)",
|
||||
"status-private": "var(--status-private)",
|
||||
"status-private-on": "var(--status-private-on)",
|
||||
"status-neutral": "var(--status-neutral)",
|
||||
"status-neutral-on": "var(--status-neutral-on)"
|
||||
},
|
||||
backgroundColor: {
|
||||
surface: "var(--surface-base)",
|
||||
"surface-alt": "var(--surface-alt)",
|
||||
"surface-raised": "var(--surface-raised)",
|
||||
"surface-muted": "var(--surface-muted)",
|
||||
"overlay-strong": "var(--surface-overlay-strong)",
|
||||
"overlay-muted": "var(--surface-overlay-muted)",
|
||||
"overlay-banner": "var(--surface-overlay-banner)",
|
||||
"overlay-panel": "var(--surface-overlay-panel)",
|
||||
"overlay-panel-soft": "var(--surface-overlay-panel-soft)",
|
||||
"overlay-panel-glass": "var(--surface-overlay-panel-glass)",
|
||||
"status-info-surface": "var(--status-info-surface)",
|
||||
"status-success-surface": "var(--status-success-surface)",
|
||||
"status-warning-surface": "var(--status-warning-surface)",
|
||||
"status-danger-surface": "var(--status-danger-surface)",
|
||||
"status-private-surface": "var(--status-private-surface)",
|
||||
"status-neutral-surface": "var(--status-neutral-surface)"
|
||||
},
|
||||
borderColor: {
|
||||
surface: "var(--border-default)",
|
||||
"surface-strong": "var(--border-strong)",
|
||||
"overlay": "var(--border-overlay)",
|
||||
"overlay-strong": "var(--border-overlay-strong)",
|
||||
"status-info-border": "var(--status-info-border)",
|
||||
"status-success-border": "var(--status-success-border)",
|
||||
"status-warning-border": "var(--status-warning-border)",
|
||||
"status-danger-border": "var(--status-danger-border)",
|
||||
"status-private-border": "var(--status-private-border)",
|
||||
"status-neutral-border": "var(--status-neutral-border)"
|
||||
},
|
||||
ringColor: {
|
||||
"status-danger": "var(--status-danger)",
|
||||
"status-warning": "var(--status-warning)",
|
||||
"status-info": "var(--status-info)",
|
||||
"status-success": "var(--status-success)"
|
||||
},
|
||||
ringOffsetColor: {
|
||||
surface: "var(--surface-base)"
|
||||
},
|
||||
borderRadius: {
|
||||
sm: "var(--radius-sm)",
|
||||
md: "var(--radius-md)",
|
||||
|
||||
Reference in new issue
Block a user