@parche/core 0.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,216 @@
1
+ ---
2
+ import 'parche:config/styles';
3
+ import BaseLayout from 'parche:layouts/BaseLayout';
4
+ import ThemePanel from 'parche:components/ThemePanel';
5
+ import LayoutRenderer from 'parche:LayoutRenderer';
6
+ import config from 'parche:config';
7
+ import { templateMap } from 'parche:registry/templates';
8
+ import { widgetMap } from 'parche:registry/widgets';
9
+ import { defaultLocale } from 'parche:config/i18n';
10
+ import { showPanel } from 'parche:config/themes';
11
+ import { resolveContent, getResolverPaths } from 'parche:registry/resolvers';
12
+ import { getEntry, render } from 'astro:content';
13
+ import {
14
+ buildSlugMap,
15
+ getAlternateUrls,
16
+ resolvePageFromSlug,
17
+ } from 'parche:utils/i18n';
18
+ import { resolveMetadata } from 'parche:utils/metadata';
19
+ import { resolveLayout } from 'parche:utils/layout';
20
+
21
+ export async function getStaticPaths() {
22
+ const slugMap = await buildSlugMap();
23
+
24
+ const pagePaths = slugMap.map((entry) => {
25
+ const { locale, pageKey, slug, data, entryId } = entry;
26
+
27
+ let urlSlug: string | undefined;
28
+ if (pageKey === 'home') {
29
+ urlSlug = locale === defaultLocale ? undefined : locale;
30
+ } else if (locale === defaultLocale) {
31
+ urlSlug = slug;
32
+ } else {
33
+ urlSlug = `${locale}/${slug}`;
34
+ }
35
+
36
+ return {
37
+ params: { slug: urlSlug },
38
+ props: { pageData: data, locale, pageKey, entryId },
39
+ };
40
+ });
41
+
42
+ // Add paths from app resolvers (e.g. blog posts at root level)
43
+ const { locales } = await import('parche:config/i18n');
44
+ const isDev = import.meta.env.DEV;
45
+ const resolverPaths = await getResolverPaths(locales, defaultLocale, { showDrafts: isDev });
46
+
47
+ return [...pagePaths, ...resolverPaths];
48
+ }
49
+
50
+ // ---- Render-time ----
51
+ // Determine what we're rendering: app content (via resolver) or page content.
52
+ let mode: 'resolver' | 'page' = 'page';
53
+ let resolvedApp: Awaited<ReturnType<typeof resolveContent>> = null;
54
+
55
+ // Page-mode variables
56
+ let pageData: any;
57
+ let locale: string = Astro.currentLocale ?? defaultLocale;
58
+ let pageKey: string = '';
59
+ let entryId: string = '';
60
+ let alternates: { locale: string; href: string }[] = [];
61
+
62
+ const isDev = import.meta.env.DEV;
63
+
64
+ if (Astro.props.fromResolver) {
65
+ // Static mode — this path came from a resolver's getPaths()
66
+ resolvedApp = await resolveContent(Astro.params.slug!, locale, {
67
+ showDrafts: isDev,
68
+ siteUrl: config.site.url || Astro.site?.href || '',
69
+ siteName: config.site.name,
70
+ });
71
+ if (resolvedApp) {
72
+ mode = 'resolver';
73
+ } else {
74
+ return Astro.redirect('/404');
75
+ }
76
+ } else if (Astro.props.pageData) {
77
+ // Static mode — page data provided by getStaticPaths
78
+ ({ pageData, locale, pageKey, entryId } = Astro.props);
79
+ } else {
80
+ // SSR mode — try resolvers first, then pages
81
+ resolvedApp = await resolveContent(Astro.params.slug ?? '', locale, {
82
+ showDrafts: isDev,
83
+ siteUrl: config.site.url || Astro.site?.href || '',
84
+ siteName: config.site.name,
85
+ });
86
+
87
+ if (resolvedApp) {
88
+ mode = 'resolver';
89
+ } else {
90
+ const resolved = await resolvePageFromSlug(Astro.params.slug, defaultLocale);
91
+ if (!resolved) {
92
+ return Astro.redirect('/404');
93
+ }
94
+ ({ pageData, locale, pageKey } = resolved);
95
+ entryId = resolved.entryId;
96
+ }
97
+ }
98
+
99
+ // ---- Resolver mode: app-provided content (e.g. blog post) ----
100
+ let AppTemplate: any = null;
101
+ let AppContent: any = null;
102
+ let appMetadata: any = null;
103
+ let appExtras: any = {};
104
+ const RelatedPosts = widgetMap['blog/RelatedPosts'];
105
+ const SeriesNav = widgetMap['blog/SeriesNav'];
106
+
107
+ if (mode === 'resolver' && resolvedApp) {
108
+ AppTemplate = templateMap[resolvedApp.template];
109
+ appMetadata = resolvedApp.metadata;
110
+ appExtras = resolvedApp.extras;
111
+
112
+ try {
113
+ const entry = await getEntry(resolvedApp.collection as any, resolvedApp.entryId as any);
114
+ if (entry) {
115
+ const { Content } = await render(entry);
116
+ AppContent = Content;
117
+ }
118
+ } catch { /* non-renderable entry */ }
119
+ }
120
+
121
+ // ---- Page mode: standard page content ----
122
+ let pageMetadata: any = null;
123
+ let pageTemplate: string = 'dynamic';
124
+ let PageTemplateComponent: any = null;
125
+ let PageMarkdownContent: any = null;
126
+ let pageLayoutName: string = 'default';
127
+
128
+ if (mode === 'page' && pageData) {
129
+ const slugMap = await buildSlugMap();
130
+ alternates = getAlternateUrls(pageKey, slugMap, defaultLocale, Astro.site);
131
+ pageTemplate = pageData.template || 'dynamic';
132
+
133
+ const resolved = resolveMetadata(pageData, config, { locale });
134
+ resolved.title = pageKey === 'home'
135
+ ? config.site.name
136
+ : `${resolved.title} — ${config.site.name}`;
137
+ pageMetadata = resolved;
138
+
139
+ PageTemplateComponent = pageTemplate !== 'dynamic' ? templateMap[pageTemplate] : null;
140
+
141
+ const pageEntry = await getEntry('pages', entryId);
142
+ if (pageEntry) {
143
+ try {
144
+ const { Content } = await render(pageEntry);
145
+ PageMarkdownContent = Content;
146
+ } catch {
147
+ // JSON entries don't support render()
148
+ }
149
+ }
150
+ pageLayoutName = pageData.layout || 'default';
151
+ }
152
+
153
+ const metadata = mode === 'resolver' ? appMetadata : pageMetadata;
154
+ const layoutName = mode === 'resolver'
155
+ ? (resolvedApp?.layout || 'default')
156
+ : pageLayoutName;
157
+ const layoutSections = await resolveLayout(layoutName, locale, defaultLocale);
158
+ ---
159
+
160
+ <BaseLayout metadata={metadata} config={config} lang={locale}>
161
+ {mode === 'page' && alternates.length > 0 && (
162
+ <Fragment slot="head">
163
+ {alternates.map((alt) => (
164
+ <link rel="alternate" hreflang={alt.locale} href={alt.href} />
165
+ ))}
166
+ <link
167
+ rel="alternate"
168
+ hreflang="x-default"
169
+ href={alternates.find((a) => a.locale === defaultLocale)?.href}
170
+ />
171
+ </Fragment>
172
+ )}
173
+
174
+ {mode === 'resolver' && resolvedApp ? (
175
+ <LayoutRenderer
176
+ layoutSections={layoutSections}
177
+ pageTemplate="dynamic"
178
+ >
179
+ {AppTemplate ? (
180
+ <AppTemplate {...resolvedApp.templateProps}>
181
+ {AppContent && <AppContent />}
182
+ </AppTemplate>
183
+ ) : (
184
+ <article class="prose max-w-4xl mx-auto py-16 px-4">
185
+ {AppContent && <AppContent />}
186
+ </article>
187
+ )}
188
+
189
+ {appExtras.seriesNav && SeriesNav && (
190
+ <div class="max-w-4xl mx-auto px-4 mb-8">
191
+ <SeriesNav
192
+ seriesName={appExtras.seriesNav.seriesName}
193
+ posts={appExtras.seriesNav.posts}
194
+ currentOrder={appExtras.seriesNav.currentOrder}
195
+ />
196
+ </div>
197
+ )}
198
+
199
+ {appExtras.relatedPosts && RelatedPosts && (
200
+ <RelatedPosts posts={appExtras.relatedPosts} />
201
+ )}
202
+ </LayoutRenderer>
203
+ ) : (
204
+ <LayoutRenderer
205
+ layoutSections={layoutSections}
206
+ pageSections={pageData?.sections}
207
+ pageTemplate={pageTemplate}
208
+ PageTemplateComponent={PageTemplateComponent}
209
+ pageData={pageData}
210
+ PageMarkdownContent={PageMarkdownContent}
211
+ />
212
+
213
+ )}
214
+
215
+ {showPanel && <ThemePanel />}
216
+ </BaseLayout>
@@ -0,0 +1,18 @@
1
+ import { defineMiddleware } from 'astro:middleware';
2
+
3
+ /**
4
+ * Parche middleware — required by Astro's `routing: 'manual'` i18n mode.
5
+ * Enriches Astro.locals.parche with resolved locale info.
6
+ * Users can override this via `routes.middleware` in parche config.
7
+ */
8
+ export const onRequest = defineMiddleware((context, next) => {
9
+ // Astro's i18n system sets currentLocale automatically even in manual mode
10
+ // We expose it in locals for convenience in user components
11
+ const locale = context.currentLocale || 'en';
12
+
13
+ context.locals.parche = {
14
+ locale,
15
+ };
16
+
17
+ return next();
18
+ });
@@ -0,0 +1,221 @@
1
+ /* =================================================================
2
+ Capa 3: Base — Entry point del design system
3
+ Importa Tailwind + tokens + semánticos.
4
+ Define dark variant, reset mínimo, y clases tipográficas compuestas.
5
+ ================================================================= */
6
+
7
+ @import "tailwindcss";
8
+ @import "./tokens.css";
9
+ @import "./semantic.css";
10
+ @import "./shadcn-compat.css";
11
+
12
+ /* Scan core's own component files. Self-relative, so it works both in the
13
+ monorepo and when installed. A consuming app's own files are picked up by its
14
+ Tailwind setup automatically. */
15
+ @source "../../**/*.{astro,ts}";
16
+
17
+ /* NOTE: the imported parches' component globs are appended here at build time
18
+ by vite-plugin-parche's transform hook — as absolute `@source` lines — since
19
+ relative paths can't reach sibling packages once installed from npm. */
20
+
21
+ /* Dark mode via clase .dark en <html> */
22
+ @custom-variant dark (&:where(.dark, .dark *));
23
+
24
+ /* ---------------------------------------------------------------
25
+ Reset base mínimo
26
+ --------------------------------------------------------------- */
27
+ @layer base {
28
+ html {
29
+ -webkit-font-smoothing: antialiased;
30
+ -moz-osx-font-smoothing: grayscale;
31
+ text-rendering: optimizeLegibility;
32
+ scroll-behavior: smooth;
33
+ }
34
+
35
+ body {
36
+ font-family: var(--font-sans);
37
+ background-color: var(--color-background);
38
+ color: var(--color-text);
39
+ transition: background-color 0.2s ease, color 0.2s ease;
40
+ }
41
+ }
42
+
43
+ /* ---------------------------------------------------------------
44
+ Clases tipográficas compuestas
45
+ Uso: <h1 class="type-h1">
46
+ --------------------------------------------------------------- */
47
+ @layer components {
48
+ .type-h1 {
49
+ font-family: var(--ds-font-heading);
50
+ font-size: var(--ds-size-h1);
51
+ font-weight: var(--ds-weight-h1);
52
+ letter-spacing: var(--ds-tracking-h1);
53
+ line-height: var(--ds-leading-h1);
54
+ color: var(--color-heading);
55
+ }
56
+
57
+ .type-h2 {
58
+ font-family: var(--ds-font-heading);
59
+ font-size: var(--ds-size-h2);
60
+ font-weight: var(--ds-weight-h2);
61
+ letter-spacing: var(--ds-tracking-h2);
62
+ line-height: var(--ds-leading-h2);
63
+ color: var(--color-heading);
64
+ }
65
+
66
+ .type-h3 {
67
+ font-family: var(--ds-font-heading);
68
+ font-size: var(--ds-size-h3);
69
+ font-weight: var(--ds-weight-h3);
70
+ letter-spacing: var(--ds-tracking-h3);
71
+ line-height: var(--ds-leading-h3);
72
+ color: var(--color-heading);
73
+ }
74
+
75
+ .type-body {
76
+ font-family: var(--ds-font-body);
77
+ font-size: var(--ds-size-body);
78
+ font-weight: var(--ds-weight-body);
79
+ letter-spacing: var(--ds-tracking-body);
80
+ line-height: var(--ds-leading-body);
81
+ color: var(--color-text);
82
+ }
83
+
84
+ .type-caption {
85
+ font-size: var(--ds-size-caption);
86
+ font-weight: var(--ds-weight-caption);
87
+ letter-spacing: var(--ds-tracking-caption);
88
+ line-height: var(--ds-leading-caption);
89
+ color: var(--color-muted);
90
+ }
91
+
92
+ .type-label {
93
+ font-size: var(--ds-size-label);
94
+ font-weight: var(--ds-weight-label);
95
+ letter-spacing: var(--ds-tracking-label);
96
+ line-height: var(--ds-leading-label);
97
+ text-transform: uppercase;
98
+ color: var(--color-muted);
99
+ }
100
+
101
+ /* Highlight — vibrant emphasis color, distinct from shadcn's --accent (subtle bg). */
102
+ .text-highlight { color: var(--ds-color-highlight); }
103
+ .bg-highlight { background-color: var(--ds-color-highlight); }
104
+
105
+ /* ---------------------------------------------------------------
106
+ Prose — Markdown content styling
107
+ Used by the content template when rendering .md pages.
108
+ Mirrors the design system tokens so markdown output matches
109
+ the manually-styled HTML it replaces.
110
+ --------------------------------------------------------------- */
111
+ .prose {
112
+ font-family: var(--ds-font-body);
113
+ font-size: var(--ds-size-body);
114
+ font-weight: var(--ds-weight-body);
115
+ letter-spacing: var(--ds-tracking-body);
116
+ line-height: var(--ds-leading-body);
117
+ color: var(--color-muted);
118
+
119
+ & > * + * {
120
+ margin-top: 1.5em;
121
+ }
122
+
123
+ & h2 {
124
+ font-family: var(--ds-font-heading);
125
+ font-size: var(--ds-size-h3);
126
+ font-weight: var(--ds-weight-h3);
127
+ letter-spacing: var(--ds-tracking-h3);
128
+ line-height: var(--ds-leading-h3);
129
+ color: var(--color-heading);
130
+ margin-top: 2em;
131
+ margin-bottom: 0.75em;
132
+ }
133
+
134
+ & h3 {
135
+ font-family: var(--ds-font-heading);
136
+ font-size: 1.25rem;
137
+ font-weight: var(--ds-weight-h3);
138
+ letter-spacing: var(--ds-tracking-h3);
139
+ line-height: var(--ds-leading-h3);
140
+ color: var(--color-heading);
141
+ margin-top: 1.75em;
142
+ margin-bottom: 0.5em;
143
+ }
144
+
145
+ & h4 {
146
+ font-family: var(--ds-font-heading);
147
+ font-size: 1.125rem;
148
+ font-weight: var(--ds-weight-h3);
149
+ color: var(--color-heading);
150
+ margin-top: 1.5em;
151
+ margin-bottom: 0.5em;
152
+ }
153
+
154
+ & p {
155
+ margin-top: 0;
156
+ margin-bottom: 0;
157
+ }
158
+
159
+ & a {
160
+ color: var(--color-primary);
161
+ text-decoration: none;
162
+ &:hover {
163
+ text-decoration: underline;
164
+ }
165
+ }
166
+
167
+ & strong {
168
+ color: var(--color-heading);
169
+ font-weight: 600;
170
+ }
171
+
172
+ & ul, & ol {
173
+ padding-left: 1.5em;
174
+ }
175
+
176
+ & ul {
177
+ list-style-type: disc;
178
+ }
179
+
180
+ & ol {
181
+ list-style-type: decimal;
182
+ }
183
+
184
+ & li + li {
185
+ margin-top: 0.5em;
186
+ }
187
+
188
+ & blockquote {
189
+ border-left: 3px solid var(--color-border);
190
+ padding-left: 1em;
191
+ color: var(--color-muted);
192
+ font-style: italic;
193
+ }
194
+
195
+ & code {
196
+ font-family: var(--font-mono);
197
+ font-size: 0.875em;
198
+ background-color: var(--color-surface);
199
+ padding: 0.125em 0.375em;
200
+ border-radius: 0.25rem;
201
+ }
202
+
203
+ & pre {
204
+ background-color: var(--color-surface);
205
+ padding: 1em;
206
+ border-radius: 0.5rem;
207
+ overflow-x: auto;
208
+ }
209
+
210
+ & pre code {
211
+ background: none;
212
+ padding: 0;
213
+ }
214
+
215
+ & hr {
216
+ border: none;
217
+ border-top: 1px solid var(--color-border);
218
+ margin: 2em 0;
219
+ }
220
+ }
221
+ }
@@ -0,0 +1,95 @@
1
+ /* =================================================================
2
+ Capa 2: Tokens semánticos
3
+ Mapea primitivos a roles contextuales. Cambia según light/dark.
4
+ @theme inline genera clases Tailwind que leen CSS vars,
5
+ permitiendo que los temas overrideen los valores.
6
+ ================================================================= */
7
+
8
+ /* ---------------------------------------------------------------
9
+ Conectar variables semánticas con Tailwind
10
+ bg-background, text-foreground, bg-surface, etc.
11
+ --------------------------------------------------------------- */
12
+ @theme inline {
13
+ --color-background: var(--ds-color-background);
14
+ --color-foreground: var(--ds-color-foreground);
15
+ --color-surface: var(--ds-color-surface);
16
+ --color-primary: var(--ds-color-primary);
17
+ --color-on-primary: var(--ds-color-on-primary);
18
+ --color-muted: var(--ds-color-muted);
19
+ --color-border: var(--ds-color-border);
20
+ --color-heading: var(--ds-color-heading);
21
+ --color-text: var(--ds-color-text);
22
+ }
23
+
24
+ /* ---------------------------------------------------------------
25
+ Light mode (default)
26
+ --------------------------------------------------------------- */
27
+ :root {
28
+ /* Color roles — AstroWind v1 defaults */
29
+ --ds-color-background: oklch(1 0 0);
30
+ --ds-color-foreground: oklch(0.07 0.01 260);
31
+ --ds-color-surface: oklch(1 0 0);
32
+ --ds-color-primary: var(--color-neutral-900) /* oklch(0.500 0.220 260) */;
33
+ --ds-color-on-primary: oklch(1 0 0);
34
+ --ds-color-muted: oklch(0.55 0.02 264.42);
35
+ --ds-color-border: oklch(0.90 0.006 260);
36
+ --ds-color-heading: oklch(0.07 0.01 260);
37
+ --ds-color-text: oklch(0.25 0.008 260);
38
+ --ds-color-highlight: oklch(0.420 0.270 295); /* v1 accent purple: rgb(109 40 217) */
39
+
40
+ /* Typography — Inter everywhere, matching v1 sizes */
41
+ --ds-font-heading: var(--font-sans);
42
+ --ds-font-body: var(--font-sans);
43
+
44
+ /* Typography — H1 */
45
+ --ds-size-h1: 3.75rem; /* 60px — matches v1 */
46
+ --ds-weight-h1: 700;
47
+ --ds-tracking-h1: -1.26125px;
48
+ --ds-leading-h1: 1.08;
49
+
50
+ /* Typography — H2 */
51
+ --ds-size-h2: 2.40rem;
52
+ --ds-weight-h2: 700;
53
+ --ds-tracking-h2: -1.26125px;
54
+ --ds-leading-h2: 1.15;
55
+
56
+ /* Typography — H3 */
57
+ --ds-size-h3: 1.5rem;
58
+ --ds-weight-h3: 600;
59
+ --ds-tracking-h3: 0;
60
+ --ds-leading-h3: 1.3;
61
+
62
+ /* Typography — Body */
63
+ --ds-size-body: 1rem;
64
+ --ds-weight-body: 400;
65
+ --ds-tracking-body: 0em;
66
+ --ds-leading-body: 1.66;
67
+
68
+ /* Typography — Caption */
69
+ --ds-size-caption: 0.875rem;
70
+ --ds-weight-caption: 400;
71
+ --ds-tracking-caption: 0.01em;
72
+ --ds-leading-caption: 1.5;
73
+
74
+ /* Typography — Label */
75
+ --ds-size-label: 0.875rem;
76
+ --ds-weight-label: 600;
77
+ --ds-tracking-label: 0.05em;
78
+ --ds-leading-label: 1.4;
79
+ }
80
+
81
+ /* ---------------------------------------------------------------
82
+ Dark mode
83
+ --------------------------------------------------------------- */
84
+ .dark {
85
+ --ds-color-background: oklch(0.100 0.040 260); /* v1 dark navy: rgb(3 6 32) */
86
+ --ds-color-foreground: oklch(0.960 0.005 260);
87
+ --ds-color-surface: oklch(0.140 0.040 260);
88
+ --ds-color-primary: oklch(0.500 0.220 260); /* same blue in dark */
89
+ --ds-color-on-primary: oklch(1 0 0);
90
+ --ds-color-muted: oklch(0.55 0.015 260);
91
+ --ds-color-border: oklch(0.200 0.030 260);
92
+ --ds-color-heading: oklch(0.970 0.003 260);
93
+ --ds-color-text: oklch(0.800 0.010 250);
94
+ --ds-color-highlight: oklch(0.550 0.250 295); /* lighter purple for dark mode */
95
+ }
@@ -0,0 +1,120 @@
1
+ /* =================================================================
2
+ shadcn/ui Compatibility Layer
3
+ Maps shadcn/ui CSS variable names to existing design system tokens.
4
+ This is a pure alias layer — no new values, just pointers.
5
+ ================================================================= */
6
+
7
+ /* ---------------------------------------------------------------
8
+ Light mode aliases
9
+ --------------------------------------------------------------- */
10
+ :root {
11
+ --background: var(--ds-color-background);
12
+ --foreground: var(--ds-color-foreground);
13
+
14
+ --card: var(--ds-color-surface);
15
+ --card-foreground: var(--ds-color-foreground);
16
+
17
+ --popover: var(--ds-color-surface);
18
+ --popover-foreground: var(--ds-color-foreground);
19
+
20
+ --primary: var(--ds-color-primary);
21
+ --primary-foreground: var(--ds-color-on-primary);
22
+
23
+ --secondary: var(--color-neutral-100);
24
+ --secondary-foreground: var(--color-neutral-900);
25
+
26
+ --muted: var(--color-neutral-100);
27
+ --muted-foreground: var(--ds-color-muted);
28
+
29
+ --accent: var(--color-neutral-100);
30
+ --accent-foreground: var(--color-neutral-900);
31
+
32
+ --destructive: var(--color-danger-600);
33
+ --destructive-foreground: oklch(1 0 0);
34
+
35
+ --border: var(--ds-color-border);
36
+ --input: var(--ds-color-border);
37
+ --ring: var(--ds-color-primary);
38
+
39
+ --radius: var(--radius-md);
40
+
41
+ --chart-1: var(--color-primary-500);
42
+ --chart-2: var(--color-secondary-500);
43
+ --chart-3: var(--color-accent-500);
44
+ --chart-4: var(--color-success-500);
45
+ --chart-5: var(--color-warning-500);
46
+
47
+ /* Sidebar (shadcn/ui sidebar component) */
48
+ --sidebar: var(--ds-color-surface);
49
+ --sidebar-foreground: var(--ds-color-foreground);
50
+ --sidebar-primary: var(--ds-color-primary);
51
+ --sidebar-primary-foreground: var(--ds-color-on-primary);
52
+ --sidebar-accent: var(--color-neutral-100);
53
+ --sidebar-accent-foreground: var(--color-neutral-900);
54
+ --sidebar-border: var(--ds-color-border);
55
+ --sidebar-ring: var(--ds-color-primary);
56
+ }
57
+
58
+ /* ---------------------------------------------------------------
59
+ Dark mode aliases
60
+ --------------------------------------------------------------- */
61
+ .dark {
62
+ --secondary: var(--color-neutral-800);
63
+ --secondary-foreground: var(--color-neutral-100);
64
+
65
+ --muted: var(--color-neutral-800);
66
+ --muted-foreground: var(--ds-color-muted);
67
+
68
+ --accent: var(--color-neutral-800);
69
+ --accent-foreground: var(--color-neutral-50);
70
+
71
+ --destructive: var(--color-danger-400);
72
+ --destructive-foreground: oklch(1 0 0);
73
+
74
+ --chart-1: var(--color-primary-400);
75
+ --chart-2: var(--color-secondary-400);
76
+ --chart-3: var(--color-accent-400);
77
+ --chart-4: var(--color-success-400);
78
+ --chart-5: var(--color-warning-400);
79
+
80
+ --sidebar-accent: var(--color-neutral-800);
81
+ --sidebar-accent-foreground: var(--color-neutral-50);
82
+ }
83
+
84
+ /* ---------------------------------------------------------------
85
+ Bridge shadcn/ui tokens into Tailwind v4
86
+ Generates utilities: bg-card, text-card-foreground,
87
+ bg-destructive, text-muted-foreground, border-input, etc.
88
+
89
+ Note: --color-background, --color-foreground, --color-primary,
90
+ --color-muted, --color-border are already bridged in semantic.css
91
+ --------------------------------------------------------------- */
92
+ @theme inline {
93
+ --color-card: var(--card);
94
+ --color-card-foreground: var(--card-foreground);
95
+ --color-popover: var(--popover);
96
+ --color-popover-foreground: var(--popover-foreground);
97
+ --color-primary-foreground: var(--primary-foreground);
98
+ --color-secondary: var(--secondary);
99
+ --color-secondary-foreground: var(--secondary-foreground);
100
+ --color-muted-foreground: var(--muted-foreground);
101
+ --color-accent: var(--accent);
102
+ --color-accent-foreground: var(--accent-foreground);
103
+ --color-destructive: var(--destructive);
104
+ --color-destructive-foreground: var(--destructive-foreground);
105
+ --color-input: var(--input);
106
+ --color-ring: var(--ring);
107
+ --color-chart-1: var(--chart-1);
108
+ --color-chart-2: var(--chart-2);
109
+ --color-chart-3: var(--chart-3);
110
+ --color-chart-4: var(--chart-4);
111
+ --color-chart-5: var(--chart-5);
112
+ --color-sidebar: var(--sidebar);
113
+ --color-sidebar-foreground: var(--sidebar-foreground);
114
+ --color-sidebar-primary: var(--sidebar-primary);
115
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
116
+ --color-sidebar-accent: var(--sidebar-accent);
117
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
118
+ --color-sidebar-border: var(--sidebar-border);
119
+ --color-sidebar-ring: var(--sidebar-ring);
120
+ }