@spacesync/client 0.1.4 → 0.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.
- package/README.md +26 -10
- package/dist/analog-clock-picker.js +3 -2
- package/dist/booking-schedule-calendars.js +3 -2
- package/dist/booking-schedule-calendars.js.map +1 -1
- package/dist/chat-stick-to-bottom.js +2 -1
- package/dist/chat-stick-to-bottom.js.map +1 -1
- package/dist/{chunk-HCQSED6Q.js → chunk-34332W2P.js} +3 -3
- package/dist/{chunk-HCQSED6Q.js.map → chunk-34332W2P.js.map} +1 -1
- package/dist/chunk-DC4QH6W2.js +17 -0
- package/dist/chunk-DC4QH6W2.js.map +1 -0
- package/dist/{chunk-R4L4TDT3.js → chunk-H3CNZCYU.js} +13 -13
- package/dist/chunk-H3CNZCYU.js.map +1 -0
- package/dist/file-viewer-dialog.js +37 -17
- package/dist/file-viewer-dialog.js.map +1 -1
- package/dist/floor-switcher.js +2 -1
- package/dist/floor-switcher.js.map +1 -1
- package/dist/layout-canvas-view.js +2 -1
- package/dist/layout-canvas-view.js.map +1 -1
- package/dist/page-list-loading.d.ts +20 -0
- package/dist/page-list-loading.js +79 -0
- package/dist/page-list-loading.js.map +1 -0
- package/dist/platform-support-message-composer.js +2 -1
- package/dist/platform-support-message-composer.js.map +1 -1
- package/dist/ui.js +2 -1
- package/package.json +10 -9
- package/dist/chunk-R4L4TDT3.js.map +0 -1
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogTitle } from './chunk-
|
|
1
|
+
import { ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogTitle } from './chunk-H3CNZCYU.js';
|
|
2
2
|
import './chunk-RV5PMZYZ.js';
|
|
3
3
|
import './chunk-L65F4EMK.js';
|
|
4
4
|
import './chunk-PBNBLCC2.js';
|
|
5
5
|
import './chunk-VVXGQKN7.js';
|
|
6
6
|
import './chunk-7YCAAP43.js';
|
|
7
|
+
import './chunk-DC4QH6W2.js';
|
|
7
8
|
import './chunk-LUB7QWGU.js';
|
|
8
9
|
import { Button } from './chunk-VHINHHZQ.js';
|
|
9
10
|
import './chunk-FCY5FYJB.js';
|
|
10
11
|
import './chunk-OWNUMPUC.js';
|
|
11
|
-
import './chunk-DMPSQ22Q.js';
|
|
12
|
+
import { cn } from './chunk-DMPSQ22Q.js';
|
|
12
13
|
import { useState, useRef, useEffect, useMemo } from 'react';
|
|
13
|
-
import { Minus, Plus, RotateCcw, Download, ExternalLink, FileText } from 'lucide-react';
|
|
14
|
+
import { Minus, Plus, RotateCcw, Download, ExternalLink, Loader2, FileText } from 'lucide-react';
|
|
14
15
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
15
16
|
|
|
16
17
|
function FileViewerDialog({
|
|
@@ -20,10 +21,12 @@ function FileViewerDialog({
|
|
|
20
21
|
}) {
|
|
21
22
|
const [zoom, setZoom] = useState(1);
|
|
22
23
|
const [dragging, setDragging] = useState(false);
|
|
24
|
+
const [imageStatus, setImageStatus] = useState("loading");
|
|
23
25
|
const scrollRef = useRef(null);
|
|
24
26
|
const dragStateRef = useRef(null);
|
|
25
27
|
useEffect(() => {
|
|
26
28
|
if (open) setZoom(1);
|
|
29
|
+
setImageStatus("loading");
|
|
27
30
|
}, [open, file?.url]);
|
|
28
31
|
const kind = useMemo(() => {
|
|
29
32
|
if (!file) return "other";
|
|
@@ -145,21 +148,38 @@ function FileViewerDialog({
|
|
|
145
148
|
onPointerMove: handleImagePointerMove,
|
|
146
149
|
onPointerUp: handleImagePointerEnd,
|
|
147
150
|
onPointerCancel: handleImagePointerEnd,
|
|
148
|
-
children: /* @__PURE__ */
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
maxWidth: "none",
|
|
158
|
-
cursor: isDraggable ? dragging ? "grabbing" : "grab" : "default",
|
|
159
|
-
touchAction: isDraggable ? "none" : "auto"
|
|
151
|
+
children: /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-[240px] w-full items-center justify-center", children: [
|
|
152
|
+
imageStatus !== "ready" ? /* @__PURE__ */ jsx(
|
|
153
|
+
"div",
|
|
154
|
+
{
|
|
155
|
+
className: "absolute inset-0 z-10 flex items-center justify-center",
|
|
156
|
+
role: "status",
|
|
157
|
+
"aria-live": "polite",
|
|
158
|
+
"aria-label": imageStatus === "error" ? "Couldn't load image" : "Loading image",
|
|
159
|
+
children: imageStatus === "error" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Couldn't load image" }) : /* @__PURE__ */ jsx(Loader2, { size: 28, className: "animate-spin text-muted-foreground" })
|
|
160
160
|
}
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
) : null,
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
"img",
|
|
164
|
+
{
|
|
165
|
+
src: file.url,
|
|
166
|
+
alt: file.name,
|
|
167
|
+
className: cn(
|
|
168
|
+
"block shrink-0 select-none rounded-lg border border-border bg-card shadow-sm",
|
|
169
|
+
imageStatus !== "ready" && "opacity-0"
|
|
170
|
+
),
|
|
171
|
+
draggable: false,
|
|
172
|
+
onLoad: () => setImageStatus("ready"),
|
|
173
|
+
onError: () => setImageStatus("error"),
|
|
174
|
+
style: {
|
|
175
|
+
width: `${zoom * 100}%`,
|
|
176
|
+
maxWidth: "none",
|
|
177
|
+
cursor: isDraggable ? dragging ? "grabbing" : "grab" : "default",
|
|
178
|
+
touchAction: isDraggable ? "none" : "auto"
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
] })
|
|
163
183
|
}
|
|
164
184
|
) }) : kind === "pdf" ? /* @__PURE__ */ jsx("object", { data: file.url, type: "application/pdf", className: "h-full w-full", children: /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [
|
|
165
185
|
/* @__PURE__ */ jsx(FileText, { size: 34, className: "text-muted-foreground" }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/files/file-viewer-dialog.tsx"],"names":[],"mappings":"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","file":"file-viewer-dialog.js","sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Download, ExternalLink, FileText, Minus, Plus, RotateCcw } from \"lucide-react\";\nimport {\n Button,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogTitle,\n} from \"../ui\";\n\nexport interface FileViewerFile {\n name: string;\n mimeType: string;\n sizeLabel?: string;\n url: string;\n}\n\nexport function FileViewerDialog({\n file,\n open,\n onOpenChange,\n}: {\n file: FileViewerFile | null;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [zoom, setZoom] = useState(1);\n const [dragging, setDragging] = useState(false);\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const dragStateRef = useRef<{\n pointerId: number;\n startX: number;\n startY: number;\n scrollLeft: number;\n scrollTop: number;\n } | null>(null);\n\n useEffect(() => {\n if (open) setZoom(1);\n }, [open, file?.url]);\n\n const kind = useMemo(() => {\n if (!file) return \"other\";\n if (file.mimeType.startsWith(\"image/\")) return \"image\";\n if (file.mimeType === \"application/pdf\" || file.name.toLowerCase().endsWith(\".pdf\")) return \"pdf\";\n return \"other\";\n }, [file]);\n\n const zoomPercent = Math.round(zoom * 100);\n const isDraggable = kind === \"image\" && zoom > 1;\n\n const handleImagePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n if (!isDraggable || !scrollRef.current) return;\n event.preventDefault();\n dragStateRef.current = {\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n scrollLeft: scrollRef.current.scrollLeft,\n scrollTop: scrollRef.current.scrollTop,\n };\n setDragging(true);\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const handleImagePointerMove = (event: React.PointerEvent<HTMLDivElement>) => {\n const state = dragStateRef.current;\n if (!state || state.pointerId !== event.pointerId || !scrollRef.current) return;\n scrollRef.current.scrollLeft = state.scrollLeft - (event.clientX - state.startX);\n scrollRef.current.scrollTop = state.scrollTop - (event.clientY - state.startY);\n };\n\n const handleImagePointerEnd = (event: React.PointerEvent<HTMLDivElement>) => {\n const state = dragStateRef.current;\n if (!state || state.pointerId !== event.pointerId) return;\n dragStateRef.current = null;\n setDragging(false);\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"flex h-[min(88vh,900px)] w-[min(96vw,1100px)] max-w-none flex-col gap-0 overflow-hidden rounded-xl border-border bg-card p-0\">\n <div className=\"flex shrink-0 flex-col gap-3 border-b border-border py-3 pl-4 pr-14 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <ResponsiveDialogTitle className=\"truncate text-base font-semibold text-foreground\">\n {file?.name ?? \"File preview\"}\n </ResponsiveDialogTitle>\n {file?.sizeLabel ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{file.sizeLabel}</p>\n ) : null}\n </div>\n {file ? (\n <div className=\"flex shrink-0 flex-wrap items-center gap-1.5 lg:justify-end\">\n {kind === \"image\" ? (\n <div className=\"flex items-center gap-0.5 rounded-lg border border-border bg-background p-0.5\">\n <button\n type=\"button\"\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-40\"\n onClick={() => setZoom((value) => Math.max(0.25, Number((value - 0.25).toFixed(2))))}\n disabled={zoom <= 0.25}\n aria-label=\"Zoom out\"\n >\n <Minus size={14} />\n </button>\n <span className=\"min-w-11 text-center text-xs font-medium tabular-nums text-muted-foreground\">\n {zoomPercent}%\n </span>\n <button\n type=\"button\"\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-40\"\n onClick={() => setZoom((value) => Math.min(4, Number((value + 0.25).toFixed(2))))}\n disabled={zoom >= 4}\n aria-label=\"Zoom in\"\n >\n <Plus size={14} />\n </button>\n <button\n type=\"button\"\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={() => setZoom(1)}\n aria-label=\"Reset zoom\"\n >\n <RotateCcw size={14} />\n </button>\n </div>\n ) : null}\n <Button\n asChild\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-9\"\n title=\"Download\"\n >\n <a href={file.url} download={file.name}>\n <Download size={14} />\n <span className=\"sr-only\">Download</span>\n </a>\n </Button>\n <Button\n asChild\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-9\"\n title=\"Open in new tab\"\n >\n <a href={file.url} target=\"_blank\" rel=\"noreferrer\">\n <ExternalLink size={14} />\n <span className=\"sr-only\">Open in new tab</span>\n </a>\n </Button>\n </div>\n ) : null}\n </div>\n <div className=\"min-h-0 flex-1 overflow-hidden bg-muted/60\">\n {!file ? (\n <div className=\"flex h-full items-center justify-center text-sm text-muted-foreground\">\n No file selected.\n </div>\n ) : kind === \"image\" ? (\n <div ref={scrollRef} className=\"h-full overflow-auto p-4\">\n <div\n className=\"flex min-h-full items-center justify-center\"\n style={{ minWidth: `${zoom * 100}%` }}\n onPointerDown={handleImagePointerDown}\n onPointerMove={handleImagePointerMove}\n onPointerUp={handleImagePointerEnd}\n onPointerCancel={handleImagePointerEnd}\n >\n <img\n src={file.url}\n alt={file.name}\n className=\"block shrink-0 select-none rounded-lg border border-border bg-card shadow-sm\"\n draggable={false}\n style={{\n width: `${zoom * 100}%`,\n maxWidth: \"none\",\n cursor: isDraggable ? (dragging ? \"grabbing\" : \"grab\") : \"default\",\n touchAction: isDraggable ? \"none\" : \"auto\",\n }}\n />\n </div>\n </div>\n ) : kind === \"pdf\" ? (\n <object data={file.url} type=\"application/pdf\" className=\"h-full w-full\">\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <FileText size={34} className=\"text-muted-foreground\" />\n <p className=\"max-w-md text-sm text-muted-foreground\">\n This browser cannot preview the PDF inline. You can still download or open it in a new tab.\n </p>\n </div>\n </object>\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <FileText size={34} className=\"text-muted-foreground\" />\n <p className=\"max-w-md text-sm text-muted-foreground\">\n Preview is not available for this file type. Download or open it in a new tab.\n </p>\n </div>\n )}\n </div>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/files/file-viewer-dialog.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAiBO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAClC,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAwC,SAAS,CAAA;AACvF,EAAA,MAAM,SAAA,GAAY,OAA8B,IAAI,CAAA;AACpD,EAAA,MAAM,YAAA,GAAe,OAMX,IAAI,CAAA;AAEd,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAA,UAAc,CAAC,CAAA;AACnB,IAAA,cAAA,CAAe,SAAS,CAAA;AAAA,EAC1B,CAAA,EAAG,CAAC,IAAA,EAAM,IAAA,EAAM,GAAG,CAAC,CAAA;AAEpB,EAAA,MAAM,IAAA,GAAO,QAAQ,MAAM;AACzB,IAAA,IAAI,CAAC,MAAM,OAAO,OAAA;AAClB,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,UAAA,CAAW,QAAQ,GAAG,OAAO,OAAA;AAC/C,IAAA,IAAI,IAAA,CAAK,QAAA,KAAa,iBAAA,IAAqB,IAAA,CAAK,IAAA,CAAK,aAAY,CAAE,QAAA,CAAS,MAAM,CAAA,EAAG,OAAO,KAAA;AAC5F,IAAA,OAAO,OAAA;AAAA,EACT,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,GAAG,CAAA;AACzC,EAAA,MAAM,WAAA,GAAc,IAAA,KAAS,OAAA,IAAW,IAAA,GAAO,CAAA;AAE/C,EAAA,MAAM,sBAAA,GAAyB,CAAC,KAAA,KAA8C;AAC5E,IAAA,IAAI,CAAC,WAAA,IAAe,CAAC,SAAA,CAAU,OAAA,EAAS;AACxC,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,YAAA,CAAa,OAAA,GAAU;AAAA,MACrB,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,QAAQ,KAAA,CAAM,OAAA;AAAA,MACd,QAAQ,KAAA,CAAM,OAAA;AAAA,MACd,UAAA,EAAY,UAAU,OAAA,CAAQ,UAAA;AAAA,MAC9B,SAAA,EAAW,UAAU,OAAA,CAAQ;AAAA,KAC/B;AACA,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,KAAA,CAAM,aAAA,CAAc,iBAAA,CAAkB,KAAA,CAAM,SAAS,CAAA;AAAA,EACvD,CAAA;AAEA,EAAA,MAAM,sBAAA,GAAyB,CAAC,KAAA,KAA8C;AAC5E,IAAA,MAAM,QAAQ,YAAA,CAAa,OAAA;AAC3B,IAAA,IAAI,CAAC,SAAS,KAAA,CAAM,SAAA,KAAc,MAAM,SAAA,IAAa,CAAC,UAAU,OAAA,EAAS;AACzE,IAAA,SAAA,CAAU,QAAQ,UAAA,GAAa,KAAA,CAAM,UAAA,IAAc,KAAA,CAAM,UAAU,KAAA,CAAM,MAAA,CAAA;AACzE,IAAA,SAAA,CAAU,QAAQ,SAAA,GAAY,KAAA,CAAM,SAAA,IAAa,KAAA,CAAM,UAAU,KAAA,CAAM,MAAA,CAAA;AAAA,EACzE,CAAA;AAEA,EAAA,MAAM,qBAAA,GAAwB,CAAC,KAAA,KAA8C;AAC3E,IAAA,MAAM,QAAQ,YAAA,CAAa,OAAA;AAC3B,IAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,SAAA,KAAc,MAAM,SAAA,EAAW;AACnD,IAAA,YAAA,CAAa,OAAA,GAAU,IAAA;AACvB,IAAA,WAAA,CAAY,KAAK,CAAA;AACjB,IAAA,IAAI,KAAA,CAAM,aAAA,CAAc,iBAAA,CAAkB,KAAA,CAAM,SAAS,CAAA,EAAG;AAC1D,MAAA,KAAA,CAAM,aAAA,CAAc,qBAAA,CAAsB,KAAA,CAAM,SAAS,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,2BACG,gBAAA,EAAA,EAAiB,IAAA,EAAY,cAC5B,QAAA,kBAAA,IAAA,CAAC,uBAAA,EAAA,EAAwB,WAAU,8HAAA,EACjC,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,oHAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,qBAAA,EAAA,EAAsB,SAAA,EAAU,kDAAA,EAC9B,QAAA,EAAA,IAAA,EAAM,QAAQ,cAAA,EACjB,CAAA;AAAA,QACC,IAAA,EAAM,4BACL,GAAA,CAAC,GAAA,EAAA,EAAE,WAAU,oCAAA,EAAsC,QAAA,EAAA,IAAA,CAAK,WAAU,CAAA,GAChE;AAAA,OAAA,EACN,CAAA;AAAA,MACC,IAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6DAAA,EACZ,QAAA,EAAA;AAAA,QAAA,IAAA,KAAS,OAAA,mBACR,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+EAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,SAAA,EAAU,2IAAA;AAAA,cACV,OAAA,EAAS,MAAM,OAAA,CAAQ,CAAC,UAAU,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,MAAA,CAAA,CAAQ,QAAQ,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAAA,cACnF,UAAU,IAAA,IAAQ,IAAA;AAAA,cAClB,YAAA,EAAW,UAAA;AAAA,cAEX,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA,WACnB;AAAA,0BACA,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6EAAA,EACb,QAAA,EAAA;AAAA,YAAA,WAAA;AAAA,YAAY;AAAA,WAAA,EACf,CAAA;AAAA,0BACA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,SAAA,EAAU,2IAAA;AAAA,cACV,OAAA,EAAS,MAAM,OAAA,CAAQ,CAAC,UAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAA,CAAA,CAAQ,QAAQ,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAAA,cAChF,UAAU,IAAA,IAAQ,CAAA;AAAA,cAClB,YAAA,EAAW,SAAA;AAAA,cAEX,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA,WAClB;AAAA,0BACA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,SAAA,EAAU,uHAAA;AAAA,cACV,OAAA,EAAS,MAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,cACxB,YAAA,EAAW,YAAA;AAAA,cAEX,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA;AACvB,SAAA,EACF,CAAA,GACE,IAAA;AAAA,wBACJ,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAO,IAAA;AAAA,YACP,OAAA,EAAQ,OAAA;AAAA,YACR,IAAA,EAAK,MAAA;AAAA,YACL,SAAA,EAAU,QAAA;AAAA,YACV,KAAA,EAAM,UAAA;AAAA,YAEN,+BAAC,GAAA,EAAA,EAAE,IAAA,EAAM,KAAK,GAAA,EAAK,QAAA,EAAU,KAAK,IAAA,EAChC,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,QAAA,EAAA,EAAS,MAAM,EAAA,EAAI,CAAA;AAAA,8BACpB,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU,QAAA,EAAA,UAAA,EAAQ;AAAA,aAAA,EACpC;AAAA;AAAA,SACF;AAAA,wBACA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAO,IAAA;AAAA,YACP,OAAA,EAAQ,OAAA;AAAA,YACR,IAAA,EAAK,MAAA;AAAA,YACL,SAAA,EAAU,QAAA;AAAA,YACV,KAAA,EAAM,iBAAA;AAAA,YAEN,QAAA,kBAAA,IAAA,CAAC,OAAE,IAAA,EAAM,IAAA,CAAK,KAAK,MAAA,EAAO,QAAA,EAAS,KAAI,YAAA,EACrC,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,MAAM,EAAA,EAAI,CAAA;AAAA,8BACxB,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAU,QAAA,EAAA,iBAAA,EAAe;AAAA,aAAA,EAC3C;AAAA;AAAA;AACF,OAAA,EACF,CAAA,GACE;AAAA,KAAA,EACN,CAAA;AAAA,wBACC,KAAA,EAAA,EAAI,SAAA,EAAU,8CACZ,QAAA,EAAA,CAAC,IAAA,uBACC,KAAA,EAAA,EAAI,SAAA,EAAU,yEAAwE,QAAA,EAAA,mBAAA,EAEvF,CAAA,GACE,SAAS,OAAA,mBACX,GAAA,CAAC,SAAI,GAAA,EAAK,SAAA,EAAW,WAAU,0BAAA,EAC7B,QAAA,kBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,6CAAA;AAAA,QACV,OAAO,EAAE,QAAA,EAAU,CAAA,EAAG,IAAA,GAAO,GAAG,CAAA,CAAA,CAAA,EAAI;AAAA,QACpC,aAAA,EAAe,sBAAA;AAAA,QACf,aAAA,EAAe,sBAAA;AAAA,QACf,WAAA,EAAa,qBAAA;AAAA,QACb,eAAA,EAAiB,qBAAA;AAAA,QAEjB,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gEAAA,EACZ,QAAA,EAAA;AAAA,UAAA,WAAA,KAAgB,OAAA,mBACf,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,wDAAA;AAAA,cACV,IAAA,EAAK,QAAA;AAAA,cACL,WAAA,EAAU,QAAA;AAAA,cACV,YAAA,EAAY,WAAA,KAAgB,OAAA,GAAU,qBAAA,GAAwB,eAAA;AAAA,cAE7D,QAAA,EAAA,WAAA,KAAgB,OAAA,mBACf,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAgC,QAAA,EAAA,qBAAA,EAAmB,CAAA,mBAEhE,GAAA,CAAC,OAAA,EAAA,EAAQ,IAAA,EAAM,EAAA,EAAI,WAAU,oCAAA,EAAqC;AAAA;AAAA,WAEtE,GACE,IAAA;AAAA,0BACJ,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAK,IAAA,CAAK,GAAA;AAAA,cACV,KAAK,IAAA,CAAK,IAAA;AAAA,cACV,SAAA,EAAW,EAAA;AAAA,gBACT,8EAAA;AAAA,gBACA,gBAAgB,OAAA,IAAW;AAAA,eAC7B;AAAA,cACA,SAAA,EAAW,KAAA;AAAA,cACX,MAAA,EAAQ,MAAM,cAAA,CAAe,OAAO,CAAA;AAAA,cACpC,OAAA,EAAS,MAAM,cAAA,CAAe,OAAO,CAAA;AAAA,cACrC,KAAA,EAAO;AAAA,gBACL,KAAA,EAAO,CAAA,EAAG,IAAA,GAAO,GAAG,CAAA,CAAA,CAAA;AAAA,gBACpB,QAAA,EAAU,MAAA;AAAA,gBACV,MAAA,EAAQ,WAAA,GAAe,QAAA,GAAW,UAAA,GAAa,MAAA,GAAU,SAAA;AAAA,gBACzD,WAAA,EAAa,cAAc,MAAA,GAAS;AAAA;AACtC;AAAA;AACF,SAAA,EACF;AAAA;AAAA,OAEJ,CAAA,GACE,IAAA,KAAS,KAAA,mBACX,GAAA,CAAC,YAAO,IAAA,EAAM,IAAA,CAAK,GAAA,EAAK,IAAA,EAAK,mBAAkB,SAAA,EAAU,eAAA,EACvD,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wEAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAwB,CAAA;AAAA,sBACtD,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA,6FAAA,EAEtD;AAAA,KAAA,EACF,CAAA,EACF,CAAA,mBAEA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wEAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAwB,CAAA;AAAA,sBACtD,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,wCAAA,EAAyC,QAAA,EAAA,gFAAA,EAEtD;AAAA,KAAA,EACF,CAAA,EAEJ;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ","file":"file-viewer-dialog.js","sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Download, ExternalLink, FileText, Loader2, Minus, Plus, RotateCcw } from \"lucide-react\";\nimport {\n Button,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogTitle,\n cn,\n} from \"../ui\";\n\nexport interface FileViewerFile {\n name: string;\n mimeType: string;\n sizeLabel?: string;\n url: string;\n}\n\nexport function FileViewerDialog({\n file,\n open,\n onOpenChange,\n}: {\n file: FileViewerFile | null;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [zoom, setZoom] = useState(1);\n const [dragging, setDragging] = useState(false);\n const [imageStatus, setImageStatus] = useState<\"loading\" | \"ready\" | \"error\">(\"loading\");\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const dragStateRef = useRef<{\n pointerId: number;\n startX: number;\n startY: number;\n scrollLeft: number;\n scrollTop: number;\n } | null>(null);\n\n useEffect(() => {\n if (open) setZoom(1);\n setImageStatus(\"loading\");\n }, [open, file?.url]);\n\n const kind = useMemo(() => {\n if (!file) return \"other\";\n if (file.mimeType.startsWith(\"image/\")) return \"image\";\n if (file.mimeType === \"application/pdf\" || file.name.toLowerCase().endsWith(\".pdf\")) return \"pdf\";\n return \"other\";\n }, [file]);\n\n const zoomPercent = Math.round(zoom * 100);\n const isDraggable = kind === \"image\" && zoom > 1;\n\n const handleImagePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n if (!isDraggable || !scrollRef.current) return;\n event.preventDefault();\n dragStateRef.current = {\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n scrollLeft: scrollRef.current.scrollLeft,\n scrollTop: scrollRef.current.scrollTop,\n };\n setDragging(true);\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const handleImagePointerMove = (event: React.PointerEvent<HTMLDivElement>) => {\n const state = dragStateRef.current;\n if (!state || state.pointerId !== event.pointerId || !scrollRef.current) return;\n scrollRef.current.scrollLeft = state.scrollLeft - (event.clientX - state.startX);\n scrollRef.current.scrollTop = state.scrollTop - (event.clientY - state.startY);\n };\n\n const handleImagePointerEnd = (event: React.PointerEvent<HTMLDivElement>) => {\n const state = dragStateRef.current;\n if (!state || state.pointerId !== event.pointerId) return;\n dragStateRef.current = null;\n setDragging(false);\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"flex h-[min(88vh,900px)] w-[min(96vw,1100px)] max-w-none flex-col gap-0 overflow-hidden rounded-xl border-border bg-card p-0\">\n <div className=\"flex shrink-0 flex-col gap-3 border-b border-border py-3 pl-4 pr-14 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"min-w-0 flex-1\">\n <ResponsiveDialogTitle className=\"truncate text-base font-semibold text-foreground\">\n {file?.name ?? \"File preview\"}\n </ResponsiveDialogTitle>\n {file?.sizeLabel ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{file.sizeLabel}</p>\n ) : null}\n </div>\n {file ? (\n <div className=\"flex shrink-0 flex-wrap items-center gap-1.5 lg:justify-end\">\n {kind === \"image\" ? (\n <div className=\"flex items-center gap-0.5 rounded-lg border border-border bg-background p-0.5\">\n <button\n type=\"button\"\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-40\"\n onClick={() => setZoom((value) => Math.max(0.25, Number((value - 0.25).toFixed(2))))}\n disabled={zoom <= 0.25}\n aria-label=\"Zoom out\"\n >\n <Minus size={14} />\n </button>\n <span className=\"min-w-11 text-center text-xs font-medium tabular-nums text-muted-foreground\">\n {zoomPercent}%\n </span>\n <button\n type=\"button\"\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-40\"\n onClick={() => setZoom((value) => Math.min(4, Number((value + 0.25).toFixed(2))))}\n disabled={zoom >= 4}\n aria-label=\"Zoom in\"\n >\n <Plus size={14} />\n </button>\n <button\n type=\"button\"\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={() => setZoom(1)}\n aria-label=\"Reset zoom\"\n >\n <RotateCcw size={14} />\n </button>\n </div>\n ) : null}\n <Button\n asChild\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-9\"\n title=\"Download\"\n >\n <a href={file.url} download={file.name}>\n <Download size={14} />\n <span className=\"sr-only\">Download</span>\n </a>\n </Button>\n <Button\n asChild\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-9\"\n title=\"Open in new tab\"\n >\n <a href={file.url} target=\"_blank\" rel=\"noreferrer\">\n <ExternalLink size={14} />\n <span className=\"sr-only\">Open in new tab</span>\n </a>\n </Button>\n </div>\n ) : null}\n </div>\n <div className=\"min-h-0 flex-1 overflow-hidden bg-muted/60\">\n {!file ? (\n <div className=\"flex h-full items-center justify-center text-sm text-muted-foreground\">\n No file selected.\n </div>\n ) : kind === \"image\" ? (\n <div ref={scrollRef} className=\"h-full overflow-auto p-4\">\n <div\n className=\"flex min-h-full items-center justify-center\"\n style={{ minWidth: `${zoom * 100}%` }}\n onPointerDown={handleImagePointerDown}\n onPointerMove={handleImagePointerMove}\n onPointerUp={handleImagePointerEnd}\n onPointerCancel={handleImagePointerEnd}\n >\n <div className=\"relative flex min-h-[240px] w-full items-center justify-center\">\n {imageStatus !== \"ready\" ? (\n <div\n className=\"absolute inset-0 z-10 flex items-center justify-center\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label={imageStatus === \"error\" ? \"Couldn't load image\" : \"Loading image\"}\n >\n {imageStatus === \"error\" ? (\n <p className=\"text-sm text-muted-foreground\">Couldn't load image</p>\n ) : (\n <Loader2 size={28} className=\"animate-spin text-muted-foreground\" />\n )}\n </div>\n ) : null}\n <img\n src={file.url}\n alt={file.name}\n className={cn(\n \"block shrink-0 select-none rounded-lg border border-border bg-card shadow-sm\",\n imageStatus !== \"ready\" && \"opacity-0\",\n )}\n draggable={false}\n onLoad={() => setImageStatus(\"ready\")}\n onError={() => setImageStatus(\"error\")}\n style={{\n width: `${zoom * 100}%`,\n maxWidth: \"none\",\n cursor: isDraggable ? (dragging ? \"grabbing\" : \"grab\") : \"default\",\n touchAction: isDraggable ? \"none\" : \"auto\",\n }}\n />\n </div>\n </div>\n </div>\n ) : kind === \"pdf\" ? (\n <object data={file.url} type=\"application/pdf\" className=\"h-full w-full\">\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <FileText size={34} className=\"text-muted-foreground\" />\n <p className=\"max-w-md text-sm text-muted-foreground\">\n This browser cannot preview the PDF inline. You can still download or open it in a new tab.\n </p>\n </div>\n </object>\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <FileText size={34} className=\"text-muted-foreground\" />\n <p className=\"max-w-md text-sm text-muted-foreground\">\n Preview is not available for this file type. Download or open it in a new tab.\n </p>\n </div>\n )}\n </div>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"]}
|
package/dist/floor-switcher.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from './chunk-
|
|
1
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from './chunk-H3CNZCYU.js';
|
|
2
2
|
import { Label } from './chunk-RV5PMZYZ.js';
|
|
3
3
|
import './chunk-L65F4EMK.js';
|
|
4
4
|
import './chunk-PBNBLCC2.js';
|
|
5
5
|
import './chunk-VVXGQKN7.js';
|
|
6
6
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from './chunk-7YCAAP43.js';
|
|
7
|
+
import './chunk-DC4QH6W2.js';
|
|
7
8
|
import { Input } from './chunk-LUB7QWGU.js';
|
|
8
9
|
import { Button } from './chunk-VHINHHZQ.js';
|
|
9
10
|
import { shellTopBarMutedIconClass, shellTopBarSecondaryButtonClass } from './chunk-FCY5FYJB.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/live-space/floor-switcher.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/live-space/floor-switcher.tsx"],"names":[],"mappings":"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","file":"floor-switcher.js","sourcesContent":["import { Check, ChevronDown, Layers, Plus } from \"lucide-react\";\nimport { shellTopBarMutedIconClass, shellTopBarSecondaryButtonClass } from \"../shell/shell-top-bar-chrome\";\nimport {\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n} from \"../ui\";\nimport { useEffect, useState } from \"react\";\n\nexport interface FloorSwitcherFloor {\n id: string;\n name: string;\n}\n\nexport function FloorSwitcher({\n floors,\n activeFloorId,\n onFloorChange,\n onAddFloor,\n}: {\n floors: FloorSwitcherFloor[];\n activeFloorId: string;\n onFloorChange: (floorId: string) => void;\n onAddFloor?: (name: string) => void;\n}) {\n const activeFloor = floors.find((f) => f.id === activeFloorId) ?? floors[0];\n const [addOpen, setAddOpen] = useState(false);\n const [name, setName] = useState(\"\");\n\n useEffect(() => {\n if (addOpen) {\n setName(`Floor ${floors.length + 1}`);\n }\n }, [addOpen, floors.length]);\n\n const handleAdd = () => {\n onAddFloor?.(name.trim() || `Floor ${floors.length + 1}`);\n setAddOpen(false);\n };\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n shellTopBarSecondaryButtonClass,\n \"min-w-0 max-w-[10rem] outline-none focus-visible:ring-2 focus-visible:ring-blue-500/30\",\n )}\n aria-label=\"Switch floor\"\n >\n <Layers size={12} className={cn(\"shrink-0\", shellTopBarMutedIconClass)} aria-hidden />\n <span className=\"truncate\">{activeFloor?.name ?? \"Floor\"}</span>\n <ChevronDown size={12} className={cn(\"shrink-0\", shellTopBarMutedIconClass)} aria-hidden />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n {floors.map((floor) => (\n <DropdownMenuItem\n key={floor.id}\n onClick={() => onFloorChange(floor.id)}\n className=\"flex items-center justify-between gap-2\"\n >\n <span className=\"truncate\">{floor.name}</span>\n {floor.id === activeFloorId ? (\n <Check size={14} className=\"shrink-0 text-blue-600\" aria-hidden />\n ) : (\n <span className=\"size-3.5 shrink-0\" aria-hidden />\n )}\n </DropdownMenuItem>\n ))}\n {onAddFloor ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem onClick={() => setAddOpen(true)}>\n <Plus size={14} className=\"mr-1.5\" />\n Add floor…\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n\n {onAddFloor ? (\n <Dialog open={addOpen} onOpenChange={setAddOpen}>\n <DialogContent className=\"sm:max-w-md border-border\">\n <DialogHeader>\n <DialogTitle>Add floor</DialogTitle>\n <DialogDescription>\n Create a new floor with its own resources and 2D layout.\n </DialogDescription>\n </DialogHeader>\n <div className=\"py-1\">\n <Label htmlFor=\"new-floor-name\">Name</Label>\n <Input\n id=\"new-floor-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Floor 2\"\n className=\"mt-2 h-9\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleAdd();\n }}\n />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setAddOpen(false)}>\n Cancel\n </Button>\n <Button type=\"button\" onClick={handleAdd}>\n Add floor\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n ) : null}\n </>\n );\n}\n"]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { useTheme } from './chunk-XU3EFSQX.js';
|
|
2
2
|
import './chunk-4Y5DBM6Z.js';
|
|
3
3
|
import { LIVE_RESOURCE_TYPE_META } from './chunk-ZIJQ7BXU.js';
|
|
4
|
-
import { Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverAnchor, PopoverContent } from './chunk-
|
|
4
|
+
import { Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverAnchor, PopoverContent } from './chunk-H3CNZCYU.js';
|
|
5
5
|
import './chunk-RV5PMZYZ.js';
|
|
6
6
|
import './chunk-L65F4EMK.js';
|
|
7
7
|
import './chunk-PBNBLCC2.js';
|
|
8
8
|
import './chunk-VVXGQKN7.js';
|
|
9
9
|
import './chunk-7YCAAP43.js';
|
|
10
|
+
import './chunk-DC4QH6W2.js';
|
|
10
11
|
import { PageListSearchField } from './chunk-H7EX6B6N.js';
|
|
11
12
|
import './chunk-LUB7QWGU.js';
|
|
12
13
|
import { Button } from './chunk-VHINHHZQ.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/live-space/layout-canvas-types.ts","../src/live-space/plan-color.ts","../src/live-space/layout-canvas-view.tsx"],"names":[],"mappings":"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","file":"layout-canvas-view.js","sourcesContent":["export type LayoutCanvasResourceType = \"desks\" | \"rooms\" | \"other\";\n\nexport interface LayoutCanvasRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface LayoutCanvasFloorLayout {\n placedItems: Record<string, LayoutCanvasRect>;\n bgImage: string | null;\n canvasWidth?: number;\n canvasHeight?: number;\n}\n\nexport const DEFAULT_CANVAS_WIDTH = 1200;\nexport const DEFAULT_CANVAS_HEIGHT = 900;\n\nexport interface LayoutCanvasPlanHint {\n id: string;\n name: string;\n color?: string;\n}\n","/** Hex colors offered as presets when creating/editing a plan. */\nexport const PLAN_COLOR_PRESETS = [\n \"#4285F4\",\n \"#10b981\",\n \"#06b6d4\",\n \"#f59e0b\",\n \"#ef4444\",\n \"#6366f1\",\n \"#a16207\",\n \"#64748b\",\n] as const;\n\nconst DEFAULT_PLAN_COLOR = PLAN_COLOR_PRESETS[0];\n\nconst HEX_RE = /^#[0-9A-Fa-f]{6}$/;\n\nexport function isPlanColorHex(value: string | undefined | null): value is string {\n return typeof value === \"string\" && HEX_RE.test(value);\n}\n\n/** Normalize stored/custom colors; fall back to a default when missing. */\nexport function resolvePlanColor(color: string | undefined | null): string {\n if (isPlanColorHex(color)) return color.toUpperCase();\n return DEFAULT_PLAN_COLOR;\n}\n\n/**\n * Soft badge / chip style from a plan hex: tinted background + saturated text.\n * Works for light surfaces; readable on dark UIs as well via alpha tint.\n */\nexport function planColorBadgeStyle(hex: string): {\n backgroundColor: string;\n color: string;\n} {\n const normalized = isPlanColorHex(hex) ? hex : DEFAULT_PLAN_COLOR;\n return {\n backgroundColor: `${normalized}1F`,\n color: normalized,\n };\n}\n\n/**\n * Subtle card wash + border from a plan hex, mixed with the theme card/border\n * so foreground text stays readable. Background is partly transparent so floor\n * plans show through underneath.\n */\nexport function planColorCardStyle(hex: string): {\n backgroundColor: string;\n borderColor: string;\n} {\n const normalized = isPlanColorHex(hex) ? hex : DEFAULT_PLAN_COLOR;\n return {\n backgroundColor: `color-mix(in srgb, ${normalized} 9%, color-mix(in srgb, var(--card) 78%, transparent))`,\n borderColor: `color-mix(in srgb, ${normalized} 28%, color-mix(in srgb, var(--border) 82%, transparent))`,\n };\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { Box, Calendar, Maximize2, Minus, Plus } from \"lucide-react\";\nimport {\n DEFAULT_CANVAS_HEIGHT,\n DEFAULT_CANVAS_WIDTH,\n type LayoutCanvasFloorLayout,\n type LayoutCanvasPlanHint,\n type LayoutCanvasResourceType,\n} from \"./layout-canvas-types\";\nimport { LIVE_RESOURCE_TYPE_META } from \"./live-resource-meta\";\nimport { planColorBadgeStyle, planColorCardStyle, resolvePlanColor } from \"./plan-color\";\nimport { PageListSearchField } from \"../shell/page-list-chrome\";\nimport {\n Button,\n cn,\n Popover,\n PopoverAnchor,\n PopoverContent,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../ui\";\nimport { useTheme } from \"../theme/theme-provider\";\n\ninterface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface LayoutCanvasViewRow {\n resource: {\n id: string;\n name: string;\n pricingPlanId: string;\n resourceType: LayoutCanvasResourceType;\n totalSlots?: number;\n };\n merged: { occupied: boolean; manual?: boolean; expectedFreeLabel?: string };\n plan?: LayoutCanvasPlanHint;\n}\n\nexport interface LayoutCanvasResourceQuickBook {\n /** When omitted, popover shows that booking is unavailable for this member. */\n onBook?: (resourceId: string) => void;\n /** Optional href for the book action (middle-click / fallback). */\n getBookingHref?: (resourceId: string) => string;\n}\n\nexport interface LayoutCanvasViewProps {\n layout: LayoutCanvasFloorLayout;\n rows: LayoutCanvasViewRow[];\n onResourceSelect?: (id: string) => void;\n /** Hover/tap popover with a quick book action (member live space). */\n resourceQuickBook?: LayoutCanvasResourceQuickBook;\n /** When set with `onSearchQueryChange`, shows a search bar and dims non-matching resources. */\n searchQuery?: string;\n onSearchQueryChange?: (value: string) => void;\n searchPlaceholder?: string;\n}\n\nexport function matchesCanvasResourceSearch(\n resourceName: string,\n planName: string | undefined,\n query: string,\n): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const name = resourceName.toLowerCase();\n const plan = planName?.toLowerCase() ?? \"\";\n return name.includes(q) || plan.includes(q);\n}\n\nfunction resourceMatchesSearch(row: LayoutCanvasViewRow, query: string): boolean {\n return matchesCanvasResourceSearch(row.resource.name, row.plan?.name, query);\n}\n\nconst CLICK_THRESHOLD_PX = 5;\nconst POPOVER_CLOSE_DELAY_MS = 250;\nconst CANVAS_QUICK_BOOK_POPOVER_CLASS =\n \"z-[100] w-56 border-border bg-card p-3 text-card-foreground shadow-lg\";\n\nfunction usePrefersHover() {\n const [prefersHover, setPrefersHover] = useState(\n () => typeof window !== \"undefined\" && window.matchMedia(\"(hover: hover)\").matches,\n );\n\n useEffect(() => {\n const mql = window.matchMedia(\"(hover: hover)\");\n const onChange = () => setPrefersHover(mql.matches);\n mql.addEventListener(\"change\", onChange);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return prefersHover;\n}\n\ntype PopoverHoverHandlers = {\n prefersHover: boolean;\n clearClose: () => void;\n scheduleClose: () => void;\n};\n\ntype ResourceQuickBookConfig = {\n quickBook: LayoutCanvasResourceQuickBook;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n hover: PopoverHoverHandlers;\n onOpen: () => void;\n onToggle: () => void;\n shouldIgnoreToggle: () => boolean;\n};\n\nfunction isCanvasResourceTarget(target: EventTarget | null): boolean {\n return target instanceof HTMLElement && target.closest(\"[data-canvas-resource]\") != null;\n}\n\nfunction ResourceQuickBookPopoverContent({\n row,\n onBook,\n getBookingHref,\n}: {\n row: LayoutCanvasViewRow;\n onBook?: (resourceId: string) => void;\n getBookingHref?: (resourceId: string) => string;\n}) {\n const { resource, merged } = row;\n const meta = LIVE_RESOURCE_TYPE_META[resource.resourceType];\n const TypeIcon = meta.Icon;\n const bookingHref = getBookingHref?.(resource.id);\n\n const handleBookPointerDown = (e: ReactPointerEvent) => {\n // Radix popover can close before click fires; book on pointerdown instead.\n e.preventDefault();\n e.stopPropagation();\n onBook?.(resource.id);\n };\n\n const bookLabel = (\n <>\n <Calendar size={14} />\n Book\n </>\n );\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span\n className={cn(\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border\",\n meta.iconTile,\n )}\n aria-hidden\n >\n <TypeIcon size={16} strokeWidth={1.75} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold leading-snug text-card-foreground\">\n {resource.name}\n </p>\n <span\n className={cn(\n \"mt-1.5 inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] font-medium\",\n merged.occupied\n ? \"border-red-100 bg-red-50 text-red-700 dark:border-red-900/50 dark:bg-red-950/50 dark:text-red-300\"\n : \"border-emerald-100 bg-emerald-50 text-emerald-800 dark:border-emerald-900/50 dark:bg-emerald-950/50 dark:text-emerald-300\",\n )}\n >\n <span\n className={cn(\n \"h-1.5 w-1.5 shrink-0 rounded-full\",\n merged.occupied ? \"bg-red-500\" : \"bg-emerald-500\",\n )}\n />\n {merged.occupied ? \"Occupied\" : \"Free\"}\n </span>\n {merged.occupied && merged.expectedFreeLabel && merged.expectedFreeLabel !== \"—\" ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{merged.expectedFreeLabel}</p>\n ) : null}\n </div>\n </div>\n {onBook ? (\n bookingHref ? (\n <Button asChild size=\"sm\" className=\"w-full\">\n <a href={bookingHref} onPointerDown={handleBookPointerDown}>\n {bookLabel}\n </a>\n </Button>\n ) : (\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"w-full\"\n onPointerDown={handleBookPointerDown}\n >\n {bookLabel}\n </Button>\n )\n ) : (\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n Booking is not available for your account.\n </p>\n )}\n </div>\n );\n}\n\nconst MIN_ZOOM = 0.12;\nconst MAX_ZOOM = 4;\nconst MIN_CARD_W = 90;\nconst MIN_CARD_H = 56;\nconst CANVAS_GRID_SIZE = 40;\n\nfunction canvasGridBackground(isDark: boolean): string {\n const line = isDark ? \"oklch(0.35 0 0)\" : \"#e5e7eb\";\n return (\n `linear-gradient(to right, ${line} 1px, transparent 1px),` +\n `linear-gradient(to bottom, ${line} 1px, transparent 1px)`\n );\n}\n\nconst CANVAS_GRID_BG_SIZE = `${CANVAS_GRID_SIZE}px ${CANVAS_GRID_SIZE}px`;\n\nfunction isFloorResourceType(type: LayoutCanvasResourceType): boolean {\n return type === \"desks\" || type === \"rooms\";\n}\n\nfunction poolSlotsLabel(totalSlots: number | undefined): string | null {\n if (totalSlots == null) return null;\n return `${totalSlots} slot${totalSlots !== 1 ? \"s\" : \"\"}`;\n}\n\nfunction PoolResourceChip({\n row,\n onClick,\n quickBookConfig,\n searchQuery,\n isMatch,\n}: {\n row: LayoutCanvasViewRow;\n onClick?: () => void;\n quickBookConfig?: ResourceQuickBookConfig;\n searchQuery: string;\n isMatch: boolean;\n}) {\n const { resource, merged, plan } = row;\n const planColor = resolvePlanColor(plan?.color);\n const slots = poolSlotsLabel(resource.totalSlots);\n const searchActive = searchQuery.trim().length > 0;\n\n const chip = (\n <button\n type=\"button\"\n data-canvas-resource=\"\"\n onClick={(e) => {\n e.stopPropagation();\n if (quickBookConfig) {\n if (!quickBookConfig.shouldIgnoreToggle()) quickBookConfig.onToggle();\n } else onClick?.();\n }}\n onMouseEnter={() => {\n if (quickBookConfig?.hover.prefersHover) {\n quickBookConfig.hover.clearClose();\n quickBookConfig.onOpen();\n }\n }}\n onMouseLeave={() => {\n if (quickBookConfig?.hover.prefersHover) quickBookConfig.hover.scheduleClose();\n }}\n className={cn(\n \"inline-flex items-center gap-2 shrink-0 px-3 py-1.5 rounded-lg border hover:bg-accent transition-colors text-left\",\n searchActive && !isMatch && \"opacity-40 saturate-50\",\n )}\n style={planColorCardStyle(planColor)}\n >\n <div\n className=\"w-6 h-6 rounded-md flex items-center justify-center shrink-0\"\n style={planColorBadgeStyle(planColor)}\n >\n <Box size={12} />\n </div>\n <span className=\"text-xs font-medium text-foreground whitespace-nowrap\">{resource.name}</span>\n <span\n className={cn(\n \"h-2 w-2 rounded-full shrink-0\",\n merged.occupied ? \"bg-red-500\" : \"bg-emerald-500\",\n )}\n />\n {slots && (\n <span className=\"text-[10px] text-muted-foreground whitespace-nowrap\">{slots}</span>\n )}\n </button>\n );\n\n if (!quickBookConfig) return chip;\n\n return (\n <Popover\n modal={false}\n open={quickBookConfig.open}\n onOpenChange={quickBookConfig.onOpenChange}\n >\n <PopoverAnchor asChild>{chip}</PopoverAnchor>\n <PopoverContent\n side=\"top\"\n align=\"center\"\n sideOffset={6}\n className={CANVAS_QUICK_BOOK_POPOVER_CLASS}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onMouseEnter={quickBookConfig.hover.clearClose}\n onMouseLeave={quickBookConfig.hover.scheduleClose}\n >\n <ResourceQuickBookPopoverContent\n row={row}\n onBook={quickBookConfig.quickBook.onBook}\n getBookingHref={quickBookConfig.quickBook.getBookingHref}\n />\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction PlacedCardView({\n id,\n rect,\n row,\n onSelect,\n quickBookConfig,\n searchQuery,\n isMatch,\n}: {\n id: string;\n rect: Rect;\n row: LayoutCanvasViewRow;\n onSelect?: (id: string) => void;\n quickBookConfig?: ResourceQuickBookConfig;\n searchQuery: string;\n isMatch: boolean;\n}) {\n const { resource, merged, plan } = row;\n const planColor = resolvePlanColor(plan?.color);\n const w = Math.max(rect.w, MIN_CARD_W);\n const h = Math.max(rect.h, MIN_CARD_H);\n const statusLabel = merged.occupied ? \"Occupied\" : merged.manual ? \"Vacant\" : \"Free\";\n const pointerStart = useRef<{ x: number; y: number } | null>(null);\n const searchActive = searchQuery.trim().length > 0;\n\n const handlePointerDown = (e: ReactPointerEvent) => {\n if (e.button !== 0) return;\n // Keep viewport pan/zoom from capturing the pointer before tap completes.\n e.stopPropagation();\n pointerStart.current = { x: e.clientX, y: e.clientY };\n };\n\n const handlePointerUp = (e: ReactPointerEvent) => {\n e.stopPropagation();\n const start = pointerStart.current;\n pointerStart.current = null;\n if (!start || quickBookConfig) return;\n if (Math.hypot(e.clientX - start.x, e.clientY - start.y) < CLICK_THRESHOLD_PX) {\n onSelect?.(id);\n }\n };\n\n const statusDot = (\n <span\n className={cn(\n \"block h-2.5 w-2.5 rounded-full ring-2 ring-white shadow-sm\",\n merged.occupied ? \"bg-red-500 animate-pulse\" : \"bg-emerald-500\",\n )}\n aria-label={statusLabel}\n />\n );\n\n const card = (\n <button\n type=\"button\"\n data-canvas-resource=\"\"\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y,\n width: w,\n height: h,\n touchAction: \"manipulation\",\n ...planColorCardStyle(planColor),\n }}\n className={cn(\n \"rounded-xl border shadow-sm overflow-hidden select-none text-left cursor-pointer hover:shadow-md transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40\",\n searchActive && !isMatch && \"opacity-40 saturate-50\",\n )}\n onPointerDown={handlePointerDown}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onClick={(e) => {\n e.stopPropagation();\n if (quickBookConfig && !quickBookConfig.shouldIgnoreToggle()) {\n quickBookConfig.onToggle();\n }\n }}\n onMouseEnter={() => {\n if (quickBookConfig?.hover.prefersHover) {\n quickBookConfig.hover.clearClose();\n quickBookConfig.onOpen();\n }\n }}\n onMouseLeave={() => {\n if (quickBookConfig?.hover.prefersHover) quickBookConfig.hover.scheduleClose();\n }}\n >\n <div className=\"absolute top-2 right-2 z-10 pointer-events-none\">\n {quickBookConfig ? (\n statusDot\n ) : (\n <Tooltip>\n <TooltipTrigger asChild>{statusDot}</TooltipTrigger>\n <TooltipContent side=\"top\" className=\"text-xs\">\n {statusLabel}\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n\n <div className=\"absolute inset-0 flex flex-col justify-between p-3 pointer-events-none\">\n <div className=\"min-w-0 pr-4\">\n <span\n className=\"text-xs font-semibold text-foreground leading-tight line-clamp-2\"\n style={{ wordBreak: \"break-word\" }}\n >\n {resource.name}\n </span>\n </div>\n\n {plan && (\n <span\n className=\"text-[9px] font-medium px-1.5 py-0.5 rounded-md self-start\"\n style={planColorBadgeStyle(planColor)}\n >\n {plan.name}\n </span>\n )}\n </div>\n </button>\n );\n\n if (!quickBookConfig) return card;\n\n return (\n <Popover\n modal={false}\n open={quickBookConfig.open}\n onOpenChange={quickBookConfig.onOpenChange}\n >\n <PopoverAnchor asChild>{card}</PopoverAnchor>\n <PopoverContent\n side=\"top\"\n align=\"center\"\n sideOffset={6}\n className={CANVAS_QUICK_BOOK_POPOVER_CLASS}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onMouseEnter={quickBookConfig.hover.clearClose}\n onMouseLeave={quickBookConfig.hover.scheduleClose}\n >\n <ResourceQuickBookPopoverContent\n row={row}\n onBook={quickBookConfig.quickBook.onBook}\n getBookingHref={quickBookConfig.quickBook.getBookingHref}\n />\n </PopoverContent>\n </Popover>\n );\n}\n\ntype PanGesture = {\n type: \"pan\";\n startMX: number;\n startMY: number;\n startPanX: number;\n startPanY: number;\n};\n\nexport function LayoutCanvasView({\n layout,\n rows,\n onResourceSelect,\n resourceQuickBook,\n searchQuery = \"\",\n onSearchQueryChange,\n searchPlaceholder = \"Search resources…\",\n}: LayoutCanvasViewProps) {\n const { resolvedTheme } = useTheme();\n const isDarkCanvas = resolvedTheme === \"dark\";\n const { placedItems, bgImage } = layout;\n const prefersHover = usePrefersHover();\n\n const canvasSize = useMemo(\n () => ({\n w: layout.canvasWidth ?? DEFAULT_CANVAS_WIDTH,\n h: layout.canvasHeight ?? DEFAULT_CANVAS_HEIGHT,\n }),\n [layout.canvasWidth, layout.canvasHeight],\n );\n\n const [zoom, setZoom] = useState(0.5);\n const [pan, setPan] = useState({ x: 40, y: 40 });\n const [isPanning, setIsPanning] = useState(false);\n const [openResourceId, setOpenResourceId] = useState<string | null>(null);\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const gestureRef = useRef<PanGesture | null>(null);\n const zoomRef = useRef(zoom);\n const panRef = useRef(pan);\n const popoverCloseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const suppressResourceToggleRef = useRef(false);\n\n const clearPopoverCloseTimer = useCallback(() => {\n if (popoverCloseTimerRef.current) {\n clearTimeout(popoverCloseTimerRef.current);\n popoverCloseTimerRef.current = null;\n }\n }, []);\n\n const schedulePopoverClose = useCallback(() => {\n clearPopoverCloseTimer();\n popoverCloseTimerRef.current = setTimeout(() => {\n setOpenResourceId(null);\n popoverCloseTimerRef.current = null;\n }, POPOVER_CLOSE_DELAY_MS);\n }, [clearPopoverCloseTimer]);\n\n const popoverHover = useMemo<PopoverHoverHandlers>(\n () => ({\n prefersHover,\n clearClose: clearPopoverCloseTimer,\n scheduleClose: schedulePopoverClose,\n }),\n [prefersHover, clearPopoverCloseTimer, schedulePopoverClose],\n );\n\n const openPopover = useCallback(\n (id: string) => {\n clearPopoverCloseTimer();\n setOpenResourceId(id);\n },\n [clearPopoverCloseTimer],\n );\n\n const togglePopover = useCallback(\n (id: string) => {\n clearPopoverCloseTimer();\n setOpenResourceId((current) => (current === id ? null : id));\n },\n [clearPopoverCloseTimer],\n );\n\n useEffect(() => () => clearPopoverCloseTimer(), [clearPopoverCloseTimer]);\n\n useEffect(() => {\n zoomRef.current = zoom;\n }, [zoom]);\n useEffect(() => {\n panRef.current = pan;\n }, [pan]);\n\n const rowById = useMemo(() => new Map(rows.map((r) => [r.resource.id, r])), [rows]);\n const otherRows = useMemo(\n () => rows.filter((r) => r.resource.resourceType === \"other\"),\n [rows],\n );\n\n const fitCanvas = useCallback(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n const vpRect = vp.getBoundingClientRect();\n const newZoom = Math.max(\n MIN_ZOOM,\n Math.min(\n MAX_ZOOM,\n Math.min((vpRect.width - 80) / canvasSize.w, (vpRect.height - 80) / canvasSize.h),\n ),\n );\n setPan({\n x: (vpRect.width - canvasSize.w * newZoom) / 2,\n y: (vpRect.height - canvasSize.h * newZoom) / 2,\n });\n setZoom(newZoom);\n }, [canvasSize.h, canvasSize.w]);\n\n useEffect(() => {\n fitCanvas();\n }, [fitCanvas]);\n\n useEffect(() => {\n const el = viewportRef.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const vpRect = el.getBoundingClientRect();\n const mx = e.clientX - vpRect.left;\n const my = e.clientY - vpRect.top;\n const factor = e.deltaY < 0 ? 1.08 : 1 / 1.08;\n const curZ = zoomRef.current;\n const newZ = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, curZ * factor));\n const curP = panRef.current;\n setZoom(newZ);\n setPan({\n x: mx - (mx - curP.x) * (newZ / curZ),\n y: my - (my - curP.y) * (newZ / curZ),\n });\n };\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n }, []);\n\n const stepZoom = (delta: number) => {\n const vp = viewportRef.current;\n const curZ = zoomRef.current;\n const newZ = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, curZ + delta));\n if (vp) {\n const vpRect = vp.getBoundingClientRect();\n const cx = vpRect.width / 2;\n const cy = vpRect.height / 2;\n const curP = panRef.current;\n setPan({\n x: cx - (cx - curP.x) * (newZ / curZ),\n y: cy - (cy - curP.y) * (newZ / curZ),\n });\n }\n setZoom(newZ);\n };\n\n useEffect(() => {\n const onKeyDown = (e: KeyboardEvent) => {\n const tag = (e.target as HTMLElement)?.tagName;\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return;\n if (e.key === \"+\" || e.key === \"=\") {\n e.preventDefault();\n stepZoom(0.15);\n } else if (e.key === \"-\" || e.key === \"_\") {\n e.preventDefault();\n stepZoom(-0.15);\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n });\n\n const handleViewportPointerDown = (e: React.PointerEvent) => {\n if (e.button !== 0 && e.button !== 1) return;\n if (isCanvasResourceTarget(e.target)) return;\n clearPopoverCloseTimer();\n setOpenResourceId(null);\n e.preventDefault();\n e.currentTarget.setPointerCapture(e.pointerId);\n setIsPanning(true);\n gestureRef.current = {\n type: \"pan\",\n startMX: e.clientX,\n startMY: e.clientY,\n startPanX: panRef.current.x,\n startPanY: panRef.current.y,\n };\n };\n\n const handleViewportPointerMove = (e: React.PointerEvent) => {\n const g = gestureRef.current;\n if (g?.type !== \"pan\") return;\n setPan({\n x: g.startPanX + (e.clientX - g.startMX),\n y: g.startPanY + (e.clientY - g.startMY),\n });\n };\n\n const handleViewportPointerUp = () => {\n if (gestureRef.current?.type === \"pan\") {\n gestureRef.current = null;\n setIsPanning(false);\n }\n };\n\n const handleSelect = (id: string) => onResourceSelect?.(id);\n\n const quickBookConfigFor = useCallback(\n (resourceId: string): ResourceQuickBookConfig | undefined => {\n if (!resourceQuickBook) return undefined;\n const wrappedOnBook = resourceQuickBook.onBook\n ? (id: string) => {\n suppressResourceToggleRef.current = true;\n clearPopoverCloseTimer();\n setOpenResourceId(null);\n resourceQuickBook.onBook?.(id);\n window.setTimeout(() => {\n suppressResourceToggleRef.current = false;\n }, 400);\n }\n : undefined;\n\n return {\n quickBook: {\n ...resourceQuickBook,\n onBook: wrappedOnBook,\n },\n open: openResourceId === resourceId,\n onOpenChange: (open) => {\n clearPopoverCloseTimer();\n setOpenResourceId(open ? resourceId : null);\n },\n hover: popoverHover,\n onOpen: () => openPopover(resourceId),\n onToggle: () => togglePopover(resourceId),\n shouldIgnoreToggle: () => suppressResourceToggleRef.current,\n };\n },\n [\n resourceQuickBook,\n openResourceId,\n clearPopoverCloseTimer,\n popoverHover,\n openPopover,\n togglePopover,\n ],\n );\n\n return (\n <div className=\"flex flex-col flex-1 min-h-0 bg-card\">\n <div className=\"flex flex-wrap items-center gap-2 p-2 border-b border-border bg-card shrink-0\">\n {onSearchQueryChange != null ? (\n <PageListSearchField\n value={searchQuery}\n onChange={onSearchQueryChange}\n placeholder={searchPlaceholder}\n className=\"min-w-0 flex-1 max-w-md h-9\"\n />\n ) : null}\n <div className=\"flex items-center gap-1 shrink-0 ml-auto\">\n <button\n type=\"button\"\n onClick={() => stepZoom(-0.15)}\n className=\"w-7 h-7 rounded-lg border border-border bg-card flex items-center justify-center text-muted-foreground hover:bg-accent transition-colors\"\n aria-label=\"Zoom out\"\n >\n <Minus size={12} />\n </button>\n <span className=\"text-xs text-muted-foreground w-10 text-center tabular-nums select-none\">\n {Math.round(zoom * 100)}%\n </span>\n <button\n type=\"button\"\n onClick={() => stepZoom(0.15)}\n className=\"w-7 h-7 rounded-lg border border-border bg-card flex items-center justify-center text-muted-foreground hover:bg-accent transition-colors\"\n aria-label=\"Zoom in\"\n >\n <Plus size={12} />\n </button>\n <button\n type=\"button\"\n onClick={fitCanvas}\n className=\"inline-flex items-center gap-1 px-2.5 h-7 rounded-lg border border-border bg-card text-xs text-muted-foreground hover:bg-accent transition-colors\"\n >\n <Maximize2 size={11} />\n Fit\n </button>\n </div>\n </div>\n\n <div className=\"flex flex-col flex-1 min-w-0 min-h-0\">\n <div\n ref={viewportRef}\n tabIndex={0}\n className=\"flex-1 min-h-[420px] overflow-hidden relative bg-card outline-none\"\n style={{ cursor: isPanning ? \"grabbing\" : \"grab\" }}\n onPointerDown={handleViewportPointerDown}\n onPointerMove={handleViewportPointerMove}\n onPointerUp={handleViewportPointerUp}\n onPointerCancel={handleViewportPointerUp}\n >\n <div\n style={{\n position: \"absolute\",\n transformOrigin: \"0px 0px\",\n transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,\n width: canvasSize.w,\n height: canvasSize.h,\n backgroundImage: bgImage ? \"none\" : canvasGridBackground(isDarkCanvas),\n backgroundSize: bgImage ? \"auto\" : CANVAS_GRID_BG_SIZE,\n backgroundColor: \"var(--card)\",\n boxShadow: isDarkCanvas\n ? \"0 2px 16px rgba(0,0,0,0.45)\"\n : \"0 2px 16px rgba(0,0,0,0.12)\",\n }}\n >\n {bgImage && (\n <img\n src={bgImage}\n alt=\"Floor plan\"\n draggable={false}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n }}\n />\n )}\n\n {Object.entries(placedItems).map(([id, rect]) => {\n const row = rowById.get(id);\n if (!row || !isFloorResourceType(row.resource.resourceType)) return null;\n return (\n <PlacedCardView\n key={id}\n id={id}\n rect={rect as Rect}\n row={row}\n onSelect={resourceQuickBook ? undefined : handleSelect}\n quickBookConfig={quickBookConfigFor(id)}\n searchQuery={searchQuery}\n isMatch={resourceMatchesSearch(row, searchQuery)}\n />\n );\n })}\n </div>\n </div>\n\n {otherRows.length > 0 && (\n <div className=\"shrink-0 border-t border-border bg-card px-4 py-2.5\">\n <div className=\"flex items-center gap-2 overflow-x-auto pb-0.5\">\n {otherRows.map((row) => {\n const resourceId = row.resource.id;\n return (\n <PoolResourceChip\n key={resourceId}\n row={row}\n onClick={resourceQuickBook ? undefined : () => handleSelect(resourceId)}\n quickBookConfig={quickBookConfigFor(resourceId)}\n searchQuery={searchQuery}\n isMatch={resourceMatchesSearch(row, searchQuery)}\n />\n );\n })}\n </div>\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/live-space/layout-canvas-types.ts","../src/live-space/plan-color.ts","../src/live-space/layout-canvas-view.tsx"],"names":[],"mappings":"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","file":"layout-canvas-view.js","sourcesContent":["export type LayoutCanvasResourceType = \"desks\" | \"rooms\" | \"other\";\n\nexport interface LayoutCanvasRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface LayoutCanvasFloorLayout {\n placedItems: Record<string, LayoutCanvasRect>;\n bgImage: string | null;\n canvasWidth?: number;\n canvasHeight?: number;\n}\n\nexport const DEFAULT_CANVAS_WIDTH = 1200;\nexport const DEFAULT_CANVAS_HEIGHT = 900;\n\nexport interface LayoutCanvasPlanHint {\n id: string;\n name: string;\n color?: string;\n}\n","/** Hex colors offered as presets when creating/editing a plan. */\nexport const PLAN_COLOR_PRESETS = [\n \"#4285F4\",\n \"#10b981\",\n \"#06b6d4\",\n \"#f59e0b\",\n \"#ef4444\",\n \"#6366f1\",\n \"#a16207\",\n \"#64748b\",\n] as const;\n\nconst DEFAULT_PLAN_COLOR = PLAN_COLOR_PRESETS[0];\n\nconst HEX_RE = /^#[0-9A-Fa-f]{6}$/;\n\nexport function isPlanColorHex(value: string | undefined | null): value is string {\n return typeof value === \"string\" && HEX_RE.test(value);\n}\n\n/** Normalize stored/custom colors; fall back to a default when missing. */\nexport function resolvePlanColor(color: string | undefined | null): string {\n if (isPlanColorHex(color)) return color.toUpperCase();\n return DEFAULT_PLAN_COLOR;\n}\n\n/**\n * Soft badge / chip style from a plan hex: tinted background + saturated text.\n * Works for light surfaces; readable on dark UIs as well via alpha tint.\n */\nexport function planColorBadgeStyle(hex: string): {\n backgroundColor: string;\n color: string;\n} {\n const normalized = isPlanColorHex(hex) ? hex : DEFAULT_PLAN_COLOR;\n return {\n backgroundColor: `${normalized}1F`,\n color: normalized,\n };\n}\n\n/**\n * Subtle card wash + border from a plan hex, mixed with the theme card/border\n * so foreground text stays readable. Background is partly transparent so floor\n * plans show through underneath.\n */\nexport function planColorCardStyle(hex: string): {\n backgroundColor: string;\n borderColor: string;\n} {\n const normalized = isPlanColorHex(hex) ? hex : DEFAULT_PLAN_COLOR;\n return {\n backgroundColor: `color-mix(in srgb, ${normalized} 9%, color-mix(in srgb, var(--card) 78%, transparent))`,\n borderColor: `color-mix(in srgb, ${normalized} 28%, color-mix(in srgb, var(--border) 82%, transparent))`,\n };\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { Box, Calendar, Maximize2, Minus, Plus } from \"lucide-react\";\nimport {\n DEFAULT_CANVAS_HEIGHT,\n DEFAULT_CANVAS_WIDTH,\n type LayoutCanvasFloorLayout,\n type LayoutCanvasPlanHint,\n type LayoutCanvasResourceType,\n} from \"./layout-canvas-types\";\nimport { LIVE_RESOURCE_TYPE_META } from \"./live-resource-meta\";\nimport { planColorBadgeStyle, planColorCardStyle, resolvePlanColor } from \"./plan-color\";\nimport { PageListSearchField } from \"../shell/page-list-chrome\";\nimport {\n Button,\n cn,\n Popover,\n PopoverAnchor,\n PopoverContent,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../ui\";\nimport { useTheme } from \"../theme/theme-provider\";\n\ninterface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface LayoutCanvasViewRow {\n resource: {\n id: string;\n name: string;\n pricingPlanId: string;\n resourceType: LayoutCanvasResourceType;\n totalSlots?: number;\n };\n merged: { occupied: boolean; manual?: boolean; expectedFreeLabel?: string };\n plan?: LayoutCanvasPlanHint;\n}\n\nexport interface LayoutCanvasResourceQuickBook {\n /** When omitted, popover shows that booking is unavailable for this member. */\n onBook?: (resourceId: string) => void;\n /** Optional href for the book action (middle-click / fallback). */\n getBookingHref?: (resourceId: string) => string;\n}\n\nexport interface LayoutCanvasViewProps {\n layout: LayoutCanvasFloorLayout;\n rows: LayoutCanvasViewRow[];\n onResourceSelect?: (id: string) => void;\n /** Hover/tap popover with a quick book action (member live space). */\n resourceQuickBook?: LayoutCanvasResourceQuickBook;\n /** When set with `onSearchQueryChange`, shows a search bar and dims non-matching resources. */\n searchQuery?: string;\n onSearchQueryChange?: (value: string) => void;\n searchPlaceholder?: string;\n}\n\nexport function matchesCanvasResourceSearch(\n resourceName: string,\n planName: string | undefined,\n query: string,\n): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const name = resourceName.toLowerCase();\n const plan = planName?.toLowerCase() ?? \"\";\n return name.includes(q) || plan.includes(q);\n}\n\nfunction resourceMatchesSearch(row: LayoutCanvasViewRow, query: string): boolean {\n return matchesCanvasResourceSearch(row.resource.name, row.plan?.name, query);\n}\n\nconst CLICK_THRESHOLD_PX = 5;\nconst POPOVER_CLOSE_DELAY_MS = 250;\nconst CANVAS_QUICK_BOOK_POPOVER_CLASS =\n \"z-[100] w-56 border-border bg-card p-3 text-card-foreground shadow-lg\";\n\nfunction usePrefersHover() {\n const [prefersHover, setPrefersHover] = useState(\n () => typeof window !== \"undefined\" && window.matchMedia(\"(hover: hover)\").matches,\n );\n\n useEffect(() => {\n const mql = window.matchMedia(\"(hover: hover)\");\n const onChange = () => setPrefersHover(mql.matches);\n mql.addEventListener(\"change\", onChange);\n return () => mql.removeEventListener(\"change\", onChange);\n }, []);\n\n return prefersHover;\n}\n\ntype PopoverHoverHandlers = {\n prefersHover: boolean;\n clearClose: () => void;\n scheduleClose: () => void;\n};\n\ntype ResourceQuickBookConfig = {\n quickBook: LayoutCanvasResourceQuickBook;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n hover: PopoverHoverHandlers;\n onOpen: () => void;\n onToggle: () => void;\n shouldIgnoreToggle: () => boolean;\n};\n\nfunction isCanvasResourceTarget(target: EventTarget | null): boolean {\n return target instanceof HTMLElement && target.closest(\"[data-canvas-resource]\") != null;\n}\n\nfunction ResourceQuickBookPopoverContent({\n row,\n onBook,\n getBookingHref,\n}: {\n row: LayoutCanvasViewRow;\n onBook?: (resourceId: string) => void;\n getBookingHref?: (resourceId: string) => string;\n}) {\n const { resource, merged } = row;\n const meta = LIVE_RESOURCE_TYPE_META[resource.resourceType];\n const TypeIcon = meta.Icon;\n const bookingHref = getBookingHref?.(resource.id);\n\n const handleBookPointerDown = (e: ReactPointerEvent) => {\n // Radix popover can close before click fires; book on pointerdown instead.\n e.preventDefault();\n e.stopPropagation();\n onBook?.(resource.id);\n };\n\n const bookLabel = (\n <>\n <Calendar size={14} />\n Book\n </>\n );\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <span\n className={cn(\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border\",\n meta.iconTile,\n )}\n aria-hidden\n >\n <TypeIcon size={16} strokeWidth={1.75} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold leading-snug text-card-foreground\">\n {resource.name}\n </p>\n <span\n className={cn(\n \"mt-1.5 inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] font-medium\",\n merged.occupied\n ? \"border-red-100 bg-red-50 text-red-700 dark:border-red-900/50 dark:bg-red-950/50 dark:text-red-300\"\n : \"border-emerald-100 bg-emerald-50 text-emerald-800 dark:border-emerald-900/50 dark:bg-emerald-950/50 dark:text-emerald-300\",\n )}\n >\n <span\n className={cn(\n \"h-1.5 w-1.5 shrink-0 rounded-full\",\n merged.occupied ? \"bg-red-500\" : \"bg-emerald-500\",\n )}\n />\n {merged.occupied ? \"Occupied\" : \"Free\"}\n </span>\n {merged.occupied && merged.expectedFreeLabel && merged.expectedFreeLabel !== \"—\" ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">{merged.expectedFreeLabel}</p>\n ) : null}\n </div>\n </div>\n {onBook ? (\n bookingHref ? (\n <Button asChild size=\"sm\" className=\"w-full\">\n <a href={bookingHref} onPointerDown={handleBookPointerDown}>\n {bookLabel}\n </a>\n </Button>\n ) : (\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"w-full\"\n onPointerDown={handleBookPointerDown}\n >\n {bookLabel}\n </Button>\n )\n ) : (\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n Booking is not available for your account.\n </p>\n )}\n </div>\n );\n}\n\nconst MIN_ZOOM = 0.12;\nconst MAX_ZOOM = 4;\nconst MIN_CARD_W = 90;\nconst MIN_CARD_H = 56;\nconst CANVAS_GRID_SIZE = 40;\n\nfunction canvasGridBackground(isDark: boolean): string {\n const line = isDark ? \"oklch(0.35 0 0)\" : \"#e5e7eb\";\n return (\n `linear-gradient(to right, ${line} 1px, transparent 1px),` +\n `linear-gradient(to bottom, ${line} 1px, transparent 1px)`\n );\n}\n\nconst CANVAS_GRID_BG_SIZE = `${CANVAS_GRID_SIZE}px ${CANVAS_GRID_SIZE}px`;\n\nfunction isFloorResourceType(type: LayoutCanvasResourceType): boolean {\n return type === \"desks\" || type === \"rooms\";\n}\n\nfunction poolSlotsLabel(totalSlots: number | undefined): string | null {\n if (totalSlots == null) return null;\n return `${totalSlots} slot${totalSlots !== 1 ? \"s\" : \"\"}`;\n}\n\nfunction PoolResourceChip({\n row,\n onClick,\n quickBookConfig,\n searchQuery,\n isMatch,\n}: {\n row: LayoutCanvasViewRow;\n onClick?: () => void;\n quickBookConfig?: ResourceQuickBookConfig;\n searchQuery: string;\n isMatch: boolean;\n}) {\n const { resource, merged, plan } = row;\n const planColor = resolvePlanColor(plan?.color);\n const slots = poolSlotsLabel(resource.totalSlots);\n const searchActive = searchQuery.trim().length > 0;\n\n const chip = (\n <button\n type=\"button\"\n data-canvas-resource=\"\"\n onClick={(e) => {\n e.stopPropagation();\n if (quickBookConfig) {\n if (!quickBookConfig.shouldIgnoreToggle()) quickBookConfig.onToggle();\n } else onClick?.();\n }}\n onMouseEnter={() => {\n if (quickBookConfig?.hover.prefersHover) {\n quickBookConfig.hover.clearClose();\n quickBookConfig.onOpen();\n }\n }}\n onMouseLeave={() => {\n if (quickBookConfig?.hover.prefersHover) quickBookConfig.hover.scheduleClose();\n }}\n className={cn(\n \"inline-flex items-center gap-2 shrink-0 px-3 py-1.5 rounded-lg border hover:bg-accent transition-colors text-left\",\n searchActive && !isMatch && \"opacity-40 saturate-50\",\n )}\n style={planColorCardStyle(planColor)}\n >\n <div\n className=\"w-6 h-6 rounded-md flex items-center justify-center shrink-0\"\n style={planColorBadgeStyle(planColor)}\n >\n <Box size={12} />\n </div>\n <span className=\"text-xs font-medium text-foreground whitespace-nowrap\">{resource.name}</span>\n <span\n className={cn(\n \"h-2 w-2 rounded-full shrink-0\",\n merged.occupied ? \"bg-red-500\" : \"bg-emerald-500\",\n )}\n />\n {slots && (\n <span className=\"text-[10px] text-muted-foreground whitespace-nowrap\">{slots}</span>\n )}\n </button>\n );\n\n if (!quickBookConfig) return chip;\n\n return (\n <Popover\n modal={false}\n open={quickBookConfig.open}\n onOpenChange={quickBookConfig.onOpenChange}\n >\n <PopoverAnchor asChild>{chip}</PopoverAnchor>\n <PopoverContent\n side=\"top\"\n align=\"center\"\n sideOffset={6}\n className={CANVAS_QUICK_BOOK_POPOVER_CLASS}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onMouseEnter={quickBookConfig.hover.clearClose}\n onMouseLeave={quickBookConfig.hover.scheduleClose}\n >\n <ResourceQuickBookPopoverContent\n row={row}\n onBook={quickBookConfig.quickBook.onBook}\n getBookingHref={quickBookConfig.quickBook.getBookingHref}\n />\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction PlacedCardView({\n id,\n rect,\n row,\n onSelect,\n quickBookConfig,\n searchQuery,\n isMatch,\n}: {\n id: string;\n rect: Rect;\n row: LayoutCanvasViewRow;\n onSelect?: (id: string) => void;\n quickBookConfig?: ResourceQuickBookConfig;\n searchQuery: string;\n isMatch: boolean;\n}) {\n const { resource, merged, plan } = row;\n const planColor = resolvePlanColor(plan?.color);\n const w = Math.max(rect.w, MIN_CARD_W);\n const h = Math.max(rect.h, MIN_CARD_H);\n const statusLabel = merged.occupied ? \"Occupied\" : merged.manual ? \"Vacant\" : \"Free\";\n const pointerStart = useRef<{ x: number; y: number } | null>(null);\n const searchActive = searchQuery.trim().length > 0;\n\n const handlePointerDown = (e: ReactPointerEvent) => {\n if (e.button !== 0) return;\n // Keep viewport pan/zoom from capturing the pointer before tap completes.\n e.stopPropagation();\n pointerStart.current = { x: e.clientX, y: e.clientY };\n };\n\n const handlePointerUp = (e: ReactPointerEvent) => {\n e.stopPropagation();\n const start = pointerStart.current;\n pointerStart.current = null;\n if (!start || quickBookConfig) return;\n if (Math.hypot(e.clientX - start.x, e.clientY - start.y) < CLICK_THRESHOLD_PX) {\n onSelect?.(id);\n }\n };\n\n const statusDot = (\n <span\n className={cn(\n \"block h-2.5 w-2.5 rounded-full ring-2 ring-white shadow-sm\",\n merged.occupied ? \"bg-red-500 animate-pulse\" : \"bg-emerald-500\",\n )}\n aria-label={statusLabel}\n />\n );\n\n const card = (\n <button\n type=\"button\"\n data-canvas-resource=\"\"\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y,\n width: w,\n height: h,\n touchAction: \"manipulation\",\n ...planColorCardStyle(planColor),\n }}\n className={cn(\n \"rounded-xl border shadow-sm overflow-hidden select-none text-left cursor-pointer hover:shadow-md transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40\",\n searchActive && !isMatch && \"opacity-40 saturate-50\",\n )}\n onPointerDown={handlePointerDown}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onClick={(e) => {\n e.stopPropagation();\n if (quickBookConfig && !quickBookConfig.shouldIgnoreToggle()) {\n quickBookConfig.onToggle();\n }\n }}\n onMouseEnter={() => {\n if (quickBookConfig?.hover.prefersHover) {\n quickBookConfig.hover.clearClose();\n quickBookConfig.onOpen();\n }\n }}\n onMouseLeave={() => {\n if (quickBookConfig?.hover.prefersHover) quickBookConfig.hover.scheduleClose();\n }}\n >\n <div className=\"absolute top-2 right-2 z-10 pointer-events-none\">\n {quickBookConfig ? (\n statusDot\n ) : (\n <Tooltip>\n <TooltipTrigger asChild>{statusDot}</TooltipTrigger>\n <TooltipContent side=\"top\" className=\"text-xs\">\n {statusLabel}\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n\n <div className=\"absolute inset-0 flex flex-col justify-between p-3 pointer-events-none\">\n <div className=\"min-w-0 pr-4\">\n <span\n className=\"text-xs font-semibold text-foreground leading-tight line-clamp-2\"\n style={{ wordBreak: \"break-word\" }}\n >\n {resource.name}\n </span>\n </div>\n\n {plan && (\n <span\n className=\"text-[9px] font-medium px-1.5 py-0.5 rounded-md self-start\"\n style={planColorBadgeStyle(planColor)}\n >\n {plan.name}\n </span>\n )}\n </div>\n </button>\n );\n\n if (!quickBookConfig) return card;\n\n return (\n <Popover\n modal={false}\n open={quickBookConfig.open}\n onOpenChange={quickBookConfig.onOpenChange}\n >\n <PopoverAnchor asChild>{card}</PopoverAnchor>\n <PopoverContent\n side=\"top\"\n align=\"center\"\n sideOffset={6}\n className={CANVAS_QUICK_BOOK_POPOVER_CLASS}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onMouseEnter={quickBookConfig.hover.clearClose}\n onMouseLeave={quickBookConfig.hover.scheduleClose}\n >\n <ResourceQuickBookPopoverContent\n row={row}\n onBook={quickBookConfig.quickBook.onBook}\n getBookingHref={quickBookConfig.quickBook.getBookingHref}\n />\n </PopoverContent>\n </Popover>\n );\n}\n\ntype PanGesture = {\n type: \"pan\";\n startMX: number;\n startMY: number;\n startPanX: number;\n startPanY: number;\n};\n\nexport function LayoutCanvasView({\n layout,\n rows,\n onResourceSelect,\n resourceQuickBook,\n searchQuery = \"\",\n onSearchQueryChange,\n searchPlaceholder = \"Search resources…\",\n}: LayoutCanvasViewProps) {\n const { resolvedTheme } = useTheme();\n const isDarkCanvas = resolvedTheme === \"dark\";\n const { placedItems, bgImage } = layout;\n const prefersHover = usePrefersHover();\n\n const canvasSize = useMemo(\n () => ({\n w: layout.canvasWidth ?? DEFAULT_CANVAS_WIDTH,\n h: layout.canvasHeight ?? DEFAULT_CANVAS_HEIGHT,\n }),\n [layout.canvasWidth, layout.canvasHeight],\n );\n\n const [zoom, setZoom] = useState(0.5);\n const [pan, setPan] = useState({ x: 40, y: 40 });\n const [isPanning, setIsPanning] = useState(false);\n const [openResourceId, setOpenResourceId] = useState<string | null>(null);\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const gestureRef = useRef<PanGesture | null>(null);\n const zoomRef = useRef(zoom);\n const panRef = useRef(pan);\n const popoverCloseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const suppressResourceToggleRef = useRef(false);\n\n const clearPopoverCloseTimer = useCallback(() => {\n if (popoverCloseTimerRef.current) {\n clearTimeout(popoverCloseTimerRef.current);\n popoverCloseTimerRef.current = null;\n }\n }, []);\n\n const schedulePopoverClose = useCallback(() => {\n clearPopoverCloseTimer();\n popoverCloseTimerRef.current = setTimeout(() => {\n setOpenResourceId(null);\n popoverCloseTimerRef.current = null;\n }, POPOVER_CLOSE_DELAY_MS);\n }, [clearPopoverCloseTimer]);\n\n const popoverHover = useMemo<PopoverHoverHandlers>(\n () => ({\n prefersHover,\n clearClose: clearPopoverCloseTimer,\n scheduleClose: schedulePopoverClose,\n }),\n [prefersHover, clearPopoverCloseTimer, schedulePopoverClose],\n );\n\n const openPopover = useCallback(\n (id: string) => {\n clearPopoverCloseTimer();\n setOpenResourceId(id);\n },\n [clearPopoverCloseTimer],\n );\n\n const togglePopover = useCallback(\n (id: string) => {\n clearPopoverCloseTimer();\n setOpenResourceId((current) => (current === id ? null : id));\n },\n [clearPopoverCloseTimer],\n );\n\n useEffect(() => () => clearPopoverCloseTimer(), [clearPopoverCloseTimer]);\n\n useEffect(() => {\n zoomRef.current = zoom;\n }, [zoom]);\n useEffect(() => {\n panRef.current = pan;\n }, [pan]);\n\n const rowById = useMemo(() => new Map(rows.map((r) => [r.resource.id, r])), [rows]);\n const otherRows = useMemo(\n () => rows.filter((r) => r.resource.resourceType === \"other\"),\n [rows],\n );\n\n const fitCanvas = useCallback(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n const vpRect = vp.getBoundingClientRect();\n const newZoom = Math.max(\n MIN_ZOOM,\n Math.min(\n MAX_ZOOM,\n Math.min((vpRect.width - 80) / canvasSize.w, (vpRect.height - 80) / canvasSize.h),\n ),\n );\n setPan({\n x: (vpRect.width - canvasSize.w * newZoom) / 2,\n y: (vpRect.height - canvasSize.h * newZoom) / 2,\n });\n setZoom(newZoom);\n }, [canvasSize.h, canvasSize.w]);\n\n useEffect(() => {\n fitCanvas();\n }, [fitCanvas]);\n\n useEffect(() => {\n const el = viewportRef.current;\n if (!el) return;\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const vpRect = el.getBoundingClientRect();\n const mx = e.clientX - vpRect.left;\n const my = e.clientY - vpRect.top;\n const factor = e.deltaY < 0 ? 1.08 : 1 / 1.08;\n const curZ = zoomRef.current;\n const newZ = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, curZ * factor));\n const curP = panRef.current;\n setZoom(newZ);\n setPan({\n x: mx - (mx - curP.x) * (newZ / curZ),\n y: my - (my - curP.y) * (newZ / curZ),\n });\n };\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n }, []);\n\n const stepZoom = (delta: number) => {\n const vp = viewportRef.current;\n const curZ = zoomRef.current;\n const newZ = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, curZ + delta));\n if (vp) {\n const vpRect = vp.getBoundingClientRect();\n const cx = vpRect.width / 2;\n const cy = vpRect.height / 2;\n const curP = panRef.current;\n setPan({\n x: cx - (cx - curP.x) * (newZ / curZ),\n y: cy - (cy - curP.y) * (newZ / curZ),\n });\n }\n setZoom(newZ);\n };\n\n useEffect(() => {\n const onKeyDown = (e: KeyboardEvent) => {\n const tag = (e.target as HTMLElement)?.tagName;\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return;\n if (e.key === \"+\" || e.key === \"=\") {\n e.preventDefault();\n stepZoom(0.15);\n } else if (e.key === \"-\" || e.key === \"_\") {\n e.preventDefault();\n stepZoom(-0.15);\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n });\n\n const handleViewportPointerDown = (e: React.PointerEvent) => {\n if (e.button !== 0 && e.button !== 1) return;\n if (isCanvasResourceTarget(e.target)) return;\n clearPopoverCloseTimer();\n setOpenResourceId(null);\n e.preventDefault();\n e.currentTarget.setPointerCapture(e.pointerId);\n setIsPanning(true);\n gestureRef.current = {\n type: \"pan\",\n startMX: e.clientX,\n startMY: e.clientY,\n startPanX: panRef.current.x,\n startPanY: panRef.current.y,\n };\n };\n\n const handleViewportPointerMove = (e: React.PointerEvent) => {\n const g = gestureRef.current;\n if (g?.type !== \"pan\") return;\n setPan({\n x: g.startPanX + (e.clientX - g.startMX),\n y: g.startPanY + (e.clientY - g.startMY),\n });\n };\n\n const handleViewportPointerUp = () => {\n if (gestureRef.current?.type === \"pan\") {\n gestureRef.current = null;\n setIsPanning(false);\n }\n };\n\n const handleSelect = (id: string) => onResourceSelect?.(id);\n\n const quickBookConfigFor = useCallback(\n (resourceId: string): ResourceQuickBookConfig | undefined => {\n if (!resourceQuickBook) return undefined;\n const wrappedOnBook = resourceQuickBook.onBook\n ? (id: string) => {\n suppressResourceToggleRef.current = true;\n clearPopoverCloseTimer();\n setOpenResourceId(null);\n resourceQuickBook.onBook?.(id);\n window.setTimeout(() => {\n suppressResourceToggleRef.current = false;\n }, 400);\n }\n : undefined;\n\n return {\n quickBook: {\n ...resourceQuickBook,\n onBook: wrappedOnBook,\n },\n open: openResourceId === resourceId,\n onOpenChange: (open) => {\n clearPopoverCloseTimer();\n setOpenResourceId(open ? resourceId : null);\n },\n hover: popoverHover,\n onOpen: () => openPopover(resourceId),\n onToggle: () => togglePopover(resourceId),\n shouldIgnoreToggle: () => suppressResourceToggleRef.current,\n };\n },\n [\n resourceQuickBook,\n openResourceId,\n clearPopoverCloseTimer,\n popoverHover,\n openPopover,\n togglePopover,\n ],\n );\n\n return (\n <div className=\"flex flex-col flex-1 min-h-0 bg-card\">\n <div className=\"flex flex-wrap items-center gap-2 p-2 border-b border-border bg-card shrink-0\">\n {onSearchQueryChange != null ? (\n <PageListSearchField\n value={searchQuery}\n onChange={onSearchQueryChange}\n placeholder={searchPlaceholder}\n className=\"min-w-0 flex-1 max-w-md h-9\"\n />\n ) : null}\n <div className=\"flex items-center gap-1 shrink-0 ml-auto\">\n <button\n type=\"button\"\n onClick={() => stepZoom(-0.15)}\n className=\"w-7 h-7 rounded-lg border border-border bg-card flex items-center justify-center text-muted-foreground hover:bg-accent transition-colors\"\n aria-label=\"Zoom out\"\n >\n <Minus size={12} />\n </button>\n <span className=\"text-xs text-muted-foreground w-10 text-center tabular-nums select-none\">\n {Math.round(zoom * 100)}%\n </span>\n <button\n type=\"button\"\n onClick={() => stepZoom(0.15)}\n className=\"w-7 h-7 rounded-lg border border-border bg-card flex items-center justify-center text-muted-foreground hover:bg-accent transition-colors\"\n aria-label=\"Zoom in\"\n >\n <Plus size={12} />\n </button>\n <button\n type=\"button\"\n onClick={fitCanvas}\n className=\"inline-flex items-center gap-1 px-2.5 h-7 rounded-lg border border-border bg-card text-xs text-muted-foreground hover:bg-accent transition-colors\"\n >\n <Maximize2 size={11} />\n Fit\n </button>\n </div>\n </div>\n\n <div className=\"flex flex-col flex-1 min-w-0 min-h-0\">\n <div\n ref={viewportRef}\n tabIndex={0}\n className=\"flex-1 min-h-[420px] overflow-hidden relative bg-card outline-none\"\n style={{ cursor: isPanning ? \"grabbing\" : \"grab\" }}\n onPointerDown={handleViewportPointerDown}\n onPointerMove={handleViewportPointerMove}\n onPointerUp={handleViewportPointerUp}\n onPointerCancel={handleViewportPointerUp}\n >\n <div\n style={{\n position: \"absolute\",\n transformOrigin: \"0px 0px\",\n transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,\n width: canvasSize.w,\n height: canvasSize.h,\n backgroundImage: bgImage ? \"none\" : canvasGridBackground(isDarkCanvas),\n backgroundSize: bgImage ? \"auto\" : CANVAS_GRID_BG_SIZE,\n backgroundColor: \"var(--card)\",\n boxShadow: isDarkCanvas\n ? \"0 2px 16px rgba(0,0,0,0.45)\"\n : \"0 2px 16px rgba(0,0,0,0.12)\",\n }}\n >\n {bgImage && (\n <img\n src={bgImage}\n alt=\"Floor plan\"\n draggable={false}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n pointerEvents: \"none\",\n userSelect: \"none\",\n }}\n />\n )}\n\n {Object.entries(placedItems).map(([id, rect]) => {\n const row = rowById.get(id);\n if (!row || !isFloorResourceType(row.resource.resourceType)) return null;\n return (\n <PlacedCardView\n key={id}\n id={id}\n rect={rect as Rect}\n row={row}\n onSelect={resourceQuickBook ? undefined : handleSelect}\n quickBookConfig={quickBookConfigFor(id)}\n searchQuery={searchQuery}\n isMatch={resourceMatchesSearch(row, searchQuery)}\n />\n );\n })}\n </div>\n </div>\n\n {otherRows.length > 0 && (\n <div className=\"shrink-0 border-t border-border bg-card px-4 py-2.5\">\n <div className=\"flex items-center gap-2 overflow-x-auto pb-0.5\">\n {otherRows.map((row) => {\n const resourceId = row.resource.id;\n return (\n <PoolResourceChip\n key={resourceId}\n row={row}\n onClick={resourceQuickBook ? undefined : () => handleSelect(resourceId)}\n quickBookConfig={quickBookConfigFor(resourceId)}\n searchQuery={searchQuery}\n isMatch={resourceMatchesSearch(row, searchQuery)}\n />\n );\n })}\n </div>\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type PageListSkeletonCell = "text" | "pill" | "avatar" | "actions" | "empty" | "checkbox" | "titleBody";
|
|
5
|
+
type PageListSkeletonColumn = {
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
align?: "left" | "right";
|
|
8
|
+
cell: PageListSkeletonCell;
|
|
9
|
+
className?: string;
|
|
10
|
+
hidden?: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare function StatValueSkeleton(): React.JSX.Element;
|
|
13
|
+
declare function PageListTableSkeleton({ columns, rows, label, minWidth, }: {
|
|
14
|
+
columns: PageListSkeletonColumn[];
|
|
15
|
+
rows?: number;
|
|
16
|
+
label?: string;
|
|
17
|
+
minWidth?: number;
|
|
18
|
+
}): React.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { type PageListSkeletonCell, type PageListSkeletonColumn, PageListTableSkeleton, StatValueSkeleton };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Skeleton } from './chunk-DC4QH6W2.js';
|
|
2
|
+
import { PageListTable, PageListStickyThead, PageListHeaderRow, PageListTh, PageListTr, PageListTd } from './chunk-H7EX6B6N.js';
|
|
3
|
+
import './chunk-LUB7QWGU.js';
|
|
4
|
+
import './chunk-VHINHHZQ.js';
|
|
5
|
+
import './chunk-FCY5FYJB.js';
|
|
6
|
+
import './chunk-OWNUMPUC.js';
|
|
7
|
+
import './chunk-DMPSQ22Q.js';
|
|
8
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
9
|
+
|
|
10
|
+
var TEXT_WIDTHS = ["w-28", "w-20", "w-24", "w-32", "w-16"];
|
|
11
|
+
function StatValueSkeleton() {
|
|
12
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex h-5 items-center", role: "status", "aria-busy": "true", "aria-label": "Loading", children: [
|
|
13
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-10" }),
|
|
14
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading" })
|
|
15
|
+
] });
|
|
16
|
+
}
|
|
17
|
+
function SkeletonCell({ cell, row, align }) {
|
|
18
|
+
switch (cell) {
|
|
19
|
+
case "checkbox":
|
|
20
|
+
return /* @__PURE__ */ jsx(Skeleton, { className: "size-4 rounded" });
|
|
21
|
+
case "avatar":
|
|
22
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2.5", children: [
|
|
23
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "size-7 shrink-0 rounded-full" }),
|
|
24
|
+
/* @__PURE__ */ jsx(Skeleton, { className: `h-3.5 ${TEXT_WIDTHS[row % TEXT_WIDTHS.length]}` })
|
|
25
|
+
] });
|
|
26
|
+
case "pill":
|
|
27
|
+
return /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16 rounded-full" });
|
|
28
|
+
case "actions":
|
|
29
|
+
return /* @__PURE__ */ jsxs("div", { className: `inline-flex gap-2 ${align === "right" ? "justify-end" : ""}`, children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-16 rounded-lg" }),
|
|
31
|
+
row % 3 !== 0 ? /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-14 rounded-lg" }) : null
|
|
32
|
+
] });
|
|
33
|
+
case "titleBody":
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 min-w-0", children: [
|
|
35
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "mt-1.5 h-2 w-2 shrink-0 rounded-full" }),
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1.5", children: [
|
|
37
|
+
/* @__PURE__ */ jsx(Skeleton, { className: `h-3.5 ${row % 2 === 0 ? "w-40" : "w-32"}` }),
|
|
38
|
+
/* @__PURE__ */ jsx(Skeleton, { className: `h-3 ${row % 3 === 0 ? "w-56" : "w-44"}` })
|
|
39
|
+
] })
|
|
40
|
+
] });
|
|
41
|
+
case "empty":
|
|
42
|
+
return null;
|
|
43
|
+
default:
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
Skeleton,
|
|
46
|
+
{
|
|
47
|
+
className: `h-3.5 ${TEXT_WIDTHS[row % TEXT_WIDTHS.length]} ${align === "right" ? "ml-auto" : ""}`
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function PageListTableSkeleton({
|
|
53
|
+
columns,
|
|
54
|
+
rows = 8,
|
|
55
|
+
label = "Loading",
|
|
56
|
+
minWidth
|
|
57
|
+
}) {
|
|
58
|
+
const visible = columns.filter((column) => !column.hidden);
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", { role: "status", "aria-busy": "true", "aria-label": label, children: [
|
|
60
|
+
/* @__PURE__ */ jsxs(PageListTable, { minWidth, children: [
|
|
61
|
+
/* @__PURE__ */ jsx(PageListStickyThead, { children: /* @__PURE__ */ jsx(PageListHeaderRow, { children: visible.map((column, i) => /* @__PURE__ */ jsx(
|
|
62
|
+
PageListTh,
|
|
63
|
+
{
|
|
64
|
+
align: column.align,
|
|
65
|
+
className: column.className,
|
|
66
|
+
"aria-hidden": column.label == null ? true : void 0,
|
|
67
|
+
children: column.label
|
|
68
|
+
},
|
|
69
|
+
i
|
|
70
|
+
)) }) }),
|
|
71
|
+
/* @__PURE__ */ jsx("tbody", { children: Array.from({ length: rows }, (_, row) => /* @__PURE__ */ jsx(PageListTr, { children: visible.map((column, i) => /* @__PURE__ */ jsx(PageListTd, { align: column.align, className: column.className, children: /* @__PURE__ */ jsx(SkeletonCell, { cell: column.cell, row, align: column.align }) }, i)) }, row)) })
|
|
72
|
+
] }),
|
|
73
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: label })
|
|
74
|
+
] });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { PageListTableSkeleton, StatValueSkeleton };
|
|
78
|
+
//# sourceMappingURL=page-list-loading.js.map
|
|
79
|
+
//# sourceMappingURL=page-list-loading.js.map
|