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.
- plexora/__init__.py +129 -0
- plexora/__main__.py +15 -0
- plexora/_url.py +105 -0
- plexora/api/__init__.py +55 -0
- plexora/api/dataset.py +398 -0
- plexora/api/http.py +19 -0
- plexora/api/plugin.py +541 -0
- plexora/api/store.py +221 -0
- plexora/cli.py +777 -0
- plexora/client/dist/354_bundle.js +2 -0
- plexora/client/dist/354_bundle.js.LICENSE.txt +20 -0
- plexora/client/dist/418_bundle.js +2 -0
- plexora/client/dist/418_bundle.js.LICENSE.txt +1 -0
- plexora/client/dist/693b935cb1f907814be9c6199a68c217.svg +19 -0
- plexora/client/dist/713c134ff47cd328a5b711526f151082.svg +18 -0
- plexora/client/dist/770_bundle.js +1 -0
- plexora/client/dist/ff743f408972e0e96ca9153ed5ae4c83.svg +23 -0
- plexora/client/dist/vendor_bundle.js +2 -0
- plexora/client/dist/vendor_bundle.js.LICENSE.txt +308 -0
- plexora/client/external/openseadragon-bin-2.4.0/LICENSE.txt +28 -0
- plexora/client/external/openseadragon-bin-2.4.0/canvas-overlay-hd.js +140 -0
- plexora/client/external/openseadragon-bin-2.4.0/changelog.txt +501 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/.gitattributes +17 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/LICENSE.txt +116 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/Toolbar.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/fullpage.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/home.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/next.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/previous.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateleft.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateright.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/zoom.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/README.md +9 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-scalebar.js +562 -0
- plexora/client/src/css/import.css +474 -0
- plexora/client/src/css/main.css +903 -0
- plexora/client/src/css/openProject.css +363 -0
- plexora/client/src/css/quickView.css +166 -0
- plexora/client/src/css/tokens.css +51 -0
- plexora/client/src/css/viewer.css +1655 -0
- plexora/client/src/img/apple-touch-icon.png +0 -0
- plexora/client/src/img/favicon.ico +0 -0
- plexora/client/src/img/logo.ai +8892 -33
- plexora/client/src/img/logo.svg +1 -0
- plexora/client/src/img/logo_with_text.ai +9011 -34
- plexora/client/src/img/logo_with_text.svg +1 -0
- plexora/client/src/js/main.js +704 -0
- plexora/client/src/js/pluginRegistry.js +108 -0
- plexora/client/src/js/services/appStatus.js +286 -0
- plexora/client/src/js/services/browsePicker.js +73 -0
- plexora/client/src/js/services/dataLayer.js +400 -0
- plexora/client/src/js/services/datasetContext.js +143 -0
- plexora/client/src/js/services/glRenderer.js +143 -0
- plexora/client/src/js/services/importFormValidation.js +257 -0
- plexora/client/src/js/services/numericData.js +100 -0
- plexora/client/src/js/services/passVariablesToFrontend.js +20 -0
- plexora/client/src/js/services/simpleEventHandler.js +25 -0
- plexora/client/src/js/vendor.js +29 -0
- plexora/client/src/js/views/channelList.js +663 -0
- plexora/client/src/js/views/colorSwatchPicker.js +202 -0
- plexora/client/src/js/views/columnClassifier.js +146 -0
- plexora/client/src/js/views/coordinateField.js +133 -0
- plexora/client/src/js/views/dataSourceField.js +276 -0
- plexora/client/src/js/views/imageViewer.js +3306 -0
- plexora/client/src/js/views/miniMap.js +787 -0
- plexora/client/src/js/views/navbarControls.js +178 -0
- plexora/client/src/js/views/openProjectPage.js +239 -0
- plexora/client/src/js/views/projectEdit.js +335 -0
- plexora/client/src/js/views/quickViewLanding.js +136 -0
- plexora/client/src/js/views/rainbow.js +326 -0
- plexora/client/src/js/views/requirementsModal.js +572 -0
- plexora/client/src/js/views/rgbImageViewer.js +115 -0
- plexora/client/src/js/views/searchableSelect.js +411 -0
- plexora/client/src/js/views/segmentationProgress.js +122 -0
- plexora/client/src/js/views/toolLoader.js +747 -0
- plexora/client/src/js/views/viewerControls.js +689 -0
- plexora/client/src/js/views/viewerManager.js +434 -0
- plexora/client/src/js/views/viewerSidebar.js +1117 -0
- plexora/client/src/js/workers/tileDecoder.js +130 -0
- plexora/client/src/shaders/frag.glsl +528 -0
- plexora/client/src/shaders/vert.glsl +12 -0
- plexora/client/templates/base.html +212 -0
- plexora/client/templates/index.html +238 -0
- plexora/client/templates/open_project.html +96 -0
- plexora/client/templates/project_columns.html +86 -0
- plexora/client/templates/project_edit.html +196 -0
- plexora/client/templates/upload.html +118 -0
- plexora/connect.py +528 -0
- plexora/datasource.py +782 -0
- plexora/jupyter.py +406 -0
- plexora/notebook_env.py +232 -0
- plexora/paths.py +486 -0
- plexora/plugins/__init__.py +12 -0
- plexora/plugins/cell_explorer/__init__.py +100 -0
- plexora/plugins/cell_explorer/server/__init__.py +11 -0
- plexora/plugins/cell_explorer/server/routes.py +167 -0
- plexora/plugins/cell_explorer/server/state.py +281 -0
- plexora/plugins/cell_explorer/server/values.py +145 -0
- plexora/plugins/cell_explorer/server/variables.py +367 -0
- plexora/plugins/cell_explorer/static/cellExplorerApi.js +158 -0
- plexora/plugins/cell_explorer/static/cellExplorerColors.js +316 -0
- plexora/plugins/cell_explorer/static/cellExplorerContinuous.js +403 -0
- plexora/plugins/cell_explorer/static/cellExplorerFigureBridge.js +133 -0
- plexora/plugins/cell_explorer/static/cellExplorerLegend.js +188 -0
- plexora/plugins/cell_explorer/static/cellExplorerRoiBridge.js +822 -0
- plexora/plugins/cell_explorer/static/cellExplorerSidebarController.js +826 -0
- plexora/plugins/cell_explorer/static/cellExplorerState.js +372 -0
- plexora/plugins/cell_explorer/static/cell_explorer.css +752 -0
- plexora/plugins/cell_explorer/templates/cell_explorer/panel.html +137 -0
- plexora/plugins/figure_builder/__init__.py +125 -0
- plexora/plugins/figure_builder/server/__init__.py +7 -0
- plexora/plugins/figure_builder/server/compose.py +365 -0
- plexora/plugins/figure_builder/server/export.py +784 -0
- plexora/plugins/figure_builder/server/export_jobs.py +148 -0
- plexora/plugins/figure_builder/server/operations.py +556 -0
- plexora/plugins/figure_builder/server/pixels.py +142 -0
- plexora/plugins/figure_builder/server/provenance.py +174 -0
- plexora/plugins/figure_builder/server/render.py +278 -0
- plexora/plugins/figure_builder/server/repository.py +701 -0
- plexora/plugins/figure_builder/server/routes.py +594 -0
- plexora/plugins/figure_builder/server/schema.py +1023 -0
- plexora/plugins/figure_builder/server/sources.py +120 -0
- plexora/plugins/figure_builder/server/textmetrics.py +155 -0
- plexora/plugins/figure_builder/static/figureActions.js +363 -0
- plexora/plugins/figure_builder/static/figureBuilderApi.js +255 -0
- plexora/plugins/figure_builder/static/figureCanvas.js +2362 -0
- plexora/plugins/figure_builder/static/figureCaptureBoxes.js +369 -0
- plexora/plugins/figure_builder/static/figureCaptureDock.js +466 -0
- plexora/plugins/figure_builder/static/figureCaptureTool.js +1034 -0
- plexora/plugins/figure_builder/static/figureConfirm.js +136 -0
- plexora/plugins/figure_builder/static/figureContextBar.js +1193 -0
- plexora/plugins/figure_builder/static/figureContextMenu.js +253 -0
- plexora/plugins/figure_builder/static/figureDocumentState.js +275 -0
- plexora/plugins/figure_builder/static/figureExportUi.js +174 -0
- plexora/plugins/figure_builder/static/figureLibrary.js +247 -0
- plexora/plugins/figure_builder/static/figureQuickEdit.js +628 -0
- plexora/plugins/figure_builder/static/figureRichText.js +634 -0
- plexora/plugins/figure_builder/static/figureSceneSnapshot.js +361 -0
- plexora/plugins/figure_builder/static/figureSchema.js +218 -0
- plexora/plugins/figure_builder/static/figureSidebarController.js +1159 -0
- plexora/plugins/figure_builder/static/figureTextEditor.js +503 -0
- plexora/plugins/figure_builder/static/figureTextPanel.js +491 -0
- plexora/plugins/figure_builder/static/figureViewOptions.js +273 -0
- plexora/plugins/figure_builder/static/figureWorkspace.js +2030 -0
- plexora/plugins/figure_builder/static/figure_builder.css +3292 -0
- plexora/plugins/figure_builder/templates/figure_builder/library.html +74 -0
- plexora/plugins/figure_builder/templates/figure_builder/workspace.html +27 -0
- plexora/plugins/figure_builder/templates/figure_builder/workspace_body.html +458 -0
- plexora/plugins/gating/__init__.py +76 -0
- plexora/plugins/gating/server/__init__.py +0 -0
- plexora/plugins/gating/server/anndata_gates.py +367 -0
- plexora/plugins/gating/server/database.py +16 -0
- plexora/plugins/gating/server/model.py +320 -0
- plexora/plugins/gating/server/routes.py +235 -0
- plexora/plugins/gating/static/csvGatingList.js +947 -0
- plexora/plugins/gating/static/gating.css +289 -0
- plexora/plugins/gating/static/gatingApi.js +221 -0
- plexora/plugins/gating/static/gatingSidebarController.js +513 -0
- plexora/plugins/gating/templates/gating/legacy.html +26 -0
- plexora/plugins/gating/templates/gating/panel.html +69 -0
- plexora/plugins/roi/__init__.py +95 -0
- plexora/plugins/roi/server/__init__.py +8 -0
- plexora/plugins/roi/server/adapters.py +655 -0
- plexora/plugins/roi/server/geojson.py +267 -0
- plexora/plugins/roi/server/geometry.py +181 -0
- plexora/plugins/roi/server/mapping.py +169 -0
- plexora/plugins/roi/server/operations.py +293 -0
- plexora/plugins/roi/server/repository.py +215 -0
- plexora/plugins/roi/server/routes.py +409 -0
- plexora/plugins/roi/server/schema.py +323 -0
- plexora/plugins/roi/static/roi.css +583 -0
- plexora/plugins/roi/static/roiApi.js +177 -0
- plexora/plugins/roi/static/roiFigureBridge.js +107 -0
- plexora/plugins/roi/static/roiGeometry.js +350 -0
- plexora/plugins/roi/static/roiRenderer.js +278 -0
- plexora/plugins/roi/static/roiSidebarController.js +1038 -0
- plexora/plugins/roi/static/roiState.js +518 -0
- plexora/plugins/roi/static/roiTools.js +993 -0
- plexora/plugins/roi/templates/roi/panel.html +240 -0
- plexora/proxy.py +57 -0
- plexora/server/models/adapters/__init__.py +94 -0
- plexora/server/models/adapters/anndata_adapter.py +388 -0
- plexora/server/models/adapters/base.py +93 -0
- plexora/server/models/adapters/classify.py +192 -0
- plexora/server/models/adapters/csv_adapter.py +105 -0
- plexora/server/models/adapters/inspection.py +265 -0
- plexora/server/models/adapters/spatialdata_adapter.py +248 -0
- plexora/server/models/centroid_tiles.py +305 -0
- plexora/server/models/data_model.py +1659 -0
- plexora/server/models/database_model.py +169 -0
- plexora/server/models/project.py +1270 -0
- plexora/server/plugins.py +199 -0
- plexora/server/routes/browse_routes.py +41 -0
- plexora/server/routes/data_routes.py +294 -0
- plexora/server/routes/import_routes.py +603 -0
- plexora/server/routes/page_routes.py +139 -0
- plexora/server/routes/project_routes.py +438 -0
- plexora/server/routes/quick_view_routes.py +62 -0
- plexora/server/routes/system_routes.py +39 -0
- plexora/server/routes/tool_routes.py +418 -0
- plexora/server/utils/addHEColumns.py +11 -0
- plexora/server/utils/fast_png.py +97 -0
- plexora/server/utils/fullConversion.py +50 -0
- plexora/server/utils/native_dialog.py +168 -0
- plexora/server/utils/pre_normalization.py +47 -0
- plexora/server/utils/segmentation_pyramid.py +598 -0
- plexora/server/utils/smallestenclosingcircle.py +126 -0
- plexora/server/utils/tiffsurgeon.py +372 -0
- plexora/server_cli.py +48 -0
- plexora/test.py +0 -0
- plexora-0.0.1.dist-info/METADATA +341 -0
- plexora-0.0.1.dist-info/RECORD +248 -0
- plexora-0.0.1.dist-info/WHEEL +5 -0
- plexora-0.0.1.dist-info/entry_points.txt +12 -0
- plexora-0.0.1.dist-info/licenses/LICENSE +207 -0
- plexora-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,903 @@
|
|
|
1
|
+
body {
|
|
2
|
+
/* !important: Bootstrap's reboot (injected by vendor_bundle.js after this
|
|
3
|
+
stylesheet) sets its own `body { background-color: var(--bs-body-bg) }`
|
|
4
|
+
-- same specificity, later in the cascade, so it otherwise wins and
|
|
5
|
+
leaves the page white. Same override pattern #topBar below already
|
|
6
|
+
uses against Bootstrap. */
|
|
7
|
+
background-color: var(--surface-0) !important;
|
|
8
|
+
font-family: 'Source Sans Pro', sans-serif;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#topBar {
|
|
12
|
+
background-color: var(--surface-1) !important;
|
|
13
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
14
|
+
height: 5vh;
|
|
15
|
+
max-height: 5vh;
|
|
16
|
+
left: 0;
|
|
17
|
+
padding: 0 var(--space-4);
|
|
18
|
+
position: relative;
|
|
19
|
+
margin: 0;
|
|
20
|
+
top: 0;
|
|
21
|
+
width: 100vw;
|
|
22
|
+
z-index: 101;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#title {
|
|
26
|
+
align-items: center;
|
|
27
|
+
color: var(--text-primary);
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
font-size: 16px;
|
|
30
|
+
gap: var(--space-2);
|
|
31
|
+
text-decoration: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#title:hover,
|
|
35
|
+
#title:focus {
|
|
36
|
+
color: var(--text-primary);
|
|
37
|
+
text-decoration: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#navbar-logo {
|
|
41
|
+
height: 24px;
|
|
42
|
+
width: auto;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#topBar .nav-link {
|
|
46
|
+
color: var(--text-secondary);
|
|
47
|
+
font-size: 15px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#topBar .nav-link:hover,
|
|
51
|
+
#topBar .nav-link:focus,
|
|
52
|
+
#topBar .dropdown.show > .nav-link {
|
|
53
|
+
color: var(--text-primary);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#topBar .dropdown-menu {
|
|
57
|
+
background-color: var(--surface-2);
|
|
58
|
+
border: 1px solid var(--border-subtle);
|
|
59
|
+
border-radius: var(--radius-md);
|
|
60
|
+
box-shadow: var(--shadow-md);
|
|
61
|
+
padding: var(--space-2) 0;
|
|
62
|
+
min-width: 220px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#topBar .dropdown-item {
|
|
66
|
+
color: var(--text-secondary);
|
|
67
|
+
font-size: 13px;
|
|
68
|
+
padding: var(--space-1) var(--space-3);
|
|
69
|
+
background-color: transparent;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#topBar .dropdown-item:hover,
|
|
73
|
+
#topBar .dropdown-item:focus {
|
|
74
|
+
color: var(--text-primary);
|
|
75
|
+
background-color: var(--surface-1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#topBar .dropdown-item.disabled,
|
|
79
|
+
#topBar .dropdown-item:disabled {
|
|
80
|
+
color: var(--text-muted);
|
|
81
|
+
pointer-events: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#topBar .dropdown-header {
|
|
85
|
+
color: var(--text-muted);
|
|
86
|
+
font-size: 11px;
|
|
87
|
+
text-transform: uppercase;
|
|
88
|
+
letter-spacing: 0.04em;
|
|
89
|
+
padding: var(--space-1) var(--space-3);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#topBar .dropdown-divider {
|
|
93
|
+
border-top: 1px solid var(--border-subtle);
|
|
94
|
+
margin: var(--space-1) 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
#topBar .nav-check-item {
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: var(--space-2);
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#topBar .nav-check-item input[type="checkbox"] {
|
|
105
|
+
margin: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#topBar .nav-check-item:has(input:disabled) {
|
|
109
|
+
color: var(--text-muted);
|
|
110
|
+
cursor: default;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* File > Export Image submenu -- a plain nested .dropdown-menu (inherits
|
|
114
|
+
the themed look above) shown via hover/focus/click rather than
|
|
115
|
+
Bootstrap's own JS, since bootstrap's data-api isn't wired for nested
|
|
116
|
+
dropdowns here. See navbarControls.js for the click-to-toggle fallback
|
|
117
|
+
(touch/keyboard) that adds/removes the "open" class below. */
|
|
118
|
+
#topBar .nav-submenu-parent {
|
|
119
|
+
align-items: center;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
display: flex;
|
|
122
|
+
gap: var(--space-3);
|
|
123
|
+
justify-content: space-between;
|
|
124
|
+
position: relative;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#topBar .nav-submenu-parent.disabled {
|
|
128
|
+
color: var(--text-muted);
|
|
129
|
+
cursor: default;
|
|
130
|
+
pointer-events: none;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#topBar .nav-submenu-caret {
|
|
134
|
+
font-size: 10px;
|
|
135
|
+
opacity: 0.7;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
#topBar .nav-submenu {
|
|
139
|
+
display: none;
|
|
140
|
+
left: 100%;
|
|
141
|
+
margin: 0;
|
|
142
|
+
position: absolute;
|
|
143
|
+
top: -1px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#topBar .nav-submenu-parent:hover .nav-submenu,
|
|
147
|
+
#topBar .nav-submenu-parent:focus-within .nav-submenu,
|
|
148
|
+
#topBar .nav-submenu-parent.open .nav-submenu {
|
|
149
|
+
display: block;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Fast custom tooltip -- the native `title` attribute has a browser-enforced
|
|
153
|
+
~1s hover delay with no CSS way to shorten it. Opt in per-element with
|
|
154
|
+
data-tooltip="..." wherever that delay actually matters (e.g. HD Mode,
|
|
155
|
+
both navbar and sidebar); everywhere else keeps using plain `title`. */
|
|
156
|
+
[data-tooltip] {
|
|
157
|
+
position: relative;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
[data-tooltip]::after {
|
|
161
|
+
background: var(--surface-2);
|
|
162
|
+
border: 1px solid var(--border-subtle);
|
|
163
|
+
border-radius: var(--radius-sm);
|
|
164
|
+
bottom: calc(100% + 6px);
|
|
165
|
+
box-shadow: var(--shadow-sm);
|
|
166
|
+
color: var(--text-primary);
|
|
167
|
+
content: attr(data-tooltip);
|
|
168
|
+
font-size: 12px;
|
|
169
|
+
font-weight: 400;
|
|
170
|
+
left: 50%;
|
|
171
|
+
max-width: 220px;
|
|
172
|
+
opacity: 0;
|
|
173
|
+
padding: 6px 8px;
|
|
174
|
+
pointer-events: none;
|
|
175
|
+
position: absolute;
|
|
176
|
+
text-align: left;
|
|
177
|
+
transform: translateX(-50%);
|
|
178
|
+
transition: opacity 80ms ease;
|
|
179
|
+
white-space: normal;
|
|
180
|
+
z-index: 400;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
[data-tooltip]:hover::after,
|
|
184
|
+
[data-tooltip]:focus-visible::after {
|
|
185
|
+
opacity: 1;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/*LOADING SPINNER SECTION*/
|
|
189
|
+
.lds-ellipsis {
|
|
190
|
+
display: inline-block;
|
|
191
|
+
position: relative;
|
|
192
|
+
width: 20px;
|
|
193
|
+
height: 20px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.lds-ellipsis div {
|
|
197
|
+
position: absolute;
|
|
198
|
+
top: 33px;
|
|
199
|
+
width: 13px;
|
|
200
|
+
height: 13px;
|
|
201
|
+
border-radius: 50%;
|
|
202
|
+
background: #000000;
|
|
203
|
+
animation-timing-function: cubic-bezier(0, 1, 1, 0);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
.lds-ellipsis div:nth-child(1) {
|
|
208
|
+
left: 8px;
|
|
209
|
+
animation: lds-ellipsis1 0.6s infinite;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.lds-ellipsis div:nth-child(2) {
|
|
213
|
+
left: 8px;
|
|
214
|
+
animation: lds-ellipsis2 0.6s infinite;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.lds-ellipsis div:nth-child(3) {
|
|
218
|
+
left: 32px;
|
|
219
|
+
animation: lds-ellipsis2 0.6s infinite;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.lds-ellipsis div:nth-child(4) {
|
|
223
|
+
left: 56px;
|
|
224
|
+
animation: lds-ellipsis3 0.6s infinite;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@keyframes lds-ellipsis1 {
|
|
228
|
+
0% {
|
|
229
|
+
transform: scale(0);
|
|
230
|
+
}
|
|
231
|
+
100% {
|
|
232
|
+
transform: scale(1);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
@keyframes lds-ellipsis3 {
|
|
237
|
+
0% {
|
|
238
|
+
transform: scale(1);
|
|
239
|
+
}
|
|
240
|
+
100% {
|
|
241
|
+
transform: scale(0);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@keyframes lds-ellipsis2 {
|
|
246
|
+
0% {
|
|
247
|
+
transform: translate(0, 0);
|
|
248
|
+
}
|
|
249
|
+
100% {
|
|
250
|
+
transform: translate(24px, 0);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/*END OF LOADING SPINNER SECTION*/
|
|
255
|
+
|
|
256
|
+
#channel_list {
|
|
257
|
+
width: 100%;
|
|
258
|
+
height: 80vh;
|
|
259
|
+
font-size: 10pt;
|
|
260
|
+
overflow-y: auto;
|
|
261
|
+
overflow-x: hidden;
|
|
262
|
+
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#upload-container {
|
|
267
|
+
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
268
|
+
padding: 20px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
#channel_list .list-group-item {
|
|
272
|
+
padding: .20rem 0.5rem;
|
|
273
|
+
border: 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
#channel_list .active {
|
|
277
|
+
background-color: rgba(0, 0, 0, 0.75);
|
|
278
|
+
border-top: 1px solid rgba(255, 255, 255, 0.5);
|
|
279
|
+
border-right: none;
|
|
280
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.5);
|
|
281
|
+
border-left: none;
|
|
282
|
+
height: 90px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
#channel_list .list-group {
|
|
286
|
+
border-radius: 0rem;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
#channel_list_loader {
|
|
290
|
+
margin-left: 33px;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.list-button {
|
|
294
|
+
cursor: pointer;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.auto-loading {
|
|
298
|
+
opacity: 50%;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.auto-btn {
|
|
302
|
+
float: right;
|
|
303
|
+
padding-top: 0;
|
|
304
|
+
padding-bottom: 0;
|
|
305
|
+
border: 1px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.image_distribution_line {
|
|
309
|
+
stroke: rgba(130, 130, 130, 0.5);
|
|
310
|
+
stroke-width: 4px;
|
|
311
|
+
fill: none;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.gmm_line {
|
|
315
|
+
stroke-width: 1px;
|
|
316
|
+
stroke-opacity: 0.75;
|
|
317
|
+
fill: none;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.slider .handle {
|
|
321
|
+
fill: #fff;
|
|
322
|
+
stroke: #000;
|
|
323
|
+
stroke-opacity: .5;
|
|
324
|
+
stroke-width: 1.25px;
|
|
325
|
+
cursor: move;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.slider text {
|
|
329
|
+
margin-top: -10px;
|
|
330
|
+
font-size: 10px;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
nav {
|
|
335
|
+
margin-bottom: 10px;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.channel-col {
|
|
339
|
+
margin: 0;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.selected-channels-header {
|
|
343
|
+
color: white;
|
|
344
|
+
font-size: 0.6rem;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.bold-selections-header * {
|
|
348
|
+
font-weight: bold;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
#upload-container * {
|
|
352
|
+
font-size: 0.8rem;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
#upload-container label {
|
|
356
|
+
font-weight: bold;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.progress-bar {
|
|
360
|
+
background-color: #5ca3c1;
|
|
361
|
+
role: progressbar;
|
|
362
|
+
width: 0%;
|
|
363
|
+
aria-valuenow: 0;
|
|
364
|
+
aria-valuemin: 0;
|
|
365
|
+
aria-valuemax: 100;
|
|
366
|
+
height: 40px;
|
|
367
|
+
border-radius: 2px;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
#upload-container .progress-bar-label {
|
|
371
|
+
top: 50%;
|
|
372
|
+
vertical-align: middle;
|
|
373
|
+
font-size: 0.5rem;
|
|
374
|
+
margin: 3px;
|
|
375
|
+
white-space: nowrap;
|
|
376
|
+
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
#upload-container .progress {
|
|
380
|
+
margin: 5px;
|
|
381
|
+
width: 100%;
|
|
382
|
+
display: none;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#upload-parent {
|
|
386
|
+
width: 800px;
|
|
387
|
+
background-color: rgba(255, 255, 255, 1);
|
|
388
|
+
padding: 10px;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
#upload_button {
|
|
392
|
+
height: 40px
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
.delete-button {
|
|
397
|
+
padding-left: 5px;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.fa-pencil, .fa-trash {
|
|
401
|
+
color: black;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.plexora-quit-overlay {
|
|
405
|
+
align-items: center;
|
|
406
|
+
background: var(--surface-0);
|
|
407
|
+
box-sizing: border-box;
|
|
408
|
+
color: var(--text-primary);
|
|
409
|
+
display: flex;
|
|
410
|
+
flex-direction: column;
|
|
411
|
+
gap: var(--space-3);
|
|
412
|
+
height: 100vh;
|
|
413
|
+
justify-content: center;
|
|
414
|
+
text-align: center;
|
|
415
|
+
width: 100vw;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.plexora-quit-icon {
|
|
419
|
+
color: var(--text-muted);
|
|
420
|
+
font-size: 40px;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.plexora-quit-overlay p {
|
|
424
|
+
color: var(--text-secondary);
|
|
425
|
+
font-size: 14px;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
/* ---------------------------------------------------------------------------
|
|
430
|
+
App-wide status indicator (appStatus.js). Pinned to the far right of the
|
|
431
|
+
navbar on every page that extends base.html.
|
|
432
|
+
|
|
433
|
+
Colours come from the shared accent tokens rather than literals so the three
|
|
434
|
+
states stay consistent with the rest of the UI:
|
|
435
|
+
--accent-success green up to date
|
|
436
|
+
--accent-warning orange working
|
|
437
|
+
--accent-danger red disconnected / error
|
|
438
|
+
--------------------------------------------------------------------------- */
|
|
439
|
+
.app-status {
|
|
440
|
+
align-items: center;
|
|
441
|
+
display: flex;
|
|
442
|
+
flex-shrink: 0;
|
|
443
|
+
gap: var(--space-2);
|
|
444
|
+
/* .navbar-nav carries me-auto, so this lands hard right of the menus. */
|
|
445
|
+
margin-left: auto;
|
|
446
|
+
font-size: 12px;
|
|
447
|
+
letter-spacing: 0.01em;
|
|
448
|
+
line-height: 1;
|
|
449
|
+
user-select: none;
|
|
450
|
+
white-space: nowrap;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.app-status-glyph {
|
|
454
|
+
background-color: var(--accent-success);
|
|
455
|
+
border-radius: 50%;
|
|
456
|
+
display: inline-block;
|
|
457
|
+
height: 9px;
|
|
458
|
+
width: 9px;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.app-status-label {
|
|
462
|
+
color: var(--text-muted);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.app-status[data-state="busy"] .app-status-glyph {
|
|
466
|
+
background-color: var(--accent-warning);
|
|
467
|
+
/* The shape-shifting glyph. Pure CSS -- morphing border-radius plus a slow
|
|
468
|
+
rotate reads as one small object changing form, with no SVG or library. */
|
|
469
|
+
animation: plexora-status-morph 1.6s var(--ease-standard) infinite;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.app-status[data-state="error"] .app-status-glyph {
|
|
473
|
+
background-color: var(--accent-danger);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.app-status[data-state="error"] .app-status-label {
|
|
477
|
+
color: var(--accent-danger);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/* Typing-like sweep across the label while work is in flight. */
|
|
481
|
+
.app-status[data-state="busy"] .app-status-label {
|
|
482
|
+
animation: plexora-status-shimmer 1.8s linear infinite;
|
|
483
|
+
background: linear-gradient(90deg,
|
|
484
|
+
var(--text-muted) 0%, var(--text-muted) 35%,
|
|
485
|
+
var(--text-primary) 50%,
|
|
486
|
+
var(--text-muted) 65%, var(--text-muted) 100%);
|
|
487
|
+
background-clip: text;
|
|
488
|
+
-webkit-background-clip: text;
|
|
489
|
+
color: transparent;
|
|
490
|
+
-webkit-text-fill-color: transparent;
|
|
491
|
+
background-size: 200% 100%;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
@keyframes plexora-status-morph {
|
|
495
|
+
0% { border-radius: 50%; transform: rotate(0deg) scale(1); }
|
|
496
|
+
30% { border-radius: 34% 66% 62% 38% / 38% 34% 66% 62%; transform: rotate(120deg) scale(0.8); }
|
|
497
|
+
60% { border-radius: 24%; transform: rotate(240deg) scale(1.06); }
|
|
498
|
+
100% { border-radius: 50%; transform: rotate(360deg) scale(1); }
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
@keyframes plexora-status-shimmer {
|
|
502
|
+
0% { background-position: 200% 0; }
|
|
503
|
+
100% { background-position: -200% 0; }
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* tokens.css already zeroes the duration tokens under this query; the status
|
|
507
|
+
animations are decorative, so drop them entirely rather than run them fast. */
|
|
508
|
+
@media (prefers-reduced-motion: reduce) {
|
|
509
|
+
.app-status[data-state="busy"] .app-status-glyph,
|
|
510
|
+
.app-status[data-state="busy"] .app-status-label {
|
|
511
|
+
animation: none;
|
|
512
|
+
}
|
|
513
|
+
.app-status[data-state="busy"] .app-status-label {
|
|
514
|
+
background: none;
|
|
515
|
+
color: var(--accent-warning);
|
|
516
|
+
-webkit-text-fill-color: var(--accent-warning);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/* ---------------------------------------------------------------------------
|
|
521
|
+
Segmentation-mask wait overlay (views/segmentationProgress.js)
|
|
522
|
+
|
|
523
|
+
Lives here rather than in import.css because both step-2 import pages use it
|
|
524
|
+
and only one of them loads import.css -- and because the overlay attaches to
|
|
525
|
+
<body>, so it is outside the .import-page wrapper those rules are scoped to.
|
|
526
|
+
--------------------------------------------------------------------------- */
|
|
527
|
+
.segmentation-progress-overlay {
|
|
528
|
+
align-items: center;
|
|
529
|
+
background: rgba(5, 7, 10, 0.82);
|
|
530
|
+
display: flex;
|
|
531
|
+
inset: 0;
|
|
532
|
+
justify-content: center;
|
|
533
|
+
position: fixed;
|
|
534
|
+
z-index: 1080;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.segmentation-progress-card {
|
|
538
|
+
background: var(--surface-1);
|
|
539
|
+
border: 1px solid var(--border-subtle);
|
|
540
|
+
border-radius: var(--radius-lg);
|
|
541
|
+
box-shadow: var(--shadow-md);
|
|
542
|
+
padding: var(--space-6);
|
|
543
|
+
width: min(420px, calc(100vw - 2 * var(--space-5)));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.segmentation-progress-title {
|
|
547
|
+
color: var(--text-primary);
|
|
548
|
+
font-size: 15px;
|
|
549
|
+
font-weight: 700;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.segmentation-progress-title.has-error {
|
|
553
|
+
color: var(--accent-danger);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.segmentation-progress-detail {
|
|
557
|
+
color: var(--text-muted);
|
|
558
|
+
font-size: 12px;
|
|
559
|
+
margin-top: var(--space-2);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.segmentation-progress-track {
|
|
563
|
+
background: var(--surface-2);
|
|
564
|
+
border-radius: var(--radius-sm);
|
|
565
|
+
height: 8px;
|
|
566
|
+
margin-top: var(--space-4);
|
|
567
|
+
overflow: hidden;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.segmentation-progress-fill {
|
|
571
|
+
background: var(--accent-channel);
|
|
572
|
+
height: 100%;
|
|
573
|
+
transition: width var(--duration-base) var(--ease-standard);
|
|
574
|
+
width: 0;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.segmentation-progress-fill.has-error {
|
|
578
|
+
background: var(--accent-danger);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/* Used until the job reports a percentage, so the panel never looks stalled
|
|
582
|
+
while the conversion is still opening a large mask. */
|
|
583
|
+
.segmentation-progress-fill.is-indeterminate {
|
|
584
|
+
animation: segmentation-progress-slide 1.1s ease-in-out infinite;
|
|
585
|
+
width: 35%;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
@keyframes segmentation-progress-slide {
|
|
589
|
+
0% { margin-left: -35%; }
|
|
590
|
+
100% { margin-left: 100%; }
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
@media (prefers-reduced-motion: reduce) {
|
|
594
|
+
.segmentation-progress-fill.is-indeterminate {
|
|
595
|
+
animation: none;
|
|
596
|
+
width: 100%;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.segmentation-progress-actions:not(:empty) {
|
|
601
|
+
margin-top: var(--space-5);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/* ------------------------------------------------------------------ */
|
|
605
|
+
/* Data-source field (dataSourceField.js) */
|
|
606
|
+
/* A path input, its pickers, and the table/image selects that appear */
|
|
607
|
+
/* only when the file forces the choice. Shared by the requirements */
|
|
608
|
+
/* modal and the edit page, so it is styled here rather than in */
|
|
609
|
+
/* import.css -- the modal opens over the viewer, which loads neither */
|
|
610
|
+
/* that stylesheet nor anything else the edit page has. */
|
|
611
|
+
/* ------------------------------------------------------------------ */
|
|
612
|
+
|
|
613
|
+
.data-source-field {
|
|
614
|
+
display: flex;
|
|
615
|
+
flex-direction: column;
|
|
616
|
+
gap: var(--space-2);
|
|
617
|
+
min-width: 0;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.data-source-extra {
|
|
621
|
+
display: flex;
|
|
622
|
+
flex-direction: column;
|
|
623
|
+
gap: var(--space-1);
|
|
624
|
+
min-width: 0;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.data-source-extra[hidden] {
|
|
628
|
+
display: none;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/* Spelled out rather than inherited from import.css, for the same reason the
|
|
632
|
+
rest of this block is here. The margin is dropped because the column above
|
|
633
|
+
already spaces these with `gap`. */
|
|
634
|
+
.data-source-field .field-hint {
|
|
635
|
+
color: var(--text-muted);
|
|
636
|
+
font-size: 11px;
|
|
637
|
+
font-weight: 400;
|
|
638
|
+
margin-top: 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/* ------------------------------------------------------------------ */
|
|
642
|
+
/* "Browse..." buttons */
|
|
643
|
+
/* Beside every path input in the app. Here rather than in import.css */
|
|
644
|
+
/* because the requirements modal opens over the viewer, which loads */
|
|
645
|
+
/* only this stylesheet -- so there the buttons rendered as bare native */
|
|
646
|
+
/* controls next to fields that were styled. */
|
|
647
|
+
/* ------------------------------------------------------------------ */
|
|
648
|
+
|
|
649
|
+
.browse-button {
|
|
650
|
+
background: var(--surface-2);
|
|
651
|
+
border: 1px solid var(--border-subtle);
|
|
652
|
+
border-radius: var(--radius-sm);
|
|
653
|
+
color: var(--text-secondary);
|
|
654
|
+
flex-shrink: 0;
|
|
655
|
+
font-size: 13px;
|
|
656
|
+
padding: 8px 12px;
|
|
657
|
+
white-space: nowrap;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.browse-button:hover {
|
|
661
|
+
border-color: var(--border-strong);
|
|
662
|
+
color: var(--text-primary);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/* ------------------------------------------------------------------ */
|
|
666
|
+
/* Requirements modal */
|
|
667
|
+
/* Shown when a plugin declares something the project has not got. Core */
|
|
668
|
+
/* owns this: it renders requirements from any plugin, so it must not */
|
|
669
|
+
/* live in a plugin stylesheet (tests/test_plugin_css_boundary.py). */
|
|
670
|
+
/* ------------------------------------------------------------------ */
|
|
671
|
+
|
|
672
|
+
.requirements-modal {
|
|
673
|
+
background: var(--surface-1);
|
|
674
|
+
color: var(--text-primary);
|
|
675
|
+
border: 1px solid var(--border-strong);
|
|
676
|
+
border-radius: var(--radius-lg);
|
|
677
|
+
box-shadow: var(--shadow-lg);
|
|
678
|
+
padding: 0;
|
|
679
|
+
width: min(720px, 92vw);
|
|
680
|
+
max-height: 86vh;
|
|
681
|
+
overflow: auto;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.requirements-modal::backdrop {
|
|
685
|
+
background: rgba(0, 0, 0, 0.62);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.requirements-form {
|
|
689
|
+
padding: var(--space-6);
|
|
690
|
+
display: flex;
|
|
691
|
+
flex-direction: column;
|
|
692
|
+
gap: var(--space-4);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.requirements-title {
|
|
696
|
+
margin: 0;
|
|
697
|
+
font-size: 1.1rem;
|
|
698
|
+
font-weight: 600;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.requirements-subtitle {
|
|
702
|
+
margin: 0;
|
|
703
|
+
color: var(--text-muted);
|
|
704
|
+
font-size: 0.85rem;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.requirements-body {
|
|
708
|
+
display: flex;
|
|
709
|
+
flex-direction: column;
|
|
710
|
+
gap: var(--space-2);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* Label beside its control, not above it. The form is a short list of "which
|
|
714
|
+
column is this?" questions, and one column of left-aligned labels is what
|
|
715
|
+
makes it answerable at a glance instead of scrolled through. */
|
|
716
|
+
.requirement-field {
|
|
717
|
+
display: grid;
|
|
718
|
+
grid-template-columns: minmax(8rem, 32%) 1fr;
|
|
719
|
+
align-items: center;
|
|
720
|
+
column-gap: var(--space-3);
|
|
721
|
+
row-gap: var(--space-1);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.requirement-field > label {
|
|
725
|
+
font-size: 0.82rem;
|
|
726
|
+
font-weight: 500;
|
|
727
|
+
color: var(--text-secondary);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/* A field whose control grows downwards -- the data path with its table
|
|
731
|
+
picker, the coordinate control with its second row. The label names the
|
|
732
|
+
first row, so it sits against that rather than drifting to the middle of
|
|
733
|
+
however tall the stack has become. */
|
|
734
|
+
.requirement-field-stacked {
|
|
735
|
+
align-items: start;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.requirement-field-stacked > label {
|
|
739
|
+
padding-top: var(--space-2);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/* "optional" rides on the label rather than taking a line of its own under
|
|
743
|
+
the control, which used to double the height of every field that had it. */
|
|
744
|
+
/* Styled here rather than leaning on import.css: the modal opens over the
|
|
745
|
+
viewer, which does not load that stylesheet. */
|
|
746
|
+
.requirement-field > label > .field-hint {
|
|
747
|
+
margin-left: var(--space-1);
|
|
748
|
+
font-size: 0.72rem;
|
|
749
|
+
font-weight: 400;
|
|
750
|
+
text-transform: lowercase;
|
|
751
|
+
color: var(--text-muted);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* Two controls answering one question ("which numbers, and logged?") share a
|
|
755
|
+
row rather than taking two, which is the whole point of the grid above. */
|
|
756
|
+
.requirement-inline {
|
|
757
|
+
display: flex;
|
|
758
|
+
align-items: center;
|
|
759
|
+
gap: var(--space-3);
|
|
760
|
+
min-width: 0;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.requirement-inline .form-select {
|
|
764
|
+
flex: 1 1 auto;
|
|
765
|
+
min-width: 0;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.requirement-inline-check {
|
|
769
|
+
display: flex;
|
|
770
|
+
align-items: center;
|
|
771
|
+
gap: var(--space-1);
|
|
772
|
+
flex: 0 0 auto;
|
|
773
|
+
font-size: 0.78rem;
|
|
774
|
+
font-weight: 400;
|
|
775
|
+
color: var(--text-secondary);
|
|
776
|
+
white-space: nowrap;
|
|
777
|
+
cursor: pointer;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.requirement-inline-check input {
|
|
781
|
+
margin: 0;
|
|
782
|
+
cursor: pointer;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/* The coordinate control (coordinateField.js): a source radio stacked over
|
|
786
|
+
whichever picker that source needs. Two rows rather than one because the
|
|
787
|
+
second depends on the first -- reading them side by side hides that the
|
|
788
|
+
choice above changes what is being asked below.
|
|
789
|
+
|
|
790
|
+
Styled here rather than in import.css because the requirements modal opens
|
|
791
|
+
over the viewer, which does not load that stylesheet -- the same reason the
|
|
792
|
+
field-hint rule above lives here. The project edit page loads both. */
|
|
793
|
+
.requirement-stack {
|
|
794
|
+
min-width: 0;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.coordinate-field {
|
|
798
|
+
display: flex;
|
|
799
|
+
flex-direction: column;
|
|
800
|
+
gap: var(--space-2);
|
|
801
|
+
min-width: 0;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.coordinate-field-source {
|
|
805
|
+
display: flex;
|
|
806
|
+
align-items: center;
|
|
807
|
+
gap: var(--space-3);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.coordinate-field-radio {
|
|
811
|
+
display: flex;
|
|
812
|
+
align-items: center;
|
|
813
|
+
gap: var(--space-1);
|
|
814
|
+
font-size: 0.78rem;
|
|
815
|
+
font-weight: 400;
|
|
816
|
+
color: var(--text-secondary);
|
|
817
|
+
white-space: nowrap;
|
|
818
|
+
cursor: pointer;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.coordinate-field-radio input {
|
|
822
|
+
margin: 0;
|
|
823
|
+
cursor: pointer;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/* The two obs selects sit side by side: one position, named twice. */
|
|
827
|
+
.coordinate-field-pair {
|
|
828
|
+
display: flex;
|
|
829
|
+
align-items: center;
|
|
830
|
+
gap: var(--space-2);
|
|
831
|
+
min-width: 0;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
.coordinate-field-pair .form-select {
|
|
835
|
+
flex: 1 1 0;
|
|
836
|
+
min-width: 0;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/* The column classifier is two drag targets, not a control -- it gets the
|
|
840
|
+
full width and its label above it. */
|
|
841
|
+
.requirement-field-wide {
|
|
842
|
+
grid-template-columns: 1fr;
|
|
843
|
+
align-items: stretch;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
.requirements-modal .form-control,
|
|
847
|
+
.requirements-modal .form-select {
|
|
848
|
+
background: var(--surface-2);
|
|
849
|
+
border: 1px solid var(--border-subtle);
|
|
850
|
+
border-radius: var(--radius-sm);
|
|
851
|
+
color: var(--text-primary);
|
|
852
|
+
padding: var(--space-2) var(--space-3);
|
|
853
|
+
font-size: 0.85rem;
|
|
854
|
+
width: 100%;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
.requirements-modal .form-control::placeholder {
|
|
858
|
+
color: var(--text-muted);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/* Every property Bootstrap's own `.form-control:focus` sets has to be named
|
|
862
|
+
here, background included. Bootstrap's CSS is injected by style-loader as a
|
|
863
|
+
<style> at the end of <head> -- after main.css's <link> -- and
|
|
864
|
+
`.form-control:focus` carries the same specificity as
|
|
865
|
+
`.requirements-modal .form-control`, so it wins the tie on source order.
|
|
866
|
+
Naming only outline and border-color left the dialog's first input painted
|
|
867
|
+
white-on-white with a blue glow the moment it took focus, which is the
|
|
868
|
+
state it opens in. */
|
|
869
|
+
.requirements-modal .form-control:focus,
|
|
870
|
+
.requirements-modal .form-select:focus {
|
|
871
|
+
background: var(--surface-2);
|
|
872
|
+
color: var(--text-primary);
|
|
873
|
+
border-color: var(--accent-channel);
|
|
874
|
+
box-shadow: 0 0 0 3px var(--accent-channel-soft);
|
|
875
|
+
outline: none;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.requirements-modal .import-field-row {
|
|
879
|
+
display: flex;
|
|
880
|
+
align-items: stretch;
|
|
881
|
+
gap: var(--space-2);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* The input takes the slack and the buttons keep their own width. Without
|
|
885
|
+
this the `width: 100%` above fights the buttons for the row. */
|
|
886
|
+
.requirements-modal .import-field-row .form-control {
|
|
887
|
+
flex: 1 1 auto;
|
|
888
|
+
min-width: 0;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.requirements-error {
|
|
892
|
+
color: var(--accent-danger);
|
|
893
|
+
background: var(--accent-danger-soft);
|
|
894
|
+
border-radius: var(--radius-sm);
|
|
895
|
+
padding: var(--space-2) var(--space-3);
|
|
896
|
+
font-size: 0.82rem;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.requirements-actions {
|
|
900
|
+
display: flex;
|
|
901
|
+
justify-content: flex-end;
|
|
902
|
+
gap: var(--space-2);
|
|
903
|
+
}
|