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,363 @@
1
+ /* Open Project page (open_project.html). Reuses the shared design tokens
2
+ from tokens.css (loaded by base.html on every page), same authoring
3
+ style as quickView.css. */
4
+
5
+ .open-project-page {
6
+ background: var(--surface-0);
7
+ box-sizing: border-box;
8
+ margin: 0 auto;
9
+ max-width: 1200px;
10
+ min-height: 95vh;
11
+ padding: var(--space-6);
12
+ }
13
+
14
+ .open-project-header {
15
+ align-items: flex-start;
16
+ display: flex;
17
+ justify-content: space-between;
18
+ margin-bottom: var(--space-5);
19
+ }
20
+
21
+ .open-project-header h1 {
22
+ color: var(--text-primary);
23
+ font-size: 26px;
24
+ font-weight: 700;
25
+ margin: 0;
26
+ }
27
+
28
+ .open-project-subtitle {
29
+ color: var(--text-muted);
30
+ font-size: 13px;
31
+ margin: var(--space-1) 0 0;
32
+ }
33
+
34
+ .open-project-create {
35
+ align-items: center;
36
+ display: inline-flex;
37
+ gap: var(--space-2);
38
+ white-space: nowrap;
39
+ }
40
+
41
+ /* [ Projects ] [ Figures ] -- rendered only when a plugin contributes a tab.
42
+ Core's look, whoever contributed the entry: a plugin supplies a label and a
43
+ destination and gets no say in how either is drawn. */
44
+ .open-project-tabs {
45
+ border-bottom: 1px solid var(--border-subtle);
46
+ display: flex;
47
+ gap: var(--space-4);
48
+ margin-bottom: var(--space-5);
49
+ }
50
+
51
+ .open-project-tab {
52
+ border-bottom: 2px solid transparent;
53
+ color: var(--text-muted);
54
+ cursor: pointer;
55
+ font-size: 14px;
56
+ font-weight: 600;
57
+ padding: 0 0 var(--space-2);
58
+ text-decoration: none;
59
+ transition: color var(--duration-fast) var(--ease-standard),
60
+ border-color var(--duration-fast) var(--ease-standard);
61
+ }
62
+
63
+ .open-project-tab:hover {
64
+ color: var(--text-primary);
65
+ }
66
+
67
+ .open-project-tab.is-active {
68
+ border-bottom-color: var(--accent-channel);
69
+ color: var(--text-primary);
70
+ }
71
+
72
+ .open-project-toolbar {
73
+ align-items: center;
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ gap: var(--space-3);
77
+ margin-bottom: var(--space-5);
78
+ }
79
+
80
+ .open-project-search {
81
+ align-items: center;
82
+ background: var(--surface-1);
83
+ border: 1px solid var(--border-subtle);
84
+ border-radius: var(--radius-md);
85
+ display: flex;
86
+ flex: 1 1 260px;
87
+ gap: var(--space-2);
88
+ padding: 0 var(--space-3);
89
+ }
90
+
91
+ .open-project-search .fa-magnifying-glass {
92
+ color: var(--text-muted);
93
+ font-size: 13px;
94
+ }
95
+
96
+ .open-project-search input {
97
+ background: transparent;
98
+ border: none;
99
+ color: var(--text-primary);
100
+ flex: 1;
101
+ font-size: 14px;
102
+ min-width: 0;
103
+ padding: 10px 0;
104
+ }
105
+
106
+ .open-project-search input:focus {
107
+ outline: none;
108
+ }
109
+
110
+ .open-project-sort {
111
+ background: var(--surface-1);
112
+ border: 1px solid var(--border-subtle);
113
+ border-radius: var(--radius-md);
114
+ color: var(--text-primary);
115
+ font-size: 13px;
116
+ padding: 10px var(--space-3);
117
+ }
118
+
119
+ .open-project-view-toggle {
120
+ display: flex;
121
+ gap: 2px;
122
+ }
123
+
124
+ .view-toggle-button {
125
+ background: var(--surface-1);
126
+ border: 1px solid var(--border-subtle);
127
+ color: var(--text-muted);
128
+ cursor: pointer;
129
+ padding: 9px var(--space-3);
130
+ transition: background var(--duration-fast) var(--ease-standard),
131
+ color var(--duration-fast) var(--ease-standard);
132
+ }
133
+
134
+ .view-toggle-button:first-child {
135
+ border-radius: var(--radius-md) 0 0 var(--radius-md);
136
+ }
137
+
138
+ .view-toggle-button:last-child {
139
+ border-left: none;
140
+ border-radius: 0 var(--radius-md) var(--radius-md) 0;
141
+ }
142
+
143
+ .view-toggle-button:hover {
144
+ color: var(--text-primary);
145
+ }
146
+
147
+ .view-toggle-button.active {
148
+ background: var(--accent-channel-soft);
149
+ color: var(--accent-channel);
150
+ }
151
+
152
+ /* Grid view */
153
+ .project-grid {
154
+ display: grid;
155
+ gap: var(--space-4);
156
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
157
+ }
158
+
159
+ .project-card {
160
+ background: var(--surface-1);
161
+ border: 1px solid var(--border-subtle);
162
+ border-radius: var(--radius-lg);
163
+ overflow: hidden;
164
+ position: relative;
165
+ transition: border-color var(--duration-base) var(--ease-standard),
166
+ transform var(--duration-base) var(--ease-standard);
167
+ }
168
+
169
+ .project-card:hover {
170
+ border-color: var(--accent-channel);
171
+ transform: translateY(-2px);
172
+ }
173
+
174
+ .project-card-link {
175
+ color: inherit;
176
+ display: block;
177
+ text-decoration: none;
178
+ }
179
+
180
+ .project-card .project-thumb {
181
+ aspect-ratio: 4 / 3;
182
+ }
183
+
184
+ .project-card-name {
185
+ color: var(--text-primary);
186
+ display: block;
187
+ font-size: 14px;
188
+ font-weight: 600;
189
+ overflow: hidden;
190
+ padding: var(--space-3) var(--space-3) 0;
191
+ text-overflow: ellipsis;
192
+ white-space: nowrap;
193
+ }
194
+
195
+ .project-card-date {
196
+ color: var(--text-muted);
197
+ display: block;
198
+ font-size: 12px;
199
+ padding: 2px var(--space-3) var(--space-3);
200
+ }
201
+
202
+ .project-card .project-actions {
203
+ position: absolute;
204
+ right: var(--space-2);
205
+ top: var(--space-2);
206
+ }
207
+
208
+ /* Marks a project that lives on a shared data directory rather than this
209
+ user's own. Sits inside the date caption so it needs no layout of its own,
210
+ and is absent entirely on an install with no shared roots configured. */
211
+ .project-shared {
212
+ align-items: center;
213
+ color: var(--text-muted);
214
+ display: inline-flex;
215
+ gap: 4px;
216
+ margin-left: var(--space-2);
217
+ }
218
+
219
+ .project-shared .fas {
220
+ font-size: 10px;
221
+ }
222
+
223
+ /* List view */
224
+ .project-list {
225
+ display: flex;
226
+ flex-direction: column;
227
+ gap: var(--space-2);
228
+ }
229
+
230
+ .project-row {
231
+ align-items: center;
232
+ background: var(--surface-1);
233
+ border: 1px solid var(--border-subtle);
234
+ border-radius: var(--radius-md);
235
+ display: flex;
236
+ position: relative;
237
+ transition: border-color var(--duration-base) var(--ease-standard);
238
+ }
239
+
240
+ .project-row:hover {
241
+ border-color: var(--accent-channel);
242
+ }
243
+
244
+ .project-row-link {
245
+ align-items: center;
246
+ color: inherit;
247
+ display: flex;
248
+ flex: 1;
249
+ gap: var(--space-3);
250
+ min-width: 0;
251
+ padding: var(--space-2) var(--space-3);
252
+ text-decoration: none;
253
+ }
254
+
255
+ .project-row .project-thumb {
256
+ border-radius: var(--radius-sm);
257
+ flex: 0 0 auto;
258
+ height: 44px;
259
+ width: 44px;
260
+ }
261
+
262
+ .project-row-name {
263
+ color: var(--text-primary);
264
+ flex: 1;
265
+ font-size: 14px;
266
+ font-weight: 600;
267
+ min-width: 0;
268
+ overflow: hidden;
269
+ text-overflow: ellipsis;
270
+ white-space: nowrap;
271
+ }
272
+
273
+ .project-row-date {
274
+ color: var(--text-muted);
275
+ flex: 0 0 auto;
276
+ font-size: 12px;
277
+ }
278
+
279
+ .project-row .project-actions {
280
+ display: flex;
281
+ padding-right: var(--space-3);
282
+ }
283
+
284
+ /* Shared: thumbnail + action buttons */
285
+ .project-thumb {
286
+ align-items: center;
287
+ background: linear-gradient(135deg, var(--surface-2), var(--surface-1));
288
+ display: flex;
289
+ justify-content: center;
290
+ overflow: hidden;
291
+ position: relative;
292
+ }
293
+
294
+ .project-thumb img {
295
+ height: 100%;
296
+ inset: 0;
297
+ object-fit: cover;
298
+ position: absolute;
299
+ width: 100%;
300
+ }
301
+
302
+ .project-thumb-icon {
303
+ color: var(--text-muted);
304
+ font-size: 20px;
305
+ }
306
+
307
+ .project-card .project-thumb-icon {
308
+ font-size: 28px;
309
+ }
310
+
311
+ .project-actions {
312
+ display: flex;
313
+ gap: var(--space-1);
314
+ }
315
+
316
+ .project-action {
317
+ align-items: center;
318
+ background: rgba(5, 7, 10, 0.82);
319
+ border: 1px solid var(--border-strong);
320
+ border-radius: var(--radius-sm);
321
+ box-shadow: var(--shadow-sm);
322
+ color: var(--text-primary);
323
+ display: flex;
324
+ font-size: 12px;
325
+ height: 26px;
326
+ justify-content: center;
327
+ text-decoration: none;
328
+ transition: background var(--duration-fast) var(--ease-standard),
329
+ border-color var(--duration-fast) var(--ease-standard);
330
+ width: 26px;
331
+ }
332
+
333
+ .project-action:hover {
334
+ background: rgba(5, 7, 10, 0.95);
335
+ border-color: var(--text-secondary);
336
+ }
337
+
338
+ .project-action-danger:hover {
339
+ border-color: var(--accent-danger);
340
+ color: var(--accent-danger);
341
+ }
342
+
343
+ /* Empty / no-results states */
344
+ .open-project-state {
345
+ align-items: center;
346
+ color: var(--text-muted);
347
+ display: flex;
348
+ flex-direction: column;
349
+ gap: var(--space-3);
350
+ padding: var(--space-6) 0;
351
+ text-align: center;
352
+ }
353
+
354
+ .open-project-state-icon {
355
+ color: var(--text-muted);
356
+ font-size: 32px;
357
+ }
358
+
359
+ .open-project-state p {
360
+ color: var(--text-secondary);
361
+ font-size: 14px;
362
+ margin: 0;
363
+ }
@@ -0,0 +1,166 @@
1
+ /* Quick-view landing page (index.html's {% else %} branch, no datasource
2
+ loaded yet). Reuses the shared design tokens from tokens.css (loaded by
3
+ base.html on every page) so this matches the viewer's look. */
4
+
5
+ .quick-view-landing {
6
+ align-items: center;
7
+ background: var(--surface-0);
8
+ box-sizing: border-box;
9
+ display: flex;
10
+ height: 95vh;
11
+ justify-content: center;
12
+ overflow: hidden;
13
+ padding: var(--space-6);
14
+ position: relative;
15
+ width: 100vw;
16
+ }
17
+
18
+ .quick-view-landing::before {
19
+ animation: quick-view-drift 24s ease-in-out infinite alternate;
20
+ background:
21
+ radial-gradient(circle at 20% 30%, var(--accent-channel-soft), transparent 45%),
22
+ radial-gradient(circle at 80% 70%, var(--accent-gate-soft), transparent 45%);
23
+ content: "";
24
+ inset: -20%;
25
+ opacity: 0.35;
26
+ position: absolute;
27
+ z-index: 0;
28
+ }
29
+
30
+ @keyframes quick-view-drift {
31
+ 0% { transform: translate(-3%, -2%) scale(1); }
32
+ 100% { transform: translate(3%, 2%) scale(1.08); }
33
+ }
34
+
35
+ @media (prefers-reduced-motion: reduce) {
36
+ .quick-view-landing::before {
37
+ animation: none;
38
+ }
39
+ }
40
+
41
+ .quick-view-card {
42
+ box-sizing: border-box;
43
+ max-width: 640px;
44
+ position: relative;
45
+ text-align: center;
46
+ width: 100%;
47
+ z-index: 1;
48
+ }
49
+
50
+ .quick-view-card h1 {
51
+ color: var(--text-primary);
52
+ font-size: 28px;
53
+ font-weight: 700;
54
+ margin: var(--space-1) 0 var(--space-2);
55
+ }
56
+
57
+ .quick-view-subtitle {
58
+ color: var(--text-secondary);
59
+ font-size: 14px;
60
+ margin: 0 0 var(--space-5);
61
+ }
62
+
63
+ .quick-view-path-fallback {
64
+ margin-top: var(--space-5);
65
+ }
66
+
67
+ .quick-view-path-label {
68
+ color: var(--text-secondary);
69
+ display: block;
70
+ font-size: 12px;
71
+ font-weight: 600;
72
+ letter-spacing: 0.02em;
73
+ text-align: left;
74
+ text-transform: uppercase;
75
+ margin-bottom: var(--space-2);
76
+ }
77
+
78
+ .quick-view-path-row {
79
+ display: flex;
80
+ gap: var(--space-2);
81
+ }
82
+
83
+ .quick-view-path-row input[type="text"] {
84
+ background: var(--surface-1);
85
+ border: 1px solid var(--border-strong);
86
+ border-radius: var(--radius-md);
87
+ color: var(--text-primary);
88
+ flex: 1;
89
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
90
+ font-size: 15px;
91
+ min-width: 0;
92
+ padding: 14px var(--space-4);
93
+ }
94
+
95
+ .quick-view-path-row input[type="text"]:focus {
96
+ border-color: var(--accent-channel);
97
+ outline: none;
98
+ }
99
+
100
+ .quick-view-path-row input[type="text"].is-invalid {
101
+ border-color: var(--accent-danger);
102
+ }
103
+
104
+ .quick-view-path-row .sidebar-action {
105
+ /* .sidebar-action (viewer.css) is width: 100% for its usual full-width
106
+ sidebar buttons -- override back to content width so it doesn't eat
107
+ the flex row meant for the path input. */
108
+ flex: 0 0 auto;
109
+ font-size: 14px;
110
+ padding: 0 var(--space-5);
111
+ width: auto;
112
+ }
113
+
114
+ .quick-view-dropzone {
115
+ background: var(--surface-1);
116
+ border: 2px dashed var(--border-strong);
117
+ border-radius: var(--radius-lg);
118
+ cursor: pointer;
119
+ padding: var(--space-5) var(--space-4);
120
+ transition: border-color var(--duration-base) var(--ease-standard),
121
+ background var(--duration-base) var(--ease-standard);
122
+ }
123
+
124
+ .quick-view-dropzone:hover,
125
+ .quick-view-dropzone:focus-visible {
126
+ background: var(--surface-2);
127
+ border-color: var(--accent-channel);
128
+ }
129
+
130
+ .quick-view-dropzone-icon {
131
+ color: var(--accent-channel);
132
+ font-size: 36px;
133
+ }
134
+
135
+ .quick-view-dropzone-text {
136
+ color: var(--text-primary);
137
+ font-size: 15px;
138
+ font-weight: 600;
139
+ margin-top: var(--space-3);
140
+ }
141
+
142
+ .quick-view-dropzone-hint {
143
+ color: var(--text-muted);
144
+ font-size: 12px;
145
+ margin-top: var(--space-1);
146
+ }
147
+
148
+ .quick-view-status {
149
+ color: var(--text-secondary);
150
+ font-size: 13px;
151
+ margin-top: var(--space-4);
152
+ }
153
+
154
+ .quick-view-status.error {
155
+ color: var(--accent-danger);
156
+ }
157
+
158
+ .quick-view-footer {
159
+ color: var(--text-muted);
160
+ font-size: 12px;
161
+ margin: var(--space-5) 0 0;
162
+ }
163
+
164
+ .quick-view-footer a {
165
+ color: var(--accent-channel);
166
+ }
@@ -0,0 +1,51 @@
1
+ /* Shared design tokens, loaded once in base.html so every page (including
2
+ ones that don't load viewer.css/import.css, e.g. the navbar on the plain
3
+ quick-view/channel-match pages) has them available. Previously this :root
4
+ block was duplicated separately in viewer.css and import.css, and had
5
+ already drifted between the two (different --duration-base, import.css
6
+ missing --accent-gate tokens, viewer.css missing --accent-warning,
7
+ --accent-success and --accent-danger-soft). This file is the single
8
+ source of truth; the --duration-base value below (180ms) is viewer.css's
9
+ former value, kept since it's the larger/more actively maintained
10
+ consumer. */
11
+ :root {
12
+ --surface-0: #05070a;
13
+ --surface-1: #0b0f15;
14
+ --surface-2: #121820;
15
+ --border-subtle: rgba(255, 255, 255, 0.12);
16
+ --border-strong: rgba(255, 255, 255, 0.22);
17
+ --text-primary: #f8fafc;
18
+ --text-secondary: #d8e1ed;
19
+ --text-muted: #8ea0b8;
20
+ --accent-gate: #f36f45;
21
+ --accent-gate-soft: rgba(243, 111, 69, 0.34);
22
+ --accent-channel: #38bdf8;
23
+ --accent-channel-soft: rgba(56, 189, 248, 0.36);
24
+ --accent-danger: #f87171;
25
+ --accent-danger-soft: rgba(248, 113, 113, 0.14);
26
+ --accent-warning: #f3b845;
27
+ --accent-warning-soft: rgba(243, 184, 69, 0.14);
28
+ --accent-success: #34d399;
29
+ --space-1: 4px;
30
+ --space-2: 8px;
31
+ --space-3: 12px;
32
+ --space-4: 16px;
33
+ --space-5: 20px;
34
+ --space-6: 24px;
35
+ --radius-sm: 6px;
36
+ --radius-md: 8px;
37
+ --radius-lg: 12px;
38
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.25);
39
+ --shadow-md: 0 10px 28px rgba(0, 0, 0, 0.35);
40
+ --shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.4);
41
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
42
+ --duration-fast: 120ms;
43
+ --duration-base: 180ms;
44
+ }
45
+
46
+ @media (prefers-reduced-motion: reduce) {
47
+ :root {
48
+ --duration-fast: 0ms;
49
+ --duration-base: 0ms;
50
+ }
51
+ }