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 React from 'react';
import { useTimelineStyles } from '../../hooks/useTimelineStyles.ts'; import { useTimelineStyles } from '../../hooks/useTimelineStyles.ts';
import { ChartConfig, ChartContainer } from "@/components/ui/chart.tsx"; import {
import { BarChart, Bar, LineChart, Line, ResponsiveContainer, Tooltip } from 'recharts'; ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { BarChart, Bar, LineChart, Line, CartesianGrid, XAxis, ResponsiveContainer } from 'recharts';
interface ChartTileProps { interface ChartTileProps {
title: string; title: string;
@@ -27,17 +32,14 @@ export default function ChartTile({
// Convert the data array to the format expected by recharts // Convert the data array to the format expected by recharts
const chartData = data.map((value, index) => ({ const chartData = data.map((value, index) => ({
value, value,
index: `Point ${index + 1}` point: `P${index + 1}`
})); }));
// Chart configuration // Chart configuration with proper color variables
const chartConfig = { const chartConfig = {
value: { value: {
label: title, label: title,
theme: { color: variant === 'line' ? 'var(--chart-2)' : 'var(--chart-1)'
light: variant === 'line' ? '#0B54DE' : '#4CAF50',
dark: variant === 'line' ? '#00CAF7' : '#4CAF50'
}
} }
} satisfies ChartConfig; } satisfies ChartConfig;
@@ -45,54 +47,94 @@ export default function ChartTile({
<div <div
className={` className={`
flex flex-col justify-between flex flex-col justify-between
w-[320px] h-[380px] w-[320px] min-h-[380px]
${contentCardStyle} ${contentCardStyle}
rounded-[18px] rounded-[18px]
relative relative
overflow-hidden overflow-hidden
transition-all duration-200 transition-all duration-200
hover:scale-[1.02] hover:scale-[1.02]
bg-background-default text-text-default
`} `}
> >
{/* Header section with icon */} {/* Header section with icon */}
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
<div className="w-6 h-6"> <div className="w-6 h-6 text-text-default">
{icon} {icon}
</div> </div>
<div> <div>
<div className="text-gray-600 dark:text-white/40 text-sm mb-1">{title}</div> <div className="text-text-muted text-sm mb-1">{title}</div>
<div className="text-gray-900 dark:text-white text-2xl font-semibold"> <div className="text-text-default text-2xl font-semibold">
{value} {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> </div>
</div> </div>
{/* Chart Container */} {/* Chart Container */}
<div className="w-full h-[160px] px-4"> <div className="w-full h-[200px] px-4 pb-6">
<ChartContainer config={chartConfig}> <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' ? ( {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 <Line
type="monotone" type="monotone"
dataKey="value" dataKey="value"
stroke="var(--color-value)" stroke="var(--chart-2)"
strokeWidth={2} strokeWidth={2}
dot={{ fill: 'var(--color-value)', r: 4 }} dot={{ fill: 'var(--chart-2)', r: 4 }}
/> />
<Tooltip />
</LineChart> </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 <Bar
dataKey="value" dataKey="value"
fill="var(--color-value)" fill="var(--chart-1)"
radius={[4, 4, 0, 0]} radius={4}
maxBarSize={32}
/> />
<Tooltip />
</BarChart> </BarChart>
)} )}
</ResponsiveContainer>
</ChartContainer> </ChartContainer>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React, { useState } from 'react';
import { useTimelineStyles } from '../../hooks/useTimelineStyles'; import { useTimelineStyles } from '../../hooks/useTimelineStyles';
import { ChartConfig, ChartContainer } from "@/components/ui/chart"; 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 { interface PieChartSegment {
value: number; value: number;
@@ -16,6 +16,90 @@ interface PieChartTileProps {
date?: Date; 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({ export default function PieChartTile({
title, title,
icon, icon,
@@ -23,102 +107,96 @@ export default function PieChartTile({
date date
}: PieChartTileProps) { }: PieChartTileProps) {
const { contentCardStyle } = useTimelineStyles(date); const { contentCardStyle } = useTimelineStyles(date);
const [activeIndex, setActiveIndex] = useState<number>(0);
// Convert segments to the format expected by recharts // Convert segments to the format expected by recharts and assign chart colors
const chartData = segments.map(segment => ({ const chartData = segments.map((segment, index) => ({
name: segment.label, 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 // Create chart configuration using the chart color variables
const chartConfig = segments.reduce((config, segment) => { const chartConfig = {
config[segment.label] = { [segments[0].label.toLowerCase()]: {
label: segment.label, label: segments[0].label,
color: segment.color color: 'var(--chart-1)'
}; },
return config; [segments[1].label.toLowerCase()]: {
}, {} as ChartConfig); 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 onPieEnter = (_: any, index: number) => {
const tooltipFormatter = (value: number, name: string) => { setActiveIndex(index);
const total = segments.reduce((sum, segment) => sum + segment.value, 0);
const percentage = ((value / total) * 100).toFixed(1);
return [`${percentage}%`, name];
}; };
return ( return (
<div <div
className={` className={`
flex flex-col flex flex-col
w-[320px] h-[380px] w-[320px] min-h-[380px]
${contentCardStyle} ${contentCardStyle}
rounded-[18px] rounded-[18px]
relative relative
overflow-hidden overflow-hidden
transition-all duration-200 transition-all duration-200
hover:scale-[1.02] hover:scale-[1.02]
bg-background-default text-text-default
`} `}
> >
{/* Header */} {/* Header */}
<div className="p-4"> <div className="p-4">
<div className="w-6 h-6 mb-4"> <div className="w-6 h-6 mb-4 text-text-default">
{icon} {icon}
</div> </div>
<div className="text-gray-600 dark:text-white/40 text-sm"> <div className="text-text-muted text-sm">
{title} {title}
</div> </div>
</div> </div>
{/* Pie Chart */} {/* Pie Chart */}
<div className="flex-1 flex flex-col items-center"> <div className="flex-1 flex items-center justify-center p-4">
<div className="w-full h-[200px]"> <div style={{ width: '100%', height: '260px', position: 'relative' }}>
<ChartContainer config={chartConfig}> <ChartContainer config={chartConfig}>
<PieChart> <ResponsiveContainer>
<PieChart margin={{ top: 30, right: 40, bottom: 10, left: 40 }}>
<Pie <Pie
activeIndex={activeIndex}
activeShape={renderActiveShape}
data={chartData} data={chartData}
dataKey="value"
nameKey="name"
cx="50%" cx="50%"
cy="50%" cy="50%"
innerRadius={0} innerRadius={45}
outerRadius={70} outerRadius={65}
paddingAngle={2} 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 <Cell
key={`cell-${index}`} key={`cell-${index}`}
fill={segment.color} fill={entry.chartColor}
className="transition-all duration-200 hover:opacity-90" stroke="var(--background-default)"
strokeWidth={2}
/> />
))} ))}
</Pie> </Pie>
<Tooltip formatter={tooltipFormatter} />
</PieChart> </PieChart>
</ResponsiveContainer>
</ChartContainer> </ChartContainer>
</div> </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>
</div> </div>
); );

View File

@@ -3,167 +3,257 @@
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@layer base { @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 { :root {
overflow: hidden; 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 */ /* shape */
--slate: #393838; --radius: 0.5rem;
/* block */ /* theming accents */
--block-teal: #13bbaf; --background-accent: var(--color-black);
--block-orange: #ff4f00; --border-accent: var(--color-black);
--text-accent: var(--color-black);
/* start arcade colors */ /* Semantic */
--constant-white: #ffffff; --background-default: var(--color-white);
--constant-black: #000000; --background-medium: var(--color-slate-200);
--grey-10: #101010; --background-muted: var(--color-slate-100);
--grey-20: #1e1e1e; --background-inverse: var(--color-black);
--grey-50: #666666; --background-danger: var(--color-red-200);
--grey-60: #959595; --background-success: var(--color-green-200);
--grey-80: #cccccc; --background-info: var(--color-blue-200);
--grey-85: #dadada; --background-warning: var(--color-yellow-200);
--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;
--background-app: var(--constant-white); --border-default: var(--color-slate-200);
--background-prominent: var(--grey-80); --border-input: var(--color-slate-200);
--background-standard: var(--grey-90); --border-strong: var(--color-slate-300);
--background-subtle: var(--grey-95); --border-inverse: var(--color-black);
--background-app-inverse: var(--constant-black); --border-danger: var(--color-red-200);
--background-subtle-inverse: var(--dark-grey-15); --border-success: var(--color-green-200);
--background-standard-inverse: var(--dark-grey-25); --border-warning: var(--color-yellow-200);
--background-prominent-inverse: var(--dark-grey-40); --border-info: var(--color-blue-200);
--border-divider: var(--grey-90); --text-default: var(--color-slate-600);
--border-inverse: var(--constant-white); --text-muted: var(--color-slate-400);
--border-prominent: var(--grey-10); --text-inverse: var(--color-white);
--border-standard: var(--grey-60); --text-danger: var(--color-red-200);
--border-subtle: var(--grey-90); --text-success: var(--color-green-200);
--text-warning: var(--color-yellow-200);
--text-info: var(--color-blue-200);
--icon-disabled: var(--grey-60); --ring: var(--border-strong);
--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);
--text-placeholder: var(--grey-60); --chart-1: #f6b44a;
--text-prominent: var(--grey-10); --chart-2: #7585ff;
--text-standard: var(--grey-20); --chart-3: #d76a6a;
--text-standard-inverse: var(--dark-grey-90); --chart-4: #d185e0;
--text-subtle: var(--grey-50); --chart-5: #91cb80;
--text-subtle-inverse: var(--dark-grey-60);
--text-prominent-inverse: var(--constant-white); --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);
} }
@media (prefers-color-scheme: dark) { .dark {
:root { /* theming accents */
--background-app: var(--constant-black); --background-accent: var(--color-white);
--background-prominent: var(--dark-grey-40); --border-accent: var(--color-white);
--background-standard: var(--dark-grey-25); --text-accent: var(--color-white);
--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);
--border-divider: var(--dark-grey-25); /* semantic */
--border-inverse: var(--constant-black); --background-default: var(--color-black);
--border-prominent: var(--constant-white); --background-medium: var(--color-slate-500);
--border-standard: var(--dark-grey-45); --background-muted: var(--color-slate-600);
--border-subtle: var(--dark-grey-25); --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);
--icon-disabled: var(--dark-grey-45); --border-default: var(--color-slate-600);
--icon-extra-subtle: var(--dark-grey-45); --border-input: var(--color-slate-600);
--icon-inverse: var(--constant-black); --border-strong: var(--color-slate-200);
--icon-prominent: var(--constant-white); --border-inverse: var(--color-white);
--icon-standard: var(--dark-grey-90); --border-danger: var(--color-red-200);
--icon-subtle: var(--dark-grey-60); --border-success: var(--color-green-200);
--border-warning: var(--color-yellow-200);
--border-info: var(--color-blue-200);
--text-placeholder: var(--dark-grey-45); --text-default: var(--color-white);
--text-prominent: var(--constant-white); --text-muted: var(--color-slate-300);
--text-standard: var(--dark-grey-90); --text-inverse: var(--color-black);
--text-standard-inverse: var(--grey-20); --text-danger: var(--color-red-100);
--text-subtle: var(--dark-grey-60); --text-success: var(--color-green-100);
--text-subtle-inverse: var(--grey-50); --text-warning: var(--color-yellow-100);
--text-prominent-inverse: var(--grey-20); --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);
} }
body { @theme inline {
background-color: var(--background-app); /* 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-face {
font-family: 'Cash Sans'; font-family: "Cash Sans";
src: src: url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Light.woff2)
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Regular.woff2) format("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) url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Regular.woff)
format('woff'); format("woff");
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Cash Sans'; font-family: "Cash Sans";
src: src: url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Medium.woff2)
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSans-Medium.woff2) format("woff2"),
format('woff2'), url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Medium.woff)
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSans-Medium.woff) format('woff'); format("woff");
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Cash Sans Mono'; font-family: "Cash Sans Mono";
src: src: url(../assets/fonts/CashSansMono-Light.woff2) format("woff2");
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff2/CashSansMono-Regular.woff2) font-weight: 300;
format('woff2'), font-style: normal;
url(https://cash-f.squarecdn.com/static/fonts/cashsans/woff/CashSansMono-Regular.woff) }
format('woff');
@font-face {
font-family: "Cash Sans Mono";
src: url(../assets/fonts/CashSansMono-Regular.woff2) format("woff2");
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
} }
@layer base {
* {
@apply border-border-default;
}
body {
@apply bg-background-default text-text-default;
}
}
.titlebar-drag-region { .titlebar-drag-region {
-webkit-app-region: drag; -webkit-app-region: drag;
height: 32px; height: 32px;
@@ -173,119 +263,3 @@
left: 0; left: 0;
z-index: 50; 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;
}
}