figrecipe 0.6.0__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 (269) hide show
  1. figrecipe/__init__.py +161 -1030
  2. figrecipe/__main__.py +12 -0
  3. figrecipe/_api/__init__.py +48 -0
  4. figrecipe/_api/_extract.py +108 -0
  5. figrecipe/_api/_notebook.py +61 -0
  6. figrecipe/_api/_panel.py +113 -0
  7. figrecipe/_api/_save.py +287 -0
  8. figrecipe/_api/_seaborn_proxy.py +34 -0
  9. figrecipe/_api/_style_manager.py +153 -0
  10. figrecipe/_api/_subplots.py +333 -0
  11. figrecipe/_api/_validate.py +82 -0
  12. figrecipe/_cli/__init__.py +7 -0
  13. figrecipe/_cli/_compose.py +87 -0
  14. figrecipe/_cli/_convert.py +117 -0
  15. figrecipe/_cli/_crop.py +82 -0
  16. figrecipe/_cli/_edit.py +70 -0
  17. figrecipe/_cli/_extract.py +128 -0
  18. figrecipe/_cli/_fonts.py +47 -0
  19. figrecipe/_cli/_info.py +67 -0
  20. figrecipe/_cli/_main.py +58 -0
  21. figrecipe/_cli/_reproduce.py +79 -0
  22. figrecipe/_cli/_style.py +77 -0
  23. figrecipe/_cli/_validate.py +66 -0
  24. figrecipe/_cli/_version.py +50 -0
  25. figrecipe/_composition/__init__.py +32 -0
  26. figrecipe/_composition/_alignment.py +452 -0
  27. figrecipe/_composition/_compose.py +179 -0
  28. figrecipe/_composition/_import_axes.py +127 -0
  29. figrecipe/_composition/_visibility.py +125 -0
  30. figrecipe/_dev/__init__.py +4 -93
  31. figrecipe/_dev/_plotters.py +76 -0
  32. figrecipe/_dev/_run_demos.py +56 -0
  33. figrecipe/_dev/browser/__init__.py +69 -0
  34. figrecipe/_dev/browser/_audio.py +240 -0
  35. figrecipe/_dev/browser/_caption.py +356 -0
  36. figrecipe/_dev/browser/_click_effect.py +146 -0
  37. figrecipe/_dev/browser/_cursor.py +196 -0
  38. figrecipe/_dev/browser/_highlight.py +105 -0
  39. figrecipe/_dev/browser/_narration.py +237 -0
  40. figrecipe/_dev/browser/_recorder.py +446 -0
  41. figrecipe/_dev/browser/_utils.py +178 -0
  42. figrecipe/_dev/browser/_video_trim/__init__.py +152 -0
  43. figrecipe/_dev/browser/_video_trim/_detection.py +223 -0
  44. figrecipe/_dev/browser/_video_trim/_markers.py +140 -0
  45. figrecipe/_dev/demo_plotters/__init__.py +35 -166
  46. figrecipe/_dev/demo_plotters/_categories.py +81 -0
  47. figrecipe/_dev/demo_plotters/_figure_creators.py +119 -0
  48. figrecipe/_dev/demo_plotters/_helpers.py +31 -0
  49. figrecipe/_dev/demo_plotters/_registry.py +50 -0
  50. figrecipe/_dev/demo_plotters/bar_categorical/__init__.py +4 -0
  51. figrecipe/_dev/demo_plotters/contour_surface/__init__.py +4 -0
  52. figrecipe/_dev/demo_plotters/distribution/__init__.py +4 -0
  53. figrecipe/_dev/demo_plotters/image_matrix/__init__.py +4 -0
  54. figrecipe/_dev/demo_plotters/line_curve/__init__.py +4 -0
  55. figrecipe/_dev/demo_plotters/{plot_plot.py → line_curve/plot_plot.py} +3 -2
  56. figrecipe/_dev/demo_plotters/scatter_points/__init__.py +4 -0
  57. figrecipe/_dev/demo_plotters/special/__init__.py +4 -0
  58. figrecipe/_dev/demo_plotters/{plot_pie.py → special/plot_pie.py} +5 -1
  59. figrecipe/_dev/demo_plotters/spectral_signal/__init__.py +4 -0
  60. figrecipe/_dev/demo_plotters/vector_flow/__init__.py +4 -0
  61. figrecipe/_editor/__init__.py +61 -13
  62. figrecipe/_editor/_bbox/__init__.py +43 -0
  63. figrecipe/_editor/_bbox/_collections.py +177 -0
  64. figrecipe/_editor/_bbox/_elements.py +159 -0
  65. figrecipe/_editor/_bbox/_extract.py +402 -0
  66. figrecipe/_editor/_bbox/_extract_axes.py +370 -0
  67. figrecipe/_editor/_bbox/_extract_text.py +466 -0
  68. figrecipe/_editor/_bbox/_lines.py +173 -0
  69. figrecipe/_editor/_bbox/_transforms.py +146 -0
  70. figrecipe/_editor/_call_overrides.py +183 -0
  71. figrecipe/_editor/_datatable_plot_handlers.py +249 -0
  72. figrecipe/_editor/_figure_layout.py +211 -0
  73. figrecipe/_editor/_flask_app.py +200 -1030
  74. figrecipe/_editor/_helpers.py +251 -0
  75. figrecipe/_editor/_hitmap/__init__.py +76 -0
  76. figrecipe/_editor/_hitmap/_artists/__init__.py +21 -0
  77. figrecipe/_editor/_hitmap/_artists/_collections.py +345 -0
  78. figrecipe/_editor/_hitmap/_artists/_images.py +68 -0
  79. figrecipe/_editor/_hitmap/_artists/_lines.py +107 -0
  80. figrecipe/_editor/_hitmap/_artists/_patches.py +163 -0
  81. figrecipe/_editor/_hitmap/_artists/_text.py +190 -0
  82. figrecipe/_editor/_hitmap/_colors.py +181 -0
  83. figrecipe/_editor/_hitmap/_detect.py +194 -0
  84. figrecipe/_editor/_hitmap/_restore.py +154 -0
  85. figrecipe/_editor/_hitmap_main.py +182 -0
  86. figrecipe/_editor/_overrides.py +4 -1
  87. figrecipe/_editor/_plot_types_registry.py +190 -0
  88. figrecipe/_editor/_preferences.py +135 -0
  89. figrecipe/_editor/_render_overrides.py +507 -0
  90. figrecipe/_editor/_renderer.py +81 -186
  91. figrecipe/_editor/_routes_annotation.py +114 -0
  92. figrecipe/_editor/_routes_axis.py +482 -0
  93. figrecipe/_editor/_routes_captions.py +130 -0
  94. figrecipe/_editor/_routes_composition.py +270 -0
  95. figrecipe/_editor/_routes_core.py +126 -0
  96. figrecipe/_editor/_routes_datatable.py +364 -0
  97. figrecipe/_editor/_routes_element.py +335 -0
  98. figrecipe/_editor/_routes_files.py +443 -0
  99. figrecipe/_editor/_routes_image.py +200 -0
  100. figrecipe/_editor/_routes_snapshot.py +94 -0
  101. figrecipe/_editor/_routes_style.py +243 -0
  102. figrecipe/_editor/_templates/__init__.py +116 -1
  103. figrecipe/_editor/_templates/_html.py +154 -64
  104. figrecipe/_editor/_templates/_html_components/__init__.py +13 -0
  105. figrecipe/_editor/_templates/_html_components/_composition_toolbar.py +79 -0
  106. figrecipe/_editor/_templates/_html_components/_file_browser.py +41 -0
  107. figrecipe/_editor/_templates/_html_datatable.py +92 -0
  108. figrecipe/_editor/_templates/_scripts/__init__.py +178 -0
  109. figrecipe/_editor/_templates/_scripts/_accordion.py +328 -0
  110. figrecipe/_editor/_templates/_scripts/_annotation_drag.py +504 -0
  111. figrecipe/_editor/_templates/_scripts/_api.py +228 -0
  112. figrecipe/_editor/_templates/_scripts/_canvas_context_menu.py +182 -0
  113. figrecipe/_editor/_templates/_scripts/_captions.py +231 -0
  114. figrecipe/_editor/_templates/_scripts/_colors.py +485 -0
  115. figrecipe/_editor/_templates/_scripts/_composition.py +283 -0
  116. figrecipe/_editor/_templates/_scripts/_core.py +493 -0
  117. figrecipe/_editor/_templates/_scripts/_datatable/__init__.py +59 -0
  118. figrecipe/_editor/_templates/_scripts/_datatable/_cell_edit.py +97 -0
  119. figrecipe/_editor/_templates/_scripts/_datatable/_clipboard.py +164 -0
  120. figrecipe/_editor/_templates/_scripts/_datatable/_context_menu.py +221 -0
  121. figrecipe/_editor/_templates/_scripts/_datatable/_core.py +150 -0
  122. figrecipe/_editor/_templates/_scripts/_datatable/_editable.py +511 -0
  123. figrecipe/_editor/_templates/_scripts/_datatable/_import.py +161 -0
  124. figrecipe/_editor/_templates/_scripts/_datatable/_plot.py +261 -0
  125. figrecipe/_editor/_templates/_scripts/_datatable/_selection.py +438 -0
  126. figrecipe/_editor/_templates/_scripts/_datatable/_table.py +256 -0
  127. figrecipe/_editor/_templates/_scripts/_datatable/_tabs.py +354 -0
  128. figrecipe/_editor/_templates/_scripts/_debug_snapshot.py +186 -0
  129. figrecipe/_editor/_templates/_scripts/_element_editor.py +325 -0
  130. figrecipe/_editor/_templates/_scripts/_files.py +429 -0
  131. figrecipe/_editor/_templates/_scripts/_files_context_menu.py +240 -0
  132. figrecipe/_editor/_templates/_scripts/_hitmap.py +512 -0
  133. figrecipe/_editor/_templates/_scripts/_image_drop.py +428 -0
  134. figrecipe/_editor/_templates/_scripts/_inspector.py +315 -0
  135. figrecipe/_editor/_templates/_scripts/_labels.py +464 -0
  136. figrecipe/_editor/_templates/_scripts/_legend_drag.py +270 -0
  137. figrecipe/_editor/_templates/_scripts/_modals.py +226 -0
  138. figrecipe/_editor/_templates/_scripts/_multi_select.py +198 -0
  139. figrecipe/_editor/_templates/_scripts/_overlays.py +292 -0
  140. figrecipe/_editor/_templates/_scripts/_panel_drag.py +505 -0
  141. figrecipe/_editor/_templates/_scripts/_panel_drag_snapshot.py +33 -0
  142. figrecipe/_editor/_templates/_scripts/_panel_position.py +463 -0
  143. figrecipe/_editor/_templates/_scripts/_panel_resize.py +230 -0
  144. figrecipe/_editor/_templates/_scripts/_panel_snap.py +307 -0
  145. figrecipe/_editor/_templates/_scripts/_region_select.py +255 -0
  146. figrecipe/_editor/_templates/_scripts/_selection.py +244 -0
  147. figrecipe/_editor/_templates/_scripts/_sync.py +242 -0
  148. figrecipe/_editor/_templates/_scripts/_tabs.py +89 -0
  149. figrecipe/_editor/_templates/_scripts/_undo_redo.py +348 -0
  150. figrecipe/_editor/_templates/_scripts/_view_mode.py +107 -0
  151. figrecipe/_editor/_templates/_scripts/_zoom.py +212 -0
  152. figrecipe/_editor/_templates/_styles/__init__.py +78 -0
  153. figrecipe/_editor/_templates/_styles/_base.py +111 -0
  154. figrecipe/_editor/_templates/_styles/_buttons.py +327 -0
  155. figrecipe/_editor/_templates/_styles/_color_input.py +123 -0
  156. figrecipe/_editor/_templates/_styles/_composition.py +87 -0
  157. figrecipe/_editor/_templates/_styles/_controls.py +430 -0
  158. figrecipe/_editor/_templates/_styles/_datatable/__init__.py +40 -0
  159. figrecipe/_editor/_templates/_styles/_datatable/_editable.py +203 -0
  160. figrecipe/_editor/_templates/_styles/_datatable/_panel.py +268 -0
  161. figrecipe/_editor/_templates/_styles/_datatable/_table.py +479 -0
  162. figrecipe/_editor/_templates/_styles/_datatable/_toolbar.py +384 -0
  163. figrecipe/_editor/_templates/_styles/_datatable/_vars.py +123 -0
  164. figrecipe/_editor/_templates/_styles/_dynamic_props.py +144 -0
  165. figrecipe/_editor/_templates/_styles/_file_browser.py +466 -0
  166. figrecipe/_editor/_templates/_styles/_forms.py +224 -0
  167. figrecipe/_editor/_templates/_styles/_hitmap.py +191 -0
  168. figrecipe/_editor/_templates/_styles/_inspector.py +90 -0
  169. figrecipe/_editor/_templates/_styles/_labels.py +118 -0
  170. figrecipe/_editor/_templates/_styles/_modals.py +127 -0
  171. figrecipe/_editor/_templates/_styles/_overlays.py +130 -0
  172. figrecipe/_editor/_templates/_styles/_preview.py +430 -0
  173. figrecipe/_editor/_templates/_styles/_selection.py +73 -0
  174. figrecipe/_editor/_templates/_styles/_spinner.py +117 -0
  175. figrecipe/_editor/static/audio/click.mp3 +0 -0
  176. figrecipe/_editor/static/click.mp3 +0 -0
  177. figrecipe/_editor/static/icons/favicon.ico +0 -0
  178. figrecipe/_integrations/__init__.py +17 -0
  179. figrecipe/_integrations/_scitex_stats.py +298 -0
  180. figrecipe/_params/_DECORATION_METHODS.py +8 -0
  181. figrecipe/_recorder.py +63 -109
  182. figrecipe/_recorder_utils.py +124 -0
  183. figrecipe/_reproducer/__init__.py +18 -0
  184. figrecipe/_reproducer/_core.py +509 -0
  185. figrecipe/_reproducer/_custom_plots.py +279 -0
  186. figrecipe/_reproducer/_seaborn.py +100 -0
  187. figrecipe/_reproducer/_violin.py +186 -0
  188. figrecipe/_signatures/_kwargs.py +273 -0
  189. figrecipe/_signatures/_loader.py +21 -423
  190. figrecipe/_signatures/_parsing.py +147 -0
  191. figrecipe/_utils/__init__.py +3 -0
  192. figrecipe/_utils/_bundle.py +205 -0
  193. figrecipe/_wrappers/_axes.py +252 -895
  194. figrecipe/_wrappers/_axes_helpers.py +136 -0
  195. figrecipe/_wrappers/_axes_plots.py +418 -0
  196. figrecipe/_wrappers/_axes_seaborn.py +157 -0
  197. figrecipe/_wrappers/_caption_generator.py +218 -0
  198. figrecipe/_wrappers/_figure.py +188 -1
  199. figrecipe/_wrappers/_panel_labels.py +127 -0
  200. figrecipe/_wrappers/_plot_helpers.py +143 -0
  201. figrecipe/_wrappers/_stat_annotation.py +274 -0
  202. figrecipe/_wrappers/_violin_helpers.py +180 -0
  203. figrecipe/styles/__init__.py +8 -6
  204. figrecipe/styles/_dotdict.py +72 -0
  205. figrecipe/styles/_finalize.py +134 -0
  206. figrecipe/styles/_fonts.py +77 -0
  207. figrecipe/styles/_kwargs_converter.py +178 -0
  208. figrecipe/styles/_plot_styles.py +209 -0
  209. figrecipe/styles/_style_applier.py +42 -480
  210. figrecipe/styles/_style_loader.py +16 -192
  211. figrecipe/styles/_themes.py +151 -0
  212. figrecipe/styles/presets/MATPLOTLIB.yaml +2 -1
  213. figrecipe/styles/presets/SCITEX.yaml +40 -28
  214. figrecipe-0.9.0.dist-info/METADATA +427 -0
  215. figrecipe-0.9.0.dist-info/RECORD +277 -0
  216. figrecipe-0.9.0.dist-info/entry_points.txt +2 -0
  217. figrecipe/_editor/_bbox.py +0 -978
  218. figrecipe/_editor/_hitmap.py +0 -937
  219. figrecipe/_editor/_templates/_scripts.py +0 -2778
  220. figrecipe/_editor/_templates/_styles.py +0 -1326
  221. figrecipe/_reproducer.py +0 -975
  222. figrecipe-0.6.0.dist-info/METADATA +0 -394
  223. figrecipe-0.6.0.dist-info/RECORD +0 -90
  224. /figrecipe/_dev/demo_plotters/{plot_bar.py → bar_categorical/plot_bar.py} +0 -0
  225. /figrecipe/_dev/demo_plotters/{plot_barh.py → bar_categorical/plot_barh.py} +0 -0
  226. /figrecipe/_dev/demo_plotters/{plot_contour.py → contour_surface/plot_contour.py} +0 -0
  227. /figrecipe/_dev/demo_plotters/{plot_contourf.py → contour_surface/plot_contourf.py} +0 -0
  228. /figrecipe/_dev/demo_plotters/{plot_tricontour.py → contour_surface/plot_tricontour.py} +0 -0
  229. /figrecipe/_dev/demo_plotters/{plot_tricontourf.py → contour_surface/plot_tricontourf.py} +0 -0
  230. /figrecipe/_dev/demo_plotters/{plot_tripcolor.py → contour_surface/plot_tripcolor.py} +0 -0
  231. /figrecipe/_dev/demo_plotters/{plot_triplot.py → contour_surface/plot_triplot.py} +0 -0
  232. /figrecipe/_dev/demo_plotters/{plot_boxplot.py → distribution/plot_boxplot.py} +0 -0
  233. /figrecipe/_dev/demo_plotters/{plot_ecdf.py → distribution/plot_ecdf.py} +0 -0
  234. /figrecipe/_dev/demo_plotters/{plot_hist.py → distribution/plot_hist.py} +0 -0
  235. /figrecipe/_dev/demo_plotters/{plot_hist2d.py → distribution/plot_hist2d.py} +0 -0
  236. /figrecipe/_dev/demo_plotters/{plot_violinplot.py → distribution/plot_violinplot.py} +0 -0
  237. /figrecipe/_dev/demo_plotters/{plot_hexbin.py → image_matrix/plot_hexbin.py} +0 -0
  238. /figrecipe/_dev/demo_plotters/{plot_imshow.py → image_matrix/plot_imshow.py} +0 -0
  239. /figrecipe/_dev/demo_plotters/{plot_matshow.py → image_matrix/plot_matshow.py} +0 -0
  240. /figrecipe/_dev/demo_plotters/{plot_pcolor.py → image_matrix/plot_pcolor.py} +0 -0
  241. /figrecipe/_dev/demo_plotters/{plot_pcolormesh.py → image_matrix/plot_pcolormesh.py} +0 -0
  242. /figrecipe/_dev/demo_plotters/{plot_spy.py → image_matrix/plot_spy.py} +0 -0
  243. /figrecipe/_dev/demo_plotters/{plot_errorbar.py → line_curve/plot_errorbar.py} +0 -0
  244. /figrecipe/_dev/demo_plotters/{plot_fill.py → line_curve/plot_fill.py} +0 -0
  245. /figrecipe/_dev/demo_plotters/{plot_fill_between.py → line_curve/plot_fill_between.py} +0 -0
  246. /figrecipe/_dev/demo_plotters/{plot_fill_betweenx.py → line_curve/plot_fill_betweenx.py} +0 -0
  247. /figrecipe/_dev/demo_plotters/{plot_stackplot.py → line_curve/plot_stackplot.py} +0 -0
  248. /figrecipe/_dev/demo_plotters/{plot_stairs.py → line_curve/plot_stairs.py} +0 -0
  249. /figrecipe/_dev/demo_plotters/{plot_step.py → line_curve/plot_step.py} +0 -0
  250. /figrecipe/_dev/demo_plotters/{plot_scatter.py → scatter_points/plot_scatter.py} +0 -0
  251. /figrecipe/_dev/demo_plotters/{plot_eventplot.py → special/plot_eventplot.py} +0 -0
  252. /figrecipe/_dev/demo_plotters/{plot_loglog.py → special/plot_loglog.py} +0 -0
  253. /figrecipe/_dev/demo_plotters/{plot_semilogx.py → special/plot_semilogx.py} +0 -0
  254. /figrecipe/_dev/demo_plotters/{plot_semilogy.py → special/plot_semilogy.py} +0 -0
  255. /figrecipe/_dev/demo_plotters/{plot_stem.py → special/plot_stem.py} +0 -0
  256. /figrecipe/_dev/demo_plotters/{plot_acorr.py → spectral_signal/plot_acorr.py} +0 -0
  257. /figrecipe/_dev/demo_plotters/{plot_angle_spectrum.py → spectral_signal/plot_angle_spectrum.py} +0 -0
  258. /figrecipe/_dev/demo_plotters/{plot_cohere.py → spectral_signal/plot_cohere.py} +0 -0
  259. /figrecipe/_dev/demo_plotters/{plot_csd.py → spectral_signal/plot_csd.py} +0 -0
  260. /figrecipe/_dev/demo_plotters/{plot_magnitude_spectrum.py → spectral_signal/plot_magnitude_spectrum.py} +0 -0
  261. /figrecipe/_dev/demo_plotters/{plot_phase_spectrum.py → spectral_signal/plot_phase_spectrum.py} +0 -0
  262. /figrecipe/_dev/demo_plotters/{plot_psd.py → spectral_signal/plot_psd.py} +0 -0
  263. /figrecipe/_dev/demo_plotters/{plot_specgram.py → spectral_signal/plot_specgram.py} +0 -0
  264. /figrecipe/_dev/demo_plotters/{plot_xcorr.py → spectral_signal/plot_xcorr.py} +0 -0
  265. /figrecipe/_dev/demo_plotters/{plot_barbs.py → vector_flow/plot_barbs.py} +0 -0
  266. /figrecipe/_dev/demo_plotters/{plot_quiver.py → vector_flow/plot_quiver.py} +0 -0
  267. /figrecipe/_dev/demo_plotters/{plot_streamplot.py → vector_flow/plot_streamplot.py} +0 -0
  268. {figrecipe-0.6.0.dist-info → figrecipe-0.9.0.dist-info}/WHEEL +0 -0
  269. {figrecipe-0.6.0.dist-info → figrecipe-0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,21 +6,28 @@ HTML template for figure editor.
6
6
 
7
7
  HTML_TEMPLATE = """
8
8
  <!DOCTYPE html>
9
- <html lang="en" data-theme="light">
9
+ <html lang="en" data-theme="DARK_MODE_THEME_PLACEHOLDER">
10
10
  <head>
11
11
  <meta charset="UTF-8">
12
12
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
- <title>figrecipe Editor</title>
13
+ <title>FigRecipe Editor</title>
14
+ <link rel="icon" type="image/x-icon" href="/static/icons/favicon.ico">
15
+ <link rel="icon" type="image/png" sizes="32x32" href="/static/icons/favicon-32x32.png">
16
+ <link rel="apple-touch-icon" sizes="192x192" href="/static/icons/scitex-icon.png">
17
+ <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
14
18
  <style>
15
19
  /* STYLES_PLACEHOLDER */
16
20
  </style>
17
21
  </head>
18
22
  <body>
23
+ <div class="spinner-overlay"><div class="spinner-container"><div class="spinner"></div><div class="spinner-text">Loading...</div></div></div>
19
24
  <div class="editor-container">
25
+ <!-- FILE_BROWSER_PLACEHOLDER -->
20
26
  <!-- Preview Panel -->
21
- <div class="preview-panel">
27
+ <div class="preview-panel" id="preview-panel">
22
28
  <div class="preview-header">
23
- <h2>Preview</h2>
29
+ <button id="btn-collapse-preview" class="btn-collapse" title="Collapse canvas">&#x276F;</button>
30
+ <span class="panel-label">CANVAS</span>
24
31
  <div class="preview-controls">
25
32
  <div class="download-dropdown">
26
33
  <button id="btn-download-main" class="btn-primary download-main" title="Download as PNG">Download PNG</button>
@@ -29,35 +36,58 @@ HTML_TEMPLATE = """
29
36
  <button id="btn-download-png-menu" class="download-option active" data-format="png">PNG</button>
30
37
  <button id="btn-download-svg-menu" class="download-option" data-format="svg">SVG</button>
31
38
  <button id="btn-download-pdf-menu" class="download-option" data-format="pdf">PDF</button>
39
+ <hr style="margin: 4px 0; border: none; border-top: 1px solid #ddd;">
40
+ <button id="btn-download-csv-menu" class="download-option" data-format="csv" title="Export plot data as CSV">CSV (Data)</button>
32
41
  </div>
33
42
  </div>
34
- <button id="btn-refresh" title="Refresh preview">Refresh</button>
35
- <button id="btn-show-hitmap" title="Toggle hitmap overlay for debugging" style="display: none;">Show Hit Regions</button>
36
- <label class="theme-toggle">
37
- <input type="checkbox" id="dark-mode-toggle">
38
- <span>Dark Mode</span>
39
- </label>
43
+ <button id="btn-refresh" title="Re-render figure (R)">Render</button>
44
+ <div class="zoom-controls">
45
+ <select id="zoom-select" title="Zoom level (+/- or scroll)">
46
+ <option value="25">25%</option>
47
+ <option value="50">50%</option>
48
+ <option value="75">75%</option>
49
+ <option value="100" selected>100%</option>
50
+ <option value="125">125%</option>
51
+ <option value="150">150%</option>
52
+ <option value="200">200%</option>
53
+ </select>
54
+ <button id="btn-zoom-fit" title="Fit to view (F)">Fit</button>
55
+ </div>
56
+ <button id="btn-ruler-grid" class="btn-ruler" title="Toggle rulers and grid (G)">Grid</button>
57
+ <button id="dark-mode-toggle" class="btn-theme" title="Toggle theme (D)">🌙</button>
58
+ <div class="toolbar-separator"></div>
59
+ <button id="btn-undo" class="btn-icon" title="Undo (Ctrl+Z)" disabled>↶</button>
60
+ <button id="btn-redo" class="btn-icon" title="Redo (Ctrl+Y)" disabled>↷</button>
61
+ <button id="btn-restore" class="btn-secondary" title="Revert all changes">Revert</button>
62
+ <button id="btn-save" class="btn-primary" title="Save (Ctrl+S)">Save</button>
63
+ <button id="btn-shortcuts" class="btn-icon btn-shortcuts" title="Keyboard shortcuts (?)">⌨</button>
40
64
  </div>
41
65
  </div>
42
- <div class="preview-wrapper">
43
- <img id="preview-image" src="data:image/png;base64,IMAGE_BASE64_PLACEHOLDER" alt="Figure preview">
44
- <svg id="hitregion-overlay" class="hitregion-overlay"></svg>
45
- <svg id="selection-overlay" class="selection-overlay"></svg>
46
- <canvas id="hitmap-canvas" style="display: none;"></canvas>
66
+ <div class="preview-wrapper" id="preview-wrapper">
67
+ <div class="zoom-container" id="zoom-container">
68
+ <img id="preview-image" src="data:image/png;base64,IMAGE_BASE64_PLACEHOLDER" alt="Figure preview">
69
+ <svg id="hitregion-overlay" class="hitregion-overlay"></svg>
70
+ <svg id="selection-overlay" class="selection-overlay"></svg>
71
+ <svg id="ruler-overlay" class="ruler-overlay"></svg>
72
+ <svg id="grid-overlay" class="grid-overlay"></svg>
73
+ <svg id="column-overlay" class="column-overlay"></svg>
74
+ <canvas id="hitmap-canvas" style="display: none;"></canvas>
75
+ </div>
76
+ <!-- Welcome overlay -->
77
+ <div id="welcome-overlay" class="welcome-overlay" style="display: WELCOME_DISPLAY_PLACEHOLDER;"><div class="welcome-content"><h2>Getting Started</h2><div class="welcome-steps"><div class="welcome-step"><span class="step-number">1</span><span class="step-text">Drop CSV/TSV in <strong>Data</strong></span></div><div class="welcome-step"><span class="step-number">2</span><span class="step-text">Click <strong>Plot</strong></span></div><div class="welcome-step"><span class="step-number">3</span><span class="step-text">Adjust in <strong>Properties</strong></span></div></div><p class="welcome-hint">Or load .yaml from Files</p></div></div>
47
78
  </div>
48
- <div class="selected-element-info" id="selected-info">
49
- Click on an element to select it
79
+ <!-- Caption Pane (below canvas) -->
80
+ <div class="caption-pane" id="caption-pane">
81
+ <span id="canvas-caption-text"><b>Fig. 1.</b></span>
50
82
  </div>
51
83
  </div>
52
84
 
53
85
  <!-- Controls Panel -->
54
- <div class="controls-panel">
86
+ <div class="controls-panel" id="controls-panel">
55
87
  <div class="controls-header">
56
- <h2>Properties</h2>
57
- <div class="controls-actions">
58
- <button id="btn-restore" class="btn-warning" title="Restore to original programmatic style">Restore</button>
59
- <button id="btn-reset" class="btn-secondary" title="Reset to last saved">Reset</button>
60
- <button id="btn-save" class="btn-primary">Save</button>
88
+ <div class="header-title">
89
+ <button id="btn-collapse-properties" class="btn-collapse" title="Collapse panel">&#x276F;</button>
90
+ <span>PROPERTIES</span>
61
91
  </div>
62
92
  </div>
63
93
  <div class="style-info">
@@ -66,11 +96,10 @@ HTML_TEMPLATE = """
66
96
  <option value="SCITEX">SCITEX</option>
67
97
  <option value="MATPLOTLIB">MATPLOTLIB</option>
68
98
  </select>
69
- <div class="theme-actions">
70
- <button id="btn-view-theme" class="btn-small" title="View theme contents">View</button>
71
- <button id="btn-download-theme" class="btn-small" title="Download theme as YAML">Download</button>
72
- <button id="btn-copy-theme" class="btn-small" title="Copy theme to clipboard">Copy</button>
73
- </div>
99
+ <label class="checkbox-inline" title="Transparent background">
100
+ <input type="checkbox" id="output_transparent" checked>
101
+ <span>Transparent</span>
102
+ </label>
74
103
  </div>
75
104
  <!-- Theme Modal -->
76
105
  <div id="theme-modal" class="modal" style="display: none;">
@@ -86,8 +115,30 @@ HTML_TEMPLATE = """
86
115
  </div>
87
116
  </div>
88
117
  </div>
118
+ <!-- Shortcuts Modal -->
119
+ <div id="shortcuts-modal" class="modal" style="display: none;">
120
+ <div class="modal-content shortcuts-modal-content">
121
+ <div class="modal-header">
122
+ <h3>Keyboard Shortcuts</h3>
123
+ <button id="shortcuts-modal-close" class="modal-close">&times;</button>
124
+ </div>
125
+ <div class="shortcuts-content">
126
+ <div class="shortcut-section"><h4>General</h4>
127
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>Z</kbd>/<kbd>Shift+Z</kbd></span><span class="shortcut-desc">Undo/Redo</span></div>
128
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>S</kbd>/<kbd>Shift+S</kbd></span><span class="shortcut-desc">Save/Download</span></div>
129
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>F5</kbd>/<kbd>Esc</kbd>/<kbd>R</kbd></span><span class="shortcut-desc">Refresh/Clear/Reset</span></div></div>
130
+ <div class="shortcut-section"><h4>Navigation</h4>
131
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>1</kbd>/<kbd>2</kbd>/<kbd>3</kbd></span><span class="shortcut-desc">Figure/Axis/Element tab</span></div></div>
132
+ <div class="shortcut-section"><h4>View</h4>
133
+ <div class="shortcut-row"><span class="shortcut-keys"><kbd>G</kbd>/<kbd>+</kbd>/<kbd>-</kbd>/<kbd>0</kbd>/<kbd>F</kbd></span><span class="shortcut-desc">Grid/Zoom/Reset/Fit</span></div></div>
134
+ <div class="shortcut-section"><h4>Panel</h4>
135
+ <div class="shortcut-row"><span class="shortcut-keys">Drag/<kbd>Alt</kbd>+Drag</span><span class="shortcut-desc">Move (snap/free)</span></div></div>
136
+ DEBUG_SHORTCUTS_PLACEHOLDER
137
+ </div>
138
+ </div>
139
+ </div>
89
140
  <div id="override-status" class="override-status" style="display: none;">
90
- <span class="override-indicator">Manual overrides active</span>
141
+ <span class="override-indicator">Modified</span>
91
142
  <span id="override-timestamp" class="override-timestamp"></span>
92
143
  </div>
93
144
 
@@ -102,7 +153,7 @@ HTML_TEMPLATE = """
102
153
  <!-- FIGURE TAB -->
103
154
  <div id="tab-content-figure" class="tab-content active">
104
155
  <!-- Dimensions Section -->
105
- <details class="section" open>
156
+ <details class="section">
106
157
  <summary>Dimensions</summary>
107
158
  <div class="section-content">
108
159
  <div class="subsection">
@@ -110,19 +161,19 @@ HTML_TEMPLATE = """
110
161
  <div class="form-grid">
111
162
  <div class="form-row">
112
163
  <label>Left</label>
113
- <input type="number" id="margins_left_mm" step="1" min="0" max="50" placeholder="12">
164
+ <input type="number" id="margins_left_mm" step="1" min="0" max="50" placeholder="1">
114
165
  </div>
115
166
  <div class="form-row">
116
167
  <label>Right</label>
117
- <input type="number" id="margins_right_mm" step="1" min="0" max="50" placeholder="3">
168
+ <input type="number" id="margins_right_mm" step="1" min="0" max="50" placeholder="1">
118
169
  </div>
119
170
  <div class="form-row">
120
171
  <label>Bottom</label>
121
- <input type="number" id="margins_bottom_mm" step="1" min="0" max="50" placeholder="10">
172
+ <input type="number" id="margins_bottom_mm" step="1" min="0" max="50" placeholder="1">
122
173
  </div>
123
174
  <div class="form-row">
124
175
  <label>Top</label>
125
- <input type="number" id="margins_top_mm" step="1" min="0" max="50" placeholder="6">
176
+ <input type="number" id="margins_top_mm" step="1" min="0" max="50" placeholder="1">
126
177
  </div>
127
178
  </div>
128
179
  </div>
@@ -144,13 +195,19 @@ HTML_TEMPLATE = """
144
195
  <details class="section">
145
196
  <summary>Output</summary>
146
197
  <div class="section-content">
147
- <div class="form-row">
148
- <label>DPI</label>
149
- <input type="number" id="output_dpi" step="50" min="72" max="600">
150
- </div>
151
- <div class="form-row">
152
- <label>Transparent</label>
153
- <input type="checkbox" id="output_transparent">
198
+ <div class="form-row"><label>DPI</label><input type="number" id="output_dpi" step="50" min="72" max="600"></div>
199
+ <div class="form-row"><label>Transparent</label><input type="checkbox" id="output_transparent"></div>
200
+ </div>
201
+ </details>
202
+ <!-- Figure Caption (Scientific) -->
203
+ <details class="section">
204
+ <summary>Figure Caption</summary>
205
+ <div class="section-content">
206
+ <div class="form-row"><label>Fig. #</label><input type="number" id="caption_figure_number" min="1" max="99" step="1" value="1" style="width:60px"></div>
207
+ <div class="form-row caption-row"><label>Caption</label><textarea id="caption_figure_text" class="caption-textarea" rows="2" placeholder="e.g., Comparison of sin and cos functions"></textarea></div>
208
+ <div class="composed-caption-preview" id="composed-caption-container">
209
+ <div class="composed-caption-label">Composed Caption:</div>
210
+ <div class="composed-caption-text" id="composed-caption-text"><b>Fig. 1.</b></div>
154
211
  </div>
155
212
  </div>
156
213
  </details>
@@ -160,8 +217,40 @@ HTML_TEMPLATE = """
160
217
  <div id="tab-content-axis" class="tab-content">
161
218
  <div class="tab-hint" id="axis-tab-hint">Select an axis element (title, label, ticks, legend) to edit</div>
162
219
 
220
+ <!-- Panel Position Section -->
221
+ <details class="section">
222
+ <summary>Panel Position</summary>
223
+ <div class="section-content">
224
+ <div class="form-row panel-indicator-row">
225
+ <label>Panel</label>
226
+ <span id="current_panel_indicator" class="panel-indicator">Select an element</span>
227
+ </div>
228
+ <div class="position-grid">
229
+ <div class="form-row">
230
+ <label>Left (mm)</label>
231
+ <input type="number" id="panel_left" step="1" min="0" placeholder="20">
232
+ </div>
233
+ <div class="form-row">
234
+ <label>Top (mm)</label>
235
+ <input type="number" id="panel_top" step="1" min="0" placeholder="15">
236
+ </div>
237
+ <div class="form-row">
238
+ <label>Width (mm)</label>
239
+ <input type="number" id="panel_width" step="1" min="0" placeholder="120">
240
+ </div>
241
+ <div class="form-row">
242
+ <label>Height (mm)</label>
243
+ <input type="number" id="panel_height" step="1" min="0" placeholder="90">
244
+ </div>
245
+ </div>
246
+ <div class="form-row" style="margin-top: 8px;">
247
+ <button id="apply_panel_position" class="btn-small">Apply Position</button>
248
+ </div>
249
+ </div>
250
+ </details>
251
+
163
252
  <!-- Axes Size Section -->
164
- <details class="section" open>
253
+ <details class="section">
165
254
  <summary>Axes Size</summary>
166
255
  <div class="section-content">
167
256
  <div class="form-row">
@@ -176,24 +265,27 @@ HTML_TEMPLATE = """
176
265
  </details>
177
266
 
178
267
  <!-- Labels Section -->
179
- <details class="section" open>
268
+ <details class="section">
180
269
  <summary>Labels</summary>
181
270
  <div class="section-content">
182
- <div class="form-row">
183
- <label>Title</label>
184
- <input type="text" id="label_title" class="label-input" placeholder="(no title)">
185
- </div>
186
- <div class="form-row">
187
- <label>X Label</label>
188
- <input type="text" id="label_xlabel" class="label-input" placeholder="(no xlabel)">
189
- </div>
190
- <div class="form-row">
191
- <label>Y Label</label>
192
- <input type="text" id="label_ylabel" class="label-input" placeholder="(no ylabel)">
271
+ <div class="form-row"><label>Title</label><input type="text" id="label_title" class="label-input" placeholder="(no title)"></div>
272
+ <div class="form-row"><label>X Label</label><input type="text" id="label_xlabel" class="label-input" placeholder="(no xlabel)"></div>
273
+ <div class="form-row"><label>Y Label</label><input type="text" id="label_ylabel" class="label-input" placeholder="(no ylabel)"></div>
274
+ <div class="form-row"><label>Suptitle</label><input type="text" id="label_suptitle" class="label-input" placeholder="(no suptitle)"></div>
275
+ </div>
276
+ </details>
277
+
278
+ <!-- Caption Section -->
279
+ <details class="section">
280
+ <summary>Caption</summary>
281
+ <div class="section-content">
282
+ <div class="form-row caption-row">
283
+ <label>Panel</label>
284
+ <textarea id="caption_panel_text" class="caption-textarea" rows="2" placeholder="e.g., Line plot showing sinusoidal functions"></textarea>
193
285
  </div>
194
- <div class="form-row">
195
- <label>Suptitle</label>
196
- <input type="text" id="label_suptitle" class="label-input" placeholder="(no suptitle)">
286
+ <div class="form-row caption-row">
287
+ <label>Figure</label>
288
+ <textarea id="caption_figure_text" class="caption-textarea" rows="3" placeholder="e.g., Overview of visualization methods..."></textarea>
197
289
  </div>
198
290
  </div>
199
291
  </details>
@@ -300,13 +392,11 @@ HTML_TEMPLATE = """
300
392
  <label>Thickness (mm)</label>
301
393
  <input type="number" id="axes_thickness_mm" step="0.05" min="0.1" max="2" placeholder="0.35">
302
394
  </div>
303
- <div class="form-row">
304
- <label>Hide Top</label>
305
- <input type="checkbox" id="behavior_hide_top_spine">
306
- </div>
307
- <div class="form-row">
308
- <label>Hide Right</label>
309
- <input type="checkbox" id="behavior_hide_right_spine">
395
+ <div class="spine-visibility-grid">
396
+ <div class="form-row"><label>Hide Top</label><input type="checkbox" id="behavior_hide_top_spine"></div>
397
+ <div class="form-row"><label>Hide Right</label><input type="checkbox" id="behavior_hide_right_spine"></div>
398
+ <div class="form-row"><label>Hide Bottom</label><input type="checkbox" id="behavior_hide_bottom_spine"></div>
399
+ <div class="form-row"><label>Hide Left</label><input type="checkbox" id="behavior_hide_left_spine"></div>
310
400
  </div>
311
401
  <div class="form-row">
312
402
  <label>Grid</label>
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """HTML components for the figure editor.
4
+
5
+ This package contains modular HTML components:
6
+ - file_browser: File browser panel
7
+ """
8
+
9
+ from ._file_browser import HTML_FILE_BROWSER
10
+
11
+ __all__ = ["HTML_FILE_BROWSER"]
12
+
13
+ # EOF
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """HTML component for composition toolbar."""
4
+
5
+ HTML_COMPOSITION_TOOLBAR = """
6
+ <!-- Composition Toolbar -->
7
+ <div id="composition-toolbar" class="composition-toolbar">
8
+ <span class="toolbar-label">Align:</span>
9
+ <button onclick="alignPanels('left')" title="Align Left" class="toolbar-btn">
10
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
11
+ <rect x="2" y="2" width="2" height="12"/>
12
+ <rect x="6" y="4" width="8" height="3"/>
13
+ <rect x="6" y="9" width="5" height="3"/>
14
+ </svg>
15
+ </button>
16
+ <button onclick="alignPanels('center_h')" title="Center Horizontal" class="toolbar-btn">
17
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
18
+ <rect x="7" y="2" width="2" height="12"/>
19
+ <rect x="3" y="4" width="10" height="3"/>
20
+ <rect x="4" y="9" width="8" height="3"/>
21
+ </svg>
22
+ </button>
23
+ <button onclick="alignPanels('right')" title="Align Right" class="toolbar-btn">
24
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
25
+ <rect x="12" y="2" width="2" height="12"/>
26
+ <rect x="2" y="4" width="8" height="3"/>
27
+ <rect x="5" y="9" width="5" height="3"/>
28
+ </svg>
29
+ </button>
30
+ <span class="toolbar-separator"></span>
31
+ <button onclick="alignPanels('top')" title="Align Top" class="toolbar-btn">
32
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
33
+ <rect x="2" y="2" width="12" height="2"/>
34
+ <rect x="3" y="6" width="3" height="8"/>
35
+ <rect x="9" y="6" width="3" height="5"/>
36
+ </svg>
37
+ </button>
38
+ <button onclick="alignPanels('center_v')" title="Center Vertical" class="toolbar-btn">
39
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
40
+ <rect x="2" y="7" width="12" height="2"/>
41
+ <rect x="3" y="2" width="3" height="12"/>
42
+ <rect x="9" y="4" width="3" height="8"/>
43
+ </svg>
44
+ </button>
45
+ <button onclick="alignPanels('bottom')" title="Align Bottom" class="toolbar-btn">
46
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
47
+ <rect x="2" y="12" width="12" height="2"/>
48
+ <rect x="3" y="2" width="3" height="8"/>
49
+ <rect x="9" y="5" width="3" height="5"/>
50
+ </svg>
51
+ </button>
52
+ <span class="toolbar-separator"></span>
53
+ <span class="toolbar-label">Distribute:</span>
54
+ <button onclick="distributePanels('horizontal')" title="Distribute Horizontally" class="toolbar-btn">
55
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
56
+ <rect x="2" y="4" width="3" height="8"/>
57
+ <rect x="6.5" y="4" width="3" height="8"/>
58
+ <rect x="11" y="4" width="3" height="8"/>
59
+ </svg>
60
+ </button>
61
+ <button onclick="distributePanels('vertical')" title="Distribute Vertically" class="toolbar-btn">
62
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
63
+ <rect x="4" y="2" width="8" height="3"/>
64
+ <rect x="4" y="6.5" width="8" height="3"/>
65
+ <rect x="4" y="11" width="8" height="3"/>
66
+ </svg>
67
+ </button>
68
+ <span class="toolbar-separator"></span>
69
+ <button onclick="smartAlign()" title="Smart Align (auto-align rows and columns)" class="toolbar-btn toolbar-btn-primary">
70
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
71
+ <path d="M8 1l2 3H6l2-3zm0 14l-2-3h4l-2 3zM1 8l3-2v4l-3-2zm14 0l-3 2V6l3 2z"/>
72
+ <rect x="6" y="6" width="4" height="4"/>
73
+ </svg>
74
+ <span>Smart</span>
75
+ </button>
76
+ </div>
77
+ """
78
+
79
+ __all__ = ["HTML_COMPOSITION_TOOLBAR"]
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """File browser panel HTML for the figure editor."""
4
+
5
+ HTML_FILE_BROWSER = """
6
+ <!-- File Browser Panel -->
7
+ <div class="file-browser-panel" id="file-browser-panel">
8
+ <div class="file-browser-header">
9
+ <div class="header-title">
10
+ <span>FILES</span>
11
+ </div>
12
+ <div class="file-browser-actions">
13
+ <button id="btn-new-file" class="btn-new-file" title="Create new figure">+</button>
14
+ <button id="btn-refresh-files" title="Refresh file list">&#x21bb;</button>
15
+ <button id="btn-collapse-browser" class="btn-collapse" title="Collapse panel">&#x276E;</button>
16
+ </div>
17
+ </div>
18
+ <div class="file-tree-container" id="file-tree-container">
19
+ <ul class="file-tree" id="file-tree">
20
+ <!-- File tree items populated by JavaScript -->
21
+ </ul>
22
+ </div>
23
+ <div class="file-browser-footer">
24
+ <a href="https://scitex.ai" target="_blank" class="brand-link" title="FigRecipe - Part of SciTeX">
25
+ <img src="data:image/png;base64,SCITEX_ICON_PLACEHOLDER" alt="SciTeX" class="brand-icon">
26
+ <div class="brand-info">
27
+ <span class="brand-name">FigRecipe</span>
28
+ <span class="brand-version">vVERSION_PLACEHOLDER by SciTeX™</span>
29
+ </div>
30
+ </a>
31
+ <div class="brand-meta" DEBUG_META_DISPLAY_PLACEHOLDER>
32
+ <span class="server-time">Started: SERVER_START_TIME_PLACEHOLDER</span>
33
+ </div>
34
+ </div>
35
+ <div class="file-browser-resize" id="file-browser-resize"></div>
36
+ </div>
37
+ """
38
+
39
+ __all__ = ["HTML_FILE_BROWSER"]
40
+
41
+ # EOF
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """HTML template component for the datatable panel.
4
+
5
+ This module contains the HTML for the collapsible datatable panel
6
+ that appears on the left side of the editor.
7
+ Plot type options are generated dynamically from the registry.
8
+ """
9
+
10
+ from .._plot_types_registry import generate_html_options
11
+
12
+
13
+ def get_html_datatable_panel() -> str:
14
+ """Generate HTML for datatable panel with dynamic plot type options."""
15
+ plot_options = generate_html_options()
16
+
17
+ return f"""
18
+ <!-- Datatable Panel (always visible, collapsible) -->
19
+ <div id="datatable-panel" class="datatable-panel">
20
+ <div class="datatable-header">
21
+ <div class="header-title">
22
+ <span>DATA</span>
23
+ </div>
24
+ <div class="datatable-header-actions">
25
+ <button id="btn-shortcuts-info" class="btn-small btn-icon" title="Keyboard shortcuts">&#x2328;</button>
26
+ <button id="btn-collapse-datatable" class="btn-collapse" title="Collapse panel">&#x276E;</button>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Tab bar for multiple datatables -->
31
+ <div class="datatable-tabs">
32
+ <div id="datatable-tab-list" class="datatable-tab-list">
33
+ <!-- Tabs dynamically populated -->
34
+ </div>
35
+ <button id="btn-new-tab" class="btn-new-tab" title="New data tab">+</button>
36
+ </div>
37
+
38
+ <!-- Tab content container -->
39
+ <div id="datatable-tab-content" class="datatable-tab-content">
40
+ <!-- Import dropzone -->
41
+ <div class="datatable-import" id="datatable-import-section">
42
+ <div id="datatable-dropzone" class="datatable-import-dropzone">
43
+ <p>Drop CSV, TSV, or JSON file here</p>
44
+ <p class="hint">or click to browse</p>
45
+ <input type="file" id="datatable-file-input" accept=".csv,.tsv,.txt,.json">
46
+ <div class="dropzone-divider">or</div>
47
+ <button class="btn-create-new" onclick="event.stopPropagation(); createNewCSV()">Create New Table</button>
48
+ </div>
49
+ </div>
50
+
51
+ <!-- Toolbar (hidden until data loaded) -->
52
+ <div class="datatable-toolbar" style="display: none;">
53
+ <select id="datatable-plot-type" class="plot-type-select" title="Plot type">
54
+ {plot_options}
55
+ </select>
56
+ <div class="split-btn">
57
+ <button id="btn-datatable-plot" class="btn-plot" disabled title="Create new plot">New</button>
58
+ <button id="btn-plot-dropdown" class="btn-plot-dropdown" title="Add to panel">▼</button>
59
+ <div id="plot-dropdown-menu" class="plot-dropdown-menu">
60
+ <!-- Panels populated dynamically -->
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Variable assignment (dynamic based on plot type) -->
66
+ <div id="datatable-var-assign" class="datatable-var-assign" style="display: none;">
67
+ <div class="var-assign-header">Assign columns to variables:</div>
68
+ <div id="var-assign-slots" class="var-assign-slots">
69
+ <!-- Slots dynamically populated by JS -->
70
+ </div>
71
+ </div>
72
+
73
+ <!-- Spreadsheet content -->
74
+ <div id="datatable-content" class="datatable-content"></div>
75
+
76
+ <!-- Selection info -->
77
+ <div id="datatable-selection-info" class="datatable-selection-info">
78
+ <span class="selected-count">0</span> columns selected
79
+ </div>
80
+ </div>
81
+ <!-- Resize handle -->
82
+ <div class="datatable-resize" id="datatable-resize"></div>
83
+ </div>
84
+ """
85
+
86
+
87
+ # For backward compatibility
88
+ HTML_DATATABLE_PANEL = get_html_datatable_panel()
89
+
90
+ __all__ = ["HTML_DATATABLE_PANEL", "get_html_datatable_panel"]
91
+
92
+ # EOF