plexora 0.0.1__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 (248) hide show
  1. plexora/__init__.py +129 -0
  2. plexora/__main__.py +15 -0
  3. plexora/_url.py +105 -0
  4. plexora/api/__init__.py +55 -0
  5. plexora/api/dataset.py +398 -0
  6. plexora/api/http.py +19 -0
  7. plexora/api/plugin.py +541 -0
  8. plexora/api/store.py +221 -0
  9. plexora/cli.py +777 -0
  10. plexora/client/dist/354_bundle.js +2 -0
  11. plexora/client/dist/354_bundle.js.LICENSE.txt +20 -0
  12. plexora/client/dist/418_bundle.js +2 -0
  13. plexora/client/dist/418_bundle.js.LICENSE.txt +1 -0
  14. plexora/client/dist/693b935cb1f907814be9c6199a68c217.svg +19 -0
  15. plexora/client/dist/713c134ff47cd328a5b711526f151082.svg +18 -0
  16. plexora/client/dist/770_bundle.js +1 -0
  17. plexora/client/dist/ff743f408972e0e96ca9153ed5ae4c83.svg +23 -0
  18. plexora/client/dist/vendor_bundle.js +2 -0
  19. plexora/client/dist/vendor_bundle.js.LICENSE.txt +308 -0
  20. plexora/client/external/openseadragon-bin-2.4.0/LICENSE.txt +28 -0
  21. plexora/client/external/openseadragon-bin-2.4.0/canvas-overlay-hd.js +140 -0
  22. plexora/client/external/openseadragon-bin-2.4.0/changelog.txt +501 -0
  23. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/.gitattributes +17 -0
  24. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/LICENSE.txt +116 -0
  25. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/Toolbar.png +0 -0
  26. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/fullpage.psd +0 -0
  27. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/home.psd +0 -0
  28. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/next.psd +0 -0
  29. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/previous.psd +0 -0
  30. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateleft.psd +0 -0
  31. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateright.psd +0 -0
  32. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/zoom.psd +0 -0
  33. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/README.md +9 -0
  34. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_grouphover.png +0 -0
  35. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_hover.png +0 -0
  36. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_pressed.png +0 -0
  37. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_rest.png +0 -0
  38. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_grouphover.png +0 -0
  39. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_hover.png +0 -0
  40. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_pressed.png +0 -0
  41. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_rest.png +0 -0
  42. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_grouphover.png +0 -0
  43. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_hover.png +0 -0
  44. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_pressed.png +0 -0
  45. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_rest.png +0 -0
  46. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_grouphover.png +0 -0
  47. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_hover.png +0 -0
  48. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_pressed.png +0 -0
  49. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_rest.png +0 -0
  50. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_grouphover.png +0 -0
  51. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_hover.png +0 -0
  52. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_pressed.png +0 -0
  53. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_rest.png +0 -0
  54. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_grouphover.png +0 -0
  55. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_hover.png +0 -0
  56. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_pressed.png +0 -0
  57. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_rest.png +0 -0
  58. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_grouphover.png +0 -0
  59. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_hover.png +0 -0
  60. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_pressed.png +0 -0
  61. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_rest.png +0 -0
  62. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_grouphover.png +0 -0
  63. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_hover.png +0 -0
  64. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_pressed.png +0 -0
  65. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_rest.png +0 -0
  66. plexora/client/external/openseadragon-bin-2.4.0/openseadragon-scalebar.js +562 -0
  67. plexora/client/src/css/import.css +474 -0
  68. plexora/client/src/css/main.css +903 -0
  69. plexora/client/src/css/openProject.css +363 -0
  70. plexora/client/src/css/quickView.css +166 -0
  71. plexora/client/src/css/tokens.css +51 -0
  72. plexora/client/src/css/viewer.css +1655 -0
  73. plexora/client/src/img/apple-touch-icon.png +0 -0
  74. plexora/client/src/img/favicon.ico +0 -0
  75. plexora/client/src/img/logo.ai +8892 -33
  76. plexora/client/src/img/logo.svg +1 -0
  77. plexora/client/src/img/logo_with_text.ai +9011 -34
  78. plexora/client/src/img/logo_with_text.svg +1 -0
  79. plexora/client/src/js/main.js +704 -0
  80. plexora/client/src/js/pluginRegistry.js +108 -0
  81. plexora/client/src/js/services/appStatus.js +286 -0
  82. plexora/client/src/js/services/browsePicker.js +73 -0
  83. plexora/client/src/js/services/dataLayer.js +400 -0
  84. plexora/client/src/js/services/datasetContext.js +143 -0
  85. plexora/client/src/js/services/glRenderer.js +143 -0
  86. plexora/client/src/js/services/importFormValidation.js +257 -0
  87. plexora/client/src/js/services/numericData.js +100 -0
  88. plexora/client/src/js/services/passVariablesToFrontend.js +20 -0
  89. plexora/client/src/js/services/simpleEventHandler.js +25 -0
  90. plexora/client/src/js/vendor.js +29 -0
  91. plexora/client/src/js/views/channelList.js +663 -0
  92. plexora/client/src/js/views/colorSwatchPicker.js +202 -0
  93. plexora/client/src/js/views/columnClassifier.js +146 -0
  94. plexora/client/src/js/views/coordinateField.js +133 -0
  95. plexora/client/src/js/views/dataSourceField.js +276 -0
  96. plexora/client/src/js/views/imageViewer.js +3306 -0
  97. plexora/client/src/js/views/miniMap.js +787 -0
  98. plexora/client/src/js/views/navbarControls.js +178 -0
  99. plexora/client/src/js/views/openProjectPage.js +239 -0
  100. plexora/client/src/js/views/projectEdit.js +335 -0
  101. plexora/client/src/js/views/quickViewLanding.js +136 -0
  102. plexora/client/src/js/views/rainbow.js +326 -0
  103. plexora/client/src/js/views/requirementsModal.js +572 -0
  104. plexora/client/src/js/views/rgbImageViewer.js +115 -0
  105. plexora/client/src/js/views/searchableSelect.js +411 -0
  106. plexora/client/src/js/views/segmentationProgress.js +122 -0
  107. plexora/client/src/js/views/toolLoader.js +747 -0
  108. plexora/client/src/js/views/viewerControls.js +689 -0
  109. plexora/client/src/js/views/viewerManager.js +434 -0
  110. plexora/client/src/js/views/viewerSidebar.js +1117 -0
  111. plexora/client/src/js/workers/tileDecoder.js +130 -0
  112. plexora/client/src/shaders/frag.glsl +528 -0
  113. plexora/client/src/shaders/vert.glsl +12 -0
  114. plexora/client/templates/base.html +212 -0
  115. plexora/client/templates/index.html +238 -0
  116. plexora/client/templates/open_project.html +96 -0
  117. plexora/client/templates/project_columns.html +86 -0
  118. plexora/client/templates/project_edit.html +196 -0
  119. plexora/client/templates/upload.html +118 -0
  120. plexora/connect.py +528 -0
  121. plexora/datasource.py +782 -0
  122. plexora/jupyter.py +406 -0
  123. plexora/notebook_env.py +232 -0
  124. plexora/paths.py +486 -0
  125. plexora/plugins/__init__.py +12 -0
  126. plexora/plugins/cell_explorer/__init__.py +100 -0
  127. plexora/plugins/cell_explorer/server/__init__.py +11 -0
  128. plexora/plugins/cell_explorer/server/routes.py +167 -0
  129. plexora/plugins/cell_explorer/server/state.py +281 -0
  130. plexora/plugins/cell_explorer/server/values.py +145 -0
  131. plexora/plugins/cell_explorer/server/variables.py +367 -0
  132. plexora/plugins/cell_explorer/static/cellExplorerApi.js +158 -0
  133. plexora/plugins/cell_explorer/static/cellExplorerColors.js +316 -0
  134. plexora/plugins/cell_explorer/static/cellExplorerContinuous.js +403 -0
  135. plexora/plugins/cell_explorer/static/cellExplorerFigureBridge.js +133 -0
  136. plexora/plugins/cell_explorer/static/cellExplorerLegend.js +188 -0
  137. plexora/plugins/cell_explorer/static/cellExplorerRoiBridge.js +822 -0
  138. plexora/plugins/cell_explorer/static/cellExplorerSidebarController.js +826 -0
  139. plexora/plugins/cell_explorer/static/cellExplorerState.js +372 -0
  140. plexora/plugins/cell_explorer/static/cell_explorer.css +752 -0
  141. plexora/plugins/cell_explorer/templates/cell_explorer/panel.html +137 -0
  142. plexora/plugins/figure_builder/__init__.py +125 -0
  143. plexora/plugins/figure_builder/server/__init__.py +7 -0
  144. plexora/plugins/figure_builder/server/compose.py +365 -0
  145. plexora/plugins/figure_builder/server/export.py +784 -0
  146. plexora/plugins/figure_builder/server/export_jobs.py +148 -0
  147. plexora/plugins/figure_builder/server/operations.py +556 -0
  148. plexora/plugins/figure_builder/server/pixels.py +142 -0
  149. plexora/plugins/figure_builder/server/provenance.py +174 -0
  150. plexora/plugins/figure_builder/server/render.py +278 -0
  151. plexora/plugins/figure_builder/server/repository.py +701 -0
  152. plexora/plugins/figure_builder/server/routes.py +594 -0
  153. plexora/plugins/figure_builder/server/schema.py +1023 -0
  154. plexora/plugins/figure_builder/server/sources.py +120 -0
  155. plexora/plugins/figure_builder/server/textmetrics.py +155 -0
  156. plexora/plugins/figure_builder/static/figureActions.js +363 -0
  157. plexora/plugins/figure_builder/static/figureBuilderApi.js +255 -0
  158. plexora/plugins/figure_builder/static/figureCanvas.js +2362 -0
  159. plexora/plugins/figure_builder/static/figureCaptureBoxes.js +369 -0
  160. plexora/plugins/figure_builder/static/figureCaptureDock.js +466 -0
  161. plexora/plugins/figure_builder/static/figureCaptureTool.js +1034 -0
  162. plexora/plugins/figure_builder/static/figureConfirm.js +136 -0
  163. plexora/plugins/figure_builder/static/figureContextBar.js +1193 -0
  164. plexora/plugins/figure_builder/static/figureContextMenu.js +253 -0
  165. plexora/plugins/figure_builder/static/figureDocumentState.js +275 -0
  166. plexora/plugins/figure_builder/static/figureExportUi.js +174 -0
  167. plexora/plugins/figure_builder/static/figureLibrary.js +247 -0
  168. plexora/plugins/figure_builder/static/figureQuickEdit.js +628 -0
  169. plexora/plugins/figure_builder/static/figureRichText.js +634 -0
  170. plexora/plugins/figure_builder/static/figureSceneSnapshot.js +361 -0
  171. plexora/plugins/figure_builder/static/figureSchema.js +218 -0
  172. plexora/plugins/figure_builder/static/figureSidebarController.js +1159 -0
  173. plexora/plugins/figure_builder/static/figureTextEditor.js +503 -0
  174. plexora/plugins/figure_builder/static/figureTextPanel.js +491 -0
  175. plexora/plugins/figure_builder/static/figureViewOptions.js +273 -0
  176. plexora/plugins/figure_builder/static/figureWorkspace.js +2030 -0
  177. plexora/plugins/figure_builder/static/figure_builder.css +3292 -0
  178. plexora/plugins/figure_builder/templates/figure_builder/library.html +74 -0
  179. plexora/plugins/figure_builder/templates/figure_builder/workspace.html +27 -0
  180. plexora/plugins/figure_builder/templates/figure_builder/workspace_body.html +458 -0
  181. plexora/plugins/gating/__init__.py +76 -0
  182. plexora/plugins/gating/server/__init__.py +0 -0
  183. plexora/plugins/gating/server/anndata_gates.py +367 -0
  184. plexora/plugins/gating/server/database.py +16 -0
  185. plexora/plugins/gating/server/model.py +320 -0
  186. plexora/plugins/gating/server/routes.py +235 -0
  187. plexora/plugins/gating/static/csvGatingList.js +947 -0
  188. plexora/plugins/gating/static/gating.css +289 -0
  189. plexora/plugins/gating/static/gatingApi.js +221 -0
  190. plexora/plugins/gating/static/gatingSidebarController.js +513 -0
  191. plexora/plugins/gating/templates/gating/legacy.html +26 -0
  192. plexora/plugins/gating/templates/gating/panel.html +69 -0
  193. plexora/plugins/roi/__init__.py +95 -0
  194. plexora/plugins/roi/server/__init__.py +8 -0
  195. plexora/plugins/roi/server/adapters.py +655 -0
  196. plexora/plugins/roi/server/geojson.py +267 -0
  197. plexora/plugins/roi/server/geometry.py +181 -0
  198. plexora/plugins/roi/server/mapping.py +169 -0
  199. plexora/plugins/roi/server/operations.py +293 -0
  200. plexora/plugins/roi/server/repository.py +215 -0
  201. plexora/plugins/roi/server/routes.py +409 -0
  202. plexora/plugins/roi/server/schema.py +323 -0
  203. plexora/plugins/roi/static/roi.css +583 -0
  204. plexora/plugins/roi/static/roiApi.js +177 -0
  205. plexora/plugins/roi/static/roiFigureBridge.js +107 -0
  206. plexora/plugins/roi/static/roiGeometry.js +350 -0
  207. plexora/plugins/roi/static/roiRenderer.js +278 -0
  208. plexora/plugins/roi/static/roiSidebarController.js +1038 -0
  209. plexora/plugins/roi/static/roiState.js +518 -0
  210. plexora/plugins/roi/static/roiTools.js +993 -0
  211. plexora/plugins/roi/templates/roi/panel.html +240 -0
  212. plexora/proxy.py +57 -0
  213. plexora/server/models/adapters/__init__.py +94 -0
  214. plexora/server/models/adapters/anndata_adapter.py +388 -0
  215. plexora/server/models/adapters/base.py +93 -0
  216. plexora/server/models/adapters/classify.py +192 -0
  217. plexora/server/models/adapters/csv_adapter.py +105 -0
  218. plexora/server/models/adapters/inspection.py +265 -0
  219. plexora/server/models/adapters/spatialdata_adapter.py +248 -0
  220. plexora/server/models/centroid_tiles.py +305 -0
  221. plexora/server/models/data_model.py +1659 -0
  222. plexora/server/models/database_model.py +169 -0
  223. plexora/server/models/project.py +1270 -0
  224. plexora/server/plugins.py +199 -0
  225. plexora/server/routes/browse_routes.py +41 -0
  226. plexora/server/routes/data_routes.py +294 -0
  227. plexora/server/routes/import_routes.py +603 -0
  228. plexora/server/routes/page_routes.py +139 -0
  229. plexora/server/routes/project_routes.py +438 -0
  230. plexora/server/routes/quick_view_routes.py +62 -0
  231. plexora/server/routes/system_routes.py +39 -0
  232. plexora/server/routes/tool_routes.py +418 -0
  233. plexora/server/utils/addHEColumns.py +11 -0
  234. plexora/server/utils/fast_png.py +97 -0
  235. plexora/server/utils/fullConversion.py +50 -0
  236. plexora/server/utils/native_dialog.py +168 -0
  237. plexora/server/utils/pre_normalization.py +47 -0
  238. plexora/server/utils/segmentation_pyramid.py +598 -0
  239. plexora/server/utils/smallestenclosingcircle.py +126 -0
  240. plexora/server/utils/tiffsurgeon.py +372 -0
  241. plexora/server_cli.py +48 -0
  242. plexora/test.py +0 -0
  243. plexora-0.0.1.dist-info/METADATA +341 -0
  244. plexora-0.0.1.dist-info/RECORD +248 -0
  245. plexora-0.0.1.dist-info/WHEEL +5 -0
  246. plexora-0.0.1.dist-info/entry_points.txt +12 -0
  247. plexora-0.0.1.dist-info/licenses/LICENSE +207 -0
  248. plexora-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,583 @@
