mirror of
https://litchi.icu/ngc2207/judge.git
synced 2025-05-18 23:26:33 +00:00
feat: add theme and language selection to code editor with language server connection support
This commit is contained in:
parent
937330ac3d
commit
1aeb472495
@ -3,16 +3,33 @@ import {
|
||||
DEFAULT_EDITOR_THEME,
|
||||
DEFAULT_EDITOR_LANGUAGE,
|
||||
} from "@/config";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Palette } from "lucide-react";
|
||||
import * as monaco from "monaco-editor";
|
||||
import { highlighter } from "@/lib/shiki";
|
||||
import { Bot, CodeXml } from "lucide-react";
|
||||
import { shikiToMonaco } from "@shikijs/monaco";
|
||||
import { connectToLanguageServer } from "@/lib/lsp";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { SUPPORTED_EDITOR_THEMES } from "@/constants/themes";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
import { DiffEditor, Editor, Monaco, loader } from "@monaco-editor/react";
|
||||
import { SUPPORTED_EDITOR_LANGUAGES_CONFIG } from "@/constants/languages";
|
||||
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
|
||||
import { connectToLanguageServer, SUPPORTED_LSP_LANGUAGES } from "@/lib/lsp";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
|
||||
self.MonacoEnvironment = {
|
||||
getWorker(_, _label) {
|
||||
return new editorWorker();
|
||||
},
|
||||
};
|
||||
|
||||
loader.config({ monaco });
|
||||
|
||||
function App() {
|
||||
@ -25,9 +42,12 @@ function App() {
|
||||
if (webSocketRef.current) {
|
||||
webSocketRef.current.close();
|
||||
}
|
||||
connectToLanguageServer(language).then((webSocket) => {
|
||||
webSocketRef.current = webSocket;
|
||||
});
|
||||
|
||||
if (language in SUPPORTED_LSP_LANGUAGES) {
|
||||
connectToLanguageServer(language).then((webSocket) => {
|
||||
webSocketRef.current = webSocket;
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (webSocketRef.current) {
|
||||
@ -40,32 +60,66 @@ function App() {
|
||||
<div className="h-screen bg-[#282c34] dark overflow-hidden">
|
||||
<Tabs defaultValue="code-editor" className="h-full mt-2">
|
||||
<ScrollArea className="border-b border-[#3e4452]">
|
||||
<TabsList className="gap-1 bg-transparent px-4 mb-2">
|
||||
<TabsTrigger
|
||||
value="code-editor"
|
||||
className="rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
<CodeXml
|
||||
className="-ms-0.5 me-1.5 opacity-60"
|
||||
size={16}
|
||||
strokeWidth={2}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
代码
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="diff-editor"
|
||||
className="500 rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
<Bot
|
||||
className="-ms-0.5 me-1.5 opacity-60"
|
||||
size={16}
|
||||
strokeWidth={2}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
AI 助教
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="flex items-center justify-between">
|
||||
<TabsList className="gap-1 bg-transparent px-4 mb-2">
|
||||
<TabsTrigger
|
||||
value="code-editor"
|
||||
className="rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
<CodeXml
|
||||
className="-ms-0.5 me-1.5 opacity-60"
|
||||
size={16}
|
||||
strokeWidth={2}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
代码
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="diff-editor"
|
||||
className="500 rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
<Bot
|
||||
className="-ms-0.5 me-1.5 opacity-60"
|
||||
size={16}
|
||||
strokeWidth={2}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
AI 助教
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="flex items-center gap-x-2 pr-4 mb-2">
|
||||
<Select value={theme} onValueChange={setTheme}>
|
||||
<SelectTrigger className="relative ps-9 w-40 bg-foreground">
|
||||
<div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 group-has-[[disabled]]:opacity-50">
|
||||
<Palette size={16} strokeWidth={2} aria-hidden="true" />
|
||||
</div>
|
||||
<SelectValue placeholder="Select Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SUPPORTED_EDITOR_THEMES.map((theme) => (
|
||||
<SelectItem key={theme.id} value={theme.id}>
|
||||
<span className="truncate">{theme.label}</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={language} onValueChange={setLanguage}>
|
||||
<SelectTrigger className="[&>span]:flex [&>span]:items-center [&>span]:gap-2 [&>span_svg]:shrink-0 [&>span_svg]:text-muted-foreground/80 w-36 bg-foreground">
|
||||
<SelectValue placeholder="Select Language" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="[&_*[role=option]>span>svg]:shrink-0 [&_*[role=option]>span>svg]:text-muted-foreground/80 [&_*[role=option]>span]:end-2 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:flex [&_*[role=option]>span]:items-center [&_*[role=option]>span]:gap-2 [&_*[role=option]]:pe-8 [&_*[role=option]]:ps-2">
|
||||
{Object.values(SUPPORTED_EDITOR_LANGUAGES_CONFIG).map(
|
||||
(language) => (
|
||||
<SelectItem key={language.id} value={language.id}>
|
||||
<language.icon size={16} aria-hidden="true" />
|
||||
<span className="truncate">{language.label}</span>
|
||||
</SelectItem>
|
||||
)
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
<TabsContent value="code-editor" className="h-full mt-0">
|
||||
@ -98,9 +152,11 @@ function App() {
|
||||
"*"
|
||||
);
|
||||
}
|
||||
connectToLanguageServer(language).then((webSocket) => {
|
||||
webSocketRef.current = webSocket;
|
||||
});
|
||||
if (language in SUPPORTED_LSP_LANGUAGES) {
|
||||
connectToLanguageServer(language).then((webSocket) => {
|
||||
webSocketRef.current = webSocket;
|
||||
});
|
||||
}
|
||||
}}
|
||||
onChange={(value) => {
|
||||
if (value !== undefined) {
|
||||
|
@ -28,15 +28,6 @@ using namespace std;
|
||||
int main() {
|
||||
cout << "Hello, World!";
|
||||
return 0;
|
||||
}`,
|
||||
},
|
||||
java: {
|
||||
path: "playground/Main.java",
|
||||
language: "java",
|
||||
value: `public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, World!");
|
||||
}
|
||||
}`,
|
||||
},
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { COriginal, CplusplusOriginal, JavaOriginal } from "devicons-react";
|
||||
import { COriginal, CplusplusOriginal } from "devicons-react";
|
||||
|
||||
export const SUPPORTED_EDITOR_LANGUAGES = ["c", "cpp", "java"];
|
||||
export const SUPPORTED_EDITOR_LANGUAGES = ["c", "cpp"];
|
||||
|
||||
export const SUPPORTED_EDITOR_LANGUAGES_CONFIG = {
|
||||
c: {
|
||||
@ -13,11 +13,6 @@ export const SUPPORTED_EDITOR_LANGUAGES_CONFIG = {
|
||||
label: "C++",
|
||||
icon: CplusplusOriginal,
|
||||
},
|
||||
java: {
|
||||
id: "java",
|
||||
label: "Java",
|
||||
icon: JavaOriginal,
|
||||
},
|
||||
};
|
||||
|
||||
export type SupportedEditorLanguage =
|
||||
|
Loading…
Reference in New Issue
Block a user