react-os-shell 0.1.32 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/{Calculator-ZZMTB7Y7.js → Calculator-VZM3FSTQ.js} +4 -4
  2. package/dist/{Calculator-ZZMTB7Y7.js.map → Calculator-VZM3FSTQ.js.map} +1 -1
  3. package/dist/{Calendar-RQVSPJAJ.js → Calendar-7DNNMOKO.js} +3 -3
  4. package/dist/{Calendar-RQVSPJAJ.js.map → Calendar-7DNNMOKO.js.map} +1 -1
  5. package/dist/{CurrencyConverter-S37JTKKZ.js → CurrencyConverter-XFIGUZ46.js} +4 -4
  6. package/dist/{CurrencyConverter-S37JTKKZ.js.map → CurrencyConverter-XFIGUZ46.js.map} +1 -1
  7. package/dist/{Documents-3P6JKOLE.js → Documents-PK7QFWGR.js} +3 -3
  8. package/dist/{Documents-3P6JKOLE.js.map → Documents-PK7QFWGR.js.map} +1 -1
  9. package/dist/{Email-UCNJ53MV.js → Email-66BDCI2Q.js} +3 -3
  10. package/dist/{Email-UCNJ53MV.js.map → Email-66BDCI2Q.js.map} +1 -1
  11. package/dist/{Minesweeper-KAOD327F.js → Minesweeper-7OGCUAKF.js} +3 -3
  12. package/dist/{Minesweeper-KAOD327F.js.map → Minesweeper-7OGCUAKF.js.map} +1 -1
  13. package/dist/{Notepad-C453L2M2.js → Notepad-MNDA6AHQ.js} +3 -3
  14. package/dist/{Notepad-C453L2M2.js.map → Notepad-MNDA6AHQ.js.map} +1 -1
  15. package/dist/{PomodoroTimer-ZZUXEFM6.js → PomodoroTimer-6DHC3H6X.js} +4 -4
  16. package/dist/{PomodoroTimer-ZZUXEFM6.js.map → PomodoroTimer-6DHC3H6X.js.map} +1 -1
  17. package/dist/Preview-WIXANNFW.js +6 -0
  18. package/dist/{Preview-X2TQ32VM.js.map → Preview-WIXANNFW.js.map} +1 -1
  19. package/dist/{Spreadsheet-SOJL4SQA.js → Spreadsheet-JT4TIKCY.js} +3 -3
  20. package/dist/{Spreadsheet-SOJL4SQA.js.map → Spreadsheet-JT4TIKCY.js.map} +1 -1
  21. package/dist/{Weather-H7R7YVRB.js → Weather-A6MEC4PN.js} +4 -4
  22. package/dist/{Weather-H7R7YVRB.js.map → Weather-A6MEC4PN.js.map} +1 -1
  23. package/dist/apps/index.js +13 -13
  24. package/dist/{chunk-AKZTZLKP.js → chunk-44AH2OXU.js} +3 -3
  25. package/dist/{chunk-AKZTZLKP.js.map → chunk-44AH2OXU.js.map} +1 -1
  26. package/dist/{chunk-CZKAKVP6.js → chunk-IQWRDQHW.js} +242 -155
  27. package/dist/chunk-IQWRDQHW.js.map +1 -0
  28. package/dist/{chunk-D7UDGZIH.js → chunk-UUJLLTV4.js} +3 -3
  29. package/dist/{chunk-D7UDGZIH.js.map → chunk-UUJLLTV4.js.map} +1 -1
  30. package/dist/index.js +4 -4
  31. package/package.json +1 -1
  32. package/dist/Preview-X2TQ32VM.js +0 -6
  33. package/dist/chunk-CZKAKVP6.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { toast_default } from './chunk-WIJ45SYD.js';
2
- import { WindowTitle } from './chunk-AKZTZLKP.js';
2
+ import { WindowTitle, getActiveModalId } from './chunk-44AH2OXU.js';
3
3
  import { useState, useEffect, useRef } from 'react';
4
4
  import * as pdfjsLib from 'pdfjs-dist';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -43,19 +43,49 @@ function Preview() {
43
43
  }, []);
44
44
  const titleName = data?.filename ? truncateForTitle(data.filename) : "Untitled";
45
45
  const fileRef = useRef(null);
46
+ const rootRef = useRef(null);
46
47
  const [isDragging, setIsDragging] = useState(false);
48
+ const dragDepthRef = useRef(0);
47
49
  const handlePick = () => fileRef.current?.click();
