Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 4320c48bb31a6c11271ef547479f8c6b5c08e525
parent a6657fbe80afa63aaf5fb38131113c3a435ab664
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu,  2 Jul 2026 00:17:30 -0400

Merge: default export to the neutral base theme (pre-theme look)

Diffstat:
Mcommon/styles/tokens.css | 11++++++++++-
Meditor/CHANGELOG.md | 1+
Mexport/CHANGELOG.md | 3+++
Mexport/app/components/Header.tsx | 9+++++----
Mexport/app/globals.css | 5+++--
Mexport/app/layout.tsx | 13++++++++-----
Mexport/app/manifest.ts | 13+++++++------
Mexport/e2e/theme-family.spec.ts | 4++--
Mexport/e2e/theme.spec.ts | 19++++++++++---------
9 files changed, 49 insertions(+), 29 deletions(-)

diff --git a/common/styles/tokens.css b/common/styles/tokens.css @@ -102,8 +102,17 @@ feel like recoloured Archive. Written with `html[data-theme="…"]` (specificity 0,1,1) so the --font-* reassignments reliably beat next/font's `.variable` class, which sets --font-display/sans/mono on <html> at specificity 0,1,0. - Base + archive keep the default soft radius and the Source super-family voice. + Archive keeps the default soft radius and the full Source super-family voice. + Base keeps the soft radius but is all-sans (see below) to match the pre-theme + export/editor look, which had no serif. --------------------------------------------------------------------------- */ +/* Base family (no data-theme): all-sans like the pre-theme site. `:not([data-theme])` + (specificity 0,1,1) targets base only and beats next/font's `.variable` class + (0,1,0) without leaking into archive, which declares no --font-* and would + otherwise inherit this from :root. */ +html:not([data-theme]) { + --font-display: var(--font-sans); /* Source Sans 3 instead of Source Serif 4 */ +} html[data-theme="selenized"] { --radius: 0.375rem; /* calm, modest rounding — a code editor's corners */ --font-display: var(--font-code); /* JetBrains Mono wordmark/headings */ diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [Unreleased] +- **The neutral Base theme is now all-sans.** The default Base family previously inherited the shared Source **Serif** display face for the wordmark and page headings; it now uses the sans face instead, matching the pre-theme all-sans look. This is a shared token change (`html:not([data-theme])` in `common/styles/tokens.css`), so any surface on the Base family — including the editor's default — reads sans; the Archive/Selenized/Swiss families keep their own type voices. - **A dedicated Cleanup page with a live "reclaimable" sidebar badge and per-channel include/exclude.** Space-reclaim cleaning now has its own home (`/cleanup`, in the Pool nav) instead of being scattered across each channel's detail page. It opens with a serif **reclamation console** readout — the total reclaimable audio across channels, a token-colored breakdown bar (transcribed audio / extra formats / wrong-format), and a per-channel ledger that runs the same `cleanAudioAction` / `cleanExtraAudioFormatsAction` / `removeWrongFormatAudioAction` sweeps (plus failed-list housekeeping) the channel page does — the per-channel `CleanupStage` stays put. The sidebar **Cleanup** item carries an amber badge with the running reclaimable total (e.g. `12.4 GB`), recomputed on each auto-refresh tick. A per-channel **Counted / Excluded** toggle (new `ChannelConfig.excludeFromCleanup`, persisted in `config.json` like `excludeFromBuild`/`excludeFromSync`) holds a channel's space back from the total without disabling its sweeps — e.g. keep a finicky-to-redownload channel's audio around for now. The headline total uses the primary "clean audio" reclaim only (the three sweeps overlap, so they aren't summed). See `editor/app/cleanup/{page.tsx,lib/loadCleanup.ts,components/{ChannelCleanupCard,ChannelCleanupToggle}.tsx}`, `editor/app/channels/actions.ts` (`toggleChannelCleanupInclusionAction`), `editor/app/{lib/nav.ts,layout.tsx}`, and `common/lib/channelConfig.ts`. - **Badges and alerts are now colorful and theme-aware in every theme.** The design system only tokenized red (`--destructive`); every green/amber/blue status was hardcoded Tailwind palette that ignored the four theme families. New semantic tokens — **`--success` / `--warning` / `--info`** (each with `-foreground` + a soft fill partner) plus `--destructive-soft` — are defined across all eight family blocks (base/archive/terminal/swiss × light/dark) and registered in `@theme inline`. The shared kit `Badge` gains `success` / `warning` / `info` / `brand` soft-filled variants, and a **new `Alert` component** (`common/components/ui/alert.tsx`) replaces ad-hoc notice divs. High-traffic status UI is migrated onto the tokens: channel stage badges (`StageBadge`), worker state badges + dots (`WorkersView`, `MonitorWidget`), the scheduler status column (`SchedulerView`), and the widget disk strip — so each recolors correctly in Archive, Terminal, and Swiss, light and dark. See `common/styles/tokens.css`, `common/components/ui/{badge,alert}.tsx`. - **Per-video "Exclude from truncated check".** Videos that legitimately have no speech for their back half (e.g. long ambient/music tails) kept getting false-flagged as truncated/incomplete transcripts. A new per-video toggle on the video panel writes an `exclude-truncated-check.json` marker (mirroring the `do-not-clean.json` pattern) that suppresses the flag everywhere it surfaces — the snapshot's `incompleteTranscript` + `shortAudio` buckets (so bulk actions, the `/actionable` lists, and channel row dots all skip it) **and** the per-video panel's "looks truncated" banner, which computes independently of the snapshot. The detection thresholds in `transcriptCoverage.ts` are unchanged (other videos unaffected). See `common/lib/excludeTruncatedCheck{,-server}.ts`, `common/controller/channelSnapshot.ts`, `editor/app/channels/[slug]/videos/[id]/{videoActions.ts,components/VideoPanel.tsx,page.tsx}`, and `editor/app/channels/[slug]/page.tsx`. diff --git a/export/CHANGELOG.md b/export/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [Unreleased] +- **The default look is back to the original clean, neutral theme.** Public sites now open in the neutral **Base** theme — the crisp white/zinc palette (near-black ink in dark mode) with a blue accent that the site had before the themed redesign — instead of the warm brass "Archive" reading room. The wordmark and headings are all-sans to match, so the default site reads the way it used to. The Archive, Selenized, and Swiss themes are all still one click away in the theme picker, and any theme you'd previously chosen is remembered. Sites that set their own brand accent keep it. (The installable-app manifest's colors follow the new default too.) + ## [0.5.0] - 2026-07-01 - **Fixed: some Odysee/Rumble/Twitch videos opened in a YouTube player.** A video you'd opened before multi-platform support was added could get stuck playing in the YouTube embed even after its data was corrected, because the browser's local transcript cache (IndexedDB) held an old record with no platform and was never invalidated. The cache now self-heals — stale records are discarded on load — so every video plays in its correct platform's player. As a safeguard, a video whose platform somehow can't be determined now shows an "Open on source site" link instead of silently loading the wrong player. - **Instant offline word-search, powered by a background FlexSearch index.** On the Offline page, each channel now has a **Build index** action: it constructs a FlexSearch full-text index for that channel in a **Web Worker** — entirely off the main thread, so indexing a large channel never freezes the page (a live progress % shows the work). Once built, a search box does **instant word/prefix search** across your indexed channels and returns the matching transcript lines (with channel + timestamp) — and because the index is built from the same shards the offline download caches, it works with no connection. The worker bundles into the static site (no server needed). This is a first, self-contained surface; the main search box will gain the same acceleration next. diff --git a/export/app/components/Header.tsx b/export/app/components/Header.tsx @@ -7,10 +7,11 @@ import { ThemeMenu } from "yt-dlp-transcript-common/components/ThemeMenu"; import { currentSite } from "../lib/site"; import SiblingSwitcher from "./SiblingSwitcher"; -// The export site's masthead, in the family "Archive / Reading Room" identity: -// a brass mark + serif wordmark, calm sans nav, and the cross-site "family" -// chrome (hub backlink + sibling switcher). All cross-site data is resolved at -// build time from the pool, so single-site installs simply render neither. +// The export site's masthead: a brand-colored mark + wordmark, calm sans nav, +// and the cross-site "family" chrome (hub backlink + sibling switcher). The +// wordmark and mark track the active theme — sans + blue under the default base +// family, serif + brass under Archive. All cross-site data is resolved at build +// time from the pool, so single-site installs simply render neither. export default function Header() { const site = currentSite(); const settings = getSettings(); diff --git a/export/app/globals.css b/export/app/globals.css @@ -3,8 +3,9 @@ @source "../../common/components"; /* Design tokens, the `dark` variant, and theme palettes live in - common/styles/tokens.css. Export runs the public "archive" family (paper/ink); - the layout sets data-theme="archive" via ThemeScript. */ + common/styles/tokens.css. Export defaults to the neutral "base" family (the + pre-theme zinc/white look, all-sans); the archive/selenized/swiss families + remain available via the ThemeMenu picker. */ body { background: var(--background); diff --git a/export/app/layout.tsx b/export/app/layout.tsx @@ -10,7 +10,10 @@ import Footer from "./components/Footer"; import { ServiceWorkerRegister } from "./components/ServiceWorkerRegister"; import "./globals.css"; -const FAMILY_BRASS = "#95661a"; +// Browser-chrome themeColor fallback when a site defines no per-site accent. +// Tracks the base family's brand blue (tokens.css --brand) now that export +// defaults to base. +const FALLBACK_THEME_COLOR = "#2563eb"; export function generateMetadata(): Metadata { const s = currentSite(); @@ -38,8 +41,8 @@ export function generateMetadata(): Metadata { } export function generateViewport(): Viewport { - // Browser chrome color tracks the site's brand accent (falls back to brass). - return { themeColor: parseAccent(currentSite().accent) ?? FAMILY_BRASS }; + // Browser chrome color tracks the site's brand accent (falls back to base brand). + return { themeColor: parseAccent(currentSite().accent) ?? FALLBACK_THEME_COLOR }; } export default async function RootLayout({ @@ -58,9 +61,9 @@ export default async function RootLayout({ style={accentVars ?? undefined} > <body className="min-h-full flex flex-col bg-background text-foreground font-sans"> - <ThemeScript defaultTheme="archive" defaultMode="system" /> + <ThemeScript defaultTheme="base" defaultMode="system" /> <ServiceWorkerRegister /> - <ThemeProvider defaultTheme="archive" defaultMode="system"> + <ThemeProvider defaultTheme="base" defaultMode="system"> <QueryProvider> <Header /> <main className="flex-1 w-full max-w-6xl mx-auto px-4 sm:px-6 py-6"> diff --git a/export/app/manifest.ts b/export/app/manifest.ts @@ -4,18 +4,19 @@ import { currentSite } from "./lib/site"; // Web App Manifest → statically emitted as /manifest.webmanifest at build time // (output: "export"). Per-site: name/description from currentSite(), theme_color -// from the site's brand accent (falls back to the family brass). Makes each +// from the site's brand accent (falls back to the base brand blue). Makes each // deployed export site installable as a standalone PWA. Icons are the shared -// Archive mark under public/icons (a per-site accent-tinted icon is a later +// mark under public/icons (a per-site accent-tinted icon is a later // refinement — theme_color already differentiates the browser chrome). export const dynamic = "force-static"; -// Family brass — the archive brand accent, used when a site sets no accent. -const FAMILY_BRASS = "#95661a"; +// Base brand blue (tokens.css --brand), used when a site sets no accent — the +// export default family is base. +const FALLBACK_THEME_COLOR = "#2563eb"; export default function manifest(): MetadataRoute.Manifest { const site = currentSite(); - const themeColor = parseAccent(site.accent) ?? FAMILY_BRASS; + const themeColor = parseAccent(site.accent) ?? FALLBACK_THEME_COLOR; return { name: site.siteTitle, short_name: site.headerTitle || site.siteTitle, @@ -24,7 +25,7 @@ export default function manifest(): MetadataRoute.Manifest { scope: "/", display: "standalone", orientation: "portrait-primary", - background_color: "#0c0a08", + background_color: "#0a0a0a", theme_color: themeColor, icons: [ { diff --git a/export/e2e/theme-family.spec.ts b/export/e2e/theme-family.spec.ts @@ -19,8 +19,8 @@ test("theme-family picker switches + persists data-theme with no FOUC", async ({ page, }) => { await page.goto("/"); - // Export defaults to the archive family. - expect((await familyState(page)).theme).toBe("archive"); + // Export defaults to the base family (no data-theme attribute). + expect((await familyState(page)).theme).toBe(null); await expect( page.getByRole("button", { name: "Choose theme" }), ).toBeVisible(); diff --git a/export/e2e/theme.spec.ts b/export/e2e/theme.spec.ts @@ -1,8 +1,9 @@ import { test, expect, type Page } from "@playwright/test"; -// Phase 2: the export site adopts the public "archive" family (paper/ink) with a -// system-default mode. The data-theme attribute is always "archive"; the mode -// toggle must apply, persist across reloads, and be set before hydration. +// The export site defaults to the neutral "base" family (the pre-theme +// zinc/white look) with a system-default mode. Base removes the data-theme +// attribute (ThemeScript), so it reads as null; the mode toggle must apply, +// persist across reloads, and be set before hydration. async function state(page: Page) { return page.evaluate(() => ({ @@ -20,13 +21,13 @@ async function cycleTo(page: Page, target: "dark" | "light") { } } -test("archive family; mode toggle applies + persists with no FOUC", async ({ +test("base family default; mode toggle applies + persists with no FOUC", async ({ page, }) => { await page.goto("/"); - // Public archive family => data-theme="archive" on <html>. - expect((await state(page)).theme).toBe("archive"); + // Default base family => no data-theme attribute on <html>. + expect((await state(page)).theme).toBe(null); await expect(page.getByRole("button", { name: /switch to/i })).toBeVisible(); // Explicit dark, then reload-persists before hydration. @@ -34,7 +35,7 @@ test("archive family; mode toggle applies + persists with no FOUC", async ({ let s = await state(page); expect(s.mode).toBe("dark"); expect(s.dark).toBe(true); - expect(s.theme).toBe("archive"); + expect(s.theme).toBe(null); await page.reload({ waitUntil: "commit" }); let onCommit = await page.evaluate(() => ({ @@ -44,7 +45,7 @@ test("archive family; mode toggle applies + persists with no FOUC", async ({ })); expect(onCommit.mode).toBe("dark"); expect(onCommit.dark).toBe(true); - expect(onCommit.theme).toBe("archive"); + expect(onCommit.theme).toBe(null); // Explicit light, then reload-persists. await cycleTo(page, "light"); @@ -60,5 +61,5 @@ test("archive family; mode toggle applies + persists with no FOUC", async ({ })); expect(onCommit.mode).toBe("light"); expect(onCommit.dark).toBe(false); - expect(onCommit.theme).toBe("archive"); + expect(onCommit.theme).toBe(null); });