matterviz 0.3.0 → 0.3.2
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/FilePicker.svelte +37 -20
- package/dist/Icon.svelte +2 -2
- package/dist/MillerIndexInput.svelte +60 -0
- package/dist/MillerIndexInput.svelte.d.ts +7 -0
- package/dist/app.css +38 -2
- package/dist/brillouin/BrillouinZone.svelte +20 -62
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
- package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +33 -0
- package/dist/chempot-diagram/compute.d.ts +38 -0
- package/dist/chempot-diagram/compute.js +650 -0
- package/dist/chempot-diagram/index.d.ts +5 -0
- package/dist/chempot-diagram/index.js +5 -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 +37 -0
- package/dist/chempot-diagram/types.d.ts +83 -0
- package/dist/chempot-diagram/types.js +27 -0
- package/dist/colors/index.d.ts +3 -1
- package/dist/colors/index.js +4 -0
- package/dist/composition/BarChart.svelte +13 -22
- package/dist/composition/BubbleChart.svelte +5 -3
- package/dist/composition/FormulaFilter.svelte +770 -90
- package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
- package/dist/composition/PieChart.svelte +43 -18
- package/dist/composition/PieChart.svelte.d.ts +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -0
- package/dist/convex-hull/ConvexHull.svelte +14 -1
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +14 -45
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +396 -134
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +93 -42
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullControls.svelte +94 -31
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
- package/dist/convex-hull/ConvexHullStats.svelte +697 -128
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
- package/dist/convex-hull/GasPressureControls.svelte +72 -38
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
- package/dist/convex-hull/TemperatureSlider.svelte +46 -19
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +36 -0
- package/dist/convex-hull/gas-thermodynamics.js +16 -5
- package/dist/convex-hull/helpers.d.ts +7 -1
- package/dist/convex-hull/helpers.js +45 -15
- package/dist/convex-hull/index.d.ts +15 -1
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +8 -21
- package/dist/convex-hull/thermodynamics.js +106 -17
- package/dist/convex-hull/types.d.ts +7 -0
- package/dist/convex-hull/types.js +11 -0
- package/dist/coordination/CoordinationBarPlot.svelte +29 -46
- package/dist/element/BohrAtom.svelte +1 -1
- package/dist/element/data.js +2 -14
- package/dist/element/data.json.gz +0 -0
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -0
- package/dist/element/types.d.ts +1 -0
- package/dist/fermi-surface/FermiSurface.svelte +21 -65
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/compute.js +1 -21
- package/dist/fermi-surface/marching-cubes.d.ts +2 -13
- package/dist/fermi-surface/marching-cubes.js +2 -519
- package/dist/fermi-surface/parse.js +17 -23
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -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 +119 -0
- package/dist/icons.js +119 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/io/export.js +15 -3
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +2 -2
- package/dist/io/index.js +2 -112
- package/dist/io/types.d.ts +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +118 -0
- package/dist/isosurface/Isosurface.svelte +231 -0
- package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
- package/dist/isosurface/IsosurfaceControls.svelte +273 -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 +548 -0
- package/dist/isosurface/slice.d.ts +11 -0
- package/dist/isosurface/slice.js +145 -0
- package/dist/isosurface/types.d.ts +55 -0
- package/dist/isosurface/types.js +178 -0
- package/dist/labels.d.ts +2 -1
- package/dist/labels.js +1 -0
- package/dist/layout/InfoTag.svelte +62 -62
- package/dist/layout/SubpageGrid.svelte +74 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +226 -53
- package/dist/layout/json-tree/JsonTree.svelte +425 -51
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
- package/dist/layout/json-tree/JsonValue.svelte +218 -97
- package/dist/layout/json-tree/types.d.ts +27 -2
- package/dist/layout/json-tree/utils.d.ts +14 -1
- package/dist/layout/json-tree/utils.js +254 -0
- package/dist/marching-cubes.d.ts +14 -0
- package/dist/marching-cubes.js +519 -0
- package/dist/math.d.ts +8 -0
- package/dist/math.js +374 -7
- package/dist/overlays/ContextMenu.svelte +3 -2
- package/dist/overlays/DraggablePane.svelte +163 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
- package/dist/phase-diagram/index.d.ts +2 -0
- package/dist/phase-diagram/index.js +2 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +865 -0
- package/dist/phase-diagram/types.d.ts +10 -0
- package/dist/phase-diagram/utils.d.ts +7 -4
- package/dist/phase-diagram/utils.js +149 -59
- package/dist/plot/AxisLabel.svelte +26 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +473 -228
- package/dist/plot/BarPlot.svelte.d.ts +3 -3
- package/dist/plot/BarPlotControls.svelte +3 -2
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +54 -54
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/ElementScatter.svelte +4 -3
- package/dist/plot/FillArea.svelte +4 -1
- package/dist/plot/Histogram.svelte +320 -230
- package/dist/plot/Histogram.svelte.d.ts +2 -2
- package/dist/plot/HistogramControls.svelte +29 -10
- package/dist/plot/HistogramControls.svelte.d.ts +6 -2
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
- package/dist/plot/PlotControls.svelte +109 -27
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/PlotLegend.svelte +1 -1
- package/dist/plot/PortalSelect.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
- package/dist/plot/ReferencePlane.svelte +1 -3
- package/dist/plot/ScatterPlot.svelte +343 -209
- package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +203 -250
- package/dist/plot/ScatterPlot3DScene.svelte +4 -7
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +95 -55
- package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ZeroLines.svelte +44 -0
- package/dist/plot/ZeroLines.svelte.d.ts +32 -0
- package/dist/plot/ZoomRect.svelte +21 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/axis-utils.d.ts +1 -1
- package/dist/plot/data-cleaning.js +1 -5
- package/dist/plot/index.d.ts +6 -2
- package/dist/plot/index.js +6 -2
- package/dist/plot/interactions.d.ts +8 -10
- package/dist/plot/interactions.js +10 -19
- package/dist/plot/layout.d.ts +7 -1
- package/dist/plot/layout.js +12 -4
- package/dist/plot/reference-line.d.ts +4 -21
- package/dist/plot/reference-line.js +7 -81
- package/dist/plot/types.d.ts +42 -17
- package/dist/plot/types.js +10 -0
- package/dist/plot/utils/label-placement.js +14 -11
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +55 -66
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/index.d.ts +1 -1
- package/dist/rdf/index.js +1 -1
- package/dist/settings.d.ts +5 -0
- package/dist/settings.js +37 -3
- package/dist/spectral/Bands.svelte +515 -143
- package/dist/spectral/Bands.svelte.d.ts +22 -2
- package/dist/spectral/helpers.d.ts +23 -1
- package/dist/spectral/helpers.js +65 -9
- package/dist/spectral/types.d.ts +2 -0
- package/dist/structure/AtomLegend.svelte +31 -10
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +92 -22
- package/dist/structure/Lattice.svelte +2 -0
- package/dist/structure/Structure.svelte +716 -173
- package/dist/structure/Structure.svelte.d.ts +7 -2
- package/dist/structure/StructureControls.svelte +26 -14
- package/dist/structure/StructureControls.svelte.d.ts +5 -1
- package/dist/structure/StructureInfoPane.svelte +7 -1
- package/dist/structure/StructureScene.svelte +386 -95
- package/dist/structure/StructureScene.svelte.d.ts +15 -4
- package/dist/structure/atom-properties.d.ts +6 -2
- package/dist/structure/atom-properties.js +38 -25
- package/dist/structure/export.js +10 -7
- package/dist/structure/ferrox-wasm-types.d.ts +3 -2
- package/dist/structure/ferrox-wasm-types.js +0 -3
- package/dist/structure/ferrox-wasm.d.ts +3 -2
- package/dist/structure/ferrox-wasm.js +1 -2
- package/dist/structure/index.d.ts +7 -0
- package/dist/structure/index.js +22 -0
- package/dist/structure/parse.js +19 -16
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +102 -0
- package/dist/structure/validation.js +6 -3
- package/dist/symmetry/SymmetryStats.svelte +18 -4
- package/dist/symmetry/WyckoffTable.svelte +18 -10
- package/dist/symmetry/index.d.ts +7 -4
- package/dist/symmetry/index.js +83 -18
- package/dist/table/HeatmapTable.svelte +468 -69
- package/dist/table/HeatmapTable.svelte.d.ts +13 -1
- package/dist/table/ToggleMenu.svelte +291 -44
- package/dist/table/ToggleMenu.svelte.d.ts +4 -1
- package/dist/table/index.d.ts +3 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +1 -0
- package/dist/trajectory/Trajectory.svelte +147 -145
- package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.js +3 -5
- 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 +339 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +187 -0
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +11 -4
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +76 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +121 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +304 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +169 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +65 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +109 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +4 -0
- package/dist/xrd/XrdPlot.svelte +6 -4
- package/dist/xrd/calc-xrd.js +0 -1
- package/package.json +33 -23
- package/readme.md +4 -4
- package/dist/trajectory/parse.d.ts +0 -42
- package/dist/trajectory/parse.js +0 -1267
- /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// HKL plane slicing for volumetric data: samples a 3D grid along an arbitrary
|
|
2
|
+
// crystallographic plane defined by Miller indices, using trilinear interpolation.
|
|
3
|
+
import { reciprocal_lattice } from '../brillouin';
|
|
4
|
+
import * as math from '../math';
|
|
5
|
+
// Trilinear interpolation of a scalar 3D grid at fractional coordinates.
|
|
6
|
+
// Periodic grids wrap with modulo; non-periodic return 0 for out-of-bounds.
|
|
7
|
+
export function trilinear_interpolate(grid, fx, fy, fz, periodic) {
|
|
8
|
+
const nx = grid.length;
|
|
9
|
+
const ny = grid[0]?.length ?? 0;
|
|
10
|
+
const nz = grid[0]?.[0]?.length ?? 0;
|
|
11
|
+
if (nx === 0 || ny === 0 || nz === 0)
|
|
12
|
+
return 0;
|
|
13
|
+
// Convert fractional to grid coordinates
|
|
14
|
+
const gx = periodic ? fx * nx : fx * (nx - 1);
|
|
15
|
+
const gy = periodic ? fy * ny : fy * (ny - 1);
|
|
16
|
+
const gz = periodic ? fz * nz : fz * (nz - 1);
|
|
17
|
+
if (!periodic) {
|
|
18
|
+
// Out-of-bounds check for non-periodic grids
|
|
19
|
+
if (fx < 0 || fx > 1 || fy < 0 || fy > 1 || fz < 0 || fz > 1)
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
const safe_mod = (val, dim) => ((val % dim) + dim) % dim;
|
|
23
|
+
const x0 = periodic
|
|
24
|
+
? safe_mod(Math.floor(gx), nx)
|
|
25
|
+
: Math.max(0, Math.min(Math.floor(gx), nx - 2));
|
|
26
|
+
const y0 = periodic
|
|
27
|
+
? safe_mod(Math.floor(gy), ny)
|
|
28
|
+
: Math.max(0, Math.min(Math.floor(gy), ny - 2));
|
|
29
|
+
const z0 = periodic
|
|
30
|
+
? safe_mod(Math.floor(gz), nz)
|
|
31
|
+
: Math.max(0, Math.min(Math.floor(gz), nz - 2));
|
|
32
|
+
const x1 = periodic ? (x0 + 1) % nx : Math.min(x0 + 1, nx - 1);
|
|
33
|
+
const y1 = periodic ? (y0 + 1) % ny : Math.min(y0 + 1, ny - 1);
|
|
34
|
+
const z1 = periodic ? (z0 + 1) % nz : Math.min(z0 + 1, nz - 1);
|
|
35
|
+
const xd = gx - Math.floor(gx);
|
|
36
|
+
const yd = gy - Math.floor(gy);
|
|
37
|
+
const zd = gz - Math.floor(gz);
|
|
38
|
+
// 8-point interpolation
|
|
39
|
+
const c000 = grid[x0][y0][z0];
|
|
40
|
+
const c001 = grid[x0][y0][z1];
|
|
41
|
+
const c010 = grid[x0][y1][z0];
|
|
42
|
+
const c011 = grid[x0][y1][z1];
|
|
43
|
+
const c100 = grid[x1][y0][z0];
|
|
44
|
+
const c101 = grid[x1][y0][z1];
|
|
45
|
+
const c110 = grid[x1][y1][z0];
|
|
46
|
+
const c111 = grid[x1][y1][z1];
|
|
47
|
+
const c00 = c000 + (c100 - c000) * xd;
|
|
48
|
+
const c01 = c001 + (c101 - c001) * xd;
|
|
49
|
+
const c10 = c010 + (c110 - c010) * xd;
|
|
50
|
+
const c11 = c011 + (c111 - c011) * xd;
|
|
51
|
+
const c0 = c00 + (c10 - c00) * yd;
|
|
52
|
+
const c1 = c01 + (c11 - c01) * yd;
|
|
53
|
+
return c0 + (c1 - c0) * zd;
|
|
54
|
+
}
|
|
55
|
+
// Sample a 2D slice through volumetric data along a Miller-index plane.
|
|
56
|
+
// `miller_indices` [h,k,l] defines the plane normal in reciprocal space.
|
|
57
|
+
// `distance` is fractional [0,1] along the normal direction within the cell.
|
|
58
|
+
// Returns null if indices are all zero.
|
|
59
|
+
export function sample_hkl_slice(volume, miller_indices, distance, n_points) {
|
|
60
|
+
const [h_idx, k_idx, l_idx] = miller_indices;
|
|
61
|
+
if (h_idx === 0 && k_idx === 0 && l_idx === 0)
|
|
62
|
+
return null;
|
|
63
|
+
const { grid, grid_dims, lattice, periodic } = volume;
|
|
64
|
+
const [nx, ny, nz] = grid_dims;
|
|
65
|
+
// Plane normal G = h*b1 + k*b2 + l*b3 where b_i are reciprocal lattice rows
|
|
66
|
+
const recip = reciprocal_lattice(lattice);
|
|
67
|
+
const plane_normal = [
|
|
68
|
+
h_idx * recip[0][0] + k_idx * recip[1][0] + l_idx * recip[2][0],
|
|
69
|
+
h_idx * recip[0][1] + k_idx * recip[1][1] + l_idx * recip[2][1],
|
|
70
|
+
h_idx * recip[0][2] + k_idx * recip[1][2] + l_idx * recip[2][2],
|
|
71
|
+
];
|
|
72
|
+
if (Math.hypot(...plane_normal) < 1e-12)
|
|
73
|
+
return null; // degenerate normal
|
|
74
|
+
const unit_normal = math.normalize_vec3(plane_normal);
|
|
75
|
+
// In-plane basis vectors
|
|
76
|
+
const [u_vec, v_vec] = math.compute_in_plane_basis(unit_normal);
|
|
77
|
+
// Compute lattice inverse for Cartesian → fractional conversion.
|
|
78
|
+
// lattice rows are vectors [a, b, c], so cart = lattice^T * frac → frac = inv(lattice^T) * cart
|
|
79
|
+
const lattice_inv = math.matrix_inverse_3x3(math.transpose_3x3_matrix(lattice));
|
|
80
|
+
// Project all 8 unit cell corners onto the (u, v) plane to find sampling bounds.
|
|
81
|
+
// Corners are at fractional coords (0 or 1) for each axis.
|
|
82
|
+
let u_min = Infinity;
|
|
83
|
+
let u_max = -Infinity;
|
|
84
|
+
let v_min = Infinity;
|
|
85
|
+
let v_max = -Infinity;
|
|
86
|
+
let normal_min = Infinity;
|
|
87
|
+
let normal_max = -Infinity;
|
|
88
|
+
for (let ci = 0; ci < 8; ci++) {
|
|
89
|
+
const fi = (ci & 1) ? 1 : 0;
|
|
90
|
+
const fj = (ci & 2) ? 1 : 0;
|
|
91
|
+
const fk = (ci & 4) ? 1 : 0;
|
|
92
|
+
// Corner in Cartesian: frac * lattice
|
|
93
|
+
const corner = [
|
|
94
|
+
fi * lattice[0][0] + fj * lattice[1][0] + fk * lattice[2][0],
|
|
95
|
+
fi * lattice[0][1] + fj * lattice[1][1] + fk * lattice[2][1],
|
|
96
|
+
fi * lattice[0][2] + fj * lattice[1][2] + fk * lattice[2][2],
|
|
97
|
+
];
|
|
98
|
+
const u_proj = math.dot(corner, u_vec);
|
|
99
|
+
const v_proj = math.dot(corner, v_vec);
|
|
100
|
+
const n_proj = math.dot(corner, unit_normal);
|
|
101
|
+
if (u_proj < u_min)
|
|
102
|
+
u_min = u_proj;
|
|
103
|
+
if (u_proj > u_max)
|
|
104
|
+
u_max = u_proj;
|
|
105
|
+
if (v_proj < v_min)
|
|
106
|
+
v_min = v_proj;
|
|
107
|
+
if (v_proj > v_max)
|
|
108
|
+
v_max = v_proj;
|
|
109
|
+
if (n_proj < normal_min)
|
|
110
|
+
normal_min = n_proj;
|
|
111
|
+
if (n_proj > normal_max)
|
|
112
|
+
normal_max = n_proj;
|
|
113
|
+
}
|
|
114
|
+
// Plane position: fractional distance [0,1] along the normal extent
|
|
115
|
+
const d_cartesian = normal_min + distance * (normal_max - normal_min);
|
|
116
|
+
// Sampling resolution: caller-specified or default to max grid dimension
|
|
117
|
+
const width = n_points ?? Math.max(nx, ny, nz);
|
|
118
|
+
const height = width;
|
|
119
|
+
const data = new Float64Array(width * height);
|
|
120
|
+
let data_min = Infinity;
|
|
121
|
+
let data_max = -Infinity;
|
|
122
|
+
const u_step = (u_max - u_min) / (width - 1 || 1);
|
|
123
|
+
const v_step = (v_max - v_min) / (height - 1 || 1);
|
|
124
|
+
for (let row = 0; row < height; row++) {
|
|
125
|
+
const v_val = v_min + row * v_step;
|
|
126
|
+
for (let col = 0; col < width; col++) {
|
|
127
|
+
const u_val = u_min + col * u_step;
|
|
128
|
+
// Cartesian position on the plane
|
|
129
|
+
const px = d_cartesian * unit_normal[0] + u_val * u_vec[0] + v_val * v_vec[0];
|
|
130
|
+
const py = d_cartesian * unit_normal[1] + u_val * u_vec[1] + v_val * v_vec[1];
|
|
131
|
+
const pz = d_cartesian * unit_normal[2] + u_val * u_vec[2] + v_val * v_vec[2];
|
|
132
|
+
// Convert to fractional coordinates: frac = lattice_inv * p
|
|
133
|
+
const fx = lattice_inv[0][0] * px + lattice_inv[0][1] * py + lattice_inv[0][2] * pz;
|
|
134
|
+
const fy = lattice_inv[1][0] * px + lattice_inv[1][1] * py + lattice_inv[1][2] * pz;
|
|
135
|
+
const fz = lattice_inv[2][0] * px + lattice_inv[2][1] * py + lattice_inv[2][2] * pz;
|
|
136
|
+
const val = trilinear_interpolate(grid, fx, fy, fz, periodic);
|
|
137
|
+
data[row * width + col] = val;
|
|
138
|
+
if (val < data_min)
|
|
139
|
+
data_min = val;
|
|
140
|
+
if (val > data_max)
|
|
141
|
+
data_max = val;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { data, width, height, min: data_min, max: data_max };
|
|
145
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Matrix3x3, Vec3 } from '../math';
|
|
2
|
+
import type { ParsedStructure } from '../structure/parse';
|
|
3
|
+
export interface DataRange {
|
|
4
|
+
min: number;
|
|
5
|
+
max: number;
|
|
6
|
+
abs_max: number;
|
|
7
|
+
mean: number;
|
|
8
|
+
}
|
|
9
|
+
export interface VolumetricData {
|
|
10
|
+
grid: number[][][];
|
|
11
|
+
grid_dims: Vec3;
|
|
12
|
+
lattice: Matrix3x3;
|
|
13
|
+
origin: Vec3;
|
|
14
|
+
data_range: DataRange;
|
|
15
|
+
data_order?: `x_fastest` | `z_fastest`;
|
|
16
|
+
periodic: boolean;
|
|
17
|
+
label?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface VolumetricFileData {
|
|
20
|
+
structure: ParsedStructure;
|
|
21
|
+
volumes: VolumetricData[];
|
|
22
|
+
}
|
|
23
|
+
export interface IsosurfaceLayer {
|
|
24
|
+
isovalue: number;
|
|
25
|
+
color: string;
|
|
26
|
+
opacity: number;
|
|
27
|
+
visible: boolean;
|
|
28
|
+
show_negative: boolean;
|
|
29
|
+
negative_color: string;
|
|
30
|
+
}
|
|
31
|
+
export interface IsosurfaceSettings {
|
|
32
|
+
isovalue: number;
|
|
33
|
+
opacity: number;
|
|
34
|
+
positive_color: string;
|
|
35
|
+
negative_color: string;
|
|
36
|
+
show_negative: boolean;
|
|
37
|
+
wireframe: boolean;
|
|
38
|
+
halo: number;
|
|
39
|
+
layers?: IsosurfaceLayer[];
|
|
40
|
+
}
|
|
41
|
+
export declare const LAYER_COLORS: readonly ["#3b82f6", "#ef4444", "#22c55e", "#a855f7", "#f97316", "#06b6d4", "#eab308", "#ec4899"];
|
|
42
|
+
export declare function grid_data_range(grid: number[][][]): DataRange;
|
|
43
|
+
export declare function pad_periodic_grid(grid: number[][][], dims: Vec3, pad_fraction: number): {
|
|
44
|
+
grid: number[][][];
|
|
45
|
+
dims: Vec3;
|
|
46
|
+
offset: Vec3;
|
|
47
|
+
};
|
|
48
|
+
export declare function downsample_grid(grid: number[][][], dims: Vec3): {
|
|
49
|
+
grid: number[][][];
|
|
50
|
+
dims: Vec3;
|
|
51
|
+
factor: number;
|
|
52
|
+
};
|
|
53
|
+
export declare const DEFAULT_ISOSURFACE_SETTINGS: IsosurfaceSettings;
|
|
54
|
+
export declare function auto_isosurface_settings(data_range: DataRange): IsosurfaceSettings;
|
|
55
|
+
export declare function generate_layers(data_range: DataRange, n_layers: number): IsosurfaceLayer[];
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Categorical palette for auto-coloring isosurface layers (Tailwind-inspired)
|
|
2
|
+
export const LAYER_COLORS = [
|
|
3
|
+
`#3b82f6`, // blue
|
|
4
|
+
`#ef4444`, // red
|
|
5
|
+
`#22c55e`, // green
|
|
6
|
+
`#a855f7`, // purple
|
|
7
|
+
`#f97316`, // orange
|
|
8
|
+
`#06b6d4`, // cyan
|
|
9
|
+
`#eab308`, // yellow
|
|
10
|
+
`#ec4899`, // pink
|
|
11
|
+
];
|
|
12
|
+
// Compute min/max/abs_max/mean of a 3D grid.
|
|
13
|
+
// Prefer using the precomputed `data_range` field on VolumetricData when available.
|
|
14
|
+
export function grid_data_range(grid) {
|
|
15
|
+
if (!grid.length || !grid[0]?.length || !grid[0][0]?.length) {
|
|
16
|
+
return { min: 0, max: 0, abs_max: 0, mean: 0 };
|
|
17
|
+
}
|
|
18
|
+
let min_val = Infinity;
|
|
19
|
+
let max_val = -Infinity;
|
|
20
|
+
let sum = 0;
|
|
21
|
+
let count = 0;
|
|
22
|
+
for (const plane of grid) {
|
|
23
|
+
for (const row of plane) {
|
|
24
|
+
for (const val of row) {
|
|
25
|
+
if (val < min_val)
|
|
26
|
+
min_val = val;
|
|
27
|
+
if (val > max_val)
|
|
28
|
+
max_val = val;
|
|
29
|
+
sum += val;
|
|
30
|
+
count++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const abs_max = Math.max(Math.abs(min_val), Math.abs(max_val));
|
|
35
|
+
return { min: min_val, max: max_val, abs_max, mean: count > 0 ? sum / count : 0 };
|
|
36
|
+
}
|
|
37
|
+
// Pad a periodic 3D grid with halo cells from the opposite face so isosurfaces
|
|
38
|
+
// extend beyond the unit cell and close into complete enclosed shapes.
|
|
39
|
+
// Returns a larger grid with dims [nx+2*pad, ny+2*pad, nz+2*pad] and the
|
|
40
|
+
// fractional offset that the padded grid's origin has shifted by.
|
|
41
|
+
export function pad_periodic_grid(grid, dims, pad_fraction) {
|
|
42
|
+
const [nx, ny, nz] = dims;
|
|
43
|
+
const frac = Math.max(0, pad_fraction);
|
|
44
|
+
const px = Math.min(Math.ceil(nx * frac), Math.floor(nx / 2));
|
|
45
|
+
const py = Math.min(Math.ceil(ny * frac), Math.floor(ny / 2));
|
|
46
|
+
const pz = Math.min(Math.ceil(nz * frac), Math.floor(nz / 2));
|
|
47
|
+
if (px === 0 && py === 0 && pz === 0)
|
|
48
|
+
return { grid, dims, offset: [0, 0, 0] };
|
|
49
|
+
const out_nx = nx + 2 * px;
|
|
50
|
+
const out_ny = ny + 2 * py;
|
|
51
|
+
const out_nz = nz + 2 * pz;
|
|
52
|
+
const wrap = (val, size) => ((val % size) + size) % size;
|
|
53
|
+
const out = new Array(out_nx);
|
|
54
|
+
for (let ix = 0; ix < out_nx; ix++) {
|
|
55
|
+
const plane = new Array(out_ny);
|
|
56
|
+
const src_x = wrap(ix - px, nx);
|
|
57
|
+
for (let iy = 0; iy < out_ny; iy++) {
|
|
58
|
+
const row = new Array(out_nz);
|
|
59
|
+
const src_y = wrap(iy - py, ny);
|
|
60
|
+
for (let iz = 0; iz < out_nz; iz++) {
|
|
61
|
+
row[iz] = grid[src_x][src_y][wrap(iz - pz, nz)];
|
|
62
|
+
}
|
|
63
|
+
plane[iy] = row;
|
|
64
|
+
}
|
|
65
|
+
out[ix] = plane;
|
|
66
|
+
}
|
|
67
|
+
// Fractional offset: the padded grid starts at -pad/n in each axis
|
|
68
|
+
const offset = [-px / nx, -py / ny, -pz / nz];
|
|
69
|
+
return { grid: out, dims: [out_nx, out_ny, out_nz], offset };
|
|
70
|
+
}
|
|
71
|
+
// Max total grid points before downsampling is applied for isosurface extraction.
|
|
72
|
+
// 500K balances visual quality with interactive performance (<200ms marching cubes).
|
|
73
|
+
const MAX_GRID_POINTS = 500_000;
|
|
74
|
+
// Downsample a 3D volumetric grid to keep total point count under MAX_GRID_POINTS.
|
|
75
|
+
// Uses block averaging to preserve data fidelity while reducing grid dimensions.
|
|
76
|
+
// Returns original grid/dims if already within budget.
|
|
77
|
+
export function downsample_grid(grid, dims) {
|
|
78
|
+
const [nx, ny, nz] = dims;
|
|
79
|
+
const total = nx * ny * nz;
|
|
80
|
+
if (total <= MAX_GRID_POINTS)
|
|
81
|
+
return { grid, dims, factor: 1 };
|
|
82
|
+
// Increase factor until the clamped output fits within budget.
|
|
83
|
+
// A single cbrt step can overshoot for anisotropic grids where max(2,...)
|
|
84
|
+
// clamping prevents a small axis from shrinking below 2.
|
|
85
|
+
// clamp_dim: returns 1 for single-cell axes, otherwise clamps to [2, src]
|
|
86
|
+
const clamp_dim = (src, fac) => Math.min(src, Math.max(2, Math.ceil(src / fac)));
|
|
87
|
+
let factor = Math.ceil(Math.cbrt(total / MAX_GRID_POINTS));
|
|
88
|
+
let new_nx = clamp_dim(nx, factor);
|
|
89
|
+
let new_ny = clamp_dim(ny, factor);
|
|
90
|
+
let new_nz = clamp_dim(nz, factor);
|
|
91
|
+
while (new_nx * new_ny * new_nz > MAX_GRID_POINTS) {
|
|
92
|
+
factor++;
|
|
93
|
+
new_nx = clamp_dim(nx, factor);
|
|
94
|
+
new_ny = clamp_dim(ny, factor);
|
|
95
|
+
new_nz = clamp_dim(nz, factor);
|
|
96
|
+
}
|
|
97
|
+
// Proportional partitioning: evenly divides [0, n) into new_n non-empty blocks.
|
|
98
|
+
// Unlike fixed-stride (ix * factor), this is safe when max(2,...) clamping
|
|
99
|
+
// produces more output cells than ceil(n/factor) would — no empty blocks.
|
|
100
|
+
const partition = (n_out, n_src) => Array.from({ length: n_out }, (_, idx) => [
|
|
101
|
+
Math.round(idx * n_src / n_out),
|
|
102
|
+
Math.round((idx + 1) * n_src / n_out),
|
|
103
|
+
]);
|
|
104
|
+
const x_ranges = partition(new_nx, nx);
|
|
105
|
+
const y_ranges = partition(new_ny, ny);
|
|
106
|
+
const z_ranges = partition(new_nz, nz);
|
|
107
|
+
const out = new Array(new_nx);
|
|
108
|
+
for (let ix = 0; ix < new_nx; ix++) {
|
|
109
|
+
const plane = new Array(new_ny);
|
|
110
|
+
const [sx_start, sx_end] = x_ranges[ix];
|
|
111
|
+
for (let iy = 0; iy < new_ny; iy++) {
|
|
112
|
+
const row = new Array(new_nz);
|
|
113
|
+
const [sy_start, sy_end] = y_ranges[iy];
|
|
114
|
+
for (let iz = 0; iz < new_nz; iz++) {
|
|
115
|
+
let sum = 0;
|
|
116
|
+
const [sz_start, sz_end] = z_ranges[iz];
|
|
117
|
+
for (let sx = sx_start; sx < sx_end; sx++) {
|
|
118
|
+
const src_plane = grid[sx];
|
|
119
|
+
for (let sy = sy_start; sy < sy_end; sy++) {
|
|
120
|
+
const src_row = src_plane[sy];
|
|
121
|
+
for (let sz = sz_start; sz < sz_end; sz++) {
|
|
122
|
+
sum += src_row[sz];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
row[iz] = sum / ((sx_end - sx_start) * (sy_end - sy_start) * (sz_end - sz_start));
|
|
127
|
+
}
|
|
128
|
+
plane[iy] = row;
|
|
129
|
+
}
|
|
130
|
+
out[ix] = plane;
|
|
131
|
+
}
|
|
132
|
+
return { grid: out, dims: [new_nx, new_ny, new_nz], factor };
|
|
133
|
+
}
|
|
134
|
+
// Default isosurface rendering settings
|
|
135
|
+
export const DEFAULT_ISOSURFACE_SETTINGS = {
|
|
136
|
+
isovalue: 0.05,
|
|
137
|
+
opacity: 0.6,
|
|
138
|
+
positive_color: `#3b82f6`, // blue
|
|
139
|
+
negative_color: `#ef4444`, // red
|
|
140
|
+
show_negative: false,
|
|
141
|
+
wireframe: false,
|
|
142
|
+
halo: 0,
|
|
143
|
+
};
|
|
144
|
+
// Compute reasonable isosurface settings from a volume's data range.
|
|
145
|
+
// Sets isovalue to 20% of abs_max and enables negative lobe when data has
|
|
146
|
+
// significant negative values (>1% of max).
|
|
147
|
+
export function auto_isosurface_settings(data_range) {
|
|
148
|
+
const has_negatives = data_range.min < -data_range.abs_max * 0.01;
|
|
149
|
+
return {
|
|
150
|
+
...DEFAULT_ISOSURFACE_SETTINGS,
|
|
151
|
+
// Fall back to default isovalue for all-zero grids to keep controls usable
|
|
152
|
+
isovalue: data_range.abs_max > 0
|
|
153
|
+
? data_range.abs_max * 0.2
|
|
154
|
+
: DEFAULT_ISOSURFACE_SETTINGS.isovalue,
|
|
155
|
+
show_negative: has_negatives,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// Generate N evenly-spaced isosurface layers across a data range.
|
|
159
|
+
// Layers are spaced from 10% to 80% of abs_max with decreasing opacity
|
|
160
|
+
// for outer (lower-isovalue) shells so inner shells remain visible.
|
|
161
|
+
export function generate_layers(data_range, n_layers) {
|
|
162
|
+
if (n_layers <= 0 || data_range.abs_max <= 0)
|
|
163
|
+
return [];
|
|
164
|
+
const has_negatives = data_range.min < -data_range.abs_max * 0.01;
|
|
165
|
+
// Space isovalues from high (inner) to low (outer)
|
|
166
|
+
return Array.from({ length: n_layers }, (_, idx) => {
|
|
167
|
+
// Fraction from 0.8 (inner) to 0.1 (outer)
|
|
168
|
+
const fraction = n_layers === 1 ? 0.2 : 0.8 - (idx / (n_layers - 1)) * 0.7;
|
|
169
|
+
return {
|
|
170
|
+
isovalue: data_range.abs_max * fraction,
|
|
171
|
+
color: LAYER_COLORS[idx % LAYER_COLORS.length],
|
|
172
|
+
opacity: n_layers === 1 ? 0.6 : 0.8 - idx * (0.5 / Math.max(n_layers - 1, 1)),
|
|
173
|
+
visible: true,
|
|
174
|
+
show_negative: has_negatives,
|
|
175
|
+
negative_color: LAYER_COLORS[(idx + 1) % LAYER_COLORS.length],
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
}
|
package/dist/labels.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ChemicalElement, ElementCategory } from './element/types';
|
|
2
|
+
import type { Vec3 } from './math';
|
|
2
3
|
import type { SymbolType } from 'd3-shape';
|
|
3
4
|
import * as d3_symbols from 'd3-shape';
|
|
4
5
|
export type D3Symbol = keyof typeof d3_symbols & `symbol${Capitalize<string>}`;
|
|
@@ -12,7 +13,7 @@ export declare const ELEM_HEATMAP_LABELS: Partial<Record<string, keyof ChemicalE
|
|
|
12
13
|
export declare const DEFAULT_FMT: [string, string];
|
|
13
14
|
export declare const FRACTION_GLYPHS: ReadonlyArray<readonly [number, string]>;
|
|
14
15
|
export declare const format_num: (num: number, fmt?: string | number) => string;
|
|
15
|
-
export declare const format_vec3: (vec:
|
|
16
|
+
export declare const format_vec3: (vec: Readonly<Vec3>, fmt_spec?: string) => string;
|
|
16
17
|
export declare const format_bytes: (bytes?: number) => string;
|
|
17
18
|
export declare function format_fractional(value: number): string;
|
|
18
19
|
export declare function parse_si_float<T extends string | number | null | undefined>(value: T): T | number | string;
|
package/dist/labels.js
CHANGED
|
@@ -56,6 +56,7 @@ export const ELEM_PROPERTY_LABELS = {
|
|
|
56
56
|
electronegativity: [`Electronegativity`, null],
|
|
57
57
|
first_ionization: [`First Ionization Energy`, `eV`],
|
|
58
58
|
melting_point: [`Melting Point`, `K`],
|
|
59
|
+
mendeleev_number: [`Mendeleev Number`, null],
|
|
59
60
|
// molar_heat: [`Molar Heat`, `J/(mol·K)`],
|
|
60
61
|
n_shells: [`Number of Shells`, null],
|
|
61
62
|
n_valence: [`Electron Valency`, null],
|
|
@@ -67,63 +67,63 @@ function handle_remove(event) {
|
|
|
67
67
|
border: 1px solid;
|
|
68
68
|
white-space: nowrap;
|
|
69
69
|
border-color: color-mix(in srgb, var(--tag-color) 25%, transparent);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
70
|
+
em {
|
|
71
|
+
font-style: normal;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
color: var(--tag-color);
|
|
74
|
+
}
|
|
75
|
+
&:hover:not(.disabled) {
|
|
76
|
+
background: color-mix(in srgb, var(--tag-color) 18%, transparent);
|
|
77
|
+
border-color: color-mix(in srgb, var(--tag-color) 40%, transparent);
|
|
78
|
+
}
|
|
79
|
+
&.sm {
|
|
80
|
+
font-size: 0.72em;
|
|
81
|
+
padding: 0 5pt;
|
|
82
|
+
border-radius: 4px;
|
|
83
|
+
}
|
|
84
|
+
&.md {
|
|
85
|
+
font-size: 0.8em;
|
|
86
|
+
padding: 1pt 6pt;
|
|
87
|
+
border-radius: 5px;
|
|
88
|
+
}
|
|
89
|
+
&.lg {
|
|
90
|
+
font-size: 0.9em;
|
|
91
|
+
padding: 3pt 8pt;
|
|
92
|
+
border-radius: 6px;
|
|
93
|
+
}
|
|
94
|
+
&.default {
|
|
95
|
+
--tag-color: var(--highlight, #4db6ff);
|
|
96
|
+
}
|
|
97
|
+
&.success {
|
|
98
|
+
--tag-color: var(--success-color, #10b981);
|
|
99
|
+
}
|
|
100
|
+
&.warning {
|
|
101
|
+
--tag-color: var(--warning-color, #f59e0b);
|
|
102
|
+
}
|
|
103
|
+
&.error {
|
|
104
|
+
--tag-color: var(--error-color, #ef4444);
|
|
105
|
+
}
|
|
106
|
+
&.info {
|
|
107
|
+
--tag-color: var(--info-color, #3b82f6);
|
|
108
|
+
}
|
|
109
|
+
&.disabled {
|
|
110
|
+
opacity: 0.5;
|
|
111
|
+
cursor: not-allowed;
|
|
112
|
+
}
|
|
113
|
+
&:active:not(.disabled) {
|
|
114
|
+
transform: scale(0.97);
|
|
115
|
+
}
|
|
116
|
+
:global(.copy-checkmark) {
|
|
117
|
+
position: absolute;
|
|
118
|
+
top: 50%;
|
|
119
|
+
right: 3pt;
|
|
120
|
+
transform: translateY(-50%);
|
|
121
|
+
background: rgba(16, 185, 129, 0.9);
|
|
122
|
+
border-radius: 50%;
|
|
123
|
+
padding: 2pt;
|
|
124
|
+
display: flex;
|
|
125
|
+
animation: pop-in 0.15s ease-out;
|
|
126
|
+
}
|
|
127
127
|
}
|
|
128
128
|
[aria-label='Remove'] {
|
|
129
129
|
display: flex;
|
|
@@ -137,11 +137,11 @@ function handle_remove(event) {
|
|
|
137
137
|
border-radius: 50%;
|
|
138
138
|
color: inherit;
|
|
139
139
|
opacity: 0.5;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
&:hover {
|
|
141
|
+
opacity: 1;
|
|
142
|
+
background: rgba(239, 68, 68, 0.2);
|
|
143
|
+
color: var(--error-color, #ef4444);
|
|
144
|
+
}
|
|
145
145
|
}
|
|
146
146
|
@keyframes pop-in {
|
|
147
147
|
from {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts">import Icon from '../Icon.svelte';
|
|
2
|
+
const { title, subtitle, subpages } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<h1>{title}</h1>
|
|
6
|
+
<p class="subtitle">{subtitle}</p>
|
|
7
|
+
|
|
8
|
+
<nav class="grid">
|
|
9
|
+
{#each subpages as { href, title: page_title, description, icon } (href)}
|
|
10
|
+
<a {href} class="card">
|
|
11
|
+
<Icon {icon} class="icon" />
|
|
12
|
+
<div>
|
|
13
|
+
<h2>{page_title}</h2>
|
|
14
|
+
<p>{description}</p>
|
|
15
|
+
</div>
|
|
16
|
+
</a>
|
|
17
|
+
{/each}
|
|
18
|
+
</nav>
|
|
19
|
+
|
|
20
|
+
<style>
|
|
21
|
+
h1 {
|
|
22
|
+
text-align: center;
|
|
23
|
+
margin-bottom: 0.3em;
|
|
24
|
+
}
|
|
25
|
+
.subtitle {
|
|
26
|
+
text-align: center;
|
|
27
|
+
color: var(--text-color-muted);
|
|
28
|
+
margin: 0 auto 2em;
|
|
29
|
+
}
|
|
30
|
+
.grid {
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
33
|
+
gap: 1.2em;
|
|
34
|
+
max-width: 1100px;
|
|
35
|
+
margin: 0 auto;
|
|
36
|
+
padding: 0;
|
|
37
|
+
}
|
|
38
|
+
.card {
|
|
39
|
+
display: flex;
|
|
40
|
+
gap: 1em;
|
|
41
|
+
align-items: flex-start;
|
|
42
|
+
padding: 1.2em 1.4em;
|
|
43
|
+
border-radius: var(--border-radius, 5pt);
|
|
44
|
+
border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
|
|
45
|
+
text-decoration: none;
|
|
46
|
+
color: inherit;
|
|
47
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
48
|
+
&:hover {
|
|
49
|
+
border-color: color-mix(in srgb, currentColor 35%, transparent);
|
|
50
|
+
box-shadow: 0 2px 12px color-mix(in srgb, currentColor 8%, transparent);
|
|
51
|
+
}
|
|
52
|
+
&:hover :global(.icon) {
|
|
53
|
+
opacity: 1;
|
|
54
|
+
}
|
|
55
|
+
h2 {
|
|
56
|
+
margin: 0 0 0.4em;
|
|
57
|
+
font-size: 1.1em;
|
|
58
|
+
}
|
|
59
|
+
p {
|
|
60
|
+
margin: 0;
|
|
61
|
+
font-size: 0.88em;
|
|
62
|
+
color: var(--text-color-muted);
|
|
63
|
+
line-height: 1.5;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
.card :global(.icon) {
|
|
67
|
+
width: 2em;
|
|
68
|
+
height: 2em;
|
|
69
|
+
flex-shrink: 0;
|
|
70
|
+
margin-top: 0.1em;
|
|
71
|
+
opacity: 0.6;
|
|
72
|
+
transition: opacity 0.15s;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IconName } from '../icons';
|
|
2
|
+
interface Props {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle: string;
|
|
5
|
+
subpages: {
|
|
6
|
+
href: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
icon: IconName;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
declare const SubpageGrid: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type SubpageGrid = ReturnType<typeof SubpageGrid>;
|
|
14
|
+
export default SubpageGrid;
|
package/dist/layout/index.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ export { default as InfoTag } from './InfoTag.svelte';
|
|
|
5
5
|
export * from './json-tree';
|
|
6
6
|
export { default as PropertyFilter } from './PropertyFilter.svelte';
|
|
7
7
|
export { default as SettingsSection } from './SettingsSection.svelte';
|
|
8
|
+
export { default as SubpageGrid } from './SubpageGrid.svelte';
|
|
8
9
|
export type InfoTagVariant = `default` | `success` | `warning` | `error` | `info`;
|
|
9
10
|
export type InfoTagSize = `sm` | `md` | `lg`;
|
package/dist/layout/index.js
CHANGED
|
@@ -5,3 +5,4 @@ export { default as InfoTag } from './InfoTag.svelte';
|
|
|
5
5
|
export * from './json-tree';
|
|
6
6
|
export { default as PropertyFilter } from './PropertyFilter.svelte';
|
|
7
7
|
export { default as SettingsSection } from './SettingsSection.svelte';
|
|
8
|
+
export { default as SubpageGrid } from './SubpageGrid.svelte';
|