50
+ const resetDrag = () => {
51
+ dragDepthRef.current = 0;
52
+ setIsDragging(false);
53
+ };
54
+ const isActiveWindow = (el) => {
55
+ const myModal = el.closest("[data-modal-id]");
56
+ if (!myModal) return true;
57
+ return getActiveModalId() === myModal.dataset.modalId;
58
+ };
59
+ useEffect(() => {
60
+ const onWindowDragEnd = () => resetDrag();
61
+ const onWindowDrop = () => resetDrag();
62
+ const onKey = (e) => {
63
+ if (e.key === "Escape") resetDrag();
64
+ };
65
+ window.addEventListener("dragend", onWindowDragEnd);
66
+ window.addEventListener("drop", onWindowDrop);
67
+ window.addEventListener("keydown", onKey);
68
+ return () => {
69
+ window.removeEventListener("dragend", onWindowDragEnd);
70
+ window.removeEventListener("drop", onWindowDrop);
71
+ window.removeEventListener("keydown", onKey);
72
+ };
73
+ }, []);
48
74
  const ingestFile = (file) => {
49
- const url = URL.createObjectURL(file);
50
75
  const ext = (file.name.split(".").pop() || "").toLowerCase();
51
76
  const kind = ext === "pdf" ? "pdf" : ext === "dxf" ? "dxf" : ["jpg", "jpeg", "png", "gif", "webp", "svg", "avif", "bmp"].includes(ext) ? "image" : ["stp", "step", "stl", "obj", "gltf", "glb", "3mf", "iges", "igs", "ply", "fbx"].includes(ext) ? "3d" : void 0;
52
77
  if (!kind) {
53
- URL.revokeObjectURL(url);
54
78
  if (ext === "dwg") toast_default.error("DWG files need server-side conversion. Convert to PDF or DXF first.");
55
79
  else toast_default.error(`Unsupported file type: .${ext || "unknown"}`);
56
80
  return;
57
81
  }
58
- setPdfPreview({ url, filename: file.name, kind });
82
+ const url = URL.createObjectURL(file);
83
+ setData((prev) => {
84
+ if (prev?.url?.startsWith("blob:") && prev.url !== url) {
85
+ URL.revokeObjectURL(prev.url);
86
+ }
87
+ return { url, filename: file.name, kind };
88
+ });
59
89
  };
