mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
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:
73
dashboard/src/utils/monacoTheme.ts
Normal file
73
dashboard/src/utils/monacoTheme.ts
Normal 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);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user