figrecipe 0.7.4__py3-none-any.whl → 0.9.0__py3-none-any.whl

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.
Files changed (143) hide show
  1. figrecipe/__init__.py +74 -76
  2. figrecipe/__main__.py +12 -0
  3. figrecipe/_api/_panel.py +67 -0
  4. figrecipe/_api/_save.py +100 -4
  5. figrecipe/_cli/__init__.py +7 -0
  6. figrecipe/_cli/_compose.py +87 -0
  7. figrecipe/_cli/_convert.py +117 -0
  8. figrecipe/_cli/_crop.py +82 -0
  9. figrecipe/_cli/_edit.py +70 -0
  10. figrecipe/_cli/_extract.py +128 -0
  11. figrecipe/_cli/_fonts.py +47 -0
  12. figrecipe/_cli/_info.py +67 -0
  13. figrecipe/_cli/_main.py +58 -0
  14. figrecipe/_cli/_reproduce.py +79 -0
  15. figrecipe/_cli/_style.py +77 -0
  16. figrecipe/_cli/_validate.py +66 -0
  17. figrecipe/_cli/_version.py +50 -0
  18. figrecipe/_composition/__init__.py +32 -0
  19. figrecipe/_composition/_alignment.py +452 -0
  20. figrecipe/_composition/_compose.py +179 -0
  21. figrecipe/_composition/_import_axes.py +127 -0
  22. figrecipe/_composition/_visibility.py +125 -0
  23. figrecipe/_dev/__init__.py +2 -0
  24. figrecipe/_dev/browser/__init__.py +69 -0
  25. figrecipe/_dev/browser/_audio.py +240 -0
  26. figrecipe/_dev/browser/_caption.py +356 -0
  27. figrecipe/_dev/browser/_click_effect.py +146 -0
  28. figrecipe/_dev/browser/_cursor.py +196 -0
  29. figrecipe/_dev/browser/_highlight.py +105 -0
  30. figrecipe/_dev/browser/_narration.py +237 -0
  31. figrecipe/_dev/browser/_recorder.py +446 -0
  32. figrecipe/_dev/browser/_utils.py +178 -0
  33. figrecipe/_dev/browser/_video_trim/__init__.py +152 -0
  34. figrecipe/_dev/browser/_video_trim/_detection.py +223 -0
  35. figrecipe/_dev/browser/_video_trim/_markers.py +140 -0
  36. figrecipe/_editor/__init__.py +36 -36
  37. figrecipe/_editor/_bbox/_extract.py +155 -9
  38. figrecipe/_editor/_bbox/_extract_text.py +124 -0
  39. figrecipe/_editor/_call_overrides.py +183 -0
  40. figrecipe/_editor/_datatable_plot_handlers.py +249 -0
  41. figrecipe/_editor/_figure_layout.py +211 -0
  42. figrecipe/_editor/_flask_app.py +157 -16
  43. figrecipe/_editor/_helpers.py +17 -8
  44. figrecipe/_editor/_hitmap/_detect.py +89 -32
  45. figrecipe/_editor/_hitmap_main.py +4 -4
  46. figrecipe/_editor/_overrides.py +4 -1
  47. figrecipe/_editor/_plot_types_registry.py +190 -0
  48. figrecipe/_editor/_render_overrides.py +38 -11
  49. figrecipe/_editor/_renderer.py +46 -1
  50. figrecipe/_editor/_routes_annotation.py +114 -0
  51. figrecipe/_editor/_routes_axis.py +35 -6
  52. figrecipe/_editor/_routes_captions.py +130 -0
  53. figrecipe/_editor/_routes_composition.py +270 -0
  54. figrecipe/_editor/_routes_core.py +15 -173
  55. figrecipe/_editor/_routes_datatable.py +364 -0
  56. figrecipe/_editor/_routes_element.py +37 -19
  57. figrecipe/_editor/_routes_files.py +443 -0
  58. figrecipe/_editor/_routes_image.py +200 -0
  59. figrecipe/_editor/_routes_snapshot.py +94 -0
  60. figrecipe/_editor/_routes_style.py +28 -8
  61. figrecipe/_editor/_templates/__init__.py +40 -2
  62. figrecipe/_editor/_templates/_html.py +97 -103
  63. figrecipe/_editor/_templates/_html_components/__init__.py +13 -0
  64. figrecipe/_editor/_templates/_html_components/_composition_toolbar.py +79 -0
  65. figrecipe/_editor/_templates/_html_components/_file_browser.py +41 -0
  66. figrecipe/_editor/_templates/_html_datatable.py +92 -0
  67. figrecipe/_editor/_templates/_scripts/__init__.py +58 -0
  68. figrecipe/_editor/_templates/_scripts/_accordion.py +328 -0
  69. figrecipe/_editor/_templates/_scripts/_annotation_drag.py +504 -0
  70. figrecipe/_editor/_templates/_scripts/_api.py +1 -1
  71. figrecipe/_editor/_templates/_scripts/_canvas_context_menu.py +182 -0
  72. figrecipe/_editor/_templates/_scripts/_captions.py +231 -0
  73. figrecipe/_editor/_templates/_scripts/_composition.py +283 -0
  74. figrecipe/_editor/_templates/_scripts/_core.py +94 -37
  75. figrecipe/_editor/_templates/_scripts/_datatable/__init__.py +59 -0
  76. figrecipe/_editor/_templates/_scripts/_datatable/_cell_edit.py +97 -0
  77. figrecipe/_editor/_templates/_scripts/_datatable/_clipboard.py +164 -0
  78. figrecipe/_editor/_templates/_scripts/_datatable/_context_menu.py +221 -0
  79. figrecipe/_editor/_templates/_scripts/_datatable/_core.py +150 -0
  80. figrecipe/_editor/_templates/_scripts/_datatable/_editable.py +511 -0
  81. figrecipe/_editor/_templates/_scripts/_datatable/_import.py +161 -0
  82. figrecipe/_editor/_templates/_scripts/_datatable/_plot.py +261 -0
  83. figrecipe/_editor/_templates/_scripts/_datatable/_selection.py +438 -0
  84. figrecipe/_editor/_templates/_scripts/_datatable/_table.py +256 -0
  85. figrecipe/_editor/_templates/_scripts/_datatable/_tabs.py +354 -0
  86. figrecipe/_editor/_templates/_scripts/_element_editor.py +17 -2
  87. figrecipe/_editor/_templates/_scripts/_files.py +274 -40
  88. figrecipe/_editor/_templates/_scripts/_files_context_menu.py +240 -0
  89. figrecipe/_editor/_templates/_scripts/_hitmap.py +87 -84
  90. figrecipe/_editor/_templates/_scripts/_image_drop.py +428 -0
  91. figrecipe/_editor/_templates/_scripts/_legend_drag.py +5 -0
  92. figrecipe/_editor/_templates/_scripts/_multi_select.py +198 -0
  93. figrecipe/_editor/_templates/_scripts/_panel_drag.py +219 -48
  94. figrecipe/_editor/_templates/_scripts/_panel_drag_snapshot.py +33 -0
  95. figrecipe/_editor/_templates/_scripts/_panel_position.py +238 -54
  96. figrecipe/_editor/_templates/_scripts/_panel_resize.py +230 -0
  97. figrecipe/_editor/_templates/_scripts/_panel_snap.py +307 -0
  98. figrecipe/_editor/_templates/_scripts/_region_select.py +255 -0
  99. figrecipe/_editor/_templates/_scripts/_selection.py +8 -1
  100. figrecipe/_editor/_templates/_scripts/_sync.py +242 -0
  101. figrecipe/_editor/_templates/_scripts/_undo_redo.py +348 -0
  102. figrecipe/_editor/_templates/_scripts/_zoom.py +52 -19
  103. figrecipe/_editor/_templates/_styles/__init__.py +9 -0
  104. figrecipe/_editor/_templates/_styles/_base.py +47 -0
  105. figrecipe/_editor/_templates/_styles/_buttons.py +127 -6
  106. figrecipe/_editor/_templates/_styles/_composition.py +87 -0
  107. figrecipe/_editor/_templates/_styles/_controls.py +168 -3
  108. figrecipe/_editor/_templates/_styles/_datatable/__init__.py +40 -0
  109. figrecipe/_editor/_templates/_styles/_datatable/_editable.py +203 -0
  110. figrecipe/_editor/_templates/_styles/_datatable/_panel.py +268 -0
  111. figrecipe/_editor/_templates/_styles/_datatable/_table.py +479 -0
  112. figrecipe/_editor/_templates/_styles/_datatable/_toolbar.py +384 -0
  113. figrecipe/_editor/_templates/_styles/_datatable/_vars.py +123 -0
  114. figrecipe/_editor/_templates/_styles/_dynamic_props.py +5 -5
  115. figrecipe/_editor/_templates/_styles/_file_browser.py +466 -0
  116. figrecipe/_editor/_templates/_styles/_forms.py +98 -0
  117. figrecipe/_editor/_templates/_styles/_hitmap.py +7 -0
  118. figrecipe/_editor/_templates/_styles/_modals.py +29 -0
  119. figrecipe/_editor/_templates/_styles/_overlays.py +5 -5
  120. figrecipe/_editor/_templates/_styles/_preview.py +213 -8
  121. figrecipe/_editor/_templates/_styles/_spinner.py +117 -0
  122. figrecipe/_editor/static/audio/click.mp3 +0 -0
  123. figrecipe/_editor/static/click.mp3 +0 -0
  124. figrecipe/_editor/static/icons/favicon.ico +0 -0
  125. figrecipe/_integrations/__init__.py +17 -0
  126. figrecipe/_integrations/_scitex_stats.py +298 -0
  127. figrecipe/_params/_DECORATION_METHODS.py +2 -0
  128. figrecipe/_recorder.py +28 -3
  129. figrecipe/_reproducer/_core.py +60 -49
  130. figrecipe/_utils/__init__.py +3 -0
  131. figrecipe/_utils/_bundle.py +205 -0
  132. figrecipe/_wrappers/_axes.py +150 -2
  133. figrecipe/_wrappers/_caption_generator.py +218 -0
  134. figrecipe/_wrappers/_figure.py +26 -1
  135. figrecipe/_wrappers/_stat_annotation.py +274 -0
  136. figrecipe/styles/_style_applier.py +10 -2
  137. figrecipe/styles/presets/SCITEX.yaml +11 -4
  138. {figrecipe-0.7.4.dist-info → figrecipe-0.9.0.dist-info}/METADATA +144 -146
  139. figrecipe-0.9.0.dist-info/RECORD +277 -0
  140. figrecipe-0.9.0.dist-info/entry_points.txt +2 -0
  141. figrecipe-0.7.4.dist-info/RECORD +0 -188
  142. {figrecipe-0.7.4.dist-info → figrecipe-0.9.0.dist-info}/WHEEL +0 -0
  143. {figrecipe-0.7.4.dist-info → figrecipe-0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -22,7 +22,9 @@ from ._base import STYLES_BASE
22
22
  from ._buttons import STYLES_BUTTONS
23
23
  from ._color_input import STYLES_COLOR_INPUT
24
24
  from ._controls import STYLES_CONTROLS
25
+ from ._datatable import STYLES_DATATABLE
25
26
  from ._dynamic_props import STYLES_DYNAMIC_PROPS
27
+ from ._file_browser import STYLES_FILE_BROWSER
26
28
  from ._forms import STYLES_FORMS
27
29
  from ._hitmap import STYLES_HITMAP
28
30
  from ._inspector import STYLES_INSPECTOR
@@ -31,10 +33,12 @@ from ._modals import STYLES_MODALS
31
33
  from ._overlays import STYLES_OVERLAYS
32
34
  from ._preview import STYLES_PREVIEW
33
35
  from ._selection import STYLES_SELECTION
36
+ from ._spinner import STYLES_SPINNER
34
37
 
35
38
  # Combined STYLES constant for backward compatibility
36
39
  STYLES = (
37
40
  STYLES_BASE
41
+ + STYLES_FILE_BROWSER
38
42
  + STYLES_PREVIEW
39
43
  + STYLES_HITMAP
40
44
  + STYLES_SELECTION
@@ -47,11 +51,14 @@ STYLES = (
47
51
  + STYLES_OVERLAYS
48
52
  + STYLES_MODALS
49
53
  + STYLES_INSPECTOR
54
+ + STYLES_SPINNER
55
+ + STYLES_DATATABLE
50
56
  )
51
57
 
52
58
  __all__ = [
53
59
  "STYLES",
54
60
  "STYLES_BASE",
61
+ "STYLES_FILE_BROWSER",
55
62
  "STYLES_PREVIEW",
56
63
  "STYLES_HITMAP",
57
64
  "STYLES_SELECTION",
@@ -64,6 +71,8 @@ __all__ = [
64
71
  "STYLES_OVERLAYS",
65
72
  "STYLES_MODALS",
66
73
  "STYLES_INSPECTOR",
74
+ "STYLES_SPINNER",
75
+ "STYLES_DATATABLE",
67
76
  ]
68
77
 
69
78
  # EOF
@@ -22,6 +22,18 @@ STYLES_BASE = """
22
22
  --success-color: #10b981;
23
23
  --error-color: #ef4444;
24
24
  --selection-color: rgba(37, 99, 235, 0.3);
25
+ /* Solid selection colors for tables (opaque, theme-aware) */
26
+ --cell-selected-bg: #dbeafe;
27
+ --cell-hover-bg: #f0f4f8;
28
+ --header-bg: #e8e8e8;
29
+ --header-input-bg: #f5f5f5;
30
+ --row-num-bg: #f0f0f0;
31
+ /* Variable-linked column colors (light mode) */
32
+ --var-linked-bg: #c7d9f0;
33
+ --var-linked-cell-bg: #e8f0fa;
34
+ /* Consistent panel header styling */
35
+ --panel-header-height: 42px;
36
+ --panel-header-bg: var(--bg-tertiary);
25
37
  }
26
38
 
27
39
  [data-theme="dark"] {
@@ -34,6 +46,15 @@ STYLES_BASE = """
34
46
  --accent-color: #3b82f6;
35
47
  --accent-hover: #60a5fa;
36
48
  --selection-color: rgba(59, 130, 246, 0.3);
49
+ /* Solid selection colors for tables (opaque, theme-aware) */
50
+ --cell-selected-bg: #1e3a5f;
51
+ --cell-hover-bg: #2a2a35;
52
+ --header-bg: #2a2a2a;
53
+ --header-input-bg: #333333;
54
+ --row-num-bg: #1e1e1e;
55
+ /* Variable-linked column colors (dark mode) */
56
+ --var-linked-bg: #2a4a6a;
57
+ --var-linked-cell-bg: #1a3045;
37
58
  }
38
59
 
39
60
  /* Reset and base */
@@ -57,6 +78,32 @@ body {
57
78
  display: flex;
58
79
  height: 100vh;
59
80
  }
81
+
82
+ /* Global scrollbar styling - thin and theme-responsive */
83
+ ::-webkit-scrollbar {
84
+ width: 6px;
85
+ height: 6px;
86
+ }
87
+
88
+ ::-webkit-scrollbar-track {
89
+ background: var(--bg-secondary);
90
+ border-radius: 3px;
91
+ }
92
+
93
+ ::-webkit-scrollbar-thumb {
94
+ background: var(--border-color);
95
+ border-radius: 3px;
96
+ }
97
+
98
+ ::-webkit-scrollbar-thumb:hover {
99
+ background: var(--text-secondary);
100
+ }
101
+
102
+ /* Firefox scrollbar */
103
+ * {
104
+ scrollbar-width: thin;
105
+ scrollbar-color: var(--border-color) var(--bg-secondary);
106
+ }
60
107
  """
61
108
 
62
109
  __all__ = ["STYLES_BASE"]
@@ -180,18 +180,139 @@ button:hover {
180
180
  flex: 1;
181
181
  }
182
182
 
183
- /* Theme toggle */
184
- .theme-toggle {
183
+ /* Theme toggle button */
184
+ .btn-theme {
185
+ width: 36px;
186
+ height: 32px;
187
+ padding: 0;
188
+ font-size: 16px;
189
+ border: 1px solid var(--border-color);
190
+ background: var(--bg-secondary);
191
+ border-radius: 4px;
192
+ cursor: pointer;
193
+ transition: all 0.15s;
194
+ }
195
+
196
+ .btn-theme:hover {
197
+ background: var(--bg-tertiary);
198
+ border-color: var(--accent-color);
199
+ }
200
+
201
+ /* Icon buttons (Undo/Redo) */
202
+ .btn-icon {
203
+ width: 32px;
204
+ height: 32px;
205
+ padding: 0;
206
+ font-size: 16px;
207
+ border: 1px solid var(--border-color);
208
+ background: var(--bg-secondary);
209
+ border-radius: 4px;
210
+ cursor: pointer;
211
+ transition: all 0.15s;
212
+ }
213
+
214
+ .btn-icon:hover:not(:disabled) {
215
+ background: var(--bg-tertiary);
216
+ border-color: var(--accent-color);
217
+ }
218
+
219
+ .btn-icon:disabled {
220
+ opacity: 0.4;
221
+ cursor: not-allowed;
222
+ }
223
+
224
+ /* Context Menu Styles */
225
+ .canvas-context-menu,
226
+ .files-context-menu,
227
+ .datatable-context-menu {
228
+ position: fixed;
229
+ min-width: 180px;
230
+ background: var(--bg-primary);
231
+ border: 1px solid var(--border-color);
232
+ border-radius: 6px;
233
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
234
+ z-index: 10000;
235
+ padding: 4px 0;
236
+ font-size: 13px;
237
+ }
238
+
239
+ .context-menu-item {
185
240
  display: flex;
186
241
  align-items: center;
187
- gap: 8px;
242
+ justify-content: space-between;
243
+ padding: 8px 12px;
188
244
  cursor: pointer;
245
+ color: var(--text-primary);
246
+ transition: background 0.1s;
247
+ }
248
+
249
+ .context-menu-item:hover {
250
+ background: var(--bg-secondary);
251
+ }
252
+
253
+ .context-menu-item .shortcut {
254
+ font-size: 11px;
255
+ color: var(--text-tertiary);
256
+ margin-left: 16px;
257
+ }
258
+
259
+ .context-menu-divider {
260
+ height: 1px;
261
+ background: var(--border-color);
262
+ margin: 4px 8px;
263
+ }
264
+
265
+ .context-menu-danger {
266
+ color: #ef4444;
267
+ }
268
+
269
+ .context-menu-danger:hover {
270
+ background: rgba(239, 68, 68, 0.1);
271
+ }
272
+
273
+ /* Toast notification */
274
+ .toast-notification {
275
+ position: fixed;
276
+ bottom: 20px;
277
+ left: 50%;
278
+ transform: translateX(-50%);
279
+ padding: 10px 20px;
280
+ background: var(--bg-primary);
281
+ border: 1px solid var(--border-color);
282
+ border-radius: 6px;
283
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
284
+ z-index: 10001;
189
285
  font-size: 13px;
190
286
  }
191
287
 
192
- .theme-toggle input {
193
- width: 18px;
194
- height: 18px;
288
+ .toast-notification.success {
289
+ border-color: var(--success-color);
290
+ }
291
+
292
+ .toast-notification.error {
293
+ border-color: #ef4444;
294
+ color: #ef4444;
295
+ }
296
+
297
+ /* Inline checkbox */
298
+ .checkbox-inline {
299
+ display: flex;
300
+ align-items: center;
301
+ gap: 6px;
302
+ cursor: pointer;
303
+ font-size: 12px;
304
+ color: var(--text-secondary);
305
+ margin-left: auto;
306
+ }
307
+
308
+ .checkbox-inline input {
309
+ width: 14px;
310
+ height: 14px;
311
+ cursor: pointer;
312
+ }
313
+
314
+ .checkbox-inline span {
315
+ user-select: none;
195
316
  }
196
317
 
197
318
  /* Loading state */
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """CSS styles for composition toolbar."""
4
+
5
+ STYLES_COMPOSITION = """
6
+ /* Composition Toolbar */
7
+ .composition-toolbar {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: 4px;
11
+ padding: 6px 12px;
12
+ background: var(--bg-secondary);
13
+ border-bottom: 1px solid var(--border-color);
14
+ flex-wrap: wrap;
15
+ }
16
+
17
+ .composition-toolbar .toolbar-label {
18
+ font-size: 11px;
19
+ color: var(--text-secondary);
20
+ margin-right: 4px;
21
+ }
22
+
23
+ .composition-toolbar .toolbar-separator {
24
+ width: 1px;
25
+ height: 20px;
26
+ background: var(--border-color);
27
+ margin: 0 6px;
28
+ }
29
+
30
+ .composition-toolbar .toolbar-btn {
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ gap: 4px;
35
+ padding: 4px 6px;
36
+ background: var(--bg-tertiary);
37
+ border: 1px solid var(--border-color);
38
+ border-radius: 4px;
39
+ color: var(--text-primary);
40
+ cursor: pointer;
41
+ transition: all 0.15s ease;
42
+ min-width: 28px;
43
+ height: 28px;
44
+ }
45
+
46
+ .composition-toolbar .toolbar-btn:hover {
47
+ background: var(--bg-hover);
48
+ border-color: var(--accent-color);
49
+ }
50
+
51
+ .composition-toolbar .toolbar-btn:active {
52
+ transform: scale(0.95);
53
+ }
54
+
55
+ .composition-toolbar .toolbar-btn svg {
56
+ width: 16px;
57
+ height: 16px;
58
+ }
59
+
60
+ .composition-toolbar .toolbar-btn-primary {
61
+ background: var(--accent-color);
62
+ color: white;
63
+ border-color: var(--accent-color);
64
+ padding: 4px 10px;
65
+ }
66
+
67
+ .composition-toolbar .toolbar-btn-primary:hover {
68
+ background: var(--accent-hover);
69
+ border-color: var(--accent-hover);
70
+ }
71
+
72
+ .composition-toolbar .toolbar-btn span {
73
+ font-size: 11px;
74
+ font-weight: 500;
75
+ }
76
+
77
+ /* Dark mode adjustments */
78
+ [data-theme="dark"] .composition-toolbar {
79
+ background: var(--bg-secondary);
80
+ }
81
+
82
+ [data-theme="dark"] .composition-toolbar .toolbar-btn {
83
+ background: var(--bg-tertiary);
84
+ }
85
+ """
86
+
87
+ __all__ = ["STYLES_COMPOSITION"]
@@ -13,35 +13,144 @@ STYLES_CONTROLS = """
13
13
  /* Controls Panel */
14
14
  .controls-panel {
15
15
  width: 350px;
16
+ min-width: 280px;
17
+ max-width: 500px;
16
18
  display: flex;
17
19
  flex-direction: column;
18
20
  background: var(--bg-primary);
19
21
  overflow: hidden;
22
+ position: relative;
23
+ border-left: 1px solid var(--border-color);
24
+ transition: width 0.2s ease-out, min-width 0.2s ease-out;
25
+ order: 20; /* Always stay at far right */
26
+ }
27
+
28
+ .controls-panel.collapsed {
29
+ width: 42px;
30
+ min-width: 42px;
31
+ }
32
+
33
+ .controls-panel.collapsed .controls-sections,
34
+ .controls-panel.collapsed .style-info,
35
+ .controls-panel.collapsed .override-status,
36
+ .controls-panel.collapsed #theme-modal,
37
+ .controls-panel.collapsed #shortcuts-modal,
38
+ .controls-panel.collapsed .properties-resize {
39
+ display: none;
40
+ }
41
+
42
+ .controls-panel.collapsed .controls-header {
43
+ flex-direction: column;
44
+ padding: 10px 6px;
45
+ gap: 8px;
46
+ }
47
+
48
+ .controls-panel.collapsed .controls-header .header-title {
49
+ justify-content: center;
50
+ }
51
+
52
+ .controls-panel.collapsed .controls-header h2,
53
+ .controls-panel.collapsed .controls-header span {
54
+ display: none;
55
+ }
56
+
57
+ .controls-panel.collapsed .controls-actions {
58
+ flex-direction: column;
59
+ gap: 4px;
60
+ width: 100%;
61
+ }
62
+
63
+ .controls-panel.collapsed .controls-actions {
64
+ display: none;
65
+ }
66
+
67
+ /* Flip collapse button when collapsed (now points left to expand) */
68
+ .controls-panel.collapsed .header-title .btn-collapse {
69
+ transform: rotate(180deg);
70
+ }
71
+
72
+ /* Properties resize handle */
73
+ .properties-resize {
74
+ width: 4px;
75
+ cursor: col-resize;
76
+ background: transparent;
77
+ position: absolute;
78
+ left: 0;
79
+ top: 0;
80
+ bottom: 0;
81
+ z-index: 10;
82
+ transition: background 0.2s;
83
+ }
84
+
85
+ .properties-resize:hover,
86
+ .properties-resize.resizing {
87
+ background: var(--accent-color);
20
88
  }
21
89
 
22
90
  .controls-header {
23
91
  display: flex;
24
92
  justify-content: space-between;
25
93
  align-items: center;
26
- padding: 12px 16px;
27
- background: var(--bg-secondary);
94
+ padding: 0 12px;
95
+ height: var(--panel-header-height);
96
+ min-height: var(--panel-header-height);
97
+ background: var(--panel-header-bg);
28
98
  border-bottom: 1px solid var(--border-color);
29
99
  }
30
100
 
101
+ .controls-header .header-title {
102
+ display: flex;
103
+ align-items: center;
104
+ gap: 8px;
105
+ }
106
+
107
+ .controls-header .header-title .btn-collapse {
108
+ width: 28px;
109
+ height: 28px;
110
+ padding: 0;
111
+ border: none;
112
+ background: transparent;
113
+ color: var(--text-secondary);
114
+ cursor: pointer;
115
+ font-size: 14px;
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ border-radius: 4px;
120
+ transition: all 0.2s;
121
+ }
122
+
123
+ .controls-header .header-title .btn-collapse:hover {
124
+ background: var(--bg-tertiary);
125
+ color: var(--text-primary);
126
+ }
127
+
31
128
  .controls-header h2 {
32
129
  font-size: 16px;
33
130
  font-weight: 600;
131
+ margin: 0;
132
+ }
133
+
134
+ /* Panel label matching FILES, DATA, CANVAS style */
135
+ .controls-header span {
136
+ font-size: 11px;
137
+ font-weight: 600;
138
+ margin: 0;
139
+ text-transform: uppercase;
140
+ letter-spacing: 0.5px;
141
+ color: var(--text-secondary);
34
142
  }
35
143
 
36
144
  .controls-actions {
37
145
  display: flex;
38
146
  gap: 8px;
147
+ align-items: center;
39
148
  }
40
149
 
41
150
  .controls-sections {
42
151
  flex: 1;
43
152
  overflow-y: auto;
44
- padding: 8px;
153
+ padding: 8px 12px 8px 8px; /* Extra right padding for scrollbar clearance */
45
154
  }
46
155
 
47
156
  /* Tab Navigation */
@@ -258,6 +367,62 @@ STYLES_CONTROLS = """
258
367
  padding: 12px 14px;
259
368
  background: var(--bg-primary);
260
369
  }
370
+
371
+ /* Panel Indicator */
372
+ .panel-indicator-row {
373
+ align-items: center;
374
+ }
375
+
376
+ .panel-indicator {
377
+ padding: 6px 12px;
378
+ font-size: 13px;
379
+ font-weight: 500;
380
+ color: var(--text-secondary);
381
+ background: var(--bg-secondary);
382
+ border-radius: 6px;
383
+ border: 1px solid var(--border-color);
384
+ display: inline-block;
385
+ }
386
+
387
+ .panel-indicator.panel-selected {
388
+ color: var(--accent-color);
389
+ background: rgba(37, 99, 235, 0.1);
390
+ border-color: var(--accent-color);
391
+ font-weight: 600;
392
+ }
393
+
394
+ [data-theme="dark"] .panel-indicator.panel-selected {
395
+ background: rgba(59, 130, 246, 0.15);
396
+ }
397
+
398
+ /* Override Status - subtle indicator */
399
+ .override-status {
400
+ display: flex;
401
+ align-items: center;
402
+ gap: 6px;
403
+ padding: 4px 12px;
404
+ font-size: 11px;
405
+ color: var(--text-tertiary);
406
+ border-bottom: 1px solid var(--border-color);
407
+ }
408
+
409
+ .override-indicator {
410
+ display: flex;
411
+ align-items: center;
412
+ gap: 4px;
413
+ }
414
+
415
+ .override-indicator::before {
416
+ content: '';
417
+ width: 6px;
418
+ height: 6px;
419
+ background: var(--accent-color);
420
+ border-radius: 50%;
421
+ }
422
+
423
+ .override-timestamp {
424
+ opacity: 0.6;
425
+ }
261
426
  """
262
427
 
263
428
  __all__ = ["STYLES_CONTROLS"]
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Datatable CSS styles - orchestrator.
4
+
5
+ Combines all datatable CSS modules:
6
+ - _panel.py: Panel layout, header, toggle
7
+ - _toolbar.py: Toolbar, import, hints
8
+ - _table.py: Spreadsheet table
9
+ - _vars.py: Variable assignment with color linking
10
+ - _editable.py: Editable table styles
11
+ """
12
+
13
+ from ._editable import CSS_DATATABLE_EDITABLE
14
+ from ._panel import CSS_DATATABLE_PANEL
15
+ from ._table import CSS_DATATABLE_TABLE
16
+ from ._toolbar import CSS_DATATABLE_TOOLBAR
17
+ from ._vars import CSS_DATATABLE_VARS
18
+
19
+
20
+ def get_styles_datatable() -> str:
21
+ """Generate combined datatable CSS."""
22
+ return (
23
+ CSS_DATATABLE_PANEL
24
+ + "\n"
25
+ + CSS_DATATABLE_TOOLBAR
26
+ + "\n"
27
+ + CSS_DATATABLE_TABLE
28
+ + "\n"
29
+ + CSS_DATATABLE_VARS
30
+ + "\n"
31
+ + CSS_DATATABLE_EDITABLE
32
+ )
33
+
34
+
35
+ # For backward compatibility
36
+ STYLES_DATATABLE = get_styles_datatable()
37
+
38
+ __all__ = ["STYLES_DATATABLE", "get_styles_datatable"]
39
+
40
+ # EOF