osanseviero commited on
Commit
9d1a465
1 Parent(s): a13a90f

Upload 56 files

Browse files
app/(main)/layout.tsx CHANGED
@@ -2,6 +2,7 @@ import Image from "next/image";
2
  import bgImg from "@/public/halo.png";
3
  import Footer from "@/components/Footer";
4
  import Header from "@/components/Header";
 
5
 
6
  export default function Layout({
7
  children,
@@ -9,18 +10,22 @@ export default function Layout({
9
  children: React.ReactNode;
10
  }>) {
11
  return (
12
- <body className="bg-brand antialiased">
 
13
  <div className="absolute inset-x-0 flex justify-center">
14
  <Image
15
  src={bgImg}
16
  alt=""
17
- className="w-full max-w-[1200px] mix-blend-screen"
18
  priority
19
  />
20
  </div>
21
 
22
- <div className="isolate">
23
  <div className="mx-auto flex min-h-screen max-w-7xl flex-col items-center justify-center py-2">
 
 
 
24
  <Header />
25
  {children}
26
  <Footer />
 
2
  import bgImg from "@/public/halo.png";
3
  import Footer from "@/components/Footer";
4
  import Header from "@/components/Header";
5
+ import ThemeToggle from "@/components/ThemeToggle";
6
 
7
  export default function Layout({
8
  children,
 
10
  children: React.ReactNode;
11
  }>) {
12
  return (
13
+ <body className="bg-brand dark:bg-dark antialiased dark:text-gray-100">
14
+ <div className="absolute inset-0 dark:bg-dark-radial" />
15
  <div className="absolute inset-x-0 flex justify-center">
16
  <Image
17
  src={bgImg}
18
  alt=""
19
+ className="w-full max-w-[1200px] mix-blend-screen dark:mix-blend-plus-lighter dark:opacity-10"
20
  priority
21
  />
22
  </div>
23
 
24
+ <div className="isolate relative">
25
  <div className="mx-auto flex min-h-screen max-w-7xl flex-col items-center justify-center py-2">
26
+ <div className="fixed right-4 top-4 z-50">
27
+ <ThemeToggle />
28
+ </div>
29
  <Header />
30
  {children}
31
  <Footer />
app/(main)/page.tsx CHANGED
@@ -39,7 +39,6 @@ export default function Home() {
39
  let [generatedCode, setGeneratedCode] = useState("");
40
  let [initialAppConfig, setInitialAppConfig] = useState({
41
  model: "",
42
- shadcn: true,
43
  });
44
  let [ref, scrollTo] = useScrollTo();
45
  let [messages, setMessages] = useState<{ role: string; content: string }[]>(
@@ -106,7 +105,7 @@ export default function Home() {
106
  return (
107
  <main className="mt-12 flex w-full flex-1 flex-col items-center px-4 text-center sm:mt-1">
108
  <a
109
- className="mb-4 inline-flex h-7 shrink-0 items-center gap-[9px] rounded-[50px] border-[0.5px] border-solid border-[#E6E6E6] bg-[rgba(234,238,255,0.65)] bg-gray-100 px-7 py-5 shadow-[0px_1px_1px_0px_rgba(0,0,0,0.25)]"
110
  href="https://ai.google.dev/gemini-api/docs"
111
  target="_blank"
112
  >
@@ -114,7 +113,7 @@ export default function Home() {
114
  Powered by <span className="font-medium">Gemini API</span>
115
  </span>
116
  </a>
117
- <h1 className="my-6 max-w-3xl text-4xl font-bold text-gray-800 sm:text-6xl">
118
  Turn your <span className="text-blue-600">idea</span>
119
  <br /> into an <span className="text-blue-600">app</span>
120
  </h1>
@@ -122,8 +121,8 @@ export default function Home() {
122
  <form className="w-full max-w-xl" onSubmit={createApp}>
123
  <fieldset disabled={loading} className="disabled:opacity-75">
124
  <div className="relative mt-5">
125
- <div className="absolute -inset-2 rounded-[32px] bg-gray-300/50" />
126
- <div className="relative flex rounded-3xl bg-white shadow-sm">
127
  <div className="relative flex flex-grow items-stretch focus-within:z-10">
128
  <textarea
129
  rows={3}
@@ -131,14 +130,14 @@ export default function Home() {
131
  value={prompt}
132
  onChange={(e) => setPrompt(e.target.value)}
133
  name="prompt"
134
- className="w-full resize-none rounded-l-3xl bg-transparent px-6 py-5 text-lg focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500"
135
  placeholder="Build me a calculator app..."
136
  />
137
  </div>
138
  <button
139
  type="submit"
140
  disabled={loading}
141
- className="relative -ml-px inline-flex items-center gap-x-1.5 rounded-r-3xl px-3 py-2 text-sm font-semibold text-blue-500 hover:text-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500 disabled:text-gray-900"
142
  >
143
  {status === "creating" ? (
144
  <LoadingDots color="black" style="large" />
@@ -150,30 +149,30 @@ export default function Home() {
150
  </div>
151
  <div className="mt-6 flex flex-col justify-center gap-4 sm:flex-row sm:items-center sm:gap-8">
152
  <div className="flex items-center justify-between gap-3 sm:justify-center">
153
- <p className="text-gray-500 sm:text-xs">Model:</p>
154
  <Select.Root
155
  name="model"
156
  disabled={loading}
157
  value={model}
158
  onValueChange={(value) => setModel(value)}
159
  >
160
- <Select.Trigger className="group flex w-60 max-w-xs items-center rounded-2xl border-[6px] border-gray-300 bg-white px-4 py-2 text-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500">
161
  <Select.Value />
162
  <Select.Icon className="ml-auto">
163
- <ChevronDownIcon className="size-6 text-gray-300 group-focus-visible:text-gray-500 group-enabled:group-hover:text-gray-500" />
164
  </Select.Icon>
165
  </Select.Trigger>
166
  <Select.Portal>
167
- <Select.Content className="overflow-hidden rounded-md bg-white shadow-lg">
168
  <Select.Viewport className="p-2">
169
  {models.map((model) => (
170
  <Select.Item
171
  key={model.value}
172
  value={model.value}
173
- className="flex cursor-pointer items-center rounded-md px-3 py-2 text-sm data-[highlighted]:bg-gray-100 data-[highlighted]:outline-none"
174
  >
175
  <Select.ItemText asChild>
176
- <span className="inline-flex items-center gap-2 text-gray-500">
177
  <div className="size-2 rounded-full bg-green-500" />
178
  {model.label}
179
  </span>
@@ -194,7 +193,7 @@ export default function Home() {
194
  </fieldset>
195
  </form>
196
 
197
- <hr className="border-1 mb-20 h-px bg-gray-700 dark:bg-gray-700" />
198
 
199
  {status !== "initial" && (
200
  <motion.div
@@ -226,9 +225,9 @@ export default function Home() {
226
  duration: 0.85,
227
  delay: 0.5,
228
  }}
229
- className="absolute inset-x-0 bottom-0 top-1/2 flex items-center justify-center rounded-r border border-gray-400 bg-gradient-to-br from-gray-100 to-gray-300 md:inset-y-0 md:left-1/2 md:right-0"
230
  >
231
- <p className="animate-pulse text-3xl font-bold">
232
  {status === "creating"
233
  ? "Building your app..."
234
  : "Updating your app..."}
 
39
  let [generatedCode, setGeneratedCode] = useState("");
40
  let [initialAppConfig, setInitialAppConfig] = useState({
41
  model: "",
 
42
  });
43
  let [ref, scrollTo] = useScrollTo();
44
  let [messages, setMessages] = useState<{ role: string; content: string }[]>(
 
105
  return (
106
  <main className="mt-12 flex w-full flex-1 flex-col items-center px-4 text-center sm:mt-1">
107
  <a
108
+ className="mb-4 inline-flex h-7 shrink-0 items-center gap-[9px] rounded-[50px] border-[0.5px] border-solid border-[#E6E6E6] bg-[rgba(234,238,255,0.65)] dark:bg-[rgba(30,41,59,0.5)] dark:border-gray-700 px-7 py-5 shadow-[0px_1px_1px_0px_rgba(0,0,0,0.25)]"
109
  href="https://ai.google.dev/gemini-api/docs"
110
  target="_blank"
111
  >
 
113
  Powered by <span className="font-medium">Gemini API</span>
114
  </span>
115
  </a>
116
+ <h1 className="my-6 max-w-3xl text-4xl font-bold text-gray-800 dark:text-white sm:text-6xl">
117
  Turn your <span className="text-blue-600">idea</span>
118
  <br /> into an <span className="text-blue-600">app</span>
119
  </h1>
 
121
  <form className="w-full max-w-xl" onSubmit={createApp}>
122
  <fieldset disabled={loading} className="disabled:opacity-75">
123
  <div className="relative mt-5">
124
+ <div className="absolute -inset-2 rounded-[32px] bg-gray-300/50 dark:bg-gray-800/50" />
125
+ <div className="relative flex rounded-3xl bg-white dark:bg-[#1E293B] shadow-sm">
126
  <div className="relative flex flex-grow items-stretch focus-within:z-10">
127
  <textarea
128
  rows={3}
 
130
  value={prompt}
131
  onChange={(e) => setPrompt(e.target.value)}
132
  name="prompt"
133
+ className="w-full resize-none rounded-l-3xl bg-transparent px-6 py-5 text-lg focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500 dark:text-gray-100 dark:placeholder-gray-400"
134
  placeholder="Build me a calculator app..."
135
  />
136
  </div>
137
  <button
138
  type="submit"
139
  disabled={loading}
140
+ className="relative -ml-px inline-flex items-center gap-x-1.5 rounded-r-3xl px-3 py-2 text-sm font-semibold text-blue-500 hover:text-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500 disabled:text-gray-900 dark:disabled:text-gray-400"
141
  >
142
  {status === "creating" ? (
143
  <LoadingDots color="black" style="large" />
 
149
  </div>
150
  <div className="mt-6 flex flex-col justify-center gap-4 sm:flex-row sm:items-center sm:gap-8">
151
  <div className="flex items-center justify-between gap-3 sm:justify-center">
152
+ <p className="text-gray-500 dark:text-gray-400 sm:text-xs">Model:</p>
153
  <Select.Root
154
  name="model"
155
  disabled={loading}
156
  value={model}
157
  onValueChange={(value) => setModel(value)}
158
  >
159
+ <Select.Trigger className="group flex w-60 max-w-xs items-center rounded-2xl border-[6px] border-gray-300 dark:border-gray-700 bg-white dark:bg-[#1E293B] px-4 py-2 text-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-500">
160
  <Select.Value />
161
  <Select.Icon className="ml-auto">
162
+ <ChevronDownIcon className="size-6 text-gray-300 group-focus-visible:text-gray-500 group-enabled:group-hover:text-gray-500 dark:text-gray-600 dark:group-focus-visible:text-gray-400 dark:group-enabled:group-hover:text-gray-400" />
163
  </Select.Icon>
164
  </Select.Trigger>
165
  <Select.Portal>
166
+ <Select.Content className="overflow-hidden rounded-md bg-white dark:bg-[#1E293B] shadow-lg">
167
  <Select.Viewport className="p-2">
168
  {models.map((model) => (
169
  <Select.Item
170
  key={model.value}
171
  value={model.value}
172
+ className="flex cursor-pointer items-center rounded-md px-3 py-2 text-sm data-[highlighted]:bg-gray-100 dark:data-[highlighted]:bg-gray-800 data-[highlighted]:outline-none"
173
  >
174
  <Select.ItemText asChild>
175
+ <span className="inline-flex items-center gap-2 text-gray-500 dark:text-gray-400">
176
  <div className="size-2 rounded-full bg-green-500" />
177
  {model.label}
178
  </span>
 
193
  </fieldset>
194
  </form>
195
 
196
+ <hr className="border-1 mb-20 h-px bg-gray-700 dark:bg-gray-700/30" />
197
 
198
  {status !== "initial" && (
199
  <motion.div
 
225
  duration: 0.85,
226
  delay: 0.5,
227
  }}
228
+ className="absolute inset-x-0 bottom-0 top-1/2 flex items-center justify-center rounded-r border border-gray-400 dark:border-gray-700 bg-gradient-to-br from-gray-100 to-gray-300 dark:from-[#1E293B] dark:to-gray-800 md:inset-y-0 md:left-1/2 md:right-0"
229
  >
230
+ <p className="animate-pulse text-3xl font-bold dark:text-gray-100">
231
  {status === "creating"
232
  ? "Building your app..."
233
  : "Updating your app..."}
app/api/generateCode/route.ts CHANGED
@@ -32,6 +32,8 @@ export async function POST(req: Request) {
32
  messages[0].content + systemPrompt + "\nPlease ONLY return code, NO backticks or language names. Don't start with \`\`\`typescript or \`\`\`javascript or \`\`\`tsx or \`\`\`."
33
  );
34
 
 
 
35
  const readableStream = new ReadableStream({
36
  async start(controller) {
37
  for await (const chunk of geminiStream.stream) {
@@ -64,6 +66,7 @@ function getSystemPrompt() {
64
  systemPrompt += `
65
  NO OTHER LIBRARIES (e.g. zod, hookform) ARE INSTALLED OR ABLE TO BE IMPORTED.
66
  `;
 
67
  return dedent(systemPrompt);
68
  }
69
 
 
32
  messages[0].content + systemPrompt + "\nPlease ONLY return code, NO backticks or language names. Don't start with \`\`\`typescript or \`\`\`javascript or \`\`\`tsx or \`\`\`."
33
  );
34
 
35
+ console.log(messages[0].content + systemPrompt + "\nPlease ONLY return code, NO backticks or language names. Don't start with \`\`\`typescript or \`\`\`javascript or \`\`\`tsx or \`\`\`.")
36
+
37
  const readableStream = new ReadableStream({
38
  async start(controller) {
39
  for await (const chunk of geminiStream.stream) {
 
66
  systemPrompt += `
67
  NO OTHER LIBRARIES (e.g. zod, hookform) ARE INSTALLED OR ABLE TO BE IMPORTED.
68
  `;
69
+
70
  return dedent(systemPrompt);
71
  }
72
 
app/layout.tsx CHANGED
@@ -1,5 +1,6 @@
1
  import type { Metadata } from "next";
2
  import "./globals.css";
 
3
 
4
  let title = "Gemini Coder – AI Code Generator";
5
  let description = "Generate your next app with Gemini";
@@ -38,7 +39,9 @@ export default function RootLayout({
38
  }>) {
39
  return (
40
  <html lang="en" className="h-full">
41
- {children}
 
 
42
  </html>
43
  );
44
  }
 
1
  import type { Metadata } from "next";
2
  import "./globals.css";
3
+ import { ThemeProvider } from "@/components/ThemeProvider";
4
 
5
  let title = "Gemini Coder – AI Code Generator";
6
  let description = "Generate your next app with Gemini";
 
39
  }>) {
40
  return (
41
  <html lang="en" className="h-full">
42
+ <ThemeProvider>
43
+ {children}
44
+ </ThemeProvider>
45
  </html>
46
  );
47
  }
components/DarkModeToggle.tsx ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useDarkMode } from '@/hooks/useDarkMode';
4
+
5
+ export function DarkModeToggle() {
6
+ const { isDarkMode, toggleDarkMode } = useDarkMode();
7
+
8
+ return (
9
+ <button
10
+ onClick={toggleDarkMode}
11
+ className="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
12
+ aria-label="Toggle dark mode"
13
+ >
14
+ {isDarkMode ? (
15
+ <svg
16
+ xmlns="http://www.w3.org/2000/svg"
17
+ fill="none"
18
+ viewBox="0 0 24 24"
19
+ strokeWidth={1.5}
20
+ stroke="currentColor"
21
+ className="w-5 h-5"
22
+ >
23
+ <path
24
+ strokeLinecap="round"
25
+ strokeLinejoin="round"
26
+ d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
27
+ />
28
+ </svg>
29
+ ) : (
30
+ <svg
31
+ xmlns="http://www.w3.org/2000/svg"
32
+ fill="none"
33
+ viewBox="0 0 24 24"
34
+ strokeWidth={1.5}
35
+ stroke="currentColor"
36
+ className="w-5 h-5"
37
+ >
38
+ <path
39
+ strokeLinecap="round"
40
+ strokeLinejoin="round"
41
+ d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z"
42
+ />
43
+ </svg>
44
+ )}
45
+ </button>
46
+ );
47
+ }
components/Header.tsx CHANGED
@@ -15,9 +15,9 @@ export default function Header() {
15
  <a
16
  href="https://github.com/osanseviero/geminicoder"
17
  target="_blank"
18
- className="ml-auto hidden items-center gap-3 rounded-2xl bg-white px-6 py-2 sm:flex"
19
  >
20
- <GithubIcon className="h-4 w-4" />
21
  <span>GitHub Repo</span>
22
  </a>
23
  </header>
 
15
  <a
16
  href="https://github.com/osanseviero/geminicoder"
17
  target="_blank"
18
+ className="ml-auto hidden items-center gap-3 rounded-2xl bg-white dark:bg-[#1E293B] dark:text-gray-100 px-6 py-2 sm:flex border border-gray-200 dark:border-gray-700"
19
  >
20
+ <GithubIcon className="h-4 w-4 dark:text-gray-100" />
21
  <span>GitHub Repo</span>
22
  </a>
23
  </header>
components/ThemeProvider.tsx ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ import { createContext, useContext, useEffect, useState } from "react";
4
+
5
+ type Theme = "light" | "dark";
6
+
7
+ type ThemeContextType = {
8
+ theme: Theme;
9
+ toggleTheme: () => void;
10
+ };
11
+
12
+ const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
13
+
14
+ export function ThemeProvider({ children }: { children: React.ReactNode }) {
15
+ const [theme, setTheme] = useState<Theme>("light");
16
+
17
+ useEffect(() => {
18
+ const savedTheme = localStorage.getItem("theme") as Theme;
19
+ if (savedTheme) {
20
+ setTheme(savedTheme);
21
+ document.documentElement.classList.toggle("dark", savedTheme === "dark");
22
+ } else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
23
+ setTheme("dark");
24
+ document.documentElement.classList.add("dark");
25
+ }
26
+ }, []);
27
+
28
+ const toggleTheme = () => {
29
+ const newTheme = theme === "light" ? "dark" : "light";
30
+ setTheme(newTheme);
31
+ localStorage.setItem("theme", newTheme);
32
+ document.documentElement.classList.toggle("dark", newTheme === "dark");
33
+ };
34
+
35
+ return (
36
+ <ThemeContext.Provider value={{ theme, toggleTheme }}>
37
+ {children}
38
+ </ThemeContext.Provider>
39
+ );
40
+ }
41
+
42
+ export function useTheme() {
43
+ const context = useContext(ThemeContext);
44
+ if (context === undefined) {
45
+ throw new Error("useTheme must be used within a ThemeProvider");
46
+ }
47
+ return context;
48
+ }
components/ThemeToggle.tsx ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ import { useTheme } from "./ThemeProvider";
4
+
5
+ export default function ThemeToggle() {
6
+ const { theme, toggleTheme } = useTheme();
7
+
8
+ return (
9
+ <button
10
+ onClick={toggleTheme}
11
+ className="flex h-8 w-8 items-center justify-center rounded-lg bg-gray-200 transition-colors hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600"
12
+ aria-label="Toggle dark mode"
13
+ >
14
+ {theme === "light" ? (
15
+ <svg
16
+ xmlns="http://www.w3.org/2000/svg"
17
+ fill="none"
18
+ viewBox="0 0 24 24"
19
+ strokeWidth={1.5}
20
+ stroke="currentColor"
21
+ className="h-5 w-5"
22
+ >
23
+ <path
24
+ strokeLinecap="round"
25
+ strokeLinejoin="round"
26
+ d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z"
27
+ />
28
+ </svg>
29
+ ) : (
30
+ <svg
31
+ xmlns="http://www.w3.org/2000/svg"
32
+ fill="none"
33
+ viewBox="0 0 24 24"
34
+ strokeWidth={1.5}
35
+ stroke="currentColor"
36
+ className="h-5 w-5"
37
+ >
38
+ <path
39
+ strokeLinecap="round"
40
+ strokeLinejoin="round"
41
+ d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
42
+ />
43
+ </svg>
44
+ )}
45
+ </button>
46
+ );
47
+ }
hooks/useDarkMode.tsx ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { createContext, useContext, useEffect, useState } from 'react';
4
+
5
+ type DarkModeContextType = {
6
+ isDarkMode: boolean;
7
+ toggleDarkMode: () => void;
8
+ };
9
+
10
+ const DarkModeContext = createContext<DarkModeContextType | undefined>(undefined);
11
+
12
+ export function DarkModeProvider({ children }: { children: React.ReactNode }) {
13
+ const [isDarkMode, setIsDarkMode] = useState(false);
14
+
15
+ useEffect(() => {
16
+ // Check if user has dark mode preference
17
+ const isDark = localStorage.getItem('darkMode') === 'true';
18
+ setIsDarkMode(isDark);
19
+ if (isDark) {
20
+ document.documentElement.classList.add('dark');
21
+ }
22
+ }, []);
23
+
24
+ const toggleDarkMode = () => {
25
+ setIsDarkMode((prev) => {
26
+ const newValue = !prev;
27
+ localStorage.setItem('darkMode', String(newValue));
28
+ if (newValue) {
29
+ document.documentElement.classList.add('dark');
30
+ } else {
31
+ document.documentElement.classList.remove('dark');
32
+ }
33
+ return newValue;
34
+ });
35
+ };
36
+
37
+ return (
38
+ <DarkModeContext.Provider value={{ isDarkMode, toggleDarkMode }}>
39
+ {children}
40
+ </DarkModeContext.Provider>
41
+ );
42
+ }
43
+
44
+ export function useDarkMode() {
45
+ const context = useContext(DarkModeContext);
46
+ if (context === undefined) {
47
+ throw new Error('useDarkMode must be used within a DarkModeProvider');
48
+ }
49
+ return context;
50
+ }
package.json CHANGED
@@ -3,9 +3,9 @@
3
  "version": "0.1.0",
4
  "private": true,
5
  "scripts": {
6
- "dev": "PORT=7860 next dev",
7
- "build": "next build",
8
- "start": "PORT=7860 next start",
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
 
3
  "version": "0.1.0",
4
  "private": true,
5
  "scripts": {
6
+ "dev": "next dev",
7
+ "build": "prisma generate && prisma migrate deploy && next build",
8
+ "start": "next start",
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
tailwind.config.ts CHANGED
@@ -3,6 +3,7 @@ import colors from "tailwindcss/colors";
3
  import defaultTheme from "tailwindcss/defaultTheme";
4
 
5
  const config: Config = {
 
6
  content: [
7
  "./pages/**/*.{js,ts,jsx,tsx,mdx}",
8
  "./components/**/*.{js,ts,jsx,tsx,mdx}",
@@ -14,7 +15,12 @@ const config: Config = {
14
  brand: "#E1E7EC",
15
  gray: colors.slate,
16
  },
17
-
 
 
 
 
 
18
  fontFamily: {
19
  sans: ['"Aeonik"', ...defaultTheme.fontFamily.sans],
20
  },
 
3
  import defaultTheme from "tailwindcss/defaultTheme";
4
 
5
  const config: Config = {
6
+ darkMode: "class",
7
  content: [
8
  "./pages/**/*.{js,ts,jsx,tsx,mdx}",
9
  "./components/**/*.{js,ts,jsx,tsx,mdx}",
 
15
  brand: "#E1E7EC",
16
  gray: colors.slate,
17
  },
18
+ backgroundColor: {
19
+ dark: "#0B1120",
20
+ },
21
+ backgroundImage: {
22
+ 'dark-radial': 'radial-gradient(circle at center, rgba(255,255,255,0.1) 0%, transparent 70%)',
23
+ },
24
  fontFamily: {
25
  sans: ['"Aeonik"', ...defaultTheme.fontFamily.sans],
26
  },