60
90
  const handleFile = (e) => {
61
91
  const file = e.target.files?.[0];
@@ -64,7 +94,7 @@ function Preview() {
64
94
  };
65
95
  const handleDrop = (e) => {
66
96
  e.preventDefault();
67
- setIsDragging(false);
97
+ resetDrag();
68
98
  const file = e.dataTransfer.files?.[0];
69
99
  if (file) ingestFile(file);
70
100
  };
@@ -147,14 +177,30 @@ function Preview() {
147
177
  "div",
148
178
  {
149
179
  className: "relative flex flex-col h-full",
150
- onDragOver: (e) => {
180
+ ref: rootRef,
181
+ onDragEnter: (e) => {
182
+ if (!e.dataTransfer?.types?.includes?.("Files")) return;
183
+ if (!isActiveWindow(e.currentTarget)) return;
151
184
  e.preventDefault();
185
+ dragDepthRef.current++;
152
186
  if (!isDragging) setIsDragging(true);
153
187
  },
154
- onDragLeave: (e) => {
155
- if (e.currentTarget === e.target) setIsDragging(false);
188
+ onDragOver: (e) => {
189
+ if (!e.dataTransfer?.types?.includes?.("Files")) return;
190
+ if (!isActiveWindow(e.currentTarget)) return;
191
+ e.preventDefault();
192
+ },
193
+ onDragLeave: () => {
194
+ if (dragDepthRef.current > 0) dragDepthRef.current--;
195
+ if (dragDepthRef.current === 0) setIsDragging(false);
196
+ },
197
+ onDrop: (e) => {
198
+ if (!isActiveWindow(e.currentTarget)) {
199
+ resetDrag();
200
+ return;
201
+ }
202
+ handleDrop(e);
156
203
  },
157
- onDrop: handleDrop,
158
204
  children: [
159
205
  /* @__PURE__ */ jsx(WindowTitle, { title: `${titleName} - Preview` }),
160
206
  Toolbar,
@@ -604,7 +650,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
604
650
  const [sectionAxis, setSectionAxis] = useState("z");
605
651
  const [sectionFlip, setSectionFlip] = useState(false);
606
652
  const [sectionPosition, setSectionPosition] = useState(0.5);
607
- const [sectionCapColor, setSectionCapColor] = useState("#9aa6b3");
653
+ const [sectionCapColor, setSectionCapColor] = useState("#c8ccd1");
608
654
  const sectionRef = useRef(null);
609
655
  useEffect(() => {
610
656
  let cancelled = false;
@@ -729,115 +775,159 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
729
775
  useEffect(() => {
730
776
  const v = viewerRef.current;
731
777
  if (!v?.viewer || loading) return;
732
- let cancelled = false;
733
- let teardown = null;
734
- (async () => {
735
- const THREE = await import('three');
736
- if (cancelled) return;
737
- const renderer = v.viewer.renderer;
738
- const scene = v.viewer.scene;
739
- if (!renderer || !scene) return;
740
- if (sectionRef.current) {
741
- const s = sectionRef.current;
742
- for (const [mat, prev] of s.materialState.entries()) {
743
- mat.clippingPlanes = prev.clippingPlanes;
744
- mat.clipShadows = prev.clipShadows;
745
- mat.needsUpdate = true;
746
- }
747
- for (const helper of s.helpers) {
748
- helper.parent?.remove(helper);
749
- helper.geometry?.dispose?.();
750
- helper.material?.dispose?.();
751
- }
752
- if (s.capMesh) {
753
- scene.remove(s.capMesh);
754
- s.capMesh.geometry?.dispose?.();
755
- s.capMesh.material?.dispose?.();
756
- }
757
- sectionRef.current = null;
778
+ const renderer = v.viewer.renderer;
779
+ const scene = v.viewer.scene;
780
+ if (!renderer || !scene) return;
781
+ if (sectionRef.current) {
782
+ const s = sectionRef.current;
783
+ for (const [mat, prev] of s.materialState.entries()) {
784
+ mat.clippingPlanes = prev.clippingPlanes;
785
+ mat.clipShadows = prev.clipShadows;
786
+ mat.needsUpdate = true;
758
787
  }
759
- if (!sectionEnabled) {
760
- renderer.localClippingEnabled = false;
761
- v.viewer.Render?.();
762
- return;
788
+ for (const helper of s.helpers) {
789
+ helper.parent?.remove(helper);
790
+ helper.material?.dispose?.();
763
791
  }
764
- const bbox = v.viewer.GetBoundingBox?.(() => true);
765
- if (!bbox) return;
766
- const plane = new THREE.Plane(new THREE.Vector3(0, 0, -1), 0);
767
- const helpers = [];
768
- const materialState = /* @__PURE__ */ new Map();
769
- const applyToMaterial = (mat) => {
770
- if (!mat || materialState.has(mat)) return;
771
- materialState.set(mat, {
772
- clippingPlanes: mat.clippingPlanes,
773
- clipShadows: mat.clipShadows
774
- });
775
- mat.clippingPlanes = [plane];
776
- mat.clipShadows = true;
777
- mat.needsUpdate = true;
778
- };
779
- const targets = [];
780
- v.viewer.mainModel?.EnumerateMeshes?.((mesh) => {
781
- if (mesh.userData?.__sectionHelper) return;
782
- targets.push(mesh);
783
- });
784
- for (const mesh of targets) {
785
- const mat = mesh.material;
786
- if (Array.isArray(mat)) for (const m of mat) applyToMaterial(m);
787
- else applyToMaterial(mat);
792
+ if (s.capMesh) {
793
+ scene.remove(s.capMesh);
794
+ s.capMesh.geometry?.dispose?.();
795
+ s.capMesh.material?.dispose?.();
796
+ }
797
+ sectionRef.current = null;
798
+ }
799
+ if (!sectionEnabled) {
800
+ renderer.localClippingEnabled = false;
801
+ v.viewer.Render?.();
802
+ return;
803
+ }
804
+ const bbox = v.viewer.GetBoundingBox?.(() => true);
805
+ if (!bbox) return;
806
+ const targets = [];
807
+ v.viewer.mainModel?.EnumerateMeshes?.((mesh) => {
808
+ if (!mesh.userData?.__sectionHelper) targets.push(mesh);
809
+ });
810
+ if (!targets.length) {
811
+ renderer.localClippingEnabled = false;
812
+ v.viewer.Render?.();
813
+ return;
814
+ }
815
+ const sample = targets[0];
816
+ const Mesh = sample.constructor;
817
+ const Material = sample.material?.constructor;
818
+ const Geometry = sample.geometry?.constructor;
819
+ const BufferAttr = sample.geometry?.attributes?.position?.constructor;
820
+ if (!Mesh || !Material || !Geometry || !BufferAttr) {
821
+ console.warn("[Preview] section: missing THREE constructors, falling back to no cap");
822
+ }
823
+ const FrontSide = 0, BackSide = 1, DoubleSide = 2;
824
+ const AlwaysStencilFunc = 519, NotEqualStencilFunc = 517;
825
+ const IncrementWrapStencilOp = 7682, DecrementWrapStencilOp = 7683;
826
+ const ReplaceStencilOp = 7681;
827
+ const plane = { normal: { x: 0, y: 0, z: -1 }, constant: 0 };
828
+ const helpers = [];
829
+ const materialState = /* @__PURE__ */ new Map();
830
+ const applyToMaterial = (mat) => {
831
+ if (!mat || materialState.has(mat)) return;
832
+ materialState.set(mat, { clippingPlanes: mat.clippingPlanes, clipShadows: mat.clipShadows });
833
+ mat.clippingPlanes = [plane];
834
+ mat.clipShadows = true;
835
+ mat.needsUpdate = true;
836
+ };
837
+ for (const mesh of targets) {
838
+ const mat = mesh.material;
839
+ if (Array.isArray(mat)) for (const m of mat) applyToMaterial(m);
840
+ else applyToMaterial(mat);
841
+ if (Mesh && Material) {
788
842
  const makeStencil = (side, op) => {
789
- const m = new THREE.MeshBasicMaterial({
790
- depthWrite: false,
791
- depthTest: false,
792
- colorWrite: false,
793
- stencilWrite: true,
794
- stencilFunc: THREE.AlwaysStencilFunc,
795
- stencilFail: op,
796
- stencilZFail: op,
797
- stencilZPass: op,
798
- side,
799
- clippingPlanes: [plane]
800
- });
801
- const helper = new THREE.Mesh(mesh.geometry, m);
843
+ const m = new Material();
844
+ m.depthWrite = false;
845
+ m.depthTest = false;
846
+ m.colorWrite = false;
847
+ m.stencilWrite = true;
848
+ m.stencilFunc = AlwaysStencilFunc;
849
+ m.stencilFail = op;
850
+ m.stencilZFail = op;
851
+ m.stencilZPass = op;
852
+ m.side = side;
853
+ m.clippingPlanes = [plane];
854
+ m.clipShadows = true;
855
+ const helper = new Mesh(mesh.geometry, m);
802
856
  helper.matrixAutoUpdate = false;
803
857
  helper.renderOrder = 1;
804
858
  helper.userData.__sectionHelper = true;
805
859
  mesh.add(helper);
806
860
  helpers.push(helper);
807
861
  };
808
- makeStencil(THREE.BackSide, THREE.IncrementWrapStencilOp);
809
- makeStencil(THREE.FrontSide, THREE.DecrementWrapStencilOp);
862
+ makeStencil(BackSide, IncrementWrapStencilOp);
863
+ makeStencil(FrontSide, DecrementWrapStencilOp);
810
864
  }
865
+ }
866
+ v.viewer.mainModel?.EnumerateEdges?.((edge) => {
867
+ const mat = edge.material;
868
+ if (Array.isArray(mat)) for (const m of mat) applyToMaterial(m);
869
+ else applyToMaterial(mat);
870
+ });
871
+ let capMesh = null;
872
+ if (Mesh && Material && Geometry && BufferAttr) {
811
873
  const dx = bbox.max.x - bbox.min.x;
812
874
  const dy = bbox.max.y - bbox.min.y;
813
875
  const dz = bbox.max.z - bbox.min.z;
814
- const capSize = Math.max(dx, dy, dz) * 2 || 1;
815
- const capGeom = new THREE.PlaneGeometry(capSize, capSize);
816
- const capMat = new THREE.MeshPhongMaterial({
817
- color: 10135219,
818
- side: THREE.DoubleSide,
819
- stencilWrite: true,
820
- stencilRef: 0,
821
- stencilFunc: THREE.NotEqualStencilFunc,
822
- stencilFail: THREE.ReplaceStencilOp,
823
- stencilZFail: THREE.ReplaceStencilOp,
824
- stencilZPass: THREE.ReplaceStencilOp
825
- });
826
- const capMesh = new THREE.Mesh(capGeom, capMat);
876
+ const capSize = Math.max(dx, dy, dz, 1) * 2;
877
+ const half = capSize / 2;
878
+ const capGeom = new Geometry();
879
+ const positions = new Float32Array([
880
+ -half,
881
+ -half,
882
+ 0,
883
+ half,
884
+ -half,
885
+ 0,
886
+ half,
887
+ half,
888
+ 0,
889
+ -half,
890
+ half,
891
+ 0
892
+ ]);
893
+ const normals = new Float32Array([
894
+ 0,
895
+ 0,
896
+ 1,
897
+ 0,
898
+ 0,
899
+ 1,
900
+ 0,
901
+ 0,
902
+ 1,
903
+ 0,
904
+ 0,
905
+ 1
906
+ ]);
907
+ capGeom.setAttribute("position", new BufferAttr(positions, 3));
908
+ capGeom.setAttribute("normal", new BufferAttr(normals, 3));
909
+ capGeom.setIndex([0, 1, 2, 0, 2, 3]);
910
+ const capMat = new Material();
911
+ const m = /^#?([0-9a-f]{6})$/i.exec(sectionCapColor);
912
+ const colorHex = m ? parseInt(m[1], 16) : 13159633;
913
+ capMat.color?.setHex?.(colorHex);
914
+ capMat.side = DoubleSide;
915
+ capMat.stencilWrite = true;
916
+ capMat.stencilRef = 0;
917
+ capMat.stencilFunc = NotEqualStencilFunc;
918
+ capMat.stencilFail = ReplaceStencilOp;
919
+ capMat.stencilZFail = ReplaceStencilOp;
920
+ capMat.stencilZPass = ReplaceStencilOp;
921
+ capMat.clippingPlanes = [];
922
+ capMesh = new Mesh(capGeom, capMat);
827
923
  capMesh.renderOrder = 2;
828
924
  capMesh.userData.__sectionHelper = true;
829
925
  scene.add(capMesh);
830
- renderer.localClippingEnabled = true;
831
- sectionRef.current = { plane, capMesh, helpers, materialState, bbox };
832
- v.viewer.Render?.();
833
- teardown = () => {
834
- };
835
- })();
836
- return () => {
837
- cancelled = true;
838
- if (teardown) teardown();
839
- };
840
- }, [sectionEnabled, loading, tree]);
926
+ }
927
+ renderer.localClippingEnabled = true;
928
+ sectionRef.current = { plane, capMesh, helpers, materialState, bbox };
929
+ v.viewer.Render?.();
930
+ }, [sectionEnabled, loading, tree, sectionCapColor]);
841
931
  useEffect(() => {
842
932
  const v = viewerRef.current;
843
933
  const s = sectionRef.current;
@@ -852,29 +942,26 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
852
942
  const nx = sectionAxis === "x" ? dir : 0;
853
943
  const ny = sectionAxis === "y" ? dir : 0;
854
944
  const nz = sectionAxis === "z" ? dir : 0;
855
- s.plane.normal.set(nx, ny, nz);
945
+ s.plane.normal.x = nx;
946
+ s.plane.normal.y = ny;
947
+ s.plane.normal.z = nz;
856
948
  s.plane.constant = -dir * value;
857
- const cx = (bbox.min.x + bbox.max.x) / 2;
858
- const cy = (bbox.min.y + bbox.max.y) / 2;
859
- const cz = (bbox.min.z + bbox.max.z) / 2;
860
- const center = { x: cx, y: cy, z: cz };
861
- const dist = nx * center.x + ny * center.y + nz * center.z + s.plane.constant;
862
- const px = center.x - nx * dist;
863
- const py = center.y - ny * dist;
864
- const pz = center.z - nz * dist;
865
- s.capMesh.position.set(px, py, pz);
866
- s.capMesh.lookAt(px + nx, py + ny, pz + nz);
867
- try {
868
- const m = /^#?([0-9a-f]{6})$/i.exec(sectionCapColor);
869
- const n = m ? parseInt(m[1], 16) : 10135219;
870
- s.capMesh.material.color.setHex(n);
871
- } catch {
949
+ if (s.capMesh) {
950
+ const cx = (bbox.min.x + bbox.max.x) / 2;
951
+ const cy = (bbox.min.y + bbox.max.y) / 2;
952
+ const cz = (bbox.min.z + bbox.max.z) / 2;
953
+ const dist = nx * cx + ny * cy + nz * cz + s.plane.constant;
954
+ const px = cx - nx * dist;
955
+ const py = cy - ny * dist;
956
+ const pz = cz - nz * dist;
957
+ s.capMesh.position.set(px, py, pz);
958
+ s.capMesh.lookAt?.(px + nx, py + ny, pz + nz);
872
959
  }
873
960
  v.viewer.Render?.();
874
961
  } catch (err) {
875
962
  console.warn("[Preview] section update failed", err);
876
963
  }
877
- }, [sectionEnabled, sectionAxis, sectionFlip, sectionPosition, sectionCapColor]);
964
+ }, [sectionEnabled, sectionAxis, sectionFlip, sectionPosition]);
878
965
  useEffect(() => {
879
966
  if (!showHint || loading) return;
880
967
  const t = setTimeout(() => setShowHint(false), 5e3);
@@ -902,7 +989,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
902
989
  const handleFit = () => {
903
990
  try {
904
991
  const v = viewerRef.current;
905
- const sphere = v?.GetBoundingSphere?.(() => true);
992
+ const sphere = v?.viewer?.GetBoundingSphere?.(() => true);
906
993
  if (sphere) v.viewer.FitSphereToWindow(sphere, true);
907
994
  v?.viewer?.Render?.();
908
995
  } catch {
@@ -913,7 +1000,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
913
1000
  const v = viewerRef.current;
914
1001
  if (!OV || !v?.viewer) return;
915
1002
  try {
916
- const sphere = v.GetBoundingSphere?.(() => true);
1003
+ const sphere = v.viewer.GetBoundingSphere?.(() => true);
917
1004
  if (!sphere) return;
918
1005
  const c = sphere.center;
919
1006
  const r = sphere.radius || 1;
@@ -971,7 +1058,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
971
1058
  setSectionAxis("z");
972
1059
  setSectionFlip(false);
973
1060
  setSectionPosition(0.5);
974
- setSectionCapColor("#9aa6b3");
1061
+ setSectionCapColor("#c8ccd1");
975
1062
  };
976
1063
  const handleDefaultDownload = () => {
977
1064
  const a = document.createElement("a");
@@ -988,24 +1075,24 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
988
1075
  /* @__PURE__ */ jsxs(
989
1076
  "div",
990
1077
  {
991
- className: "group flex items-center gap-1 px-1.5 py-1 hover:bg-slate-700/50 cursor-default text-[12px] text-slate-200",
1078
+ className: "group flex items-center gap-1 px-1.5 py-1 hover:bg-gray-100 cursor-default text-[12px] text-gray-700",
992
1079
  style: { paddingLeft: `${depth * 12 + 6}px` },
993
1080
  children: [
994
1081
  hasChildren ? /* @__PURE__ */ jsx(
995
1082
  "button",
996
1083
  {
997
1084
  onClick: () => toggleExpanded(node.id),
998
- className: "h-4 w-4 shrink-0 flex items-center justify-center text-slate-400 hover:text-slate-100",
1085
+ className: "h-4 w-4 shrink-0 flex items-center justify-center text-gray-500 hover:text-gray-900",
999
1086
  title: isExpanded ? "Collapse" : "Expand",
1000
1087
  children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: isExpanded ? "M19.5 8.25l-7.5 7.5-7.5-7.5" : "M8.25 4.5l7.5 7.5-7.5 7.5" }) })
1001
1088
  }
1002
- ) : /* @__PURE__ */ jsx("span", { className: "h-4 w-4 shrink-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "h-1 w-1 rounded-full bg-slate-500" }) }),
1089
+ ) : /* @__PURE__ */ jsx("span", { className: "h-4 w-4 shrink-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "h-1 w-1 rounded-full bg-gray-400" }) }),
1003
1090
  /* @__PURE__ */ jsx("span", { className: `flex-1 truncate ${isVisible ? "" : "opacity-40"}`, title: node.name, children: node.name }),
1004
1091
  /* @__PURE__ */ jsx(
1005
1092
  "button",
1006
1093
  {
1007
1094
  onClick: () => fitNode(),
1008
- className: "h-4 w-4 shrink-0 text-slate-500 hover:text-slate-100 opacity-0 group-hover:opacity-100 transition-opacity",
1095
+ className: "h-4 w-4 shrink-0 text-gray-400 hover:text-gray-900 opacity-0 group-hover:opacity-100 transition-opacity",
1009
1096
  title: "Fit to view",
1010
1097
  children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" }) })
1011
1098
  }
@@ -1014,7 +1101,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1014
1101
  "button",
1015
1102
  {
1016
1103
  onClick: () => toggleNodeVisible(node),
1017
- className: "h-4 w-4 shrink-0 text-slate-400 hover:text-slate-100",
1104
+ className: "h-4 w-4 shrink-0 text-gray-500 hover:text-gray-900",
1018
1105
  title: isVisible ? "Hide" : "Show",
1019
1106
  children: isVisible ? /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: [
1020
1107
  /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" }),
@@ -1028,12 +1115,12 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1028
1115
  isExpanded && hasChildren && /* @__PURE__ */ jsx("div", { children: node.children.map((c) => renderTreeNode(c, depth + 1)) })
1029
1116
  ] }, node.id);
1030
1117
  };
1031
- const tBtn = "h-8 w-8 shrink-0 flex items-center justify-center rounded text-slate-300 hover:bg-slate-700 hover:text-white transition-colors";
1032
- const tBtnActive = "h-8 w-8 shrink-0 flex items-center justify-center rounded bg-slate-700 text-white";
1033
- const tBtnSep = "h-5 w-px bg-slate-700 mx-1";
1034
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full bg-slate-900", children: [
1035
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5 bg-slate-800 border-b border-slate-700 shrink-0", children: [
1036
- /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold tracking-wide text-slate-300 px-2 truncate max-w-xs", title: filename, children: filename }),
1118
+ const tBtn = "h-8 w-8 shrink-0 flex items-center justify-center rounded text-gray-600 hover:bg-gray-200 hover:text-gray-900 transition-colors";
1119
+ const tBtnActive = "h-8 w-8 shrink-0 flex items-center justify-center rounded bg-gray-200 text-gray-900";
1120
+ const tBtnSep = "h-5 w-px bg-gray-300 mx-1";
1121
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full bg-white", children: [
1122
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5 bg-gray-50 border-b border-gray-200 shrink-0", children: [
1123
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold tracking-wide text-gray-700 px-2 truncate max-w-xs", title: filename, children: filename }),
1037
1124
  /* @__PURE__ */ jsx("div", { className: tBtnSep }),
1038
1125
  /* @__PURE__ */ jsx("button", { onClick: handleFit, className: tBtn, title: "Fit to view", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" }) }) }),
1039
1126
  /* @__PURE__ */ jsx("div", { className: tBtnSep }),
@@ -1057,10 +1144,10 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1057
1144
  onEmail && /* @__PURE__ */ jsx("button", { onClick: onEmail, className: tBtn, title: "Email", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }) })
1058
1145
  ] }),
1059
1146
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex min-h-0", children: [
1060
- showMeshes && /* @__PURE__ */ jsxs("div", { className: "w-60 shrink-0 bg-slate-800 border-r border-slate-700 flex flex-col", children: [
1061
- /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-slate-400 border-b border-slate-700", children: "Meshes" }),
1062
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: tree ? renderTreeNode(tree) : /* @__PURE__ */ jsx("div", { className: "px-3 py-3 text-[11px] text-slate-500 italic", children: loading ? "Reading model\u2026" : "No structure available" }) }),
1063
- tree && /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 text-[10px] text-slate-500 border-t border-slate-700", children: hidden.size === 0 ? "All visible" : `${hidden.size} hidden` })
1147
+ showMeshes && /* @__PURE__ */ jsxs("div", { className: "w-60 shrink-0 bg-gray-50 border-r border-gray-200 flex flex-col", children: [
1148
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-gray-500 border-b border-gray-200", children: "Meshes" }),
1149
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: tree ? renderTreeNode(tree) : /* @__PURE__ */ jsx("div", { className: "px-3 py-3 text-[11px] text-gray-500 italic", children: loading ? "Reading model\u2026" : "No structure available" }) }),
1150
+ tree && /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 text-[10px] text-gray-500 border-t border-gray-200", children: hidden.size === 0 ? "All visible" : `${hidden.size} hidden` })
1064
1151
  ] }),
1065
1152
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", style: { background: bgColor }, children: [
1066
1153
  /* @__PURE__ */ jsx("div", { ref: containerRef, style: { width: "100%", height: "100%" } }),
@@ -1081,12 +1168,12 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1081
1168
  ] }),
1082
1169
  error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-red-600 px-6 text-center bg-white/85", children: error })
1083
1170
  ] }),
1084
- showSettings && /* @__PURE__ */ jsxs("div", { className: "w-60 shrink-0 bg-slate-800 border-l border-slate-700 flex flex-col", children: [
1085
- /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-slate-400 border-b border-slate-700", children: "Model Display" }),
1086
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-3 py-3 space-y-3 text-[12px] text-slate-200", children: [
1171
+ showSettings && /* @__PURE__ */ jsxs("div", { className: "w-60 shrink-0 bg-gray-50 border-l border-gray-200 flex flex-col", children: [
1172
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-gray-500 border-b border-gray-200", children: "Model Display" }),
1173
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-3 py-3 space-y-3 text-[12px] text-gray-700", children: [
1087
1174
  /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2", children: [
1088
1175
  /* @__PURE__ */ jsx("span", { children: "Background Color" }),
1089
- /* @__PURE__ */ jsx("input", { type: "color", value: bgColor, onChange: (e) => setBgColor(e.target.value), className: "h-6 w-10 rounded border border-slate-600 bg-transparent" })
1176
+ /* @__PURE__ */ jsx("input", { type: "color", value: bgColor, onChange: (e) => setBgColor(e.target.value), className: "h-6 w-10 rounded border border-gray-300 bg-white" })
1090
1177
  ] }),
1091
1178
  /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2", children: [
1092
1179
  /* @__PURE__ */ jsx("span", { children: "Show Edges" }),
@@ -1094,7 +1181,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1094
1181
  "button",
1095
1182
  {
1096
1183
  onClick: () => setShowEdges((s) => !s),
1097
- className: `relative h-5 w-9 rounded-full transition-colors ${showEdges ? "bg-blue-500" : "bg-slate-600"}`,
1184
+ className: `relative h-5 w-9 rounded-full transition-colors ${showEdges ? "bg-blue-500" : "bg-gray-300"}`,
1098
1185
  children: /* @__PURE__ */ jsx("span", { className: `absolute top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${showEdges ? "translate-x-4" : "translate-x-0.5"}` })
1099
1186
  }
1100
1187
  )
@@ -1108,14 +1195,14 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1108
1195
  value: edgeColor,
1109
1196
  onChange: (e) => setEdgeColor(e.target.value),
1110
1197
  disabled: !showEdges,
1111
- className: "h-6 w-10 rounded border border-slate-600 bg-transparent disabled:opacity-40"
1198
+ className: "h-6 w-10 rounded border border-gray-300 bg-white disabled:opacity-40"
1112
1199
  }
1113
1200
  )
1114
1201
  ] }),
