@camox/cli 0.16.0 → 0.16.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camox/cli",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "bin": {
5
5
  "camox": "./dist/index.mjs"
6
6
  },
@@ -26,7 +26,7 @@
26
26
  "@types/node": "^24.12.2",
27
27
  "@typescript/native-preview": "7.0.0-dev.20260412.1",
28
28
  "vite-plus": "latest",
29
- "@camox/api-contract": "0.16.0"
29
+ "@camox/api-contract": "0.16.1"
30
30
  },
31
31
  "nx": {
32
32
  "tags": [
@@ -6,7 +6,7 @@
6
6
  "tailwind": {
7
7
  "config": "",
8
8
  "css": "src/styles.css",
9
- "baseColor": "gray",
9
+ "baseColor": "zinc",
10
10
  "cssVariables": true,
11
11
  "prefix": ""
12
12
  },
@@ -18,5 +18,8 @@
18
18
  "lib": "@/lib",
19
19
  "hooks": "@/hooks"
20
20
  },
21
+ "rtl": false,
22
+ "menuColor": "default",
23
+ "menuAccent": "subtle",
21
24
  "registries": {}
22
25
  }
@@ -13,6 +13,8 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@base-ui/react": "^1.4.0",
16
+ "@fontsource-variable/inter": "^5.2.8",
17
+ "@fontsource-variable/noto-serif": "^5.2.9",
16
18
  "@tailwindcss/vite": "^4.2.2",
17
19
  "@tanstack/react-query": "^5.99.0",
18
20
  "@tanstack/react-router": "^1.168.18",
@@ -26,7 +28,7 @@
26
28
  "nitro": "3.0.260311-beta",
27
29
  "react": "^19.2.5",
28
30
  "react-dom": "^19.2.5",
29
- "shadcn": "^4.3.1",
31
+ "shadcn": "^4.6.0",
30
32
  "tailwind-merge": "^3.5.0",
31
33
  "tailwindcss": "^4.0.6"
32
34
  },
