From 32a28aec2d067167a1f23aaba384b32c9faa2659 Mon Sep 17 00:00:00 2001 From: OpenScanner Dev Date: Mon, 13 Apr 2026 00:18:44 +0000 Subject: [PATCH] feat(frontend): upgrade Tailwind CSS v4 + DaisyUI v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Upgrade tailwindcss 3→4.2, daisyui 4→5, add @tailwindcss/vite plugin - Remove postcss.config.js and tailwind.config.ts (CSS-first config) - Rewrite index.css: @import tailwindcss, @plugin daisyui, custom themes - Add DaisyUI v5 design tokens to custom themes (--radius-*, --size-*, etc.) - Migrate removed classes across 14 component files: - form-control → flex flex-col - label-text → text-sm, label-text-alt → text-xs - Remove input-bordered, select-bordered, textarea-bordered, file-input-bordered - Remove .label wrapper divs, convert label toggles to flex - Convert @utility blocks for led-branding, led-indicator, history-row - Remove postcss-import, autoprefixer, tailwindcss PostCSS plugins --- .github/copilot-instructions.md | 2 +- docs/architecture.md | 2 +- docs/plan.md | 2 +- docs/tailwind-daisyui-upgrade.md | 261 +++++ frontend/package.json | 7 +- frontend/pnpm-lock.yaml | 931 +++++++----------- frontend/postcss.config.js | 6 - .../src/components/admin/ApiKeysPanel.tsx | 23 +- .../src/components/admin/DirWatchPanel.tsx | 122 +-- .../src/components/admin/DownstreamsPanel.tsx | 30 +- .../src/components/admin/GroupsTagsPanel.tsx | 8 +- frontend/src/components/admin/LogsPanel.tsx | 24 +- .../src/components/admin/OptionsPanel.tsx | 34 +- .../src/components/admin/SystemsPanel.tsx | 130 +-- frontend/src/components/admin/ToolsPanel.tsx | 10 +- frontend/src/components/admin/UsersPanel.tsx | 76 +- .../src/components/admin/WebhooksPanel.tsx | 38 +- frontend/src/components/scanner/LEDPanel.tsx | 24 +- .../src/components/scanner/SearchPanel.tsx | 64 +- frontend/src/index.css | 94 +- frontend/src/pages/Login.tsx | 8 +- frontend/src/pages/Setup.tsx | 6 +- frontend/tailwind.config.ts | 50 - frontend/vite.config.ts | 3 +- 24 files changed, 963 insertions(+), 992 deletions(-) create mode 100644 docs/tailwind-daisyui-upgrade.md delete mode 100644 frontend/postcss.config.js delete mode 100644 frontend/tailwind.config.ts diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 435ecd0..880fd05 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -7,7 +7,7 @@ OpenScanner is a modern web-based radio call manager — a reimplementation of r ## Tech Stack - **Backend:** Go 1.25, Gin, coder/websocket, modernc.org/sqlite, sqlc, golang-jwt, bcrypt, golang-migrate, kardianos/service, log/slog, go:embed, webpush-go -- **Frontend:** React 18, TypeScript (strict), Vite, DaisyUI, Tailwind CSS (dark/light themes), Redux Toolkit, RTK Query, @tanstack/react-virtual, Service Worker (PWA + push notifications) +- **Frontend:** React 18, TypeScript (strict), Vite, Tailwind CSS 4 (@tailwindcss/vite), DaisyUI 5 (dark/light themes), Redux Toolkit, RTK Query, @tanstack/react-virtual, Service Worker (PWA + push notifications) - **Database:** SQLite (WAL mode) — all application configuration is stored in the DB - **Server config:** CLI flags, environment variables, or optional INI file (for listen address, DB path, TLS) - **Audio:** Files stored on filesystem, FFmpeg for conversion (4 modes: disabled/enabled/norm/loudnorm), bounded worker pool diff --git a/docs/architecture.md b/docs/architecture.md index bd5625f..29b1865 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -4,7 +4,7 @@ ## Overview -OpenScanner is a modern web-based radio call manager inspired by rdio-scanner. It uses a Go backend (Gin + SQLite) with a React frontend (TypeScript + DaisyUI), connected via WebSocket for real-time call streaming. +OpenScanner is a modern web-based radio call manager inspired by rdio-scanner. It uses a Go backend (Gin + SQLite) with a React frontend (TypeScript + Tailwind CSS 4 + DaisyUI 5), connected via WebSocket for real-time call streaming. ## System Diagram diff --git a/docs/plan.md b/docs/plan.md index 55af4d6..b2102b6 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -24,7 +24,7 @@ OpenScanner is a modern reimplementation of [rdio-scanner](https://github.com/ch | Logging | log/slog (structured, levelled) | | Deployment | go:embed frontend into single Go binary | | Frontend framework | React 18 + TypeScript (strict) + Vite | -| UI components | DaisyUI + Tailwind CSS (dark/light themes) | +| UI components | Tailwind CSS 4 + DaisyUI 5 (dark/light themes) | | State management | Redux Toolkit + RTK Query | | Virtual scrolling | @tanstack/react-virtual (long admin lists) | | PWA | Service Worker (app-shell cache + push notifications) + manifest | diff --git a/docs/tailwind-daisyui-upgrade.md b/docs/tailwind-daisyui-upgrade.md new file mode 100644 index 0000000..63afb80 --- /dev/null +++ b/docs/tailwind-daisyui-upgrade.md @@ -0,0 +1,261 @@ +# Tailwind CSS v4 + DaisyUI v5 Upgrade Plan + +> **Status: COMPLETED** — All migration steps have been applied, tests pass (145/145), production build succeeds. + +## Why Upgrade? + +- **Dev mode is slow**: Tailwind v3 + PostCSS compiles CSS lazily on first request. DaisyUI's theme generation adds ~3–5s delay before the UI renders in dev mode. +- **Tailwind v4** uses a Rust-based engine — CSS compilation is near-instant. +- **DaisyUI v5** is a stable release (5.5.19) with cleaner defaults (borders on by default, simplified classes). +- Since Vite is our bundler, we can use `@tailwindcss/vite` for the best performance — no PostCSS needed. + +## Current Versions + +| Package | Current | Target | +| ----------------- | ------- | ---------- | +| tailwindcss | 3.4.17 | 4.2.2 | +| @tailwindcss/vite | — | 4.2.2 | +| daisyui | 4.12.24 | 5.5.19 | +| autoprefixer | 10.4.21 | **remove** | +| postcss | 8.5.4 | **remove** | + +## Migration Steps + +### Step 1: Update Dependencies + +```bash +cd frontend +pnpm remove tailwindcss autoprefixer postcss +pnpm add -D tailwindcss@4.2.2 @tailwindcss/vite@4.2.2 +pnpm add -D daisyui@5.5.19 +``` + +### Step 2: Replace PostCSS with Vite Plugin + +**Delete** `postcss.config.js` — no longer needed. + +**Delete** `tailwind.config.ts` — config moves into CSS. + +**Update** `vite.config.ts`: + +```ts +import tailwindcss from "@tailwindcss/vite"; + +export default defineConfig({ + plugins: [react(), tailwindcss()], + // ... +}); +``` + +### Step 3: Migrate CSS Entry Point + +**Before** (`src/index.css`): + +```css +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer components { + .led-branding { + letter-spacing: 2px; + } + .led-indicator { + width: 24px; + height: 12px; + } + .history-row { + font-size: 11px; + line-height: 21px; + } +} +``` + +**After** (`src/index.css`): + +```css +@import "tailwindcss"; +@plugin "daisyui" { + themes: false; +} + +/* Custom themes */ +@plugin "daisyui/theme" { + name: "openscanner-dark"; + default: true; + prefersdark: true; + color-scheme: dark; + --color-base-100: #121212; + --color-base-200: #1e1e1e; + --color-base-300: #2d2d2d; + --color-base-content: #e0e0e0; /* maps to neutral-content */ + --color-primary: #00e676; + --color-primary-content: #000000; + --color-secondary: #ff9100; + --color-accent: #29b6f6; + --color-neutral: #1e1e1e; + --color-neutral-content: #e0e0e0; + --color-info: #29b6f6; + --color-success: #00e676; + --color-warning: #ffea00; + --color-error: #ff1744; +} + +@plugin "daisyui/theme" { + name: "openscanner-light"; + default: false; + color-scheme: light; + --color-base-100: #ffffff; + --color-base-200: #f5f5f5; + --color-base-300: #e0e0e0; + --color-base-content: #1e1e1e; + --color-primary: #2e7d32; + --color-primary-content: #ffffff; + --color-secondary: #e65100; + --color-accent: #0277bd; + --color-neutral: #f5f5f5; + --color-neutral-content: #1e1e1e; + --color-info: #0277bd; + --color-success: #2e7d32; + --color-warning: #f9a825; + --color-error: #c62828; +} + +/* Custom utilities */ +@utility led-branding { + letter-spacing: 2px; +} + +@utility led-indicator { + width: 24px; + height: 12px; +} + +@utility history-row { + font-size: 11px; + line-height: 21px; +} + +/* Restore cursor: pointer on buttons (TW4 changed default to cursor: default) */ +@layer base { + button:not(:disabled), + [role="button"]:not(:disabled) { + cursor: pointer; + } +} +``` + +### Step 4: DaisyUI v5 Class Removals + +These classes had borders as opt-in in v4; in v5, borders are the default. **Remove** them: + +| Class to remove | Est. occurrences | Files affected | +| --------------------- | ---------------- | -------------- | +| `input-bordered` | ~45 | 12 files | +| `select-bordered` | ~18 | 7 files | +| `textarea-bordered` | ~5 | 5 files | +| `file-input-bordered` | ~3 | 1 file | + +**Find/replace command:** + +```bash +# Remove the class from className strings +grep -rn "input-bordered\|select-bordered\|textarea-bordered\|file-input-bordered" \ + --include="*.tsx" --include="*.ts" frontend/src/ +``` + +### Step 5: DaisyUI v5 Structural Changes + +#### `form-control` → `fieldset` (~63 occurrences) + +The `form-control` class is removed in v5. It previously set `display: flex; flex-direction: column`. Options: + +**Option A (minimal):** Replace `form-control` with `flex flex-col` — preserves layout with no DOM changes. + +**Option B (semantic):** Refactor `