diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index f8bcd073..67e0f8ff 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,21 +1,25 @@ -{"id":"developer-160","title":"Migrate about site to use shared plugin","status":"open","priority":2,"issue_type":"task","created_at":"2026-02-26T19:34:53.303830388Z","created_by":"joost","updated_at":"2026-02-26T19:34:53.303830388Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["phase-3"]} -{"id":"developer-17h","title":"Fix button.tsx regression in about (restore Slot/asChild support)","status":"open","priority":2,"issue_type":"task","created_at":"2026-02-26T19:34:54.325834684Z","created_by":"joost","updated_at":"2026-02-26T19:34:54.325834684Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["phase-4"]} -{"id":"developer-1jy","title":"Implement Starlight plugin entry point (index.ts) with CSS/component injection","status":"open","priority":1,"issue_type":"task","created_at":"2026-02-26T19:34:48.534122026Z","created_by":"joost","updated_at":"2026-02-26T19:34:48.534122026Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["phase-1"]} -{"id":"developer-1zd","title":"Decide: private (GitHub Packages) vs public npm for plugin","status":"open","priority":2,"issue_type":"task","created_at":"2026-02-26T19:34:56.243808164Z","created_by":"joost","updated_at":"2026-02-26T19:34:56.243808164Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["decision"]} -{"id":"developer-21l","title":"Decide: Tailwind 4 migration timing relative to plugin extraction","status":"open","priority":3,"issue_type":"task","created_at":"2026-02-26T19:34:57.154617698Z","created_by":"joost","updated_at":"2026-02-26T19:34:57.154617698Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["decision"]} +{"id":"developer-160","title":"Migrate about site to use shared plugin","description":"## What\nMigrate the about site to consume the shared plugin instead of local copies.\n\n## Acceptance Criteria\n- [ ] `bun add @fashionunited/starlight-plugin-theme` added to dependencies\n- [ ] astro.config.mjs: add fashionunitedTheme() to starlight plugins array\n- [ ] Remove local files now provided by plugin: utils.ts, constants.ts, button.tsx, card.tsx, PageTitle.astro\n- [ ] Keep Head.astro override (has PostHog, OG images, service worker — extends plugin's base)\n- [ ] Replace shared portions of tailwind.config.mjs with preset import\n- [ ] Split src/tailwind.css: shared base removed (from plugin), prompt system CSS stays local\n- [ ] Keep site-specific: PageSidebar.astro, NavLink.astro, PostHog.astro, tools system, videos system, ApplicationButtons.tsx, middleware (CSP)\n- [ ] `bun dev` starts without errors\n- [ ] `bun run build` succeeds\n- [ ] `bun test:e2e` passes\n- [ ] Visual regression check: all pages look identical before/after","status":"closed","priority":2,"issue_type":"task","created_at":"2026-02-26T19:34:53.303830388Z","created_by":"joost","updated_at":"2026-02-26T20:39:24.542777506Z","closed_at":"2026-02-26T20:39:24.542709133Z","close_reason":"About site migrated to shared plugin. Build passes, all 412 unit tests pass. Commit bb258f14 on shared-theme-plugin branch pushed to origin.","source_repo":".","compaction_level":0,"original_size":0,"labels":["phase-3"],"dependencies":[{"issue_id":"developer-160","depends_on_id":"developer-3gr","type":"parent-child","created_at":"2026-02-26T20:03:20.705838598Z","created_by":"joost"},{"issue_id":"developer-160","depends_on_id":"developer-49h","type":"blocks","created_at":"2026-02-26T19:57:53.657850562Z","created_by":"joost"}]} +{"id":"developer-17h","title":"Fix button.tsx regression in about (restore Slot/asChild support)","description":"## What\nFix the button.tsx regression in about where Slot/asChild support was removed.\n\n## Acceptance Criteria\n- [ ] about's button.tsx uses the shared plugin version (which has proper @radix-ui/react-slot support)\n- [ ] `asChild` prop works correctly in about's usage of Button component\n- [ ] No more commented-out Slot import or hardcoded - - - - - - - - diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx deleted file mode 100644 index 12394222..00000000 --- a/src/components/ui/button.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const buttonVariants = cva( - "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean -} - -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" - -export { Button } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx deleted file mode 100644 index afa13ecf..00000000 --- a/src/components/ui/card.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" - -const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardTitle.displayName = "CardTitle" - -const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardDescription.displayName = "CardDescription" - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardContent.displayName = "CardContent" - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" - -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 31e72228..f636fc72 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -1,5 +1,5 @@ --- -import '@/styles/globals.css' +import "@fuww/starlight-plugin-theme/styles/globals.css"; import "@fontsource-variable/inter/index.css"; --- diff --git a/src/lib/utils.ts b/src/lib/utils.ts index bd0c391d..29504e47 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,6 +1 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} +export { cn } from "@fuww/starlight-plugin-theme/lib/utils"; diff --git a/src/pages/register.astro b/src/pages/register.astro index 05dbf79b..814a59a7 100644 --- a/src/pages/register.astro +++ b/src/pages/register.astro @@ -1,6 +1,6 @@ --- import Layout from "../layouts/Layout.astro"; -import { Button } from "@/components/ui/button"; +import { Button } from "@fuww/starlight-plugin-theme/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { @@ -10,7 +10,7 @@ import { CardFooter, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@fuww/starlight-plugin-theme/components/ui/card"; export const prerender = false; --- diff --git a/src/styles/custom.css b/src/styles/custom.css deleted file mode 100644 index d1d5a88a..00000000 --- a/src/styles/custom.css +++ /dev/null @@ -1,46 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* Dark mode background fix */ -:root[data-theme="dark"] { - --sl-color-bg: #17181c; - --sl-color-bg-nav: #24272f; - --sl-color-bg-sidebar: #24272f; -} - -/* Homepage header gradient */ -.hero h1 { - background: linear-gradient(135deg, #2563eb 0%, #1e40af 50%, #1e3a8a 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -/* Navbar header gradient */ -.site-title { - background: linear-gradient(90deg, #3b82f6 0%, #2563eb 50%, #1d4ed8 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -/* Button gradients */ -.sl-link-button[data-type="primary"] { - background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); - border: none; -} - -.sl-link-button[data-type="primary"]:hover { - background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%); -} - -/* Sidebar active state */ -[aria-current="page"] { - background: linear-gradient(180deg, #eff6ff 0%, #dbeafe 100%); - border-radius: 0.25rem; -} - -:root[data-theme="dark"] [aria-current="page"] { - background: linear-gradient(180deg, #1e3a8a 0%, #1e40af 100%); -} diff --git a/src/styles/globals.css b/src/styles/globals.css deleted file mode 100644 index 95d8cab1..00000000 --- a/src/styles/globals.css +++ /dev/null @@ -1,81 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - :root { - --background: 0 0% 100%; - --foreground: 222.2 47.4% 11.2%; - - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - - --popover: 0 0% 100%; - --popover-foreground: 222.2 47.4% 11.2%; - - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - - --card: 0 0% 100%; - --card-foreground: 222.2 47.4% 11.2%; - - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - - --destructive: 0 100% 50%; - --destructive-foreground: 210 40% 98%; - - --ring: 215 20.2% 65.1%; - - --radius: 0.5rem; - } - - .dark { - --background: 224 71% 4%; - --foreground: 213 31% 91%; - - --muted: 223 47% 11%; - --muted-foreground: 215.4 16.3% 56.9%; - - --accent: 216 34% 17%; - --accent-foreground: 210 40% 98%; - - --popover: 224 71% 4%; - --popover-foreground: 215 20.2% 65.1%; - - --border: 216 34% 17%; - --input: 216 34% 17%; - - --card: 224 71% 4%; - --card-foreground: 213 31% 91%; - - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 1.2%; - - --secondary: 222.2 47.4% 11.2%; - --secondary-foreground: 210 40% 98%; - - --destructive: 0 63% 31%; - --destructive-foreground: 210 40% 98%; - - --ring: 216 34% 17%; - - --radius: 0.5rem; - } -} - -@layer base { - * { - @apply border-border; - } - body { - @apply bg-background text-foreground; - font-feature-settings: "rlig" 1, "calt" 1; - } -} diff --git a/tailwind.config.mjs b/tailwind.config.mjs index 9e892b31..3d5f26e6 100644 --- a/tailwind.config.mjs +++ b/tailwind.config.mjs @@ -1,141 +1,17 @@ -const { fontFamily } = require('tailwindcss/defaultTheme') import starlightPlugin from '@astrojs/starlight-tailwind'; -const colors = require('tailwindcss/colors') - -// Generated color palettes -// https://starlight.astro.build/guides/css-and-tailwind/#color-theme-editor -// Sophisticated blue palette inspired by Solid.js -const accent = { - 200: '#93c5fd', - 600: '#2563eb', - 900: '#1e3a8a', - 950: '#172554' -}; -const gray = { - 100: '#f5f6f8', - 200: '#eceef2', - 300: '#c0c2c7', - 400: '#888b96', - 500: '#545861', - 700: '#353841', - 800: '#24272f', - 900: '#17181c' -}; +import { fuThemePreset, accent, gray } from '@fuww/starlight-plugin-theme/tailwind-preset'; +import typography from '@tailwindcss/typography'; +import animate from 'tailwindcss-animate'; /** @type {import('tailwindcss').Config} */ export default { - darkMode: ["class"], + presets: [fuThemePreset], content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], plugins: [ starlightPlugin({ - colors: { - accent, - gray, - } + colors: { accent, gray } }), - require("@tailwindcss/typography"), - require("tailwindcss-animate"), + typography, + animate, ], - theme: { - container: { - center: true, - padding: "2rem", - screens: { - "2xl": "1400px", - }, - }, - letterSpacing: { - tight: '-0.015em', - }, - colors: { - accent, - gray, - white: colors.white, - dark: "#111", - }, - extend: { - fontFamily: { - sans: [ - "Inter Variable", - "Inter", - ...fontFamily.sans, - ], - }, - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - // Sophisticated blue palette - blue: { - 50: '#eff6ff', - 100: '#dbeafe', - 200: '#bfdbfe', - 300: '#93c5fd', - 400: '#60a5fa', - 500: '#3b82f6', - 600: '#2563eb', - 700: '#1d4ed8', - 800: '#1e40af', - 900: '#1e3a8a', - 950: '#172554', - }, - }, - backgroundImage: { - 'gradient-blue-light': 'linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%)', - 'gradient-blue': 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)', - 'gradient-blue-hero': 'linear-gradient(135deg, #eff6ff 0%, #dbeafe 25%, #bfdbfe 50%, #93c5fd 100%)', - 'gradient-blue-dark': 'linear-gradient(135deg, #2563eb 0%, #1e40af 50%, #1e3a8a 100%)', - 'gradient-blue-sidebar': 'linear-gradient(180deg, #eff6ff 0%, #dbeafe 100%)', - }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", - }, - keyframes: { - "accordion-down": { - from: { height: "0" }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: "0" }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, - }, - }, - } +}