@@ -11,11 +11,11 @@ const footer = createBlock({
11
11
  links: Type.RepeatableItem({
12
12
  content: {
13
13
  link: Type.Link({
14
- default: { text: "Link", href: "#", newTab: false },
14
+ default: { text: "Footer link", href: "#", newTab: false },
15
15
  title: "Link",
16
16
  }),
17
17
  },
18
- minItems: 1,
18
+ minItems: 2,
19
19
  maxItems: 12,
20
20
  title: "Links",
21
21
  toMarkdown: (c) => [c.link],
@@ -27,14 +27,17 @@ const footer = createBlock({
27
27
 
28
28
  function FooterComponent() {
29
29
  return (
30
- <footer className="dark bg-background py-12">
30
+ <footer className="dark bg-background py-4">
31
31
  <div className="container mx-auto px-4">
32
- <div className="flex flex-col items-center gap-6 sm:flex-row sm:justify-between">
33
- <footer.Field name="title">
34
- {(props) => <div {...props} className="text-foreground text-lg font-bold" />}
35
- </footer.Field>
32
+ <div className="flex flex-wrap items-center justify-between gap-x-6 gap-y-2">
33
+ <div className="flex items-center gap-2">
34
+ <footer.Field name="title">
35
+ {(props) => <div {...props} className="text-foreground text-sm font-bold" />}
36
+ </footer.Field>
37
+ <div className="text-muted-foreground text-sm">&copy; {new Date().getFullYear()}</div>
38
+ </div>
36
39
 
37
- <div className="flex flex-wrap items-center gap-4">
40
+ <div className="ml-auto flex flex-wrap items-center justify-end gap-4">
38
41
  <footer.Repeater name="links">
39
42
  {(linkItem) => (
40
43
  <linkItem.Link name="link">
@@ -49,10 +52,6 @@ function FooterComponent() {
49
52
  </footer.Repeater>
50
53
  </div>
51
54
  </div>
52
-
53
- <div className="text-muted-foreground mt-8 text-center text-sm">
54
- &copy; {new Date().getFullYear()} All rights reserved.
55
- </div>
56
55
  </div>
57
56
  </footer>
58
57
  );
@@ -10,11 +10,11 @@ const hero = createBlock({
10
10
  "Use this block as the main landing section at the top of a page. It should capture attention immediately with a clear value proposition.",
11
11
  content: {
12
12
  title: Type.String({
13
- default: "Welcome to {{projectName}}",
13
+ default: "Let's get going on {{projectName}}",
14
14
  title: "Title",
15
15
  }),
16
16
  description: Type.String({
17
- default: "Build something amazing with Camox.",
17
+ default: "Build something amazing with Camox. Press ⌘+Enter to start editing content.",
18
18
  maxLength: 280,
19
19
  title: "Description",
20
20
  }),
@@ -22,12 +22,55 @@ const hero = createBlock({
22
22
  default: { text: "Get Started", href: "/", newTab: false },
23
23
  title: "CTA",
24
24
  }),
25
+ illustration: Type.Image({
26
+ title: "Illustration",
27
+ }),
28
+ },
29
+ settings: {
30
+ withIllustration: Type.Boolean({
31
+ default: true,
32
+ title: "With illustration",
33
+ }),
25
34
  },
26
35
  component: HeroComponent,
27
- toMarkdown: (c) => [`# ${c.title}`, c.description, c.cta],
36
+ toMarkdown: (c, s) => [`# ${c.title}`, c.description, s.withIllustration(c.illustration), c.cta],
28
37
  });
29
38
 
30
39
  function HeroComponent() {
40
+ const withIllustration = hero.useSetting("withIllustration");
41
+
42
+ if (withIllustration) {
43
+ return (
44
+ <section className="py-32">
45
+ <div className="container mx-auto px-4">
46
+ <div className="grid items-center gap-12 lg:grid-cols-[1fr_auto]">
47
+ <div className="text-left">
48
+ <hero.Field name="title">
49
+ {(props) => (
50
+ <h1
51
+ {...props}
52
+ className="text-foreground mb-6 text-5xl font-bold tracking-tight sm:text-6xl"
53
+ />
54
+ )}
55
+ </hero.Field>
56
+ <hero.Field name="description">
57
+ {(props) => <p {...props} className="text-muted-foreground mb-10 text-xl" />}
58
+ </hero.Field>
59
+ <hero.Link name="cta">
60
+ {(props) => <Button size="lg" nativeButton={false} render={<Link {...props} />} />}
61
+ </hero.Link>
62
+ </div>
63
+ <hero.Image name="illustration">
64
+ {(props) => (
65
+ <img {...props} className="h-auto w-full max-w-sm rounded-lg lg:max-w-md" />
66
+ )}
67
+ </hero.Image>
68
+ </div>
69
+ </div>
70
+ </section>
71
+ );
72
+ }
73
+
31
74
  return (
32
75
  <section className="flex flex-col items-center justify-center py-32">
33
76
  <div className="container mx-auto px-4">
@@ -45,7 +45,7 @@ function NavbarComponent() {
45
45
  <div className="container mx-auto px-4">
46
46
  <div className="flex h-16 items-center justify-between">
47
47
  <navbar.Link name="title">
48
- {(props) => <Link {...props} className="text-foreground text-xl font-bold" />}
48
+ {(props) => <Link {...props} className="text-foreground text-lg font-bold" />}
49
49
  </navbar.Link>
50
50
 
51
51
  <div className="flex items-center gap-6">
@@ -45,50 +45,47 @@ const statistics = createBlock({
45
45
  function StatisticsComponent() {
46
46
  return (
47
47
  <section className="dark bg-background py-24">
48
- <div className="container mx-auto px-4">
49
- <div className="mx-auto max-w-6xl">
50
- <div className="mb-16">
51
- <statistics.Field name="title">
52
- {(props) => (
53
- <div
54
- {...props}
55
- className="text-primary mb-4 text-sm font-semibold tracking-wider uppercase"
56
- />
57
- )}
58
- </statistics.Field>
59
- <statistics.Field name="subtitle">
60
- {(props) => (
61
- <h2 {...props} className="text-foreground mb-6 text-4xl font-bold sm:text-5xl" />
62
- )}
63
- </statistics.Field>
64
- <statistics.Field name="description">
65
- {(props) => (
66
- <p {...props} className="text-muted-foreground max-w-3xl text-lg leading-relaxed" />
67
- )}
68
- </statistics.Field>
69
- </div>
70
-
71
- <div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-4">
72
- <statistics.Repeater name="statistics">
73
- {(stat) => (
74
- <div className="flex gap-3">
75
- <div className="w-0.5 bg-linear-to-b from-teal-400 to-blue-500" />
76
- <div className="flex flex-col">
77
- <stat.Field name="number">
78
- {(props) => (
79
- <div {...props} className="text-foreground mb-2 text-4xl font-bold" />
80
- )}
81
- </stat.Field>
82
- <stat.Field name="label">
83
- {(props) => (
84
- <p {...props} className="text-muted-foreground text-sm leading-relaxed" />
85
- )}
86
- </stat.Field>
87
- </div>
48
+ <div className="container mx-auto">
49
+ <div className="mb-16">
50
+ <statistics.Field name="title">
51
+ {(props) => (
52
+ <div
53
+ {...props}
54
+ className="text-accent-foreground mb-4 text-sm font-semibold tracking-wider uppercase"
55
+ />
56
+ )}
57
+ </statistics.Field>
58
+ <statistics.Field name="subtitle">
59
+ {(props) => (
60
+ <h2 {...props} className="text-foreground mb-6 text-4xl font-bold sm:text-5xl" />
61
+ )}
62
+ </statistics.Field>
63
+ <statistics.Field name="description">
64
+ {(props) => (
65
+ <p {...props} className="text-muted-foreground max-w-3xl text-lg leading-relaxed" />
66
+ )}
67
+ </statistics.Field>
68
+ </div>
69
+ <div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-4">
70
+ <statistics.Repeater name="statistics">
71
+ {(stat) => (
72
+ <div className="flex gap-3">
73
+ <div className="w-0.5 bg-linear-to-b from-teal-400 to-emerald-500" />
74
+ <div className="flex flex-col">
75
+ <stat.Field name="number">
76
+ {(props) => (
77
+ <div {...props} className="text-foreground mb-2 text-4xl font-bold" />
78
+ )}
79
+ </stat.Field>
80
+ <stat.Field name="label">
81
+ {(props) => (
82
+ <p {...props} className="text-muted-foreground text-sm leading-relaxed" />
83
+ )}
84
+ </stat.Field>
88
85
  </div>
89
- )}
90
- </statistics.Repeater>
91
- </div>
86
+ </div>
87
+ )}
88
+ </statistics.Repeater>
92
89
  </div>
93
90
  </div>
94
91
  </section>
@@ -0,0 +1,158 @@
1
+ import { Type, createBlock } from "camox/createBlock";
2
+
3
+ import { cn } from "@/lib/utils";
4
+
5
+ const youtubeVideo = createBlock({
6
+ id: "youtube-video",
7
+ title: "YouTube Video",
8
+ description:
9
+ "Embeds a YouTube video. Use this block to display a single YouTube video on a page. Don't try to guess the URL, use a web search tool to find a specific video URL instead.",
10
+ content: {
11
+ url: Type.Embed({
12
+ pattern:
13
+ "https:\\/\\/(www\\.)?(youtube\\.com\\/(watch\\?v=|embed\\/|shorts\\/)|youtu\\.be\\/).+",
14
+ default: "https://www.youtube.com/watch?v=-W_nFlIAWFM",
15
+ title: "YouTube URL",
16
+ }),
17
+ },
18
+ settings: {
19
+ fullWidth: Type.Boolean({
20
+ default: false,
21
+ title: "Full Width",
22
+ }),
23
+ theme: Type.Enum({
24
+ options: {
25
+ light: "Light",
26
+ dark: "Dark",
27
+ },
28
+ default: "light",
29
+ title: "Theme",
30
+ }),
31
+ autoplay: Type.Boolean({
32
+ default: false,
33
+ title: "Autoplay",
34
+ }),
35
+ mute: Type.Boolean({
36
+ default: false,
37
+ title: "Mute",
38
+ }),
39
+ controls: Type.Boolean({
40
+ default: true,
41
+ title: "Controls",
42
+ }),
43
+ showCaptions: Type.Boolean({
44
+ default: false,
45
+ title: "Show Captions",
46
+ }),
47
+ rel: Type.Boolean({
48
+ default: false,
49
+ title: "Related Videos",
50
+ }),
51
+ fullscreen: Type.Boolean({
52
+ default: true,
53
+ title: "Fullscreen",
54
+ }),
55
+ },
56
+ component: YouTubeVideoComponent,
57
+ toMarkdown: (c) => [c.url],
58
+ });
59
+
60
+ function extractVideoId(url: string): string | null {
61
+ const shortMatch = url.match(/youtu\.be\/([^?&]+)/);
62
+ if (shortMatch) return shortMatch[1];
63
+
64
+ const shortsMatch = url.match(/youtube\.com\/shorts\/([^?&]+)/);
65
+ if (shortsMatch) return shortsMatch[1];
66
+
67
+ const watchMatch = url.match(/[?&]v=([^&]+)/);
68
+ if (watchMatch) return watchMatch[1];
69
+
70
+ const embedMatch = url.match(/youtube\.com\/embed\/([^?&]+)/);
71
+ if (embedMatch) return embedMatch[1];
72
+
73
+ return null;
74
+ }
75
+
76
+ interface YouTubeParams {
77
+ autoplay: boolean;
78
+ mute: boolean;
79
+ controls: boolean;
80
+ showCaptions: boolean;
81
+ rel: boolean;
82
+ fullscreen: boolean;
83
+ }
84
+
85
+ function getYouTubeEmbedUrl(url: string, params: YouTubeParams): string {
86
+ const videoId = extractVideoId(url);
87
+ if (!videoId) return url;
88
+
89
+ const searchParams = new URLSearchParams();
90
+
91
+ if (params.autoplay) searchParams.set("autoplay", "1");
92
+ if (params.mute) searchParams.set("mute", "1");
93
+ if (!params.controls) searchParams.set("controls", "0");
94
+ if (params.showCaptions) searchParams.set("cc_load_policy", "1");
95
+ if (!params.rel) searchParams.set("rel", "0");
96
+ if (!params.fullscreen) searchParams.set("fs", "0");
97
+ searchParams.set("disablekb", "1");
98
+
99
+ const query = searchParams.toString();
100
+ return `https://www.youtube.com/embed/${videoId}${query ? `?${query}` : ""}`;
101
+ }
102
+
103
+ function YouTubeVideoComponent() {
104
+ const fullWidth = youtubeVideo.useSetting("fullWidth");
105
+ const theme = youtubeVideo.useSetting("theme");
106
+ const autoplay = youtubeVideo.useSetting("autoplay");
107
+ const mute = youtubeVideo.useSetting("mute");
108
+ const controls = youtubeVideo.useSetting("controls");
109
+ const showCaptions = youtubeVideo.useSetting("showCaptions");
110
+ const rel = youtubeVideo.useSetting("rel");
111
+ const fullscreen = youtubeVideo.useSetting("fullscreen");
112
+
113
+ const params: YouTubeParams = {
114
+ autoplay,
115
+ mute,
116
+ controls,
117
+ showCaptions,
118
+ rel,
119
+ fullscreen,
120
+ };
121
+
122
+ return (
123
+ <section className={cn(theme === "dark" ? "dark" : "light")}>
124
+ <div className={cn("bg-background", !fullWidth && "py-12")}>
125
+ <div className={cn(!fullWidth && "container mx-auto px-4")}>
126
+ <youtubeVideo.Embed name="url">
127
+ {(_props, { url }) => (
128
+ <div
129
+ className={cn(
130
+ "relative w-full",
131
+ !fullWidth && "overflow-hidden rounded-lg shadow-lg",
132
+ )}
133
+ style={{ paddingBottom: "56.25%" }}
134
+ >
135
+ <iframe
136
+ src={getYouTubeEmbedUrl(url, params)}
137
+ title="YouTube video"
138
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
139
+ allowFullScreen={fullscreen}
140
+ style={{
141
+ position: "absolute",
142
+ top: 0,
143
+ left: 0,
144
+ width: "100%",
145
+ height: "100%",
146
+ border: 0,
147
+ }}
148
+ />
149
+ </div>
150
+ )}
151
+ </youtubeVideo.Embed>
152
+ </div>
153
+ </div>
154
+ </section>
155
+ );
156
+ }
157
+
158
+ export { youtubeVideo as block };
@@ -1,5 +1,6 @@
1
1
  import { createLayout } from "camox/createLayout";
2
2
 
3
+ import { block as faqBlock } from "../blocks/faq";
3
4
  import { block as footerBlock } from "../blocks/footer";
4
5
  import { block as heroBlock } from "../blocks/hero";
5
6
  import { block as navbarBlock } from "../blocks/navbar";
@@ -12,7 +13,7 @@ const defaultLayout = createLayout({
12
13
  blocks: {
13
14
  before: [navbarBlock],
14
15
  after: [footerBlock],
15
- initial: [heroBlock, statisticsBlock],
16
+ initial: [heroBlock, statisticsBlock, faqBlock],
16
17
  },
17
18
  component: DefaultLayout,
18
19
  buildMetaTitle: ({ pageMetaTitle, projectName }) => `${pageMetaTitle} | ${projectName}`,
@@ -1,7 +1,6 @@
1
- import type { ClassValue } from "clsx";
2
- import { clsx } from "clsx";
1
+ import { clsx, type ClassValue } from "clsx";
3
2
  import { twMerge } from "tailwind-merge";
4
3
 
5
- export function cn(...inputs: Array<ClassValue>) {
4
+ export function cn(...inputs: ClassValue[]) {
6
5
  return twMerge(clsx(inputs));
7
6
  }
@@ -1,6 +1,8 @@
1
1
  @import "tailwindcss";
2
2
  @import "tw-animate-css";
3
3
  @import "shadcn/tailwind.css";
4
+ @import "@fontsource-variable/inter";
5
+ @import "@fontsource-variable/noto-serif";
4
6
 
5
7
  @custom-variant dark (&:is(.dark *));
6
8
 
@@ -15,73 +17,73 @@ body {
15
17
 
16
18
  :root {
17
19
  --background: oklch(1 0 0);
18
- --foreground: oklch(0.13 0.028 261.692);
20
+ --foreground: oklch(0.141 0.005 285.823);
19
21
  --card: oklch(1 0 0);
20
- --card-foreground: oklch(0.13 0.028 261.692);
22
+ --card-foreground: oklch(0.141 0.005 285.823);
21
23
  --popover: oklch(1 0 0);
22
- --popover-foreground: oklch(0.13 0.028 261.692);
23
- --primary: oklch(0.21 0.034 264.665);
24
- --primary-foreground: oklch(0.985 0.002 247.839);
25
- --secondary: oklch(0.967 0.003 264.542);
26
- --secondary-foreground: oklch(0.21 0.034 264.665);
27
- --muted: oklch(0.967 0.003 264.542);
28
- --muted-foreground: oklch(0.551 0.027 264.364);
29
- --accent: oklch(0.967 0.003 264.542);
30
- --accent-foreground: oklch(0.21 0.034 264.665);
24
+ --popover-foreground: oklch(0.141 0.005 285.823);
25
+ --primary: oklch(0.62 0.19 260);
26
+ --primary-foreground: oklch(0.984 0.019 200.873);
27
+ --secondary: oklch(0.967 0.001 286.375);
28
+ --secondary-foreground: oklch(0.21 0.006 285.885);
29
+ --muted: oklch(0.967 0.001 286.375);
30
+ --muted-foreground: oklch(0.552 0.016 285.938);
31
+ --accent: oklch(0.967 0.001 286.375);
32
+ --accent-foreground: oklch(0.21 0.006 285.885);
31
33
  --destructive: oklch(0.577 0.245 27.325);
32
34
  --destructive-foreground: oklch(0.577 0.245 27.325);
33
- --border: oklch(0.928 0.006 264.531);
34
- --input: oklch(0.928 0.006 264.531);
35
- --ring: oklch(0.707 0.022 261.325);
36
- --chart-1: oklch(0.646 0.222 41.116);
37
- --chart-2: oklch(0.6 0.118 184.704);
38
- --chart-3: oklch(0.398 0.07 227.392);
39
- --chart-4: oklch(0.828 0.189 84.429);
40
- --chart-5: oklch(0.769 0.188 70.08);
41
- --radius: 0.4rem;
42
- --sidebar: oklch(0.985 0.002 247.839);
43
- --sidebar-foreground: oklch(0.13 0.028 261.692);
44
- --sidebar-primary: oklch(0.21 0.034 264.665);
45
- --sidebar-primary-foreground: oklch(0.985 0.002 247.839);
46
- --sidebar-accent: oklch(0.967 0.003 264.542);
47
- --sidebar-accent-foreground: oklch(0.21 0.034 264.665);
48
- --sidebar-border: oklch(0.928 0.006 264.531);
49
- --sidebar-ring: oklch(0.707 0.022 261.325);
35
+ --border: oklch(0.92 0.004 286.32);
36
+ --input: oklch(0.92 0.004 286.32);
37
+ --ring: oklch(0.705 0.015 286.067);
38
+ --chart-1: oklch(0.871 0.006 286.286);
39
+ --chart-2: oklch(0.552 0.016 285.938);
40
+ --chart-3: oklch(0.442 0.017 285.786);
41
+ --chart-4: oklch(0.37 0.013 285.805);
42
+ --chart-5: oklch(0.274 0.006 286.033);
43
+ --radius: 0.625rem;
44
+ --sidebar: oklch(0.985 0 0);
45
+ --sidebar-foreground: oklch(0.141 0.005 285.823);
46
+ --sidebar-primary: oklch(0.609 0.126 221.723);
47
+ --sidebar-primary-foreground: oklch(0.984 0.019 200.873);
48
+ --sidebar-accent: oklch(0.967 0.001 286.375);
49
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
50
+ --sidebar-border: oklch(0.92 0.004 286.32);
51
+ --sidebar-ring: oklch(0.705 0.015 286.067);
50
52
  }
51
53
 
52
54
  .dark {
53
- --background: oklch(0.13 0.028 261.692);
54
- --foreground: oklch(0.985 0.002 247.839);
55
- --card: oklch(0.21 0.034 264.665);
56
- --card-foreground: oklch(0.985 0.002 247.839);
57
- --popover: oklch(0.21 0.034 264.665);
58
- --popover-foreground: oklch(0.985 0.002 247.839);
59
- --primary: oklch(0.928 0.006 264.531);
60
- --primary-foreground: oklch(0.21 0.034 264.665);
61
- --secondary: oklch(0.278 0.033 256.848);
62
- --secondary-foreground: oklch(0.985 0.002 247.839);
63
- --muted: oklch(0.278 0.033 256.848);
64
- --muted-foreground: oklch(0.707 0.022 261.325);
65
- --accent: oklch(0.278 0.033 256.848);
66
- --accent-foreground: oklch(0.985 0.002 247.839);
55
+ --background: oklch(0.141 0.005 285.823);
56
+ --foreground: oklch(0.985 0 0);
57
+ --card: oklch(0.21 0.006 285.885);
58
+ --card-foreground: oklch(0.985 0 0);
59
+ --popover: oklch(0.21 0.006 285.885);
60
+ --popover-foreground: oklch(0.985 0 0);
61
+ --primary: oklch(0.62 0.19 260);
62
+ --primary-foreground: oklch(0.984 0.019 200.873);
63
+ --secondary: oklch(0.274 0.006 286.033);
64
+ --secondary-foreground: oklch(0.985 0 0);
65
+ --muted: oklch(0.274 0.006 286.033);
66
+ --muted-foreground: oklch(0.705 0.015 286.067);
67
+ --accent: oklch(0.274 0.006 286.033);
68
+ --accent-foreground: oklch(0.985 0 0);
67
69
  --destructive: oklch(0.704 0.191 22.216);
68
70
  --destructive-foreground: oklch(0.637 0.237 25.331);
69
71
  --border: oklch(1 0 0 / 10%);
70
72
  --input: oklch(1 0 0 / 15%);
71
- --ring: oklch(0.551 0.027 264.364);
72
- --chart-1: oklch(0.488 0.243 264.376);
73
- --chart-2: oklch(0.696 0.17 162.48);
74
- --chart-3: oklch(0.769 0.188 70.08);
75
- --chart-4: oklch(0.627 0.265 303.9);
76
- --chart-5: oklch(0.645 0.246 16.439);
77
- --sidebar: oklch(0.21 0.034 264.665);
78
- --sidebar-foreground: oklch(0.985 0.002 247.839);
79
- --sidebar-primary: oklch(0.488 0.243 264.376);
80
- --sidebar-primary-foreground: oklch(0.985 0.002 247.839);
81
- --sidebar-accent: oklch(0.278 0.033 256.848);
82
- --sidebar-accent-foreground: oklch(0.985 0.002 247.839);
73
+ --ring: oklch(0.552 0.016 285.938);
74
+ --chart-1: oklch(0.871 0.006 286.286);
75
+ --chart-2: oklch(0.552 0.016 285.938);
76
+ --chart-3: oklch(0.442 0.017 285.786);
77
+ --chart-4: oklch(0.37 0.013 285.805);
78
+ --chart-5: oklch(0.274 0.006 286.033);
79
+ --sidebar: oklch(0.21 0.006 285.885);
80
+ --sidebar-foreground: oklch(0.985 0 0);
81
+ --sidebar-primary: oklch(0.715 0.143 215.221);
82
+ --sidebar-primary-foreground: oklch(0.302 0.056 229.695);
83
+ --sidebar-accent: oklch(0.274 0.006 286.033);
84
+ --sidebar-accent-foreground: oklch(0.985 0 0);
83
85
  --sidebar-border: oklch(1 0 0 / 10%);
84
- --sidebar-ring: oklch(0.551 0.027 264.364);
86
+ --sidebar-ring: oklch(0.552 0.016 285.938);
85
87
  }
86
88
 
87
89
  @theme inline {
@@ -121,6 +123,11 @@ body {
121
123
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
122
124
  --color-sidebar-border: var(--sidebar-border);
123
125
  --color-sidebar-ring: var(--sidebar-ring);
126
+ --font-sans: "Inter Variable", sans-serif;
127
+ --font-heading: "Inter Variable", sans-serif;
128
+ --radius-2xl: calc(var(--radius) * 1.8);
129
+ --radius-3xl: calc(var(--radius) * 2.2);
130
+ --radius-4xl: calc(var(--radius) * 2.6);
124
131
  }
125
132
 
126
133
  @layer base {
@@ -133,4 +140,13 @@ body {
133
140
  a:focus-visible {
134
141
  @apply border-ring ring-ring/50 rounded-md ring-3 outline-none;
135
142
  }
143
+ html {
144
+ @apply font-sans;
145
+ }
146
+ }
147
+
148
+ @utility container {
149
+ margin-inline: auto;
150
+ padding-inline: 1rem;
151
+ max-width: 80rem;
136
152
  }