refactor: convert to bun-workspaces monorepo (desktop/ + www/)
- Move the Tauri app (React frontend + Rust backend) into desktop/ via git mv — configs unchanged (relative paths: tauri.conf.json, vite.config.ts) - Root package.json becomes a private bun workspace container with orchestration scripts; desktop package renamed gridline-desktop - Scaffold www/ with Astro 7 + Tailwind v4 (hand-wired vite plugin, static output, ready for Dokploy) - Update release.yml for the new layout: projectPath: desktop, desktop/src-tauri resource paths, rust-cache workspace path - Update README + AGENTS.md structure trees and dev commands - Verified: vitest (1074), cargo test (354), desktop build, tauri dev (window launches), tauri build (dmg + app bundles), Astro build
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import Editor, { type OnMount, type BeforeMount } from "@monaco-editor/react";
|
||||
import * as monaco from "monaco-editor";
|
||||
import { useSettingsStore } from "../../stores/settingsStore";
|
||||
|
||||
interface QueryEditorProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
onRun: () => void;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export function QueryEditor({
|
||||
value,
|
||||
onChange,
|
||||
onRun,
|
||||
readOnly = false,
|
||||
}: QueryEditorProps) {
|
||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
|
||||
|
||||
const editorFontFamily = useSettingsStore(
|
||||
(s) => s.settings?.editor_font_family ?? "Space Mono",
|
||||
);
|
||||
const editorFontSize = useSettingsStore(
|
||||
(s) => s.settings?.editor_font_size ?? 13,
|
||||
);
|
||||
const editorWordWrap = useSettingsStore(
|
||||
(s) => s.settings?.editor_word_wrap ?? "off",
|
||||
);
|
||||
const editorMinimap = useSettingsStore(
|
||||
(s) => s.settings?.editor_minimap ?? false,
|
||||
);
|
||||
const editorTabSize = useSettingsStore(
|
||||
(s) => s.settings?.editor_tab_size ?? 4,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
editorRef.current?.updateOptions?.({
|
||||
fontFamily: editorFontFamily,
|
||||
fontSize: editorFontSize,
|
||||
wordWrap: editorWordWrap === "on" ? "on" : "off",
|
||||
minimap: { enabled: editorMinimap },
|
||||
tabSize: editorTabSize,
|
||||
});
|
||||
monaco.editor.remeasureFonts();
|
||||
}, [editorFontFamily, editorFontSize, editorWordWrap, editorMinimap, editorTabSize]);
|
||||
|
||||
const handleMount: OnMount = useCallback(
|
||||
(editor) => {
|
||||
editorRef.current = editor;
|
||||
editor.addAction({
|
||||
id: "run-query",
|
||||
label: "Run Query",
|
||||
keybindings: [2048 | 3], // Cmd/Ctrl+Enter
|
||||
run: () => onRun(),
|
||||
});
|
||||
editor.focus();
|
||||
|
||||
// Custom fonts (@fontsource Space Mono) load asynchronously. Monaco
|
||||
// measures glyph widths at creation, so if the font lands after that the
|
||||
// cursor/selection drift rightward the further along the line you are.
|
||||
// Re-measure now (fonts may already be ready) and again once fonts load.
|
||||
const reMeasure = () => monaco.editor.remeasureFonts();
|
||||
reMeasure();
|
||||
try {
|
||||
void document.fonts?.load('13px "Space Mono"').then(() => {
|
||||
requestAnimationFrame(reMeasure);
|
||||
// WebKit can settle a frame late; re-measure once more to be safe
|
||||
setTimeout(reMeasure, 200);
|
||||
});
|
||||
} catch {
|
||||
// fonts API unavailable — nothing more we can do
|
||||
}
|
||||
},
|
||||
[onRun],
|
||||
);
|
||||
|
||||
// Transparent editor background so the app's canvas shows through
|
||||
const handleBeforeMount: BeforeMount = useCallback((monaco) => {
|
||||
monaco.editor.defineTheme("gridline-sql", {
|
||||
base: "vs-dark",
|
||||
inherit: true,
|
||||
rules: [],
|
||||
colors: {
|
||||
"editor.background": "#00000000",
|
||||
"editorGutter.background": "#00000000",
|
||||
"editor.lineHighlightBackground": "#ffffff08",
|
||||
"editorLineNumber.foreground": "#5b5b5e",
|
||||
"editorLineNumber.activeForeground": "#a1a1a6",
|
||||
},
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="h-full min-h-0" data-testid="query-editor">
|
||||
<Editor
|
||||
height="100%"
|
||||
language="sql"
|
||||
theme="gridline-sql"
|
||||
beforeMount={handleBeforeMount}
|
||||
value={value}
|
||||
onChange={(v) => onChange(v ?? "")}
|
||||
onMount={handleMount}
|
||||
options={{
|
||||
minimap: { enabled: editorMinimap },
|
||||
fontSize: editorFontSize,
|
||||
fontFamily: editorFontFamily,
|
||||
lineNumbers: "on",
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: editorWordWrap === "on" ? "on" : "off",
|
||||
readOnly,
|
||||
placeholder: "Enter your SQL query…",
|
||||
automaticLayout: true,
|
||||
tabSize: editorTabSize,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user