floor-editor-ts 1.1.4 → 1.1.6

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.
@@ -6951,6 +6951,54 @@ var localStore = {
6951
6951
  }
6952
6952
  };
6953
6953
  //#endregion
6954
+ //#region src/lib/packageDefaults.ts
6955
+ var DEFAULT_CONFIG = {
6956
+ viewOnly: false,
6957
+ floorMaxWidth: 600,
6958
+ floorMaxHeight: 400,
6959
+ heatmapEnabled: false,
6960
+ heatmapMatrix: [],
6961
+ projectName: void 0,
6962
+ selectedCameraSerial: null,
6963
+ showCameraCones: false,
6964
+ showCameraLabels: true,
6965
+ cameraHeatmapMatrix: []
6966
+ };
6967
+ function normalizeConfig(value) {
6968
+ if (!value || typeof value !== "object") return { ...DEFAULT_CONFIG };
6969
+ return {
6970
+ ...DEFAULT_CONFIG,
6971
+ ...value
6972
+ };
6973
+ }
6974
+ function normalizeFloorData(data) {
6975
+ if (!data || typeof data !== "object") return createDefaultProject();
6976
+ if (!Array.isArray(data.floors) || data.floors.length === 0) return createDefaultProject();
6977
+ if (!data.activeFloorId || !data.floors.some((f) => f.id === data.activeFloorId)) return {
6978
+ ...createDefaultProject(),
6979
+ ...data,
6980
+ floors: data.floors,
6981
+ activeFloorId: data.floors[0].id
6982
+ };
6983
+ return data;
6984
+ }
6985
+ var RUNTIME_FURNITURE_FIELDS = [
6986
+ "showHeatmap",
6987
+ "heatmapMatrix",
6988
+ "hasPerson"
6989
+ ];
6990
+ /** Strip runtime-only fields before persisting or dispatching floor:save. */
6991
+ function exportProjectForSave(project) {
6992
+ const exported = JSON.parse(JSON.stringify(project));
6993
+ exported.updatedAt = /* @__PURE__ */ new Date();
6994
+ for (const floor of exported.floors) floor.furniture = floor.furniture.map((item) => {
6995
+ const clean = { ...item };
6996
+ for (const key of RUNTIME_FURNITURE_FIELDS) delete clean[key];
6997
+ return clean;
6998
+ });
6999
+ return exported;
7000
+ }
7001
+ //#endregion
6954
7002
  //#region src/lib/utils/furnitureCatalog.ts
