-
Notifications
You must be signed in to change notification settings - Fork 0
SSG(Server Side Generation) 설정 #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ lerna-debug.log* | |
| node_modules | ||
| dist | ||
| dist-ssr | ||
| .react-router | ||
| *.local | ||
|
|
||
| # Editor directories and files | ||
|
|
||
Large diffs are not rendered by default.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,33 +7,37 @@ | |
| "license": "MIT", | ||
| "homepage": "https://www.daleui.com", | ||
| "scripts": { | ||
| "dev": "vite", | ||
| "build": "tsc -b && vite build", | ||
| "dev": "react-router dev", | ||
| "build": "tsc -b && react-router build", | ||
| "format": "prettier --check .", | ||
| "lint": "eslint .", | ||
| "test": "vitest", | ||
| "coverage": "vitest run --coverage", | ||
| "preview": "vite preview", | ||
| "deploy": "bun run build && wrangler deploy", | ||
| "prepare": "panda codegen" | ||
| "prepare": "panda codegen && react-router typegen" | ||
| }, | ||
| "dependencies": { | ||
| "@fontsource-variable/jetbrains-mono": "^5.2.8", | ||
| "@mdx-js/react": "^3.1.1", | ||
| "@react-router/node": "^7.15.1", | ||
| "browserslist": "^4.28.2", | ||
| "daleui": "^1.0.0", | ||
| "isbot": "^5", | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| "mermaid": "^11.15.0", | ||
| "pretendard": "^1.3.9", | ||
| "react": "^19.2.6", | ||
| "react-dom": "^19.2.6", | ||
| "react-router": "^7.15.1", | ||
| "zod": "^4.4.3" | ||
| }, | ||
| "devDependencies": { | ||
| "@cloudflare/vite-plugin": "^1.36.4", | ||
| "@cloudflare/vite-plugin": "^1.37.1", | ||
| "@codecov/vite-plugin": "^1.9.1", | ||
| "@eslint/js": "^10.0.1", | ||
| "@pandacss/dev": "^1.11.1", | ||
| "@mdx-js/rollup": "^3.1.1", | ||
| "@pandacss/dev": "^1.11.1", | ||
| "@react-router/dev": "^7.15.1", | ||
| "@testing-library/jest-dom": "^6.9.1", | ||
| "@testing-library/react": "^16.3.2", | ||
| "@testing-library/user-event": "^14.6.1", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { readdirSync } from "node:fs"; | ||
| import { join } from "node:path"; | ||
| import type { Config } from "@react-router/dev/config"; | ||
|
|
||
| const blogDir = join(import.meta.dirname, "src/content/blog"); | ||
| const blogSlugs = readdirSync(blogDir) | ||
| .filter((name) => name.endsWith(".mdx")) | ||
| .map((name) => name.replace(/\.mdx$/, "")); | ||
|
|
||
| export default { | ||
| appDirectory: "src", | ||
| buildDirectory: "dist", | ||
| ssr: false, | ||
| async prerender({ getStaticPaths }) { | ||
| return [...getStaticPaths(), ...blogSlugs.map((slug) => `/blog/${slug}`)]; | ||
| }, | ||
| } satisfies Config; |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import { useCallback, useSyncExternalStore } from "react"; | ||
|
|
||
| export type Theme = "light" | "dark"; | ||
|
|
||
| const STORAGE_KEY = "theme"; | ||
| const DARK_CLASS = "dark"; | ||
|
|
||
| function getResolvedTheme(): Theme { | ||
| if (typeof document === "undefined") return "light"; | ||
| return document.documentElement.classList.contains(DARK_CLASS) | ||
| ? "dark" | ||
| : "light"; | ||
| } | ||
|
|
||
| function getServerTheme(): Theme { | ||
| return "light"; | ||
| } | ||
|
|
||
| function applyTheme(theme: Theme) { | ||
| document.documentElement.classList.toggle(DARK_CLASS, theme === "dark"); | ||
| } | ||
|
|
||
| function subscribe(notify: () => void): () => void { | ||
| const root = document.documentElement; | ||
| const classObserver = new MutationObserver(notify); | ||
| classObserver.observe(root, { attributes: true, attributeFilter: ["class"] }); | ||
|
|
||
| const onStorage = (event: StorageEvent) => { | ||
| if (event.key !== STORAGE_KEY) return; | ||
| if (event.newValue === "dark" || event.newValue === "light") { | ||
| applyTheme(event.newValue); | ||
| } | ||
| }; | ||
| window.addEventListener("storage", onStorage); | ||
|
|
||
| return () => { | ||
| classObserver.disconnect(); | ||
| window.removeEventListener("storage", onStorage); | ||
| }; | ||
| } | ||
|
|
||
| export function useTheme() { | ||
| const theme = useSyncExternalStore( | ||
| subscribe, | ||
| getResolvedTheme, | ||
| getServerTheme, | ||
| ); | ||
|
|
||
| const toggleTheme = useCallback(() => { | ||
| const current = getResolvedTheme(); | ||
| const next = current === "dark" ? "light" : "dark"; | ||
| localStorage.setItem(STORAGE_KEY, next); | ||
| applyTheme(next); | ||
| }, []); | ||
|
|
||
| return { | ||
| isDark: theme === "dark", | ||
| toggleTheme, | ||
| }; | ||
| } |
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router"; | ||
| import "daleui/styles.css"; | ||
| import "./index.css"; | ||
| import { Navigation } from "./layouts/Navigation"; | ||
| import { Footer } from "./layouts/Footer"; | ||
|
|
||
| export function Layout({ children }: { children: React.ReactNode }) { | ||
| return ( | ||
| <html lang="ko"> | ||
| <head> | ||
| <meta charSet="UTF-8" /> | ||
| <link rel="icon" type="image/svg+xml" href="/logo.svg" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| {/* FOUC를 방지 */} | ||
| <script> | ||
| {` | ||
| (function () { | ||
| try { | ||
| var stored = localStorage.getItem('theme'); | ||
| var prefersDark = !stored && window.matchMedia('(prefers-color-scheme: dark)').matches; | ||
| if (stored === 'dark' || prefersDark) { | ||
| document.documentElement.classList.add('dark'); | ||
| } | ||
| } catch (e) {} | ||
| })(); | ||
| `} | ||
| </script> | ||
| <Meta /> | ||
| <Links /> | ||
| </head> | ||
| <body> | ||
| <Navigation /> | ||
| {children} | ||
| <Footer /> | ||
| <ScrollRestoration /> | ||
| <Scripts /> | ||
| </body> | ||
| </html> | ||
| ); | ||
| } | ||
|
|
||
| export default function App() { | ||
| return <Outlet />; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import { type RouteConfig, index, route } from "@react-router/dev/routes"; | ||
|
|
||
| export default [ | ||
| index("routes/home.tsx"), | ||
| route("blog/:slug", "routes/blog.$slug.tsx"), | ||
| ] satisfies RouteConfig; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,20 @@ | ||
| import { Box, Flex, Heading, Text, VStack } from "daleui"; | ||
| import { useEffect, useRef } from "react"; | ||
| import { css } from "../../styled-system/css"; | ||
| import type { BlogFrontmatter } from "../content/blog/schema"; | ||
| import type { MdxDoc } from "../mdx/types"; | ||
| import { findBlog } from "../content/blog/loader"; | ||
|
|
||
| type BlogPageProps = { | ||
| post: MdxDoc<BlogFrontmatter>; | ||
| }; | ||
| // eslint-disable-next-line react-refresh/only-export-components | ||
| export function meta({ params }: { params: { slug: string } }) { | ||
| const post = findBlog(params.slug); | ||
| return [{ title: post ? `${post.frontmatter.title} | Dale UI` : "Dale UI" }]; | ||
| } | ||
|
|
||
| export default function BlogSlug({ params }: { params: { slug: string } }) { | ||
| const post = findBlog(params.slug); | ||
| if (!post) { | ||
| throw new Response("Not Found", { status: 404 }); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분이 이해가 잘 안되는데 자세히 설명가능할까요? |
||
|
|
||
| export function BlogPage({ post }: BlogPageProps) { | ||
| const { default: Component, frontmatter } = post; | ||
| const articleRef = useRef<HTMLElement>(null); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
의견 감사합니다. typegen은 prepare로 분리하였습니다.