ui-v2: match tile / chart designs (#2633)

This commit is contained in:
Zane
2025-05-22 09:17:43 -07:00
committed by GitHub
parent 8cf8bbded2
commit f56b30fdba
5 changed files with 445 additions and 351 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,12 @@
import React from 'react';
import { useTimelineStyles } from '../../hooks/useTimelineStyles.ts';
import { ChartConfig, ChartContainer } from "@/components/ui/chart.tsx";
import { BarChart, Bar, LineChart, Line, ResponsiveContainer, Tooltip } from 'recharts';
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { BarChart, Bar, LineChart, Line, CartesianGrid, XAxis, ResponsiveContainer } from 'recharts';
interface ChartTileProps {
title: string;
@@ -27,17 +32,14 @@ export default function ChartTile({
// Convert the data array to the format expected by recharts
const chartData = data.map((value, index) => ({
value,
index: `Point ${index + 1}`
point: `P${index + 1}`
}));
// Chart configuration
// Chart configuration with proper color variables
const chartConfig = {
value: {
label: title,
theme: {
light: variant === 'line' ? '#0B54DE' : '#4CAF50',
dark: variant === 'line' ? '#00CAF7' : '#4CAF50'
}
color: variant === 'line' ? 'var(--chart-2)' : 'var(--chart-1)'
}
} satisfies ChartConfig;
@@ -45,54 +47,94 @@ export default function ChartTile({
<div
className={`
flex flex-col justify-between
w-[320px] h-[380px]
w-[320px] min-h-[380px]
${contentCardStyle}
rounded-[18px]
relative
overflow-hidden
transition-all duration-200
hover:scale-[1.02]
bg-background-default text-text-default
`}
>
{/* Header section with icon */}
<div className="p-4 space-y-4">
<div className="w-6 h-6">
<div className="w-6 h-6 text-text-default">
{icon}
</div>
<div>
<div className="text-gray-600 dark:text-white/40 text-sm mb-1">{title}</div>
<div className="text-gray-900 dark:text-white text-2xl font-semibold">
<div className="text-text-muted text-sm mb-1">{title}</div>
<div className="text-text-default text-2xl font-semibold">
{value}
{trend && <span className="ml-1 text-sm">{trend}</span>}
{trend && <span className="ml-1 text-sm text-text-muted">{trend}</span>}
</div>
</div>
</div>
{/* Chart Container */}
<div className="w-full h-[160px] px-4">
<ChartContainer config={chartConfig}>
<div className="w-full h-[200px] px-4 pb-6">
<ChartContainer
config={chartConfig}
className="[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-tooltip-wrapper]:!pointer-events-none"
>
<ResponsiveContainer width="100%" height="100%">
{variant === 'line' ? (
<LineChart data={chartData}>
<LineChart data={chartData} margin={{ top: 10, right: 10, bottom: 0, left: -20 }}>
<CartesianGrid vertical={false} className="stroke-border/50" />
<XAxis
dataKey="point"
tickLine={false}
tickMargin={10}
axisLine={false}
height={40}
tick={{ fill: 'var(--text-muted)' }}
/>
<ChartTooltip
content={
<ChartTooltipContent
className="border-border/50 bg-background-default text-text-default min-w-[180px] [&_.flex.flex-1]:gap-4 [&_.flex.flex-1>span]:whitespace-nowrap"
/>
}
/>
<Line
type="monotone"
dataKey="value"
stroke="var(--color-value)"
stroke="var(--chart-2)"
strokeWidth={2}
dot={{ fill: 'var(--color-value)', r: 4 }}
dot={{ fill: 'var(--chart-2)', r: 4 }}
/>
<Tooltip />
</LineChart>
) : (
<BarChart data={chartData}>
<BarChart data={chartData} margin={{ top: 10, right: 10, bottom: 0, left: 10 }}>
<CartesianGrid vertical={false} className="stroke-border/50" />
<XAxis
dataKey="point"
tickLine={false}
tickMargin={10}
axisLine={false}
height={40}
tick={{ fill: 'var(--text-muted)' }}
interval={0}
/>
<ChartTooltip
cursor={false}
content={
<ChartTooltipContent
indicator="dashed"
className="border-border/50 bg-background-default text-text-default min-w-[180px] [&_.flex.flex-1]:gap-4 [&_.flex.flex-1>span]:whitespace-nowrap"
/>
}
/>
<Bar
dataKey="value"
fill="var(--color-value)"
radius={[4, 4, 0, 0]}
fill="var(--chart-1)"
radius={4}
maxBarSize={32}
/>
<Tooltip />
</BarChart>
)}
</ResponsiveContainer>
</ChartContainer>
</div>
</div>

View File

@@ -1,7 +1,7 @@
import React from 'react';
import React, { useState } from 'react';
import { useTimelineStyles } from '../../hooks/useTimelineStyles';
import { ChartConfig, ChartContainer } from "@/components/ui/chart";
import { PieChart, Pie, Cell, Tooltip, Legend } from 'recharts';
import { PieChart, Pie, Cell, Sector, ResponsiveContainer } from 'recharts';
interface PieChartSegment {
value: number;
@@ -16,6 +16,90 @@ interface PieChartTileProps {
date?: Date;
}
// Custom label renderer with connecting lines
const renderCustomizedLabel = ({
cx,
cy,
midAngle,
innerRadius,
outerRadius,
percent,
payload,
fill,
}: any) => {
const RADIAN = Math.PI / 180;
const sin = Math.sin(-RADIAN * midAngle);
const cos = Math.cos(-RADIAN * midAngle);
// Adjust these values to position labels closer to the pie
const labelOffset = 12;
const labelDistance = 18;
// Calculate positions with shorter distances
const mx = cx + (outerRadius + labelOffset) * cos;
const my = cy + (outerRadius + labelOffset) * sin;
const ex = mx + (cos >= 0 ? 1 : -1) * labelDistance;
const ey = my;
// Text anchor based on which side of the pie we're on
const textAnchor = cos >= 0 ? "start" : "end";
// Calculate percentage
const value = (percent * 100).toFixed(0);
// Determine if label should be on top or bottom half for potential y-offset
const isTopHalf = my < cy;
const yOffset = isTopHalf ? -2 : 2;
// Force specific adjustments for "In Progress" label if needed
const isInProgress = payload.name === "In Progress";
const adjustedEx = isInProgress ? ex - 5 : ex;
return (
<g>
{/* Label line - using absolute coordinates for reliability */}
<path
d={`M${cx + outerRadius * cos},${cy + outerRadius * sin}L${mx},${my}L${adjustedEx},${ey}`}
stroke={fill}
strokeWidth={1}
fill="none"
style={{ opacity: 1 }}
/>
{/* Label text with adjusted position */}
<text
x={adjustedEx + (cos >= 0 ? 5 : -5)}
y={ey + yOffset}
textAnchor={textAnchor}
fill="var(--text-default)"
className="text-[10px]"
style={{
pointerEvents: 'none',
}}
>
{payload.name} ({value}%)
</text>
</g>
);
};
// Active shape renderer for hover effect
const renderActiveShape = (props: any) => {
const { cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill } = props;
return (
<Sector
cx={cx}
cy={cy}
innerRadius={innerRadius}
outerRadius={outerRadius + 4}
startAngle={startAngle}
endAngle={endAngle}
fill={fill}
cornerRadius={4}
/>
);
};
export default function PieChartTile({
title,
icon,
@@ -23,102 +107,96 @@ export default function PieChartTile({
date
}: PieChartTileProps) {
const { contentCardStyle } = useTimelineStyles(date);
const [activeIndex, setActiveIndex] = useState<number>(0);
// Convert segments to the format expected by recharts
const chartData = segments.map(segment => ({
// Convert segments to the format expected by recharts and assign chart colors
const chartData = segments.map((segment, index) => ({
name: segment.label,
value: segment.value
value: segment.value,
chartColor: `var(--chart-${index + 1})` // Use chart-1, chart-2, chart-3, etc.
}));
// Create chart configuration with theme colors
const chartConfig = segments.reduce((config, segment) => {
config[segment.label] = {
label: segment.label,
color: segment.color
};
return config;
}, {} as ChartConfig);
// Create chart configuration using the chart color variables
const chartConfig = {
[segments[0].label.toLowerCase()]: {
label: segments[0].label,
color: 'var(--chart-1)'
},
[segments[1].label.toLowerCase()]: {
label: segments[1].label,
color: 'var(--chart-2)'
},
[segments[2].label.toLowerCase()]: {
label: segments[2].label,
color: 'var(--chart-3)'
}
} satisfies ChartConfig;
// Custom tooltip formatter
const tooltipFormatter = (value: number, name: string) => {
const total = segments.reduce((sum, segment) => sum + segment.value, 0);
const percentage = ((value / total) * 100).toFixed(1);
return [`${percentage}%`, name];
const onPieEnter = (_: any, index: number) => {
setActiveIndex(index);
};
return (
<div
className={`
flex flex-col
w-[320px] h-[380px]
w-[320px] min-h-[380px]
${contentCardStyle}
rounded-[18px]
relative
overflow-hidden
transition-all duration-200
hover:scale-[1.02]
bg-background-default text-text-default
`}
>
{/* Header */}
<div className="p-4">
<div className="w-6 h-6 mb-4">
<div className="w-6 h-6 mb-4 text-text-default">
{icon}
</div>
<div className="text-gray-600 dark:text-white/40 text-sm">
<div className="text-text-muted text-sm">
{title}
</div>
</div>
{/* Pie Chart */}
<div className="flex-1 flex flex-col items-center">
<div className="w-full h-[200px]">
<div className="flex-1 flex items-center justify-center p-4">
<div style={{ width: '100%', height: '260px', position: 'relative' }}>
<ChartContainer config={chartConfig}>
<PieChart>
<ResponsiveContainer>
<PieChart margin={{ top: 30, right: 40, bottom: 10, left: 40 }}>
<Pie
activeIndex={activeIndex}
activeShape={renderActiveShape}
data={chartData}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius={0}
outerRadius={70}
paddingAngle={2}
innerRadius={45}
outerRadius={65}
paddingAngle={5}
dataKey="value"
onMouseEnter={onPieEnter}
cornerRadius={4}
label={renderCustomizedLabel}
labelLine={false}
startAngle={90}
endAngle={-270}
isAnimationActive={false}
>
{segments.map((segment, index) => (
{chartData.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={segment.color}
className="transition-all duration-200 hover:opacity-90"
fill={entry.chartColor}
stroke="var(--background-default)"
strokeWidth={2}
/>
))}
</Pie>
<Tooltip formatter={tooltipFormatter} />
</PieChart>
</ResponsiveContainer>
</ChartContainer>
</div>
{/* Legend */}
<div className="mt-2 px-4 w-full space-y-2">
{segments.map((segment, index) => {
const percentage = ((segment.value / segments.reduce((sum, s) => sum + s.value, 0)) * 100).toFixed(1);
return (
<div key={index} className="flex items-center justify-between">
<div className="flex items-center">
<div
className="w-3 h-3 rounded-full mr-2"
style={{ backgroundColor: segment.color }}
/>
<span className="text-sm text-gray-600 dark:text-white/60">
{segment.label}
</span>
</div>
<span className="text-sm font-medium text-gray-900 dark:text-white">
{percentage}%
</span>
</div>
);
})}
</div>
</div>
</div>
);

View File

@@ -3,167 +3,257 @@
@custom-variant dark (&:is(.dark *));
@layer base {
:root {
@theme {
/* reset */
--color-*: initial;
/* constants */
--color-white: #ffffff;
--color-black: #000000;
/* slate */
--color-slate-100: #f0f2f8;
--color-slate-200: #c8cdd6;
--color-slate-300: #a1a7b0;
--color-slate-400: #6e747e;
--color-slate-500: #4a4e54;
--color-slate-600: #2e2e2e;
/* utility */
--color-red-100: #ff6b6b;
--color-red-200: #f94b4b;
--color-blue-100: #7cacff;
--color-blue-200: #5c98f9;
--color-green-100: #a3d795;
--color-green-200: #91cb80;
--color-yellow-100: #ffd966;
--color-yellow-200: #fbcd44;
}
:root {
overflow: hidden;
--spring-easing: linear(
0,
0.009,
0.035 2.1%,
0.141,
0.281 6.7%,
0.723 12.9%,
0.938 16.7%,
1.017,
1.077,
1.121,
1.149 24.3%,
1.159,
1.163,
1.161,
1.154 29.9%,
1.129 32.8%,
1.051 39.6%,
1.017 43.1%,
0.991,
0.977 51%,
0.974 53.8%,
0.975 57.1%,
0.997 69.8%,
1.003 76.9%,
1.004 83.8%,
1
);
--spring-duration: 1.333s;
/* custom slate */
--slate: #393838;
/* shape */
--radius: 0.5rem;
/* block */
--block-teal: #13bbaf;
--block-orange: #ff4f00;
/* theming accents */
--background-accent: var(--color-black);
--border-accent: var(--color-black);
--text-accent: var(--color-black);
/* start arcade colors */
--constant-white: #ffffff;
--constant-black: #000000;
--grey-10: #101010;
--grey-20: #1e1e1e;
--grey-50: #666666;
--grey-60: #959595;
--grey-80: #cccccc;
--grey-85: #dadada;
--grey-90: #e8e8e8;
--grey-95: #f0f0f0;
--dark-grey-15: #1a1a1a;
--dark-grey-25: #232323;
--dark-grey-30: #2a2a2a;
--dark-grey-40: #333333;
--dark-grey-45: #595959;
--dark-grey-60: #878787;
--dark-grey-90: #e1e1e1;
/* Semantic */
--background-default: var(--color-white);
--background-medium: var(--color-slate-200);
--background-muted: var(--color-slate-100);
--background-inverse: var(--color-black);
--background-danger: var(--color-red-200);
--background-success: var(--color-green-200);
--background-info: var(--color-blue-200);
--background-warning: var(--color-yellow-200);
--background-app: var(--constant-white);
--background-prominent: var(--grey-80);
--background-standard: var(--grey-90);
--background-subtle: var(--grey-95);
--background-app-inverse: var(--constant-black);
--background-subtle-inverse: var(--dark-grey-15);
--background-standard-inverse: var(--dark-grey-25);
--background-prominent-inverse: var(--dark-grey-40);
--border-default: var(--color-slate-200);
--border-input: var(--color-slate-200);
--border-strong: var(--color-slate-300);
--border-inverse: var(--color-black);
--border-danger: var(--color-red-200);
--border-success: var(--color-green-200);
--border-warning: var(--color-yellow-200);
--border-info: var(--color-blue-200);
--border-divider: var(--grey-90);
--border-inverse: var(--constant-white);
--border-prominent: var(--grey-10);
--border-standard: var(--grey-60);
--border-subtle: var(--grey-90);
--text-default: var(--color-slate-600);
--text-muted: var(--color-slate-400);
--text-inverse: var(--color-white);
--text-danger: var(--color-red-200);
--text-success: var(--color-green-200);
--text-warning: var(--color-yellow-200);
--text-info: var(--color-blue-200);
--icon-disabled: var(--grey-60);
--icon-extra-subtle: var(--grey-60);
--icon-inverse: var(--constant-white);
--icon-prominent: var(--grey-10);
--icon-standard: var(--grey-20);
--icon-subtle: var(--grey-50);
--ring: var(--border-strong);
--text-placeholder: var(--grey-60);
--text-prominent: var(--grey-10);
--text-standard: var(--grey-20);
--text-standard-inverse: var(--dark-grey-90);
--text-subtle: var(--grey-50);
--text-subtle-inverse: var(--dark-grey-60);
--text-prominent-inverse: var(--constant-white);
}
--chart-1: #f6b44a;
--chart-2: #7585ff;
--chart-3: #d76a6a;
--chart-4: #d185e0;
--chart-5: #91cb80;
@media (prefers-color-scheme: dark) {
:root {
--background-app: var(--constant-black);
--background-prominent: var(--dark-grey-40);
--background-standard: var(--dark-grey-25);
--background-subtle: var(--dark-grey-15);
--background-app-inverse: var(--constant-white);
--background-subtle-inverse: var(--grey-95);
--background-standard-inverse: var(--grey-90);
--background-prominent-inverse: var(--grey-80);
--sidebar: var(--background-default);
--sidebar-foreground: var(--text-default);
--sidebar-primary: var(--background-accent);
--sidebar-primary-foreground: var(--text-inverse);
--sidebar-accent: var(--background-muted);
--sidebar-accent-foreground: var(--text-default);
--sidebar-border: var(--border-default);
--sidebar-ring: var(--border-default);
}
--border-divider: var(--dark-grey-25);
--border-inverse: var(--constant-black);
--border-prominent: var(--constant-white);
--border-standard: var(--dark-grey-45);
--border-subtle: var(--dark-grey-25);
.dark {
/* theming accents */
--background-accent: var(--color-white);
--border-accent: var(--color-white);
--text-accent: var(--color-white);
--icon-disabled: var(--dark-grey-45);
--icon-extra-subtle: var(--dark-grey-45);
--icon-inverse: var(--constant-black);
--icon-prominent: var(--constant-white);
--icon-standard: var(--dark-grey-90);
--icon-subtle: var(--dark-grey-60);
/* semantic */
--background-default: var(--color-black);
--background-medium: var(--color-slate-500);
--background-muted: var(--color-slate-600);
--background-inverse: var(--color-white);
--background-danger: var(--color-red-100);
--background-success: var(--color-green-100);
--background-info: var(--color-blue-100);
--background-warning: var(--color-yellow-100);
--text-placeholder: var(--dark-grey-45);
--text-prominent: var(--constant-white);
--text-standard: var(--dark-grey-90);
--text-standard-inverse: var(--grey-20);
--text-subtle: var(--dark-grey-60);
--text-subtle-inverse: var(--grey-50);
--text-prominent-inverse: var(--grey-20);
}
}
--border-default: var(--color-slate-600);
--border-input: var(--color-slate-600);
--border-strong: var(--color-slate-200);
--border-inverse: var(--color-white);
--border-danger: var(--color-red-200);
--border-success: var(--color-green-200);
--border-warning: var(--color-yellow-200);
--border-info: var(--color-blue-200);
body {
background-color: var(--background-app);
}
--text-default: var(--color-white);
--text-muted: var(--color-slate-300);
--text-inverse: var(--color-black);
--text-danger: var(--color-red-100);
--text-success: var(--color-green-100);
--text-warning: var(--color-yellow-100);
--text-info: var(--color-blue-100);
--ring: var(--border-strong);
--chart-1: #f6b44a;
--chart-2: #7585ff;
--chart-3: #d76a6a;
--chart-4: #d185e0;
--chart-5: #91cb80;
--sidebar: var(--background-default);
--sidebar-foreground: var(--text-default);
--sidebar-primary: var(--background-accent);
--sidebar-primary-foreground: var(--text-inverse);
--sidebar-accent: var(--background-muted);
--sidebar-accent-foreground: var(--text-default);
--sidebar-border: var(--border-default);
--sidebar-ring: var(--border-default);
}
@theme inline {
/* semantic */
--color-background-default: var(--background-default);
--color-background-medium: var(--background-medium);
--color-background-inverse: var(--background-inverse);
--color-background-muted: var(--background-muted);
--color-background-danger: var(--background-danger);
--color-background-success: var(--background-success);
--color-background-info: var(--background-info);
--color-background-warning: var(--background-warning);
--color-background-accent: var(--background-accent);
--color-border-accent: var(--border-accent);
--color-text-accent: var(--text-accent);
--color-border-default: var(--border-default);
--color-border-input: var(--border-input);
--color-border-strong: var(--border-strong);
--color-border-inverse: var(--border-inverse);
--color-border-danger: var(--border-danger);
--color-border-success: var(--border-success);
--color-border-warning: var(--border-warning);
--color-border-info: var(--border-info);
--color-text-default: var(--text);
--color-text-muted: var(--text-muted);
--color-text-inverse: var(--text-inverse);
--color-text-danger: var(--text-danger);
--color-text-success: var(--text-success);
--color-text-warning: var(--text-warning);
--color-text-info: var(--text-info);
/* fonts */
--font-sans: "Cash Sans", sans-serif;
--font-mono: "Cash Sans Mono", monospace;
--font-serif: serif;
/* shape */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
@font-face {
font-family: 'Cash Sans';
src:
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Regular.woff2)
format('woff2'),
font-family: "Cash Sans";
src: url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Light.woff2)
format("woff2"),
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Light.woff)
format("woff");
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: "Cash Sans";
src: url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Regular.woff2)
format("woff2"),
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Regular.woff)
format('woff');
format("woff");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Cash Sans';
src:
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Medium.woff2)
format('woff2'),
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Medium.woff) format('woff');
font-family: "Cash Sans";
src: url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Medium.woff2)
format("woff2"),
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Medium.woff)
format("woff");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Cash Sans Mono';
src:
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSansMono-Regular.woff2)
format('woff2'),
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSansMono-Regular.woff)
format('woff');
font-family: "Cash Sans Mono";
src: url(../assets/fonts/CashSansMono-Light.woff2) format("woff2");
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: "Cash Sans Mono";
src: url(../assets/fonts/CashSansMono-Regular.woff2) format("woff2");
font-weight: 400;
font-style: normal;
}
@layer base {
* {
@apply border-border-default;
}
body {
@apply bg-background-default text-text-default;
}
}
.titlebar-drag-region {
-webkit-app-region: drag;
height: 32px;
@@ -173,119 +263,3 @@
left: 0;
z-index: 50;
}
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--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-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-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
:root {
--radius: 0.625rem;
--background: oklch(1 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.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--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.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--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.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}