mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: sync demo theme with app
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>SnapOtter Demo</title>
|
||||
<meta name="description" content="Try SnapOtter - open-source, self-hosted file processing platform. Live demo." />
|
||||
<meta name="theme-color" content="#3b82f6" />
|
||||
<meta name="theme-color" content="#E07832" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.png" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
|
||||
@@ -6,14 +6,14 @@ export function DemoBanner() {
|
||||
if (dismissed) return null;
|
||||
|
||||
return (
|
||||
<div className="relative z-[9999] flex items-center justify-center gap-3 bg-blue-600 px-4 py-2 text-sm text-white">
|
||||
<div className="relative z-[9999] flex items-center justify-center gap-3 bg-primary px-4 py-2 text-sm text-primary-foreground">
|
||||
<span>
|
||||
This is a live demo. Processing is disabled.{" "}
|
||||
<a
|
||||
href="https://github.com/snapotter-hq/SnapOtter"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="font-semibold underline underline-offset-2 hover:text-blue-100"
|
||||
className="font-semibold underline underline-offset-2 hover:text-primary-subtle"
|
||||
>
|
||||
Self-host SnapOtter
|
||||
</a>{" "}
|
||||
@@ -22,7 +22,7 @@ export function DemoBanner() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setDismissed(true)}
|
||||
className="ms-2 shrink-0 rounded px-1.5 py-0.5 text-xs font-medium hover:bg-blue-700"
|
||||
className="ms-2 shrink-0 rounded px-1.5 py-0.5 text-xs font-medium hover:bg-primary-dark"
|
||||
aria-label="Dismiss banner"
|
||||
>
|
||||
Dismiss
|
||||
|
||||
@@ -20,7 +20,7 @@ function patchDemoErrors(root: Element) {
|
||||
if (el.dataset.demoPatch) return;
|
||||
el.dataset.demoPatch = "1";
|
||||
el.classList.remove("text-red-500");
|
||||
el.style.color = "#3b82f6";
|
||||
el.style.color = "var(--color-primary)";
|
||||
el.style.fontSize = "13px";
|
||||
el.style.lineHeight = "1.5";
|
||||
|
||||
|
||||
@@ -1,108 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
@import "../../../web/src/styles/globals.css";
|
||||
@source "../../../web/src/**/*.tsx";
|
||||
@source "../../../web/src/**/*.ts";
|
||||
|
||||
:root {
|
||||
font-family:
|
||||
"Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", "Noto Sans", "Noto Sans CJK SC", "Noto Sans CJK TC",
|
||||
"Noto Sans CJK JP", "Noto Sans CJK KR", "Noto Sans Arabic",
|
||||
"Noto Sans Devanagari", "Noto Sans Thai", sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji";
|
||||
}
|
||||
|
||||
@theme {
|
||||
--color-primary: #3b82f6;
|
||||
--color-primary-foreground: #ffffff;
|
||||
--color-background: #ffffff;
|
||||
--color-foreground: #0f172a;
|
||||
--color-muted: #f1f5f9;
|
||||
--color-muted-foreground: #64748b;
|
||||
--color-border: #e2e8f0;
|
||||
--color-card: #ffffff;
|
||||
--color-card-foreground: #0f172a;
|
||||
--color-sidebar: #f8fafc;
|
||||
--color-sidebar-foreground: #334155;
|
||||
--color-accent: #3b82f6;
|
||||
--color-destructive: #ef4444;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-background: #0f172a;
|
||||
--color-foreground: #f8fafc;
|
||||
--color-muted: #1e293b;
|
||||
--color-muted-foreground: #94a3b8;
|
||||
--color-border: #334155;
|
||||
--color-card: #1e293b;
|
||||
--color-card-foreground: #f8fafc;
|
||||
--color-sidebar: #1e293b;
|
||||
--color-sidebar-foreground: #cbd5e1;
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
height: 4px;
|
||||
border-radius: 9999px;
|
||||
background: var(--color-muted);
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-foreground);
|
||||
cursor: pointer;
|
||||
border: 2px solid var(--color-background);
|
||||
box-shadow: 0 0 0 1px var(--color-border);
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-foreground);
|
||||
cursor: pointer;
|
||||
border: 2px solid var(--color-background);
|
||||
box-shadow: 0 0 0 1px var(--color-border);
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-track {
|
||||
height: 4px;
|
||||
border-radius: 9999px;
|
||||
background: var(--color-muted);
|
||||
}
|
||||
|
||||
[dir="rtl"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[dir="rtl"] input[type="text"],
|
||||
[dir="rtl"] input[type="password"],
|
||||
[dir="rtl"] input[type="email"],
|
||||
[dir="rtl"] input[type="number"],
|
||||
[dir="rtl"] input[type="search"],
|
||||
[dir="rtl"] textarea,
|
||||
[dir="rtl"] select {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[dir="rtl"] input[type="range"] {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
[dir="rtl"] pre,
|
||||
[dir="rtl"] code {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
@source "../**/*.tsx";
|
||||
@source "../**/*.ts";
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
<title>SnapOtter</title>
|
||||
<meta name="description" content="Open-source, self-hosted file processing platform" />
|
||||
<meta name="theme-color" content="#3b82f6" />
|
||||
<meta name="theme-color" content="#E07832" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.png" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{ "src": "/logo-192.png", "sizes": "192x192", "type": "image/png" },
|
||||
{ "src": "/logo-512.png", "sizes": "512x512", "type": "image/png" }
|
||||
],
|
||||
"theme_color": "#3b82f6",
|
||||
"theme_color": "#E07832",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const demoStylesPath = path.resolve(process.cwd(), "apps/demo/src/styles/globals.css");
|
||||
const demoBannerPath = path.resolve(process.cwd(), "apps/demo/src/demo-banner.tsx");
|
||||
const demoHtmlPath = path.resolve(process.cwd(), "apps/demo/index.html");
|
||||
const demoMainPath = path.resolve(process.cwd(), "apps/demo/src/main.tsx");
|
||||
const webHtmlPath = path.resolve(process.cwd(), "apps/web/index.html");
|
||||
const webManifestPath = path.resolve(process.cwd(), "apps/web/public/manifest.json");
|
||||
const webStylesPath = path.resolve(process.cwd(), "apps/web/src/styles/globals.css");
|
||||
|
||||
function readFixture(filePath: string): string {
|
||||
return readFileSync(filePath, "utf8");
|
||||
}
|
||||
|
||||
describe("demo theme", () => {
|
||||
it("inherits the real web app global stylesheet instead of carrying copied color tokens", () => {
|
||||
const demoStyles = readFixture(demoStylesPath);
|
||||
|
||||
expect(demoStyles).toContain('@import "../../../web/src/styles/globals.css";');
|
||||
expect(demoStyles).toContain('@source "../../../web/src/**/*.tsx";');
|
||||
expect(demoStyles).toContain('@source "../../../web/src/**/*.ts";');
|
||||
expect(demoStyles).not.toContain("--color-primary:");
|
||||
expect(demoStyles).not.toContain("#3b82f6");
|
||||
});
|
||||
|
||||
it("does not hardcode the old blue demo accent in demo-only UI", () => {
|
||||
const demoOnlyUi = [demoBannerPath, demoMainPath].map(readFixture).join("\n");
|
||||
|
||||
expect(demoOnlyUi).not.toMatch(/bg-blue-|text-blue-|hover:bg-blue-|hover:text-blue-|#3b82f6/i);
|
||||
});
|
||||
|
||||
it("uses the current app primary color for browser theme metadata", () => {
|
||||
const webStyles = readFixture(webStylesPath);
|
||||
const primaryColor = webStyles.match(/--color-primary:\s*(#[0-9a-f]{6})/i)?.[1];
|
||||
|
||||
expect(primaryColor).toBeDefined();
|
||||
|
||||
for (const htmlPath of [demoHtmlPath, webHtmlPath]) {
|
||||
expect(readFixture(htmlPath)).toContain(`name="theme-color" content="${primaryColor}"`);
|
||||
}
|
||||
|
||||
expect(JSON.parse(readFixture(webManifestPath))).toMatchObject({
|
||||
theme_color: primaryColor,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user