Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions app/apple-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ImageResponse } from 'next/og'

export const size = {
width: 180,
height: 180,
}
export const contentType = 'image/png'

export default function AppleIcon() {
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: '#0a0a0a',
}}
>
<div
style={{
width: 158,
height: 158,
borderRadius: 34,
background: '#5eead4',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<svg
width="112"
height="112"
viewBox="0 0 24 24"
fill="none"
stroke="#0a0a0a"
strokeWidth="2.75"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m5 16-4-4 4-4" />
<path d="m19 8 4 4-4 4" />
<path d="m14 4-4 16" />
</svg>
</div>
</div>
),
{
...size,
},
)
}
72 changes: 36 additions & 36 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,45 @@

@custom-variant dark (&:is(.dark *));

/* Codeplans.ai - Dark theme inspired by Vercel dashboard */
/* Codeplans.ai - Light theme (mirrors the dark palette below) */
:root {
--background: oklch(0.07 0 0);
--foreground: oklch(0.95 0 0);
--card: oklch(0.11 0 0);
--card-foreground: oklch(0.95 0 0);
--popover: oklch(0.11 0 0);
--popover-foreground: oklch(0.95 0 0);
--primary: oklch(0.95 0 0);
--primary-foreground: oklch(0.07 0 0);
--secondary: oklch(0.18 0 0);
--secondary-foreground: oklch(0.95 0 0);
--muted: oklch(0.15 0 0);
--muted-foreground: oklch(0.6 0 0);
--accent: oklch(0.7 0.15 145);
--accent-foreground: oklch(0.07 0 0);
--background: oklch(0.985 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.6 0.15 145);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.55 0.22 25);
--destructive-foreground: oklch(0.95 0 0);
--border: oklch(0.22 0 0);
--input: oklch(0.15 0 0);
--ring: oklch(0.7 0.15 145);
--chart-1: oklch(0.7 0.15 145);
--chart-2: oklch(0.65 0.2 250);
--chart-3: oklch(0.75 0.15 55);
--chart-4: oklch(0.6 0.2 300);
--chart-5: oklch(0.65 0.18 25);
--destructive-foreground: oklch(0.985 0 0);
--border: oklch(0.9 0 0);
--input: oklch(0.9 0 0);
--ring: oklch(0.6 0.15 145);
--chart-1: oklch(0.55 0.15 145);
--chart-2: oklch(0.5 0.2 250);
--chart-3: oklch(0.6 0.15 55);
--chart-4: oklch(0.5 0.2 300);
--chart-5: oklch(0.5 0.18 25);
--radius: 0.5rem;
--sidebar: oklch(0.09 0 0);
--sidebar-foreground: oklch(0.95 0 0);
--sidebar-primary: oklch(0.7 0.15 145);
--sidebar-primary-foreground: oklch(0.07 0 0);
--sidebar-accent: oklch(0.15 0 0);
--sidebar-accent-foreground: oklch(0.95 0 0);
--sidebar-border: oklch(0.22 0 0);
--sidebar-ring: oklch(0.7 0.15 145);
--success: oklch(0.7 0.15 145);
--success-foreground: oklch(0.07 0 0);
--warning: oklch(0.75 0.15 55);
--warning-foreground: oklch(0.07 0 0);
--sidebar: oklch(0.97 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.6 0.15 145);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.94 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.9 0 0);
--sidebar-ring: oklch(0.6 0.15 145);
--success: oklch(0.55 0.15 145);
--success-foreground: oklch(0.985 0 0);
--warning: oklch(0.6 0.15 55);
--warning-foreground: oklch(0.985 0 0);
}

.dark {
Expand Down
24 changes: 5 additions & 19 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from 'next'
import { Geist, Geist_Mono } from 'next/font/google'
import { Analytics } from '@vercel/analytics/next'
import { ThemeProvider } from '@/components/theme-provider'
import './globals.css'

const _geist = Geist({ subsets: ["latin"] });
Expand All @@ -9,23 +10,6 @@ const _geistMono = Geist_Mono({ subsets: ["latin"] });
export const metadata: Metadata = {
title: 'CodePlans — Engineering Planning',
description: 'Coordinate and track changes across your software architecture. Products, assets, code plans, and tasks in one place.',
icons: {
icon: [
{
url: '/icon-light-32x32.png',
media: '(prefers-color-scheme: light)',
},
{
url: '/icon-dark-32x32.png',
media: '(prefers-color-scheme: dark)',
},
{
url: '/icon.svg',
type: 'image/svg+xml',
},
],
apple: '/apple-icon.png',
},
}

export default function RootLayout({
Expand All @@ -34,9 +18,11 @@ export default function RootLayout({
children: React.ReactNode
}>) {
return (
<html lang="en" className="dark">
<html lang="en" suppressHydrationWarning>
<body className="font-sans antialiased">
{children}
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
{children}
</ThemeProvider>
<Analytics />
</body>
</html>
Expand Down
3 changes: 3 additions & 0 deletions components/app-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@/components/ui/dropdown-menu'
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
import { Badge } from '@/components/ui/badge'
import { ThemeToggle } from '@/components/theme-toggle'
import {
LayoutDashboard,
UserCircle2,
Expand Down Expand Up @@ -265,6 +266,8 @@ export function AppShell({ children, user, orgName, products, selectedProductId,
</div>

<div className="ml-auto flex items-center gap-2">
<ThemeToggle />

<Button variant="ghost" size="icon" className="relative">
<Bell className="h-5 w-5" />
</Button>
Expand Down
54 changes: 54 additions & 0 deletions components/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use client'

import { useEffect, useState } from 'react'
import { useTheme } from 'next-themes'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Sun, Moon, Monitor } from 'lucide-react'
import { cn } from '@/lib/utils'

const OPTIONS = [
{ value: 'light', label: 'Light', icon: Sun },
{ value: 'dark', label: 'Dark', icon: Moon },
{ value: 'system', label: 'System', icon: Monitor },
] as const

export function ThemeToggle() {
const { theme, setTheme } = useTheme()
// Avoid rendering an icon that doesn't match the persisted theme before hydration
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])

const current = OPTIONS.find((o) => o.value === theme) ?? OPTIONS[2]
const CurrentIcon = current.icon

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" title="Toggle theme">
{mounted ? <CurrentIcon className="h-5 w-5" /> : <Monitor className="h-5 w-5" />}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-36">
{OPTIONS.map((option) => {
const Icon = option.icon
return (
<DropdownMenuItem
key={option.value}
onClick={() => setTheme(option.value)}
className={cn('gap-2', theme === option.value && 'font-medium')}
>
<Icon className="h-4 w-4" />
{option.label}
</DropdownMenuItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
)
}
2 changes: 1 addition & 1 deletion components/ui/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function Switch({
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input border-border focus-visible:border-ring focus-visible:ring-ring/50 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codeplans",
"version": "0.3.19",
"version": "0.3.20",
"description": "Manage and track coordinated changes across your software architecture.",
"author": "Sai Prakash <sylonzero@gmail.com>",
"homepage": "https://codeplans.ai",
Expand Down
Binary file removed public/apple-icon.png
Binary file not shown.
Binary file removed public/icon-dark-32x32.png
Binary file not shown.
Binary file removed public/icon-light-32x32.png
Binary file not shown.
26 changes: 0 additions & 26 deletions public/icon.svg

This file was deleted.

Loading