matterviz 0.3.6 → 0.3.7
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.
- package/dist/EmptyState.svelte.d.ts +9 -0
- package/dist/FilePicker.svelte +360 -0
- package/dist/FilePicker.svelte.d.ts +17 -0
- package/dist/Icon.svelte.d.ts +13 -0
- package/dist/MillerIndexInput.svelte +66 -0
- package/dist/MillerIndexInput.svelte.d.ts +7 -0
- package/dist/api/mp.d.ts +6 -0
- package/dist/api/mp.js +22 -0
- package/dist/api/optimade.d.ts +45 -0
- package/dist/api/optimade.js +135 -0
- package/dist/brillouin/BrillouinZone.svelte +549 -0
- package/dist/brillouin/BrillouinZone.svelte.d.ts +83 -0
- package/dist/brillouin/BrillouinZoneControls.svelte +144 -0
- package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +17 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte +146 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +146 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
- package/dist/brillouin/BrillouinZoneScene.svelte +476 -0
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +48 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte +92 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +8 -0
- package/dist/brillouin/compute.d.ts +17 -0
- package/dist/brillouin/compute.js +426 -0
- package/dist/brillouin/index.d.ts +8 -0
- package/dist/brillouin/index.js +7 -0
- package/dist/brillouin/types.d.ts +43 -0
- package/dist/brillouin/types.js +1 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
- package/dist/chempot-diagram/async-compute.svelte.js +78 -0
- package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
- package/dist/chempot-diagram/chempot-worker.js +11 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +32 -0
- package/dist/chempot-diagram/compute.d.ts +48 -0
- package/dist/chempot-diagram/compute.js +806 -0
- package/dist/chempot-diagram/index.d.ts +6 -0
- package/dist/chempot-diagram/index.js +6 -0
- package/dist/chempot-diagram/pointer.d.ts +16 -0
- package/dist/chempot-diagram/pointer.js +40 -0
- package/dist/chempot-diagram/temperature.d.ts +15 -0
- package/dist/chempot-diagram/temperature.js +34 -0
- package/dist/chempot-diagram/types.d.ts +81 -0
- package/dist/chempot-diagram/types.js +28 -0
- package/dist/colors/index.d.ts +47 -0
- package/dist/colors/index.js +203 -0
- package/dist/composition/BarChart.svelte +297 -0
- package/dist/composition/BarChart.svelte.d.ts +39 -0
- package/dist/composition/BubbleChart.svelte +218 -0
- package/dist/composition/BubbleChart.svelte.d.ts +28 -0
- package/dist/composition/Composition.svelte +165 -0
- package/dist/composition/Composition.svelte.d.ts +15 -0
- package/dist/composition/Formula.svelte +268 -0
- package/dist/composition/Formula.svelte.d.ts +19 -0
- package/dist/composition/FormulaFilter.svelte +1257 -0
- package/dist/composition/FormulaFilter.svelte.d.ts +51 -0
- package/dist/composition/PieChart.svelte +323 -0
- package/dist/composition/PieChart.svelte.d.ts +37 -0
- package/dist/composition/format.d.ts +15 -0
- package/dist/composition/format.js +109 -0
- package/dist/composition/index.d.ts +20 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +56 -0
- package/dist/composition/parse.js +474 -0
- package/dist/constants.d.ts +29 -0
- package/dist/constants.js +99 -0
- package/dist/controls.d.ts +14 -0
- package/dist/controls.js +30 -0
- package/dist/convex-hull/ConvexHull.svelte +157 -0
- package/dist/convex-hull/ConvexHull.svelte.d.ts +13 -0
- package/dist/convex-hull/ConvexHull2D.svelte +825 -0
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +11 -0
- package/dist/convex-hull/ConvexHull3D.svelte +1801 -0
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +8 -0
- package/dist/convex-hull/ConvexHull4D.svelte +1398 -0
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +8 -0
- package/dist/convex-hull/ConvexHullControls.svelte +535 -0
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +48 -0
- package/dist/convex-hull/ConvexHullInfoPane.svelte +125 -0
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +20 -0
- package/dist/convex-hull/ConvexHullStats.svelte +929 -0
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +17 -0
- package/dist/convex-hull/ConvexHullTooltip.svelte +131 -0
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +33 -0
- package/dist/convex-hull/GasPressureControls.svelte +247 -0
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +11 -0
- package/dist/convex-hull/StructurePopup.svelte +151 -0
- package/dist/convex-hull/StructurePopup.svelte.d.ts +18 -0
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +8 -0
- package/dist/convex-hull/barycentric-coords.d.ts +18 -0
- package/dist/convex-hull/barycentric-coords.js +182 -0
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +40 -0
- package/dist/convex-hull/gas-thermodynamics.d.ts +16 -0
- package/dist/convex-hull/gas-thermodynamics.js +314 -0
- package/dist/convex-hull/helpers.d.ts +114 -0
- package/dist/convex-hull/helpers.js +710 -0
- package/dist/convex-hull/index.d.ts +119 -0
- package/dist/convex-hull/index.js +58 -0
- package/dist/convex-hull/thermodynamics.d.ts +67 -0
- package/dist/convex-hull/thermodynamics.js +1752 -0
- package/dist/convex-hull/types.d.ts +162 -0
- package/dist/convex-hull/types.js +36 -0
- package/dist/coordination/CoordinationBarPlot.svelte +311 -0
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +30 -0
- package/dist/coordination/calc-coordination.d.ts +15 -0
- package/dist/coordination/calc-coordination.js +63 -0
- package/dist/coordination/index.d.ts +8 -0
- package/dist/coordination/index.js +7 -0
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte.d.ts +20 -0
- package/dist/element/ElementHeading.svelte +26 -0
- package/dist/element/ElementHeading.svelte.d.ts +8 -0
- package/dist/element/ElementPhoto.svelte +57 -0
- package/dist/element/ElementPhoto.svelte.d.ts +9 -0
- package/dist/element/ElementStats.svelte +80 -0
- package/dist/element/ElementStats.svelte.d.ts +8 -0
- package/dist/element/ElementTile.svelte +484 -0
- package/dist/element/ElementTile.svelte.d.ts +29 -0
- package/dist/element/Nucleus.svelte.d.ts +17 -0
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +2 -0
- package/dist/element/index.d.ts +8 -0
- package/dist/element/index.js +7 -0
- package/dist/element/types.d.ts +57 -0
- package/dist/element/types.js +1 -0
- package/dist/feedback/ClickFeedback.svelte +58 -0
- package/dist/feedback/ClickFeedback.svelte.d.ts +12 -0
- package/dist/feedback/DragOverlay.svelte +42 -0
- package/dist/feedback/DragOverlay.svelte.d.ts +7 -0
- package/dist/feedback/Spinner.svelte.d.ts +7 -0
- package/dist/feedback/StatusMessage.svelte.d.ts +9 -0
- package/dist/feedback/index.d.ts +4 -0
- package/dist/feedback/index.js +4 -0
- package/dist/fermi-surface/FermiSlice.svelte +189 -0
- package/dist/fermi-surface/FermiSlice.svelte.d.ts +24 -0
- package/dist/fermi-surface/FermiSurface.svelte +600 -0
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +83 -0
- package/dist/fermi-surface/FermiSurfaceControls.svelte +448 -0
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +35 -0
- package/dist/fermi-surface/FermiSurfaceScene.svelte +794 -0
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +50 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +8 -0
- package/dist/fermi-surface/compute.d.ts +5 -0
- package/dist/fermi-surface/compute.js +538 -0
- package/dist/fermi-surface/constants.d.ts +9 -0
- package/dist/fermi-surface/constants.js +27 -0
- package/dist/fermi-surface/export.d.ts +5 -0
- package/dist/fermi-surface/export.js +50 -0
- package/dist/fermi-surface/index.d.ts +12 -0
- package/dist/fermi-surface/index.js +13 -0
- package/dist/fermi-surface/marching-cubes.d.ts +2 -0
- package/dist/fermi-surface/marching-cubes.js +2 -0
- package/dist/fermi-surface/parse.d.ts +2 -0
- package/dist/fermi-surface/parse.js +491 -0
- package/dist/fermi-surface/symmetry.d.ts +3 -0
- package/dist/fermi-surface/symmetry.js +46 -0
- package/dist/fermi-surface/types.d.ts +110 -0
- package/dist/fermi-surface/types.js +4 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
- package/dist/heatmap-matrix/index.d.ts +53 -0
- package/dist/heatmap-matrix/index.js +100 -0
- package/dist/heatmap-matrix/shared.d.ts +2 -0
- package/dist/heatmap-matrix/shared.js +4 -0
- package/dist/icons.d.ts +569 -0
- package/dist/icons.js +648 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +39 -0
- package/dist/io/decompress.d.ts +11 -0
- package/dist/io/decompress.js +74 -0
- package/dist/io/export.d.ts +16 -0
- package/dist/io/export.js +316 -0
- package/dist/io/fetch.d.ts +5 -0
- package/dist/io/fetch.js +39 -0
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +7 -0
- package/dist/io/index.js +6 -0
- package/dist/io/is-binary.d.ts +1 -0
- package/dist/io/is-binary.js +20 -0
- package/dist/io/types.d.ts +8 -0
- package/dist/io/types.js +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +123 -0
- package/dist/isosurface/Isosurface.svelte +285 -0
- package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
- package/dist/isosurface/IsosurfaceControls.svelte +277 -0
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
- package/dist/isosurface/index.d.ts +5 -0
- package/dist/isosurface/index.js +6 -0
- package/dist/isosurface/parse.d.ts +6 -0
- package/dist/isosurface/parse.js +553 -0
- package/dist/isosurface/slice.d.ts +11 -0
- package/dist/isosurface/slice.js +140 -0
- package/dist/isosurface/types.d.ts +56 -0
- package/dist/isosurface/types.js +227 -0
- package/dist/labels.d.ts +53 -0
- package/dist/labels.js +277 -0
- package/dist/layout/FullscreenToggle.svelte +50 -0
- package/dist/layout/FullscreenToggle.svelte.d.ts +7 -0
- package/dist/layout/InfoCard.svelte +120 -0
- package/dist/layout/InfoCard.svelte.d.ts +21 -0
- package/dist/layout/InfoTag.svelte +185 -0
- package/dist/layout/InfoTag.svelte.d.ts +19 -0
- package/dist/layout/PropertyFilter.svelte +246 -0
- package/dist/layout/PropertyFilter.svelte.d.ts +24 -0
- package/dist/layout/SettingsSection.svelte +148 -0
- package/dist/layout/SettingsSection.svelte.d.ts +17 -0
- package/dist/layout/SubpageGrid.svelte +82 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/fullscreen.d.ts +9 -0
- package/dist/layout/fullscreen.js +53 -0
- package/dist/layout/index.d.ts +10 -0
- package/dist/layout/index.js +8 -0
- package/dist/layout/json-tree/JsonNode.svelte +548 -0
- package/dist/layout/json-tree/JsonNode.svelte.d.ts +11 -0
- package/dist/layout/json-tree/JsonTree.svelte +1230 -0
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +6 -0
- package/dist/layout/json-tree/JsonValue.svelte.d.ts +9 -0
- package/dist/layout/json-tree/index.d.ts +3 -0
- package/dist/layout/json-tree/index.js +3 -0
- package/dist/layout/json-tree/types.d.ts +74 -0
- package/dist/layout/json-tree/types.js +2 -0
- package/dist/layout/json-tree/utils.d.ts +29 -0
- package/dist/layout/json-tree/utils.js +641 -0
- package/dist/marching-cubes.d.ts +14 -0
- package/dist/marching-cubes.js +540 -0
- package/dist/math.d.ts +101 -0
- package/dist/math.js +905 -0
- package/dist/overlays/ContextMenu.svelte +162 -0
- package/dist/overlays/ContextMenu.svelte.d.ts +25 -0
- package/dist/overlays/CopyButton.svelte +45 -0
- package/dist/overlays/CopyButton.svelte.d.ts +8 -0
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +487 -0
- package/dist/overlays/DraggablePane.svelte.d.ts +36 -0
- package/dist/overlays/InfoPaneCards.svelte +149 -0
- package/dist/overlays/InfoPaneCards.svelte.d.ts +22 -0
- package/dist/overlays/index.d.ts +3 -0
- package/dist/overlays/index.js +3 -0
- package/dist/periodic-table/PeriodicTable.svelte +469 -0
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +55 -0
- package/dist/periodic-table/PeriodicTableControls.svelte +557 -0
- package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +24 -0
- package/dist/periodic-table/PropertySelect.svelte +37 -0
- package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
- package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
- package/dist/periodic-table/index.d.ts +10 -0
- package/dist/periodic-table/index.js +4 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +44 -0
- package/dist/phase-diagram/PhaseDiagramControls.svelte +444 -0
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +30 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +19 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +16 -0
- package/dist/phase-diagram/TdbInfoPanel.svelte +203 -0
- package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +12 -0
- package/dist/phase-diagram/build-diagram.d.ts +11 -0
- package/dist/phase-diagram/build-diagram.js +160 -0
- package/dist/phase-diagram/colors.d.ts +35 -0
- package/dist/phase-diagram/colors.js +51 -0
- package/dist/phase-diagram/diagram-input.d.ts +29 -0
- package/dist/phase-diagram/diagram-input.js +3 -0
- package/dist/phase-diagram/index.d.ts +13 -0
- package/dist/phase-diagram/index.js +11 -0
- package/dist/phase-diagram/parse.d.ts +55 -0
- package/dist/phase-diagram/parse.js +272 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +867 -0
- package/dist/phase-diagram/types.d.ts +93 -0
- package/dist/phase-diagram/types.js +1 -0
- package/dist/phase-diagram/utils.d.ts +118 -0
- package/dist/phase-diagram/utils.js +604 -0
- package/dist/plot/AxisLabel.svelte +51 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +2113 -0
- package/dist/plot/BarPlot.svelte.d.ts +84 -0
- package/dist/plot/BarPlotControls.svelte +66 -0
- package/dist/plot/BarPlotControls.svelte.d.ts +18 -0
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +721 -0
- package/dist/plot/ColorBar.svelte.d.ts +31 -0
- package/dist/plot/ColorScaleSelect.svelte +54 -0
- package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
- package/dist/plot/ElementScatter.svelte +63 -0
- package/dist/plot/ElementScatter.svelte.d.ts +14 -0
- package/dist/plot/FillArea.svelte.d.ts +21 -0
- package/dist/plot/Histogram.svelte +1558 -0
- package/dist/plot/Histogram.svelte.d.ts +50 -0
- package/dist/plot/HistogramControls.svelte +212 -0
- package/dist/plot/HistogramControls.svelte.d.ts +22 -0
- package/dist/plot/InteractiveAxisLabel.svelte +96 -0
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +14 -0
- package/dist/plot/Line.svelte +84 -0
- package/dist/plot/Line.svelte.d.ts +15 -0
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte +537 -0
- package/dist/plot/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/PlotLegend.svelte +569 -0
- package/dist/plot/PlotLegend.svelte.d.ts +29 -0
- package/dist/plot/PlotTooltip.svelte +67 -0
- package/dist/plot/PlotTooltip.svelte.d.ts +17 -0
- package/dist/plot/PortalSelect.svelte +253 -0
- package/dist/plot/PortalSelect.svelte.d.ts +16 -0
- package/dist/plot/ReferenceLine.svelte.d.ts +20 -0
- package/dist/plot/ReferenceLine3D.svelte +156 -0
- package/dist/plot/ReferenceLine3D.svelte.d.ts +14 -0
- package/dist/plot/ReferencePlane.svelte +175 -0
- package/dist/plot/ReferencePlane.svelte.d.ts +14 -0
- package/dist/plot/ScatterPlot.svelte +2778 -0
- package/dist/plot/ScatterPlot.svelte.d.ts +96 -0
- package/dist/plot/ScatterPlot3D.svelte +529 -0
- package/dist/plot/ScatterPlot3D.svelte.d.ts +95 -0
- package/dist/plot/ScatterPlot3DControls.svelte +437 -0
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +20 -0
- package/dist/plot/ScatterPlot3DScene.svelte +912 -0
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +74 -0
- package/dist/plot/ScatterPlotControls.svelte +306 -0
- package/dist/plot/ScatterPlotControls.svelte.d.ts +17 -0
- package/dist/plot/ScatterPoint.svelte +182 -0
- package/dist/plot/ScatterPoint.svelte.d.ts +22 -0
- package/dist/plot/SpacegroupBarPlot.svelte +293 -0
- package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
- package/dist/plot/Surface3D.svelte +197 -0
- package/dist/plot/Surface3D.svelte.d.ts +13 -0
- package/dist/plot/ZeroLines.svelte +97 -0
- package/dist/plot/ZeroLines.svelte.d.ts +33 -0
- package/dist/plot/ZoomRect.svelte +23 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.d.ts +19 -0
- package/dist/plot/axis-utils.js +78 -0
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.d.ts +37 -0
- package/dist/plot/data-cleaning.js +855 -0
- package/dist/plot/data-transform.d.ts +16 -0
- package/dist/plot/data-transform.js +45 -0
- package/dist/plot/defaults.d.ts +19 -0
- package/dist/plot/defaults.js +9 -0
- package/dist/plot/fill-utils.d.ts +46 -0
- package/dist/plot/fill-utils.js +322 -0
- package/dist/plot/hover-lock.svelte.d.ts +14 -0
- package/dist/plot/hover-lock.svelte.js +46 -0
- package/dist/plot/index.d.ts +41 -0
- package/dist/plot/index.js +39 -0
- package/dist/plot/interactions.d.ts +12 -0
- package/dist/plot/interactions.js +101 -0
- package/dist/plot/layout.d.ts +78 -0
- package/dist/plot/layout.js +273 -0
- package/dist/plot/reference-line.d.ts +60 -0
- package/dist/plot/reference-line.js +314 -0
- package/dist/plot/scales.d.ts +48 -0
- package/dist/plot/scales.js +481 -0
- package/dist/plot/svg.d.ts +1 -0
- package/dist/plot/svg.js +11 -0
- package/dist/plot/types.d.ts +831 -0
- package/dist/plot/types.js +99 -0
- package/dist/plot/utils/label-placement.d.ts +68 -0
- package/dist/plot/utils/label-placement.js +326 -0
- package/dist/plot/utils/series-visibility.d.ts +15 -0
- package/dist/plot/utils/series-visibility.js +85 -0
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +247 -0
- package/dist/rdf/RdfPlot.svelte.d.ts +27 -0
- package/dist/rdf/calc-rdf.d.ts +4 -0
- package/dist/rdf/calc-rdf.js +111 -0
- package/dist/rdf/index.d.ts +23 -0
- package/dist/rdf/index.js +2 -0
- package/dist/sanitize.d.ts +6 -0
- package/dist/sanitize.js +116 -0
- package/dist/settings.d.ts +255 -0
- package/dist/settings.js +1132 -0
- package/dist/spectral/Bands.svelte +1040 -0
- package/dist/spectral/Bands.svelte.d.ts +40 -0
- package/dist/spectral/BandsAndDos.svelte +134 -0
- package/dist/spectral/BandsAndDos.svelte.d.ts +18 -0
- package/dist/spectral/BrillouinBandsDos.svelte +252 -0
- package/dist/spectral/BrillouinBandsDos.svelte.d.ts +20 -0
- package/dist/spectral/Dos.svelte +697 -0
- package/dist/spectral/Dos.svelte.d.ts +29 -0
- package/dist/spectral/helpers.d.ts +119 -0
- package/dist/spectral/helpers.js +1032 -0
- package/dist/spectral/index.d.ts +6 -0
- package/dist/spectral/index.js +6 -0
- package/dist/spectral/types.d.ts +84 -0
- package/dist/spectral/types.js +2 -0
- package/dist/state.svelte.d.ts +25 -0
- package/dist/state.svelte.js +45 -0
- package/dist/structure/Arrow.svelte +72 -0
- package/dist/structure/Arrow.svelte.d.ts +15 -0
- package/dist/structure/AtomLegend.svelte +815 -0
- package/dist/structure/AtomLegend.svelte.d.ts +35 -0
- package/dist/structure/Bond.svelte +140 -0
- package/dist/structure/Bond.svelte.d.ts +9 -0
- package/dist/structure/CanvasTooltip.svelte +33 -0
- package/dist/structure/CanvasTooltip.svelte.d.ts +12 -0
- package/dist/structure/CellSelect.svelte +349 -0
- package/dist/structure/CellSelect.svelte.d.ts +13 -0
- package/dist/structure/Cylinder.svelte +45 -0
- package/dist/structure/Cylinder.svelte.d.ts +10 -0
- package/dist/structure/Lattice.svelte +196 -0
- package/dist/structure/Lattice.svelte.d.ts +17 -0
- package/dist/structure/Structure.svelte +2248 -0
- package/dist/structure/Structure.svelte.d.ts +89 -0
- package/dist/structure/StructureControls.svelte +1273 -0
- package/dist/structure/StructureControls.svelte.d.ts +31 -0
- package/dist/structure/StructureExportPane.svelte +252 -0
- package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
- package/dist/structure/StructureInfoPane.svelte +737 -0
- package/dist/structure/StructureInfoPane.svelte.d.ts +19 -0
- package/dist/structure/StructureScene.svelte +2255 -0
- package/dist/structure/StructureScene.svelte.d.ts +111 -0
- package/dist/structure/atom-properties.d.ts +37 -0
- package/dist/structure/atom-properties.js +200 -0
- package/dist/structure/bond-order-perception.d.ts +13 -0
- package/dist/structure/bond-order-perception.js +384 -0
- package/dist/structure/bonding.d.ts +68 -0
- package/dist/structure/bonding.js +696 -0
- package/dist/structure/export.d.ts +20 -0
- package/dist/structure/export.js +727 -0
- package/dist/structure/index.d.ts +126 -0
- package/dist/structure/index.js +169 -0
- package/dist/structure/label-placement.d.ts +14 -0
- package/dist/structure/label-placement.js +72 -0
- package/dist/structure/measure.d.ts +6 -0
- package/dist/structure/measure.js +29 -0
- package/dist/structure/parse.d.ts +66 -0
- package/dist/structure/parse.js +1392 -0
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +99 -0
- package/dist/structure/pbc.d.ts +9 -0
- package/dist/structure/pbc.js +123 -0
- package/dist/structure/supercell.d.ts +8 -0
- package/dist/structure/supercell.js +170 -0
- package/dist/structure/validation.d.ts +2 -0
- package/dist/structure/validation.js +10 -0
- package/dist/symmetry/SymmetryStats.svelte +226 -0
- package/dist/symmetry/SymmetryStats.svelte.d.ts +21 -0
- package/dist/symmetry/WyckoffTable.svelte +120 -0
- package/dist/symmetry/WyckoffTable.svelte.d.ts +11 -0
- package/dist/symmetry/cell-transform.d.ts +12 -0
- package/dist/symmetry/cell-transform.js +91 -0
- package/dist/symmetry/index.d.ts +43 -0
- package/dist/symmetry/index.js +228 -0
- package/dist/symmetry/spacegroups.d.ts +9 -0
- package/dist/symmetry/spacegroups.js +394 -0
- package/dist/table/HeatmapTable.svelte +1833 -0
- package/dist/table/HeatmapTable.svelte.d.ts +49 -0
- package/dist/table/ToggleMenu.svelte +385 -0
- package/dist/table/ToggleMenu.svelte.d.ts +11 -0
- package/dist/table/index.d.ts +74 -0
- package/dist/table/index.js +38 -0
- package/dist/theme/ThemeControl.svelte +53 -0
- package/dist/theme/ThemeControl.svelte.d.ts +9 -0
- package/dist/theme/index.d.ts +29 -0
- package/dist/theme/index.js +79 -0
- package/dist/time.d.ts +4 -0
- package/dist/time.js +70 -0
- package/dist/tooltip/TooltipContent.svelte +58 -0
- package/dist/tooltip/TooltipContent.svelte.d.ts +31 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/types.d.ts +8 -0
- package/dist/tooltip/types.js +1 -0
- package/dist/trajectory/Trajectory.svelte +1545 -0
- package/dist/trajectory/Trajectory.svelte.d.ts +77 -0
- package/dist/trajectory/TrajectoryError.svelte +128 -0
- package/dist/trajectory/TrajectoryError.svelte.d.ts +13 -0
- package/dist/trajectory/TrajectoryExportPane.svelte +357 -0
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +17 -0
- package/dist/trajectory/TrajectoryInfoPane.svelte +313 -0
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +17 -0
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.d.ts +5 -0
- package/dist/trajectory/extract.js +162 -0
- package/dist/trajectory/format-detect.d.ts +9 -0
- package/dist/trajectory/format-detect.js +76 -0
- package/dist/trajectory/frame-reader.d.ts +17 -0
- package/dist/trajectory/frame-reader.js +332 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +164 -0
- package/dist/trajectory/index.d.ts +63 -0
- package/dist/trajectory/index.js +126 -0
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +73 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +127 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +298 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +179 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +68 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +110 -0
- package/dist/trajectory/plotting.d.ts +28 -0
- package/dist/trajectory/plotting.js +423 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +45 -0
- package/dist/xrd/XrdPlot.svelte +615 -0
- package/dist/xrd/XrdPlot.svelte.d.ts +28 -0
- package/dist/xrd/broadening.d.ts +20 -0
- package/dist/xrd/broadening.js +97 -0
- package/dist/xrd/calc-xrd.d.ts +37 -0
- package/dist/xrd/calc-xrd.js +336 -0
- package/dist/xrd/index.d.ts +37 -0
- package/dist/xrd/index.js +4 -0
- package/dist/xrd/parse.d.ts +13 -0
- package/dist/xrd/parse.js +749 -0
- package/license +1 -1
- package/package.json +232 -1457
- package/readme.md +98 -171
- package/.vscode/launch.json +0 -13
- package/.vscodeignore +0 -7
- package/dist/assets/STLExporter-BpTH3YHE.js +0 -8
- package/dist/assets/browser-DdDecX_W.js +0 -1
- package/dist/assets/export-qgn-H9y6.js +0 -2
- package/dist/assets/main-DiKYzti2.css +0 -1
- package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
- package/dist/extension.js +0 -31293
- package/dist/src/lib/FilePicker.svelte +0 -360
- package/dist/src/lib/MillerIndexInput.svelte +0 -66
- package/dist/src/lib/api/mp.ts +0 -26
- package/dist/src/lib/api/optimade.ts +0 -204
- package/dist/src/lib/brillouin/BrillouinZone.svelte +0 -549
- package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +0 -144
- package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +0 -146
- package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +0 -146
- package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +0 -476
- package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +0 -92
- package/dist/src/lib/brillouin/compute.ts +0 -529
- package/dist/src/lib/brillouin/index.ts +0 -8
- package/dist/src/lib/brillouin/types.ts +0 -51
- package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +0 -327
- package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +0 -846
- package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +0 -3193
- package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +0 -94
- package/dist/src/lib/chempot-diagram/chempot-worker.ts +0 -11
- package/dist/src/lib/chempot-diagram/color.ts +0 -42
- package/dist/src/lib/chempot-diagram/compute.ts +0 -1014
- package/dist/src/lib/chempot-diagram/index.ts +0 -6
- package/dist/src/lib/chempot-diagram/pointer.ts +0 -56
- package/dist/src/lib/chempot-diagram/temperature.ts +0 -77
- package/dist/src/lib/chempot-diagram/types.ts +0 -130
- package/dist/src/lib/colors/index.ts +0 -249
- package/dist/src/lib/composition/BarChart.svelte +0 -297
- package/dist/src/lib/composition/BubbleChart.svelte +0 -218
- package/dist/src/lib/composition/Composition.svelte +0 -165
- package/dist/src/lib/composition/Formula.svelte +0 -268
- package/dist/src/lib/composition/FormulaFilter.svelte +0 -1257
- package/dist/src/lib/composition/PieChart.svelte +0 -323
- package/dist/src/lib/composition/format.ts +0 -155
- package/dist/src/lib/composition/index.ts +0 -37
- package/dist/src/lib/composition/parse.ts +0 -605
- package/dist/src/lib/constants.ts +0 -134
- package/dist/src/lib/controls.ts +0 -42
- package/dist/src/lib/convex-hull/ConvexHull.svelte +0 -157
- package/dist/src/lib/convex-hull/ConvexHull2D.svelte +0 -825
- package/dist/src/lib/convex-hull/ConvexHull3D.svelte +0 -1801
- package/dist/src/lib/convex-hull/ConvexHull4D.svelte +0 -1398
- package/dist/src/lib/convex-hull/ConvexHullControls.svelte +0 -535
- package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +0 -125
- package/dist/src/lib/convex-hull/ConvexHullStats.svelte +0 -929
- package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +0 -131
- package/dist/src/lib/convex-hull/GasPressureControls.svelte +0 -247
- package/dist/src/lib/convex-hull/StructurePopup.svelte +0 -151
- package/dist/src/lib/convex-hull/barycentric-coords.ts +0 -246
- package/dist/src/lib/convex-hull/demo-temperature.ts +0 -63
- package/dist/src/lib/convex-hull/gas-thermodynamics.ts +0 -405
- package/dist/src/lib/convex-hull/helpers.ts +0 -932
- package/dist/src/lib/convex-hull/index.ts +0 -202
- package/dist/src/lib/convex-hull/thermodynamics.ts +0 -2192
- package/dist/src/lib/convex-hull/types.ts +0 -267
- package/dist/src/lib/coordination/CoordinationBarPlot.svelte +0 -311
- package/dist/src/lib/coordination/calc-coordination.ts +0 -93
- package/dist/src/lib/coordination/index.ts +0 -9
- package/dist/src/lib/effects.svelte.ts +0 -48
- package/dist/src/lib/element/ElementHeading.svelte +0 -26
- package/dist/src/lib/element/ElementPhoto.svelte +0 -57
- package/dist/src/lib/element/ElementStats.svelte +0 -80
- package/dist/src/lib/element/ElementTile.svelte +0 -484
- package/dist/src/lib/element/data.ts +0 -14
- package/dist/src/lib/element/index.ts +0 -8
- package/dist/src/lib/element/types.ts +0 -62
- package/dist/src/lib/feedback/ClickFeedback.svelte +0 -58
- package/dist/src/lib/feedback/DragOverlay.svelte +0 -42
- package/dist/src/lib/feedback/index.ts +0 -4
- package/dist/src/lib/fermi-surface/FermiSlice.svelte +0 -189
- package/dist/src/lib/fermi-surface/FermiSurface.svelte +0 -600
- package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +0 -448
- package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +0 -794
- package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
- package/dist/src/lib/fermi-surface/compute.ts +0 -728
- package/dist/src/lib/fermi-surface/constants.ts +0 -32
- package/dist/src/lib/fermi-surface/export.ts +0 -64
- package/dist/src/lib/fermi-surface/index.ts +0 -14
- package/dist/src/lib/fermi-surface/marching-cubes.ts +0 -3
- package/dist/src/lib/fermi-surface/parse.ts +0 -574
- package/dist/src/lib/fermi-surface/symmetry.ts +0 -56
- package/dist/src/lib/fermi-surface/types.ts +0 -159
- package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +0 -1545
- package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
- package/dist/src/lib/heatmap-matrix/index.ts +0 -167
- package/dist/src/lib/heatmap-matrix/shared.ts +0 -7
- package/dist/src/lib/icons.ts +0 -650
- package/dist/src/lib/index.ts +0 -61
- package/dist/src/lib/io/decompress.ts +0 -92
- package/dist/src/lib/io/export.ts +0 -385
- package/dist/src/lib/io/fetch.ts +0 -46
- package/dist/src/lib/io/file-drop.ts +0 -51
- package/dist/src/lib/io/index.ts +0 -7
- package/dist/src/lib/io/is-binary.ts +0 -24
- package/dist/src/lib/io/types.ts +0 -8
- package/dist/src/lib/io/url-drop.ts +0 -141
- package/dist/src/lib/isosurface/Isosurface.svelte +0 -285
- package/dist/src/lib/isosurface/IsosurfaceControls.svelte +0 -277
- package/dist/src/lib/isosurface/index.ts +0 -7
- package/dist/src/lib/isosurface/parse.ts +0 -656
- package/dist/src/lib/isosurface/slice.ts +0 -175
- package/dist/src/lib/isosurface/types.ts +0 -309
- package/dist/src/lib/labels.ts +0 -320
- package/dist/src/lib/layout/FullscreenToggle.svelte +0 -50
- package/dist/src/lib/layout/InfoCard.svelte +0 -120
- package/dist/src/lib/layout/InfoTag.svelte +0 -185
- package/dist/src/lib/layout/PropertyFilter.svelte +0 -246
- package/dist/src/lib/layout/SettingsSection.svelte +0 -148
- package/dist/src/lib/layout/SubpageGrid.svelte +0 -82
- package/dist/src/lib/layout/fullscreen.ts +0 -65
- package/dist/src/lib/layout/index.ts +0 -11
- package/dist/src/lib/layout/json-tree/JsonNode.svelte +0 -548
- package/dist/src/lib/layout/json-tree/JsonTree.svelte +0 -1230
- package/dist/src/lib/layout/json-tree/index.ts +0 -3
- package/dist/src/lib/layout/json-tree/types.ts +0 -126
- package/dist/src/lib/layout/json-tree/utils.ts +0 -682
- package/dist/src/lib/marching-cubes.ts +0 -614
- package/dist/src/lib/math.ts +0 -1081
- package/dist/src/lib/overlays/ContextMenu.svelte +0 -162
- package/dist/src/lib/overlays/CopyButton.svelte +0 -45
- package/dist/src/lib/overlays/DragControlTab.svelte +0 -98
- package/dist/src/lib/overlays/DraggablePane.svelte +0 -487
- package/dist/src/lib/overlays/InfoPaneCards.svelte +0 -149
- package/dist/src/lib/overlays/index.ts +0 -3
- package/dist/src/lib/periodic-table/PeriodicTable.svelte +0 -469
- package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +0 -557
- package/dist/src/lib/periodic-table/PropertySelect.svelte +0 -37
- package/dist/src/lib/periodic-table/index.ts +0 -12
- package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
- package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +0 -444
- package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
- package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +0 -184
- package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +0 -391
- package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +0 -203
- package/dist/src/lib/phase-diagram/build-diagram.ts +0 -186
- package/dist/src/lib/phase-diagram/colors.ts +0 -58
- package/dist/src/lib/phase-diagram/diagram-input.ts +0 -40
- package/dist/src/lib/phase-diagram/index.ts +0 -13
- package/dist/src/lib/phase-diagram/parse.ts +0 -348
- package/dist/src/lib/phase-diagram/svg-to-diagram.ts +0 -1023
- package/dist/src/lib/phase-diagram/types.ts +0 -144
- package/dist/src/lib/phase-diagram/utils.ts +0 -775
- package/dist/src/lib/plot/AxisLabel.svelte +0 -51
- package/dist/src/lib/plot/BarPlot.svelte +0 -2113
- package/dist/src/lib/plot/BarPlotControls.svelte +0 -66
- package/dist/src/lib/plot/BinnedScatterPlot.svelte +0 -1114
- package/dist/src/lib/plot/ColorBar.svelte +0 -721
- package/dist/src/lib/plot/ColorScaleSelect.svelte +0 -54
- package/dist/src/lib/plot/ElementScatter.svelte +0 -63
- package/dist/src/lib/plot/Histogram.svelte +0 -1558
- package/dist/src/lib/plot/HistogramControls.svelte +0 -212
- package/dist/src/lib/plot/InteractiveAxisLabel.svelte +0 -96
- package/dist/src/lib/plot/Line.svelte +0 -84
- package/dist/src/lib/plot/PlotAxis.svelte +0 -169
- package/dist/src/lib/plot/PlotControls.svelte +0 -537
- package/dist/src/lib/plot/PlotLegend.svelte +0 -569
- package/dist/src/lib/plot/PlotTooltip.svelte +0 -67
- package/dist/src/lib/plot/PortalSelect.svelte +0 -253
- package/dist/src/lib/plot/ReferenceLine3D.svelte +0 -156
- package/dist/src/lib/plot/ReferencePlane.svelte +0 -175
- package/dist/src/lib/plot/ScatterPlot.svelte +0 -2778
- package/dist/src/lib/plot/ScatterPlot3D.svelte +0 -529
- package/dist/src/lib/plot/ScatterPlot3DControls.svelte +0 -437
- package/dist/src/lib/plot/ScatterPlot3DScene.svelte +0 -912
- package/dist/src/lib/plot/ScatterPlotControls.svelte +0 -306
- package/dist/src/lib/plot/ScatterPoint.svelte +0 -182
- package/dist/src/lib/plot/SpacegroupBarPlot.svelte +0 -293
- package/dist/src/lib/plot/Surface3D.svelte +0 -197
- package/dist/src/lib/plot/ZeroLines.svelte +0 -97
- package/dist/src/lib/plot/ZoomRect.svelte +0 -23
- package/dist/src/lib/plot/adaptive-density.ts +0 -316
- package/dist/src/lib/plot/auto-place.ts +0 -184
- package/dist/src/lib/plot/axis-utils.ts +0 -122
- package/dist/src/lib/plot/binned-scatter-types.ts +0 -83
- package/dist/src/lib/plot/data-cleaning.ts +0 -1069
- package/dist/src/lib/plot/data-transform.ts +0 -69
- package/dist/src/lib/plot/defaults.ts +0 -9
- package/dist/src/lib/plot/fill-utils.ts +0 -494
- package/dist/src/lib/plot/hover-lock.svelte.ts +0 -60
- package/dist/src/lib/plot/index.ts +0 -53
- package/dist/src/lib/plot/interactions.ts +0 -119
- package/dist/src/lib/plot/layout.ts +0 -425
- package/dist/src/lib/plot/reference-line.ts +0 -426
- package/dist/src/lib/plot/scales.ts +0 -654
- package/dist/src/lib/plot/svg.ts +0 -23
- package/dist/src/lib/plot/types.ts +0 -1144
- package/dist/src/lib/plot/utils/label-placement.ts +0 -541
- package/dist/src/lib/plot/utils/series-visibility.ts +0 -140
- package/dist/src/lib/plot/utils.ts +0 -11
- package/dist/src/lib/rdf/RdfPlot.svelte +0 -247
- package/dist/src/lib/rdf/calc-rdf.ts +0 -167
- package/dist/src/lib/rdf/index.ts +0 -27
- package/dist/src/lib/sanitize.ts +0 -126
- package/dist/src/lib/settings.ts +0 -1479
- package/dist/src/lib/spectral/Bands.svelte +0 -1040
- package/dist/src/lib/spectral/BandsAndDos.svelte +0 -134
- package/dist/src/lib/spectral/BrillouinBandsDos.svelte +0 -252
- package/dist/src/lib/spectral/Dos.svelte +0 -697
- package/dist/src/lib/spectral/helpers.ts +0 -1381
- package/dist/src/lib/spectral/index.ts +0 -8
- package/dist/src/lib/spectral/types.ts +0 -112
- package/dist/src/lib/state.svelte.ts +0 -64
- package/dist/src/lib/structure/Arrow.svelte +0 -72
- package/dist/src/lib/structure/AtomLegend.svelte +0 -815
- package/dist/src/lib/structure/Bond.svelte +0 -140
- package/dist/src/lib/structure/CanvasTooltip.svelte +0 -33
- package/dist/src/lib/structure/CellSelect.svelte +0 -349
- package/dist/src/lib/structure/Cylinder.svelte +0 -45
- package/dist/src/lib/structure/Lattice.svelte +0 -196
- package/dist/src/lib/structure/Structure.svelte +0 -2248
- package/dist/src/lib/structure/StructureControls.svelte +0 -1273
- package/dist/src/lib/structure/StructureExportPane.svelte +0 -252
- package/dist/src/lib/structure/StructureInfoPane.svelte +0 -737
- package/dist/src/lib/structure/StructureScene.svelte +0 -2255
- package/dist/src/lib/structure/atom-properties.ts +0 -316
- package/dist/src/lib/structure/bond-order-perception.ts +0 -447
- package/dist/src/lib/structure/bonding.ts +0 -944
- package/dist/src/lib/structure/export.ts +0 -861
- package/dist/src/lib/structure/index.ts +0 -291
- package/dist/src/lib/structure/label-placement.ts +0 -130
- package/dist/src/lib/structure/measure.ts +0 -45
- package/dist/src/lib/structure/parse.ts +0 -1705
- package/dist/src/lib/structure/partial-occupancy.ts +0 -183
- package/dist/src/lib/structure/pbc.ts +0 -164
- package/dist/src/lib/structure/supercell.ts +0 -226
- package/dist/src/lib/structure/validation.ts +0 -11
- package/dist/src/lib/symmetry/SymmetryStats.svelte +0 -226
- package/dist/src/lib/symmetry/WyckoffTable.svelte +0 -120
- package/dist/src/lib/symmetry/cell-transform.ts +0 -118
- package/dist/src/lib/symmetry/index.ts +0 -348
- package/dist/src/lib/symmetry/spacegroups.ts +0 -404
- package/dist/src/lib/table/HeatmapTable.svelte +0 -1833
- package/dist/src/lib/table/ToggleMenu.svelte +0 -385
- package/dist/src/lib/table/index.ts +0 -139
- package/dist/src/lib/theme/ThemeControl.svelte +0 -53
- package/dist/src/lib/theme/index.ts +0 -107
- package/dist/src/lib/time.ts +0 -71
- package/dist/src/lib/tooltip/TooltipContent.svelte +0 -58
- package/dist/src/lib/tooltip/index.ts +0 -2
- package/dist/src/lib/tooltip/types.ts +0 -13
- package/dist/src/lib/trajectory/Trajectory.svelte +0 -1545
- package/dist/src/lib/trajectory/TrajectoryError.svelte +0 -128
- package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +0 -357
- package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +0 -313
- package/dist/src/lib/trajectory/constants.ts +0 -7
- package/dist/src/lib/trajectory/extract.ts +0 -196
- package/dist/src/lib/trajectory/format-detect.ts +0 -96
- package/dist/src/lib/trajectory/frame-reader.ts +0 -456
- package/dist/src/lib/trajectory/helpers.ts +0 -217
- package/dist/src/lib/trajectory/index.ts +0 -218
- package/dist/src/lib/trajectory/parse/ase.ts +0 -109
- package/dist/src/lib/trajectory/parse/hdf5.ts +0 -173
- package/dist/src/lib/trajectory/parse/index.ts +0 -411
- package/dist/src/lib/trajectory/parse/lammps.ts +0 -215
- package/dist/src/lib/trajectory/parse/vasp.ts +0 -102
- package/dist/src/lib/trajectory/parse/xyz.ts +0 -143
- package/dist/src/lib/trajectory/plotting.ts +0 -599
- package/dist/src/lib/trajectory/types.ts +0 -13
- package/dist/src/lib/utils.ts +0 -56
- package/dist/src/lib/xrd/XrdPlot.svelte +0 -615
- package/dist/src/lib/xrd/broadening.ts +0 -130
- package/dist/src/lib/xrd/calc-xrd.ts +0 -397
- package/dist/src/lib/xrd/index.ts +0 -38
- package/dist/src/lib/xrd/parse.ts +0 -858
- package/dist/webview.js +0 -29421
- package/icon.png +0 -0
- package/matterviz-0.3.2.vsix +0 -0
- package/matterviz-0.3.4.vsix +0 -0
- package/matterviz-0.3.5.vsix +0 -0
- package/scripts/sync-config.ts +0 -101
- package/src/declarations.d.ts +0 -2
- package/src/extension.ts +0 -972
- package/src/node-io.ts +0 -65
- package/src/types.ts +0 -17
- package/src/webview/JsonBrowser.svelte +0 -1079
- package/src/webview/PlotPanel.svelte +0 -346
- package/src/webview/detect.ts +0 -444
- package/src/webview/main.ts +0 -764
- package/src/webview/plot-utils.ts +0 -250
- package/test-fixtures/all-viz-types.json.gz +0 -0
- package/test-fixtures/plot-demo-data.json.gz +0 -0
- package/tests/detect.test.ts +0 -604
- package/tests/extension.test.ts +0 -2041
- package/tests/node-io.test.ts +0 -39
- package/tests/plot-utils.test.ts +0 -302
- package/tests/vite-plugin-json-gz.test.ts +0 -114
- package/tests/vscode-mock.ts +0 -18
- package/tests/webview.test.ts +0 -231
- package/tsconfig.json +0 -20
- package/vite-plugin-json-gz.ts +0 -29
- package/vite.config.ts +0 -34
- package/vite.extension.config.ts +0 -34
- /package/dist/{src/lib/EmptyState.svelte → EmptyState.svelte} +0 -0
- /package/dist/{src/lib/Icon.svelte → Icon.svelte} +0 -0
- /package/dist/{src/lib/app.css → app.css} +0 -0
- /package/dist/{src/lib/chempot-diagram → chempot-diagram}/ChemPotScene3D.svelte +0 -0
- /package/dist/{src/lib/colors → colors}/alloy-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/dark-mode-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/jmol-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/muted-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/pastel-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/vesta-colors.json +0 -0
- /package/dist/{src/lib/convex-hull → convex-hull}/TemperatureSlider.svelte +0 -0
- /package/dist/{src/lib/element → element}/BohrAtom.svelte +0 -0
- /package/dist/{src/lib/element → element}/Nucleus.svelte +0 -0
- /package/dist/{src/lib/element → element}/data.json +0 -0
- /package/dist/{src/lib/element → element}/data.json.gz +0 -0
- /package/dist/{src/lib/element → element}/data.json.gz.d.ts +0 -0
- /package/dist/{src/lib/element → element}/data.schema.json +0 -0
- /package/dist/{src/lib/element-image-urls.json → element-image-urls.json} +0 -0
- /package/dist/{src/lib/feedback → feedback}/Spinner.svelte +0 -0
- /package/dist/{src/lib/feedback → feedback}/StatusMessage.svelte +0 -0
- /package/dist/{src/lib/layout → layout}/json-tree/JsonValue.svelte +0 -0
- /package/dist/{src/lib/periodic-table → periodic-table}/TableInset.svelte +0 -0
- /package/dist/{src/lib/plot → plot}/FillArea.svelte +0 -0
- /package/dist/{src/lib/plot → plot}/ReferenceLine.svelte +0 -0
- /package/dist/{src/lib/theme → theme}/themes.mjs +0 -0
- /package/dist/{src/lib/xrd → xrd}/atomic_scattering_params.json +0 -0
|
@@ -1,1833 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { luminance, watch_dark_mode } from '$lib/colors'
|
|
3
|
-
import Icon from '$lib/Icon.svelte'
|
|
4
|
-
import { format_num } from '$lib/labels'
|
|
5
|
-
import { SettingsSection } from '$lib/layout'
|
|
6
|
-
import ContextMenu from '$lib/overlays/ContextMenu.svelte'
|
|
7
|
-
import DraggablePane from '$lib/overlays/DraggablePane.svelte'
|
|
8
|
-
import type {
|
|
9
|
-
CellSnippet,
|
|
10
|
-
CellVal,
|
|
11
|
-
ExportData,
|
|
12
|
-
InitialSort,
|
|
13
|
-
Label,
|
|
14
|
-
MultiSortState,
|
|
15
|
-
Pagination,
|
|
16
|
-
RowData,
|
|
17
|
-
Search,
|
|
18
|
-
SortHint,
|
|
19
|
-
SortState,
|
|
20
|
-
SpecialCells,
|
|
21
|
-
} from '$lib/table'
|
|
22
|
-
import { calc_cell_color, strip_html } from '$lib/table'
|
|
23
|
-
import { sanitize_html } from '$lib/sanitize'
|
|
24
|
-
import { normalize_unicode_minus } from '$lib/utils'
|
|
25
|
-
import type { Snippet } from 'svelte'
|
|
26
|
-
import { tooltip } from 'svelte-multiselect/attachments'
|
|
27
|
-
import { flip } from 'svelte/animate'
|
|
28
|
-
import type { HTMLAttributes } from 'svelte/elements'
|
|
29
|
-
import { SvelteMap } from 'svelte/reactivity'
|
|
30
|
-
|
|
31
|
-
// Helper to check if value is invalid (null, undefined, NaN)
|
|
32
|
-
const is_invalid = (val: unknown) =>
|
|
33
|
-
val == null || (typeof val === `number` && Number.isNaN(val))
|
|
34
|
-
|
|
35
|
-
const NUMERIC_WITH_ERROR_RE =
|
|
36
|
-
/^([-+−]?(?:\d+\.?\d*|\d*\.\d+)(?:[eE][-+−]?\d+)?)\s*(?:±|\+[-−]|\()/
|
|
37
|
-
|
|
38
|
-
const parse_numeric_string = (val: string): number | null => {
|
|
39
|
-
const numeric_str = val.match(NUMERIC_WITH_ERROR_RE)?.[1] ?? val
|
|
40
|
-
if (numeric_str.trim() === ``) return null
|
|
41
|
-
const num = Number(normalize_unicode_minus(numeric_str))
|
|
42
|
-
return isNaN(num) ? null : num
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Get sort value from a cell (handles HTML data-sort-value and numbers with errors)
|
|
46
|
-
const get_sort_val = (val: CellVal): string | number => {
|
|
47
|
-
if (typeof val === `string`) {
|
|
48
|
-
// Check for HTML data-sort-value attribute first
|
|
49
|
-
const sort_attr_match = val.match(/data-sort-value="([^"]*)"/)
|
|
50
|
-
if (sort_attr_match) {
|
|
51
|
-
const num = Number(sort_attr_match[1])
|
|
52
|
-
return isNaN(num) ? sort_attr_match[1] : num
|
|
53
|
-
}
|
|
54
|
-
const num = parse_numeric_string(val)
|
|
55
|
-
if (num !== null) return num
|
|
56
|
-
}
|
|
57
|
-
return val as string | number
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let {
|
|
61
|
-
data = $bindable([]),
|
|
62
|
-
columns = [],
|
|
63
|
-
sort_hint = undefined,
|
|
64
|
-
cell,
|
|
65
|
-
special_cells,
|
|
66
|
-
controls,
|
|
67
|
-
initial_sort = undefined,
|
|
68
|
-
sort = $bindable({ column: ``, dir: `asc` }), // allows external control/sync of sorting
|
|
69
|
-
fixed_header = false,
|
|
70
|
-
default_num_format = `.3`,
|
|
71
|
-
show_heatmap = $bindable(true),
|
|
72
|
-
heatmap_class = `heatmap`,
|
|
73
|
-
onrowclick,
|
|
74
|
-
onrowdblclick,
|
|
75
|
-
column_order = $bindable([]),
|
|
76
|
-
export_data = false,
|
|
77
|
-
show_column_toggle = false,
|
|
78
|
-
search = false,
|
|
79
|
-
show_row_select = false,
|
|
80
|
-
pagination = false,
|
|
81
|
-
selected_rows = $bindable([]),
|
|
82
|
-
hidden_columns = $bindable([]),
|
|
83
|
-
scroll_style,
|
|
84
|
-
root_style,
|
|
85
|
-
onsort = undefined,
|
|
86
|
-
onsorterror = undefined,
|
|
87
|
-
loading = $bindable(false),
|
|
88
|
-
sort_data = true,
|
|
89
|
-
heatmap_opacity = $bindable(1),
|
|
90
|
-
empty_message = `No data`,
|
|
91
|
-
show_row_numbers = false,
|
|
92
|
-
allow_better_toggle = false,
|
|
93
|
-
show_controls = $bindable(false),
|
|
94
|
-
controls_open = $bindable(false),
|
|
95
|
-
header_cell,
|
|
96
|
-
footer,
|
|
97
|
-
...rest
|
|
98
|
-
}: HTMLAttributes<HTMLDivElement> & {
|
|
99
|
-
data: RowData[]
|
|
100
|
-
columns?: Label[]
|
|
101
|
-
sort_hint?: SortHint
|
|
102
|
-
cell?: CellSnippet
|
|
103
|
-
special_cells?: SpecialCells
|
|
104
|
-
controls?: Snippet
|
|
105
|
-
initial_sort?: InitialSort
|
|
106
|
-
sort?: { column: string; dir: `asc` | `desc` }
|
|
107
|
-
fixed_header?: boolean
|
|
108
|
-
default_num_format?: string
|
|
109
|
-
show_heatmap?: boolean
|
|
110
|
-
heatmap_class?: string
|
|
111
|
-
onrowclick?: (event: MouseEvent | KeyboardEvent, row: RowData) => void
|
|
112
|
-
onrowdblclick?: (event: MouseEvent, row: RowData) => void
|
|
113
|
-
// Array of column IDs to control display order. IDs are derived as:
|
|
114
|
-
// - Ungrouped columns: col.key ?? col.label
|
|
115
|
-
// - Grouped columns: `${col.key ?? col.label} (${col.group})`
|
|
116
|
-
// This allows persisting/restoring column order across sessions.
|
|
117
|
-
column_order?: string[]
|
|
118
|
-
export_data?: ExportData
|
|
119
|
-
show_column_toggle?: boolean
|
|
120
|
-
search?: Search
|
|
121
|
-
show_row_select?: boolean
|
|
122
|
-
pagination?: Pagination
|
|
123
|
-
selected_rows?: RowData[]
|
|
124
|
-
hidden_columns?: string[]
|
|
125
|
-
scroll_style?: string
|
|
126
|
-
// Inline styles for the root table container (merged with rest.style). Use instead of global CSS overrides.
|
|
127
|
-
root_style?: string
|
|
128
|
-
// Async callback for server-side sorting. When provided, client-side sorting is skipped
|
|
129
|
-
// and the callback is called with (column_id, direction) to fetch new data from server.
|
|
130
|
-
onsort?: (column: string, dir: `asc` | `desc`) => Promise<RowData[]>
|
|
131
|
-
// Callback when onsort fails, receives the error for parent handling (e.g. toast notification)
|
|
132
|
-
onsorterror?: (error: unknown, column: string, dir: `asc` | `desc`) => void
|
|
133
|
-
// Loading state during async sort operations
|
|
134
|
-
loading?: boolean
|
|
135
|
-
// Whether to sort data client-side. Set to false when parent handles sorting externally.
|
|
136
|
-
// When onsort is provided, sort_data behavior is implicitly false.
|
|
137
|
-
sort_data?: boolean
|
|
138
|
-
// Heatmap cell background opacity (0–1). Controls both the visual fade via CSS
|
|
139
|
-
// color-mix() and the JS text contrast correction. Default 1 (fully opaque).
|
|
140
|
-
heatmap_opacity?: number
|
|
141
|
-
// Message shown when the table has no data rows. Set to empty string to hide.
|
|
142
|
-
empty_message?: string
|
|
143
|
-
// Show a row number column as the first column
|
|
144
|
-
show_row_numbers?: boolean
|
|
145
|
-
// When true, show a toggle in colored column headers to cycle gradient direction
|
|
146
|
-
allow_better_toggle?: boolean
|
|
147
|
-
// Whether the gear icon for the controls pane is visible
|
|
148
|
-
show_controls?: boolean
|
|
149
|
-
// Whether the controls pane is expanded
|
|
150
|
-
controls_open?: boolean
|
|
151
|
-
// Custom snippet for rendering header cells. Falls back to {@html col.label}.
|
|
152
|
-
header_cell?: Snippet<[{ col: Label }]>
|
|
153
|
-
// Footer snippet rendered inside <tfoot> below the table body
|
|
154
|
-
footer?: Snippet
|
|
155
|
-
} = $props()
|
|
156
|
-
|
|
157
|
-
let container_el = $state<HTMLDivElement>()
|
|
158
|
-
|
|
159
|
-
// Read --page-bg from computed style for text contrast calculation.
|
|
160
|
-
// Recalculates on mount and when the theme changes (dark/light mode toggle).
|
|
161
|
-
let page_bg_lum = $state(luminance(`white`))
|
|
162
|
-
$effect(() => {
|
|
163
|
-
if (!container_el) return
|
|
164
|
-
const read_page_bg = () => {
|
|
165
|
-
if (!container_el) return
|
|
166
|
-
const page_bg = getComputedStyle(container_el).getPropertyValue(`--page-bg`)
|
|
167
|
-
.trim()
|
|
168
|
-
page_bg_lum = luminance(page_bg || `white`)
|
|
169
|
-
}
|
|
170
|
-
read_page_bg()
|
|
171
|
-
return watch_dark_mode(read_page_bg)
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// Detect HTML to prevent setting raw HTML as data-sort-value. Simple string matching
|
|
175
|
-
// suffices since false positives just skip setting the attr (sorting still works by inner data-sort-value).
|
|
176
|
-
function is_html_str(val: unknown): boolean {
|
|
177
|
-
if (typeof val !== `string`) return false
|
|
178
|
-
return (
|
|
179
|
-
(val.includes(`<`) && val.includes(`>`)) || // Has angle brackets
|
|
180
|
-
val.startsWith(`<`) || // Has HTML entity for <
|
|
181
|
-
val.includes(`href=`) || // Has href attribute
|
|
182
|
-
val.includes(`class=`) // Has class attribute
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Normalize initial_sort config
|
|
187
|
-
let initial_sort_config = $derived(
|
|
188
|
-
initial_sort
|
|
189
|
-
? typeof initial_sort === `string`
|
|
190
|
-
? { column: initial_sort, direction: `asc` as const }
|
|
191
|
-
: { direction: `asc` as const, ...initial_sort }
|
|
192
|
-
: null,
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
// Normalize pagination config
|
|
196
|
-
let pagination_config = $derived(
|
|
197
|
-
pagination
|
|
198
|
-
? { page_size: 25, ...(typeof pagination === `object` ? pagination : {}) }
|
|
199
|
-
: null,
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
// Mutable page size — writable $derived allows user to change via dropdown
|
|
203
|
-
let effective_page_size = $derived(pagination_config?.page_size ?? 25)
|
|
204
|
-
|
|
205
|
-
// Normalize search config
|
|
206
|
-
let search_config = $derived(
|
|
207
|
-
search
|
|
208
|
-
? {
|
|
209
|
-
placeholder: `Filter...`,
|
|
210
|
-
expanded: false,
|
|
211
|
-
...(typeof search === `object` ? search : {}),
|
|
212
|
-
}
|
|
213
|
-
: null,
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
// Normalize export_data config
|
|
217
|
-
type ExportFormat = `csv` | `json`
|
|
218
|
-
const default_formats: ExportFormat[] = [`csv`, `json`]
|
|
219
|
-
let export_config = $derived(
|
|
220
|
-
export_data
|
|
221
|
-
? {
|
|
222
|
-
formats: default_formats,
|
|
223
|
-
filename: `table-export`,
|
|
224
|
-
...(typeof export_data === `object` ? export_data : {}),
|
|
225
|
-
}
|
|
226
|
-
: null,
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
// Derive sort_state from bindable prop, falling back to initial_sort if sort not yet set
|
|
230
|
-
// This ensures immediate sorting on first render without waiting for effects
|
|
231
|
-
let sort_state = $derived<SortState>({
|
|
232
|
-
column: sort.column || initial_sort_config?.column || ``,
|
|
233
|
-
ascending: sort.column
|
|
234
|
-
? sort.dir !== `desc`
|
|
235
|
-
: initial_sort_config?.direction !== `desc`,
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
// Multi-column sort state (for Shift+click)
|
|
239
|
-
let multi_sort = $state<MultiSortState>([])
|
|
240
|
-
|
|
241
|
-
// Search/filter state
|
|
242
|
-
let search_query = $state(``)
|
|
243
|
-
let search_expanded = $derived(search_config?.expanded ?? false)
|
|
244
|
-
|
|
245
|
-
// Pagination state
|
|
246
|
-
let current_page = $state(1)
|
|
247
|
-
|
|
248
|
-
// Dropdown states
|
|
249
|
-
let show_column_dropdown = $state(false)
|
|
250
|
-
let show_export_dropdown = $state(false)
|
|
251
|
-
|
|
252
|
-
// Per-column gradient direction overrides (user-toggled via header)
|
|
253
|
-
let better_overrides = new SvelteMap<string, `higher` | `lower`>()
|
|
254
|
-
|
|
255
|
-
// Per-column color scale overrides
|
|
256
|
-
let color_scale_overrides = new SvelteMap<string, string>()
|
|
257
|
-
|
|
258
|
-
const color_scale_options = [
|
|
259
|
-
`interpolateViridis`,
|
|
260
|
-
`interpolatePlasma`,
|
|
261
|
-
`interpolateInferno`,
|
|
262
|
-
`interpolateCividis`,
|
|
263
|
-
`interpolateTurbo`,
|
|
264
|
-
`interpolateBlues`,
|
|
265
|
-
`interpolateGreens`,
|
|
266
|
-
`interpolateReds`,
|
|
267
|
-
`interpolateYlOrRd`,
|
|
268
|
-
] as const
|
|
269
|
-
|
|
270
|
-
// Columns that have a color gradient
|
|
271
|
-
let colored_columns = $derived(
|
|
272
|
-
columns.filter((col) =>
|
|
273
|
-
col.color_scale !== null && col.color_scale !== undefined
|
|
274
|
-
),
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
// Column resize state
|
|
278
|
-
let resize_col_id = $state<string | null>(null)
|
|
279
|
-
let resize_start_x = $state(0)
|
|
280
|
-
let resize_start_width = $state(0)
|
|
281
|
-
let column_widths = $state<Record<string, number>>({})
|
|
282
|
-
|
|
283
|
-
// Auto-discover columns from data keys when none are provided
|
|
284
|
-
$effect.pre(() => {
|
|
285
|
-
if (columns.length > 0 || data.length === 0) return
|
|
286
|
-
const seen: Record<string, true> = {}
|
|
287
|
-
for (const row of data.slice(0, 50)) {
|
|
288
|
-
for (const key of Object.keys(row)) {
|
|
289
|
-
if (key !== `style` && key !== `class`) seen[key] = true
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
columns = Object.keys(seen).map((key) => ({ label: key }))
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
// Helper to make column IDs (needed since column labels in different groups can be repeated)
|
|
296
|
-
const get_col_id = (col: Label) =>
|
|
297
|
-
col.group ? `${col.key ?? col.label} (${col.group})` : (col.key ?? col.label)
|
|
298
|
-
|
|
299
|
-
// Sync column_order with columns: initialize if empty, remove stale IDs, append new IDs
|
|
300
|
-
$effect(() => {
|
|
301
|
-
if (columns.length === 0) return
|
|
302
|
-
const col_ids = columns.map(get_col_id)
|
|
303
|
-
|
|
304
|
-
// Case 1: First render - initialize with default order
|
|
305
|
-
if (column_order.length === 0) {
|
|
306
|
-
column_order = col_ids
|
|
307
|
-
return
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Case 2: Sync needed - keep valid IDs in their order, append any new ones
|
|
311
|
-
const valid_ids = new Set(col_ids)
|
|
312
|
-
const kept = column_order.filter((id) => valid_ids.has(id))
|
|
313
|
-
const new_ids = col_ids.filter((id) => !kept.includes(id))
|
|
314
|
-
const new_order = [...kept, ...new_ids]
|
|
315
|
-
|
|
316
|
-
// Skip assignment if content is unchanged to prevent infinite effect loop.
|
|
317
|
-
// After drag reorder, column_order differs from col_ids (default order) but the
|
|
318
|
-
// computed new_order equals the current column_order — assigning a new array
|
|
319
|
-
// reference would re-trigger this effect endlessly.
|
|
320
|
-
if (new_order.length === column_order.length &&
|
|
321
|
-
new_order.every((id, idx) => id === column_order[idx])) return
|
|
322
|
-
|
|
323
|
-
column_order = new_order
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
// Reorder columns based on column_order
|
|
327
|
-
let ordered_columns = $derived.by(() => {
|
|
328
|
-
if (column_order.length === 0) return columns
|
|
329
|
-
|
|
330
|
-
const col_map = new SvelteMap(columns.map((col) => [get_col_id(col), col]))
|
|
331
|
-
|
|
332
|
-
// Add columns in specified order, then any remaining columns that weren't in the order list
|
|
333
|
-
const ordered = column_order
|
|
334
|
-
.map((id) => col_map.get(id))
|
|
335
|
-
.filter((col): col is Label => col != null)
|
|
336
|
-
|
|
337
|
-
const ordered_ids = new Set(ordered.map(get_col_id))
|
|
338
|
-
const remaining = columns.filter((col) => !ordered_ids.has(get_col_id(col)))
|
|
339
|
-
|
|
340
|
-
return [...ordered, ...remaining]
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
let drag_col_id = $state<string | null>(null)
|
|
344
|
-
let drag_over_col_id = $state<string | null>(null)
|
|
345
|
-
|
|
346
|
-
// Merge root_style with rest.style for root div; omit style from rest to avoid duplicate
|
|
347
|
-
let rest_props = $derived.by(() => {
|
|
348
|
-
const { style: rest_style, ...other_props } = rest
|
|
349
|
-
const merged = [rest_style, root_style].filter(Boolean).join(`; `)
|
|
350
|
-
return { ...other_props, ...(merged ? { style: merged } : {}) }
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
// WeakMap to assign stable unique IDs to row objects for efficient comparison and keying
|
|
354
|
-
// This avoids O(n) JSON.stringify calls and prevents unnecessary re-renders
|
|
355
|
-
const row_id_map = new WeakMap<RowData, string>()
|
|
356
|
-
let row_id_counter = 0
|
|
357
|
-
|
|
358
|
-
function get_row_id(row: RowData): string {
|
|
359
|
-
let id = row_id_map.get(row)
|
|
360
|
-
if (id === undefined) {
|
|
361
|
-
id = `row_${row_id_counter++}`
|
|
362
|
-
row_id_map.set(row, id)
|
|
363
|
-
}
|
|
364
|
-
return id
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Returns 'left' or 'right' to indicate which side of target to insert dragged column
|
|
368
|
-
function get_drag_side(target_col_id: string): `left` | `right` | null {
|
|
369
|
-
if (!drag_col_id) return null
|
|
370
|
-
const drag_idx = column_order.indexOf(drag_col_id)
|
|
371
|
-
const target_idx = column_order.indexOf(target_col_id)
|
|
372
|
-
if (drag_idx === -1 || target_idx === -1) return null
|
|
373
|
-
return drag_idx < target_idx ? `right` : `left`
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function reset_drag_state() {
|
|
377
|
-
drag_col_id = null
|
|
378
|
-
drag_over_col_id = null
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const get_drag_col_group = () =>
|
|
382
|
-
ordered_columns.find((col) => get_col_id(col) === drag_col_id)?.group
|
|
383
|
-
|
|
384
|
-
function handle_drag_start(event: DragEvent, col: Label) {
|
|
385
|
-
if (!event.dataTransfer) return
|
|
386
|
-
drag_col_id = get_col_id(col)
|
|
387
|
-
event.dataTransfer.effectAllowed = `move`
|
|
388
|
-
event.dataTransfer.setData(`text/html`, ``)
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function handle_drag_over(event: DragEvent, col: Label) {
|
|
392
|
-
event.preventDefault()
|
|
393
|
-
if (!event.dataTransfer) return
|
|
394
|
-
event.dataTransfer.dropEffect = `move`
|
|
395
|
-
|
|
396
|
-
// Prevent cross-group drag-over to keep group headers contiguous
|
|
397
|
-
if (get_drag_col_group() !== col.group) {
|
|
398
|
-
event.dataTransfer.dropEffect = `none`
|
|
399
|
-
drag_over_col_id = null
|
|
400
|
-
return
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
drag_over_col_id = get_col_id(col)
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function handle_drop(event: DragEvent, target_col: Label) {
|
|
407
|
-
event.preventDefault()
|
|
408
|
-
|
|
409
|
-
// Block cross-group (or group→ungroup) reorders to preserve group contiguity
|
|
410
|
-
if (!drag_col_id || drag_col_id === get_col_id(target_col)) {
|
|
411
|
-
reset_drag_state()
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Block cross-group reorders to preserve group contiguity
|
|
416
|
-
if (get_drag_col_group() !== target_col.group) {
|
|
417
|
-
reset_drag_state()
|
|
418
|
-
return
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
const target_col_id = get_col_id(target_col)
|
|
422
|
-
const drag_idx = column_order.indexOf(drag_col_id)
|
|
423
|
-
const target_idx = column_order.indexOf(target_col_id)
|
|
424
|
-
|
|
425
|
-
if (drag_idx === -1 || target_idx === -1) {
|
|
426
|
-
reset_drag_state()
|
|
427
|
-
return
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Reorder: remove dragged column, then insert at target position
|
|
431
|
-
// When dragging left-to-right (drag_idx < target_idx), removing the dragged
|
|
432
|
-
// element shifts all subsequent indices down by 1, so we must adjust target_idx
|
|
433
|
-
const new_order = [...column_order]
|
|
434
|
-
new_order.splice(drag_idx, 1)
|
|
435
|
-
const adjusted_target = drag_idx < target_idx ? target_idx - 1 : target_idx
|
|
436
|
-
new_order.splice(adjusted_target, 0, drag_col_id)
|
|
437
|
-
column_order = new_order
|
|
438
|
-
reset_drag_state()
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Filter data based on search query
|
|
442
|
-
let filtered_data = $derived.by(() => {
|
|
443
|
-
const base_data = data?.filter?.((row) =>
|
|
444
|
-
Object.values(row).some((val) => val !== undefined)
|
|
445
|
-
) ?? []
|
|
446
|
-
|
|
447
|
-
if (!search_query.trim()) return base_data
|
|
448
|
-
|
|
449
|
-
const query = search_query.toLowerCase().trim()
|
|
450
|
-
return base_data.filter((row) =>
|
|
451
|
-
Object.values(row).some((val) => {
|
|
452
|
-
if (val == null) return false
|
|
453
|
-
const clean_val = strip_html(String(val)).toLowerCase()
|
|
454
|
-
return clean_val.includes(query)
|
|
455
|
-
})
|
|
456
|
-
)
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
let sorted_data = $derived.by(() => {
|
|
460
|
-
// Skip client-side sorting when using async onsort callback or sort_data is false
|
|
461
|
-
if (onsort || !sort_data) return filtered_data
|
|
462
|
-
|
|
463
|
-
if (!sort_state.column && multi_sort.length === 0) return filtered_data
|
|
464
|
-
|
|
465
|
-
// Build sort criteria: multi_sort takes precedence, fallback to single sort
|
|
466
|
-
const sort_criteria = multi_sort.length > 0
|
|
467
|
-
? multi_sort
|
|
468
|
-
: sort_state.column
|
|
469
|
-
? [sort_state]
|
|
470
|
-
: []
|
|
471
|
-
|
|
472
|
-
if (sort_criteria.length === 0) return filtered_data
|
|
473
|
-
|
|
474
|
-
return [...filtered_data].sort((row1, row2) => {
|
|
475
|
-
for (const { column, ascending } of sort_criteria) {
|
|
476
|
-
const matched_col = ordered_columns.find((col) => get_col_id(col) === column)
|
|
477
|
-
if (!matched_col) continue
|
|
478
|
-
|
|
479
|
-
const col_id = get_col_id(matched_col)
|
|
480
|
-
const val1 = row1[col_id]
|
|
481
|
-
const val2 = row2[col_id]
|
|
482
|
-
|
|
483
|
-
if (val1 === val2) continue
|
|
484
|
-
|
|
485
|
-
// Push invalid values to bottom
|
|
486
|
-
if (is_invalid(val1) || is_invalid(val2)) {
|
|
487
|
-
return +is_invalid(val1) - +is_invalid(val2)
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const sort_val1 = get_sort_val(val1)
|
|
491
|
-
const sort_val2 = get_sort_val(val2)
|
|
492
|
-
const modifier = ascending ? 1 : -1
|
|
493
|
-
|
|
494
|
-
if (typeof sort_val1 === `string` && typeof sort_val2 === `string`) {
|
|
495
|
-
const cmp = sort_val1.localeCompare(sort_val2, undefined, {
|
|
496
|
-
numeric: true,
|
|
497
|
-
sensitivity: `base`,
|
|
498
|
-
})
|
|
499
|
-
if (cmp !== 0) return cmp * modifier
|
|
500
|
-
} else {
|
|
501
|
-
if (sort_val1 !== sort_val2) {
|
|
502
|
-
return (sort_val1 ?? 0) < (sort_val2 ?? 0) ? -modifier : modifier
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
return 0
|
|
507
|
-
})
|
|
508
|
-
})
|
|
509
|
-
|
|
510
|
-
// Paginated data
|
|
511
|
-
let paginated_data = $derived.by(() => {
|
|
512
|
-
if (!pagination_config) return sorted_data
|
|
513
|
-
const start = (current_page - 1) * effective_page_size
|
|
514
|
-
return sorted_data.slice(start, start + effective_page_size)
|
|
515
|
-
})
|
|
516
|
-
|
|
517
|
-
let total_pages = $derived(
|
|
518
|
-
Math.ceil(sorted_data.length / effective_page_size),
|
|
519
|
-
)
|
|
520
|
-
|
|
521
|
-
// Track previous values to detect actual changes
|
|
522
|
-
let prev_search_query = $state(``)
|
|
523
|
-
let prev_data_length = $state(0)
|
|
524
|
-
|
|
525
|
-
// Track async sort requests to prevent race conditions
|
|
526
|
-
let sort_request_id = 0
|
|
527
|
-
|
|
528
|
-
// Reset to page 1 when search query or data length actually changes
|
|
529
|
-
$effect(() => {
|
|
530
|
-
const query_changed = search_query !== prev_search_query
|
|
531
|
-
const data_changed = sorted_data.length !== prev_data_length
|
|
532
|
-
|
|
533
|
-
if (query_changed || data_changed) {
|
|
534
|
-
current_page = 1
|
|
535
|
-
prev_search_query = search_query
|
|
536
|
-
prev_data_length = sorted_data.length
|
|
537
|
-
} else if (total_pages > 0 && current_page > total_pages) {
|
|
538
|
-
// Clamp when total pages decreases (e.g., page size increase)
|
|
539
|
-
current_page = total_pages
|
|
540
|
-
}
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
async function sort_rows(
|
|
544
|
-
column: string,
|
|
545
|
-
group: string | undefined,
|
|
546
|
-
event: MouseEvent | KeyboardEvent,
|
|
547
|
-
) {
|
|
548
|
-
// Find the column using both label and group if provided
|
|
549
|
-
const col = ordered_columns.find(
|
|
550
|
-
(candidate_col) => candidate_col.label === column && candidate_col.group === group,
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
if (!col) return // Skip if column not found
|
|
554
|
-
if (col.sortable === false) return // Skip sorting if column marked as unsortable
|
|
555
|
-
|
|
556
|
-
const col_id = get_col_id(col)
|
|
557
|
-
|
|
558
|
-
// Shift+click for multi-column sort
|
|
559
|
-
if (event.shiftKey) {
|
|
560
|
-
const existing_idx = multi_sort.findIndex((sort_entry) => sort_entry.column === col_id)
|
|
561
|
-
if (existing_idx >= 0) {
|
|
562
|
-
// Toggle direction or remove if clicked again
|
|
563
|
-
const existing = multi_sort[existing_idx]
|
|
564
|
-
if (existing.ascending === (col.better === `lower`)) {
|
|
565
|
-
// Remove from multi-sort
|
|
566
|
-
multi_sort = multi_sort.filter((_, idx) => idx !== existing_idx)
|
|
567
|
-
} else {
|
|
568
|
-
// Toggle direction
|
|
569
|
-
multi_sort = multi_sort.map((sort_entry, idx) =>
|
|
570
|
-
idx === existing_idx ? { ...sort_entry, ascending: !sort_entry.ascending } : sort_entry
|
|
571
|
-
)
|
|
572
|
-
}
|
|
573
|
-
} else {
|
|
574
|
-
// Add to multi-sort
|
|
575
|
-
multi_sort = [...multi_sort, {
|
|
576
|
-
column: col_id,
|
|
577
|
-
ascending: col.better === `lower`,
|
|
578
|
-
}]
|
|
579
|
-
}
|
|
580
|
-
// Clear single sort when using multi-sort
|
|
581
|
-
sort = { column: ``, dir: `asc` }
|
|
582
|
-
} else {
|
|
583
|
-
// Regular click - single column sort
|
|
584
|
-
multi_sort = [] // Clear multi-sort
|
|
585
|
-
// Use sort_state.column for comparison since it includes initial_sort fallback
|
|
586
|
-
const new_dir = sort_state.column !== col_id
|
|
587
|
-
? (col.better === `lower` ? `asc` : `desc`)
|
|
588
|
-
: (sort_state.ascending ? `desc` : `asc`)
|
|
589
|
-
|
|
590
|
-
// Save previous sort state in case we need to revert on error
|
|
591
|
-
const prev_sort = { ...sort }
|
|
592
|
-
sort = { column: col_id, dir: new_dir }
|
|
593
|
-
|
|
594
|
-
// If onsort callback provided, fetch new data from server
|
|
595
|
-
if (onsort) {
|
|
596
|
-
loading = true
|
|
597
|
-
const request_id = ++sort_request_id
|
|
598
|
-
try {
|
|
599
|
-
const result = await onsort(col_id, new_dir)
|
|
600
|
-
// Only update if this is still the most recent request (avoid race condition)
|
|
601
|
-
if (request_id === sort_request_id) {
|
|
602
|
-
data = result
|
|
603
|
-
}
|
|
604
|
-
} catch (err) {
|
|
605
|
-
console.error(`Sort callback failed:`, err)
|
|
606
|
-
// Revert sort state on failure so UI doesn't show wrong direction
|
|
607
|
-
if (request_id === sort_request_id) {
|
|
608
|
-
sort = prev_sort
|
|
609
|
-
onsorterror?.(err, col_id, new_dir)
|
|
610
|
-
}
|
|
611
|
-
} finally {
|
|
612
|
-
// Only clear loading if this is still the most recent request
|
|
613
|
-
if (request_id === sort_request_id) {
|
|
614
|
-
loading = false
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// Extract numeric value from strings with uncertainty notation: "1.23 ± 0.05", "1.23 +- 0.05", "1.23(5)"
|
|
622
|
-
function parse_numeric_val(val: CellVal): number | null {
|
|
623
|
-
if (typeof val === `number`) return Number.isNaN(val) ? null : val
|
|
624
|
-
return typeof val === `string` ? parse_numeric_string(val) : null
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// Memoize parsed column values to avoid O(N²) re-parsing in calc_color
|
|
628
|
-
let parsed_column_values = $derived.by(() => {
|
|
629
|
-
const result = new SvelteMap<string, (number | null)[]>()
|
|
630
|
-
for (const col of ordered_columns) {
|
|
631
|
-
if (col.color_scale === null) continue
|
|
632
|
-
const col_id = get_col_id(col)
|
|
633
|
-
result.set(col_id, sorted_data.map((row) => parse_numeric_val(row[col_id])))
|
|
634
|
-
}
|
|
635
|
-
return result
|
|
636
|
-
})
|
|
637
|
-
|
|
638
|
-
function calc_color(val: CellVal, col: Label) {
|
|
639
|
-
if (!show_heatmap || col.color_scale === null) {
|
|
640
|
-
return { bg: null, text: null }
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Parse numeric value from strings with uncertainty notation
|
|
644
|
-
const numeric_val = parse_numeric_val(val)
|
|
645
|
-
if (numeric_val === null) return { bg: null, text: null }
|
|
646
|
-
|
|
647
|
-
const col_id = get_col_id(col)
|
|
648
|
-
// Use memoized parsed values for the column
|
|
649
|
-
const numeric_vals = parsed_column_values.get(col_id) ?? []
|
|
650
|
-
|
|
651
|
-
const better = better_overrides.get(col_id) ?? col.better
|
|
652
|
-
const scale = (color_scale_overrides.get(col_id) ?? col.color_scale ??
|
|
653
|
-
`interpolateViridis`) as Parameters<typeof calc_cell_color>[3]
|
|
654
|
-
const color = calc_cell_color(
|
|
655
|
-
numeric_val,
|
|
656
|
-
numeric_vals,
|
|
657
|
-
better,
|
|
658
|
-
scale,
|
|
659
|
-
col.scale_type || `linear`,
|
|
660
|
-
)
|
|
661
|
-
|
|
662
|
-
// Recompute text contrast against effective bg (cell bg blended with page bg by opacity).
|
|
663
|
-
// Approximation: blend luminances directly; accurate enough for black/white text choice.
|
|
664
|
-
if (color.bg && heatmap_opacity < 1) {
|
|
665
|
-
const blended_lum = luminance(color.bg) * heatmap_opacity +
|
|
666
|
-
page_bg_lum * (1 - heatmap_opacity)
|
|
667
|
-
color.text = blended_lum > 0.7 ? `black` : `white`
|
|
668
|
-
}
|
|
669
|
-
return color
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
let visible_columns = $derived(
|
|
673
|
-
ordered_columns.filter((col) =>
|
|
674
|
-
col.visible !== false && !hidden_columns.includes(get_col_id(col))
|
|
675
|
-
),
|
|
676
|
-
)
|
|
677
|
-
|
|
678
|
-
const sort_indicator = (col: Label, current_sort_state: SortState) => {
|
|
679
|
-
const hide_sort_indicator = col.show_sort_indicator === false ||
|
|
680
|
-
col.style?.includes(`--hide-sort-indicator`)
|
|
681
|
-
if (hide_sort_indicator) return ``
|
|
682
|
-
|
|
683
|
-
const col_id = get_col_id(col)
|
|
684
|
-
|
|
685
|
-
// Check multi-sort first
|
|
686
|
-
const multi_idx = multi_sort.findIndex((sort_entry) => sort_entry.column === col_id)
|
|
687
|
-
if (multi_idx >= 0) {
|
|
688
|
-
const arrow = multi_sort[multi_idx].ascending ? `↓` : `↑`
|
|
689
|
-
const badge = multi_sort.length > 1 ? `<sup>${multi_idx + 1}</sup>` : ``
|
|
690
|
-
return `<span style="font-size: 0.8em;">${arrow}${badge}</span>`
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
const is_sorted = current_sort_state.column === col_id
|
|
694
|
-
if (!is_sorted) return ``
|
|
695
|
-
// Show indicator only for actively sorted columns.
|
|
696
|
-
const arrow = current_sort_state.ascending ? `↓` : `↑`
|
|
697
|
-
|
|
698
|
-
return arrow ? `<span style="font-size: 0.8em;">${arrow}</span>` : ``
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// Context menu state for column header right-click
|
|
702
|
-
let context_menu_col = $state<string | null>(null)
|
|
703
|
-
let context_menu_pos = $state({ x: 0, y: 0 })
|
|
704
|
-
|
|
705
|
-
const better_sections = [
|
|
706
|
-
{
|
|
707
|
-
title: `Gradient direction`,
|
|
708
|
-
options: [
|
|
709
|
-
{ value: `higher`, label: `▲ Higher is better` },
|
|
710
|
-
{ value: `lower`, label: `▼ Lower is better` },
|
|
711
|
-
],
|
|
712
|
-
},
|
|
713
|
-
] as const
|
|
714
|
-
|
|
715
|
-
// Row selection using WeakMap-based ID lookup instead of O(n) JSON.stringify comparison
|
|
716
|
-
function toggle_row_select(row: RowData) {
|
|
717
|
-
const row_id = get_row_id(row)
|
|
718
|
-
const idx = selected_rows.findIndex((selected_row) => get_row_id(selected_row) === row_id)
|
|
719
|
-
if (idx >= 0) {
|
|
720
|
-
selected_rows = selected_rows.filter((_, i) => i !== idx)
|
|
721
|
-
} else {
|
|
722
|
-
selected_rows = [...selected_rows, row]
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
function is_row_selected(row: RowData): boolean {
|
|
727
|
-
const row_id = get_row_id(row)
|
|
728
|
-
return selected_rows.some((selected_row) => get_row_id(selected_row) === row_id)
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// Select-all: checks if every row on the current page is selected
|
|
732
|
-
let all_page_selected = $derived(
|
|
733
|
-
paginated_data.length > 0 && paginated_data.every((row) => is_row_selected(row)),
|
|
734
|
-
)
|
|
735
|
-
|
|
736
|
-
function toggle_select_all() {
|
|
737
|
-
if (all_page_selected) {
|
|
738
|
-
const page_ids = new Set(paginated_data.map(get_row_id))
|
|
739
|
-
selected_rows = selected_rows.filter((row) => !page_ids.has(get_row_id(row)))
|
|
740
|
-
} else {
|
|
741
|
-
const already = new Set(selected_rows.map(get_row_id))
|
|
742
|
-
const new_rows = paginated_data.filter((row) => !already.has(get_row_id(row)))
|
|
743
|
-
selected_rows = [...selected_rows, ...new_rows]
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// Data source for exports: selected rows when any are selected, otherwise all sorted data
|
|
748
|
-
let export_rows = $derived(
|
|
749
|
-
show_row_select && selected_rows.length > 0 ? selected_rows : sorted_data,
|
|
750
|
-
)
|
|
751
|
-
|
|
752
|
-
// Serialize table as delimited text (shared by CSV export and clipboard copy)
|
|
753
|
-
// Per RFC 4180, fields containing commas, double quotes, or newlines must be quoted
|
|
754
|
-
function serialize_table(delimiter: string, csv_quote = false): string {
|
|
755
|
-
const quote = (str: string) => {
|
|
756
|
-
if (!csv_quote) return str
|
|
757
|
-
if (str.includes(`,`) || str.includes(`"`) || str.includes(`\n`)) {
|
|
758
|
-
return `"${str.replace(/"/g, `""`)}"`
|
|
759
|
-
}
|
|
760
|
-
return str
|
|
761
|
-
}
|
|
762
|
-
const headers = visible_columns.map((col) => quote(strip_html(col.label)))
|
|
763
|
-
const rows = export_rows.map((row) =>
|
|
764
|
-
visible_columns.map((col) => {
|
|
765
|
-
const val = row[get_col_id(col)]
|
|
766
|
-
if (val == null) return ``
|
|
767
|
-
return quote(strip_html(String(val)))
|
|
768
|
-
})
|
|
769
|
-
)
|
|
770
|
-
return [headers.join(delimiter), ...rows.map((row) => row.join(delimiter))].join(`\n`)
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
function export_csv(filename = `table-export`) {
|
|
774
|
-
download_file(serialize_table(`,`, true), `${filename}.csv`, `text/csv`)
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
function export_json(filename = `table-export`) {
|
|
778
|
-
const rows = export_rows.map((row) => {
|
|
779
|
-
const clean_row: Record<string, unknown> = {}
|
|
780
|
-
for (const col of visible_columns) {
|
|
781
|
-
const col_id = get_col_id(col)
|
|
782
|
-
const val = row[col_id]
|
|
783
|
-
clean_row[strip_html(col.label)] = typeof val === `string`
|
|
784
|
-
? strip_html(val)
|
|
785
|
-
: val
|
|
786
|
-
}
|
|
787
|
-
return clean_row
|
|
788
|
-
})
|
|
789
|
-
download_file(
|
|
790
|
-
JSON.stringify(rows, null, 2),
|
|
791
|
-
`${filename}.json`,
|
|
792
|
-
`application/json`,
|
|
793
|
-
)
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
function download_file(content: string, filename: string, mime_type: string) {
|
|
797
|
-
const blob = new Blob([content], { type: mime_type })
|
|
798
|
-
const url = URL.createObjectURL(blob)
|
|
799
|
-
const link = document.createElement(`a`)
|
|
800
|
-
link.href = url
|
|
801
|
-
link.download = filename
|
|
802
|
-
document.body.appendChild(link)
|
|
803
|
-
link.click()
|
|
804
|
-
document.body.removeChild(link)
|
|
805
|
-
URL.revokeObjectURL(url)
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
function copy_to_clipboard() {
|
|
809
|
-
navigator.clipboard.writeText(serialize_table(`\t`))
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
// Column visibility toggle
|
|
813
|
-
function toggle_column(col_id: string) {
|
|
814
|
-
if (hidden_columns.includes(col_id)) {
|
|
815
|
-
hidden_columns = hidden_columns.filter((id) => id !== col_id)
|
|
816
|
-
} else {
|
|
817
|
-
hidden_columns = [...hidden_columns, col_id]
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// Column resize handlers
|
|
822
|
-
function start_resize(event: MouseEvent, col: Label) {
|
|
823
|
-
event.preventDefault()
|
|
824
|
-
event.stopPropagation()
|
|
825
|
-
resize_col_id = get_col_id(col)
|
|
826
|
-
resize_start_x = event.clientX
|
|
827
|
-
const th = event.target instanceof Element ? event.target.parentElement : null
|
|
828
|
-
resize_start_width = th?.offsetWidth ?? 100
|
|
829
|
-
|
|
830
|
-
document.addEventListener(`mousemove`, handle_resize)
|
|
831
|
-
document.addEventListener(`mouseup`, stop_resize)
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
function handle_resize(event: MouseEvent) {
|
|
835
|
-
if (!resize_col_id) return
|
|
836
|
-
const delta = event.clientX - resize_start_x
|
|
837
|
-
const new_width = Math.min(500, Math.max(50, resize_start_width + delta))
|
|
838
|
-
column_widths = { ...column_widths, [resize_col_id]: new_width }
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
function stop_resize() {
|
|
842
|
-
resize_col_id = null
|
|
843
|
-
document.removeEventListener(`mousemove`, handle_resize)
|
|
844
|
-
document.removeEventListener(`mouseup`, stop_resize)
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// Normalize sort_hint to a config object with defaults
|
|
848
|
-
let hint_config = $derived(
|
|
849
|
-
sort_hint
|
|
850
|
-
? {
|
|
851
|
-
position: `bottom` as const,
|
|
852
|
-
permanent: false,
|
|
853
|
-
...(typeof sort_hint === `string` ? { text: sort_hint } : sort_hint),
|
|
854
|
-
}
|
|
855
|
-
: null,
|
|
856
|
-
)
|
|
857
|
-
</script>
|
|
858
|
-
|
|
859
|
-
{#snippet sort_hint_element(pos: `top` | `bottom`)}
|
|
860
|
-
{#if hint_config?.position === pos}
|
|
861
|
-
<div
|
|
862
|
-
class="sort-hint {hint_config.class ?? ``}"
|
|
863
|
-
class:permanent={hint_config.permanent}
|
|
864
|
-
style={hint_config.style}
|
|
865
|
-
>
|
|
866
|
-
{hint_config.text}
|
|
867
|
-
</div>
|
|
868
|
-
{/if}
|
|
869
|
-
{/snippet}
|
|
870
|
-
|
|
871
|
-
<div
|
|
872
|
-
{@attach tooltip({ allow_html: true })}
|
|
873
|
-
{...rest_props}
|
|
874
|
-
bind:this={container_el}
|
|
875
|
-
class="table-container {rest_props.class ?? ``}"
|
|
876
|
-
style:--heatmap-opacity="{heatmap_opacity * 100}%"
|
|
877
|
-
onmouseleave={() => {
|
|
878
|
-
show_column_dropdown = false
|
|
879
|
-
show_export_dropdown = false
|
|
880
|
-
context_menu_col = null
|
|
881
|
-
}}
|
|
882
|
-
>
|
|
883
|
-
<!-- Floating control buttons -->
|
|
884
|
-
<section class="control-buttons">
|
|
885
|
-
{#if search_config}
|
|
886
|
-
{#if search_expanded || search_query}
|
|
887
|
-
<input
|
|
888
|
-
type="search"
|
|
889
|
-
class="search-input"
|
|
890
|
-
placeholder={search_config.placeholder}
|
|
891
|
-
bind:value={search_query}
|
|
892
|
-
onblur={() => {
|
|
893
|
-
if (!search_query) search_expanded = false
|
|
894
|
-
}}
|
|
895
|
-
/>
|
|
896
|
-
<button
|
|
897
|
-
class="icon-btn"
|
|
898
|
-
onclick={() => {
|
|
899
|
-
search_query = ``
|
|
900
|
-
search_expanded = false
|
|
901
|
-
}}
|
|
902
|
-
{@attach tooltip({ content: `Clear`, placement: `top` })}
|
|
903
|
-
>
|
|
904
|
-
<Icon icon="Cross" style="width: 10px" />
|
|
905
|
-
</button>
|
|
906
|
-
{:else}
|
|
907
|
-
<button
|
|
908
|
-
class="icon-btn"
|
|
909
|
-
onclick={() => search_expanded = true}
|
|
910
|
-
{@attach tooltip({ content: `Search`, placement: `top` })}
|
|
911
|
-
>
|
|
912
|
-
<Icon icon="Search" style="width: 14px" />
|
|
913
|
-
</button>
|
|
914
|
-
{/if}
|
|
915
|
-
{/if}
|
|
916
|
-
|
|
917
|
-
{#if show_column_toggle}
|
|
918
|
-
<div class="dropdown-wrapper">
|
|
919
|
-
<button
|
|
920
|
-
class="icon-btn"
|
|
921
|
-
class:active={show_column_dropdown}
|
|
922
|
-
onclick={() => show_column_dropdown = !show_column_dropdown}
|
|
923
|
-
{@attach tooltip({ content: `Columns`, placement: `top` })}
|
|
924
|
-
>
|
|
925
|
-
<Icon icon="Columns" style="width: 14px" />
|
|
926
|
-
</button>
|
|
927
|
-
{#if show_column_dropdown}
|
|
928
|
-
<div class="dropdown-pane">
|
|
929
|
-
{#each ordered_columns as col (get_col_id(col))}
|
|
930
|
-
{@const col_id = get_col_id(col)}
|
|
931
|
-
<label class="dropdown-option">
|
|
932
|
-
<input
|
|
933
|
-
type="checkbox"
|
|
934
|
-
checked={!hidden_columns.includes(col_id)}
|
|
935
|
-
onchange={() => toggle_column(col_id)}
|
|
936
|
-
/>
|
|
937
|
-
{@html sanitize_html(col.label)}
|
|
938
|
-
</label>
|
|
939
|
-
{/each}
|
|
940
|
-
</div>
|
|
941
|
-
{/if}
|
|
942
|
-
</div>
|
|
943
|
-
{/if}
|
|
944
|
-
|
|
945
|
-
{#if export_config}
|
|
946
|
-
<div class="dropdown-wrapper">
|
|
947
|
-
<button
|
|
948
|
-
class="icon-btn"
|
|
949
|
-
class:active={show_export_dropdown}
|
|
950
|
-
onclick={() => show_export_dropdown = !show_export_dropdown}
|
|
951
|
-
{@attach tooltip({ content: `Export`, placement: `top` })}
|
|
952
|
-
>
|
|
953
|
-
<Icon icon="Export" style="width: 14px" />
|
|
954
|
-
</button>
|
|
955
|
-
{#if show_export_dropdown}
|
|
956
|
-
<div class="dropdown-pane">
|
|
957
|
-
{#if export_config.formats.includes(`csv`)}
|
|
958
|
-
<button
|
|
959
|
-
class="dropdown-option"
|
|
960
|
-
onclick={() => {
|
|
961
|
-
export_csv(export_config.filename)
|
|
962
|
-
show_export_dropdown = false
|
|
963
|
-
}}
|
|
964
|
-
>
|
|
965
|
-
<Icon icon="Download" style="width: 12px" /> CSV
|
|
966
|
-
</button>
|
|
967
|
-
{/if}
|
|
968
|
-
{#if export_config.formats.includes(`json`)}
|
|
969
|
-
<button
|
|
970
|
-
class="dropdown-option"
|
|
971
|
-
onclick={() => {
|
|
972
|
-
export_json(export_config.filename)
|
|
973
|
-
show_export_dropdown = false
|
|
974
|
-
}}
|
|
975
|
-
>
|
|
976
|
-
<Icon icon="Download" style="width: 12px" /> JSON
|
|
977
|
-
</button>
|
|
978
|
-
{/if}
|
|
979
|
-
<button
|
|
980
|
-
class="dropdown-option"
|
|
981
|
-
onclick={() => {
|
|
982
|
-
copy_to_clipboard()
|
|
983
|
-
show_export_dropdown = false
|
|
984
|
-
}}
|
|
985
|
-
>
|
|
986
|
-
<Icon icon="Copy" style="width: 12px" /> Copy
|
|
987
|
-
</button>
|
|
988
|
-
</div>
|
|
989
|
-
{/if}
|
|
990
|
-
</div>
|
|
991
|
-
{/if}
|
|
992
|
-
|
|
993
|
-
{#if show_row_select && selected_rows.length > 0}
|
|
994
|
-
<button
|
|
995
|
-
class="icon-btn selection-badge"
|
|
996
|
-
onclick={() => selected_rows = []}
|
|
997
|
-
title="Clear {selected_rows.length} selected rows"
|
|
998
|
-
>
|
|
999
|
-
<span class="badge">{selected_rows.length}</span>
|
|
1000
|
-
<Icon icon="Cross" style="width: 10px" />
|
|
1001
|
-
</button>
|
|
1002
|
-
{/if}
|
|
1003
|
-
|
|
1004
|
-
{#if controls}
|
|
1005
|
-
{@render controls()}
|
|
1006
|
-
{/if}
|
|
1007
|
-
</section>
|
|
1008
|
-
|
|
1009
|
-
{#if show_controls}
|
|
1010
|
-
<DraggablePane
|
|
1011
|
-
bind:show={controls_open}
|
|
1012
|
-
closed_icon="Settings"
|
|
1013
|
-
open_icon="Cross"
|
|
1014
|
-
toggle_props={{
|
|
1015
|
-
title: `${controls_open ? `Close` : `Open`} table controls`,
|
|
1016
|
-
style: `position: absolute; top: 5pt; right: 1ex; z-index: 10`,
|
|
1017
|
-
}}
|
|
1018
|
-
pane_props={{ style: `max-height: 60vh; overflow-y: auto; font-size: 0.85em` }}
|
|
1019
|
-
>
|
|
1020
|
-
<SettingsSection
|
|
1021
|
-
title="Heatmap"
|
|
1022
|
-
current_values={{ show_heatmap, heatmap_opacity }}
|
|
1023
|
-
on_reset={() => {
|
|
1024
|
-
show_heatmap = true
|
|
1025
|
-
heatmap_opacity = 1
|
|
1026
|
-
}}
|
|
1027
|
-
>
|
|
1028
|
-
<label><input type="checkbox" bind:checked={show_heatmap} /> Show heatmap</label>
|
|
1029
|
-
{#if show_heatmap}
|
|
1030
|
-
<label>
|
|
1031
|
-
Opacity
|
|
1032
|
-
<input
|
|
1033
|
-
type="range"
|
|
1034
|
-
min="0"
|
|
1035
|
-
max="1"
|
|
1036
|
-
step="0.05"
|
|
1037
|
-
bind:value={heatmap_opacity}
|
|
1038
|
-
/>
|
|
1039
|
-
<input
|
|
1040
|
-
type="number"
|
|
1041
|
-
min="0"
|
|
1042
|
-
max="1"
|
|
1043
|
-
step="0.05"
|
|
1044
|
-
bind:value={heatmap_opacity}
|
|
1045
|
-
style="width: 3.5em"
|
|
1046
|
-
/>
|
|
1047
|
-
</label>
|
|
1048
|
-
{/if}
|
|
1049
|
-
</SettingsSection>
|
|
1050
|
-
|
|
1051
|
-
<SettingsSection
|
|
1052
|
-
title="Display"
|
|
1053
|
-
current_values={{ show_row_numbers }}
|
|
1054
|
-
on_reset={() => {
|
|
1055
|
-
show_row_numbers = false
|
|
1056
|
-
}}
|
|
1057
|
-
>
|
|
1058
|
-
<label><input type="checkbox" bind:checked={show_row_numbers} /> Row
|
|
1059
|
-
numbers</label>
|
|
1060
|
-
</SettingsSection>
|
|
1061
|
-
|
|
1062
|
-
{#if colored_columns.length > 0}
|
|
1063
|
-
<SettingsSection
|
|
1064
|
-
title="Column Colors"
|
|
1065
|
-
current_values={Object.fromEntries([...better_overrides, ...color_scale_overrides])}
|
|
1066
|
-
on_reset={() => {
|
|
1067
|
-
better_overrides.clear()
|
|
1068
|
-
color_scale_overrides.clear()
|
|
1069
|
-
}}
|
|
1070
|
-
>
|
|
1071
|
-
{#each colored_columns as col (get_col_id(col))}
|
|
1072
|
-
{@const col_id = get_col_id(col)}
|
|
1073
|
-
<div class="col-color-row">
|
|
1074
|
-
<span class="col-color-label">{@html sanitize_html(col.label)}</span>
|
|
1075
|
-
<select
|
|
1076
|
-
value={color_scale_overrides.get(col_id) ?? col.color_scale ??
|
|
1077
|
-
`interpolateViridis`}
|
|
1078
|
-
onchange={(event) => {
|
|
1079
|
-
const val = event.currentTarget.value
|
|
1080
|
-
if (
|
|
1081
|
-
val === (col.color_scale ?? `interpolateViridis`)
|
|
1082
|
-
) color_scale_overrides.delete(col_id)
|
|
1083
|
-
else color_scale_overrides.set(col_id, val)
|
|
1084
|
-
}}
|
|
1085
|
-
>
|
|
1086
|
-
{#each color_scale_options as scale (scale)}
|
|
1087
|
-
<option value={scale}>{scale.replace(`interpolate`, ``)}</option>
|
|
1088
|
-
{/each}
|
|
1089
|
-
</select>
|
|
1090
|
-
<select
|
|
1091
|
-
value={better_overrides.get(col_id) ?? col.better ?? ``}
|
|
1092
|
-
onchange={(event) => {
|
|
1093
|
-
const val = event.currentTarget.value
|
|
1094
|
-
if (!val) better_overrides.delete(col_id)
|
|
1095
|
-
else better_overrides.set(col_id, val as `higher` | `lower`)
|
|
1096
|
-
}}
|
|
1097
|
-
>
|
|
1098
|
-
<option value="">Default</option>
|
|
1099
|
-
<option value="higher">▲ High</option>
|
|
1100
|
-
<option value="lower">▼ Low</option>
|
|
1101
|
-
</select>
|
|
1102
|
-
</div>
|
|
1103
|
-
{/each}
|
|
1104
|
-
</SettingsSection>
|
|
1105
|
-
{/if}
|
|
1106
|
-
</DraggablePane>
|
|
1107
|
-
{/if}
|
|
1108
|
-
|
|
1109
|
-
{@render sort_hint_element(`top`)}
|
|
1110
|
-
|
|
1111
|
-
<div
|
|
1112
|
-
class="table-scroll"
|
|
1113
|
-
style={scroll_style}
|
|
1114
|
-
class:has-scroll={scroll_style}
|
|
1115
|
-
>
|
|
1116
|
-
{#if loading}
|
|
1117
|
-
<div class="loading-overlay">
|
|
1118
|
-
<div class="loading-spinner"></div>
|
|
1119
|
-
</div>
|
|
1120
|
-
{/if}
|
|
1121
|
-
<table class:fixed-header={fixed_header} class={heatmap_class}>
|
|
1122
|
-
<thead>
|
|
1123
|
-
<!-- Don't add a table row for group headers if there are none -->
|
|
1124
|
-
{#if visible_columns.some((col) => col.group)}
|
|
1125
|
-
<!-- First level headers -->
|
|
1126
|
-
<tr class="group-header">
|
|
1127
|
-
{#if show_row_select}
|
|
1128
|
-
<th class="select-col"></th>
|
|
1129
|
-
{/if}
|
|
1130
|
-
{#if show_row_numbers}
|
|
1131
|
-
<th class="row-num-col"></th>
|
|
1132
|
-
{/if}
|
|
1133
|
-
{#each visible_columns as col (get_col_id(col))}
|
|
1134
|
-
{#if !col.group}
|
|
1135
|
-
<th class:sticky-col={col.sticky}></th>
|
|
1136
|
-
{:else}
|
|
1137
|
-
{@const group_cols = visible_columns.filter((column) =>
|
|
1138
|
-
column.group === col.group
|
|
1139
|
-
)}
|
|
1140
|
-
<!-- Only render the group header once for each group by checking if this is the first column of this group -->
|
|
1141
|
-
{#if visible_columns.findIndex((column) => column.group === col.group) ===
|
|
1142
|
-
visible_columns.findIndex((column) =>
|
|
1143
|
-
column.group === col.group && column.label === col.label
|
|
1144
|
-
)}
|
|
1145
|
-
<th title={col.description} colspan={group_cols.length}>
|
|
1146
|
-
{@html sanitize_html(col.group)}
|
|
1147
|
-
</th>
|
|
1148
|
-
{/if}
|
|
1149
|
-
{/if}
|
|
1150
|
-
{/each}
|
|
1151
|
-
</tr>
|
|
1152
|
-
{/if}
|
|
1153
|
-
<!-- Second level headers -->
|
|
1154
|
-
<tr>
|
|
1155
|
-
{#if show_row_select}
|
|
1156
|
-
<th
|
|
1157
|
-
class="select-col"
|
|
1158
|
-
title={all_page_selected ? `Deselect all` : `Select all on this page`}
|
|
1159
|
-
>
|
|
1160
|
-
<input
|
|
1161
|
-
type="checkbox"
|
|
1162
|
-
checked={all_page_selected}
|
|
1163
|
-
onchange={toggle_select_all}
|
|
1164
|
-
/>
|
|
1165
|
-
</th>
|
|
1166
|
-
{/if}
|
|
1167
|
-
{#if show_row_numbers}
|
|
1168
|
-
<th class="row-num-col">#</th>
|
|
1169
|
-
{/if}
|
|
1170
|
-
{#each visible_columns as col (get_col_id(col))}
|
|
1171
|
-
{@const col_id = get_col_id(col)}
|
|
1172
|
-
{@const drag_side = drag_over_col_id === col_id
|
|
1173
|
-
? get_drag_side(col_id)
|
|
1174
|
-
: null}
|
|
1175
|
-
{@const col_width = column_widths[col_id]}
|
|
1176
|
-
<th
|
|
1177
|
-
title={col.description}
|
|
1178
|
-
tabindex={col.sortable === false ? undefined : 0}
|
|
1179
|
-
role={col.sortable === false ? undefined : `button`}
|
|
1180
|
-
oncontextmenu={(event) => {
|
|
1181
|
-
if (
|
|
1182
|
-
!allow_better_toggle || col.color_scale === null ||
|
|
1183
|
-
col.color_scale === undefined
|
|
1184
|
-
) return
|
|
1185
|
-
event.preventDefault()
|
|
1186
|
-
event.stopPropagation()
|
|
1187
|
-
context_menu_col = col_id
|
|
1188
|
-
const rect = container_el?.getBoundingClientRect()
|
|
1189
|
-
context_menu_pos = {
|
|
1190
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
1191
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
1192
|
-
}
|
|
1193
|
-
}}
|
|
1194
|
-
onclick={(event) => {
|
|
1195
|
-
if (!drag_col_id && !resize_col_id) {
|
|
1196
|
-
sort_rows(
|
|
1197
|
-
col.label,
|
|
1198
|
-
col.group,
|
|
1199
|
-
event,
|
|
1200
|
-
)
|
|
1201
|
-
}
|
|
1202
|
-
}}
|
|
1203
|
-
onkeydown={(event) => {
|
|
1204
|
-
if (
|
|
1205
|
-
(event.key === `Enter` || event.key === ` `) &&
|
|
1206
|
-
!drag_col_id && !resize_col_id
|
|
1207
|
-
) {
|
|
1208
|
-
event.preventDefault()
|
|
1209
|
-
sort_rows(col.label, col.group, event)
|
|
1210
|
-
}
|
|
1211
|
-
}}
|
|
1212
|
-
style={`${col.style ?? ``}${
|
|
1213
|
-
col_width
|
|
1214
|
-
? `; width: ${col_width}px; min-width: ${col_width}px`
|
|
1215
|
-
: ``
|
|
1216
|
-
}`}
|
|
1217
|
-
class:sticky-col={col.sticky}
|
|
1218
|
-
class:not-sortable={col.sortable === false}
|
|
1219
|
-
class:dragging={drag_col_id === col_id}
|
|
1220
|
-
class:resizing={resize_col_id === col_id}
|
|
1221
|
-
data-drag-side={drag_side}
|
|
1222
|
-
draggable="true"
|
|
1223
|
-
aria-dropeffect="move"
|
|
1224
|
-
aria-sort={sort_state.column === col_id
|
|
1225
|
-
? (sort_state.ascending ? `ascending` : `descending`)
|
|
1226
|
-
: `none`}
|
|
1227
|
-
ondragstart={(event: DragEvent & { currentTarget: HTMLElement }) => {
|
|
1228
|
-
handle_drag_start(event, col)
|
|
1229
|
-
event.currentTarget.setAttribute(`aria-grabbed`, `true`)
|
|
1230
|
-
}}
|
|
1231
|
-
ondragover={(event) => handle_drag_over(event, col)}
|
|
1232
|
-
ondragleave={() => (drag_over_col_id = null)}
|
|
1233
|
-
ondrop={(event) => handle_drop(event, col)}
|
|
1234
|
-
ondragend={(event: DragEvent & { currentTarget: HTMLElement }) => {
|
|
1235
|
-
reset_drag_state()
|
|
1236
|
-
event.currentTarget.removeAttribute(`aria-grabbed`)
|
|
1237
|
-
}}
|
|
1238
|
-
>
|
|
1239
|
-
{#if header_cell}
|
|
1240
|
-
{@render header_cell({ col })}
|
|
1241
|
-
{:else}
|
|
1242
|
-
{@html sanitize_html(col.label)}
|
|
1243
|
-
{/if}
|
|
1244
|
-
{@html sanitize_html(sort_indicator(col, sort_state))}
|
|
1245
|
-
<!-- Column resize handle -->
|
|
1246
|
-
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
1247
|
-
<span
|
|
1248
|
-
class="resize-handle"
|
|
1249
|
-
onmousedown={(event) => start_resize(event, col)}
|
|
1250
|
-
role="separator"
|
|
1251
|
-
aria-orientation="vertical"
|
|
1252
|
-
aria-valuenow={column_widths[get_col_id(col)] ?? 100}
|
|
1253
|
-
aria-valuemin={50}
|
|
1254
|
-
aria-valuemax={500}
|
|
1255
|
-
></span>
|
|
1256
|
-
</th>
|
|
1257
|
-
{/each}
|
|
1258
|
-
</tr>
|
|
1259
|
-
</thead>
|
|
1260
|
-
<tbody>
|
|
1261
|
-
{#each paginated_data as row, row_idx (get_row_id(row))}
|
|
1262
|
-
{@const row_selected = show_row_select && is_row_selected(row)}
|
|
1263
|
-
<tr
|
|
1264
|
-
animate:flip={{ duration: 500 }}
|
|
1265
|
-
style={row.style}
|
|
1266
|
-
class={row.class ?? ``}
|
|
1267
|
-
class:selected={row_selected}
|
|
1268
|
-
tabindex={onrowclick ? 0 : undefined}
|
|
1269
|
-
onclick={onrowclick ? (event) => onrowclick(event, row) : undefined}
|
|
1270
|
-
ondblclick={onrowdblclick ? (event) => onrowdblclick(event, row) : undefined}
|
|
1271
|
-
onkeydown={onrowclick
|
|
1272
|
-
? (event) => {
|
|
1273
|
-
if (event.key === `Enter` || event.key === ` `) {
|
|
1274
|
-
event.preventDefault()
|
|
1275
|
-
onrowclick(event, row)
|
|
1276
|
-
} else if (event.key === `ArrowDown`) {
|
|
1277
|
-
event.preventDefault()
|
|
1278
|
-
const next = event.currentTarget.nextElementSibling
|
|
1279
|
-
if (next instanceof HTMLElement) next.focus()
|
|
1280
|
-
} else if (event.key === `ArrowUp`) {
|
|
1281
|
-
event.preventDefault()
|
|
1282
|
-
const prev = event.currentTarget.previousElementSibling
|
|
1283
|
-
if (prev instanceof HTMLElement) prev.focus()
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
: undefined}
|
|
1287
|
-
>
|
|
1288
|
-
{#if show_row_select}
|
|
1289
|
-
<td class="select-col">
|
|
1290
|
-
<input
|
|
1291
|
-
type="checkbox"
|
|
1292
|
-
checked={row_selected}
|
|
1293
|
-
onchange={() => toggle_row_select(row)}
|
|
1294
|
-
/>
|
|
1295
|
-
</td>
|
|
1296
|
-
{/if}
|
|
1297
|
-
{#if show_row_numbers}
|
|
1298
|
-
<td class="row-num-col">
|
|
1299
|
-
{(current_page - 1) * effective_page_size + row_idx + 1}
|
|
1300
|
-
</td>
|
|
1301
|
-
{/if}
|
|
1302
|
-
{#each visible_columns as col (get_col_id(col))}
|
|
1303
|
-
{@const val = row[get_col_id(col)]}
|
|
1304
|
-
{@const color = calc_color(val, col)}
|
|
1305
|
-
{@const col_width = column_widths[get_col_id(col)]}
|
|
1306
|
-
<td
|
|
1307
|
-
data-col={col.label}
|
|
1308
|
-
data-sort-value={is_html_str(val) ? null : val}
|
|
1309
|
-
class:sticky-col={col.sticky}
|
|
1310
|
-
style:--cell-bg={color.bg}
|
|
1311
|
-
style:color={color.text}
|
|
1312
|
-
style={`${col.cell_style ?? col.style ?? ``}${
|
|
1313
|
-
col_width
|
|
1314
|
-
? `; width: ${col_width}px; max-width: ${col_width}px`
|
|
1315
|
-
: ``
|
|
1316
|
-
}`}
|
|
1317
|
-
>
|
|
1318
|
-
{#if special_cells?.[col.label]}
|
|
1319
|
-
{@render special_cells[col.label]({ row, col, val })}
|
|
1320
|
-
{:else if cell}
|
|
1321
|
-
{@render cell({ row, col, val })}
|
|
1322
|
-
{:else if typeof val === `number` && !Number.isNaN(val)}
|
|
1323
|
-
{format_num(val, col.format ?? default_num_format)}
|
|
1324
|
-
{:else if val === undefined || val === null || Number.isNaN(val)}
|
|
1325
|
-
<span {@attach tooltip({ content: `Not available` })}>
|
|
1326
|
-
n/a
|
|
1327
|
-
</span>
|
|
1328
|
-
{:else}
|
|
1329
|
-
{@html sanitize_html(val)}
|
|
1330
|
-
{/if}
|
|
1331
|
-
</td>
|
|
1332
|
-
{/each}
|
|
1333
|
-
</tr>
|
|
1334
|
-
{:else}
|
|
1335
|
-
{#if empty_message}
|
|
1336
|
-
<tr class="empty-row">
|
|
1337
|
-
<td
|
|
1338
|
-
colspan={visible_columns.length + (show_row_select ? 1 : 0) +
|
|
1339
|
-
(show_row_numbers ? 1 : 0)}
|
|
1340
|
-
>
|
|
1341
|
-
{empty_message}
|
|
1342
|
-
</td>
|
|
1343
|
-
</tr>
|
|
1344
|
-
{/if}
|
|
1345
|
-
{/each}
|
|
1346
|
-
</tbody>
|
|
1347
|
-
{#if footer}
|
|
1348
|
-
<tfoot>
|
|
1349
|
-
{@render footer()}
|
|
1350
|
-
</tfoot>
|
|
1351
|
-
{/if}
|
|
1352
|
-
</table>
|
|
1353
|
-
</div>
|
|
1354
|
-
|
|
1355
|
-
{@render sort_hint_element(`bottom`)}
|
|
1356
|
-
|
|
1357
|
-
{#if pagination_config && total_pages > 1}
|
|
1358
|
-
<div class="pagination">
|
|
1359
|
-
<button
|
|
1360
|
-
class="page-btn"
|
|
1361
|
-
disabled={current_page === 1}
|
|
1362
|
-
onclick={() => current_page = 1}
|
|
1363
|
-
title="First page"
|
|
1364
|
-
>
|
|
1365
|
-
«
|
|
1366
|
-
</button>
|
|
1367
|
-
<button
|
|
1368
|
-
class="page-btn"
|
|
1369
|
-
disabled={current_page === 1}
|
|
1370
|
-
onclick={() => current_page--}
|
|
1371
|
-
title="Previous page"
|
|
1372
|
-
>
|
|
1373
|
-
‹
|
|
1374
|
-
</button>
|
|
1375
|
-
<span class="page-info">
|
|
1376
|
-
Page
|
|
1377
|
-
<input
|
|
1378
|
-
type="number"
|
|
1379
|
-
class="page-input"
|
|
1380
|
-
min="1"
|
|
1381
|
-
max={total_pages}
|
|
1382
|
-
value={current_page}
|
|
1383
|
-
onchange={(event) => {
|
|
1384
|
-
const val = parseInt(event.currentTarget.value, 10)
|
|
1385
|
-
current_page = Math.max(1, Math.min(total_pages, isNaN(val) ? 1 : val))
|
|
1386
|
-
event.currentTarget.value = String(current_page)
|
|
1387
|
-
}}
|
|
1388
|
-
/>
|
|
1389
|
-
of {total_pages}
|
|
1390
|
-
<span class="row-count">({sorted_data.length} rows)</span>
|
|
1391
|
-
</span>
|
|
1392
|
-
<button
|
|
1393
|
-
class="page-btn"
|
|
1394
|
-
disabled={current_page === total_pages}
|
|
1395
|
-
onclick={() => current_page++}
|
|
1396
|
-
title="Next page"
|
|
1397
|
-
>
|
|
1398
|
-
›
|
|
1399
|
-
</button>
|
|
1400
|
-
<button
|
|
1401
|
-
class="page-btn"
|
|
1402
|
-
disabled={current_page === total_pages}
|
|
1403
|
-
onclick={() => current_page = total_pages}
|
|
1404
|
-
title="Last page"
|
|
1405
|
-
>
|
|
1406
|
-
»
|
|
1407
|
-
</button>
|
|
1408
|
-
{#if pagination_config.page_sizes}
|
|
1409
|
-
<select
|
|
1410
|
-
class="page-size-select"
|
|
1411
|
-
onchange={(event) => {
|
|
1412
|
-
effective_page_size = parseInt(event.currentTarget.value, 10)
|
|
1413
|
-
current_page = 1
|
|
1414
|
-
}}
|
|
1415
|
-
>
|
|
1416
|
-
{#each pagination_config.page_sizes as size (size)}
|
|
1417
|
-
<option value={size} selected={size === effective_page_size}>
|
|
1418
|
-
{size} / page
|
|
1419
|
-
</option>
|
|
1420
|
-
{/each}
|
|
1421
|
-
</select>
|
|
1422
|
-
{/if}
|
|
1423
|
-
</div>
|
|
1424
|
-
{/if}
|
|
1425
|
-
|
|
1426
|
-
<ContextMenu
|
|
1427
|
-
sections={better_sections}
|
|
1428
|
-
selected_values={{ 'Gradient direction': better_overrides.get(context_menu_col ?? ``) ?? `` }}
|
|
1429
|
-
position={context_menu_pos}
|
|
1430
|
-
visible={context_menu_col !== null}
|
|
1431
|
-
on_close={() => context_menu_col = null}
|
|
1432
|
-
style={[
|
|
1433
|
-
`--surface-bg: light-dark(#fff, #1e1e1e)`,
|
|
1434
|
-
`--border-color: light-dark(rgba(0,0,0,0.15), rgba(255,255,255,0.15))`,
|
|
1435
|
-
`--text-color: light-dark(#333, #eee)`,
|
|
1436
|
-
`--text-color-muted: light-dark(#888, #999)`,
|
|
1437
|
-
`--surface-bg-hover: light-dark(rgba(0,0,0,0.06), rgba(255,255,255,0.1))`,
|
|
1438
|
-
`--accent-color: light-dark(rgba(0,0,0,0.1), rgba(255,255,255,0.15))`,
|
|
1439
|
-
`z-index: 200`,
|
|
1440
|
-
].join(`; `)}
|
|
1441
|
-
on_select={(_, option) => {
|
|
1442
|
-
if (!context_menu_col) return
|
|
1443
|
-
const current = better_overrides.get(context_menu_col)
|
|
1444
|
-
if (current === option.value) better_overrides.delete(context_menu_col)
|
|
1445
|
-
else better_overrides.set(context_menu_col, option.value as `higher` | `lower`)
|
|
1446
|
-
context_menu_col = null
|
|
1447
|
-
}}
|
|
1448
|
-
/>
|
|
1449
|
-
</div>
|
|
1450
|
-
|
|
1451
|
-
<style>
|
|
1452
|
-
.table-container {
|
|
1453
|
-
font-size: var(--heatmap-font-size, 0.9em);
|
|
1454
|
-
width: fit-content;
|
|
1455
|
-
max-width: 100%;
|
|
1456
|
-
max-height: inherit;
|
|
1457
|
-
margin: 0 auto;
|
|
1458
|
-
position: relative;
|
|
1459
|
-
display: flex;
|
|
1460
|
-
flex-direction: column;
|
|
1461
|
-
}
|
|
1462
|
-
.table-scroll {
|
|
1463
|
-
position: relative;
|
|
1464
|
-
overflow: auto;
|
|
1465
|
-
}
|
|
1466
|
-
.table-scroll.has-scroll {
|
|
1467
|
-
border: 1px solid light-dark(rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.12));
|
|
1468
|
-
border-radius: var(--border-radius, 3pt);
|
|
1469
|
-
overflow-x: hidden;
|
|
1470
|
-
overflow-y: auto;
|
|
1471
|
-
}
|
|
1472
|
-
table {
|
|
1473
|
-
border-collapse: separate;
|
|
1474
|
-
border-spacing: 0;
|
|
1475
|
-
display: table; /* Override global display: block to enable sticky headers */
|
|
1476
|
-
}
|
|
1477
|
-
th, td {
|
|
1478
|
-
padding: var(--heatmap-cell-padding, 1pt 5pt);
|
|
1479
|
-
text-align: var(--heatmap-text-align, left);
|
|
1480
|
-
border: var(--heatmap-cell-border, none);
|
|
1481
|
-
white-space: nowrap;
|
|
1482
|
-
overflow: hidden;
|
|
1483
|
-
text-overflow: ellipsis;
|
|
1484
|
-
/* --cell-bg is set inline per-cell by calc_color(); --heatmap-opacity is set
|
|
1485
|
-
on the container from the heatmap_opacity prop to fade cell backgrounds */
|
|
1486
|
-
background-color: color-mix(
|
|
1487
|
-
in srgb,
|
|
1488
|
-
var(--cell-bg, transparent) var(--heatmap-opacity, 100%),
|
|
1489
|
-
transparent
|
|
1490
|
-
);
|
|
1491
|
-
}
|
|
1492
|
-
th {
|
|
1493
|
-
background: var(--heatmap-header-bg, var(--page-bg, Canvas));
|
|
1494
|
-
position: sticky;
|
|
1495
|
-
top: 0;
|
|
1496
|
-
z-index: 2;
|
|
1497
|
-
cursor: pointer;
|
|
1498
|
-
user-select: none;
|
|
1499
|
-
}
|
|
1500
|
-
th:hover {
|
|
1501
|
-
background: var(--heatmap-header-hover-bg, var(--nav-bg));
|
|
1502
|
-
}
|
|
1503
|
-
th.dragging {
|
|
1504
|
-
opacity: 0.4;
|
|
1505
|
-
cursor: grabbing;
|
|
1506
|
-
}
|
|
1507
|
-
th[data-drag-side='left'] {
|
|
1508
|
-
border-left: 4px solid var(--highlight, #4a9eff);
|
|
1509
|
-
}
|
|
1510
|
-
th[data-drag-side='right'] {
|
|
1511
|
-
border-right: 4px solid var(--highlight, #4a9eff);
|
|
1512
|
-
}
|
|
1513
|
-
th[draggable='true'] {
|
|
1514
|
-
cursor: grab;
|
|
1515
|
-
}
|
|
1516
|
-
th.sticky-col {
|
|
1517
|
-
position: sticky;
|
|
1518
|
-
left: 0;
|
|
1519
|
-
top: 0;
|
|
1520
|
-
background: var(--heatmap-header-bg, var(--page-bg, Canvas));
|
|
1521
|
-
z-index: 4; /* Higher than regular th (2) to stay above when both scroll */
|
|
1522
|
-
border-right: 1px solid var(--border, #ddd);
|
|
1523
|
-
}
|
|
1524
|
-
td.sticky-col {
|
|
1525
|
-
position: sticky;
|
|
1526
|
-
left: 0;
|
|
1527
|
-
background: var(--page-bg, Canvas);
|
|
1528
|
-
z-index: 1;
|
|
1529
|
-
border-right: 1px solid var(--border, #ddd);
|
|
1530
|
-
}
|
|
1531
|
-
tbody tr:hover {
|
|
1532
|
-
filter: var(--heatmap-row-hover-filter, brightness(1.1));
|
|
1533
|
-
}
|
|
1534
|
-
tbody tr[tabindex] {
|
|
1535
|
-
cursor: pointer;
|
|
1536
|
-
}
|
|
1537
|
-
tbody tr:focus-visible {
|
|
1538
|
-
outline: 2px solid var(--highlight, #4a9eff);
|
|
1539
|
-
outline-offset: -2px;
|
|
1540
|
-
}
|
|
1541
|
-
td[data-sort-value] {
|
|
1542
|
-
cursor: default;
|
|
1543
|
-
}
|
|
1544
|
-
.group-header th {
|
|
1545
|
-
text-align: center;
|
|
1546
|
-
border-bottom: 1px solid var(--border);
|
|
1547
|
-
}
|
|
1548
|
-
/* Sticky cells in group header row need higher z-index to clip scrolling group headers */
|
|
1549
|
-
.group-header th.sticky-col {
|
|
1550
|
-
z-index: 5;
|
|
1551
|
-
}
|
|
1552
|
-
/* Floating control buttons above the table */
|
|
1553
|
-
.control-buttons {
|
|
1554
|
-
display: flex;
|
|
1555
|
-
justify-content: flex-end;
|
|
1556
|
-
align-items: center;
|
|
1557
|
-
gap: 2px;
|
|
1558
|
-
margin-bottom: 1px;
|
|
1559
|
-
opacity: 0;
|
|
1560
|
-
pointer-events: none;
|
|
1561
|
-
transition: opacity 0.15s;
|
|
1562
|
-
}
|
|
1563
|
-
.table-container:hover .control-buttons,
|
|
1564
|
-
.control-buttons:focus-within {
|
|
1565
|
-
opacity: 1;
|
|
1566
|
-
pointer-events: auto;
|
|
1567
|
-
}
|
|
1568
|
-
.icon-btn {
|
|
1569
|
-
padding: 2px 4px;
|
|
1570
|
-
border: none;
|
|
1571
|
-
border-radius: 3px;
|
|
1572
|
-
background: light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.1));
|
|
1573
|
-
color: light-dark(#333, #ddd);
|
|
1574
|
-
cursor: pointer;
|
|
1575
|
-
display: flex;
|
|
1576
|
-
align-items: center;
|
|
1577
|
-
justify-content: center;
|
|
1578
|
-
gap: 2px;
|
|
1579
|
-
font-size: 0.8em;
|
|
1580
|
-
}
|
|
1581
|
-
.icon-btn :global(svg) {
|
|
1582
|
-
width: 12px;
|
|
1583
|
-
height: 12px;
|
|
1584
|
-
}
|
|
1585
|
-
.icon-btn:hover {
|
|
1586
|
-
background: light-dark(rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.2));
|
|
1587
|
-
}
|
|
1588
|
-
.icon-btn.active {
|
|
1589
|
-
background: light-dark(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.25));
|
|
1590
|
-
}
|
|
1591
|
-
.selection-badge {
|
|
1592
|
-
position: relative;
|
|
1593
|
-
}
|
|
1594
|
-
.selection-badge .badge {
|
|
1595
|
-
background: var(--highlight, #4a9eff);
|
|
1596
|
-
color: white;
|
|
1597
|
-
font-size: 0.7em;
|
|
1598
|
-
padding: 1px 4px;
|
|
1599
|
-
border-radius: 8px;
|
|
1600
|
-
min-width: 14px;
|
|
1601
|
-
text-align: center;
|
|
1602
|
-
}
|
|
1603
|
-
.dropdown-wrapper {
|
|
1604
|
-
position: relative;
|
|
1605
|
-
}
|
|
1606
|
-
.dropdown-pane {
|
|
1607
|
-
position: absolute;
|
|
1608
|
-
top: 100%;
|
|
1609
|
-
right: 0;
|
|
1610
|
-
margin-top: 4px;
|
|
1611
|
-
padding: 4px 0;
|
|
1612
|
-
background: light-dark(rgba(255, 255, 255, 0.98), rgba(30, 30, 30, 0.98));
|
|
1613
|
-
border: 1px solid light-dark(rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.15));
|
|
1614
|
-
border-radius: 6px;
|
|
1615
|
-
box-shadow: 0 4px 12px light-dark(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.4));
|
|
1616
|
-
max-height: 280px;
|
|
1617
|
-
overflow-y: auto;
|
|
1618
|
-
z-index: 100;
|
|
1619
|
-
color: light-dark(#333, #eee);
|
|
1620
|
-
font-size: 0.95em;
|
|
1621
|
-
}
|
|
1622
|
-
.dropdown-option {
|
|
1623
|
-
display: flex;
|
|
1624
|
-
align-items: center;
|
|
1625
|
-
gap: 8px;
|
|
1626
|
-
padding: 3px 6px;
|
|
1627
|
-
cursor: pointer;
|
|
1628
|
-
font-size: 0.95em;
|
|
1629
|
-
white-space: nowrap;
|
|
1630
|
-
background: transparent;
|
|
1631
|
-
border: none;
|
|
1632
|
-
color: inherit;
|
|
1633
|
-
width: 100%;
|
|
1634
|
-
text-align: left;
|
|
1635
|
-
}
|
|
1636
|
-
.dropdown-option:hover {
|
|
1637
|
-
background: light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.1));
|
|
1638
|
-
}
|
|
1639
|
-
/* Column toggle labels - more compact */
|
|
1640
|
-
label.dropdown-option {
|
|
1641
|
-
padding: 4px 10px;
|
|
1642
|
-
gap: 6px;
|
|
1643
|
-
}
|
|
1644
|
-
.search-input {
|
|
1645
|
-
padding: 2px 4px;
|
|
1646
|
-
border: 1px solid light-dark(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.2));
|
|
1647
|
-
border-radius: 3px;
|
|
1648
|
-
background: light-dark(rgba(255, 255, 255, 0.9), rgba(0, 0, 0, 0.3));
|
|
1649
|
-
color: light-dark(#333, #eee);
|
|
1650
|
-
font-size: 0.8em;
|
|
1651
|
-
width: 110px;
|
|
1652
|
-
box-sizing: border-box;
|
|
1653
|
-
}
|
|
1654
|
-
.search-input:focus {
|
|
1655
|
-
outline: 1px solid var(--highlight, #4a9eff);
|
|
1656
|
-
}
|
|
1657
|
-
.search-input::placeholder {
|
|
1658
|
-
color: light-dark(#999, #666);
|
|
1659
|
-
}
|
|
1660
|
-
.sort-hint {
|
|
1661
|
-
text-align: center;
|
|
1662
|
-
font-size: 0.75em;
|
|
1663
|
-
color: var(--text-muted);
|
|
1664
|
-
padding: 4px 0;
|
|
1665
|
-
opacity: 0;
|
|
1666
|
-
transition: opacity 0.15s;
|
|
1667
|
-
}
|
|
1668
|
-
.table-container:hover .sort-hint,
|
|
1669
|
-
.sort-hint.permanent {
|
|
1670
|
-
opacity: 1;
|
|
1671
|
-
}
|
|
1672
|
-
.not-sortable {
|
|
1673
|
-
cursor: default;
|
|
1674
|
-
}
|
|
1675
|
-
tr.highlight {
|
|
1676
|
-
background-color: var(--nav-bg) !important;
|
|
1677
|
-
}
|
|
1678
|
-
tr.highlight, tr.highlight :global(a) {
|
|
1679
|
-
color: var(--highlight) !important;
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
/* Row selection */
|
|
1683
|
-
.select-col {
|
|
1684
|
-
width: 30px;
|
|
1685
|
-
text-align: center;
|
|
1686
|
-
vertical-align: middle;
|
|
1687
|
-
padding: 2px !important;
|
|
1688
|
-
}
|
|
1689
|
-
.select-col :global(svg) {
|
|
1690
|
-
display: block;
|
|
1691
|
-
margin: auto;
|
|
1692
|
-
}
|
|
1693
|
-
tr.selected {
|
|
1694
|
-
background: var(--highlight-bg, rgba(74, 158, 255, 0.15)) !important;
|
|
1695
|
-
}
|
|
1696
|
-
tr.selected td {
|
|
1697
|
-
border-top: 1px solid var(--highlight, #4a9eff);
|
|
1698
|
-
border-bottom: 1px solid var(--highlight, #4a9eff);
|
|
1699
|
-
}
|
|
1700
|
-
/* Pagination */
|
|
1701
|
-
.pagination {
|
|
1702
|
-
display: flex;
|
|
1703
|
-
align-items: center;
|
|
1704
|
-
justify-content: center;
|
|
1705
|
-
gap: 8px;
|
|
1706
|
-
margin-top: 12px;
|
|
1707
|
-
padding-top: 12px;
|
|
1708
|
-
border-top: 1px solid var(--border);
|
|
1709
|
-
}
|
|
1710
|
-
.page-btn {
|
|
1711
|
-
padding: 4px 10px;
|
|
1712
|
-
border: 1px solid var(--border, #444);
|
|
1713
|
-
border-radius: 4px;
|
|
1714
|
-
background: var(--page-bg, Canvas);
|
|
1715
|
-
color: inherit;
|
|
1716
|
-
cursor: pointer;
|
|
1717
|
-
font-size: 1em;
|
|
1718
|
-
}
|
|
1719
|
-
.page-btn:hover:not(:disabled) {
|
|
1720
|
-
background: var(--nav-bg, #333);
|
|
1721
|
-
}
|
|
1722
|
-
.page-btn:disabled {
|
|
1723
|
-
opacity: 0.4;
|
|
1724
|
-
cursor: not-allowed;
|
|
1725
|
-
}
|
|
1726
|
-
.page-info {
|
|
1727
|
-
font-size: 0.9em;
|
|
1728
|
-
display: flex;
|
|
1729
|
-
align-items: center;
|
|
1730
|
-
gap: 4px;
|
|
1731
|
-
}
|
|
1732
|
-
.page-input {
|
|
1733
|
-
min-width: 1em !important; /* Override global min-width: 40px from app.css */
|
|
1734
|
-
padding: 2px 4px;
|
|
1735
|
-
border: 1px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2));
|
|
1736
|
-
border-radius: 3px;
|
|
1737
|
-
background: light-dark(#fff, #333);
|
|
1738
|
-
color: inherit;
|
|
1739
|
-
font-size: inherit;
|
|
1740
|
-
text-align: center;
|
|
1741
|
-
-moz-appearance: textfield;
|
|
1742
|
-
appearance: textfield;
|
|
1743
|
-
}
|
|
1744
|
-
.page-input::-webkit-outer-spin-button,
|
|
1745
|
-
.page-input::-webkit-inner-spin-button {
|
|
1746
|
-
-webkit-appearance: none;
|
|
1747
|
-
appearance: none;
|
|
1748
|
-
margin: 0;
|
|
1749
|
-
}
|
|
1750
|
-
.page-input:focus {
|
|
1751
|
-
outline: 1px solid var(--highlight, #4a9eff);
|
|
1752
|
-
}
|
|
1753
|
-
.row-count {
|
|
1754
|
-
color: var(--text-muted);
|
|
1755
|
-
font-size: 0.85em;
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
.col-color-row {
|
|
1759
|
-
display: flex;
|
|
1760
|
-
align-items: center;
|
|
1761
|
-
gap: 4px;
|
|
1762
|
-
padding: 2px 0;
|
|
1763
|
-
select {
|
|
1764
|
-
font-size: 0.85em;
|
|
1765
|
-
padding: 1px 2px;
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
.col-color-label {
|
|
1769
|
-
flex: 1;
|
|
1770
|
-
overflow: hidden;
|
|
1771
|
-
text-overflow: ellipsis;
|
|
1772
|
-
white-space: nowrap;
|
|
1773
|
-
min-width: 0;
|
|
1774
|
-
}
|
|
1775
|
-
/* Column resize */
|
|
1776
|
-
.resize-handle {
|
|
1777
|
-
position: absolute;
|
|
1778
|
-
right: 0;
|
|
1779
|
-
top: 0;
|
|
1780
|
-
bottom: 0;
|
|
1781
|
-
width: 4px;
|
|
1782
|
-
cursor: col-resize;
|
|
1783
|
-
background: transparent;
|
|
1784
|
-
}
|
|
1785
|
-
.resize-handle:hover,
|
|
1786
|
-
th.resizing .resize-handle {
|
|
1787
|
-
background: var(--highlight, #4a9eff);
|
|
1788
|
-
}
|
|
1789
|
-
/* Loading overlay */
|
|
1790
|
-
.loading-overlay {
|
|
1791
|
-
position: absolute;
|
|
1792
|
-
inset: 0;
|
|
1793
|
-
background: light-dark(rgba(255, 255, 255, 0.7), rgba(0, 0, 0, 0.5));
|
|
1794
|
-
display: flex;
|
|
1795
|
-
align-items: center;
|
|
1796
|
-
justify-content: center;
|
|
1797
|
-
z-index: 10;
|
|
1798
|
-
}
|
|
1799
|
-
.loading-spinner {
|
|
1800
|
-
width: 24px;
|
|
1801
|
-
height: 24px;
|
|
1802
|
-
border: 3px solid light-dark(#e5e7eb, #444);
|
|
1803
|
-
border-top-color: var(--highlight, #3b82f6);
|
|
1804
|
-
border-radius: 50%;
|
|
1805
|
-
animation: spin 0.8s linear infinite;
|
|
1806
|
-
}
|
|
1807
|
-
@keyframes spin {
|
|
1808
|
-
to {
|
|
1809
|
-
transform: rotate(360deg);
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
.empty-row td {
|
|
1813
|
-
text-align: center;
|
|
1814
|
-
padding: 2em !important;
|
|
1815
|
-
color: var(--text-muted, #888);
|
|
1816
|
-
font-style: italic;
|
|
1817
|
-
}
|
|
1818
|
-
.row-num-col {
|
|
1819
|
-
text-align: right;
|
|
1820
|
-
color: var(--text-muted, #888);
|
|
1821
|
-
font-size: 0.85em;
|
|
1822
|
-
width: 2em;
|
|
1823
|
-
padding-right: 8px !important;
|
|
1824
|
-
}
|
|
1825
|
-
.page-size-select {
|
|
1826
|
-
padding: 2px 4px;
|
|
1827
|
-
border: 1px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2));
|
|
1828
|
-
border-radius: 3px;
|
|
1829
|
-
background: light-dark(#fff, #333);
|
|
1830
|
-
color: inherit;
|
|
1831
|
-
font-size: 0.9em;
|
|
1832
|
-
}
|
|
1833
|
-
</style>
|