diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d3145e6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +Dockerfile +.dockerignore +node_modules +README.md +.next +.git \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3c18059 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "tabWidth": 2, + "printWidth": 120, + "arrowParens": "always", + "singleQuote": false, + "trailingComma": "all", + "useTabs": false, + "semi": true, + "bracketSpacing": true +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..41cfb0a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +FROM oven/bun:1-alpine AS base + +FROM base AS deps + +RUN apk update && apk upgrade && apk add --no-cache libc6-compat +WORKDIR /app + +COPY package.json bun.lockb ./ +RUN \ + if [ -f bun.lockb ]; then bun i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN \ + if [ -f bun.lockb ]; then bun run build; \ + else echo "Lockfile not found." && exit 1; \ + fi + +FROM base AS runner +WORKDIR /app + +RUN apk update && apk upgrade && apk add --no-cache dumb-init + +ENV NODE_ENV=production + +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 + +ENV HOSTNAME="0.0.0.0" +CMD ["dumb-init", "bun", "run", "server.js"] \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index e9ffa30..fe2648e 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,10 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: "standalone", + experimental: { + optimizePackageImports: ["@chakra-ui/react"], + }, }; export default nextConfig; diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx index 9d03ad4..eea974c 100644 --- a/src/app/blog/[slug]/page.tsx +++ b/src/app/blog/[slug]/page.tsx @@ -1,5 +1,5 @@ -export default async function Post({ params }: { params: { slug: string } }) { - const { slug } = params; +export default async function Post({ params }: { params: Promise<{ slug: string }> }) { + const { slug } = await params; return (

Post: {slug}

diff --git a/src/app/globals.css b/src/app/globals.css index 6b717ad..b5c61c9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,21 +1,3 @@ @tailwind base; @tailwind components; @tailwind utilities; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87e..8163b1e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,3 +1,4 @@ +import { Provider } from "@/components/ui/provider"; import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; @@ -23,11 +24,9 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - - {children} + + + {children} ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 3eee014..c75150c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,101 +1,11 @@ -import Image from "next/image"; +import { Button } from "@/components/ui/button"; +import { VStack } from "@chakra-ui/react"; export default function Home() { return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.tsx - - . -
  2. -
  3. Save and see your changes instantly.
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
-
- -
+ + + + ); } diff --git a/src/components/ui/color-mode.tsx b/src/components/ui/color-mode.tsx index a87f63b..8490e12 100644 --- a/src/components/ui/color-mode.tsx +++ b/src/components/ui/color-mode.tsx @@ -1,57 +1,57 @@ -"use client" +"use client"; -import type { IconButtonProps } from "@chakra-ui/react" -import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react" -import { ThemeProvider, useTheme } from "next-themes" -import type { ThemeProviderProps } from "next-themes" -import * as React from "react" -import { LuMoon, LuSun } from "react-icons/lu" +import type { IconButtonProps } from "@chakra-ui/react"; +import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react"; +import type { ThemeProviderProps } from "next-themes"; +import { ThemeProvider, useTheme } from "next-themes"; +import * as React from "react"; +import { LuMoon, LuSun } from "react-icons/lu"; +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface ColorModeProviderProps extends ThemeProviderProps {} export function ColorModeProvider(props: ColorModeProviderProps) { - return ( - - ) + return ; } -export type ColorMode = "light" | "dark" +export type ColorMode = "light" | "dark"; export interface UseColorModeReturn { - colorMode: ColorMode - setColorMode: (colorMode: ColorMode) => void - toggleColorMode: () => void + colorMode: ColorMode; + setColorMode: (colorMode: ColorMode) => void; + toggleColorMode: () => void; } export function useColorMode(): UseColorModeReturn { - const { resolvedTheme, setTheme } = useTheme() + const { resolvedTheme, setTheme } = useTheme(); const toggleColorMode = () => { - setTheme(resolvedTheme === "light" ? "dark" : "light") - } + setTheme(resolvedTheme === "light" ? "dark" : "light"); + }; return { colorMode: resolvedTheme as ColorMode, setColorMode: setTheme, toggleColorMode, - } + }; } export function useColorModeValue(light: T, dark: T) { - const { colorMode } = useColorMode() - return colorMode === "dark" ? dark : light + const { colorMode } = useColorMode(); + return colorMode === "dark" ? dark : light; } export function ColorModeIcon() { - const { colorMode } = useColorMode() - return colorMode === "dark" ? : + const { colorMode } = useColorMode(); + return colorMode === "dark" ? : ; } +// eslint-disable-next-line @typescript-eslint/no-empty-object-type interface ColorModeButtonProps extends Omit {} -export const ColorModeButton = React.forwardRef< - HTMLButtonElement, - ColorModeButtonProps ->(function ColorModeButton(props, ref) { - const { toggleColorMode } = useColorMode() +export const ColorModeButton = React.forwardRef(function ColorModeButton( + props, + ref, +) { + const { toggleColorMode } = useColorMode(); return ( }> - ) -}) + ); +});