feat: add Fira Code Variable font and enhance snippet editor with Shiki highlighter

This commit is contained in:
ngc2207 2024-11-23 00:58:07 +08:00
parent 8d90b08925
commit 83b8380f04
3 changed files with 59 additions and 18 deletions

View File

@ -9,6 +9,7 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@fontsource-variable/fira-code": "^5.1.0",
"@monaco-editor/react": "^4.6.0", "@monaco-editor/react": "^4.6.0",
"@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.1", "@radix-ui/react-collapsible": "^1.1.1",
@ -23,6 +24,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"devicons-react": "^1.3.0", "devicons-react": "^1.3.0",
"lucide-react": "^0.460.0", "lucide-react": "^0.460.0",
"monaco-editor-core": "^0.52.0",
"next": "15.0.3", "next": "15.0.3",
"next-themes": "^0.4.3", "next-themes": "^0.4.3",
"prisma": "^5.22.0", "prisma": "^5.22.0",

View File

@ -1,38 +1,77 @@
"use client"; "use client";
import "@fontsource-variable/fira-code";
import { Snippet } from "@prisma/client"; import { Snippet } from "@prisma/client";
import { Editor } from "@monaco-editor/react"; import { createHighlighter } from "shiki";
import { useEffect, useRef } from "react";
import * as monaco from "monaco-editor-core";
import { shikiToMonaco } from "@shikijs/monaco";
interface SnippetShowFormProps { interface SnippetShowFormProps {
snippet: Snippet; snippet: Snippet;
} }
export function SnippetShowForm({ snippet }: SnippetShowFormProps) { export function SnippetShowForm({ snippet }: SnippetShowFormProps) {
return ( const editorContainerRef = useRef<HTMLDivElement>(null);
<div className="flex-grow"> const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
<Editor
height="100vh" useEffect(() => {
theme="vs-light" async function initializeEditor() {
language={snippet.language} const highlighter = await createHighlighter({
defaultValue={snippet.code} themes: ["one-dark-pro"],
options={{ langs: [snippet.language],
});
monaco.languages.register({ id: snippet.language });
shikiToMonaco(highlighter, monaco);
const editorContainer = editorContainerRef.current;
if (!editorContainer) {
throw new Error("Editor container not found");
}
if (!editorRef.current) {
editorRef.current = monaco.editor.create(editorContainer, {
value: snippet.code,
language: snippet.language,
theme: "vitesse-light",
readOnly: true, readOnly: true,
minimap: { enabled: false }, minimap: { enabled: false },
scrollbar: { scrollbar: {
vertical: "hidden", vertical: "auto",
horizontal: "hidden", horizontal: "auto",
verticalScrollbarSize: 0, // verticalScrollbarSize: 0,
horizontalScrollbarSize: 0, // horizontalScrollbarSize: 0,
}, },
scrollBeyondLastLine: false, // scrollBeyondLastLine: false,
guides: { guides: {
bracketPairs: true, bracketPairs: true,
indentation: true, indentation: true,
}, },
showFoldingControls: "always", showFoldingControls: "always",
fontSize: 14, fontSize: 14,
}} fontFamily: "Fira Code Variable, monospace",
/> fontLigatures: true,
</div> automaticLayout: true,
});
}
}
initializeEditor();
return () => {
if (editorRef.current) {
editorRef.current.dispose();
editorRef.current = null;
}
};
}, [snippet]);
return (
<div
ref={editorContainerRef}
style={{ height: "100vh" }}
></div>
); );
} }

View File

@ -27,7 +27,7 @@ export default async function SnippetsPage() {
</div> </div>
</div> </div>
<Separator className="my-4" /> <Separator className="my-4" />
<div className="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"> <div className="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-4">
{renderedSnippets} {renderedSnippets}
</div> </div>
</div> </div>