From 6a6f1e04546a74dbe9ea4117b58f8d989475dc3f Mon Sep 17 00:00:00 2001 From: songtianlun Date: Mon, 28 Jul 2025 23:26:50 +0800 Subject: [PATCH] Add dark modle --- src/app/globals.css | 183 +++++++++++++++++------- src/app/layout.tsx | 66 ++++++++- src/app/page.tsx | 104 +++++++------- src/app/profile/page.tsx | 2 +- src/components/layout/Header.tsx | 80 ++++++----- src/components/ui/theme-toggle.tsx | 214 +++++++++++++++++++++++++++++ src/contexts/ThemeContext.tsx | 113 +++++++++++++++ 7 files changed, 620 insertions(+), 142 deletions(-) create mode 100644 src/components/ui/theme-toggle.tsx create mode 100644 src/contexts/ThemeContext.tsx diff --git a/src/app/globals.css b/src/app/globals.css index 0e51d02..84859fe 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,65 +1,146 @@ @import "tailwindcss"; +/* Light theme variables */ :root { - --background: #ffffff; - --foreground: #0f172a; - --muted: #f8fafc; - --muted-foreground: #64748b; - --border: #e2e8f0; - --input: #ffffff; - --primary: #0f172a; - --primary-foreground: #f8fafc; - --secondary: #f1f5f9; - --secondary-foreground: #0f172a; - --accent: #f1f5f9; - --accent-foreground: #0f172a; - --destructive: #ef4444; - --destructive-foreground: #fef2f2; - --ring: #0f172a; + --background: 255 255 255; + --foreground: 15 23 42; + --card: 255 255 255; + --card-foreground: 15 23 42; + --popover: 255 255 255; + --popover-foreground: 15 23 42; + --primary: 15 23 42; + --primary-foreground: 248 250 252; + --secondary: 241 245 249; + --secondary-foreground: 15 23 42; + --muted: 248 250 252; + --muted-foreground: 100 116 139; + --accent: 241 245 249; + --accent-foreground: 15 23 42; + --destructive: 239 68 68; + --destructive-foreground: 254 242 242; + --border: 226 232 240; + --input: 255 255 255; + --ring: 15 23 42; + --radius: 0.5rem; +} + +/* Dark theme variables */ +.dark { + --background: 2 6 23; + --foreground: 248 250 252; + --card: 15 23 42; + --card-foreground: 248 250 252; + --popover: 15 23 42; + --popover-foreground: 248 250 252; + --primary: 248 250 252; + --primary-foreground: 15 23 42; + --secondary: 30 41 59; + --secondary-foreground: 248 250 252; + --muted: 15 23 42; + --muted-foreground: 148 163 184; + --accent: 30 41 59; + --accent-foreground: 248 250 252; + --destructive: 220 38 38; + --destructive-foreground: 254 242 242; + --border: 30 41 59; + --input: 15 23 42; + --ring: 248 250 252; } @theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-border: var(--border); - --color-input: var(--input); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-destructive-foreground: var(--destructive-foreground); - --color-ring: var(--ring); + --color-background: rgb(var(--background)); + --color-foreground: rgb(var(--foreground)); + --color-card: rgb(var(--card)); + --color-card-foreground: rgb(var(--card-foreground)); + --color-popover: rgb(var(--popover)); + --color-popover-foreground: rgb(var(--popover-foreground)); + --color-primary: rgb(var(--primary)); + --color-primary-foreground: rgb(var(--primary-foreground)); + --color-secondary: rgb(var(--secondary)); + --color-secondary-foreground: rgb(var(--secondary-foreground)); + --color-muted: rgb(var(--muted)); + --color-muted-foreground: rgb(var(--muted-foreground)); + --color-accent: rgb(var(--accent)); + --color-accent-foreground: rgb(var(--accent-foreground)); + --color-destructive: rgb(var(--destructive)); + --color-destructive-foreground: rgb(var(--destructive-foreground)); + --color-border: rgb(var(--border)); + --color-input: rgb(var(--input)); + --color-ring: rgb(var(--ring)); + --radius: var(--radius); --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); } -@media (prefers-color-scheme: dark) { - :root { - --background: #020617; - --foreground: #f8fafc; - --muted: #0f172a; - --muted-foreground: #94a3b8; - --border: #1e293b; - --input: #0f172a; - --primary: #f8fafc; - --primary-foreground: #0f172a; - --secondary: #1e293b; - --secondary-foreground: #f8fafc; - --accent: #1e293b; - --accent-foreground: #f8fafc; - --destructive: #dc2626; - --destructive-foreground: #fef2f2; - --ring: #f8fafc; - } +/* Base styles */ +* { + border-color: rgb(var(--border)); +} + +html { + scroll-behavior: smooth; } body { - background: var(--background); - color: var(--foreground); - font-family: var(--font-sans), Arial, Helvetica, sans-serif; + background-color: rgb(var(--background)); + color: rgb(var(--foreground)); + font-family: var(--font-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-feature-settings: "rlig" 1, "calt" 1; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Selection styles */ +::selection { + background-color: rgb(var(--primary) / 0.1); + color: rgb(var(--primary)); +} + +/* Focus styles */ +:focus-visible { + outline: 2px solid rgb(var(--ring)); + outline-offset: 2px; +} + +/* Scrollbar styles */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: rgb(var(--muted)); +} + +::-webkit-scrollbar-thumb { + background: rgb(var(--muted-foreground) / 0.3); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgb(var(--muted-foreground) / 0.5); +} + +/* Dark mode scrollbar */ +.dark ::-webkit-scrollbar-track { + background: rgb(var(--muted)); +} + +.dark ::-webkit-scrollbar-thumb { + background: rgb(var(--muted-foreground) / 0.3); +} + +.dark ::-webkit-scrollbar-thumb:hover { + background: rgb(var(--muted-foreground) / 0.5); +} + +/* Print styles */ +@media print { + * { + background: transparent !important; + color: black !important; + box-shadow: none !important; + text-shadow: none !important; + } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3deb76e..09b301c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,20 +1,57 @@ -import type { Metadata } from "next"; +import type { Metadata, Viewport } from "next"; import { Geist, Geist_Mono } from "next/font/google"; +import { ThemeProvider } from "@/contexts/ThemeContext"; import "./globals.css"; const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"], + preload: true, + display: "swap", }); const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"], + preload: true, + display: "swap", }); export const metadata: Metadata = { title: "Prmbr - AI Prompt Studio", description: "Build, manage and optimize your AI prompts with Prmbr", + keywords: ["AI", "prompt", "builder", "studio", "GPT", "ChatGPT", "Claude"], + authors: [{ name: "Prmbr Team" }], + creator: "Prmbr", + publisher: "Prmbr", + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + "max-video-preview": -1, + "max-image-preview": "large", + "max-snippet": -1, + }, + }, + manifest: "/manifest.json", + icons: { + icon: "/favicon.ico", + shortcut: "/favicon-16x16.png", + apple: "/apple-touch-icon.png", + }, +}; + +export const viewport: Viewport = { + width: "device-width", + initialScale: 1, + maximumScale: 1, + userScalable: false, + themeColor: [ + { media: "(prefers-color-scheme: light)", color: "#ffffff" }, + { media: "(prefers-color-scheme: dark)", color: "#020617" }, + ], }; export default function RootLayout({ @@ -23,11 +60,32 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + + + +