feat(playground): add theme selector component and enhance code editor with additional themes and languages
This commit is contained in:
parent
668145a9c7
commit
f590d77578
@ -1,52 +1,87 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useRef } from "react";
|
|
||||||
import "@fontsource-variable/fira-code";
|
import "@fontsource-variable/fira-code";
|
||||||
import { createHighlighter } from "shiki";
|
import { createHighlighter } from "shiki";
|
||||||
import type { editor } from "monaco-editor";
|
import type { editor } from "monaco-editor";
|
||||||
import { shikiToMonaco } from "@shikijs/monaco";
|
import { shikiToMonaco } from "@shikijs/monaco";
|
||||||
|
import { useEffect, useRef, useMemo } from "react";
|
||||||
import { useCodeEditorStore } from "@/store/codeEditorStore";
|
import { useCodeEditorStore } from "@/store/codeEditorStore";
|
||||||
import MonacoEditor, { type Monaco } from "@monaco-editor/react";
|
import MonacoEditor, { type Monaco } from "@monaco-editor/react";
|
||||||
|
|
||||||
|
const ADDITIONAL_THEMES = [
|
||||||
|
"andromeeda",
|
||||||
|
"aurora-x",
|
||||||
|
"ayu-dark",
|
||||||
|
"catppuccin-frappe",
|
||||||
|
"catppuccin-latte",
|
||||||
|
"catppuccin-macchiato",
|
||||||
|
"catppuccin-mocha",
|
||||||
|
"dark-plus",
|
||||||
|
"dracula",
|
||||||
|
"dracula-soft",
|
||||||
|
"one-dark-pro",
|
||||||
|
"vitesse-dark",
|
||||||
|
"vitesse-light",
|
||||||
|
];
|
||||||
|
|
||||||
|
const ADDITIONAL_LANGUAGES = ["c", "java"] as const satisfies Parameters<
|
||||||
|
typeof createHighlighter
|
||||||
|
>[0]["langs"];
|
||||||
|
|
||||||
export function CodeEditor() {
|
export function CodeEditor() {
|
||||||
const monacoRef = useRef<Monaco | null>(null);
|
const monacoRef = useRef<Monaco | null>(null);
|
||||||
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
||||||
const { lang, theme, value, isLigature } = useCodeEditorStore();
|
const { lang, theme, value, isLigature } = useCodeEditorStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (monacoRef.current && editorRef.current) {
|
||||||
|
monacoRef.current.editor.setTheme(theme);
|
||||||
|
}
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
const options = useMemo(
|
||||||
|
() => ({
|
||||||
|
minimap: { enabled: false },
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: "Fira Code Variable, monospace",
|
||||||
|
tabSize: 4,
|
||||||
|
showFoldingControls: "always" as const,
|
||||||
|
fontLigatures: isLigature,
|
||||||
|
automaticLayout: true,
|
||||||
|
guides: {
|
||||||
|
bracketPairs: true,
|
||||||
|
indentation: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[isLigature]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleEditorMount = async (
|
||||||
|
editor: editor.IStandaloneCodeEditor,
|
||||||
|
monaco: Monaco
|
||||||
|
) => {
|
||||||
|
editorRef.current = editor;
|
||||||
|
monacoRef.current = monaco;
|
||||||
|
|
||||||
|
for (const lang of ADDITIONAL_LANGUAGES) {
|
||||||
|
monacoRef.current?.languages.register({ id: lang });
|
||||||
|
}
|
||||||
|
|
||||||
|
const highlighter = await createHighlighter({
|
||||||
|
themes: ADDITIONAL_THEMES,
|
||||||
|
langs: ADDITIONAL_LANGUAGES,
|
||||||
|
});
|
||||||
|
|
||||||
|
shikiToMonaco(highlighter, monacoRef.current);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
language={lang}
|
language={lang}
|
||||||
theme="vs-dark"
|
theme={theme}
|
||||||
options={{
|
options={options}
|
||||||
minimap: { enabled: false },
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: "Fira Code Variable, monospace",
|
|
||||||
tabSize: 4,
|
|
||||||
showFoldingControls: "always",
|
|
||||||
fontLigatures: isLigature,
|
|
||||||
automaticLayout: true,
|
|
||||||
}}
|
|
||||||
value={value}
|
value={value}
|
||||||
onMount={(editor, monaco) => {
|
onMount={handleEditorMount}
|
||||||
editorRef.current = editor;
|
|
||||||
monacoRef.current = monaco;
|
|
||||||
void (async () => {
|
|
||||||
const ADDITIONAL_LANGUAGES = [
|
|
||||||
"c",
|
|
||||||
"java",
|
|
||||||
] as const satisfies Parameters<typeof createHighlighter>[0]["langs"];
|
|
||||||
|
|
||||||
for (const lang of ADDITIONAL_LANGUAGES) {
|
|
||||||
monacoRef.current?.languages.register({ id: lang });
|
|
||||||
}
|
|
||||||
|
|
||||||
const highlighter = await createHighlighter({
|
|
||||||
themes: [theme],
|
|
||||||
langs: ADDITIONAL_LANGUAGES,
|
|
||||||
});
|
|
||||||
|
|
||||||
shikiToMonaco(highlighter, monacoRef.current);
|
|
||||||
})();
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
47
src/app/playground/components/theme-selector.tsx
Normal file
47
src/app/playground/components/theme-selector.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { useCodeEditorStore } from "@/store/codeEditorStore";
|
||||||
|
|
||||||
|
const themeOptions = [
|
||||||
|
{ value: "andromeeda", label: "Andromeeda" },
|
||||||
|
{ value: "aurora-x", label: "Aurora X" },
|
||||||
|
{ value: "ayu-dark", label: "Ayu Dark" },
|
||||||
|
{ value: "catppuccin-frappe", label: "Catppuccin Frappé" },
|
||||||
|
{ value: "catppuccin-latte", label: "Catppuccin Latte" },
|
||||||
|
{ value: "catppuccin-macchiato", label: "Catppuccin Macchiato" },
|
||||||
|
{ value: "catppuccin-mocha", label: "Catppuccin Mocha" },
|
||||||
|
{ value: "dark-plus", label: "Dark Plus" },
|
||||||
|
{ value: "dracula", label: "Dracula Theme" },
|
||||||
|
{ value: "dracula-soft", label: "Dracula Theme Soft" },
|
||||||
|
{ value: "one-dark-pro", label: "One Dark Pro" },
|
||||||
|
{ value: "vitesse-dark", label: "Vitesse Dark" },
|
||||||
|
{ value: "vitesse-light", label: "Vitesse Light" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function ThemeSelector() {
|
||||||
|
const { theme, setTheme } = useCodeEditorStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Select defaultValue={theme} onValueChange={setTheme}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select theme" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{themeOptions.map((option) => (
|
||||||
|
<SelectItem key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -3,14 +3,9 @@ import {
|
|||||||
SidebarProvider,
|
SidebarProvider,
|
||||||
SidebarTrigger,
|
SidebarTrigger,
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import {
|
|
||||||
Breadcrumb,
|
|
||||||
BreadcrumbItem,
|
|
||||||
BreadcrumbList,
|
|
||||||
BreadcrumbPage,
|
|
||||||
} from "@/components/ui/breadcrumb";
|
|
||||||
import { SessionProvider } from "next-auth/react";
|
import { SessionProvider } from "next-auth/react";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import ThemeSelector from "./components/theme-selector";
|
||||||
import { ModeSwitcher } from "@/components/mode-switcher";
|
import { ModeSwitcher } from "@/components/mode-switcher";
|
||||||
import LanguageSwitcher from "@/components/language-switcher";
|
import LanguageSwitcher from "@/components/language-switcher";
|
||||||
import { PlaygroundSidebar } from "@/app/playground/components/playground-sidebar";
|
import { PlaygroundSidebar } from "@/app/playground/components/playground-sidebar";
|
||||||
@ -28,15 +23,7 @@ export default function PlaygroundLayout({
|
|||||||
<SidebarTrigger />
|
<SidebarTrigger />
|
||||||
<ModeSwitcher />
|
<ModeSwitcher />
|
||||||
<Separator orientation="vertical" className="mr-2 h-4" />
|
<Separator orientation="vertical" className="mr-2 h-4" />
|
||||||
<Breadcrumb>
|
<ThemeSelector />
|
||||||
<BreadcrumbList>
|
|
||||||
<BreadcrumbItem>
|
|
||||||
<BreadcrumbPage className="line-clamp-1">
|
|
||||||
Project Management & Task Tracking
|
|
||||||
</BreadcrumbPage>
|
|
||||||
</BreadcrumbItem>
|
|
||||||
</BreadcrumbList>
|
|
||||||
</Breadcrumb>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-auto px-3">
|
<div className="ml-auto px-3">
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
|
Loading…
Reference in New Issue
Block a user