1
+ /* Regions panel.
2
+ *
3
+ * This plugin's appearance, in this plugin's directory: core cannot ship the
4
+ * look of a tool it may not have installed, and nothing here may style a
5
+ * core-owned element (both directions are asserted by
6
+ * tests/test_plugin_css_boundary.py). Colours come from tokens.css, which
7
+ * base.html loads for every page, so the panel matches the rest of the sidebar
8
+ * without restating any of it. */
9
+
10
+ #roi_panel_section {
11
+ border-color: rgba(56, 189, 248, 0.28);
12
+ }
13
+
14
+ #roi_panel_section .section-heading h2 {
15
+ color: #dff1ff;
16
+ }
17
+
18
+ .roi-hidden-file {
19
+ display: none;
20
+ }
21
+
22
+ /* -- banners: the two states where saving cannot proceed ---------------- */
23
+
24
+ .roi-banner {
25
+ align-items: flex-start;
26
+ border-radius: var(--radius-sm);
27
+ display: flex;
28
+ font-size: 12px;
29
+ gap: var(--space-2);
30
+ line-height: 1.45;
31
+ margin-bottom: var(--space-3);
32
+ padding: var(--space-3);
33
+ }
34
+
35
+ .roi-banner-danger {
36
+ background: var(--accent-danger-soft);
37
+ border: 1px solid var(--accent-danger);
38
+ color: #ffe4e4;
39
+ }
40
+
41
+ .roi-banner-warning {
42
+ background: var(--accent-warning-soft);
43
+ border: 1px solid var(--accent-warning);
44
+ color: #fdf0d5;
45
+ }
46
+
47
+ .roi-banner-detail {
48
+ color: var(--text-secondary);
49
+ font-size: 11px;
50
+ margin-top: var(--space-1);
51
+ }
52
+
53
+ .roi-banner-actions {
54
+ display: flex;
55
+ flex-wrap: wrap;
56
+ gap: var(--space-2);
57
+ margin-top: var(--space-2);
58
+ }
59
+
60
+ .roi-banner-actions .sidebar-action {
61
+ font-size: 11px;
62
+ padding: 4px 8px;
63
+ }
64
+
65
+ /* -- toolbar ------------------------------------------------------------ */
66
+
67
+ .roi-toolbar {
68
+ display: grid;
69
+ gap: var(--space-2);
70
+ grid-template-columns: repeat(4, 1fr);
71
+ margin-bottom: var(--space-2);
72
+ }
73
+
74
+ .roi-tool {
75
+ align-items: center;
76
+ background: rgba(255, 255, 255, 0.06);
77
+ border: 1px solid var(--border-subtle);
78
+ border-radius: var(--radius-sm);
79
+ color: var(--text-secondary);
80
+ cursor: pointer;
81
+ display: flex;
82
+ flex-direction: column;
83
+ gap: 2px;
84
+ padding: var(--space-2) 0;
85
+ transition: background var(--duration-fast) var(--ease-standard),
86
+ border-color var(--duration-fast) var(--ease-standard);
87
+ }
88
+
89
+ .roi-tool:hover:not(:disabled) {
90
+ background: rgba(255, 255, 255, 0.12);
91
+ color: #ffffff;
92
+ }
93
+
94
+ .roi-tool.is-active {
95
+ background: var(--accent-channel-soft);
96
+ border-color: var(--accent-channel);
97
+ color: #ffffff;
98
+ }
99
+
100
+ .roi-tool:disabled {
101
+ cursor: default;
102
+ opacity: 0.4;
103
+ }
104
+
105
+ .roi-tool-key {
106
+ font-size: 9px;
107
+ letter-spacing: 0.06em;
108
+ opacity: 0.7;
109
+ }
110
+
111
+ .roi-hint {
112
+ color: var(--text-muted);
113
+ font-size: 11px;
114
+ line-height: 1.5;
115
+ margin-bottom: var(--space-3);
116
+ }
117
+
118
+ .roi-hint kbd {
119
+ background: rgba(255, 255, 255, 0.1);
120
+ border: 1px solid var(--border-subtle);
121
+ border-radius: 3px;
122
+ font-family: inherit;
123
+ font-size: 10px;
124
+ padding: 1px 4px;
125
+ }
126
+
127
+ /* -- categories --------------------------------------------------------- */
128
+
129
+ .roi-category-list {
130
+ display: flex;
131
+ flex-direction: column;
132
+ gap: var(--space-1);
133
+ margin-bottom: var(--space-2);
134
+ max-height: 220px;
135
+ overflow-y: auto;
136
+ }
137
+
138
+ .roi-category {
139
+ align-items: center;
140
+ border: 1px solid transparent;
141
+ border-radius: var(--radius-sm);
142
+ display: flex;
143
+ gap: var(--space-2);
144
+ padding: 3px var(--space-2) 3px 3px;
145
+ }
146
+
147
+ .roi-category.is-active {
148
+ background: rgba(255, 255, 255, 0.07);
149
+ border-color: var(--border-strong);
150
+ }
151
+
152
+ /* Hidden categories stay listed and stay operable -- being unable to find the
153
+ control that un-hides something is worse than the thing being hidden. */
154
+ .roi-category.is-hidden .roi-category-label,
155
+ .roi-category.is-hidden .roi-category-count {
156
+ opacity: 0.45;
157
+ text-decoration: line-through;
158
+ }
159
+
160
+ .roi-swatch {
161
+ background: none;
162
+ border: 1px solid var(--border-subtle);
163
+ border-radius: var(--radius-sm);
164
+ cursor: pointer;
165
+ flex: 0 0 auto;
166
+ height: 22px;
167
+ padding: 0;
168
+ width: 22px;
169
+ }
170
+
171
+ .roi-category-label {
172
+ background: none;
173
+ border: 0;
174
+ color: var(--text-primary);
175
+ cursor: pointer;
176
+ flex: 1 1 auto;
177
+ font-size: 12px;
178
+ min-width: 0;
179
+ overflow: hidden;
180
+ padding: 0;
181
+ text-align: left;
182
+ text-overflow: ellipsis;
183
+ white-space: nowrap;
184
+ }
185
+
186
+ .roi-category-count {
187
+ color: var(--text-muted);
188
+ flex: 0 0 auto;
189
+ font-size: 11px;
190
+ font-variant-numeric: tabular-nums;
191
+ }
192
+
193
+ .roi-category-action {
194
+ flex: 0 0 auto;
195
+ font-size: 10px;
196
+ height: 22px;
197
+ width: 22px;
198
+ }
199
+
200
+ /* Core's main.css carries a global `.fa-trash { color: black }`, written for a
201
+ light surface somewhere else in the app. It targets the GLYPH, so it beats
202
+ any colour inherited from the button around it -- which is why every trash
203
+ icon in this panel rendered as a black shape on a dark background no matter
204
+ what the button was set to. Handing the glyph back to its button is enough;
205
+ the rule is core's and other pages may be leaning on it, so it stays put and
206
+ this override is scoped to this plugin's own section. */
207
+ #roi_panel_section .fa-trash {
208
+ color: inherit;
209
+ }
210
+
211
+ /* And `.icon-button` carries `min-width: 28px`, sized for the buttons in a
212
+ section heading. The three small ones on this panel sit inside rows of text
213
+ and set their own smaller width, which that floor was quietly overriding --
214
+ leaving each of them wider than it is tall. Squares, as drawn. */
215
+ .roi-category-action,
216
+ .roi-selection-action,
217
+ .roi-destination-close,
218
+ .roi-modal-close {
219
+ min-width: 0;
220
+ }
221
+
222
+ .roi-modal-close {
223
+ flex: 0 0 auto;
224
+ font-size: 12px;
225
+ height: 26px;
226
+ width: 26px;
227
+ }
228
+
229
+ /* The controls that destroy something, coloured so they do not read as another
230
+ toggle sitting next to the eye and the padlock. Amber at rest, red under the
231
+ cursor: careful, then dangerous. Both trash buttons on this panel share the
232
+ rule, so they can never come to mean two different degrees of danger. */
233
+ .roi-category-delete,
234
+ .roi-danger-action {
235
+ color: var(--accent-warning);
236
+ }
237
+
238
+ .roi-category-delete:hover,
239
+ .roi-danger-action:hover {
240
+ background: var(--accent-danger-soft);
241
+ color: var(--accent-danger);
242
+ }
243
+
244
+ /* -- nothing here yet ---------------------------------------------------- */
245
+
246
+ .roi-empty {
247
+ background: var(--surface-2);
248
+ border: 1px dashed var(--border-subtle);
249
+ border-radius: var(--radius-sm);
250
+ margin-bottom: var(--space-2);
251
+ padding: var(--space-2);
252
+ }
253
+
254
+ .roi-category-add {
255
+ display: flex;
256
+ gap: var(--space-2);
257
+ margin-bottom: var(--space-3);
258
+ }
259
+
260
+ /* One rule for every text control this panel owns -- the category name, the
261
+ region name, the category dropdown, the destination. They sit within a few
262
+ rows of each other in a 320px column, and three heights there read as three
263
+ different kinds of control. */
264
+ .roi-input {
265
+ background: var(--surface-2);
266
+ border: 1px solid var(--border-subtle);
267
+ border-radius: var(--radius-sm);
268
+ box-sizing: border-box;
269
+ color: var(--text-primary);
270
+ font-family: inherit;
271
+ font-size: 12px;
272
+ min-width: 0;
273
+ padding: 6px var(--space-2);
274
+ width: 100%;
275
+ }
276
+
277
+ .roi-input:focus {
278
+ border-color: var(--accent-channel);
279
+ outline: none;
280
+ }
281
+
282
+ .roi-category-add .roi-input {
283
+ flex: 1 1 auto;
284
+ }
285
+
286
+ /* -- selected region ---------------------------------------------------- */
287
+
288
+ .roi-selection-head {
289
+ align-items: center;
290
+ display: flex;
291
+ gap: var(--space-2);
292
+ justify-content: space-between;
293
+ }
294
+
295
+ /* `.control-label` is written for a label stacked above its field, so it
296
+ carries a bottom margin. Both of this panel's heading rows put a label beside
297
+ something else instead, and have to take that margin back. */
298
+ .roi-selection-head .control-label,
299
+ .roi-destination-head .control-label {
300
+ margin: 0;
301
+ }
302
+
303
+ .roi-selection-tools {
304
+ display: flex;
305
+ gap: var(--space-1);
306
+ }
307
+
308
+ .roi-selection-action {
309
+ flex: 0 0 auto;
310
+ font-size: 11px;
311
+ height: 24px;
312
+ width: 24px;
313
+ }
314
+
315
+ .roi-selection-action.is-active {
316
+ color: var(--accent-channel);
317
+ }
318
+
319
+ /* Which padlock is showing, decided by the button's own pressed state. See the
320
+ note in panel.html: this is a CSS swap because FontAwesome replaces the span
321
+ with an <svg> whose class cannot be rewritten without breaking it. */
322
+ #roi_selection_locked .fa-lock,
323
+ #roi_selection_locked[aria-pressed="true"] .fa-lock-open {
324
+ display: none;
325
+ }
326
+
327
+ #roi_selection_locked[aria-pressed="true"] .fa-lock {
328
+ display: inline-block;
329
+ }
330
+
331
+ .roi-selection-row {
332
+ align-items: center;
333
+ display: flex;
334
+ gap: var(--space-2);
335
+ margin: var(--space-1) 0 var(--space-2);
336
+ }
337
+
338
+ .roi-selection-name {
339
+ flex: 1 1 58%;
340
+ }
341
+
342
+ .roi-select-wrap {
343
+ flex: 0 1 42%;
344
+ min-width: 0;
345
+ position: relative;
346
+ }
347
+
348
+ /* Room for the swatch, which sits over this padding rather than in the flow --
349
+ a <select> cannot hold an element. */
350
+ .roi-select-wrap .roi-input {
351
+ padding-left: 24px;
352
+ }
353
+
354
+ .roi-selection-swatch {
355
+ border-radius: 50%;
356
+ height: 9px;
357
+ left: 9px;
358
+ pointer-events: none;
359
+ position: absolute;
360
+ top: 50%;
361
+ transform: translateY(-50%);
362
+ width: 9px;
363
+ }
364
+
365
+ .roi-selection-note {
366
+ margin-bottom: var(--space-2);
367
+ }
368
+
369
+ /* -- where a native save goes ------------------------------------------- */
370
+
371
+ /* Opened by the save button, closed by the save. Bordered and inset so that a
372
+ block which appears mid-panel reads as a step in the thing above it rather
373
+ than as another control that has always been there. */
374
+ .roi-destination {
375
+ background: rgba(255, 255, 255, 0.05);
376
+ border: 1px solid var(--border-subtle);
377
+ border-radius: var(--radius-sm);
378
+ margin-bottom: var(--space-2);
379
+ padding: var(--space-2);
380
+ }
381
+
382
+ .roi-destination-head {
383
+ align-items: center;
384
+ display: flex;
385
+ gap: var(--space-2);
386
+ justify-content: space-between;
387
+ margin-bottom: var(--space-1);
388
+ }
389
+
390
+ .roi-destination-close {
391
+ flex: 0 0 auto;
392
+ font-size: 11px;
393
+ height: 22px;
394
+ width: 22px;
395
+ }
396
+
397
+ .roi-destination-hint {
398
+ margin: var(--space-1) 0 0;
399
+ overflow-wrap: anywhere;
400
+ }
401
+
402
+ /* -- the two ways out, on one row --------------------------------------- */
403
+
404
+ /* Save and Map to cells are peers, not steps, so they sit beside each other.
405
+ Flex rather than a grid of fixed tracks: exactly one of the two save buttons
406
+ is shown at a time and the mapping pair is absent altogether without a table,
407
+ and `flex: 1 1 0` gives whatever survives the full width without this file
408
+ having to know which combination it got.
409
+
410
+ `.sidebar-action-fancy` is core's, sized to stand alone: full width, its own
411
+ top margin, 12px of side padding. All three are wrong for a button sharing a
412
+ row 288px wide, so they are taken back here -- scoped inside this plugin's
413
+ own row, which is the only place the assumption does not hold. */
414
+ .roi-actions {
415
+ align-items: center;
416
+ display: flex;
417
+ gap: var(--space-2);
418
+ margin-top: 14px;
419
+ }
420
+
421
+ .roi-actions .sidebar-action-fancy {
422
+ flex: 1 1 0;
423
+ font-size: 12px;
424
+ gap: 6px;
425
+ letter-spacing: 0;
426
+ margin-top: 0;
427
+ min-width: 0;
428
+ overflow: hidden;
429
+ padding: 0 8px;
430
+ white-space: nowrap;
431
+ }
432
+
433
+ /* Both labels fit the narrowest sidebar with room to spare, on the fonts this
434
+ app ships. This is for the ones it does not: a label that outgrows its half
435
+ of the row is cut with an ellipsis rather than escaping the button. */
436
+ .roi-actions .sidebar-action-fancy > span:last-child {
437
+ min-width: 0;
438
+ overflow: hidden;
439
+ text-overflow: ellipsis;
440
+ }
441
+
442
+ /* The ? next to Map to cells. Square, quiet, and the same height as the icon
443
+ buttons elsewhere on the panel -- it explains a button, it does not compete
444
+ with one. */
445
+ .roi-map-info {
446
+ flex: 0 0 auto;
447
+ font-size: 11px;
448
+ height: 26px;
449
+ min-width: 0;
450
+ width: 26px;
451
+ }
452
+
453
+ /* -- what Map to cells does --------------------------------------------- */
454
+
455
+ /* A plugin's own dialog rather than core's `.requirements-modal`: that one is
456
+ core's element, rendered from any plugin's requirements, and styling it from
457
+ here would be this plugin reaching into core (tests/test_plugin_css_boundary.py).
458
+ The widths and the backdrop match it on purpose -- a user should not be able
459
+ to tell that two different parts of the app drew these. */
460
+ .roi-modal {
461
+ background: var(--surface-1);
462
+ border: 1px solid var(--border-strong);
463
+ border-radius: var(--radius-lg);
464
+ box-shadow: var(--shadow-lg);
465
+ color: var(--text-primary);
466
+ max-height: 86vh;
467
+ overflow: auto;
468
+ padding: 0;
469
+ width: min(560px, 92vw);
470
+ }
471
+
472
+ .roi-modal::backdrop {
473
+ background: rgba(0, 0, 0, 0.62);
474
+ }
475
+
476
+ .roi-modal-head {
477
+ align-items: center;
478
+ background: var(--surface-1);
479
+ border-bottom: 1px solid var(--border-subtle);
480
+ display: flex;
481
+ gap: var(--space-2);
482
+ justify-content: space-between;
483
+ padding: var(--space-4) var(--space-6);
484
+ /* The body is long enough to scroll, and a heading that scrolls away takes
485
+ with it the only control that closes the thing. */
486
+ position: sticky;
487
+ top: 0;
488
+ }
489
+
490
+ .roi-modal-title {
491
+ font-size: 1.05rem;
492
+ font-weight: 600;
493
+ margin: 0;
494
+ }
495
+
496
+ .roi-modal-body {
497
+ font-size: 12.5px;
498
+ line-height: 1.6;
499
+ padding: var(--space-4) var(--space-6) var(--space-6);
500
+ }
501
+
502
+ .roi-modal-body p {
503
+ color: var(--text-secondary);
504
+ margin: 0 0 var(--space-3);
505
+ }
506
+
507
+ .roi-modal-body ul {
508
+ color: var(--text-secondary);
509
+ margin: 0 0 var(--space-3);
510
+ padding-left: var(--space-4);
511
+ }
512
+
513
+ .roi-modal-body li {
514
+ margin-bottom: var(--space-1);
515
+ }
516
+
517
+ /* The last line, which is not about how the feature works but about which of
518
+ the two buttons a user wanted. Separated so it does not read as a sixth rule
519
+ of the mapping. */
520
+ .roi-modal-body .roi-modal-aside {
521
+ border-top: 1px solid var(--border-subtle);
522
+ margin-bottom: 0;
523
+ padding-top: var(--space-3);
524
+ }
525
+
526
+ .roi-modal-body code {
527
+ background: rgba(255, 255, 255, 0.08);
528
+ border-radius: 3px;
529
+ font-size: 11.5px;
530
+ padding: 1px 4px;
531
+ /* Column names run to `plexora_rois_category`; in a 560px dialog that is
532
+ fine, at 92vw on a phone it is what breaks the layout. */
533
+ overflow-wrap: anywhere;
534
+ }
535
+
536
+ /* The only part of this dialog that is about THIS project rather than about
537
+ the feature: the names the two columns will actually get. Boxed so the eye
538
+ lands on it, and unbulleted because each line already opens with the column
539
+ name set in code -- a bullet in front of that is one marker too many. */
540
+ .roi-modal-body .roi-modal-note {
541
+ background: var(--surface-2);
542
+ border: 1px solid var(--border-subtle);
543
+ border-radius: var(--radius-sm);
544
+ color: var(--text-primary);
545
+ list-style: none;
546
+ padding: var(--space-2) var(--space-3);
547
+ }
548
+
549
+ /* -- status ------------------------------------------------------------- */
550
+
551
+ .roi-status {
552
+ align-items: center;
553
+ color: var(--text-muted);
554
+ display: flex;
555
+ font-size: 11px;
556
+ gap: var(--space-2);
557
+ margin-top: var(--space-3);
558
+ }
559
+
560
+ .roi-status-dot {
561
+ border-radius: 50%;
562
+ flex: 0 0 auto;
563
+ height: 7px;
564
+ width: 7px;
565
+ }
566
+
567
+ .roi-status-saved { background: var(--accent-success); }
568
+ .roi-status-saving { background: var(--accent-channel); }
569
+ .roi-status-dirty { background: var(--accent-warning); }
570
+ .roi-status-failed { background: var(--accent-danger); }
571
+ .roi-status-conflict { background: var(--accent-warning); }
572
+ .roi-status-blocked { background: var(--accent-danger); }
573
+
574
+ .roi-message {
575
+ background: var(--surface-2);
576
+ border: 1px solid var(--border-subtle);
577
+ border-radius: var(--radius-sm);
578
+ color: var(--text-secondary);
579
+ font-size: 11px;
580
+ line-height: 1.45;
581
+ margin-top: var(--space-2);
582
+ padding: var(--space-2);
583
+ }