feat(dashboard): glassmorphism editor and reactor Monaco theme

ConfigPage.vue:
- Editor dialog now uses glassmorphism container with backdrop-filter blur(40px)
- Editor card: deep obsidian translucent bg, inset shadow, cyan border
- Monaco theme changed from vs-dark to custom reactor-dark
  - Transparent background reveals reactor canvas beneath
  - Cherenkov blue line highlights and cursor
  - Industrial precision line numbers

New monacoTheme.ts:
- defineReactorMonacoTheme() registers the custom theme
- Transparent editor background (rgba 0,0,0,0)
- Cyan cursor, selection, and line highlight colors
This commit is contained in:
LIghtJUNction
2026-03-29 16:51:59 +08:00
parent 282ef94911
commit b79e252100
2 changed files with 161 additions and 36 deletions

View File

@@ -0,0 +1,73 @@
import type { editor } from "monaco-editor";
/**
* Defines the custom "reactor" Monaco theme:
* - Transparent background so the reactor canvas shows through
* - Cherenkov blue accents for UI elements
* - Industrial precision aesthetic
*/
export function defineReactorMonacoTheme() {
// Access monaco via the global
const monaco = (window as any).monaco;
if (!monaco) return;
monaco.editor.defineTheme("reactor-dark", {
base: "vs-dark",
inherit: true,
rules: [
{ token: "", foreground: "E4E1E6", background: "00000000" },
{ token: "comment", foreground: "5C6370", fontStyle: "italic" },
{ token: "keyword", foreground: "7DD9CC" },
{ token: "string", foreground: "69F0AE" },
{ token: "number", foreground: "FFD54F" },
{ token: "type", foreground: "A1C9FF" },
{ token: "delimiter", foreground: "8E9099" },
{ token: "variable", foreground: "E4E1E6" },
],
colors: {
"editor.background": "#00000000",
"editor.foreground": "#E4E1E6",
"editor.lineHighlightBackground": "#1A3A5C22",
"editor.lineHighlightBorder": "#00F2FF18",
"editor.selectionBackground": "#005FB044",
"editor.inactiveSelectionBackground": "#005FB022",
"editorLineNumber.foreground": "#44474F",
"editorLineNumber.activeForeground": "#00F2FF",
"editorCursor.foreground": "#00F2FF",
"editorWhitespace.foreground": "#1A1A22",
"editorIndentGuide.background": "#1A1A22",
"editorIndentGuide.activeBackground": "#00F2FF22",
"editor.wordHighlightBackground": "#005FB018",
"editorGutter.background": "#00000000",
"scrollbar.shadow": "#00000000",
"scrollbarSlider.background": "#1A3A5C44",
"scrollbarSlider.hoverBackground": "#1A3A5C88",
"scrollbarSlider.activeBackground": "#00F2FF44",
},
} satisfies editor.IStandaloneThemeData);
}
/**
* Highlight error lines in Monaco editor with Cherenkov red glow
*/
export function setMonacoEditorErrors(
monaco: any,
editorInstance: editor.IStandaloneCodeEditor | null,
errors: Array<{ line: number; message: string }>,
) {
if (!editorInstance || !monaco) return;
const model = editorInstance.getModel();
if (!model) return;
const markers: editor.IMarkerData[] = errors.map((err) => ({
severity: monaco.MarkerSeverity.Error,
message: err.message,
startLineNumber: err.line,
startColumn: 1,
endLineNumber: err.line,
endColumn: model.getLineMaxColumn(err.line),
}));
monaco.editor.setModelMarkers(model, "reactor-errors", markers);
}

View File

