diff --git a/.gitignore b/.gitignore index 545302f..e689fe2 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ next-env.d.ts .next-types src/lib/gql .fonts +.theme diff --git a/package.json b/package.json index 05df540..c27f4ed 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,13 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "pnpm download-fonts && pnpm codegen && next build", + "build": "pnpm download-fonts && pnpm download-theme && pnpm codegen && next build", "codegen": "graphql-codegen --config codegen.ts", "db:push": "drizzle-kit push:pg", "deploy-worker": "wrangler deploy misc/multi-tenancy-worker.ts --name multi-tenant-on-website --compatibility-date 2023-12-05", "dev": "pnpm download-fonts && concurrently \"pnpm codegen --watch\" \"next dev\"", "download-fonts": "./scripts/download-fonts.sh", + "download-theme": "./scripts/download-theme.sh", "format": "prettier --write .", "lint": "next lint", "start": "next start" diff --git a/scripts/download-theme.sh b/scripts/download-theme.sh new file mode 100755 index 0000000..59560aa --- /dev/null +++ b/scripts/download-theme.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +mkdir -p ./.theme +cd ./.theme + +echo -n "Downloading theme file..." +curl -L "https://l.joulev.dev/theme" -o "theme.json" -s +echo " done" +cd .. diff --git a/src/app/(public)/apps/snippets/create-snippet-action.ts b/src/app/(public)/apps/snippets/create-snippet-action.ts index 54a3f53..f90598b 100644 --- a/src/app/(public)/apps/snippets/create-snippet-action.ts +++ b/src/app/(public)/apps/snippets/create-snippet-action.ts @@ -6,7 +6,7 @@ import { redirect } from "next/navigation"; import { getHighlighter, toShikiTheme } from "shikiji"; import * as v from "valibot"; -import { env } from "~/env.mjs"; +import themeJson from "~/../.theme/theme.json"; import { db } from "~/lib/db"; import { codeSnippets } from "~/lib/db/schema"; @@ -21,8 +21,7 @@ function processCode(code: string) { } async function highlightCode(code: string, language: string) { - const themeJson: unknown = await fetch(env.EDITOR_THEME_URL).then(r => r.json()); - const theme = toShikiTheme(themeJson as Parameters[0]); + const theme = toShikiTheme(themeJson as unknown as Parameters[0]); const highlighter = await getHighlighter({ themes: [theme], langs: [language] }); return highlighter.codeToHtml(code, { theme: theme.name, lang: language }); } diff --git a/src/app/(public)/apps/snippets/editor.tsx b/src/app/(public)/apps/snippets/editor.tsx index cc905bb..6733a78 100644 --- a/src/app/(public)/apps/snippets/editor.tsx +++ b/src/app/(public)/apps/snippets/editor.tsx @@ -43,7 +43,6 @@ export function Editor() { res.json()); - return Response.json(json); -} diff --git a/src/components/shiki-editor.tsx b/src/components/shiki-editor.tsx index f14d94d..2544751 100644 --- a/src/components/shiki-editor.tsx +++ b/src/components/shiki-editor.tsx @@ -1,12 +1,10 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { type Highlighter, type ThemeRegistration, getHighlighter, toShikiTheme } from "shikiji"; +import themeJson from "~/../.theme/theme.json"; + interface ShikiEditorProps { name: string; - /** - * URL to the theme JSON - */ - theme: string; language: string; tabSize?: number; value: string; @@ -20,25 +18,13 @@ interface Shiki { const preloadedLanguages = ["tsx", "css", "html", "json"]; -async function getShikiTheme(theme: string) { - const themeJson: unknown = await fetch(theme).then(r => r.json()); - return toShikiTheme(themeJson as Parameters[0]); -} - async function delay(ms: number): Promise { return new Promise(resolve => { setTimeout(resolve, ms); }); } -export function ShikiEditor({ - name, - theme, - language, - tabSize = 2, - value, - onChange, -}: ShikiEditorProps) { +export function ShikiEditor({ name, language, tabSize = 2, value, onChange }: ShikiEditorProps) { const [shiki, setShiki] = useState(null); const [loadedLanguages, setLoadedLanguages] = useState(preloadedLanguages); const [displayedLanguage, setDisplayedLanguage] = useState(language); @@ -87,14 +73,16 @@ export function ShikiEditor({ // Load Shiki useEffect(() => { (async () => { - const resolvedTheme = await getShikiTheme(theme); + const resolvedTheme = toShikiTheme( + themeJson as unknown as Parameters[0], + ); const highlighter = await getHighlighter({ themes: [resolvedTheme], langs: preloadedLanguages, }); setShiki({ highlighter, theme: resolvedTheme }); })().catch(() => setShiki(new Error())); - }, [theme]); + }, []); // Load languages that are not preloaded useEffect(() => { diff --git a/src/env.mjs b/src/env.mjs index 6243311..171513e 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -11,7 +11,6 @@ export const env = createEnv({ GITHUB_TOKEN: z.string().startsWith("ghp_"), RECENT_FAVOURITE_PLAYLIST_ID: z.string().length(YOUTUBE_PLAYLIST_ID_LENGTH), DATABASE_URL: z.string().startsWith("postgres://"), - EDITOR_THEME_URL: z.string().url(), // irasuto R2_ACCOUNT_ID: z.string().min(1),