@bpmn-nova/studio 0.3.1-preview → 0.3.2-preview
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -4
- package/dist/canvas.js +2 -1
- package/dist/context-menu.js +1 -1
- package/dist/controller.js +82 -4
- package/dist/index.d.ts +62 -3
- package/dist/modules/palette/index.d.ts +14 -2
- package/dist/modules/palette/index.js +3 -3
- package/dist/modules/properties-bpmn/index.js +3 -1
- package/dist/modules/renderer-svg/index.d.ts +1 -0
- package/dist/modules/renderer-svg/index.js +1 -1
- package/dist/shell.js +130 -19
- package/dist/styles.css +8 -0
- package/llms-full.txt +3082 -0
- package/llms.txt +225 -0
- package/package.json +4 -2
package/dist/shell.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createDefaultIconRegistry, hydrateIcons } from './modules/icons/index.js';
|
|
2
2
|
import { createDefaultPaletteRegistry, PalettePanel } from './modules/palette/index.js';
|
|
3
3
|
import { createDefaultPropertiesRegistry, PropertiesPanel } from './modules/properties/index.js';
|
|
4
|
-
import { demoRuntime } from './modules/runtime/index.js';
|
|
5
4
|
import { BpmnViewer } from './modules/viewer/index.js';
|
|
6
5
|
import { ThemeController } from './modules/theme/index.js';
|
|
7
6
|
import { openSvgExportPreview } from './modules/export-svg/index.js';
|
|
@@ -29,6 +28,39 @@ function mountSlot(slot, container, context) {
|
|
|
29
28
|
return null;
|
|
30
29
|
}
|
|
31
30
|
|
|
31
|
+
const STUDIO_MODES = ['design', 'viewer', 'instance'];
|
|
32
|
+
const STUDIO_SHELL_REGIONS = ['header', 'left', 'right', 'footer'];
|
|
33
|
+
const DEFAULT_STUDIO_SHELL_REGIONS = Object.freeze({
|
|
34
|
+
header: 'default',
|
|
35
|
+
left: 'default',
|
|
36
|
+
right: 'default',
|
|
37
|
+
footer: 'default',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function normalizeAllowedModes(allowedModes) {
|
|
41
|
+
if (allowedModes === undefined || allowedModes === null) return [...STUDIO_MODES];
|
|
42
|
+
if (!Array.isArray(allowedModes)) throw new Error('allowedModes must be an array of Studio modes.');
|
|
43
|
+
const normalized = [...new Set(allowedModes.filter((mode) => STUDIO_MODES.includes(mode)))];
|
|
44
|
+
if (!normalized.length || normalized.length !== allowedModes.length) {
|
|
45
|
+
throw new Error('allowedModes must contain one or more unique design, viewer, or instance modes.');
|
|
46
|
+
}
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function normalizeRegions(regions, current = DEFAULT_STUDIO_SHELL_REGIONS) {
|
|
51
|
+
if (regions === undefined || regions === null) return { ...current };
|
|
52
|
+
if (!regions || typeof regions !== 'object' || Array.isArray(regions)) {
|
|
53
|
+
throw new Error('regions must be an object containing header, left, right, or footer modes.');
|
|
54
|
+
}
|
|
55
|
+
for (const name of Object.keys(regions)) {
|
|
56
|
+
if (!STUDIO_SHELL_REGIONS.includes(name)) throw new Error(`Unknown Studio Shell region: ${name}.`);
|
|
57
|
+
if (!['default', 'hidden'].includes(regions[name])) {
|
|
58
|
+
throw new Error(`Studio Shell region "${name}" must be "default" or "hidden".`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { ...current, ...regions };
|
|
62
|
+
}
|
|
63
|
+
|
|
32
64
|
export class BpmnStudioShell {
|
|
33
65
|
constructor({
|
|
34
66
|
container,
|
|
@@ -41,8 +73,10 @@ export class BpmnStudioShell {
|
|
|
41
73
|
rendererOptions = {},
|
|
42
74
|
slots = {},
|
|
43
75
|
layout = null,
|
|
44
|
-
|
|
76
|
+
regions = null,
|
|
77
|
+
runtime = null,
|
|
45
78
|
mode = 'design',
|
|
79
|
+
allowedModes = null,
|
|
46
80
|
projection = undefined,
|
|
47
81
|
responsive = false,
|
|
48
82
|
projectionOptions = null,
|
|
@@ -54,8 +88,13 @@ export class BpmnStudioShell {
|
|
|
54
88
|
onThemeChange = null,
|
|
55
89
|
} = {}) {
|
|
56
90
|
if (!container || !studio) throw new Error('BpmnStudioShell requires container and studio.');
|
|
91
|
+
if (typeof layout === 'function' && regions !== null && regions !== undefined) {
|
|
92
|
+
throw new Error('BpmnStudioShell options "layout" and "regions" cannot be used together.');
|
|
93
|
+
}
|
|
94
|
+
const resolvedAllowedModes = normalizeAllowedModes(allowedModes);
|
|
95
|
+
const resolvedMode = resolvedAllowedModes.includes(mode) ? mode : resolvedAllowedModes[0];
|
|
57
96
|
const instanceProjection = projection || (responsive ? 'auto' : 'approval');
|
|
58
|
-
const activeProjection =
|
|
97
|
+
const activeProjection = resolvedMode === 'instance' ? instanceProjection : 'standard';
|
|
59
98
|
Object.assign(this, {
|
|
60
99
|
container,
|
|
61
100
|
studio,
|
|
@@ -66,24 +105,57 @@ export class BpmnStudioShell {
|
|
|
66
105
|
rendererOptions,
|
|
67
106
|
slots,
|
|
68
107
|
runtime,
|
|
69
|
-
mode,
|
|
108
|
+
mode: resolvedMode,
|
|
109
|
+
allowedModes: resolvedAllowedModes,
|
|
70
110
|
projection: activeProjection,
|
|
71
111
|
_instanceProjection: instanceProjection,
|
|
72
112
|
responsive,
|
|
73
113
|
projectionOptions,
|
|
74
114
|
runtimeAppearance,
|
|
75
115
|
svgExport: svgExport || rendererOptions.svgExport || null,
|
|
116
|
+
_usesCustomLayout: typeof layout === 'function',
|
|
117
|
+
_regions: normalizeRegions(regions),
|
|
76
118
|
});
|
|
77
119
|
this.propertiesRegistry = propertiesRegistry || createDefaultPropertiesRegistry({ studio });
|
|
78
120
|
this.interactions = createInteractionController({ studio, templates: templateRegistry });
|
|
79
121
|
this._cleanups = [];
|
|
80
122
|
this._instances = [];
|
|
81
123
|
this._svgExportPreview = null;
|
|
124
|
+
this.actions = Object.freeze({
|
|
125
|
+
undo: () => this.studio.undo(),
|
|
126
|
+
redo: () => this.studio.redo(),
|
|
127
|
+
beautify: (options) => {
|
|
128
|
+
this.studio.commands.beautify(options);
|
|
129
|
+
requestAnimationFrame(() => this._fitActive());
|
|
130
|
+
},
|
|
131
|
+
rerouteEdges: (options) => {
|
|
132
|
+
this.studio.commands.rerouteEdges(options);
|
|
133
|
+
requestAnimationFrame(() => this._fitActive());
|
|
134
|
+
},
|
|
135
|
+
fitView: () => this.fitView(),
|
|
136
|
+
validate: () => this.studio.validate(),
|
|
137
|
+
importXml: (xml, engine) => this.studio.importXml(xml, engine),
|
|
138
|
+
exportXml: (engine) => this.studio.exportXml(engine),
|
|
139
|
+
exportSvg: (options) => this.exportSvg(options),
|
|
140
|
+
openSvgExportPreview: (options) => this.openSvgExportPreview(options),
|
|
141
|
+
});
|
|
82
142
|
this.container.classList.add('nova-studio-shell');
|
|
83
143
|
this.themeController = new ThemeController({ root: this.container, theme, onChange: onThemeChange });
|
|
84
144
|
this.container.style.setProperty('--nova-left-width', `${leftWidth}px`);
|
|
85
145
|
this.container.style.setProperty('--nova-right-width', `${rightWidth}px`);
|
|
86
|
-
const context = {
|
|
146
|
+
const context = {
|
|
147
|
+
studio,
|
|
148
|
+
shell: this,
|
|
149
|
+
actions: this.actions,
|
|
150
|
+
getState: () => this.studio.getState(),
|
|
151
|
+
subscribe: (listener) => this.studio.subscribe(listener),
|
|
152
|
+
iconRegistry,
|
|
153
|
+
paletteRegistry,
|
|
154
|
+
propertiesRegistry: this.propertiesRegistry,
|
|
155
|
+
templateRegistry,
|
|
156
|
+
contextMenuRegistry,
|
|
157
|
+
interactions: this.interactions,
|
|
158
|
+
};
|
|
87
159
|
const mount = {
|
|
88
160
|
canvas: (host, options = {}) => this._mountCanvas(host, options),
|
|
89
161
|
palette: (host, options = {}) => this._mountPalette(host, options),
|
|
@@ -109,7 +181,7 @@ export class BpmnStudioShell {
|
|
|
109
181
|
{ value: 'design', label: '流程设计', iconId: 'ui.design' },
|
|
110
182
|
{ value: 'viewer', label: '流程展示', iconId: 'ui.preview' },
|
|
111
183
|
{ value: 'instance', label: '审批轨迹', iconId: 'ui.trace' },
|
|
112
|
-
]) {
|
|
184
|
+
].filter((item) => this.allowedModes.includes(item.value))) {
|
|
113
185
|
const button = node('button');
|
|
114
186
|
button.type = 'button';
|
|
115
187
|
button.setAttribute('data-mode', item.value);
|
|
@@ -144,8 +216,8 @@ export class BpmnStudioShell {
|
|
|
144
216
|
};
|
|
145
217
|
|
|
146
218
|
const divider = () => tools.appendChild(node('span', 'nova-studio-tool-divider'));
|
|
147
|
-
const undo = tool('', '撤销 Ctrl/⌘+Z', () => this.
|
|
148
|
-
const redo = tool('', '重做 Ctrl/⌘+Y', () => this.
|
|
219
|
+
const undo = tool('', '撤销 Ctrl/⌘+Z', () => this.actions.undo(), 'is-icon', 'ui.undo');
|
|
220
|
+
const redo = tool('', '重做 Ctrl/⌘+Y', () => this.actions.redo(), 'is-icon', 'ui.redo');
|
|
149
221
|
divider();
|
|
150
222
|
const beautifySplit = node('div', 'nova-studio-beautify-split');
|
|
151
223
|
const beautifyButton = node('button', 'nova-studio-tool nova-studio-beautify is-magic');
|
|
@@ -200,7 +272,7 @@ export class BpmnStudioShell {
|
|
|
200
272
|
});
|
|
201
273
|
beautifySplit.append(beautifyButton, beautifyCaret, beautifyMenu);
|
|
202
274
|
tools.appendChild(beautifySplit);
|
|
203
|
-
const fit = tool('最佳视图', '适应画布内容', () => this.
|
|
275
|
+
const fit = tool('最佳视图', '适应画布内容', () => this.actions.fitView(), '', 'ui.fitView');
|
|
204
276
|
|
|
205
277
|
const importInput = node('input', 'nova-studio-import-input');
|
|
206
278
|
importInput.type = 'file';
|
|
@@ -220,7 +292,7 @@ export class BpmnStudioShell {
|
|
|
220
292
|
exportSvgButton.addEventListener('click', () => {
|
|
221
293
|
exportPopover.classList.add('is-hidden');
|
|
222
294
|
exportButton.focus({ preventScroll: true });
|
|
223
|
-
this.openSvgExportPreview();
|
|
295
|
+
this.actions.openSvgExportPreview();
|
|
224
296
|
});
|
|
225
297
|
const exportBpmnButton = node('button', 'nova-studio-export-option');
|
|
226
298
|
exportBpmnButton.type = 'button';
|
|
@@ -240,7 +312,7 @@ export class BpmnStudioShell {
|
|
|
240
312
|
const file = importInput.files?.[0];
|
|
241
313
|
if (!file) return;
|
|
242
314
|
try {
|
|
243
|
-
this.
|
|
315
|
+
this.actions.importXml(await file.text(), this.studio.model.engine);
|
|
244
316
|
this._setStatus('已导入 BPMN 文件', 'ok');
|
|
245
317
|
requestAnimationFrame(() => this._fitActive());
|
|
246
318
|
} catch (error) {
|
|
@@ -295,9 +367,13 @@ export class BpmnStudioShell {
|
|
|
295
367
|
this.container.append(header, body);
|
|
296
368
|
hydrateIcons(this.container, this.iconRegistry);
|
|
297
369
|
Object.assign(this, {
|
|
370
|
+
_header: header,
|
|
371
|
+
_headerStart: brand,
|
|
298
372
|
_body: body,
|
|
299
373
|
_left: left,
|
|
300
374
|
_right: right,
|
|
375
|
+
_canvasColumn: canvasColumn,
|
|
376
|
+
_footer: statusbar,
|
|
301
377
|
_canvasHost: canvasHost,
|
|
302
378
|
_floatingHead: floatingHead,
|
|
303
379
|
_scopeBack: scopeBack,
|
|
@@ -328,8 +404,15 @@ export class BpmnStudioShell {
|
|
|
328
404
|
else this.palette = mount.palette(left, { canvas: this.canvas });
|
|
329
405
|
if (this.slots.right) this._recordCleanup(mountSlot(this.slots.right, right, { ...context, canvas: this.canvas }));
|
|
330
406
|
else this.properties = mount.properties(right, { canvas: this.canvas });
|
|
331
|
-
if (this.slots.header) {
|
|
407
|
+
if (this.slots.header) {
|
|
408
|
+
header.innerHTML = '';
|
|
409
|
+
this._recordCleanup(mountSlot(this.slots.header, header, { ...context, canvas: this.canvas }));
|
|
410
|
+
} else if (this.slots.headerStart) {
|
|
411
|
+
brand.innerHTML = '';
|
|
412
|
+
this._recordCleanup(mountSlot(this.slots.headerStart, brand, { ...context, canvas: this.canvas }));
|
|
413
|
+
}
|
|
332
414
|
if (this.slots.footer) { statusbar.innerHTML = ''; this._recordCleanup(mountSlot(this.slots.footer, statusbar, { ...context, canvas: this.canvas })); }
|
|
415
|
+
hydrateIcons(this.container, this.iconRegistry);
|
|
333
416
|
this._offState = this.studio.subscribe((event) => {
|
|
334
417
|
if (event.type === 'historyChanged' || event.type === 'modelChanged') {
|
|
335
418
|
undo.disabled = !this.studio.history.canUndo;
|
|
@@ -399,14 +482,13 @@ export class BpmnStudioShell {
|
|
|
399
482
|
|
|
400
483
|
_runBeautify(action = null) {
|
|
401
484
|
const settings = this.studio.model.settings || {};
|
|
402
|
-
if (action === 'routing') this.
|
|
403
|
-
else if (action === 'smooth') this.
|
|
404
|
-
else this.
|
|
485
|
+
if (action === 'routing') this.actions.rerouteEdges({ edgeStyle: 'rounded' });
|
|
486
|
+
else if (action === 'smooth') this.actions.rerouteEdges({ edgeStyle: 'smooth' });
|
|
487
|
+
else this.actions.beautify({
|
|
405
488
|
direction: action || settings.direction || 'horizontal',
|
|
406
489
|
density: settings.layoutDensity || 'balanced',
|
|
407
490
|
edgeStyle: settings.edgeStyle || 'rounded',
|
|
408
491
|
});
|
|
409
|
-
requestAnimationFrame(() => this._fitActive());
|
|
410
492
|
}
|
|
411
493
|
|
|
412
494
|
_syncDensityButtons() {
|
|
@@ -416,13 +498,14 @@ export class BpmnStudioShell {
|
|
|
416
498
|
}
|
|
417
499
|
|
|
418
500
|
_setMode(mode, { force = false } = {}) {
|
|
419
|
-
if (!
|
|
501
|
+
if (!this.allowedModes.includes(mode)) return;
|
|
420
502
|
if (!force && this.mode === mode) return;
|
|
421
503
|
this.mode = mode;
|
|
422
504
|
this.projection = mode === 'instance' ? this._instanceProjection : 'standard';
|
|
423
505
|
this._modeButtons?.forEach((button, value) => button.classList.toggle('is-active', value === mode));
|
|
424
506
|
const readonly = mode !== 'design';
|
|
425
507
|
this._body?.classList.toggle('is-readonly', readonly);
|
|
508
|
+
this._applyRegions({ fit: false });
|
|
426
509
|
this._floatingHead?.classList.toggle('is-hidden', readonly);
|
|
427
510
|
this._designControls?.forEach((control) => control.classList.toggle('is-hidden-by-mode', readonly));
|
|
428
511
|
this._projectionSwitch?.classList.toggle('is-hidden', mode !== 'instance');
|
|
@@ -563,6 +646,34 @@ export class BpmnStudioShell {
|
|
|
563
646
|
this._syncProjectionButtons();
|
|
564
647
|
if (this.mode === 'instance') this.viewer?.setProjection?.(projection);
|
|
565
648
|
}
|
|
649
|
+
getRegions() { return Object.freeze({ ...this._regions }); }
|
|
650
|
+
setRegions(regions) {
|
|
651
|
+
if (this._usesCustomLayout) {
|
|
652
|
+
throw new Error('BpmnStudioShell setRegions() is unavailable when a custom layout is active.');
|
|
653
|
+
}
|
|
654
|
+
const next = normalizeRegions(regions, this._regions);
|
|
655
|
+
const changed = STUDIO_SHELL_REGIONS.some((name) => next[name] !== this._regions[name]);
|
|
656
|
+
this._regions = next;
|
|
657
|
+
if (changed) this._applyRegions();
|
|
658
|
+
return this.getRegions();
|
|
659
|
+
}
|
|
660
|
+
_applyRegions({ fit = true } = {}) {
|
|
661
|
+
if (this._usesCustomLayout || !this._body) return;
|
|
662
|
+
const readonly = this.mode !== 'design';
|
|
663
|
+
const headerHidden = this._regions.header === 'hidden';
|
|
664
|
+
const leftHidden = readonly || this._regions.left === 'hidden';
|
|
665
|
+
const rightHidden = this._regions.right === 'hidden';
|
|
666
|
+
const footerHidden = this._regions.footer === 'hidden';
|
|
667
|
+
this.container.classList.toggle('is-header-hidden', headerHidden);
|
|
668
|
+
this._body.classList.toggle('is-left-hidden', leftHidden);
|
|
669
|
+
this._body.classList.toggle('is-right-hidden', rightHidden);
|
|
670
|
+
this._canvasColumn?.classList.toggle('is-footer-hidden', footerHidden);
|
|
671
|
+
if (this._header) this._header.hidden = headerHidden;
|
|
672
|
+
if (this._left) this._left.hidden = leftHidden;
|
|
673
|
+
if (this._right) this._right.hidden = rightHidden;
|
|
674
|
+
if (this._footer) this._footer.hidden = footerHidden;
|
|
675
|
+
if (fit) requestAnimationFrame(() => this._fitActive());
|
|
676
|
+
}
|
|
566
677
|
setTheme(theme) { return this.themeController.setTheme(theme); }
|
|
567
678
|
setThemeMode(mode) { return this.themeController.setMode(mode); }
|
|
568
679
|
getThemeState() { return this.themeController.getState(); }
|
|
@@ -618,7 +729,7 @@ export class BpmnStudioShell {
|
|
|
618
729
|
}
|
|
619
730
|
|
|
620
731
|
_showValidationStatus() {
|
|
621
|
-
const issues = this.
|
|
732
|
+
const issues = this.actions.validate();
|
|
622
733
|
if (!issues.length) this._setStatus('校验通过:流程结构正常', 'ok');
|
|
623
734
|
else {
|
|
624
735
|
const errors = issues.filter((issue) => issue.level === 'error').length;
|
|
@@ -628,7 +739,7 @@ export class BpmnStudioShell {
|
|
|
628
739
|
}
|
|
629
740
|
|
|
630
741
|
_exportBpmn() {
|
|
631
|
-
const blob = new Blob([this.
|
|
742
|
+
const blob = new Blob([this.actions.exportXml()], { type: 'application/xml;charset=utf-8' });
|
|
632
743
|
const url = URL.createObjectURL(blob);
|
|
633
744
|
const anchor = node('a');
|
|
634
745
|
anchor.href = url;
|
package/dist/styles.css
CHANGED
|
@@ -1141,6 +1141,8 @@ textarea.property-control { resize: vertical; }
|
|
|
1141
1141
|
|
|
1142
1142
|
/* @bpmn-nova/internal/studio */
|
|
1143
1143
|
.nova-studio-shell { --nova-left-width: 244px; --nova-right-width: 360px; --nova-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; --nova-font-size-xs: 10px; --nova-font-size-sm: 12px; --nova-font-size-md: 14px; --nova-font-size-lg: 16px; --nova-font-weight-regular: 400; --nova-font-weight-medium: 500; --nova-font-weight-semibold: 600; --nova-font-weight-bold: 700; position: relative; isolation: isolate; width: 100%; height: 100%; min-height: 520px; overflow: hidden; display: grid; grid-template-rows: 58px minmax(0, 1fr); color: var(--nova-color-text, #263148); background: var(--nova-color-canvas, #f6f7fb); font-family: var(--nova-font-family); }
|
|
1144
|
+
.nova-studio-shell.is-header-hidden { grid-template-rows: minmax(0, 1fr); }
|
|
1145
|
+
.nova-studio-header[hidden], .nova-studio-left[hidden], .nova-studio-right[hidden], .nova-studio-statusbar[hidden] { display: none !important; }
|
|
1144
1146
|
.nova-studio-header { min-width: 0; border-bottom: 1px solid var(--nova-color-divider, #e4e8f0); background: var(--nova-color-surface, #fff); display: grid; grid-template-columns: minmax(180px, auto) auto minmax(0, 1fr); align-items: center; gap: 18px; padding: 0 12px 0 14px; }
|
|
1145
1147
|
.nova-studio-brand { min-width: 0; display: flex; align-items: center; gap: 10px; }
|
|
1146
1148
|
.nova-studio-brand-mark { flex: none; width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; color: var(--nova-color-text-inverse, #fff); background: linear-gradient(145deg, var(--nova-color-primary, #5362da), var(--nova-color-primary-hover)); font-size: var(--nova-font-size-md); font-weight: var(--nova-font-weight-bold); box-shadow: var(--nova-shadow-sm); }
|
|
@@ -1194,7 +1196,11 @@ textarea.property-control { resize: vertical; }
|
|
|
1194
1196
|
.nova-studio-beautify-action-icon > .nova-icon-svg { width: 14px; height: 14px; }
|
|
1195
1197
|
.nova-studio-beautify-action strong { font-size: var(--nova-font-size-sm); font-weight: var(--nova-font-weight-semibold); line-height: 18px; }.nova-studio-beautify-action small { color: #778195; color: var(--nova-color-text-muted, #778195); font-size: var(--nova-font-size-xs); line-height: 14px; }
|
|
1196
1198
|
.nova-studio-body { min-width: 0; min-height: 0; display: grid; grid-template-columns: var(--nova-left-width) minmax(320px, 1fr) var(--nova-right-width); }
|
|
1199
|
+
.nova-studio-body.is-left-hidden { grid-template-columns: minmax(320px, 1fr) var(--nova-right-width); }
|
|
1200
|
+
.nova-studio-body.is-right-hidden { grid-template-columns: var(--nova-left-width) minmax(320px, 1fr); }
|
|
1201
|
+
.nova-studio-body.is-left-hidden.is-right-hidden { grid-template-columns: minmax(320px, 1fr); }
|
|
1197
1202
|
.nova-studio-body.is-readonly { grid-template-columns: minmax(320px, 1fr) var(--nova-right-width); }
|
|
1203
|
+
.nova-studio-body.is-readonly.is-right-hidden { grid-template-columns: minmax(320px, 1fr); }
|
|
1198
1204
|
.nova-studio-body.is-readonly .nova-studio-left { display: none; }
|
|
1199
1205
|
.nova-studio-left, .nova-studio-right, .nova-studio-canvas-column, .nova-studio-canvas { min-width: 0; min-height: 0; overflow: hidden; }
|
|
1200
1206
|
.nova-studio-left { border-right: 1px solid var(--nova-color-divider, #e4e8f0); background: var(--nova-color-surface, #fff); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
|
|
@@ -1206,6 +1212,7 @@ textarea.property-control { resize: vertical; }
|
|
|
1206
1212
|
.nova-studio-left::-webkit-scrollbar-thumb:hover, .nova-studio-right::-webkit-scrollbar-thumb:hover { background: #c1c9d5; background: var(--nova-color-text-muted); }
|
|
1207
1213
|
.nova-studio-left::-webkit-scrollbar-button, .nova-studio-right::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
|
|
1208
1214
|
.nova-studio-canvas-column { display: grid; grid-template-rows: minmax(0, 1fr) 35px; background: var(--nova-color-canvas, #f7f8fc); }
|
|
1215
|
+
.nova-studio-canvas-column.is-footer-hidden { grid-template-rows: minmax(0, 1fr); }
|
|
1209
1216
|
.nova-studio-canvas-stage { position: relative; min-width: 0; min-height: 0; overflow: hidden; }
|
|
1210
1217
|
.nova-studio-canvas { position: relative; }
|
|
1211
1218
|
.nova-studio-canvas-stage > .nova-studio-canvas { width: 100%; height: 100%; }
|
|
@@ -1422,6 +1429,7 @@ textarea.property-control { resize: vertical; }
|
|
|
1422
1429
|
}
|
|
1423
1430
|
@media (max-width: 720px) {
|
|
1424
1431
|
.nova-studio-shell { grid-template-rows: 54px minmax(0,1fr); }
|
|
1432
|
+
.nova-studio-shell.is-header-hidden { grid-template-rows: minmax(0, 1fr); }
|
|
1425
1433
|
.nova-studio-header { grid-template-columns: auto minmax(0,1fr); padding-left: 9px; }
|
|
1426
1434
|
.nova-studio-brand-copy { display: none; }
|
|
1427
1435
|
.nova-studio-body { grid-template-columns: 1fr; }
|