@@ -147,43 +147,48 @@
transition="dialog-bottom-transition"
scrollable
>
<v-card>
<v-toolbar color="primary" dark>
<v-btn icon @click="codeEditorDialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
<v-toolbar-title>{{ tm("codeEditor.title") }}</v-toolbar-title>
<v-spacer />
<v-toolbar-items style="display: flex; align-items: center">
<v-btn
style="margin-left: 16px"
size="small"
@click="configToString()"
>
{{ tm("editor.revertCode") }}
<div class="editor-reactor-container">
<v-card class="editor-glass-card">
<v-toolbar
class="editor-toolbar"
elevation="0"
>
<v-btn icon @click="codeEditorDialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
<v-btn
v-if="config_data_has_changed"
style="margin-left: 16px"
size="small"
@click="applyStrConfig()"
>
{{ tm("editor.applyConfig") }}
</v-btn>
<small style="margin-left: 16px"
>💡 {{ tm("editor.applyTip") }}</small
>
</v-toolbar-items>
</v-toolbar>
<v-card-text class="pa-0">
<VueMonacoEditor
v-model:value="config_data_str"
language="json"
theme="vs-dark"
style="height: calc(100vh - 64px)"
/>
</v-card-text>
</v-card>
<v-toolbar-title>{{ tm("codeEditor.title") }}</v-toolbar-title>
<v-spacer />
<v-toolbar-items style="display: flex; align-items: center">
<v-btn
style="margin-left: 16px"
size="small"
@click="configToString()"
>
{{ tm("editor.revertCode") }}
</v-btn>
<v-btn
v-if="config_data_has_changed"
style="margin-left: 16px"
size="small"
@click="applyStrConfig()"
>
{{ tm("editor.applyConfig") }}
</v-btn>
<small style="margin-left: 16px"
>💡 {{ tm("editor.applyTip") }}</small
>
</v-toolbar-items>
</v-toolbar>
<v-card-text class="pa-0 editor-monaco-wrapper">
<VueMonacoEditor
v-model:value="config_data_str"
language="json"
theme="reactor-dark"
style="height: calc(100vh - 64px)"
/>
</v-card-text>
</v-card>
</div>
</v-dialog>
<!-- Config Management Dialog -->
@@ -337,6 +342,7 @@ import {
} from "@/utils/confirmDialog";
import UnsavedChangesConfirmDialog from "@/components/config/UnsavedChangesConfirmDialog.vue";
import { normalizeTextInput } from "@/utils/inputValue";
import { defineReactorMonacoTheme } from "@/utils/monacoTheme";
export default {
name: "ConfigPage",
@@ -498,6 +504,9 @@ export default {
}
},
},
beforeMount() {
defineReactorMonacoTheme();
},
mounted() {
const hashConfigType = this.extractConfigTypeFromHash(
this.$route?.fullPath || "",
@@ -1105,4 +1114,47 @@ export default {
padding: 0;
border-radius: 0 0 16px 16px;
}
/* Reactor glassmorphism editor container */
.editor-reactor-container {
width: 100vw;
height: 100vh;
background: rgba(10, 10, 12, 0.92);
backdrop-filter: blur(40px) saturate(1.3);
display: flex;
align-items: center;
justify-content: center;
padding: 32px;
box-sizing: border-box;
}
.editor-glass-card {
width: 100%;
max-width: 1400px;
height: calc(100vh - 64px);
background: rgba(15, 15, 22, 0.55) !important;
backdrop-filter: blur(24px) saturate(1.2);
border: 1px solid rgba(0, 242, 255, 0.15);
border-radius: 28px !important;
box-shadow:
inset 0 0 40px rgba(0, 0, 0, 0.6),
0 0 80px rgba(0, 26, 51, 0.4),
0 0 0 0.5px rgba(0, 242, 255, 0.05);
overflow: hidden;
display: flex;
flex-direction: column;
}
.editor-toolbar {
background: rgba(10, 10, 16, 0.8) !important;
border-bottom: 1px solid rgba(0, 242, 255, 0.08) !important;
backdrop-filter: blur(12px);
flex-shrink: 0;
}
.editor-monaco-wrapper {
flex: 1;
overflow: hidden;
border-radius: 0 0 28px 28px;
}
</style>