mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart theming: selectable chart theme + spec↔config merge/extract
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
* inline near the editor (spec §03E), mirroring the preview via PreviewStore.
|
||||
*/
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect, useRef, type RefObject } from 'react';
|
||||
// `edcore.main` is the full standalone editor — every feature contribution
|
||||
// (folding, suggest widget, word operations like Cmd+Backspace, find, bracket
|
||||
// colorization, multi-cursor, …) — but WITHOUT the `monaco-editor` barrel's
|
||||
@@ -25,6 +25,11 @@ import '../infrastructure/monaco-env'; // side-effect: wire workers before creat
|
||||
import { configureVegaLiteJson } from '../infrastructure/monaco-schema';
|
||||
import { configureJsonFormatter, installFormatOnPaste } from '../infrastructure/monaco-format';
|
||||
import { openModal } from '../modals/ModalCoordinator';
|
||||
import {
|
||||
installSpecConfigActions,
|
||||
runExtractConfig,
|
||||
runMergeChartTheme,
|
||||
} from '../services/spec-config-actions';
|
||||
import { useAppStore } from '../stores/AppStore';
|
||||
import { confirm } from '../stores/ConfirmStore';
|
||||
import { hasInlineData } from '../stores/ExtractStore';
|
||||
@@ -35,6 +40,7 @@ import { selectActiveSnippet, selectShownText, useSnippetStore } from '../stores
|
||||
import { useUserSettingsStore } from '../stores/UserSettingsStore';
|
||||
import { Icon } from './Icon';
|
||||
import { SegmentedControl, type SegmentedOption } from './SegmentedControl';
|
||||
import { SelectControl } from './SelectControl';
|
||||
import {
|
||||
NumberControl,
|
||||
RangeControl,
|
||||
@@ -139,7 +145,30 @@ configureVegaLiteJson();
|
||||
// Register the compact JSON formatter once (Format Document + format-on-paste, §03A).
|
||||
configureJsonFormatter();
|
||||
|
||||
function EditorToolbar() {
|
||||
/** The two spec↔config operations, surfaced as an overflow menu (council:
|
||||
* Carbon menu-buttons — overflow for additional options under space
|
||||
* constraint; NN/g #6 — a visible home, with the Monaco context menu and F1
|
||||
* palette as the #7 accelerators on the same code paths). */
|
||||
const CONFIG_ACTIONS = [
|
||||
{
|
||||
value: 'merge',
|
||||
label: 'Merge chart theme into spec',
|
||||
detail: 'Write the active chart theme into the config block',
|
||||
},
|
||||
{
|
||||
value: 'extract',
|
||||
label: 'Extract config from spec',
|
||||
detail: 'Remove the config block and copy it to the clipboard',
|
||||
},
|
||||
] as const;
|
||||
|
||||
type ConfigActionId = (typeof CONFIG_ACTIONS)[number]['value'];
|
||||
|
||||
function EditorToolbar({
|
||||
editorRef,
|
||||
}: {
|
||||
editorRef: RefObject<monaco.editor.IStandaloneCodeEditor | null>;
|
||||
}) {
|
||||
const activeId = useSnippetStore((s) => s.activeSnippetId);
|
||||
const editorView = useSnippetStore((s) => s.editorView);
|
||||
const setEditorView = useSnippetStore((s) => s.setEditorView);
|
||||
@@ -161,6 +190,13 @@ function EditorToolbar() {
|
||||
// the button and the Cmd/Ctrl+S shortcut (EventRouter) behave identically.
|
||||
const handlePublish = publishActiveSnippet;
|
||||
|
||||
const handleConfigAction = (action: ConfigActionId) => {
|
||||
const editor = editorRef.current;
|
||||
if (!editor) return;
|
||||
if (action === 'merge') runMergeChartTheme(editor);
|
||||
else void runExtractConfig(editor);
|
||||
};
|
||||
|
||||
const handleRevert = async () => {
|
||||
const ok = await confirm({
|
||||
title: 'Revert draft',
|
||||
@@ -207,6 +243,17 @@ function EditorToolbar() {
|
||||
<span className={styles.actionLabel}>Extract to Dataset</span>
|
||||
</button>
|
||||
)}
|
||||
<SelectControl
|
||||
id="editor-config-actions"
|
||||
label="Spec config actions"
|
||||
heading="Spec config"
|
||||
options={CONFIG_ACTIONS}
|
||||
onSelect={handleConfigAction}
|
||||
triggerClassName={styles.action}
|
||||
triggerContent="Config"
|
||||
triggerTitle="Spec config actions — merge the chart theme in, or extract the config out"
|
||||
disabled={activeId === null || editorView === 'published'}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className={`${styles.action} ${styles.collapsible}`}
|
||||
@@ -286,6 +333,11 @@ export function SpecEditor() {
|
||||
// up the formatted text. No-op on the read-only published view / invalid JSON.
|
||||
const pasteSub = installFormatOnPaste(editor);
|
||||
|
||||
// Merge-chart-theme / extract-config actions (context menu + F1 palette,
|
||||
// docs/chart-theming-scope.md §4.3). Edits land via onDidChangeModelContent
|
||||
// above, so the draft buffer stays in sync like any other edit.
|
||||
const configActionsSub = installSpecConfigActions(editor);
|
||||
|
||||
// Cmd/Ctrl+S is owned globally by the EventRouter (docs/architecture/04 →
|
||||
// "bind listeners in exactly one place"), which publishes before the
|
||||
// interactive-context gate so it works while the editor has focus. Monaco
|
||||
@@ -294,6 +346,7 @@ export function SpecEditor() {
|
||||
return () => {
|
||||
sub.dispose();
|
||||
pasteSub.dispose();
|
||||
configActionsSub.dispose();
|
||||
editor.dispose();
|
||||
editorRef.current = null;
|
||||
};
|
||||
@@ -336,7 +389,7 @@ export function SpecEditor() {
|
||||
|
||||
return (
|
||||
<div className={styles.editorPane}>
|
||||
<EditorToolbar />
|
||||
<EditorToolbar editorRef={editorRef} />
|
||||
<div className={styles.editorWrap}>
|
||||
{activeId === null && <div className={styles.placeholder}>Select or create a snippet</div>}
|
||||
<div className={styles.editor} ref={hostRef} />
|
||||
|
||||
Reference in New Issue
Block a user