@stevejtrettel/shader-sandbox 0.1.3 → 0.1.4
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 +220 -23
- package/bin/cli.js +106 -14
- package/dist-lib/app/App.d.ts +143 -15
- package/dist-lib/app/App.d.ts.map +1 -1
- package/dist-lib/app/App.js +1343 -108
- package/dist-lib/app/app.css +349 -24
- package/dist-lib/app/types.d.ts +48 -5
- package/dist-lib/app/types.d.ts.map +1 -1
- package/dist-lib/editor/EditorPanel.d.ts +2 -2
- package/dist-lib/editor/EditorPanel.d.ts.map +1 -1
- package/dist-lib/editor/EditorPanel.js +1 -1
- package/dist-lib/editor/editor-panel.css +55 -32
- package/dist-lib/editor/prism-editor.css +16 -16
- package/dist-lib/embed.js +1 -1
- package/dist-lib/engine/{ShadertoyEngine.d.ts → ShaderEngine.d.ts} +134 -10
- package/dist-lib/engine/ShaderEngine.d.ts.map +1 -0
- package/dist-lib/engine/ShaderEngine.js +1523 -0
- package/dist-lib/engine/glHelpers.d.ts +24 -0
- package/dist-lib/engine/glHelpers.d.ts.map +1 -1
- package/dist-lib/engine/glHelpers.js +88 -0
- package/dist-lib/engine/std140.d.ts +47 -0
- package/dist-lib/engine/std140.d.ts.map +1 -0
- package/dist-lib/engine/std140.js +119 -0
- package/dist-lib/engine/types.d.ts +55 -5
- package/dist-lib/engine/types.d.ts.map +1 -1
- package/dist-lib/engine/types.js +1 -1
- package/dist-lib/index.d.ts +4 -3
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -1
- package/dist-lib/layouts/SplitLayout.d.ts +2 -1
- package/dist-lib/layouts/SplitLayout.d.ts.map +1 -1
- package/dist-lib/layouts/SplitLayout.js +3 -0
- package/dist-lib/layouts/TabbedLayout.d.ts.map +1 -1
- package/dist-lib/layouts/UILayout.d.ts +55 -0
- package/dist-lib/layouts/UILayout.d.ts.map +1 -0
- package/dist-lib/layouts/UILayout.js +147 -0
- package/dist-lib/layouts/default.css +2 -2
- package/dist-lib/layouts/index.d.ts +11 -1
- package/dist-lib/layouts/index.d.ts.map +1 -1
- package/dist-lib/layouts/index.js +17 -1
- package/dist-lib/layouts/split.css +33 -31
- package/dist-lib/layouts/tabbed.css +127 -74
- package/dist-lib/layouts/types.d.ts +14 -3
- package/dist-lib/layouts/types.d.ts.map +1 -1
- package/dist-lib/main.js +33 -0
- package/dist-lib/project/configHelpers.d.ts +45 -0
- package/dist-lib/project/configHelpers.d.ts.map +1 -0
- package/dist-lib/project/configHelpers.js +196 -0
- package/dist-lib/project/generatedLoader.d.ts +2 -2
- package/dist-lib/project/generatedLoader.d.ts.map +1 -1
- package/dist-lib/project/generatedLoader.js +23 -5
- package/dist-lib/project/loadProject.d.ts +6 -6
- package/dist-lib/project/loadProject.d.ts.map +1 -1
- package/dist-lib/project/loadProject.js +396 -144
- package/dist-lib/project/loaderHelper.d.ts +4 -4
- package/dist-lib/project/loaderHelper.d.ts.map +1 -1
- package/dist-lib/project/loaderHelper.js +278 -116
- package/dist-lib/project/types.d.ts +292 -13
- package/dist-lib/project/types.d.ts.map +1 -1
- package/dist-lib/project/types.js +13 -1
- package/dist-lib/styles/base.css +5 -1
- package/dist-lib/uniforms/UniformControls.d.ts +60 -0
- package/dist-lib/uniforms/UniformControls.d.ts.map +1 -0
- package/dist-lib/uniforms/UniformControls.js +518 -0
- package/dist-lib/uniforms/UniformStore.d.ts +74 -0
- package/dist-lib/uniforms/UniformStore.d.ts.map +1 -0
- package/dist-lib/uniforms/UniformStore.js +145 -0
- package/dist-lib/uniforms/UniformsPanel.d.ts +53 -0
- package/dist-lib/uniforms/UniformsPanel.d.ts.map +1 -0
- package/dist-lib/uniforms/UniformsPanel.js +124 -0
- package/dist-lib/uniforms/index.d.ts +11 -0
- package/dist-lib/uniforms/index.d.ts.map +1 -0
- package/dist-lib/uniforms/index.js +8 -0
- package/package.json +1 -1
- package/src/app/App.ts +1469 -126
- package/src/app/app.css +349 -24
- package/src/app/types.ts +53 -5
- package/src/editor/EditorPanel.ts +5 -5
- package/src/editor/editor-panel.css +55 -32
- package/src/editor/prism-editor.css +16 -16
- package/src/embed.ts +1 -1
- package/src/engine/ShaderEngine.ts +1934 -0
- package/src/engine/glHelpers.ts +117 -0
- package/src/engine/std140.ts +136 -0
- package/src/engine/types.ts +69 -5
- package/src/index.ts +4 -3
- package/src/layouts/SplitLayout.ts +8 -3
- package/src/layouts/TabbedLayout.ts +3 -3
- package/src/layouts/UILayout.ts +185 -0
- package/src/layouts/default.css +2 -2
- package/src/layouts/index.ts +20 -1
- package/src/layouts/split.css +33 -31
- package/src/layouts/tabbed.css +127 -74
- package/src/layouts/types.ts +19 -3
- package/src/layouts/ui.css +289 -0
- package/src/main.ts +39 -1
- package/src/project/configHelpers.ts +225 -0
- package/src/project/generatedLoader.ts +27 -6
- package/src/project/loadProject.ts +459 -173
- package/src/project/loaderHelper.ts +377 -130
- package/src/project/types.ts +360 -14
- package/src/styles/base.css +5 -1
- package/src/styles/theme.css +292 -0
- package/src/uniforms/UniformControls.ts +660 -0
- package/src/uniforms/UniformStore.ts +166 -0
- package/src/uniforms/UniformsPanel.ts +163 -0
- package/src/uniforms/index.ts +13 -0
- package/src/uniforms/uniform-controls.css +342 -0
- package/src/uniforms/uniforms-panel.css +277 -0
- package/templates/shaders/example-buffer/config.json +1 -0
- package/dist-lib/engine/ShadertoyEngine.d.ts.map +0 -1
- package/dist-lib/engine/ShadertoyEngine.js +0 -704
- package/src/engine/ShadertoyEngine.ts +0 -929
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Layout
|
|
3
|
+
*
|
|
4
|
+
* Shader on left, uniform controls panel on right (~200px wide).
|
|
5
|
+
* Playback controls (play/pause, reset, screenshot) at bottom of UI panel.
|
|
6
|
+
* Responsive: stacks vertically on small screens (<600px).
|
|
7
|
+
*/
|
|
8
|
+
import './ui.css';
|
|
9
|
+
export class UILayout {
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.uniformControls = null;
|
|
12
|
+
this.playPauseButton = null;
|
|
13
|
+
// Callbacks (set by App)
|
|
14
|
+
this.onPlayPause = null;
|
|
15
|
+
this.onReset = null;
|
|
16
|
+
this.onScreenshot = null;
|
|
17
|
+
this.onUniformChange = null;
|
|
18
|
+
this.container = opts.container;
|
|
19
|
+
this.project = opts.project;
|
|
20
|
+
// Create root layout container
|
|
21
|
+
this.root = document.createElement('div');
|
|
22
|
+
this.root.className = 'layout-ui';
|
|
23
|
+
// Create canvas container (left side)
|
|
24
|
+
this.canvasContainer = document.createElement('div');
|
|
25
|
+
this.canvasContainer.className = 'ui-canvas-container';
|
|
26
|
+
// Create UI panel (right side)
|
|
27
|
+
this.uiPanel = document.createElement('div');
|
|
28
|
+
this.uiPanel.className = 'ui-panel';
|
|
29
|
+
// Create uniforms container (scrollable, vertically centered)
|
|
30
|
+
this.uniformsContainer = document.createElement('div');
|
|
31
|
+
this.uniformsContainer.className = 'ui-uniforms-container';
|
|
32
|
+
this.uiPanel.appendChild(this.uniformsContainer);
|
|
33
|
+
// Create playback controls container (fixed at bottom)
|
|
34
|
+
this.playbackContainer = document.createElement('div');
|
|
35
|
+
this.playbackContainer.className = 'ui-playback-container';
|
|
36
|
+
this.buildPlaybackControls();
|
|
37
|
+
this.uiPanel.appendChild(this.playbackContainer);
|
|
38
|
+
// Load uniform controls
|
|
39
|
+
this.loadUniformControls();
|
|
40
|
+
// Assemble and append to DOM
|
|
41
|
+
this.root.appendChild(this.canvasContainer);
|
|
42
|
+
this.root.appendChild(this.uiPanel);
|
|
43
|
+
this.container.appendChild(this.root);
|
|
44
|
+
}
|
|
45
|
+
getCanvasContainer() {
|
|
46
|
+
return this.canvasContainer;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Set callbacks for playback controls.
|
|
50
|
+
* Called by App after initialization.
|
|
51
|
+
*/
|
|
52
|
+
setPlaybackCallbacks(callbacks) {
|
|
53
|
+
this.onPlayPause = callbacks.onPlayPause;
|
|
54
|
+
this.onReset = callbacks.onReset;
|
|
55
|
+
this.onScreenshot = callbacks.onScreenshot;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Set callback for uniform changes.
|
|
59
|
+
* Called by App after initialization.
|
|
60
|
+
*/
|
|
61
|
+
setUniformCallback(callback) {
|
|
62
|
+
this.onUniformChange = callback;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Update play/pause button state.
|
|
66
|
+
*/
|
|
67
|
+
setPaused(paused) {
|
|
68
|
+
if (this.playPauseButton) {
|
|
69
|
+
this.playPauseButton.innerHTML = paused
|
|
70
|
+
? `<svg viewBox="0 0 16 16"><path d="M4 3v10l8-5-8-5z"/></svg>`
|
|
71
|
+
: `<svg viewBox="0 0 16 16"><path d="M5 3h2v10H5V3zm4 0h2v10H9V3z"/></svg>`;
|
|
72
|
+
this.playPauseButton.title = paused ? 'Play' : 'Pause';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
dispose() {
|
|
76
|
+
if (this.uniformControls) {
|
|
77
|
+
this.uniformControls.destroy();
|
|
78
|
+
this.uniformControls = null;
|
|
79
|
+
}
|
|
80
|
+
this.container.innerHTML = '';
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build playback control buttons.
|
|
84
|
+
*/
|
|
85
|
+
buildPlaybackControls() {
|
|
86
|
+
// Play/Pause button
|
|
87
|
+
this.playPauseButton = document.createElement('button');
|
|
88
|
+
this.playPauseButton.className = 'ui-control-button';
|
|
89
|
+
this.playPauseButton.title = 'Pause';
|
|
90
|
+
this.playPauseButton.innerHTML = `<svg viewBox="0 0 16 16"><path d="M5 3h2v10H5V3zm4 0h2v10H9V3z"/></svg>`;
|
|
91
|
+
this.playPauseButton.addEventListener('click', () => {
|
|
92
|
+
if (this.onPlayPause)
|
|
93
|
+
this.onPlayPause();
|
|
94
|
+
});
|
|
95
|
+
// Reset button
|
|
96
|
+
const resetButton = document.createElement('button');
|
|
97
|
+
resetButton.className = 'ui-control-button';
|
|
98
|
+
resetButton.title = 'Reset';
|
|
99
|
+
resetButton.innerHTML = `<svg viewBox="0 0 16 16"><path d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/><path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/></svg>`;
|
|
100
|
+
resetButton.addEventListener('click', () => {
|
|
101
|
+
if (this.onReset)
|
|
102
|
+
this.onReset();
|
|
103
|
+
});
|
|
104
|
+
// Screenshot button
|
|
105
|
+
const screenshotButton = document.createElement('button');
|
|
106
|
+
screenshotButton.className = 'ui-control-button';
|
|
107
|
+
screenshotButton.title = 'Screenshot';
|
|
108
|
+
screenshotButton.innerHTML = `<svg viewBox="0 0 16 16"><path d="M10.5 8.5a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z"/><path d="M2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2zm.5 2a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 2.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z"/></svg>`;
|
|
109
|
+
screenshotButton.addEventListener('click', () => {
|
|
110
|
+
if (this.onScreenshot)
|
|
111
|
+
this.onScreenshot();
|
|
112
|
+
});
|
|
113
|
+
this.playbackContainer.appendChild(this.playPauseButton);
|
|
114
|
+
this.playbackContainer.appendChild(resetButton);
|
|
115
|
+
this.playbackContainer.appendChild(screenshotButton);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Load uniform controls dynamically.
|
|
119
|
+
*/
|
|
120
|
+
async loadUniformControls() {
|
|
121
|
+
const uniforms = this.project.uniforms;
|
|
122
|
+
// If no uniforms, show empty state
|
|
123
|
+
if (!uniforms || Object.keys(uniforms).length === 0) {
|
|
124
|
+
const emptyState = document.createElement('div');
|
|
125
|
+
emptyState.className = 'ui-empty-state';
|
|
126
|
+
emptyState.textContent = 'No uniforms';
|
|
127
|
+
this.uniformsContainer.appendChild(emptyState);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const { UniformControls } = await import('../uniforms/UniformControls');
|
|
132
|
+
this.uniformControls = new UniformControls({
|
|
133
|
+
container: this.uniformsContainer,
|
|
134
|
+
uniforms: uniforms,
|
|
135
|
+
onChange: (name, value) => {
|
|
136
|
+
if (this.onUniformChange) {
|
|
137
|
+
this.onUniformChange(name, value);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.error('Failed to load uniform controls:', err);
|
|
144
|
+
this.uniformsContainer.textContent = 'Failed to load controls';
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
position: relative;
|
|
16
16
|
width: 800px;
|
|
17
17
|
height: 600px;
|
|
18
|
-
background:
|
|
18
|
+
background: var(--bg-canvas);
|
|
19
19
|
border-radius: 8px;
|
|
20
|
-
box-shadow:
|
|
20
|
+
box-shadow: var(--shadow-lg), var(--shadow-sm);
|
|
21
21
|
overflow: hidden;
|
|
22
22
|
}
|
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Layouts - Modular layout system for Shadertoy viewer
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides five layout modes:
|
|
5
5
|
* - Default: Canvas centered with styling
|
|
6
6
|
* - Fullscreen: Canvas fills entire viewport
|
|
7
7
|
* - Split: Canvas on left, code viewer on right
|
|
8
8
|
* - Tabbed: Single window with tabs for shader and code
|
|
9
|
+
* - UI: Canvas on left, uniforms panel on right
|
|
9
10
|
*/
|
|
10
11
|
export { FullscreenLayout } from './FullscreenLayout';
|
|
11
12
|
export { DefaultLayout } from './DefaultLayout';
|
|
12
13
|
export { SplitLayout } from './SplitLayout';
|
|
13
14
|
export { TabbedLayout } from './TabbedLayout';
|
|
15
|
+
export { UILayout } from './UILayout';
|
|
14
16
|
export type { BaseLayout, LayoutOptions, LayoutMode } from './types';
|
|
15
17
|
import { BaseLayout, LayoutOptions, LayoutMode } from './types';
|
|
18
|
+
import { ThemeMode } from '../project/types';
|
|
19
|
+
/**
|
|
20
|
+
* Apply theme to the document.
|
|
21
|
+
* Sets the data-theme attribute on the html element.
|
|
22
|
+
*
|
|
23
|
+
* @param theme - Theme mode to apply ('light', 'dark', or 'system')
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyTheme(theme: ThemeMode): void;
|
|
16
26
|
/**
|
|
17
27
|
* Factory function to create the appropriate layout based on mode.
|
|
18
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layouts/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layouts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAOrE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAEjD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,GACrB,UAAU,CAgBZ"}
|
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Layouts - Modular layout system for Shadertoy viewer
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides five layout modes:
|
|
5
5
|
* - Default: Canvas centered with styling
|
|
6
6
|
* - Fullscreen: Canvas fills entire viewport
|
|
7
7
|
* - Split: Canvas on left, code viewer on right
|
|
8
8
|
* - Tabbed: Single window with tabs for shader and code
|
|
9
|
+
* - UI: Canvas on left, uniforms panel on right
|
|
9
10
|
*/
|
|
10
11
|
export { FullscreenLayout } from './FullscreenLayout';
|
|
11
12
|
export { DefaultLayout } from './DefaultLayout';
|
|
12
13
|
export { SplitLayout } from './SplitLayout';
|
|
13
14
|
export { TabbedLayout } from './TabbedLayout';
|
|
15
|
+
export { UILayout } from './UILayout';
|
|
14
16
|
import { FullscreenLayout } from './FullscreenLayout';
|
|
15
17
|
import { DefaultLayout } from './DefaultLayout';
|
|
16
18
|
import { SplitLayout } from './SplitLayout';
|
|
17
19
|
import { TabbedLayout } from './TabbedLayout';
|
|
20
|
+
import { UILayout } from './UILayout';
|
|
21
|
+
/**
|
|
22
|
+
* Apply theme to the document.
|
|
23
|
+
* Sets the data-theme attribute on the html element.
|
|
24
|
+
*
|
|
25
|
+
* @param theme - Theme mode to apply ('light', 'dark', or 'system')
|
|
26
|
+
*/
|
|
27
|
+
export function applyTheme(theme) {
|
|
28
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
29
|
+
}
|
|
18
30
|
/**
|
|
19
31
|
* Factory function to create the appropriate layout based on mode.
|
|
20
32
|
*
|
|
@@ -23,6 +35,8 @@ import { TabbedLayout } from './TabbedLayout';
|
|
|
23
35
|
* @returns Layout instance implementing BaseLayout interface
|
|
24
36
|
*/
|
|
25
37
|
export function createLayout(mode, options) {
|
|
38
|
+
// Apply theme from project configuration
|
|
39
|
+
applyTheme(options.project.theme);
|
|
26
40
|
switch (mode) {
|
|
27
41
|
case 'fullscreen':
|
|
28
42
|
return new FullscreenLayout(options);
|
|
@@ -32,5 +46,7 @@ export function createLayout(mode, options) {
|
|
|
32
46
|
return new SplitLayout(options);
|
|
33
47
|
case 'tabbed':
|
|
34
48
|
return new TabbedLayout(options);
|
|
49
|
+
case 'ui':
|
|
50
|
+
return new UILayout(options);
|
|
35
51
|
}
|
|
36
52
|
}
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
.layout-split .canvas-container {
|
|
17
17
|
position: relative;
|
|
18
18
|
flex: 1;
|
|
19
|
-
background:
|
|
19
|
+
background: var(--bg-canvas);
|
|
20
20
|
border-radius: 8px;
|
|
21
|
-
box-shadow:
|
|
21
|
+
box-shadow: var(--shadow-md), var(--shadow-sm);
|
|
22
22
|
overflow: hidden;
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -27,17 +27,17 @@
|
|
|
27
27
|
flex: 1;
|
|
28
28
|
display: flex;
|
|
29
29
|
flex-direction: column;
|
|
30
|
-
background:
|
|
30
|
+
background: var(--bg-secondary);
|
|
31
31
|
border-radius: 8px;
|
|
32
|
-
box-shadow:
|
|
32
|
+
box-shadow: var(--shadow-md), var(--shadow-sm);
|
|
33
33
|
overflow: hidden;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/* ===== Code Panel ===== */
|
|
37
37
|
.tab-bar {
|
|
38
38
|
display: flex;
|
|
39
|
-
background:
|
|
40
|
-
border-bottom: 1px solid
|
|
39
|
+
background: var(--tab-bg);
|
|
40
|
+
border-bottom: 1px solid var(--border-primary);
|
|
41
41
|
padding: 8px 8px 0 8px;
|
|
42
42
|
gap: 4px;
|
|
43
43
|
}
|
|
@@ -50,17 +50,18 @@
|
|
|
50
50
|
font-size: 13px;
|
|
51
51
|
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
52
52
|
cursor: pointer;
|
|
53
|
-
transition: background 0.2s;
|
|
54
|
-
color:
|
|
53
|
+
transition: background 0.2s, color 0.2s;
|
|
54
|
+
color: var(--tab-text);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
.tab-button:hover {
|
|
58
|
-
background:
|
|
58
|
+
background: var(--button-bg-hover);
|
|
59
|
+
color: var(--tab-text-hover);
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
.tab-button.active {
|
|
62
|
-
background:
|
|
63
|
-
color:
|
|
63
|
+
background: var(--bg-secondary);
|
|
64
|
+
color: var(--tab-text-active);
|
|
64
65
|
font-weight: 500;
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -69,10 +70,10 @@
|
|
|
69
70
|
top: 12px;
|
|
70
71
|
right: 12px;
|
|
71
72
|
padding: 6px;
|
|
72
|
-
background:
|
|
73
|
+
background: var(--button-bg);
|
|
73
74
|
border: none;
|
|
74
75
|
border-radius: 4px;
|
|
75
|
-
color:
|
|
76
|
+
color: var(--button-text);
|
|
76
77
|
cursor: pointer;
|
|
77
78
|
transition: all 0.2s;
|
|
78
79
|
z-index: 10;
|
|
@@ -82,8 +83,8 @@
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
.copy-button:hover {
|
|
85
|
-
background:
|
|
86
|
-
color:
|
|
86
|
+
background: var(--button-bg-hover);
|
|
87
|
+
color: var(--button-text-hover);
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
.copy-button:active {
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
.copy-button.copied {
|
|
94
|
-
color:
|
|
95
|
+
color: var(--success-text);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
.code-viewer {
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
min-height: 0; /* Allow shrinking below content size in flexbox */
|
|
100
101
|
overflow: auto;
|
|
101
102
|
position: relative;
|
|
102
|
-
background:
|
|
103
|
+
background: var(--code-bg);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
/* Prism.js syntax highlighting */
|
|
@@ -109,7 +110,8 @@
|
|
|
109
110
|
font-size: 13px;
|
|
110
111
|
line-height: 1.5;
|
|
111
112
|
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
112
|
-
background:
|
|
113
|
+
background: var(--code-bg);
|
|
114
|
+
color: var(--code-text);
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
.code-viewer code {
|
|
@@ -117,23 +119,23 @@
|
|
|
117
119
|
font-size: inherit;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
/* Prism theme -
|
|
121
|
-
.token.comment { color:
|
|
122
|
-
.token.keyword { color:
|
|
123
|
-
.token.string { color:
|
|
124
|
-
.token.number { color:
|
|
125
|
-
.token.operator { color:
|
|
126
|
-
.token.function { color:
|
|
127
|
-
.token.class-name { color:
|
|
128
|
-
.token.punctuation { color:
|
|
122
|
+
/* Prism theme - uses CSS variables */
|
|
123
|
+
.token.comment { color: var(--syntax-comment); }
|
|
124
|
+
.token.keyword { color: var(--syntax-keyword); }
|
|
125
|
+
.token.string { color: var(--syntax-string); }
|
|
126
|
+
.token.number { color: var(--syntax-number); }
|
|
127
|
+
.token.operator { color: var(--syntax-operator); }
|
|
128
|
+
.token.function { color: var(--syntax-function); }
|
|
129
|
+
.token.class-name { color: var(--syntax-class); }
|
|
130
|
+
.token.punctuation { color: var(--syntax-punctuation); }
|
|
129
131
|
|
|
130
132
|
/* Image tab styling */
|
|
131
133
|
.tab-button.image-tab {
|
|
132
|
-
color:
|
|
134
|
+
color: var(--accent-secondary);
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
.tab-button.image-tab.active {
|
|
136
|
-
color:
|
|
138
|
+
color: var(--accent-secondary);
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
/* Image viewer */
|
|
@@ -143,7 +145,7 @@
|
|
|
143
145
|
justify-content: center;
|
|
144
146
|
height: 100%;
|
|
145
147
|
padding: 16px;
|
|
146
|
-
background:
|
|
148
|
+
background: var(--image-viewer-bg);
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
.image-viewer img {
|
|
@@ -151,7 +153,7 @@
|
|
|
151
153
|
max-height: 100%;
|
|
152
154
|
object-fit: contain;
|
|
153
155
|
border-radius: 4px;
|
|
154
|
-
box-shadow:
|
|
156
|
+
box-shadow: var(--shadow-sm);
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
/* ===== Responsive adjustments ===== */
|