6955
7003
  var furnitureCatalog = [
6956
7004
  {
@@ -56025,8 +56073,8 @@ var root_2$12 = /* @__PURE__ */ from_html(`<div class="absolute bottom-0 left-0
56025
56073
  var root_3$12 = /* @__PURE__ */ from_html(`<div class="absolute bottom-0 left-0 right-0 h-0.5 bg-slate-700 dark:bg-slate-300 rounded-t"></div>`);
56026
56074
  var root_4$11 = /* @__PURE__ */ from_html(`<div class="absolute bottom-0 left-0 right-0 h-0.5 bg-slate-700 dark:bg-slate-300 rounded-t"></div>`);
56027
56075
  var root_5$8 = /* @__PURE__ */ from_html(`<div class="absolute bottom-0 left-0 right-0 h-0.5 bg-slate-700 dark:bg-slate-300 rounded-t"></div>`);
56028
- var root_6$6 = /* @__PURE__ */ from_html(`<div class="space-y-4"><label class="block"><span class="text-sm font-medium text-gray-700 dark:text-gray-300">Project Name</span> <input type="text" class="mt-1 w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:ring-2 focus:ring-slate-500 focus:border-slate-500 outline-none bg-white dark:bg-gray-700 dark:text-gray-100" placeholder="Untitled Project"/></label> <label class="block"><span class="text-sm font-medium text-gray-700 dark:text-gray-300">Description</span> <textarea rows="3" class="mt-1 w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:ring-2 focus:ring-slate-500 focus:border-slate-500 outline-none resize-none bg-white dark:bg-gray-700 dark:text-gray-100" placeholder="Add a description for this project..."></textarea></label></div>`);
56029
- var root_7$5 = /* @__PURE__ */ from_html(`<div class="flex items-center justify-between mb-5"><span class="text-sm font-medium text-gray-700 dark:text-gray-300">Metrics unit</span> <div class="flex rounded-lg border border-gray-300 dark:border-gray-600 overflow-hidden"><button>m, cm</button> <button>ft, inch</button></div></div> <div class="bg-gray-50 dark:bg-gray-700/50 rounded-xl divide-y divide-gray-200 dark:divide-gray-600"><label class="flex items-center justify-between px-4 py-3.5 cursor-pointer"><span class="text-sm text-gray-700">Dimensions</span> <input type="checkbox" class="w-10 h-5 rounded-full appearance-none cursor-pointer bg-gray-300 checked:bg-slate-700 relative transition-colors
56076
+ var root_6$5 = /* @__PURE__ */ from_html(`<div class="space-y-4"><label class="block"><span class="text-sm font-medium text-gray-700 dark:text-gray-300">Project Name</span> <input type="text" class="mt-1 w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:ring-2 focus:ring-slate-500 focus:border-slate-500 outline-none bg-white dark:bg-gray-700 dark:text-gray-100" placeholder="Untitled Project"/></label> <label class="block"><span class="text-sm font-medium text-gray-700 dark:text-gray-300">Description</span> <textarea rows="3" class="mt-1 w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:ring-2 focus:ring-slate-500 focus:border-slate-500 outline-none resize-none bg-white dark:bg-gray-700 dark:text-gray-100" placeholder="Add a description for this project..."></textarea></label></div>`);
56077
+ var root_7$6 = /* @__PURE__ */ from_html(`<div class="flex items-center justify-between mb-5"><span class="text-sm font-medium text-gray-700 dark:text-gray-300">Metrics unit</span> <div class="flex rounded-lg border border-gray-300 dark:border-gray-600 overflow-hidden"><button>m, cm</button> <button>ft, inch</button></div></div> <div class="bg-gray-50 dark:bg-gray-700/50 rounded-xl divide-y divide-gray-200 dark:divide-gray-600"><label class="flex items-center justify-between px-4 py-3.5 cursor-pointer"><span class="text-sm text-gray-700">Dimensions</span> <input type="checkbox" class="w-10 h-5 rounded-full appearance-none cursor-pointer bg-gray-300 checked:bg-slate-700 relative transition-colors
56030
56078
  before:content-[''] before:absolute before:w-4 before:h-4 before:rounded-full before:bg-white before:top-0.5 before:left-0.5 before:transition-transform checked:before:translate-x-5"/></label> <label class="flex items-center justify-between px-4 py-3.5 cursor-pointer"><span class="text-sm text-gray-700">External Dimensions</span> <input type="checkbox" class="w-10 h-5 rounded-full appearance-none cursor-pointer bg-gray-300 checked:bg-slate-700 relative transition-colors
56031
56079
  before:content-[''] before:absolute before:w-4 before:h-4 before:rounded-full before:bg-white before:top-0.5 before:left-0.5 before:transition-transform checked:before:translate-x-5"/></label> <label class="flex items-center justify-between px-4 py-3.5 cursor-pointer"><span class="text-sm text-gray-700">Internal Dimensions</span> <input type="checkbox" class="w-10 h-5 rounded-full appearance-none cursor-pointer bg-gray-300 checked:bg-slate-700 relative transition-colors
56032
56080
  before:content-[''] before:absolute before:w-4 before:h-4 before:rounded-full before:bg-white before:top-0.5 before:left-0.5 before:transition-transform checked:before:translate-x-5"/></label> <label class="flex items-center justify-between px-4 py-3.5 cursor-pointer"><span class="text-sm text-gray-700">Extension Lines</span> <input type="checkbox" class="w-10 h-5 rounded-full appearance-none cursor-pointer bg-gray-300 checked:bg-slate-700 relative transition-colors
@@ -56186,7 +56234,7 @@ function SettingsDialog($$anchor, $$props) {
56186
56234
  var div_8 = sibling(div_3, 2);
56187
56235
  var node_5 = child(div_8);
56188
56236
  var consequent_4 = ($$anchor) => {
56189
- var div_9 = root_6$6();
56237
+ var div_9 = root_6$5();
56190
56238
  var label_1 = child(div_9);
56191
56239
  var input = sibling(child(label_1), 2);
56192
56240
  remove_input_defaults(input);
@@ -56205,7 +56253,7 @@ function SettingsDialog($$anchor, $$props) {
56205
56253
  append($$anchor, div_9);
56206
56254
  };
56207
56255
  var consequent_5 = ($$anchor) => {
56208
- var fragment_1 = root_7$5();
56256
+ var fragment_1 = root_7$6();
56209
56257
  var div_10 = first_child(fragment_1);
56210
56258
  var div_11 = sibling(child(div_10), 2);
56211
56259
  var button_5 = child(div_11);
@@ -56762,7 +56810,7 @@ async function autoSave(onDispatch) {
56762
56810
  try {
56763
56811
  const thumbnail = captureThumbnail(p.id);
56764
56812
  onDispatch("floor:autoSave", { data: {
56765
- ...p,
56813
+ ...exportProjectForSave(p),
56766
56814
  thumbnail
56767
56815
  } });
56768
56816
  saveState.set("saved");
@@ -56895,9 +56943,9 @@ var root_2$9 = /* @__PURE__ */ from_html(`<input type="text" class="bg-white/20
56895
56943
  var root_3$9 = /* @__PURE__ */ from_html(`<button class="font-semibold text-white text-sm hover:bg-white/10 px-2 py-0.5 rounded transition-colors" title="Click to rename"> </button>`);
56896
56944
  var root_4$8 = /* @__PURE__ */ from_html(`<button> </button>`);
56897
56945
  var root_5$5 = /* @__PURE__ */ from_html(`<div class="flex bg-white/15 rounded-full p-0.5"><button title="Select mode (V)" aria-label="Select mode"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg></button> <button title="Pan mode (H)" aria-label="Pan mode"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 11V6a2 2 0 0 0-4 0v1"></path><path d="M14 10V4a2 2 0 0 0-4 0v2"></path><path d="M10 10.5V6a2 2 0 0 0-4 0v8"></path><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"></path></svg></button></div>`);
56898
- var root_6$5 = /* @__PURE__ */ from_html(`<div class="flex items-center gap-1 bg-white/15 rounded-full p-0.5"><button class="w-7 h-7 flex items-center justify-center text-white/80 hover:text-white hover:bg-white/10 rounded-full transition-colors text-sm font-bold" title="Zoom Out (−)" aria-label="Zoom Out">−</button> <button class="px-2 py-1 text-xs font-medium text-white/80 hover:text-white hover:bg-white/10 rounded-full transition-colors min-w-[3rem] text-center" title="Reset Zoom (100%)"> </button> <button class="w-7 h-7 flex items-center justify-center text-white/80 hover:text-white hover:bg-white/10 rounded-full transition-colors text-sm font-bold" title="Zoom In (+)" aria-label="Zoom In">+</button></div>`);
56946
+ var root_6$4 = /* @__PURE__ */ from_html(`<div class="flex items-center gap-1 bg-white/15 rounded-full p-0.5"><button class="w-7 h-7 flex items-center justify-center text-white/80 hover:text-white hover:bg-white/10 rounded-full transition-colors text-sm font-bold" title="Zoom Out (−)" aria-label="Zoom Out">−</button> <button class="px-2 py-1 text-xs font-medium text-white/80 hover:text-white hover:bg-white/10 rounded-full transition-colors min-w-[3rem] text-center" title="Reset Zoom (100%)"> </button> <button class="w-7 h-7 flex items-center justify-center text-white/80 hover:text-white hover:bg-white/10 rounded-full transition-colors text-sm font-bold" title="Zoom In (+)" aria-label="Zoom In">+</button></div>`);
56899
56947
  var root_8$2 = /* @__PURE__ */ from_html(`<button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg> Import JSON</button>`);
56900
- var root_7$4 = /* @__PURE__ */ from_html(`<div class="absolute right-0 top-full mt-1 bg-white rounded-lg shadow-lg border border-gray-200 py-1 w-48 z-50"><button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg> Print Layout</button> <div class="h-px bg-gray-100 my-1"></div> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><path d="M21 15l-5-5L5 21"></path></svg> Export 2D as PNG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"></path><path d="M2 17l10 5 10-5"></path><path d="M2 12l10 5 10-5"></path></svg> Export 3D as PNG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19V5"></path><path d="M5 12l7-7 7 7"></path></svg> Export as SVG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M8 16h2"></path><path d="M14 16h2"></path></svg> Export as DXF</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M9 16h6"></path></svg> Export as DWG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M16 11v6"></path><path d="M8 11v6"></path><path d="M12 11v6"></path></svg> Export as PDF</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path></svg> Download JSON</button> <div class="h-px bg-gray-100 my-1"></div> <!> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg> New Project</button></div>`);
56948
+ var root_7$5 = /* @__PURE__ */ from_html(`<div class="absolute right-0 top-full mt-1 bg-white rounded-lg shadow-lg border border-gray-200 py-1 w-48 z-50"><button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg> Print Layout</button> <div class="h-px bg-gray-100 my-1"></div> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><path d="M21 15l-5-5L5 21"></path></svg> Export 2D as PNG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"></path><path d="M2 17l10 5 10-5"></path><path d="M2 12l10 5 10-5"></path></svg> Export 3D as PNG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19V5"></path><path d="M5 12l7-7 7 7"></path></svg> Export as SVG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M8 16h2"></path><path d="M14 16h2"></path></svg> Export as DXF</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M9 16h6"></path></svg> Export as DWG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M16 11v6"></path><path d="M8 11v6"></path><path d="M12 11v6"></path></svg> Export as PDF</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path></svg> Download JSON</button> <div class="h-px bg-gray-100 my-1"></div> <!> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg> New Project</button></div>`);
56901
56949
  var root_1$10 = /* @__PURE__ */ from_html(`<div class="h-12 bg-gradient-to-r from-slate-800 to-slate-700 flex items-center px-4 gap-3 shrink-0 shadow-sm"><!> <div class="h-5 w-px bg-white/20"></div> <div class="flex items-center gap-1"><!> <button class="text-white/80 hover:text-white text-xs hover:bg-white/10 px-1.5 py-0.5 rounded transition-colors" title="Add Floor" aria-label="Add Floor">+</button> <span class="text-white/40 text-[10px] ml-1"> </span></div> <div class="flex-1"></div> <button class="p-1.5 text-white/80 hover:text-white hover:bg-white/10 rounded transition-colors" title="Undo (Ctrl+Z)" aria-label="Undo"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"></polyline><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path></svg></button> <button class="p-1.5 text-white/80 hover:text-white hover:bg-white/10 rounded transition-colors" title="Redo (Ctrl+Y)" aria-label="Redo"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.13-9.36L23 10"></path></svg></button> <div class="h-5 w-px bg-white/20"></div> <button aria-label="Snap to Grid"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg></button> <!> <button aria-label="Toggle Furniture"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="12" width="20" height="8" rx="1"></rect><path d="M4 12V7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v5"></path><line x1="12" y1="12" x2="12" y2="20"></line></svg></button> <div class="h-5 w-px bg-white/20"></div> <!> <button class="p-1.5 text-white/80 hover:text-white hover:bg-white/10 rounded transition-colors" title="Version History" aria-label="Version History"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg></button> <button class="px-2 py-1.5 text-white/80 hover:text-white hover:bg-white/10 rounded transition-colors" title="Area Summary" aria-label="Area Summary"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"></rect><path d="M3 9h18"></path><path d="M9 3v18"></path></svg></button> <button class="px-2 py-1.5 text-white/80 hover:text-white hover:bg-white/10 rounded transition-colors" title="Settings" aria-label="Settings"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg></button> <div class="h-5 w-px bg-white/20"></div> <div class="relative"><button class="px-3 py-1.5 text-sm text-white/90 hover:text-white hover:bg-white/10 rounded transition-colors flex items-center gap-1.5"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg> Export</button> <!></div> <span><!></span> <button class="px-3 py-1.5 text-sm bg-white text-slate-800 font-semibold rounded-lg hover:bg-blue-50 transition-colors shadow-sm">Save</button></div>`);
56902
56950
  var root_13$2 = /* @__PURE__ */ from_html(`<div class="absolute right-0 top-full mt-1 bg-white rounded-lg shadow-lg border border-gray-200 py-1 w-48 z-50"><button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg> Print Layout</button> <div class="h-px bg-gray-100 my-1"></div> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><path d="M21 15l-5-5L5 21"></path></svg> Export 2D as PNG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"></path><path d="M2 17l10 5 10-5"></path><path d="M2 12l10 5 10-5"></path></svg> Export 3D as PNG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19V5"></path><path d="M5 12l7-7 7 7"></path></svg> Export as SVG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M8 16h2"></path><path d="M14 16h2"></path></svg> Export as DXF</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M9 16h6"></path></svg> Export as DWG</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path><path d="M16 11v6"></path><path d="M8 11v6"></path><path d="M12 11v6"></path></svg> Export as PDF</button> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><path d="M14 2v6h6"></path></svg> Download JSON</button> <div class="h-px bg-gray-100 my-1"></div> <button class="w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 text-left flex items-center gap-2"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg> Import JSON</button></div>`);
56903
56951
  var root_12$2 = /* @__PURE__ */ from_html(`<div class="h-12 bg-gradient-to-r from-slate-800 to-slate-700 flex items-center justify-between px-4 gap-3 shrink-0 shadow-sm"><span class="font-semibold text-white text-sm px-2 py-0.5 rounded transition-colors"> </span> <div class="relative"><button class="px-3 py-1.5 text-sm text-white/90 hover:text-white hover:bg-white/10 rounded transition-colors flex items-center gap-1.5"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg> Import</button> <!></div></div>`);
@@ -56947,9 +56995,10 @@ function TopBar($$anchor, $$props) {
56947
56995
  }
56948
56996
  async function save() {
56949
56997
  const p = get$1(currentProject);
56998
+ if (!p) return;
56950
56999
  const thumbnail = captureThumbnail(p.id);
56951
57000
  $$props.onDispatch("floor:save", { data: {
56952
- ...p,
57001
+ ...exportProjectForSave(p),
56953
57002
  thumbnail
56954
57003
  } });
56955
57004
  }
@@ -57152,7 +57201,7 @@ function TopBar($$anchor, $$props) {
57152
57201
  var button_8 = sibling(node_3, 2);
57153
57202
  var node_4 = sibling(button_8, 4);
57154
57203
  var consequent_2 = ($$anchor) => {
57155
- var div_3 = root_6$5();
57204
+ var div_3 = root_6$4();
57156
57205
  var button_9 = child(div_3);
57157
57206
  var button_10 = sibling(button_9, 2);
57158
57207
  var text_4 = child(button_10);
@@ -57175,7 +57224,7 @@ function TopBar($$anchor, $$props) {
57175
57224
  var button_15 = child(div_4);
57176
57225
  var node_5 = sibling(button_15, 2);
57177
57226
  var consequent_4 = ($$anchor) => {
57178
- var div_5 = root_7$4();
57227
+ var div_5 = root_7$5();
57179
57228
  var button_16 = child(div_5);
57180
57229
  var button_17 = sibling(button_16, 4);
57181
57230
  var button_18 = sibling(button_17, 2);
@@ -58013,10 +58062,10 @@ var root_3$7 = /* @__PURE__ */ from_html(`<button draggable="true"><div class="w
58013
58062
  var root_4$6 = /* @__PURE__ */ from_html(`<button draggable="true"><div class="w-9 h-9 rounded-lg bg-cyan-50 flex items-center justify-center"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0e7490" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="1"></rect><line x1="12" y1="4" x2="12" y2="20"></line><line x1="3" y1="12" x2="21" y2="12"></line></svg></div> <span class="text-xs font-medium text-gray-600"> </span> <span class="text-[10px] text-gray-400"> </span></button>`);
58014
58063
  var root_2$7 = /* @__PURE__ */ from_html(`<div class="grid grid-cols-2 gap-2 mb-3"></div> <h3 class="text-xs font-semibold text-gray-400 uppercase mb-2">Windows</h3> <div class="grid grid-cols-2 gap-2"></div>`, 1);
58015
58064
  var root_1$8 = /* @__PURE__ */ from_html(`<div class="space-y-1"><h3 class="text-xs font-semibold text-gray-400 uppercase mb-2">Tools</h3> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg></div> <div class="text-left"><div class="font-medium">Select <span class="text-gray-400 text-xs ml-1">V</span></div> <div class="text-xs text-gray-400">Click to select elements</div></div></button> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="8" width="18" height="8" rx="1"></rect><line x1="7" y1="8" x2="7" y2="16"></line><line x1="12" y1="8" x2="12" y2="16"></line><line x1="17" y1="8" x2="17" y2="16"></line></svg></div> <div class="text-left"><div class="font-medium">Draw Wall <span class="text-gray-400 text-xs ml-1">W</span></div> <div class="text-xs text-gray-400">Click to draw, dbl-click to finish</div></div></button> <h3 class="text-xs font-semibold text-gray-400 uppercase mb-2 mt-3">Structure</h3> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 5h-5V2h-3v6h-4V5H7v6H2v3h5v3h3v-3h4v3h3v-6h5z"></path></svg></div> <div class="text-left"><div class="font-medium">Add Stairs</div> <div class="text-xs text-gray-400">Click to place stairs</div></div></button> <div class="flex gap-2"><button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="6"></circle><line x1="6" y1="6" x2="18" y2="18"></line><line x1="18" y1="6" x2="6" y2="18"></line></svg></div> <div class="text-left"><div class="font-medium text-xs">Round Column</div></div></button> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="6" y="6" width="12" height="12"></rect><line x1="6" y1="6" x2="18" y2="18"></line><line x1="18" y1="6" x2="6" y2="18"></line></svg></div> <div class="text-left"><div class="font-medium text-xs">Square Column</div></div></button></div> <h3 class="text-xs font-semibold text-gray-400 uppercase mb-2 mt-3">Annotate</h3> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7V4h16v3"></path><line x1="12" y1="4" x2="12" y2="20"></line><line x1="8" y1="20" x2="16" y2="20"></line></svg></div> <div class="text-left"><div class="font-medium">Text Label</div> <div class="text-xs text-gray-400">Add text annotations (T)</div></div></button> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><line x1="16" y1="5" x2="22" y2="5"></line><line x1="19" y1="2" x2="19" y2="8"></line><line x1="3" y1="12" x2="12" y2="12"></line></svg></div> <div class="text-left"><div class="font-medium">Dimension</div> <div class="text-xs text-gray-400">Add dimension annotations (N)</div></div></button> <button><div><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h5l2-7 4 14 2-7h7"></path></svg></div> <div class="text-left"><div class="font-medium">Measure</div> <div class="text-xs text-gray-400">Measure distances (M)</div></div></button> <h3 class="text-xs font-semibold text-gray-400 uppercase mb-2 mt-3">Import</h3> <button class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm transition-colors hover:bg-gray-50 text-gray-700"><div class="w-9 h-9 rounded-lg bg-gray-100 flex items-center justify-center"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path></svg></div> <div class="text-left"><div class="font-medium">Import Image</div> <div class="text-xs text-gray-400">Floor plan background</div></div></button> <button class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm transition-colors hover:bg-gray-50 text-gray-700"><div class="w-9 h-9 rounded-lg bg-gray-100 flex items-center justify-center"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg></div> <div class="text-left"><div class="font-medium">Import RoomPlan</div> <div class="text-xs text-gray-400">iOS LiDAR scan (.json/.zip)</div></div></button> <button class="w-full flex items-center justify-between px-1 py-2 mt-3"><h3 class="text-xs font-semibold text-gray-400 uppercase">Doors</h3> <span class="text-gray-400 text-xs"> </span></button> <!></div>`);
58016
- var root_6$4 = /* @__PURE__ */ from_html(`<button class="flex flex-col items-center gap-1.5 p-3 rounded-lg border-2 border-gray-100 hover:border-blue-300 hover:bg-blue-50 transition-colors cursor-grab active:cursor-grabbing" draggable="true"><div class="w-12 h-12 rounded-lg bg-gray-50 flex items-center justify-center text-2xl font-mono"> </div> <span class="text-xs font-medium text-gray-600"> </span></button>`);
58017
- var root_7$3 = /* @__PURE__ */ from_html(`<button class="flex flex-col items-center gap-1.5 p-3 rounded-lg border-2 border-gray-100 hover:border-green-300 hover:bg-green-50 transition-colors cursor-grab active:cursor-grabbing" draggable="true"><div class="w-12 h-12 rounded-lg bg-green-50 flex items-center justify-center text-lg"><!></div> <span class="text-xs font-medium text-gray-600"> </span> <span class="text-[10px] text-gray-400"> </span></button>`);
58065
+ var root_6$3 = /* @__PURE__ */ from_html(`<button class="flex flex-col items-center gap-1.5 p-3 rounded-lg border-2 border-gray-100 hover:border-blue-300 hover:bg-blue-50 transition-colors cursor-grab active:cursor-grabbing" draggable="true"><div class="w-12 h-12 rounded-lg bg-gray-50 flex items-center justify-center text-2xl font-mono"> </div> <span class="text-xs font-medium text-gray-600"> </span></button>`);
58066
+ var root_7$4 = /* @__PURE__ */ from_html(`<button class="flex flex-col items-center gap-1.5 p-3 rounded-lg border-2 border-gray-100 hover:border-green-300 hover:bg-green-50 transition-colors cursor-grab active:cursor-grabbing" draggable="true"><div class="w-12 h-12 rounded-lg bg-green-50 flex items-center justify-center text-lg"><!></div> <span class="text-xs font-medium text-gray-600"> </span> <span class="text-[10px] text-gray-400"> </span></button>`);
58018
58067
  var root_5$4 = /* @__PURE__ */ from_html(`<div class="space-y-2"><h3 class="text-xs font-semibold text-gray-400 uppercase mb-2">Room Presets</h3> <p class="text-xs text-gray-400 mb-3">Click to add a room shape to the canvas</p> <div class="grid grid-cols-2 gap-2"></div> <hr class="my-3 border-gray-200"/> <h3 class="text-xs font-semibold text-gray-400 uppercase mb-2">Room Templates</h3> <p class="text-xs text-gray-400 mb-3">Pre-furnished rooms — walls + furniture in one click</p> <div class="grid grid-cols-2 gap-2"></div></div>`);
58019
- var root_16$2 = /* @__PURE__ */ from_html(`<button class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 w-5 h-5 flex items-center justify-center rounded-full hover:bg-gray-100" title="Clear search"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>`);
58068
+ var root_16$1 = /* @__PURE__ */ from_html(`<button class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 w-5 h-5 flex items-center justify-center rounded-full hover:bg-gray-100" title="Clear search"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>`);
58020
58069
  var root_17$1 = /* @__PURE__ */ from_html(`<div class="text-[10px] text-gray-400 px-1"> </div>`);
58021
58070
  var root_18$2 = /* @__PURE__ */ from_html(`<button> </button>`);
58022
58071
  var root_20$2 = /* @__PURE__ */ from_html(`<button draggable="true"><span role="button" tabindex="0"> </span> <div class="w-8 h-8 rounded-lg flex items-center justify-center"><div class="w-4 h-4 rounded-sm"></div></div> <span class="text-[10px] font-medium text-gray-600 leading-tight text-center"> </span></button>`);
@@ -58024,8 +58073,8 @@ var root_19$2 = /* @__PURE__ */ from_html(`<div class="mt-1"><h4 class="text-[10
58024
58073
  var root_22$2 = /* @__PURE__ */ from_html(`<span class="text-xs font-medium text-gray-600"> <mark class="bg-yellow-200 text-gray-800 rounded-sm px-0.5"> </mark> </span>`);
58025
58074
  var root_23$2 = /* @__PURE__ */ from_html(`<span class="text-xs font-medium text-gray-600"> </span>`);
58026
58075
  var root_21$2 = /* @__PURE__ */ from_html(`<button draggable="true"><span role="button" tabindex="0"> </span> <div class="w-10 h-10 rounded-lg flex items-center justify-center"><div class="w-5 h-5 rounded-sm"></div></div> <!> <span class="text-[10px] text-gray-400"> </span></button>`);
58027
- var root_15$1 = /* @__PURE__ */ from_html(`<div class="space-y-2"><div class="relative"><input type="text" placeholder="Search furniture..." class="w-full px-3 py-2 pr-8 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-200 focus:border-blue-400 outline-none"/> <!></div> <!> <div class="flex flex-wrap gap-1 max-h-24 overflow-y-auto"><button>All</button> <button> </button> <!></div> <!> <div class="grid grid-cols-2 gap-2 mt-2"></div></div>`);
58028
- var root_24$1 = /* @__PURE__ */ from_html(`<div class="fixed z-50 pointer-events-none"><div class="bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden" style="width: 220px;"><div class="w-full h-[120px] bg-gray-50 flex items-center justify-center p-3"><div class="w-16 h-16 rounded-xl flex items-center justify-center"><div class="w-10 h-10 rounded-md"></div></div></div> <div class="p-3 space-y-1.5"><div class="flex items-center gap-2"><span class="text-sm font-semibold text-gray-800"> </span> <span class="px-1.5 py-0.5 rounded-full text-[9px] font-semibold text-white"> </span></div> <div class="text-xs text-gray-500"> </div></div></div></div>`);
58076
+ var root_15$2 = /* @__PURE__ */ from_html(`<div class="space-y-2"><div class="relative"><input type="text" placeholder="Search furniture..." class="w-full px-3 py-2 pr-8 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-200 focus:border-blue-400 outline-none"/> <!></div> <!> <div class="flex flex-wrap gap-1 max-h-24 overflow-y-auto"><button>All</button> <button> </button> <!></div> <!> <div class="grid grid-cols-2 gap-2 mt-2"></div></div>`);
58077
+ var root_24$2 = /* @__PURE__ */ from_html(`<div class="fixed z-50 pointer-events-none"><div class="bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden" style="width: 220px;"><div class="w-full h-[120px] bg-gray-50 flex items-center justify-center p-3"><div class="w-16 h-16 rounded-xl flex items-center justify-center"><div class="w-10 h-10 rounded-md"></div></div></div> <div class="p-3 space-y-1.5"><div class="flex items-center gap-2"><span class="text-sm font-semibold text-gray-800"> </span> <span class="px-1.5 py-0.5 rounded-full text-[9px] font-semibold text-white"> </span></div> <div class="text-xs text-gray-500"> </div></div></div></div>`);
58029
58078
  var root_25 = /* @__PURE__ */ from_html(`<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center"><div class="bg-white rounded-xl shadow-2xl w-80 p-5"><h3 class="text-sm font-bold text-gray-800 mb-1">Import RoomPlan</h3> <p class="text-xs text-gray-400 mb-4"> </p> <div class="space-y-3"><label class="flex items-start gap-2.5 cursor-pointer"><input type="checkbox" class="accent-blue-500 mt-0.5"/> <div><div class="text-sm font-medium text-gray-700">Straighten walls</div> <div class="text-xs text-gray-400">Snap near-horizontal/vertical walls to axis</div></div></label> <label class="flex items-start gap-2.5 cursor-pointer"><input type="checkbox" class="accent-blue-500 mt-0.5"/> <div><div class="text-sm font-medium text-gray-700">Enforce orthogonal <span class="text-xs text-blue-400 font-mono"> </span></div> <div class="text-xs text-gray-400">Force all walls to 90°/180° angles</div></div></label> <label class="block"><div class="text-xs text-gray-500 mb-1">Corner merge distance (cm)</div> <input type="number" min="0" max="50" step="5" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label></div> <div class="flex gap-2 mt-5"><button class="flex-1 px-3 py-2 border border-gray-200 rounded-lg text-sm text-gray-600 hover:bg-gray-50 transition-colors">Cancel</button> <button class="flex-1 px-3 py-2 bg-blue-500 text-white rounded-lg text-sm font-medium hover:bg-blue-600 transition-colors">Import</button></div></div></div>`);
58030
58079
  var root$4 = /* @__PURE__ */ from_html(`<div class="relative w-64 bg-white border-r border-gray-200 flex flex-col h-full overflow-hidden"><div class="flex border-b border-gray-200"><button>Build</button> <button>Rooms</button> <button>Objects</button></div> <div class="flex-1 overflow-y-auto p-3"><!></div> <button title="Layers Panel (L)" aria-label="Toggle Layers Panel">🗂</button> <button title="Undo History" aria-label="Toggle Undo History">⟲</button> <button class="absolute bottom-4 left-4 w-8 h-8 rounded-full bg-slate-700 text-white text-sm font-bold shadow-lg hover:bg-slate-600 transition-colors z-50" title="Keyboard Shortcuts (?)" aria-label="Keyboard Shortcuts">?</button></div> <!> <!>`, 1);
58031
58080
  function BuildPanel($$anchor, $$props) {
@@ -58488,7 +58537,7 @@ function BuildPanel($$anchor, $$props) {
58488
58537
  var div_16 = root_5$4();
58489
58538
  var div_17 = sibling(child(div_16), 4);
58490
58539
  each(div_17, 21, () => roomPresets, index$1, ($$anchor, preset) => {
58491
- var button_16 = root_6$4();
58540
+ var button_16 = root_6$3();
58492
58541
  var div_18 = child(button_16);
58493
58542
  var text_6 = child(div_18, true);
58494
58543
  reset(div_18);
@@ -58511,7 +58560,7 @@ function BuildPanel($$anchor, $$props) {
58511
58560
  reset(div_17);
58512
58561
  var div_19 = sibling(div_17, 8);
58513
58562
  each(div_19, 21, () => roomTemplates, index$1, ($$anchor, tmpl) => {
58514
- var button_17 = root_7$3();
58563
+ var button_17 = root_7$4();
58515
58564
  var div_20 = child(button_17);
58516
58565
  var node_2 = child(div_20);
58517
58566
  var consequent_2 = ($$anchor) => {
@@ -58570,13 +58619,13 @@ function BuildPanel($$anchor, $$props) {
58570
58619
  append($$anchor, div_16);
58571
58620
  };
58572
58621
  var consequent_13 = ($$anchor) => {
58573
- var div_21 = root_15$1();
58622
+ var div_21 = root_15$2();
58574
58623
  var div_22 = child(div_21);
58575
58624
  var input_1 = child(div_22);
58576
58625
  remove_input_defaults(input_1);
58577
58626
  var node_3 = sibling(input_1, 2);
58578
58627
  var consequent_9 = ($$anchor) => {
58579
- var button_18 = root_16$2();
58628
+ var button_18 = root_16$1();
58580
58629
  delegated("click", button_18, () => set(search, ""));
58581
58630
  append($$anchor, button_18);
58582
58631
  };
@@ -58788,7 +58837,7 @@ function BuildPanel($$anchor, $$props) {
58788
58837
  var node_8 = sibling(div, 2);
58789
58838
  var consequent_14 = ($$anchor) => {
58790
58839
  const item = /* @__PURE__ */ user_derived(() => get(hoveredItem));
58791
- var div_32 = root_24$1();
58840
+ var div_32 = root_24$2();
58792
58841
  var div_33 = child(div_32);
58793
58842
  var div_34 = child(div_33);
58794
58843
  var div_35 = child(div_34);
@@ -59153,8 +59202,8 @@ init_client();
59153
59202
  var root_3$6 = /* @__PURE__ */ from_html(`<button></button>`);
59154
59203
  var root_4$5 = /* @__PURE__ */ from_html(`<button><span class="bg-white/80 backdrop-blur-sm rounded px-1 py-0.5 mb-0.5 text-gray-700"> </span></button>`);
59155
59204
  var root_2$6 = /* @__PURE__ */ from_html(`<div class="space-y-2"><span class="text-xs text-gray-500">Color</span> <div class="grid grid-cols-6 gap-1.5"></div> <label class="flex items-center gap-2"><span class="text-xs text-gray-500">Custom:</span> <input type="color" class="w-8 h-6 rounded border border-gray-200 cursor-pointer"/></label> <span class="text-xs text-gray-500">Texture</span> <div class="grid grid-cols-3 gap-1.5"><button>None</button> <!></div></div>`);
59156
- var root_6$3 = /* @__PURE__ */ from_html(`<button></button>`);
59157
- var root_7$2 = /* @__PURE__ */ from_html(`<button><span class="bg-white/80 backdrop-blur-sm rounded px-1 py-0.5 mb-0.5 text-gray-700"> </span></button>`);
59205
+ var root_6$2 = /* @__PURE__ */ from_html(`<button></button>`);
59206
+ var root_7$3 = /* @__PURE__ */ from_html(`<button><span class="bg-white/80 backdrop-blur-sm rounded px-1 py-0.5 mb-0.5 text-gray-700"> </span></button>`);
59158
59207
  var root_5$3 = /* @__PURE__ */ from_html(`<div class="space-y-2"><span class="text-xs text-gray-500">Color</span> <div class="grid grid-cols-6 gap-1.5"></div> <label class="flex items-center gap-2"><span class="text-xs text-gray-500">Custom:</span> <input type="color" class="w-8 h-6 rounded border border-gray-200 cursor-pointer"/></label> <span class="text-xs text-gray-500">Texture</span> <div class="grid grid-cols-3 gap-1.5"><button>None</button> <!></div></div>`);
59159
59208
  var root_1$7 = /* @__PURE__ */ from_html(`<h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-gray-200 rounded flex items-center justify-center text-xs">▭</span> Wall Properties</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" disabled="" class="w-full px-2 py-1 border border-gray-200 rounded text-sm bg-gray-50"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <div class="flex items-center gap-2"><span class="text-xs text-gray-500">Curved</span> <button> </button></div> <div><div class="flex border-b border-gray-200 mb-3"><button>Interior</button> <button>Exterior</button></div> <!></div></div>`, 1);
59160
59209
  var root_8$1 = /* @__PURE__ */ from_html(`<h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-amber-100 rounded flex items-center justify-center text-xs">🚪</span> Door Properties</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" min="1" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Type</span> <select class="w-full px-2 py-1 border border-gray-200 rounded text-sm"><option>Single</option><option>Double</option><option>Sliding</option><option>French</option><option>Pocket</option><option>Bifold</option></select></label> <label class="block"><span class="text-xs text-gray-500">Hinge Side</span> <div class="flex gap-2"><button>Left</button> <button>Right</button></div></label> <label class="block"><span class="text-xs text-gray-500">Opens</span> <div class="flex gap-2"><button>Inward</button> <button>Outward</button></div></label></div>`, 1);
@@ -59163,16 +59212,16 @@ var root_11$1 = /* @__PURE__ */ from_html(`<label class="block"><span class="tex
59163
59212
  var root_12$1 = /* @__PURE__ */ from_html(`<button></button>`);
59164
59213
  var root_10$1 = /* @__PURE__ */ from_html(`<h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-purple-100 rounded flex items-center justify-center text-xs"> </span> <button> </button></h3> <div class="space-y-3"><!> <div><div class="flex items-center gap-1 mb-2"><span class="text-xs text-gray-500">Color</span> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-gray-400"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path></svg></div> <div class="grid grid-cols-5 gap-1.5 mb-2"></div> <div class="flex items-center gap-2"><span class="text-xs text-gray-500">Custom:</span> <input type="color" class="w-8 h-6 rounded border border-gray-200 cursor-pointer"/></div></div> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" min="1" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" min="1" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" min="1" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Material</span> <select class="w-full px-2 py-1 border border-gray-200 rounded text-sm"><option>Wood</option><option>Metal</option><option>Fabric</option><option>Leather</option><option>Glass</option><option>Plastic</option><option>Stone</option><option>Ceramic</option></select></label> <label class="block"><span class="text-xs text-gray-500">Rotation (degrees)</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <div class="flex gap-1"><button class="flex-1 px-2 py-1.5 border border-gray-200 rounded text-sm hover:bg-gray-50 transition-colors" title="Rotate 90° left">↺ 90°</button> <button class="flex-1 px-2 py-1.5 border border-gray-200 rounded text-sm hover:bg-gray-50 transition-colors" title="Rotate 90° right">↻ 90°</button></div> <div class="flex gap-1"><button class="flex-1 px-2 py-1.5 border border-gray-200 rounded text-sm hover:bg-gray-50 transition-colors" title="Flip horizontally">↔ Flip H</button> <button class="flex-1 px-2 py-1.5 border border-gray-200 rounded text-sm hover:bg-gray-50 transition-colors" title="Flip vertically">↕ Flip V</button></div> <button class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm text-gray-600 hover:bg-gray-50 transition-colors">Reset to defaults</button></div>`, 1);
59165
59214
  var root_14$1 = /* @__PURE__ */ from_html(`<option> </option>`);
59166
- var root_15 = /* @__PURE__ */ from_html(`<button></button>`);
59215
+ var root_15$1 = /* @__PURE__ */ from_html(`<button></button>`);
59167
59216
  var root_18$1 = /* @__PURE__ */ from_html(`<button><div class="w-full h-12 rounded-md mb-1 overflow-hidden"></div> <div class="text-center leading-3 text-[10px] text-gray-600 truncate"> </div></button>`);
59168
- var root_16$1 = /* @__PURE__ */ from_html(`<div><span class="text-xs font-medium text-gray-600 mb-1.5 block"> </span> <div class="grid grid-cols-3 gap-1.5"></div></div>`);
59217
+ var root_16 = /* @__PURE__ */ from_html(`<div><span class="text-xs font-medium text-gray-600 mb-1.5 block"> </span> <div class="grid grid-cols-3 gap-1.5"></div></div>`);
59169
59218
  var root_13$1 = /* @__PURE__ */ from_html(`<h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-green-100 rounded flex items-center justify-center text-xs">⬜</span> Room Properties</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500">Room Type</span> <select class="w-full px-2 py-1 border border-gray-200 rounded text-sm"></select></label> <label class="block"><span class="text-xs text-gray-500">Room Name</span> <input type="text" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Category</span> <select class="w-full px-2 py-1 border border-gray-200 rounded text-sm"><option>🏠 Indoor</option><option>🌳 Outdoor</option><option>🚗 Garage</option><option>🔧 Utility</option></select></label> <div><span class="text-xs text-gray-500">Area</span> <p class="text-sm text-gray-700"> </p></div> <div><span class="text-xs text-gray-500 mb-1.5 block">Room Color</span> <div class="grid grid-cols-5 gap-1.5 mb-2"></div> <div class="flex items-center gap-2"><span class="text-xs text-gray-500">Custom:</span> <input type="color" class="w-8 h-6 rounded border border-gray-200 cursor-pointer"/></div></div> <div><div class="flex items-center gap-1 mb-2"><span class="text-xs text-gray-500">Floor Material</span> <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="text-gray-400"><path d="M3 3h18v18H3z"></path><path d="M8 8h8v8H8z"></path></svg></div> <div class="space-y-3"></div></div></div>`, 1);
59170
59219
  var root_19$1 = /* @__PURE__ */ from_html(`<h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-gray-200 rounded flex items-center justify-center text-xs">🪜</span> Stair Properties</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500">Type</span> <select class="w-full px-2 py-1 border border-gray-200 rounded text-sm"><option>Straight</option><option>L-Shaped</option><option>U-Shaped</option><option>Spiral</option></select></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Risers</span> <input type="number" min="3" max="30" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Direction</span> <div class="flex gap-2"><button>Up ↑</button> <button>Down ↓</button></div></label> <label class="block"><span class="text-xs text-gray-500">Rotation (degrees)</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label></div>`, 1);
59171
59220
  var root_21$1 = /* @__PURE__ */ from_html(`<button></button>`);
59172
59221
  var root_22$1 = /* @__PURE__ */ from_html(`<label class="block"><span class="text-xs text-gray-500">Rotation (degrees)</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label>`);
59173
59222
  var root_20$1 = /* @__PURE__ */ from_html(`<h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-gray-200 rounded flex items-center justify-center text-xs">🏛️</span> Column Properties</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500">Shape</span> <div class="flex gap-2"><button>⭕ Round</button> <button>⬜ Square</button></div></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" min="10" max="200" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500"> </span> <input type="number" min="50" max="1000" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <div><span class="text-xs text-gray-500 mb-1.5 block">Color</span> <div class="grid grid-cols-5 gap-1.5 mb-2"></div> <div class="flex items-center gap-2"><span class="text-xs text-gray-500">Custom:</span> <input type="color" class="w-8 h-6 rounded border border-gray-200 cursor-pointer"/></div></div> <!></div>`, 1);
59174
59223
  var root_23$1 = /* @__PURE__ */ from_html(`<div class="space-y-3"><h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-emerald-100 rounded flex items-center justify-center text-xs">🏷️</span> Text Annotation</h3> <label class="block"><span class="text-xs text-gray-500">Text</span> <input type="text" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Font Size</span> <input type="number" min="8" max="72" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Color</span> <div class="flex items-center gap-2"><input type="color" class="w-8 h-6 rounded border border-gray-200 cursor-pointer"/> <span class="text-xs text-gray-400"> </span></div></label> <label class="block"><span class="text-xs text-gray-500">Rotation (°)</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">X</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <label class="block"><span class="text-xs text-gray-500">Y</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label></div>`);
59175
- var root_24 = /* @__PURE__ */ from_html(`<div class="mt-4 pt-3 border-t border-gray-200"><h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-blue-100 rounded flex items-center justify-center text-xs">🖼️</span> Background Image</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500">Opacity</span> <input type="range" min="0.05" max="1" step="0.05" class="w-full"/></label> <label class="block"><span class="text-xs text-gray-500">Scale</span> <input type="range" min="0.1" max="5" step="0.05" class="w-full"/></label> <label class="block"><span class="text-xs text-gray-500">Rotation</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <div class="flex gap-2"><button> </button> <button class="flex-1 px-2 py-1.5 border rounded text-sm border-gray-200 hover:bg-gray-50">📏 Set Scale</button></div> <button class="w-full px-2 py-1.5 border border-red-300 rounded text-sm text-red-600 hover:bg-red-50">Remove Image</button></div></div>`);
59224
+ var root_24$1 = /* @__PURE__ */ from_html(`<div class="mt-4 pt-3 border-t border-gray-200"><h3 class="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2"><span class="w-6 h-6 bg-blue-100 rounded flex items-center justify-center text-xs">🖼️</span> Background Image</h3> <div class="space-y-3"><label class="block"><span class="text-xs text-gray-500">Opacity</span> <input type="range" min="0.05" max="1" step="0.05" class="w-full"/></label> <label class="block"><span class="text-xs text-gray-500">Scale</span> <input type="range" min="0.1" max="5" step="0.05" class="w-full"/></label> <label class="block"><span class="text-xs text-gray-500">Rotation</span> <input type="number" class="w-full px-2 py-1 border border-gray-200 rounded text-sm"/></label> <div class="flex gap-2"><button> </button> <button class="flex-1 px-2 py-1.5 border rounded text-sm border-gray-200 hover:bg-gray-50">📏 Set Scale</button></div> <button class="w-full px-2 py-1.5 border border-red-300 rounded text-sm text-red-600 hover:bg-red-50">Remove Image</button></div></div>`);
59176
59225
  var root$3 = /* @__PURE__ */ from_html(`<div style="top: 48px; bottom: 36px;"><!> <!></div>`);
59177
59226
  function PropertiesPanel($$anchor, $$props) {
59178
59227
  push($$props, true);
@@ -59724,7 +59773,7 @@ function PropertiesPanel($$anchor, $$props) {
59724
59773
  var div_8 = root_5$3();
59725
59774
  var div_9 = sibling(child(div_8), 2);
59726
59775
  each(div_9, 21, () => wallColors, index$1, ($$anchor, wc) => {
59727
- var button_6 = root_6$3();
59776
+ var button_6 = root_6$2();
59728
59777
  template_effect(() => {
59729
59778
  var _$$get$color2;
59730
59779
  set_class(button_6, 1, `w-7 h-7 rounded-md border-2 hover:border-gray-300 transition-colors ${get(sideColor) === get(wc).color ? "border-blue-500 ring-1 ring-blue-200" : "border-gray-200"}`);
@@ -59755,7 +59804,7 @@ function PropertiesPanel($$anchor, $$props) {
59755
59804
  "subway-tile": images.subwayTile
59756
59805
  }[get(wc).id]) !== null && _redBrick$exposedBr2 !== void 0 ? _redBrick$exposedBr2 : "";
59757
59806
  });
59758
- var button_8 = root_7$2();
59807
+ var button_8 = root_7$3();
59759
59808
  var span_4 = child(button_8);
59760
59809
  var text_5 = child(span_4, true);
59761
59810
  reset(span_4);
@@ -60296,7 +60345,7 @@ function PropertiesPanel($$anchor, $$props) {
60296
60345
  var div_23 = sibling(div_22, 2);
60297
60346
  var div_24 = sibling(child(div_23), 2);
60298
60347
  each(div_24, 21, () => roomColorPresets, index$1, ($$anchor, preset) => {
60299
- var button_20 = root_15();
60348
+ var button_20 = root_15$1();
60300
60349
  template_effect(() => {
60301
60350
  var _$$get$color5;
60302
60351
  set_class(button_20, 1, `w-7 h-7 rounded-md border-2 hover:border-gray-300 transition-colors ${get(selectedRoom).color === get(preset).color ? "border-blue-500 ring-1 ring-blue-200" : "border-gray-200"}`);
@@ -60315,7 +60364,7 @@ function PropertiesPanel($$anchor, $$props) {
60315
60364
  var div_26 = sibling(div_23, 2);
60316
60365
  var div_27 = sibling(child(div_26), 2);
60317
60366
  each(div_27, 21, () => textureGroups, index$1, ($$anchor, group) => {
60318
- var div_28 = root_16$1();
60367
+ var div_28 = root_16();
60319
60368
  var span_18 = child(div_28);
60320
60369
  var text_23 = child(span_18, true);
60321
60370
  reset(span_18);
@@ -60595,7 +60644,7 @@ function PropertiesPanel($$anchor, $$props) {
60595
60644
  });
60596
60645
  var node_7 = sibling(node, 2);
60597
60646
  var consequent_12 = ($$anchor) => {
60598
- var div_41 = root_24();
60647
+ var div_41 = root_24$1();
60599
60648
  var div_42 = sibling(child(div_41), 2);
60600
60649
  var label_44 = child(div_42);
60601
60650
  var input_37 = sibling(child(label_44), 2);
@@ -61948,8 +61997,17 @@ function drawFurnitureIcon(ctx, catalogId, w, d, color, strokeColor, heatmapMatr
61948
61997
  }
61949
61998
  //#endregion
61950
61999
  //#region src/lib/utils/shortcuts.ts
62000
+ /** True when the user is typing in a form field — canvas shortcuts should not run. */
62001
+ function isEditableTarget(e) {
62002
+ const el = e.target;
62003
+ if (!el) return false;
62004
+ const tag = el.tagName;
62005
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
62006
+ if (el.isContentEditable) return true;
62007
+ return !!el.closest("[contenteditable=\"true\"]");
62008
+ }
61951
62009
  function handleGlobalShortcut(e, ctx = {}) {
61952
- var _e$target;
62010
+ if (isEditableTarget(e)) return false;
61953
62011
  const mod = e.metaKey || e.ctrlKey;
61954
62012
  if (mod && e.key === "z" && !e.shiftKey) {
61955
62013
  e.preventDefault();
@@ -61970,8 +62028,6 @@ function handleGlobalShortcut(e, ctx = {}) {
61970
62028
  }
61971
62029
  return true;
61972
62030
  }
61973
- const tag = (_e$target = e.target) === null || _e$target === void 0 ? void 0 : _e$target.tagName;
61974
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return false;
61975
62031
  if (e.key === "Escape") {
61976
62032
  selectedTool.set("select");
61977
62033
  selectedElementId.set(null);
@@ -62040,8 +62096,8 @@ var root_2$4 = /* @__PURE__ */ from_html(`<button class="ctx-item svelte-wxo1tu"
62040
62096
  var root_3$4 = /* @__PURE__ */ from_html(`<button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">✂️</span> Split Wall</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">〰️</span> </button> <div class="ctx-sep svelte-wxo1tu"></div> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">⚙️</span> Properties</button> <div class="ctx-sep svelte-wxo1tu"></div> <button class="ctx-item ctx-danger svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🗑️</span> Delete Wall</button>`, 1);
62041
62097
  var root_4$3 = /* @__PURE__ */ from_html(`<button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">⚙️</span> Properties</button> <div class="ctx-sep svelte-wxo1tu"></div> <button class="ctx-item ctx-danger svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🗑️</span> Delete</button>`, 1);
62042
62098
  var root_5$1 = /* @__PURE__ */ from_html(`<button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">✏️</span> Rename Room</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🎨</span> Change Floor Texture</button> <div class="ctx-sep svelte-wxo1tu"></div> <button class="ctx-item ctx-danger svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🗑️</span> Delete Room</button>`, 1);
62043
- var root_7$1 = /* @__PURE__ */ from_html(`<button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">📋</span> Paste</button> <div class="ctx-sep svelte-wxo1tu"></div>`, 1);
62044
- var root_6$2 = /* @__PURE__ */ from_html(`<!> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">⬜</span> Select All</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">📦</span> Group Selected (Ctrl+G)</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">📤</span> Ungroup (Ctrl+Shift+G)</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🧱</span> Add Wall</button> <div class="ctx-sep svelte-wxo1tu"></div> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🔍</span> Zoom to Fit</button>`, 1);
62099
+ var root_7$2 = /* @__PURE__ */ from_html(`<button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">📋</span> Paste</button> <div class="ctx-sep svelte-wxo1tu"></div>`, 1);
62100
+ var root_6$1 = /* @__PURE__ */ from_html(`<!> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">⬜</span> Select All</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">📦</span> Group Selected (Ctrl+G)</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">📤</span> Ungroup (Ctrl+Shift+G)</button> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🧱</span> Add Wall</button> <div class="ctx-sep svelte-wxo1tu"></div> <button class="ctx-item svelte-wxo1tu" role="menuitem"><span class="ctx-icon svelte-wxo1tu">🔍</span> Zoom to Fit</button>`, 1);
62045
62101
  var root_1$5 = /* @__PURE__ */ from_html(`<div class="fixed z-[9999] bg-white border border-gray-200 rounded-lg shadow-xl py-1 min-w-[180px] text-sm select-none" role="menu"><!></div>`);
62046
62102
  function ContextMenu($$anchor, $$props) {
62047
62103
  push($$props, true);
@@ -62150,10 +62206,10 @@ function ContextMenu($$anchor, $$props) {
62150
62206
  append($$anchor, fragment_4);
62151
62207
  };
62152
62208
  var consequent_5 = ($$anchor) => {
62153
- var fragment_5 = root_6$2();
62209
+ var fragment_5 = root_6$1();
62154
62210
  var node_2 = first_child(fragment_5);
62155
62211
  var consequent_4 = ($$anchor) => {
62156
- var fragment_6 = root_7$1();
62212
+ var fragment_6 = root_7$2();
62157
62213
  var button_17 = first_child(fragment_6);
62158
62214
  next(2);
62159
62215
  delegated("click", button_17, () => clickItem("paste"));
@@ -63356,7 +63412,7 @@ function drawWindowDistanceDimensions(cs, wall, window, dimSettings) {
63356
63412
  }
63357
63413
  }
63358
63414
  function drawFurnitureItem(cs, item, selected, options) {
63359
- var _item$scale$x, _item$scale, _item$scale$y, _item$scale2, _item$width, _item$depth, _options$showCameraCo, _options$showCameraLa, _item$color;
63415
+ var _item$scale$x, _item$scale, _item$scale$y, _item$scale2, _item$width, _item$depth, _options$showCameraCo, _options$showCameraLa, _options$cameraHeatma, _item$color;
63360
63416
  const { ctx, zoom } = cs;
63361
63417
  const cat = getCatalogItem(item.catalogId);
63362
63418
  if (!cat) return;
@@ -63370,6 +63426,9 @@ function drawFurnitureItem(cs, item, selected, options) {
63370
63426
  const showCameraCones = (_options$showCameraCo = options === null || options === void 0 ? void 0 : options.showCameraCones) !== null && _options$showCameraCo !== void 0 ? _options$showCameraCo : false;
63371
63427
  const showCameraLabels = (_options$showCameraLa = options === null || options === void 0 ? void 0 : options.showCameraLabels) !== null && _options$showCameraLa !== void 0 ? _options$showCameraLa : true;
63372
63428
  const isCamera = item.catalogId === "camera";
63429
+ const useConfigHeatmap = isCamera && highlighted && !!(options === null || options === void 0 || (_options$cameraHeatma = options.cameraHeatmapMatrix) === null || _options$cameraHeatma === void 0 ? void 0 : _options$cameraHeatma.length);
63430
+ const drawHeatmapMatrix = useConfigHeatmap ? options.cameraHeatmapMatrix : item.heatmapMatrix;
63431
+ const drawShowHeatmap = item.showHeatmap || useConfigHeatmap;
63373
63432
  ctx.save();
63374
63433
  ctx.translate(s.x, s.y);
63375
63434
  ctx.rotate(angle);
@@ -63377,7 +63436,7 @@ function drawFurnitureItem(cs, item, selected, options) {
63377
63436
  const itemColor = (_item$color = item.color) !== null && _item$color !== void 0 ? _item$color : cat.color;
63378
63437
  const strokeColor = selected ? "#3b82f6" : itemColor;
63379
63438
  ctx.lineWidth = selected ? 2 : 1;
63380
- drawFurnitureIcon(ctx, item.catalogId, w, d, itemColor, strokeColor, item.heatmapMatrix, item.hasPerson, item.showHeatmap, isCamera ? showCameraCones : false, isCamera ? highlighted : false);
63439
+ drawFurnitureIcon(ctx, item.catalogId, w, d, itemColor, strokeColor, drawHeatmapMatrix, item.hasPerson, drawShowHeatmap, isCamera ? showCameraCones : false, isCamera ? highlighted : false);
63381
63440
  const fontSize = Math.max(8, Math.min(12, Math.min(w, d) * .2));
63382
63441
  if (showCameraLabels && Math.min(w, d) > 20) {
63383
63442
  var _item$name;
@@ -64561,32 +64620,33 @@ var root_1$4 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-2 z-10
64561
64620
  var root_3$3 = /* @__PURE__ */ from_html(`<input type="text" class="absolute bg-white border-2 border-blue-500 rounded px-2 py-1 text-sm text-center shadow-lg outline-none"/>`);
64562
64621
  var root_4$2 = /* @__PURE__ */ from_html(`<input type="text" class="absolute bg-white border-2 border-blue-500 rounded px-2 py-1 text-sm text-center shadow-lg outline-none"/>`);
64563
64622
  var root_5 = /* @__PURE__ */ from_html(`<div class="absolute inset-0 flex items-center justify-center pointer-events-none"><div class="text-center opacity-60"><div class="text-5xl mb-3">🏠</div> <div class="text-sm font-medium text-gray-500">Start building your floor plan</div> <div class="text-xs text-gray-400 mt-1">Draw walls with <span class="font-mono bg-gray-100 px-1 rounded">W</span> or drag items from the sidebar</div></div></div>`);
64564
- var root_6$1 = /* @__PURE__ */ from_html(`<canvas width="180" height="120" class="absolute bottom-10 right-2 rounded-lg shadow-lg border border-gray-300 cursor-crosshair bg-white" style="z-index: 15;"></canvas>`);
64565
- var root_7 = /* @__PURE__ */ from_html(`<span> </span> <span> </span> <span class="text-gray-300">|</span>`, 1);
64566
- var root_9 = /* @__PURE__ */ from_html(`<span> </span>`);
64623
+ var root_6 = /* @__PURE__ */ from_html(`<canvas width="180" height="120" class="absolute bottom-10 right-2 rounded-lg shadow-lg border border-gray-300 cursor-crosshair bg-white" style="z-index: 15;"></canvas>`);
64624
+ var root_8 = /* @__PURE__ */ from_html(`<span> </span> <span> </span> <span class="text-gray-300">|</span>`, 1);
64567
64625
  var root_10 = /* @__PURE__ */ from_html(`<span> </span>`);
64568
64626
  var root_11 = /* @__PURE__ */ from_html(`<span> </span>`);
64569
- var root_8 = /* @__PURE__ */ from_html(`<span> </span> <!> <!> <!> <span class="text-gray-300">|</span>`, 1);
64570
- var root_12 = /* @__PURE__ */ from_html(`<span class="text-blue-600 font-medium"> </span> <span class="text-gray-300">|</span>`, 1);
64571
- var root_14 = /* @__PURE__ */ from_html(`<label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span> </span></label>`);
64572
- var root_13 = /* @__PURE__ */ from_html(`<div class="absolute bottom-12 right-2 z-20 bg-white rounded-lg shadow-lg border border-gray-200 p-3 text-xs min-w-[160px]"><div class="font-semibold text-gray-700 mb-2">Layers</div> <!> <hr class="my-1 border-gray-100"/> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Room Labels</span></label> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Dimensions</span></label></div>`);
64573
- var root_17 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Flip swing" aria-label="Flip swing"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 16V4m0 0L3 8m4-4l4 4M17 8v12m0 0l4-4m-4 4l-4-4"></path></svg></button>`);
64574
- var root_18 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Split wall at midpoint" aria-label="Split wall at midpoint"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M4 12h4M16 12h4"></path></svg></button>`);
64575
- var root_16 = /* @__PURE__ */ from_html(`<div class="absolute z-40 flex items-center gap-0.5 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Duplicate" aria-label="Duplicate"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"></path></svg></button> <!> <!> <div class="w-px h-5 bg-gray-200 mx-0.5"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-red-50 text-gray-400 hover:text-red-600" title="Delete" aria-label="Delete"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14"></path></svg></button></div>`);
64576
- var root_19 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-blue-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to add wall segment · Double-click to finish · C to close loop ·
64627
+ var root_12 = /* @__PURE__ */ from_html(`<span> </span>`);
64628
+ var root_9 = /* @__PURE__ */ from_html(`<span> </span> <!> <!> <!> <span class="text-gray-300">|</span>`, 1);
64629
+ var root_13 = /* @__PURE__ */ from_html(`<span class="text-blue-600 font-medium"> </span> <span class="text-gray-300">|</span>`, 1);
64630
+ var root_7$1 = /* @__PURE__ */ from_html(`<div class="absolute bottom-2 right-2 bg-white/80 rounded px-2 py-1 text-xs text-gray-500 flex gap-3"><!> <!> <!> <span> </span> <button class="hover:text-gray-700" title="Zoom to Fit (F)">⊞ Fit</button> <button class="hover:text-gray-700" title="Toggle Grid (G)"> </button> <button class="hover:text-gray-700" title="Toggle Snap to Grid (S)"> </button> <button class="hover:text-gray-700" title="Toggle Furniture"> </button> <button class="hover:text-gray-700" title="Layer Visibility">🗂 Layers</button> <button class="hover:text-gray-700" title="Toggle Rulers"> </button> <button class="hover:text-gray-700" title="Toggle Mini-map"> </button></div>`);
64631
+ var root_15 = /* @__PURE__ */ from_html(`<label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span> </span></label>`);
64632
+ var root_14 = /* @__PURE__ */ from_html(`<div class="absolute bottom-12 right-2 z-20 bg-white rounded-lg shadow-lg border border-gray-200 p-3 text-xs min-w-[160px]"><div class="font-semibold text-gray-700 mb-2">Layers</div> <!> <hr class="my-1 border-gray-100"/> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Room Labels</span></label> <label class="flex items-center gap-2 py-0.5 cursor-pointer hover:bg-gray-50 rounded px-1"><input type="checkbox" class="accent-blue-500"/> <span>Dimensions</span></label></div>`);
64633
+ var root_18 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Flip swing" aria-label="Flip swing"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 16V4m0 0L3 8m4-4l4 4M17 8v12m0 0l4-4m-4 4l-4-4"></path></svg></button>`);
64634
+ var root_19 = /* @__PURE__ */ from_html(`<button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Split wall at midpoint" aria-label="Split wall at midpoint"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M4 12h4M16 12h4"></path></svg></button>`);
64635
+ var root_17 = /* @__PURE__ */ from_html(`<div class="absolute z-40 flex items-center gap-0.5 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700" title="Duplicate" aria-label="Duplicate"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"></path></svg></button> <!> <!> <div class="w-px h-5 bg-gray-200 mx-0.5"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-red-50 text-gray-400 hover:text-red-600" title="Delete" aria-label="Delete"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14"></path></svg></button></div>`);
64636
+ var root_20 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-blue-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to add wall segment · Double-click to finish · C to close loop ·
64577
64637
  Esc to cancel</div>`);
64578
- var root_20 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-purple-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
64579
- var root_21 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-red-600 text-white px-3 py-1 rounded-full text-xs shadow">Right-click two points to measure · M to exit · Esc to cancel</div>`);
64580
- var root_22 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-emerald-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to place text label · Esc to cancel</div>`);
64581
- var root_23 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-indigo-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
64582
- var root_2$3 = /* @__PURE__ */ from_html(`<!> <!> <!> <!> <div class="absolute bottom-2 right-2 bg-white/80 rounded px-2 py-1 text-xs text-gray-500 flex gap-3"><!> <!> <!> <span> </span> <button class="hover:text-gray-700" title="Zoom to Fit (F)">⊞ Fit</button> <button class="hover:text-gray-700" title="Toggle Grid (G)"> </button> <button class="hover:text-gray-700" title="Toggle Snap to Grid (S)"> </button> <button class="hover:text-gray-700" title="Toggle Furniture"> </button> <button class="hover:text-gray-700" title="Layer Visibility">🗂 Layers</button> <button class="hover:text-gray-700" title="Toggle Rulers"> </button> <button class="hover:text-gray-700" title="Toggle Mini-map"> </button></div> <!> <!> <!> <!> <!> <!> <!> <div class="absolute bottom-3 left-3 z-20 flex items-center gap-1 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-600 hover:text-gray-800 font-bold text-lg" title="Zoom Out (−)" aria-label="Zoom out">−</button> <button class="min-w-[3.5rem] h-7 flex items-center justify-center rounded hover:bg-gray-100 text-xs font-medium text-gray-600 hover:text-gray-800 tabular-nums" title="Reset to 100%" aria-label="Zoom to 100%"> </button> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-600 hover:text-gray-800 font-bold text-lg" title="Zoom In (+)" aria-label="Zoom in">+</button> <div class="w-px h-5 bg-gray-200"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700 text-sm" title="Zoom to Fit (F)" aria-label="Zoom to fit">⊞</button></div> <!>`, 1);
64638
+ var root_21 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-purple-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
64639
+ var root_22 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-red-600 text-white px-3 py-1 rounded-full text-xs shadow">Right-click two points to measure · M to exit · Esc to cancel</div>`);
64640
+ var root_23 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-emerald-600 text-white px-3 py-1 rounded-full text-xs shadow">Click to place text label · Esc to cancel</div>`);
64641
+ var root_24 = /* @__PURE__ */ from_html(`<div class="absolute top-2 left-1/2 -translate-x-1/2 bg-indigo-600 text-white px-3 py-1 rounded-full text-xs shadow"> </div>`);
64642
+ var root_2$3 = /* @__PURE__ */ from_html(`<!> <!> <!> <!> <!> <!> <!> <!> <!> <!> <!> <!> <div class="absolute bottom-3 left-3 z-20 flex items-center gap-1 bg-white rounded-lg shadow-lg border border-gray-200 px-1 py-0.5"><button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-600 hover:text-gray-800 font-bold text-lg" title="Zoom Out (−)" aria-label="Zoom out">−</button> <button class="min-w-[3.5rem] h-7 flex items-center justify-center rounded hover:bg-gray-100 text-xs font-medium text-gray-600 hover:text-gray-800 tabular-nums" title="Reset to 100%" aria-label="Zoom to 100%"> </button> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-600 hover:text-gray-800 font-bold text-lg" title="Zoom In (+)" aria-label="Zoom in">+</button> <div class="w-px h-5 bg-gray-200"></div> <button class="w-7 h-7 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700 text-sm" title="Zoom to Fit (F)" aria-label="Zoom to fit">⊞</button></div> <!>`, 1);
64583
64643
  var root$1 = /* @__PURE__ */ from_html(`<div class="w-full h-full relative overflow-hidden" role="application"><div><canvas aria-label="Floor plan editor canvas"></canvas></div> <!> <!></div>`);
64584
64644
  function FloorPlanCanvas($$anchor, $$props) {
64585
64645
  push($$props, true);
64586
64646
  const $panMode = () => store_get(panMode, "$panMode", $$stores);
64587
64647
  const $projectSettings = () => store_get(projectSettings, "$projectSettings", $$stores);
64588
64648
  const [$$stores, $$cleanup] = setup_stores();
64589
- let selectedCameraSerial = prop($$props, "selectedCameraSerial", 3, null), showCameraCones = prop($$props, "showCameraCones", 3, false), showCameraLabels = prop($$props, "showCameraLabels", 3, true);
64649
+ let selectedCameraSerial = prop($$props, "selectedCameraSerial", 3, null), showCameraCones = prop($$props, "showCameraCones", 3, false), showCameraLabels = prop($$props, "showCameraLabels", 3, true), cameraHeatmapMatrix = prop($$props, "cameraHeatmapMatrix", 19, () => []);
64590
64650
  let canvas;
64591
64651
  let ctx;
64592
64652
  let width = /* @__PURE__ */ state(800);
@@ -64673,11 +64733,18 @@ function FloorPlanCanvas($$anchor, $$props) {
64673
64733
  let showRulers = /* @__PURE__ */ state(true);
64674
64734
  user_effect(() => {
64675
64735
  if ($$props.viewOnly) set(showRulers, false);
64736
+ if ($$props.viewOnly) set(showMinimap, false);
64676
64737
  });
64677
64738
  user_effect(() => {
64739
+ if ($$props.viewOnly) {
64740
+ $$props.floorMaxWidth;
64741
+ $$props.floorMaxHeight;
64742
+ needsFitToCanvas = true;
64743
+ }
64678
64744
  selectedCameraSerial();
64679
64745
  showCameraCones();
64680
64746
  showCameraLabels();
64747
+ cameraHeatmapMatrix();
64681
64748
  $$props.projectName;
64682
64749
  $$props.heatmapEnabled;
64683
64750
  $$props.heatmapMatrix;
@@ -65121,7 +65188,8 @@ function FloorPlanCanvas($$anchor, $$props) {
65121
65188
  drawFurnitureItem(getCS(), item, selected, {
65122
65189
  selectedCameraSerial: selectedCameraSerial(),
65123
65190
  showCameraCones: showCameraCones(),
65124
- showCameraLabels: showCameraLabels()
65191
+ showCameraLabels: showCameraLabels(),
65192
+ cameraHeatmapMatrix: cameraHeatmapMatrix()
65125
65193
  });
65126
65194
  }
65127
65195
  let placementWallSnap = /* @__PURE__ */ state(null);
@@ -65501,6 +65569,49 @@ function FloorPlanCanvas($$anchor, $$props) {
65501
65569
  height
65502
65570
  };
65503
65571
  }
65572
+ function getFloorContentBounds(floor = get(currentFloor)) {
65573
+ if (!floor) return null;
65574
+ let minX = Infinity;
65575
+ let maxX = -Infinity;
65576
+ let minY = Infinity;
65577
+ let maxY = -Infinity;
65578
+ let found = false;
65579
+ const expand = (x, y, pad = 0) => {
65580
+ minX = Math.min(minX, x - pad);
65581
+ maxX = Math.max(maxX, x + pad);
65582
+ minY = Math.min(minY, y - pad);
65583
+ maxY = Math.max(maxY, y + pad);
65584
+ found = true;
65585
+ };
65586
+ for (const wall of floor.walls) {
65587
+ expand(wall.start.x, wall.start.y, wall.thickness / 2);
65588
+ expand(wall.end.x, wall.end.y, wall.thickness / 2);
65589
+ if (wall.curvePoint) expand(wall.curvePoint.x, wall.curvePoint.y, wall.thickness / 2);
65590
+ }
65591
+ for (const item of floor.furniture) {
65592
+ var _item$scale$x, _item$scale, _item$scale$y, _item$scale2, _ref, _item$width, _ref2, _item$depth;
65593
+ const cat = getCatalogItem(item.catalogId);
65594
+ const sx = Math.abs((_item$scale$x = (_item$scale = item.scale) === null || _item$scale === void 0 ? void 0 : _item$scale.x) !== null && _item$scale$x !== void 0 ? _item$scale$x : 1);
65595
+ const sy = Math.abs((_item$scale$y = (_item$scale2 = item.scale) === null || _item$scale2 === void 0 ? void 0 : _item$scale2.y) !== null && _item$scale$y !== void 0 ? _item$scale$y : 1);
65596
+ const w = ((_ref = (_item$width = item.width) !== null && _item$width !== void 0 ? _item$width : cat === null || cat === void 0 ? void 0 : cat.width) !== null && _ref !== void 0 ? _ref : 50) * sx;
65597
+ const d = ((_ref2 = (_item$depth = item.depth) !== null && _item$depth !== void 0 ? _item$depth : cat === null || cat === void 0 ? void 0 : cat.depth) !== null && _ref2 !== void 0 ? _ref2 : 50) * sy;
65598
+ const pad = Math.max(w, d) * .6;
65599
+ if (item.catalogId === "camera") expand(item.position.x, item.position.y, Math.max(w, d) * 6);
65600
+ else expand(item.position.x, item.position.y, pad);
65601
+ }
65602
+ if (!found) return getFloorWallBounds(floor);
65603
+ const width = maxX - minX;
65604
+ const height = maxY - minY;
65605
+ if (width <= 0 || height <= 0) return null;
65606
+ return {
65607
+ minX,
65608
+ minY,
65609
+ maxX,
65610
+ maxY,
65611
+ width,
65612
+ height
65613
+ };
65614
+ }
65504
65615
  function getCanvasFrameStyle() {
65505
65616
  return "width: 100%; height: 100%";
65506
65617
  }
@@ -65513,8 +65624,8 @@ function FloorPlanCanvas($$anchor, $$props) {
65513
65624
  canvasDirty = false;
65514
65625
  ctx.clearRect(0, 0, get(width), get(height));
65515
65626
  ctx.fillStyle = "#f8f9fa";
65516
- ctx.fillRect(0, 0, $$props.viewOnly ? $$props.floorMaxWidth : get(width), $$props.viewOnly ? $$props.floorMaxHeight : get(height));
65517
- drawGrid();
65627
+ ctx.fillRect(0, 0, get(width), get(height));
65628
+ if (!$$props.viewOnly) drawGrid();
65518
65629
  if (!$$props.viewOnly && get(layerVis).guides) drawGuides$1();
65519
65630
  drawBackgroundImage();
65520
65631
  const floor = get(currentFloor);
@@ -67488,7 +67599,7 @@ function FloorPlanCanvas($$anchor, $$props) {
67488
67599
  set(zoom, 1);
67489
67600
  return;
67490
67601
  }
67491
- const bounds = getFloorWallBounds(get(currentFloor));
67602
+ const bounds = $$props.viewOnly ? getFloorContentBounds(get(currentFloor)) : getFloorWallBounds(get(currentFloor));
67492
67603
  if (!bounds) {
67493
67604
  set(camX, 0);
67494
67605
  set(camY, 0);
@@ -67505,12 +67616,13 @@ function FloorPlanCanvas($$anchor, $$props) {
67505
67616
  canvas.height = get(height);
67506
67617
  }
67507
67618
  }
67508
- const padding = 0;
67619
+ const padding = $$props.viewOnly ? 24 : 0;
67509
67620
  const contentW = bounds.width + padding * 2;
67510
67621
  const contentH = bounds.height + padding * 2;
67511
67622
  set(camX, (bounds.minX + bounds.maxX) / 2);
67512
67623
  set(camY, (bounds.minY + bounds.maxY) / 2);
67513
- set(zoom, Math.max(get(width) / contentW, get(height) / contentH), true);
67624
+ if ($$props.viewOnly) set(zoom, Math.min(get(width) / contentW, get(height) / contentH), true);
67625
+ else set(zoom, Math.max(get(width) / contentW, get(height) / contentH), true);
67514
67626
  set(zoom, Math.max(get(zoom), .1), true);
67515
67627
  markDirty();
67516
67628
  }
@@ -68505,6 +68617,7 @@ function FloorPlanCanvas($$anchor, $$props) {
68505
68617
  }
68506
68618
  function onKeyDown(e) {
68507
68619
  if ($$props.viewOnly) return;
68620
+ if (isEditableTarget(e)) return;
68508
68621
  set(shiftDown, e.shiftKey, true);
68509
68622
  if (e.code === "Space") {
68510
68623
  set(spaceDown, true);
@@ -69051,7 +69164,7 @@ function FloorPlanCanvas($$anchor, $$props) {
69051
69164
  if ($$props.viewOnly && $$props.projectName) $$render(consequent);
69052
69165
  });
69053
69166
  var node_1 = sibling(node, 2);
69054
- var consequent_21 = ($$anchor) => {
69167
+ var consequent_22 = ($$anchor) => {
69055
69168
  var fragment = root_2$3();
69056
69169
  var node_2 = first_child(fragment);
69057
69170
  var consequent_1 = ($$anchor) => {
@@ -69152,136 +69265,163 @@ function FloorPlanCanvas($$anchor, $$props) {
69152
69265
  });
69153
69266
  var node_5 = sibling(node_4, 2);
69154
69267
  var consequent_4 = ($$anchor) => {
69155
- var canvas_2 = root_6$1();
69268
+ var canvas_2 = root_6();
69156
69269
  bind_this(canvas_2, ($$value) => minimapCanvas = $$value, () => minimapCanvas);
69157
69270
  delegated("click", canvas_2, onMinimapClick);
69158
69271
  append($$anchor, canvas_2);
69159
69272
  };
69160
69273
  if_block(node_5, ($$render) => {
69161
- if (get(showMinimap) && get(currentFloor) && get(currentFloor).walls.length > 0) $$render(consequent_4);
69162
- });
69163
- var div_4 = sibling(node_5, 2);
69164
- var node_6 = child(div_4);
69165
- var consequent_5 = ($$anchor) => {
69166
- var fragment_1 = root_7();
69167
- var span = first_child(fragment_1);
69168
- var text_2 = child(span);
69169
- reset(span);
69170
- var span_1 = sibling(span, 2);
69171
- var text_3 = child(span_1, true);
69172
- reset(span_1);
69173
- next(2);
69174
- template_effect(($0) => {
69175
- var _$$get$length;
69176
- set_text(text_2, `${(_$$get$length = get(detectedRooms).length) !== null && _$$get$length !== void 0 ? _$$get$length : ""} room${get(detectedRooms).length !== 1 ? "s" : ""}`);
69177
- set_text(text_3, $0);
69178
- }, [() => formatArea(get(detectedRooms).reduce((s, r) => s + r.area, 0), $projectSettings().units)]);
69179
- append($$anchor, fragment_1);
69180
- };
69181
- if_block(node_6, ($$render) => {
69182
- if (get(detectedRooms).length > 0) $$render(consequent_5);
69274
+ if (!$$props.viewOnly && get(showMinimap) && get(currentFloor) && get(currentFloor).walls.length > 0) $$render(consequent_4);
69183
69275
  });
69184
- var node_7 = sibling(node_6, 2);
69185
- var consequent_9 = ($$anchor) => {
69186
- var fragment_2 = root_8();
69187
- var span_2 = first_child(fragment_2);
69188
- var text_4 = child(span_2);
69189
- reset(span_2);
69190
- var node_8 = sibling(span_2, 2);
69191
- var consequent_6 = ($$anchor) => {
69192
- var span_3 = root_9();
69193
- var text_5 = child(span_3);
69194
- reset(span_3);
69195
- template_effect(() => {
69196
- var _$$get$doors$length;
69197
- return set_text(text_5, `${(_$$get$doors$length = get(currentFloor).doors.length) !== null && _$$get$doors$length !== void 0 ? _$$get$doors$length : ""} door${get(currentFloor).doors.length !== 1 ? "s" : ""}`);
69198
- });
69199
- append($$anchor, span_3);
69276
+ var node_6 = sibling(node_5, 2);
69277
+ var consequent_11 = ($$anchor) => {
69278
+ var div_4 = root_7$1();
69279
+ var node_7 = child(div_4);
69280
+ var consequent_5 = ($$anchor) => {
69281
+ var fragment_1 = root_8();
69282
+ var span = first_child(fragment_1);
69283
+ var text_2 = child(span);
69284
+ reset(span);
69285
+ var span_1 = sibling(span, 2);
69286
+ var text_3 = child(span_1, true);
69287
+ reset(span_1);
69288
+ next(2);
69289
+ template_effect(($0) => {
69290
+ var _$$get$length;
69291
+ set_text(text_2, `${(_$$get$length = get(detectedRooms).length) !== null && _$$get$length !== void 0 ? _$$get$length : ""} room${get(detectedRooms).length !== 1 ? "s" : ""}`);
69292
+ set_text(text_3, $0);
69293
+ }, [() => formatArea(get(detectedRooms).reduce((s, r) => s + r.area, 0), $projectSettings().units)]);
69294
+ append($$anchor, fragment_1);
69200
69295
  };
69201
- if_block(node_8, ($$render) => {
69202
- if (get(currentFloor).doors.length > 0) $$render(consequent_6);
69296
+ if_block(node_7, ($$render) => {
69297
+ if (get(detectedRooms).length > 0) $$render(consequent_5);
69203
69298
  });
69204
- var node_9 = sibling(node_8, 2);
69205
- var consequent_7 = ($$anchor) => {
69206
- var span_4 = root_10();
69207
- var text_6 = child(span_4);
69208
- reset(span_4);
69299
+ var node_8 = sibling(node_7, 2);
69300
+ var consequent_9 = ($$anchor) => {
69301
+ var fragment_2 = root_9();
69302
+ var span_2 = first_child(fragment_2);
69303
+ var text_4 = child(span_2);
69304
+ reset(span_2);
69305
+ var node_9 = sibling(span_2, 2);
69306
+ var consequent_6 = ($$anchor) => {
69307
+ var span_3 = root_10();
69308
+ var text_5 = child(span_3);
69309
+ reset(span_3);
69310
+ template_effect(() => {
69311
+ var _$$get$doors$length;
69312
+ return set_text(text_5, `${(_$$get$doors$length = get(currentFloor).doors.length) !== null && _$$get$doors$length !== void 0 ? _$$get$doors$length : ""} door${get(currentFloor).doors.length !== 1 ? "s" : ""}`);
69313
+ });
69314
+ append($$anchor, span_3);
69315
+ };
69316
+ if_block(node_9, ($$render) => {
69317
+ if (get(currentFloor).doors.length > 0) $$render(consequent_6);
69318
+ });
69319
+ var node_10 = sibling(node_9, 2);
69320
+ var consequent_7 = ($$anchor) => {
69321
+ var span_4 = root_11();
69322
+ var text_6 = child(span_4);
69323
+ reset(span_4);
69324
+ template_effect(() => {
69325
+ var _$$get$windows$length;
69326
+ return set_text(text_6, `${(_$$get$windows$length = get(currentFloor).windows.length) !== null && _$$get$windows$length !== void 0 ? _$$get$windows$length : ""} window${get(currentFloor).windows.length !== 1 ? "s" : ""}`);
69327
+ });
69328
+ append($$anchor, span_4);
69329
+ };
69330
+ if_block(node_10, ($$render) => {
69331
+ if (get(currentFloor).windows.length > 0) $$render(consequent_7);
69332
+ });
69333
+ var node_11 = sibling(node_10, 2);
69334
+ var consequent_8 = ($$anchor) => {
69335
+ var span_5 = root_12();
69336
+ var text_7 = child(span_5);
69337
+ reset(span_5);
69338
+ template_effect(() => {
69339
+ var _$$get$furniture$leng;
69340
+ return set_text(text_7, `${(_$$get$furniture$leng = get(currentFloor).furniture.length) !== null && _$$get$furniture$leng !== void 0 ? _$$get$furniture$leng : ""} object${get(currentFloor).furniture.length !== 1 ? "s" : ""}`);
69341
+ });
69342
+ append($$anchor, span_5);
69343
+ };
69344
+ if_block(node_11, ($$render) => {
69345
+ if (get(currentFloor).furniture.length > 0) $$render(consequent_8);
69346
+ });
69347
+ next(2);
69209
69348
  template_effect(() => {
69210
- var _$$get$windows$length;
69211
- return set_text(text_6, `${(_$$get$windows$length = get(currentFloor).windows.length) !== null && _$$get$windows$length !== void 0 ? _$$get$windows$length : ""} window${get(currentFloor).windows.length !== 1 ? "s" : ""}`);
69349
+ var _$$get$walls$length;
69350
+ return set_text(text_4, `${(_$$get$walls$length = get(currentFloor).walls.length) !== null && _$$get$walls$length !== void 0 ? _$$get$walls$length : ""} wall${get(currentFloor).walls.length !== 1 ? "s" : ""}`);
69212
69351
  });
69213
- append($$anchor, span_4);
69352
+ append($$anchor, fragment_2);
69214
69353
  };
69215
- if_block(node_9, ($$render) => {
69216
- if (get(currentFloor).windows.length > 0) $$render(consequent_7);
69354
+ if_block(node_8, ($$render) => {
69355
+ if (get(currentFloor)) $$render(consequent_9);
69217
69356
  });
69218
- var node_10 = sibling(node_9, 2);
69219
- var consequent_8 = ($$anchor) => {
69220
- var span_5 = root_11();
69221
- var text_7 = child(span_5);
69222
- reset(span_5);
69357
+ var node_12 = sibling(node_8, 2);
69358
+ var consequent_10 = ($$anchor) => {
69359
+ var fragment_3 = root_13();
69360
+ var span_6 = first_child(fragment_3);
69361
+ var text_8 = child(span_6);
69362
+ reset(span_6);
69363
+ next(2);
69223
69364
  template_effect(() => {
69224
- var _$$get$furniture$leng;
69225
- return set_text(text_7, `${(_$$get$furniture$leng = get(currentFloor).furniture.length) !== null && _$$get$furniture$leng !== void 0 ? _$$get$furniture$leng : ""} object${get(currentFloor).furniture.length !== 1 ? "s" : ""}`);
69365
+ var _$$get$size;
69366
+ return set_text(text_8, `${(_$$get$size = get(currentSelectedIds).size) !== null && _$$get$size !== void 0 ? _$$get$size : ""} selected`);
69226
69367
  });
69227
- append($$anchor, span_5);
69368
+ append($$anchor, fragment_3);
69228
69369
  };
69229
- if_block(node_10, ($$render) => {
69230
- if (get(currentFloor).furniture.length > 0) $$render(consequent_8);
69370
+ if_block(node_12, ($$render) => {
69371
+ if (get(currentSelectedIds).size > 1) $$render(consequent_10);
69231
69372
  });
69232
- next(2);
69233
- template_effect(() => {
69234
- var _$$get$walls$length;
69235
- return set_text(text_4, `${(_$$get$walls$length = get(currentFloor).walls.length) !== null && _$$get$walls$length !== void 0 ? _$$get$walls$length : ""} wall${get(currentFloor).walls.length !== 1 ? "s" : ""}`);
69236
- });
69237
- append($$anchor, fragment_2);
69238
- };
69239
- if_block(node_7, ($$render) => {
69240
- if (get(currentFloor)) $$render(consequent_9);
69241
- });
69242
- var node_11 = sibling(node_7, 2);
69243
- var consequent_10 = ($$anchor) => {
69244
- var fragment_3 = root_12();
69245
- var span_6 = first_child(fragment_3);
69246
- var text_8 = child(span_6);
69247
- reset(span_6);
69248
- next(2);
69249
- template_effect(() => {
69250
- var _$$get$size;
69251
- return set_text(text_8, `${(_$$get$size = get(currentSelectedIds).size) !== null && _$$get$size !== void 0 ? _$$get$size : ""} selected`);
69252
- });
69253
- append($$anchor, fragment_3);
69373
+ var span_7 = sibling(node_12, 2);
69374
+ var text_9 = child(span_7);
69375
+ reset(span_7);
69376
+ var button = sibling(span_7, 2);
69377
+ var button_1 = sibling(button, 2);
69378
+ var text_10 = child(button_1);
69379
+ reset(button_1);
69380
+ var button_2 = sibling(button_1, 2);
69381
+ var text_11 = child(button_2);
69382
+ reset(button_2);
69383
+ var button_3 = sibling(button_2, 2);
69384
+ var text_12 = child(button_3);
69385
+ reset(button_3);
69386
+ var button_4 = sibling(button_3, 2);
69387
+ var button_5 = sibling(button_4, 2);
69388
+ var text_13 = child(button_5);
69389
+ reset(button_5);
69390
+ var button_6 = sibling(button_5, 2);
69391
+ var text_14 = child(button_6);
69392
+ text_14.nodeValue = "🗺 Map";
69393
+ reset(button_6);
69394
+ reset(div_4);
69395
+ template_effect(($0) => {
69396
+ set_text(text_9, `Zoom: ${$0 !== null && $0 !== void 0 ? $0 : ""}%`);
69397
+ set_text(text_10, `${get(showGrid) ? "▦" : "▢"} Grid`);
69398
+ set_text(text_11, `${get(currentSnapToGrid) ? "🧲" : "↔"} Snap`);
69399
+ set_text(text_12, `${get(showFurniture) ? "🪑" : "👻"} Furniture`);
69400
+ set_text(text_13, `${get(showRulers) ? "📏" : "📐"} Rulers`);
69401
+ }, [() => Math.round(get(zoom) * 100)]);
69402
+ delegated("click", button, () => zoomToFit());
69403
+ delegated("click", button_1, () => set(showGrid, !get(showGrid)));
69404
+ delegated("click", button_2, () => projectSettings.update((s) => ({
69405
+ ...s,
69406
+ snapToGrid: !s.snapToGrid
69407
+ })));
69408
+ delegated("click", button_3, () => layerVisibility.update((v) => ({
69409
+ ...v,
69410
+ furniture: !v.furniture
69411
+ })));
69412
+ delegated("click", button_4, () => set(showLayerPanel, !get(showLayerPanel)));
69413
+ delegated("click", button_5, () => set(showRulers, !get(showRulers)));
69414
+ delegated("click", button_6, () => set(showMinimap, !get(showMinimap)));
69415
+ append($$anchor, div_4);
69254
69416
  };
69255
- if_block(node_11, ($$render) => {
69256
- if (get(currentSelectedIds).size > 1) $$render(consequent_10);
69417
+ if_block(node_6, ($$render) => {
69418
+ if (!$$props.viewOnly) $$render(consequent_11);
69257
69419
  });
69258
- var span_7 = sibling(node_11, 2);
69259
- var text_9 = child(span_7);
69260
- reset(span_7);
69261
- var button = sibling(span_7, 2);
69262
- var button_1 = sibling(button, 2);
69263
- var text_10 = child(button_1);
69264
- reset(button_1);
69265
- var button_2 = sibling(button_1, 2);
69266
- var text_11 = child(button_2);
69267
- reset(button_2);
69268
- var button_3 = sibling(button_2, 2);
69269
- var text_12 = child(button_3);
69270
- reset(button_3);
69271
- var button_4 = sibling(button_3, 2);
69272
- var button_5 = sibling(button_4, 2);
69273
- var text_13 = child(button_5);
69274
- reset(button_5);
69275
- var button_6 = sibling(button_5, 2);
69276
- var text_14 = child(button_6);
69277
- text_14.nodeValue = "🗺 Map";
69278
- reset(button_6);
69279
- reset(div_4);
69280
- var node_12 = sibling(div_4, 2);
69281
- var consequent_11 = ($$anchor) => {
69282
- var div_5 = root_13();
69283
- var node_13 = sibling(child(div_5), 2);
69284
- each(node_13, 16, () => [
69420
+ var node_13 = sibling(node_6, 2);
69421
+ var consequent_12 = ($$anchor) => {
69422
+ var div_5 = root_14();
69423
+ var node_14 = sibling(child(div_5), 2);
69424
+ each(node_14, 16, () => [
69285
69425
  ["walls", "Walls"],
69286
69426
  ["doors", "Doors"],
69287
69427
  ["windows", "Windows"],
@@ -69294,7 +69434,7 @@ function FloorPlanCanvas($$anchor, $$props) {
69294
69434
  var $$array = /* @__PURE__ */ user_derived(() => to_array($$item, 2));
69295
69435
  let key = () => get($$array)[0];
69296
69436
  let label = () => get($$array)[1];
69297
- var label_1 = root_14();
69437
+ var label_1 = root_15();
69298
69438
  var input_2 = child(label_1);
69299
69439
  remove_input_defaults(input_2);
69300
69440
  var span_8 = sibling(input_2, 2);
@@ -69311,7 +69451,7 @@ function FloorPlanCanvas($$anchor, $$props) {
69311
69451
  })));
69312
69452
  append($$anchor, label_1);
69313
69453
  });
69314
- var label_2 = sibling(node_13, 4);
69454
+ var label_2 = sibling(node_14, 4);
69315
69455
  var input_3 = child(label_2);
69316
69456
  remove_input_defaults(input_3);
69317
69457
  next(2);
@@ -69326,11 +69466,11 @@ function FloorPlanCanvas($$anchor, $$props) {
69326
69466
  bind_checked(input_4, () => get(showDimensions), ($$value) => set(showDimensions, $$value));
69327
69467
  append($$anchor, div_5);
69328
69468
  };
69329
- if_block(node_12, ($$render) => {
69330
- if (get(showLayerPanel)) $$render(consequent_11);
69469
+ if_block(node_13, ($$render) => {
69470
+ if (get(showLayerPanel)) $$render(consequent_12);
69331
69471
  });
69332
- var node_14 = sibling(node_12, 2);
69333
- var consequent_15 = ($$anchor) => {
69472
+ var node_15 = sibling(node_13, 2);
69473
+ var consequent_16 = ($$anchor) => {
69334
69474
  const el = /* @__PURE__ */ user_derived(() => (() => {
69335
69475
  const f = get(currentFloor);
69336
69476
  const wall = f.walls.find((w) => w.id === get(currentSelectedId));
@@ -69363,24 +69503,24 @@ function FloorPlanCanvas($$anchor, $$props) {
69363
69503
  return null;
69364
69504
  })());
69365
69505
  var fragment_4 = comment();
69366
- var node_15 = first_child(fragment_4);
69367
- var consequent_14 = ($$anchor) => {
69368
- var div_6 = root_16();
69506
+ var node_16 = first_child(fragment_4);
69507
+ var consequent_15 = ($$anchor) => {
69508
+ var div_6 = root_17();
69369
69509
  var button_7 = child(div_6);
69370
- var node_16 = sibling(button_7, 2);
69371
- var consequent_12 = ($$anchor) => {
69372
- var button_8 = root_17();
69510
+ var node_17 = sibling(button_7, 2);
69511
+ var consequent_13 = ($$anchor) => {
69512
+ var button_8 = root_18();
69373
69513
  delegated("click", button_8, () => {
69374
69514
  if (get(el).door) updateDoor(get(el).door.id, { swingDirection: get(el).door.swingDirection === "left" ? "right" : "left" });
69375
69515
  });
69376
69516
  append($$anchor, button_8);
69377
69517
  };
69378
- if_block(node_16, ($$render) => {
69379
- if (get(el).type === "door" && get(el).door) $$render(consequent_12);
69518
+ if_block(node_17, ($$render) => {
69519
+ if (get(el).type === "door" && get(el).door) $$render(consequent_13);
69380
69520
  });
69381
- var node_17 = sibling(node_16, 2);
69382
- var consequent_13 = ($$anchor) => {
69383
- var button_9 = root_18();
69521
+ var node_18 = sibling(node_17, 2);
69522
+ var consequent_14 = ($$anchor) => {
69523
+ var button_9 = root_19();
69384
69524
  delegated("click", button_9, () => {
69385
69525
  if (get(currentSelectedId)) {
69386
69526
  if (splitWall(get(currentSelectedId), .5)) selectedElementId.set(null);
@@ -69388,10 +69528,10 @@ function FloorPlanCanvas($$anchor, $$props) {
69388
69528
  });
69389
69529
  append($$anchor, button_9);
69390
69530
  };
69391
- if_block(node_17, ($$render) => {
69392
- if (get(el).type === "wall" && get(currentSelectedId) && get(currentSelectedIds).size === 0) $$render(consequent_13);
69531
+ if_block(node_18, ($$render) => {
69532
+ if (get(el).type === "wall" && get(currentSelectedId) && get(currentSelectedIds).size === 0) $$render(consequent_14);
69393
69533
  });
69394
- var button_10 = sibling(node_17, 4);
69534
+ var button_10 = sibling(node_18, 4);
69395
69535
  reset(div_6);
69396
69536
  template_effect(() => {
69397
69537
  var _$$get$pos$x;
@@ -69420,24 +69560,24 @@ function FloorPlanCanvas($$anchor, $$props) {
69420
69560
  });
69421
69561
  append($$anchor, div_6);
69422
69562
  };
69423
- if_block(node_15, ($$render) => {
69424
- if (get(el)) $$render(consequent_14);
69563
+ if_block(node_16, ($$render) => {
69564
+ if (get(el)) $$render(consequent_15);
69425
69565
  });
69426
69566
  append($$anchor, fragment_4);
69427
69567
  };
69428
- if_block(node_14, ($$render) => {
69429
- if ((get(currentSelectedId) || get(currentSelectedIds).size > 0) && get(currentFloor) && get(currentTool) === "select") $$render(consequent_15);
69568
+ if_block(node_15, ($$render) => {
69569
+ if ((get(currentSelectedId) || get(currentSelectedIds).size > 0) && get(currentFloor) && get(currentTool) === "select") $$render(consequent_16);
69430
69570
  });
69431
- var node_18 = sibling(node_14, 2);
69432
- var consequent_16 = ($$anchor) => {
69433
- append($$anchor, root_19());
69571
+ var node_19 = sibling(node_15, 2);
69572
+ var consequent_17 = ($$anchor) => {
69573
+ append($$anchor, root_20());
69434
69574
  };
69435
- if_block(node_18, ($$render) => {
69436
- if (get(currentTool) === "wall" && get(wallStart)) $$render(consequent_16);
69575
+ if_block(node_19, ($$render) => {
69576
+ if (get(currentTool) === "wall" && get(wallStart)) $$render(consequent_17);
69437
69577
  });
69438
- var node_19 = sibling(node_18, 2);
69439
- var consequent_17 = ($$anchor) => {
69440
- var div_8 = root_20();
69578
+ var node_20 = sibling(node_19, 2);
69579
+ var consequent_18 = ($$anchor) => {
69580
+ var div_8 = root_21();
69441
69581
  var text_16 = child(div_8);
69442
69582
  reset(div_8);
69443
69583
  template_effect(() => {
@@ -69447,35 +69587,35 @@ function FloorPlanCanvas($$anchor, $$props) {
69447
69587
  });
69448
69588
  append($$anchor, div_8);
69449
69589
  };
69450
- if_block(node_19, ($$render) => {
69451
- if (get(currentPlacingId) && get(currentTool) === "furniture") $$render(consequent_17);
69452
- });
69453
- var node_20 = sibling(node_19, 2);
69454
- var consequent_18 = ($$anchor) => {
69455
- append($$anchor, root_21());
69456
- };
69457
69590
  if_block(node_20, ($$render) => {
69458
- if (get(measuring)) $$render(consequent_18);
69591
+ if (get(currentPlacingId) && get(currentTool) === "furniture") $$render(consequent_18);
69459
69592
  });
69460
69593
  var node_21 = sibling(node_20, 2);
69461
69594
  var consequent_19 = ($$anchor) => {
69462
69595
  append($$anchor, root_22());
69463
69596
  };
69464
69597
  if_block(node_21, ($$render) => {
69465
- if (get(textAnnotationMode)) $$render(consequent_19);
69598
+ if (get(measuring)) $$render(consequent_19);
69466
69599
  });
69467
69600
  var node_22 = sibling(node_21, 2);
69468
69601
  var consequent_20 = ($$anchor) => {
69469
- var div_11 = root_23();
69602
+ append($$anchor, root_23());
69603
+ };
69604
+ if_block(node_22, ($$render) => {
69605
+ if (get(textAnnotationMode)) $$render(consequent_20);
69606
+ });
69607
+ var node_23 = sibling(node_22, 2);
69608
+ var consequent_21 = ($$anchor) => {
69609
+ var div_11 = root_24();
69470
69610
  var text_17 = child(div_11);
69471
69611
  reset(div_11);
69472
69612
  template_effect(() => set_text(text_17, `${get(annotationStart) ? "Click second point to create annotation" : "Click first point"} · N to exit · Esc to cancel`));
69473
69613
  append($$anchor, div_11);
69474
69614
  };
69475
- if_block(node_22, ($$render) => {
69476
- if (get(annotating)) $$render(consequent_20);
69615
+ if_block(node_23, ($$render) => {
69616
+ if (get(annotating)) $$render(consequent_21);
69477
69617
  });
69478
- var div_12 = sibling(node_22, 2);
69618
+ var div_12 = sibling(node_23, 2);
69479
69619
  var button_11 = child(div_12);
69480
69620
  var button_12 = sibling(button_11, 2);
69481
69621
  var text_18 = child(button_12);
@@ -69516,27 +69656,7 @@ function FloorPlanCanvas($$anchor, $$props) {
69516
69656
  },
69517
69657
  onaction: handleContextMenuAction
69518
69658
  });
69519
- template_effect(($0, $1) => {
69520
- set_text(text_9, `Zoom: ${$0 !== null && $0 !== void 0 ? $0 : ""}%`);
69521
- set_text(text_10, `${get(showGrid) ? "▦" : "▢"} Grid`);
69522
- set_text(text_11, `${get(currentSnapToGrid) ? "🧲" : "↔"} Snap`);
69523
- set_text(text_12, `${get(showFurniture) ? "🪑" : "👻"} Furniture`);
69524
- set_text(text_13, `${get(showRulers) ? "📏" : "📐"} Rulers`);
69525
- set_text(text_18, `${$1 !== null && $1 !== void 0 ? $1 : ""}%`);
69526
- }, [() => Math.round(get(zoom) * 100), () => Math.round(get(zoom) * 100)]);
69527
- delegated("click", button, () => zoomToFit());
69528
- delegated("click", button_1, () => set(showGrid, !get(showGrid)));
69529
- delegated("click", button_2, () => projectSettings.update((s) => ({
69530
- ...s,
69531
- snapToGrid: !s.snapToGrid
69532
- })));
69533
- delegated("click", button_3, () => layerVisibility.update((v) => ({
69534
- ...v,
69535
- furniture: !v.furniture
69536
- })));
69537
- delegated("click", button_4, () => set(showLayerPanel, !get(showLayerPanel)));
69538
- delegated("click", button_5, () => set(showRulers, !get(showRulers)));
69539
- delegated("click", button_6, () => set(showMinimap, !get(showMinimap)));
69659
+ template_effect(($0) => set_text(text_18, `${$0 !== null && $0 !== void 0 ? $0 : ""}%`), [() => Math.round(get(zoom) * 100)]);
69540
69660
  delegated("click", button_11, () => {
69541
69661
  const newZoom = Math.max(.1, get(zoom) * .8);
69542
69662
  const worldCX = (get(width) / 2 - get(width) / 2) / get(zoom) + get(camX);
@@ -69555,20 +69675,14 @@ function FloorPlanCanvas($$anchor, $$props) {
69555
69675
  append($$anchor, fragment);
69556
69676
  };
69557
69677
  if_block(node_1, ($$render) => {
69558
- if (!$$props.viewOnly) $$render(consequent_21);
69678
+ if (!$$props.viewOnly) $$render(consequent_22);
69559
69679
  });
69560
69680
  reset(div);
69561
69681
  template_effect(($0) => {
69562
69682
  set_style(div_1, $0);
69563
69683
  classes = set_class(canvas_1, 1, "block w-full h-full", null, classes, { "pointer-events-none": $$props.viewOnly });
69564
69684
  set_attribute(canvas_1, "tabindex", $$props.viewOnly ? -1 : 0);
69565
- set_style(canvas_1, `
69566
- cursor: ${get(cursorStyle)};
69567
- max-width: ${$$props.viewOnly ? `${$$props.floorMaxWidth}px` : "unset"};
69568
- max-height: ${$$props.viewOnly ? `${$$props.floorMaxHeight}px` : "unset"};
69569
- min-width: ${$$props.viewOnly ? `${$$props.floorMaxWidth}px` : "unset"};
69570
- min-height: ${$$props.viewOnly ? `${$$props.floorMaxHeight}px` : "unset"};
69571
- `);
69685
+ set_style(canvas_1, `cursor: ${get(cursorStyle)};`);
69572
69686
  }, [() => getCanvasFrameStyle()]);
69573
69687
  delegated("mousedown", canvas_1, onMouseDown);
69574
69688
  delegated("mousemove", canvas_1, onMouseMove);
@@ -70552,42 +70666,11 @@ function OnboardingTooltip($$anchor, $$props) {
70552
70666
  }
70553
70667
  delegate(["click"]);
70554
70668
  //#endregion
70555
- //#region src/lib/packageDefaults.ts
70556
- var DEFAULT_CONFIG = {
70557
- viewOnly: false,
70558
- floorMaxWidth: 600,
70559
- floorMaxHeight: 400,
70560
- heatmapEnabled: false,
70561
- heatmapMatrix: [],
70562
- projectName: void 0,
70563
- selectedCameraSerial: null,
70564
- showCameraCones: false,
70565
- showCameraLabels: true
70566
- };
70567
- function normalizeConfig(value) {
70568
- if (!value || typeof value !== "object") return { ...DEFAULT_CONFIG };
70569
- return {
70570
- ...DEFAULT_CONFIG,
70571
- ...value
70572
- };
70573
- }
70574
- function normalizeFloorData(data) {
70575
- if (!data || typeof data !== "object") return createDefaultProject();
70576
- if (!Array.isArray(data.floors) || data.floors.length === 0) return createDefaultProject();
70577
- if (!data.activeFloorId || !data.floors.some((f) => f.id === data.activeFloorId)) return {
70578
- ...createDefaultProject(),
70579
- ...data,
70580
- floors: data.floors,
70581
- activeFloorId: data.floors[0].id
70582
- };
70583
- return data;
70584
- }
70585
- //#endregion
70586
70669
  //#region src/App.svelte
70587
70670
  init_client();
70588
70671
  init_index_client();
70589
70672
  var root_3 = /* @__PURE__ */ from_html(`<!> <!>`, 1);
70590
- var root_6 = /* @__PURE__ */ from_html(`<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50" role="dialog" tabindex="-1" aria-label="Keyboard Shortcuts"><div class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full mx-4 max-h-[85vh] flex flex-col" role="document"><div class="flex items-center justify-between px-6 pt-5 pb-3 border-b border-gray-100"><div class="flex items-center gap-2"><svg class="w-5 h-5 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707"></path></svg> <h2 class="text-lg font-bold text-slate-800">Keyboard Shortcuts</h2></div> <div class="flex items-center gap-2"><button class="text-xs px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-600 hover:text-slate-800 transition-colors flex items-center gap-1.5" aria-label="Copy all shortcuts"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg> Copy All</button> <button class="text-gray-400 hover:text-gray-600 text-xl leading-none" aria-label="Close shortcuts">✕</button></div></div> <div class="overflow-y-auto px-6 py-4"><div class="grid grid-cols-2 gap-x-8 gap-y-0 text-sm"><div><div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-indigo-500">Tools</span> <div class="flex-1 h-px bg-indigo-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Select tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">V</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Wall tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">W</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Door tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">D</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Pan mode</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">H</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Measure tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">M</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Annotate tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">N</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Text tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">T</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Toggle snap</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">S</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-amber-500">Edit</span> <div class="flex-1 h-px bg-amber-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Undo</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+Z</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Redo</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+Y</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Copy</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+C</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Paste</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+V</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Select all</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+A</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Deselect all</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+D</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Save project</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+S</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Cancel / Deselect</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Esc</kbd></div></div></div> <div><div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-emerald-500">Elements</span> <div class="flex-1 h-px bg-emerald-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Rotate element</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">R</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Delete selected</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Del</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Lock / Unlock</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+L</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Group selection</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+G</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Ungroup</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+⇧+G</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-blue-500">View</span> <div class="flex-1 h-px bg-blue-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Toggle 2D / 3D</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Tab</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Zoom to fit</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">F</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Toggle grid</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">G</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Toggle layers</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">L</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Show shortcuts</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">?</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-purple-500">Canvas</span> <div class="flex-1 h-px bg-purple-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Zoom in / out</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Scroll</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Zoom in / out</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">+ / −</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Pan canvas</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Space+Drag</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-rose-500">Walls</span> <div class="flex-1 h-px bg-rose-100"></div></div> <div class="space-y-1.5"><div class="flex justify-between"><span class="text-gray-600">Finish wall chain</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Dbl-click</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Close wall loop</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">C</kbd></div></div></div></div></div> <div class="px-6 py-3 border-t border-gray-100 text-center"><p class="text-xs text-gray-400">Press <kbd class="px-1 py-0.5 bg-gray-100 rounded text-xs font-mono border border-gray-200">?</kbd> or <kbd class="px-1 py-0.5 bg-gray-100 rounded text-xs font-mono border border-gray-200">Esc</kbd> to close</p></div></div></div>`);
70673
+ var root_7 = /* @__PURE__ */ from_html(`<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50" role="dialog" tabindex="-1" aria-label="Keyboard Shortcuts"><div class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full mx-4 max-h-[85vh] flex flex-col" role="document"><div class="flex items-center justify-between px-6 pt-5 pb-3 border-b border-gray-100"><div class="flex items-center gap-2"><svg class="w-5 h-5 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707"></path></svg> <h2 class="text-lg font-bold text-slate-800">Keyboard Shortcuts</h2></div> <div class="flex items-center gap-2"><button class="text-xs px-3 py-1.5 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-600 hover:text-slate-800 transition-colors flex items-center gap-1.5" aria-label="Copy all shortcuts"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg> Copy All</button> <button class="text-gray-400 hover:text-gray-600 text-xl leading-none" aria-label="Close shortcuts">✕</button></div></div> <div class="overflow-y-auto px-6 py-4"><div class="grid grid-cols-2 gap-x-8 gap-y-0 text-sm"><div><div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-indigo-500">Tools</span> <div class="flex-1 h-px bg-indigo-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Select tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">V</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Wall tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">W</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Door tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">D</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Pan mode</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">H</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Measure tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">M</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Annotate tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">N</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Text tool</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">T</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Toggle snap</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">S</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-amber-500">Edit</span> <div class="flex-1 h-px bg-amber-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Undo</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+Z</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Redo</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+Y</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Copy</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+C</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Paste</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+V</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Select all</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+A</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Deselect all</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+D</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Save project</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+S</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Cancel / Deselect</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Esc</kbd></div></div></div> <div><div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-emerald-500">Elements</span> <div class="flex-1 h-px bg-emerald-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Rotate element</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">R</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Delete selected</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Del</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Lock / Unlock</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+L</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Group selection</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+G</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Ungroup</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Ctrl+⇧+G</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-blue-500">View</span> <div class="flex-1 h-px bg-blue-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Toggle 2D / 3D</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Tab</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Zoom to fit</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">F</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Toggle grid</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">G</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Toggle layers</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">L</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Show shortcuts</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">?</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-purple-500">Canvas</span> <div class="flex-1 h-px bg-purple-100"></div></div> <div class="space-y-1.5 mb-5"><div class="flex justify-between"><span class="text-gray-600">Zoom in / out</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Scroll</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Zoom in / out</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">+ / −</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Pan canvas</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Space+Drag</kbd></div></div> <div class="flex items-center gap-2 mb-2"><span class="text-xs font-bold uppercase tracking-wider text-rose-500">Walls</span> <div class="flex-1 h-px bg-rose-100"></div></div> <div class="space-y-1.5"><div class="flex justify-between"><span class="text-gray-600">Finish wall chain</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">Dbl-click</kbd></div> <div class="flex justify-between"><span class="text-gray-600">Close wall loop</span><kbd class="px-1.5 py-0.5 bg-gray-100 rounded text-xs font-mono text-slate-700 border border-gray-200">C</kbd></div></div></div></div></div> <div class="px-6 py-3 border-t border-gray-100 text-center"><p class="text-xs text-gray-400">Press <kbd class="px-1 py-0.5 bg-gray-100 rounded text-xs font-mono border border-gray-200">?</kbd> or <kbd class="px-1 py-0.5 bg-gray-100 rounded text-xs font-mono border border-gray-200">Esc</kbd> to close</p></div></div></div>`);
70591
70674
  var root = /* @__PURE__ */ from_html(`<div class="h-full flex flex-col overflow-hidden"><!> <div class="flex flex-1 overflow-hidden"><!> <div class="flex-1 min-w-0 relative"><!></div> <!> <!></div></div> <!> <!> <!> <!> <!>`, 1);
70592
70675
  function App($$anchor, $$props) {
70593
70676
  var _$$props$stores, _$$props$stores2;
@@ -70629,12 +70712,12 @@ function App($$anchor, $$props) {
70629
70712
  });
70630
70713
  var fragment = root();
70631
70714
  event("keydown", $window, (e) => {
70632
- var _e$target, _e$target2, _e$target3;
70715
+ if (isEditableTarget(e)) return;
70633
70716
  if (e.key === "p" && (e.ctrlKey || e.metaKey)) {
70634
70717
  e.preventDefault();
70635
70718
  set(printOpen, true);
70636
70719
  }
70637
- if (e.key === "k" && (e.ctrlKey || e.metaKey) || e.key === "/" && !e.ctrlKey && !e.metaKey && ((_e$target = e.target) === null || _e$target === void 0 ? void 0 : _e$target.tagName) !== "INPUT" && ((_e$target2 = e.target) === null || _e$target2 === void 0 ? void 0 : _e$target2.tagName) !== "TEXTAREA") {
70720
+ if (e.key === "k" && (e.ctrlKey || e.metaKey) || e.key === "/" && !e.ctrlKey && !e.metaKey) {
70638
70721
  e.preventDefault();
70639
70722
  set(commandPaletteOpen, !get(commandPaletteOpen));
70640
70723
  }
@@ -70643,7 +70726,7 @@ function App($$anchor, $$props) {
70643
70726
  e.preventDefault();
70644
70727
  }
70645
70728
  if (e.key === "Escape" && get(showHelp)) set(showHelp, false);
70646
- if (e.key === "l" && !e.ctrlKey && !e.metaKey && !e.altKey && ((_e$target3 = e.target) === null || _e$target3 === void 0 ? void 0 : _e$target3.tagName) !== "INPUT") set(showLayers, !get(showLayers));
70729
+ if (e.key === "l" && !e.ctrlKey && !e.metaKey && !e.altKey) set(showLayers, !get(showLayers));
70647
70730
  });
70648
70731
  var div = first_child(fragment);
70649
70732
  var node = child(div);
@@ -70730,6 +70813,10 @@ function App($$anchor, $$props) {
70730
70813
  var _$$get10;
70731
70814
  return (_$$get10 = get(config)) === null || _$$get10 === void 0 ? void 0 : _$$get10.showCameraLabels;
70732
70815
  });
70816
+ let $9 = /* @__PURE__ */ user_derived(() => {
70817
+ var _$$get11;
70818
+ return (_$$get11 = get(config)) === null || _$$get11 === void 0 ? void 0 : _$$get11.cameraHeatmapMatrix;
70819
+ });
70733
70820
  FloorPlanCanvas(node_3, {
70734
70821
  get viewOnly() {
70735
70822
  return get($0);
@@ -70757,6 +70844,9 @@ function App($$anchor, $$props) {
70757
70844
  },
70758
70845
  get showCameraLabels() {
70759
70846
  return get($8);
70847
+ },
70848
+ get cameraHeatmapMatrix() {
70849
+ return get($9);
70760
70850
  }
70761
70851
  });
70762
70852
  }
@@ -70778,15 +70868,20 @@ function App($$anchor, $$props) {
70778
70868
  LayersPanel($$anchor, {});
70779
70869
  };
70780
70870
  if_block(node_5, ($$render) => {
70781
- if (get(showLayers) && get(mode) === "2d") $$render(consequent_4);
70871
+ if (get(showLayers) && get(mode) === "2d" && !get(config).viewOnly) $$render(consequent_4);
70782
70872
  });
70783
70873
  var node_6 = sibling(node_5, 2);
70784
- {
70785
- let $0 = /* @__PURE__ */ user_derived(() => get(mode) === "3d");
70786
- PropertiesPanel(node_6, { get is3D() {
70787
- return get($0);
70788
- } });
70789
- }
70874
+ var consequent_5 = ($$anchor) => {
70875
+ {
70876
+ let $0 = /* @__PURE__ */ user_derived(() => get(mode) === "3d");
70877
+ PropertiesPanel($$anchor, { get is3D() {
70878
+ return get($0);
70879
+ } });
70880
+ }
70881
+ };
70882
+ if_block(node_6, ($$render) => {
70883
+ if (!get(config).viewOnly) $$render(consequent_5);
70884
+ });
70790
70885
  reset(div_1);
70791
70886
  reset(div);
70792
70887
  var node_7 = sibling(div, 2);
@@ -70799,8 +70894,8 @@ function App($$anchor, $$props) {
70799
70894
  }
70800
70895
  });
70801
70896
  var node_8 = sibling(node_7, 2);
70802
- var consequent_5 = ($$anchor) => {
70803
- var div_3 = root_6();
70897
+ var consequent_6 = ($$anchor) => {
70898
+ var div_3 = root_7();
70804
70899
  var div_4 = child(div_3);
70805
70900
  var div_5 = child(div_4);
70806
70901
  var div_6 = sibling(child(div_5), 2);
@@ -70870,7 +70965,7 @@ function App($$anchor, $$props) {
70870
70965
  append($$anchor, div_3);
70871
70966
  };
70872
70967
  if_block(node_8, ($$render) => {
70873
- if (get(showHelp)) $$render(consequent_5);
70968
+ if (get(showHelp)) $$render(consequent_6);
70874
70969
  });
70875
70970
  var node_9 = sibling(node_8, 2);
70876
70971
  CommandPalette(node_9, {
@@ -70920,9 +71015,16 @@ var FloorEditor = class extends HTMLElement {
70920
71015
  connectedCallback() {
70921
71016
  const shadow = this.attachShadow({ mode: "open" });
70922
71017
  const style = document.createElement("style");
70923
- style.textContent = app_default;
71018
+ style.textContent = app_default + `
71019
+ :host {
71020
+ display: block;
71021
+ width: 100%;
71022
+ height: 100%;
71023
+ }
71024
+ `;
70924
71025
  shadow.appendChild(style);
70925
71026
  _classPrivateFieldSet2(_wrapper, this, document.createElement("div"));
71027
+ _classPrivateFieldGet2(_wrapper, this).style.cssText = "width:100%;height:100%;display:block;";
70926
71028
  shadow.appendChild(_classPrivateFieldGet2(_wrapper, this));
70927
71029
  _classPrivateFieldSet2(_app, this, mount(App, {
70928
71030
  target: _classPrivateFieldGet2(_wrapper, this),