From b5254cf33d25b6d6a3aef0588a074806b8c5a7e5 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:49:34 +0000 Subject: [PATCH] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- public/favicon.svg | 5 + public/og.svg | 20 +++ src/components/mika/Logo.tsx | 19 +++ src/components/mika/ThemeToggle.tsx | 21 +++ src/components/theme-provider.tsx | 65 ++++++++ src/routeTree.gen.ts | 9 ++ src/styles.css | 227 ++++++++++++++++++---------- 7 files changed, 289 insertions(+), 77 deletions(-) create mode 100644 public/favicon.svg create mode 100644 public/og.svg create mode 100644 src/components/mika/Logo.tsx create mode 100644 src/components/mika/ThemeToggle.tsx create mode 100644 src/components/theme-provider.tsx diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..27dbdc5 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,5 @@ + + + M. + diff --git a/public/og.svg b/public/og.svg new file mode 100644 index 0000000..6d155cf --- /dev/null +++ b/public/og.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + Mika. + + + Seu assistente de IA no Telegram + + + mika.domco.ai + + + diff --git a/src/components/mika/Logo.tsx b/src/components/mika/Logo.tsx new file mode 100644 index 0000000..0388116 --- /dev/null +++ b/src/components/mika/Logo.tsx @@ -0,0 +1,19 @@ +import { Link } from "@tanstack/react-router"; +import { cn } from "@/lib/utils"; + +export function Logo({ className, size = "md" }: { className?: string; size?: "sm" | "md" | "lg" }) { + const sizes = { + sm: "text-xl", + md: "text-2xl", + lg: "text-3xl", + }; + return ( + + Mika. + + ); +} diff --git a/src/components/mika/ThemeToggle.tsx b/src/components/mika/ThemeToggle.tsx new file mode 100644 index 0000000..ec19fe1 --- /dev/null +++ b/src/components/mika/ThemeToggle.tsx @@ -0,0 +1,21 @@ +"use client"; + +import { Moon, Sun } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { useTheme } from "@/components/theme-provider"; + +export function ThemeToggle() { + const { theme, toggleTheme } = useTheme(); + return ( + + ); +} diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx new file mode 100644 index 0000000..20a32a3 --- /dev/null +++ b/src/components/theme-provider.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { createContext, useContext, useEffect, useState, type ReactNode } from "react"; + +type Theme = "light" | "dark"; +type ThemeContextValue = { + theme: Theme; + setTheme: (t: Theme) => void; + toggleTheme: () => void; +}; + +const ThemeContext = createContext(null); +const STORAGE_KEY = "mika-theme"; + +function applyTheme(theme: Theme) { + if (typeof document === "undefined") return; + const root = document.documentElement; + if (theme === "dark") root.classList.add("dark"); + else root.classList.remove("dark"); + root.style.colorScheme = theme; +} + +function getInitialTheme(): Theme { + if (typeof window === "undefined") return "light"; + try { + const stored = window.localStorage.getItem(STORAGE_KEY); + if (stored === "light" || stored === "dark") return stored; + } catch {} + if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) return "dark"; + return "light"; +} + +export function ThemeProvider({ children }: { children: ReactNode }) { + const [theme, setThemeState] = useState("light"); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + const t = getInitialTheme(); + setThemeState(t); + applyTheme(t); + setMounted(true); + }, []); + + const setTheme = (t: Theme) => { + setThemeState(t); + applyTheme(t); + try { + window.localStorage.setItem(STORAGE_KEY, t); + } catch {} + }; + + const toggleTheme = () => setTheme(theme === "dark" ? "light" : "dark"); + + return ( + +
{children}
+
+ ); +} + +export function useTheme() { + const ctx = useContext(ThemeContext); + if (!ctx) throw new Error("useTheme deve ser usado dentro de ThemeProvider"); + return ctx; +} diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index d204c26..dceedff 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -57,3 +57,12 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() + +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { + interface Register { + ssr: true + router: Awaited> + } +} diff --git a/src/styles.css b/src/styles.css index a9806b4..dfd4671 100644 --- a/src/styles.css +++ b/src/styles.css @@ -5,47 +5,48 @@ @custom-variant dark (&:is(.dark *)); /* - * Design system definition. - * - * The @theme inline block maps CSS custom properties to Tailwind utility - * classes (e.g. --color-primary -> bg-primary, text-primary). - * - * The :root and .dark blocks define the actual color values using oklch. - * All colors MUST use oklch format. - * - * To add a new semantic color: - * 1. Add the variable to :root (light value) and .dark (dark value) - * 2. Register it in @theme inline as --color-: var(--) + * Mika Design System + * Paleta inspirada em Linear / Supabase / Cal.com. + * - Primary: Indigo (#6366F1) — confiança e tecnologia + * - Secondary: Emerald (#10B981) — sucesso/check + * - Accent: Amber (#F59E0B) — destaque, ponto final do wordmark + * Todas as cores em oklch. */ @theme inline { + --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --radius-2xl: calc(var(--radius) + 8px); --radius-3xl: calc(var(--radius) + 12px); - --radius-4xl: calc(var(--radius) + 16px); + --color-background: var(--background); --color-foreground: var(--foreground); + --color-surface: var(--surface); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); + --color-primary-dark: var(--primary-dark); + --color-primary-light: var(--primary-light); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); --color-destructive: var(--destructive); --color-destructive-foreground: var(--destructive-foreground); + --color-success: var(--success); + --color-warning: var(--warning); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); - --color-ring-offset-background: var(--background); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); @@ -63,73 +64,115 @@ :root { --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.129 0.042 264.695); + + /* Mika light tokens */ + --background: oklch(0.985 0 0); /* #FAFAFA */ + --foreground: oklch(0.18 0.04 265); /* #0F172A */ + --surface: oklch(1 0 0); /* #FFFFFF */ + --card: oklch(1 0 0); - --card-foreground: oklch(0.129 0.042 264.695); + --card-foreground: oklch(0.18 0.04 265); --popover: oklch(1 0 0); - --popover-foreground: oklch(0.129 0.042 264.695); - --primary: oklch(0.208 0.042 265.755); - --primary-foreground: oklch(0.984 0.003 247.858); - --secondary: oklch(0.968 0.007 247.896); - --secondary-foreground: oklch(0.208 0.042 265.755); - --muted: oklch(0.968 0.007 247.896); - --muted-foreground: oklch(0.554 0.046 257.417); - --accent: oklch(0.968 0.007 247.896); - --accent-foreground: oklch(0.208 0.042 265.755); - --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.984 0.003 247.858); - --border: oklch(0.929 0.013 255.508); - --input: oklch(0.929 0.013 255.508); - --ring: oklch(0.704 0.04 256.788); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.984 0.003 247.858); - --sidebar-foreground: oklch(0.129 0.042 264.695); - --sidebar-primary: oklch(0.208 0.042 265.755); - --sidebar-primary-foreground: oklch(0.984 0.003 247.858); - --sidebar-accent: oklch(0.968 0.007 247.896); - --sidebar-accent-foreground: oklch(0.208 0.042 265.755); - --sidebar-border: oklch(0.929 0.013 255.508); - --sidebar-ring: oklch(0.704 0.04 256.788); + --popover-foreground: oklch(0.18 0.04 265); + + --primary: oklch(0.62 0.19 277); /* #6366F1 indigo-500 */ + --primary-foreground: oklch(0.99 0 0); + --primary-dark: oklch(0.55 0.21 277); /* #4F46E5 indigo-600 */ + --primary-light: oklch(0.74 0.13 277); /* #818CF8 indigo-400 */ + + --secondary: oklch(0.72 0.17 162); /* #10B981 emerald-500 */ + --secondary-foreground: oklch(0.99 0 0); + + --accent: oklch(0.78 0.16 75); /* #F59E0B amber-500 */ + --accent-foreground: oklch(0.18 0.04 265); + + --muted: oklch(0.96 0.005 256); + --muted-foreground: oklch(0.55 0.03 256);/* #64748B */ + + --destructive: oklch(0.63 0.23 25); /* #EF4444 */ + --destructive-foreground: oklch(0.99 0 0); + --success: oklch(0.72 0.17 162); + --warning: oklch(0.78 0.16 75); + + --border: oklch(0.92 0.01 256); /* #E2E8F0 */ + --input: oklch(0.92 0.01 256); + --ring: oklch(0.62 0.19 277); + + --chart-1: oklch(0.62 0.19 277); + --chart-2: oklch(0.72 0.17 162); + --chart-3: oklch(0.78 0.16 75); + --chart-4: oklch(0.55 0.21 277); + --chart-5: oklch(0.74 0.13 277); + + --sidebar: oklch(1 0 0); + --sidebar-foreground: oklch(0.18 0.04 265); + --sidebar-primary: oklch(0.62 0.19 277); + --sidebar-primary-foreground: oklch(0.99 0 0); + --sidebar-accent: oklch(0.96 0.005 256); + --sidebar-accent-foreground: oklch(0.18 0.04 265); + --sidebar-border: oklch(0.92 0.01 256); + --sidebar-ring: oklch(0.62 0.19 277); + + /* Gradientes & sombras Mika */ + --gradient-hero: radial-gradient(circle at 30% 20%, oklch(0.62 0.19 277 / 0.18), transparent 60%), + radial-gradient(circle at 80% 80%, oklch(0.72 0.17 162 / 0.12), transparent 55%); + --gradient-primary: linear-gradient(135deg, oklch(0.62 0.19 277), oklch(0.55 0.21 277)); + --shadow-soft: 0 1px 2px oklch(0.18 0.04 265 / 0.04), 0 4px 12px oklch(0.18 0.04 265 / 0.06); + --shadow-glow: 0 10px 40px -10px oklch(0.62 0.19 277 / 0.45); } .dark { - --background: oklch(0.129 0.042 264.695); - --foreground: oklch(0.984 0.003 247.858); - --card: oklch(0.208 0.042 265.755); - --card-foreground: oklch(0.984 0.003 247.858); - --popover: oklch(0.208 0.042 265.755); - --popover-foreground: oklch(0.984 0.003 247.858); - --primary: oklch(0.929 0.013 255.508); - --primary-foreground: oklch(0.208 0.042 265.755); - --secondary: oklch(0.279 0.041 260.031); - --secondary-foreground: oklch(0.984 0.003 247.858); - --muted: oklch(0.279 0.041 260.031); - --muted-foreground: oklch(0.704 0.04 256.788); - --accent: oklch(0.279 0.041 260.031); - --accent-foreground: oklch(0.984 0.003 247.858); - --destructive: oklch(0.704 0.191 22.216); - --destructive-foreground: oklch(0.984 0.003 247.858); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.551 0.027 264.364); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.208 0.042 265.755); - --sidebar-foreground: oklch(0.984 0.003 247.858); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.984 0.003 247.858); - --sidebar-accent: oklch(0.279 0.041 260.031); - --sidebar-accent-foreground: oklch(0.984 0.003 247.858); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.551 0.027 264.364); + --background: oklch(0.18 0.04 265); /* #0F172A */ + --foreground: oklch(0.96 0.01 247); /* #F1F5F9 */ + --surface: oklch(0.25 0.04 260); /* #1E293B */ + + --card: oklch(0.25 0.04 260); + --card-foreground: oklch(0.96 0.01 247); + --popover: oklch(0.25 0.04 260); + --popover-foreground: oklch(0.96 0.01 247); + + --primary: oklch(0.62 0.19 277); + --primary-foreground: oklch(0.99 0 0); + --primary-dark: oklch(0.55 0.21 277); + --primary-light: oklch(0.74 0.13 277); + + --secondary: oklch(0.72 0.17 162); + --secondary-foreground: oklch(0.99 0 0); + + --accent: oklch(0.78 0.16 75); + --accent-foreground: oklch(0.18 0.04 265); + + --muted: oklch(0.28 0.04 260); + --muted-foreground: oklch(0.65 0.03 256); + + --destructive: oklch(0.63 0.23 25); + --destructive-foreground: oklch(0.99 0 0); + --success: oklch(0.72 0.17 162); + --warning: oklch(0.78 0.16 75); + + --border: oklch(0.32 0.03 256); /* #334155 */ + --input: oklch(0.32 0.03 256); + --ring: oklch(0.74 0.13 277); + + --chart-1: oklch(0.74 0.13 277); + --chart-2: oklch(0.72 0.17 162); + --chart-3: oklch(0.78 0.16 75); + --chart-4: oklch(0.55 0.21 277); + --chart-5: oklch(0.62 0.19 277); + + --sidebar: oklch(0.22 0.04 262); + --sidebar-foreground: oklch(0.96 0.01 247); + --sidebar-primary: oklch(0.74 0.13 277); + --sidebar-primary-foreground: oklch(0.99 0 0); + --sidebar-accent: oklch(0.28 0.04 260); + --sidebar-accent-foreground: oklch(0.96 0.01 247); + --sidebar-border: oklch(0.32 0.03 256); + --sidebar-ring: oklch(0.74 0.13 277); + + --gradient-hero: radial-gradient(circle at 30% 20%, oklch(0.62 0.19 277 / 0.25), transparent 60%), + radial-gradient(circle at 80% 80%, oklch(0.72 0.17 162 / 0.18), transparent 55%); + --shadow-soft: 0 1px 2px oklch(0 0 0 / 0.3), 0 8px 24px oklch(0 0 0 / 0.35); + --shadow-glow: 0 10px 40px -10px oklch(0.62 0.19 277 / 0.55); } @layer base { @@ -137,8 +180,38 @@ border-color: var(--color-border); } + html { + font-family: var(--font-sans); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + } + body { background-color: var(--color-background); color: var(--color-foreground); + font-feature-settings: "cv02", "cv03", "cv04", "cv11"; + } + + ::selection { + background-color: oklch(0.62 0.19 277 / 0.25); + color: var(--color-foreground); + } +} + +@layer utilities { + .bg-gradient-hero { + background-image: var(--gradient-hero); + } + .bg-gradient-primary { + background-image: var(--gradient-primary); + } + .shadow-soft { + box-shadow: var(--shadow-soft); + } + .shadow-glow { + box-shadow: var(--shadow-glow); + } + .text-balance { + text-wrap: balance; } }