1115
1202
  /* @__PURE__ */ jsxs("div", { className: showEdges ? "" : "opacity-40 pointer-events-none", children: [
1116
1203
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 mb-1", children: [
1117
1204
  /* @__PURE__ */ jsx("span", { children: "Edge Threshold" }),
1118
- /* @__PURE__ */ jsxs("span", { className: "text-slate-400 tabular-nums", children: [
1205
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-500 tabular-nums", children: [
1119
1206
  edgeThreshold,
1120
1207
  "\xB0"
1121
1208
  ] })
@@ -1133,14 +1220,14 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1133
1220
  }
1134
1221
  )
1135
1222
  ] }),
1136
- /* @__PURE__ */ jsxs("div", { className: "border-t border-slate-700 -mx-3 px-3 pt-3 mt-1", children: [
1223
+ /* @__PURE__ */ jsxs("div", { className: "border-t border-gray-200 -mx-3 px-3 pt-3 mt-1", children: [
1137
1224
  /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2", children: [
1138
1225
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Section View" }),
1139
1226
  /* @__PURE__ */ jsx(
1140
1227
  "button",
1141
1228
  {
1142
1229
  onClick: () => setSectionEnabled((s) => !s),
1143
- className: `relative h-5 w-9 rounded-full transition-colors ${sectionEnabled ? "bg-blue-500" : "bg-slate-600"}`,
1230
+ className: `relative h-5 w-9 rounded-full transition-colors ${sectionEnabled ? "bg-blue-500" : "bg-gray-300"}`,
1144
1231
  children: /* @__PURE__ */ jsx("span", { className: `absolute top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${sectionEnabled ? "translate-x-4" : "translate-x-0.5"}` })
1145
1232
  }
1146
1233
  )
@@ -1153,7 +1240,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1153
1240
  "button",
1154
1241
  {
1155
1242
  onClick: () => setSectionFlip((f) => !f),
1156
- className: "text-[10px] text-slate-300 hover:text-white px-1.5 py-0.5 rounded bg-slate-700 hover:bg-slate-600",
1243
+ className: "text-[10px] text-gray-600 hover:text-gray-900 px-1.5 py-0.5 rounded bg-gray-100 hover:bg-gray-200",
1157
1244
  title: "Flip section direction",
1158
1245
  children: sectionFlip ? "\u2190 flipped" : "flip \u2192"
1159
1246
  }
@@ -1163,7 +1250,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1163
1250
  "button",
1164
1251
  {
1165
1252
  onClick: () => setSectionAxis(ax),
1166
- className: `py-1 rounded text-[11px] font-semibold ${sectionAxis === ax ? "bg-blue-500 text-white" : "bg-slate-700 text-slate-300 hover:bg-slate-600"}`,
1253
+ className: `py-1 rounded text-[11px] font-semibold ${sectionAxis === ax ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-700 hover:bg-gray-200"}`,
1167
1254
  children: ax.toUpperCase()
1168
1255
  },
1169
1256
  ax
@@ -1172,7 +1259,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1172
1259
  /* @__PURE__ */ jsxs("div", { children: [
1173
1260
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 mb-1", children: [
1174
1261
  /* @__PURE__ */ jsx("span", { children: "Position" }),
1175
- /* @__PURE__ */ jsxs("span", { className: "text-slate-400 tabular-nums", children: [
1262
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-500 tabular-nums", children: [
1176
1263
  Math.round(sectionPosition * 100),
1177
1264
  "%"
1178
1265
  ] })
@@ -1198,18 +1285,18 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1198
1285
  type: "color",
1199
1286
  value: sectionCapColor,
1200
1287
  onChange: (e) => setSectionCapColor(e.target.value),
1201
- className: "h-6 w-10 rounded border border-slate-600 bg-transparent"
1288
+ className: "h-6 w-10 rounded border border-gray-300 bg-white"
1202
1289
  }
1203
1290
  )
1204
1291
  ] })
1205
1292
  ] })
1206
1293
  ] })
1207
1294
  ] }),
1208
- /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-t border-slate-700", children: /* @__PURE__ */ jsx(
1295
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-t border-gray-200", children: /* @__PURE__ */ jsx(
1209
1296
  "button",
1210
1297
  {
1211
1298
  onClick: handleResetDisplay,
1212
- className: "w-full text-[11px] text-slate-300 bg-slate-700 hover:bg-slate-600 rounded py-1.5 transition-colors",
1299
+ className: "w-full text-[11px] text-gray-700 bg-gray-100 hover:bg-gray-200 rounded py-1.5 transition-colors",
1213
1300
  children: "Reset to Default"
1214
1301
  }
1215
1302
  ) })
@@ -1267,5 +1354,5 @@ function ImagePanel({ url, filename, onDownload, onEmail }) {
1267
1354
  }
1268
1355
 
1269
1356
  export { Preview, setPdfPreview };
1270
- //# sourceMappingURL=chunk-CZKAKVP6.js.map
1271
- //# sourceMappingURL=chunk-CZKAKVP6.js.map
1357
+ //# sourceMappingURL=chunk-IQWRDQHW.js.map
1358
+ //# sourceMappingURL=chunk-IQWRDQHW.js.map