pubuilder 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,79 +1,99 @@
1
1
  "use client";
2
- import { jsxs as b, jsx as l, Fragment as F } from "react/jsx-runtime";
3
- import { memo as W, useRef as L, useState as C, useEffect as k, useMemo as G, useLayoutEffect as U } from "react";
4
- import { createPortal as X } from "react-dom";
5
- import { create as q } from "zustand";
6
- import { Handle as T, Position as N, ReactFlow as Z } from "@xyflow/react";
7
- function Se(e) {
8
- return e;
9
- }
10
- const K = { width: 1440, height: 900 };
11
- function A(e, r, o) {
12
- o != null && e.append(r, String(o));
13
- }
14
- function Q(e, r) {
15
- const o = e.indexOf("#"), t = o >= 0 ? e.slice(o) : "", a = o >= 0 ? e.slice(0, o) : e, c = a.indexOf("?"), s = c >= 0 ? a.slice(0, c) : a, n = new URLSearchParams(c >= 0 ? a.slice(c + 1) : "");
16
- for (const [d, u] of Object.entries(r.query))
17
- if (n.delete(d), Array.isArray(u))
18
- for (const m of u) A(n, d, m);
19
- else
20
- A(n, d, u);
21
- const i = n.toString();
22
- return `${s}${i ? `?${i}` : ""}${t}`;
23
- }
24
- function J(e) {
25
- const r = [], o = /* @__PURE__ */ new Set(), t = (a, c, s) => {
26
- for (const n of a) {
27
- if (!n.path) throw new Error("[pubuilder] page.path는 필수입니다");
28
- if (!n.title) throw new Error(`[pubuilder] "${n.path}"의 title이 없습니다`);
29
- if (o.has(n.path)) throw new Error(`[pubuilder] 중복 path: ${n.path}`);
30
- if (o.add(n.path), r.push({
31
- id: n.path,
32
- path: n.path,
33
- title: n.title,
34
- external: n.external ?? /^https?:\/\//.test(n.path),
35
- parentId: c,
36
- depth: s
37
- }), n.variants?.length) {
38
- if (n.external ?? /^https?:\/\//.test(n.path))
39
- throw new Error(`[pubuilder] 외부 페이지에는 variants를 사용할 수 없습니다: ${n.path}`);
40
- for (const i of n.variants) {
41
- if (!i.title) throw new Error(`[pubuilder] "${n.path}" variant의 title이 없습니다`);
42
- const d = Q(n.path, i);
43
- if (o.has(d)) throw new Error(`[pubuilder] 중복 path: ${d}`);
44
- o.add(d), r.push({
45
- id: d,
46
- path: d,
47
- title: i.title,
48
- external: !1,
49
- parentId: n.path,
50
- depth: s + 1
51
- });
52
- }
53
- }
54
- n.children?.length && t(n.children, n.path, s + 1);
2
+ import { jsxs as d, jsx as n, Fragment as ee } from "react/jsx-runtime";
3
+ import { createContext as ae, memo as ce, useRef as D, useState as _, useEffect as R, useMemo as V, useContext as te, useLayoutEffect as ie } from "react";
4
+ import { createPortal as se } from "react-dom";
5
+ import { normalizeIA as de } from "./config.js";
6
+ import { defineIA as Xe } from "./config.js";
7
+ import { create as ue } from "zustand";
8
+ import { Handle as J, Position as j, ReactFlow as pe } from "@xyflow/react";
9
+ const be = "http://localhost:4816";
10
+ class oe extends Error {
11
+ constructor(t, r) {
12
+ super(t), this.code = r, this.name = "ApiError";
13
+ }
14
+ }
15
+ class re {
16
+ constructor(t = be) {
17
+ this.baseUrl = t;
18
+ }
19
+ async request(t, r) {
20
+ const o = await fetch(`${this.baseUrl}${t}`, {
21
+ ...r,
22
+ headers: { "content-type": "application/json", ...r?.headers }
23
+ });
24
+ if (!o.ok) {
25
+ const l = await o.json().catch(() => ({}));
26
+ throw new oe(l.message ?? `요청 실패 (${o.status})`, l.code);
55
27
  }
56
- };
57
- if (t(e.pages, null, 0), r.length === 0) throw new Error("[pubuilder] pages가 비어 있습니다");
58
- return { nodes: r, viewport: e.viewport ?? K };
28
+ return o.status === 204 ? void 0 : await o.json();
29
+ }
30
+ async isAlive() {
31
+ try {
32
+ return await this.request("/api/health"), !0;
33
+ } catch {
34
+ return !1;
35
+ }
36
+ }
37
+ listSkills() {
38
+ return this.request("/api/skills");
39
+ }
40
+ toggleSkill(t, r) {
41
+ return this.request(`/api/skills/${encodeURIComponent(t)}`, { method: "PATCH", body: JSON.stringify({ enabled: r }) });
42
+ }
43
+ uploadSkill(t, r) {
44
+ return this.request("/api/skills", { method: "POST", body: JSON.stringify({ filename: t, content: r }) });
45
+ }
46
+ removeSkill(t) {
47
+ return this.request(`/api/skills/${encodeURIComponent(t)}`, { method: "DELETE" });
48
+ }
49
+ tokenStatus() {
50
+ return this.request("/api/settings/figma-token");
51
+ }
52
+ saveToken(t) {
53
+ return this.request("/api/settings/figma-token", { method: "PUT", body: JSON.stringify({ token: t }) });
54
+ }
55
+ deleteToken() {
56
+ return this.request("/api/settings/figma-token", { method: "DELETE" });
57
+ }
58
+ startPublish(t) {
59
+ return this.request("/api/publish", { method: "POST", body: JSON.stringify(t) });
60
+ }
61
+ cancelPublish(t) {
62
+ return this.request(`/api/publish/${t}`, { method: "DELETE" });
63
+ }
64
+ /** SSE 구독 — 반환값 호출로 해제 */
65
+ subscribePublish(t, r) {
66
+ const o = new EventSource(`${this.baseUrl}/api/publish/${t}/events`);
67
+ let l = !1;
68
+ return o.onmessage = (a) => {
69
+ const i = JSON.parse(a.data);
70
+ (i.type === "done" || i.type === "error") && (l = !0), r(i);
71
+ }, o.onerror = () => {
72
+ o.close(), l || (l = !0, r({ type: "error", text: "서버 연결이 끊겼어요. pubuilder serve 상태를 확인해주세요" }));
73
+ }, () => o.close();
74
+ }
59
75
  }
60
- function ee() {
76
+ const Y = ae(new re());
77
+ function fe() {
61
78
  return typeof process < "u" && process.env.NODE_ENV === "production";
62
79
  }
63
- const x = q((e) => ({
80
+ const y = ue((e) => ({
64
81
  isMapOpen: !1,
65
82
  viewerPath: null,
66
83
  granularity: "section",
67
84
  inspectEnabled: !0,
68
85
  selection: null,
86
+ selectedOuterHTML: null,
87
+ skillDrawerOpen: !1,
69
88
  openMap: () => e({ isMapOpen: !0 }),
70
- closeMap: () => e({ isMapOpen: !1, viewerPath: null, selection: null }),
71
- openViewer: (r) => e({ viewerPath: r, selection: null }),
72
- closeViewer: () => e({ viewerPath: null, selection: null }),
73
- setGranularity: (r) => e({ granularity: r }),
74
- setInspectEnabled: (r) => e({ inspectEnabled: r }),
75
- setSelection: (r) => e({ selection: r })
76
- })), oe = ".react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}", te = "pubuilder-styles", re = "pubuilder-xyflow-styles", ne = (
89
+ closeMap: () => e({ isMapOpen: !1, viewerPath: null, selection: null, selectedOuterHTML: null }),
90
+ openViewer: (t) => e({ viewerPath: t, selection: null, selectedOuterHTML: null }),
91
+ closeViewer: () => e({ viewerPath: null, selection: null, selectedOuterHTML: null }),
92
+ setGranularity: (t) => e({ granularity: t }),
93
+ setInspectEnabled: (t) => e({ inspectEnabled: t }),
94
+ setSelectionWithHTML: (t, r) => e({ selection: t, selectedOuterHTML: r }),
95
+ toggleSkillDrawer: () => e((t) => ({ skillDrawerOpen: !t.skillDrawerOpen }))
96
+ })), ge = ".react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}", he = "pubuilder-styles", me = "pubuilder-xyflow-styles", xe = (
77
97
  /* css */
78
98
  `
79
99
  .pbu-fab {
@@ -312,145 +332,245 @@ const x = q((e) => ({
312
332
  border-radius: 2px;
313
333
  margin-right: 6px;
314
334
  }
315
- .pbu-phase3 {
335
+ .pbu-publish {
316
336
  margin-top: 4px;
317
337
  padding: 10px;
318
- border: 1px dashed #3c3c3c;
338
+ border: 1px solid #3c3c3c;
319
339
  border-radius: 2px;
320
340
  display: flex;
321
341
  flex-direction: column;
322
342
  gap: 8px;
323
343
  }
324
- .pbu-phase3 > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: #8c8c8c; }
325
- .pbu-phase3 input {
344
+ .pbu-publish > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: #8c8c8c; }
345
+ .pbu-publish input {
326
346
  background: #1e1e1e;
327
347
  border: 1px solid #3c3c3c;
328
348
  border-radius: 2px;
329
- color: #8c8c8c;
349
+ color: #cccccc;
330
350
  font-size: 11px;
331
351
  padding: 5px 8px;
332
352
  }
333
- .pbu-badge {
334
- background: #37373d;
335
- color: #d7ba7d;
336
- font-size: 9px;
337
- font-weight: 700;
338
- padding: 1px 5px;
353
+ .pbu-publish input:disabled { color: #8c8c8c; cursor: not-allowed; }
354
+ .pbu-publish-log {
355
+ max-height: 200px;
356
+ overflow-y: auto;
357
+ background: #1e1e1e;
358
+ border: 1px solid #3c3c3c;
359
+ border-radius: 2px;
360
+ padding: 6px 8px;
361
+ font-family: ui-monospace, Menlo, monospace;
362
+ font-size: 11px;
363
+ display: flex;
364
+ flex-direction: column;
365
+ gap: 2px;
366
+ }
367
+ .pbu-log-line { color: #cccccc; white-space: pre-wrap; word-break: break-all; }
368
+ .pbu-log-tool { color: #8c8c8c; }
369
+ .pbu-log-error { color: #f2b3b3; }
370
+ .pbu-log-done { color: #89d185; font-weight: 600; }
371
+
372
+ .pbu-drawer {
373
+ position: fixed;
374
+ top: 0;
375
+ right: 0;
376
+ height: 100vh;
377
+ width: 360px;
378
+ z-index: 2147483300;
379
+ background: #252526;
380
+ border-left: 1px solid #3c3c3c;
381
+ padding: 12px;
382
+ overflow-y: auto;
383
+ display: flex;
384
+ flex-direction: column;
385
+ gap: 10px;
386
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
387
+ font-size: 12px;
388
+ color: #cccccc;
389
+ }
390
+ .pbu-drawer-header {
391
+ display: flex;
392
+ align-items: center;
393
+ justify-content: space-between;
394
+ padding-bottom: 8px;
395
+ border-bottom: 1px solid #3c3c3c;
396
+ }
397
+ .pbu-drawer-group {
398
+ display: flex;
399
+ align-items: center;
400
+ justify-content: space-between;
401
+ font-size: 10px;
402
+ font-weight: 600;
403
+ text-transform: uppercase;
404
+ letter-spacing: 0.06em;
405
+ color: #8c8c8c;
406
+ margin-top: 6px;
407
+ }
408
+ .pbu-skill-row {
409
+ display: flex;
410
+ align-items: center;
411
+ gap: 8px;
412
+ padding: 4px 0;
413
+ border-bottom: 1px solid #2d2d2d;
414
+ }
415
+ .pbu-skill-row .pbu-hint {
416
+ flex: 1;
417
+ min-width: 0;
418
+ white-space: nowrap;
419
+ overflow: hidden;
420
+ text-overflow: ellipsis;
421
+ }
422
+ .pbu-token-masked {
423
+ font-family: ui-monospace, Menlo, monospace;
424
+ font-size: 11px;
425
+ color: #cccccc;
426
+ background: #1e1e1e;
427
+ border: 1px solid #3c3c3c;
339
428
  border-radius: 2px;
340
- margin-left: 4px;
429
+ padding: 6px 8px;
430
+ }
431
+ .pbu-drawer-error {
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: space-between;
435
+ gap: 8px;
436
+ background: #5a1d1d;
437
+ border: 1px solid #832525;
438
+ color: #f2b3b3;
439
+ font-size: 11px;
440
+ padding: 6px 8px;
441
+ border-radius: 2px;
442
+ }
443
+ .pbu-drawer-code {
444
+ display: flex;
445
+ align-items: center;
446
+ gap: 8px;
447
+ margin: 8px 0;
448
+ background: #1e1e1e;
449
+ border: 1px solid #3c3c3c;
450
+ border-radius: 2px;
451
+ padding: 6px 8px;
452
+ }
453
+ .pbu-drawer-code code {
454
+ flex: 1;
455
+ font-family: ui-monospace, Menlo, monospace;
456
+ font-size: 11px;
457
+ color: #cccccc;
341
458
  }
342
459
  `
343
460
  );
344
- function j(e, r) {
461
+ function X(e, t) {
345
462
  if (document.getElementById(e)) return;
346
- const o = document.createElement("style");
347
- o.id = e, o.textContent = r, document.head.appendChild(o);
463
+ const r = document.createElement("style");
464
+ r.id = e, r.textContent = t, document.head.appendChild(r);
348
465
  }
349
- function ae() {
350
- typeof document > "u" || (j(re, oe), j(te, ne));
466
+ function we() {
467
+ typeof document > "u" || (X(me, ge), X(he, xe));
351
468
  }
352
- function le(e, r, o, t = 140, a = 48) {
353
- const c = /* @__PURE__ */ new Map();
354
- for (const d of e) {
355
- const u = c.get(d.parentId) ?? [];
356
- u.push(d), c.set(d.parentId, u);
469
+ function ye(e, t, r, o = 140, l = 48) {
470
+ const a = /* @__PURE__ */ new Map();
471
+ for (const u of e) {
472
+ const w = a.get(u.parentId) ?? [];
473
+ w.push(u), a.set(u.parentId, w);
357
474
  }
358
- const s = /* @__PURE__ */ new Map();
359
- let n = 0;
360
- const i = (d) => {
361
- const u = c.get(d.id) ?? [], m = d.depth * (r + t);
362
- let w;
363
- if (u.length === 0)
364
- w = n, n += o + a;
475
+ const i = /* @__PURE__ */ new Map();
476
+ let c = 0;
477
+ const h = (u) => {
478
+ const w = a.get(u.id) ?? [], f = u.depth * (t + o);
479
+ let v;
480
+ if (w.length === 0)
481
+ v = c, c += r + l;
365
482
  else {
366
- const p = u.map(i);
367
- w = (Math.min(...p) + Math.max(...p)) / 2;
483
+ const N = w.map(h);
484
+ v = (Math.min(...N) + Math.max(...N)) / 2;
368
485
  }
369
- return s.set(d.id, { x: m, y: w }), w;
486
+ return i.set(u.id, { x: f, y: v }), v;
370
487
  };
371
- for (const d of c.get(null) ?? []) i(d);
372
- return e.map((d) => ({ ...d, ...s.get(d.id) }));
373
- }
374
- const ce = W(function(r) {
375
- const { page: o, viewport: t, thumbWidth: a, bodyHeight: c } = r.data, s = x((w) => w.openViewer), n = L(null), [i, d] = C(!1);
376
- k(() => {
377
- const w = n.current;
378
- if (!w || o.external) return;
379
- const p = new IntersectionObserver(([v]) => {
380
- v.isIntersecting && (d(!0), p.disconnect());
488
+ for (const u of a.get(null) ?? []) h(u);
489
+ return e.map((u) => ({ ...u, ...i.get(u.id) }));
490
+ }
491
+ const ve = ce(function(t) {
492
+ const { page: r, viewport: o, thumbWidth: l, bodyHeight: a } = t.data, i = y((v) => v.openViewer), c = D(null), [h, u] = _(!1);
493
+ R(() => {
494
+ const v = c.current;
495
+ if (!v || r.external) return;
496
+ const N = new IntersectionObserver(([g]) => {
497
+ g.isIntersecting && (u(!0), N.disconnect());
381
498
  });
382
- return p.observe(w), () => p.disconnect();
383
- }, [o.external]);
384
- const u = a / t.width;
385
- return /* @__PURE__ */ b("div", { ref: n, className: "pbu-node", style: { width: a }, onClick: () => {
386
- o.external ? window.open(o.path, "_blank", "noopener") : s(o.path);
499
+ return N.observe(v), () => N.disconnect();
500
+ }, [r.external]);
501
+ const w = l / o.width;
502
+ return /* @__PURE__ */ d("div", { ref: c, className: "pbu-node", style: { width: l }, onClick: () => {
503
+ r.external ? window.open(r.path, "_blank", "noopener") : i(r.path);
387
504
  }, children: [
388
- /* @__PURE__ */ l(T, { type: "target", position: N.Left, className: "pbu-handle", isConnectable: !1 }),
389
- /* @__PURE__ */ b("div", { className: "pbu-node-header", children: [
390
- /* @__PURE__ */ l("span", { className: "pbu-node-title", children: o.title }),
391
- /* @__PURE__ */ l("span", { className: "pbu-node-path", children: o.external ? "외부 ↗" : o.path })
505
+ /* @__PURE__ */ n(J, { type: "target", position: j.Left, className: "pbu-handle", isConnectable: !1 }),
506
+ /* @__PURE__ */ d("div", { className: "pbu-node-header", children: [
507
+ /* @__PURE__ */ n("span", { className: "pbu-node-title", children: r.title }),
508
+ /* @__PURE__ */ n("span", { className: "pbu-node-path", children: r.external ? "외부 ↗" : r.path })
392
509
  ] }),
393
- /* @__PURE__ */ b("div", { className: "pbu-node-body", style: { height: c }, children: [
394
- o.external ? /* @__PURE__ */ l("div", { className: "pbu-node-placeholder", children: "↗ 외부 링크" }) : i ? /* @__PURE__ */ l(
510
+ /* @__PURE__ */ d("div", { className: "pbu-node-body", style: { height: a }, children: [
511
+ r.external ? /* @__PURE__ */ n("div", { className: "pbu-node-placeholder", children: "↗ 외부 링크" }) : h ? /* @__PURE__ */ n(
395
512
  "iframe",
396
513
  {
397
514
  className: "pbu-node-iframe",
398
- src: o.path,
399
- title: `${o.title} 미리보기`,
515
+ src: r.path,
516
+ title: `${r.title} 미리보기`,
400
517
  loading: "lazy",
401
518
  tabIndex: -1,
402
519
  style: {
403
- width: t.width,
404
- height: t.height,
405
- transform: `scale(${u})`
520
+ width: o.width,
521
+ height: o.height,
522
+ transform: `scale(${w})`
406
523
  }
407
524
  }
408
- ) : /* @__PURE__ */ l("div", { className: "pbu-node-placeholder", children: "…" }),
409
- /* @__PURE__ */ l("div", { className: "pbu-node-shield" })
525
+ ) : /* @__PURE__ */ n("div", { className: "pbu-node-placeholder", children: "…" }),
526
+ /* @__PURE__ */ n("div", { className: "pbu-node-shield" })
410
527
  ] }),
411
- /* @__PURE__ */ l(T, { type: "source", position: N.Right, className: "pbu-handle", isConnectable: !1 })
528
+ /* @__PURE__ */ n(J, { type: "source", position: j.Right, className: "pbu-handle", isConnectable: !1 })
412
529
  ] });
413
- }), ie = { page: ce }, S = 260, se = 30;
414
- function de({ ia: e }) {
415
- const r = x((a) => a.closeMap), { nodes: o, edges: t } = G(() => {
416
- const a = S / e.viewport.width, c = Math.round(e.viewport.height * a), s = c + se, n = le(e.nodes, S, s), i = n.map((u) => ({
417
- id: u.id,
530
+ }), ke = { page: ve }, G = 260, _e = 30;
531
+ function Ne({ ia: e }) {
532
+ const t = y((a) => a.closeMap), r = y((a) => a.toggleSkillDrawer), { nodes: o, edges: l } = V(() => {
533
+ const a = G / e.viewport.width, i = Math.round(e.viewport.height * a), c = i + _e, h = ye(e.nodes, G, c), u = h.map((f) => ({
534
+ id: f.id,
418
535
  type: "page",
419
- position: { x: u.x, y: u.y },
536
+ position: { x: f.x, y: f.y },
420
537
  data: {
421
- page: u,
538
+ page: f,
422
539
  viewport: e.viewport,
423
- thumbWidth: S,
424
- bodyHeight: c
540
+ thumbWidth: G,
541
+ bodyHeight: i
425
542
  },
426
- sourcePosition: N.Right,
427
- targetPosition: N.Left
428
- })), d = n.filter((u) => u.parentId).map((u) => ({
429
- id: `${u.parentId}->${u.id}`,
430
- source: u.parentId,
431
- target: u.id,
543
+ sourcePosition: j.Right,
544
+ targetPosition: j.Left
545
+ })), w = h.filter((f) => f.parentId).map((f) => ({
546
+ id: `${f.parentId}->${f.id}`,
547
+ source: f.parentId,
548
+ target: f.id,
432
549
  type: "smoothstep"
433
550
  }));
434
- return { nodes: i, edges: d };
551
+ return { nodes: u, edges: w };
435
552
  }, [e]);
436
- return k(() => {
437
- const a = (c) => {
438
- c.key === "Escape" && (x.getState().viewerPath || r());
553
+ return R(() => {
554
+ const a = (i) => {
555
+ if (i.key !== "Escape") return;
556
+ const c = y.getState();
557
+ c.viewerPath || c.skillDrawerOpen || t();
439
558
  };
440
559
  return window.addEventListener("keydown", a), () => window.removeEventListener("keydown", a);
441
- }, [r]), /* @__PURE__ */ b("div", { className: "pbu-overlay", children: [
442
- /* @__PURE__ */ b("div", { className: "pbu-bar", children: [
443
- /* @__PURE__ */ l("span", { className: "pbu-logo", children: "pubuilder" }),
444
- /* @__PURE__ */ l("span", { className: "pbu-hint", children: "노드 클릭 → 페이지 확대 · 스크롤 줌 · 드래그 팬 · Esc 닫기" }),
445
- /* @__PURE__ */ l("span", { className: "pbu-spacer" }),
446
- /* @__PURE__ */ l("button", { type: "button", className: "pbu-icon-btn", onClick: r, "aria-label": "닫기", children: "✕" })
560
+ }, [t]), /* @__PURE__ */ d("div", { className: "pbu-overlay", children: [
561
+ /* @__PURE__ */ d("div", { className: "pbu-bar", children: [
562
+ /* @__PURE__ */ n("span", { className: "pbu-logo", children: "pubuilder" }),
563
+ /* @__PURE__ */ n("span", { className: "pbu-hint", children: "노드 클릭 → 페이지 확대 · 스크롤 줌 · 드래그 팬 · Esc 닫기" }),
564
+ /* @__PURE__ */ n("span", { className: "pbu-spacer" }),
565
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: r, children: "🧰 스킬함" }),
566
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-icon-btn", onClick: t, "aria-label": "닫기", children: "✕" })
447
567
  ] }),
448
- /* @__PURE__ */ l("div", { className: "pbu-canvas", children: /* @__PURE__ */ l(
449
- Z,
568
+ /* @__PURE__ */ n("div", { className: "pbu-canvas", children: /* @__PURE__ */ n(
569
+ pe,
450
570
  {
451
571
  nodes: o,
452
- edges: t,
453
- nodeTypes: ie,
572
+ edges: l,
573
+ nodeTypes: ke,
454
574
  fitView: !0,
455
575
  fitViewOptions: { padding: 0.15, maxZoom: 1 },
456
576
  minZoom: 0.05,
@@ -462,25 +582,25 @@ function de({ ia: e }) {
462
582
  ) })
463
583
  ] });
464
584
  }
465
- function ue() {
466
- const e = x((t) => t.isMapOpen), r = x((t) => t.openMap), o = x((t) => t.closeMap);
467
- return /* @__PURE__ */ l(
585
+ function ze() {
586
+ const e = y((o) => o.isMapOpen), t = y((o) => o.openMap), r = y((o) => o.closeMap);
587
+ return /* @__PURE__ */ n(
468
588
  "button",
469
589
  {
470
590
  type: "button",
471
591
  className: "pbu-fab",
472
592
  title: "Page Map (pubuilder)",
473
593
  "aria-label": "페이지 맵 열기",
474
- onClick: () => e ? o() : r(),
475
- children: /* @__PURE__ */ b("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
476
- /* @__PURE__ */ l("polygon", { points: "3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21" }),
477
- /* @__PURE__ */ l("line", { x1: "9", y1: "3", x2: "9", y2: "18" }),
478
- /* @__PURE__ */ l("line", { x1: "15", y1: "6", x2: "15", y2: "21" })
594
+ onClick: () => e ? r() : t(),
595
+ children: /* @__PURE__ */ d("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
596
+ /* @__PURE__ */ n("polygon", { points: "3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21" }),
597
+ /* @__PURE__ */ n("line", { x1: "9", y1: "3", x2: "9", y2: "18" }),
598
+ /* @__PURE__ */ n("line", { x1: "15", y1: "6", x2: "15", y2: "21" })
479
599
  ] })
480
600
  }
481
601
  );
482
602
  }
483
- const pe = /* @__PURE__ */ new Set([
603
+ const Ce = /* @__PURE__ */ new Set([
484
604
  "section",
485
605
  "header",
486
606
  "footer",
@@ -489,7 +609,7 @@ const pe = /* @__PURE__ */ new Set([
489
609
  "article",
490
610
  "aside",
491
611
  "form"
492
- ]), fe = /* @__PURE__ */ new Set([
612
+ ]), Ee = /* @__PURE__ */ new Set([
493
613
  "a",
494
614
  "button",
495
615
  "input",
@@ -509,371 +629,640 @@ const pe = /* @__PURE__ */ new Set([
509
629
  "p",
510
630
  "label"
511
631
  ]);
512
- function Y(e, r) {
513
- const o = [];
514
- let t = e;
515
- for (; t && t !== r.body && t !== r.documentElement; )
516
- o.push(t), t = t.parentElement;
517
- return o;
518
- }
519
- function be(e, r) {
520
- const o = Y(e, r);
521
- if (o.length === 0) return null;
522
- const t = o.find((s) => {
523
- const n = s.tagName.toLowerCase();
524
- return pe.has(n) && n !== "main";
632
+ function ne(e, t) {
633
+ const r = [];
634
+ let o = e;
635
+ for (; o && o !== t.body && o !== t.documentElement; )
636
+ r.push(o), o = o.parentElement;
637
+ return r;
638
+ }
639
+ function Se(e, t) {
640
+ const r = ne(e, t);
641
+ if (r.length === 0) return null;
642
+ const o = r.find((i) => {
643
+ const c = i.tagName.toLowerCase();
644
+ return Ce.has(c) && c !== "main";
525
645
  });
526
- if (t) return t;
527
- const a = o.find((s) => s.tagName.toLowerCase() === "main");
528
- if (a) return a;
529
- const c = r.body.scrollHeight || 1;
530
- for (let s = o.length - 1; s >= 0; s--) {
531
- const n = o[s].getBoundingClientRect();
532
- if (n.height > 0 && n.height < c * 0.8) return o[s];
646
+ if (o) return o;
647
+ const l = r.find((i) => i.tagName.toLowerCase() === "main");
648
+ if (l) return l;
649
+ const a = t.body.scrollHeight || 1;
650
+ for (let i = r.length - 1; i >= 0; i--) {
651
+ const c = r[i].getBoundingClientRect();
652
+ if (c.height > 0 && c.height < a * 0.8) return r[i];
533
653
  }
534
- return o[o.length - 1];
535
- }
536
- function he(e, r) {
537
- const o = Y(e, r);
538
- for (const t of o) {
539
- if (fe.has(t.tagName.toLowerCase())) return t;
540
- const a = t.getBoundingClientRect(), c = t.children.length > 0 || (t.textContent ?? "").trim().length > 0;
541
- if (a.width >= 40 && a.height >= 24 && c) return t;
654
+ return r[r.length - 1];
655
+ }
656
+ function Te(e, t) {
657
+ const r = ne(e, t);
658
+ for (const o of r) {
659
+ if (Ee.has(o.tagName.toLowerCase())) return o;
660
+ const l = o.getBoundingClientRect(), a = o.children.length > 0 || (o.textContent ?? "").trim().length > 0;
661
+ if (l.width >= 40 && l.height >= 24 && a) return o;
542
662
  }
543
- return o[0] ?? null;
663
+ return r[0] ?? null;
544
664
  }
545
- function ge(e, r, o) {
546
- return o === "all" ? r.body : o === "section" ? be(e, r) : he(e, r);
665
+ function Le(e, t, r) {
666
+ return r === "all" ? t.body : r === "section" ? Se(e, t) : Te(e, t);
547
667
  }
548
- function xe(e) {
549
- const o = e.querySelector("h1, h2, h3, h4, h5, h6")?.textContent?.trim();
550
- if (o) return E(o);
551
- const t = e.getAttribute("aria-label");
552
- if (t) return E(t);
553
- const a = e.getAttribute("alt");
554
- if (a) return E(a);
555
- const c = (e.textContent ?? "").trim().replace(/\s+/g, " ");
556
- return c ? E(c) : `<${e.tagName.toLowerCase()}>`;
668
+ function Me(e) {
669
+ const r = e.querySelector("h1, h2, h3, h4, h5, h6")?.textContent?.trim();
670
+ if (r) return B(r);
671
+ const o = e.getAttribute("aria-label");
672
+ if (o) return B(o);
673
+ const l = e.getAttribute("alt");
674
+ if (l) return B(l);
675
+ const a = (e.textContent ?? "").trim().replace(/\s+/g, " ");
676
+ return a ? B(a) : `<${e.tagName.toLowerCase()}>`;
557
677
  }
558
- function E(e, r = 30) {
559
- return e.length > r ? `${e.slice(0, r)}…` : e;
678
+ function B(e, t = 30) {
679
+ return e.length > t ? `${e.slice(0, t)}…` : e;
560
680
  }
561
- function we(e, r) {
681
+ function Pe(e, t) {
562
682
  if (e.id) return `#${CSS.escape(e.id)}`;
563
- const o = [];
564
- let t = e;
565
- for (; t && t !== r.body && o.length < 8; ) {
566
- if (t.id)
567
- return o.unshift(`#${CSS.escape(t.id)}`), o.join(" > ");
568
- const a = t.tagName.toLowerCase(), c = t.parentElement;
569
- let s = a;
570
- if (c) {
571
- const n = Array.from(c.children).filter(
572
- (i) => i.tagName === t.tagName
683
+ const r = [];
684
+ let o = e;
685
+ for (; o && o !== t.body && r.length < 8; ) {
686
+ if (o.id)
687
+ return r.unshift(`#${CSS.escape(o.id)}`), r.join(" > ");
688
+ const l = o.tagName.toLowerCase(), a = o.parentElement;
689
+ let i = l;
690
+ if (a) {
691
+ const c = Array.from(a.children).filter(
692
+ (h) => h.tagName === o.tagName
573
693
  );
574
- n.length > 1 && (s += `:nth-of-type(${n.indexOf(t) + 1})`);
694
+ c.length > 1 && (i += `:nth-of-type(${c.indexOf(o) + 1})`);
575
695
  }
576
- o.unshift(s), t = c;
696
+ r.unshift(i), o = a;
577
697
  }
578
- return o.join(" > ");
698
+ return r.join(" > ");
579
699
  }
580
- function H(e, r, o) {
581
- const t = e.createElement("div");
582
- t.setAttribute("data-pubuilder", "highlight"), Object.assign(t.style, {
700
+ function K(e, t, r) {
701
+ const o = e.createElement("div");
702
+ o.setAttribute("data-pubuilder", "highlight"), Object.assign(o.style, {
583
703
  position: "fixed",
584
704
  top: "0",
585
705
  left: "0",
586
706
  display: "none",
587
- border: `1px solid ${r}`,
588
- background: o,
707
+ border: `1px solid ${t}`,
708
+ background: r,
589
709
  borderRadius: "0",
590
710
  pointerEvents: "none",
591
711
  zIndex: "2147483647",
592
712
  boxSizing: "border-box"
593
713
  });
594
- const a = e.createElement("div");
595
- return Object.assign(a.style, {
714
+ const l = e.createElement("div");
715
+ return Object.assign(l.style, {
596
716
  position: "absolute",
597
717
  left: "-1px",
598
718
  top: "-22px",
599
719
  padding: "2px 7px",
600
- background: r,
720
+ background: t,
601
721
  color: "#fff",
602
722
  font: "600 10px/16px system-ui, sans-serif",
603
723
  borderRadius: "0",
604
724
  whiteSpace: "nowrap",
605
725
  pointerEvents: "none"
606
- }), t.appendChild(a), { root: t, label: a };
726
+ }), o.appendChild(l), { root: o, label: l };
607
727
  }
608
- function V(e, r, o, t) {
609
- const a = r.getBoundingClientRect(), c = t ?? -1 / 0, s = Math.max(a.top, c), n = a.bottom - s;
610
- if (n <= 2) {
611
- M(e);
728
+ function Z(e, t, r, o) {
729
+ const l = t.getBoundingClientRect(), a = o ?? -1 / 0, i = Math.max(l.top, a), c = l.bottom - i;
730
+ if (c <= 2) {
731
+ W(e);
612
732
  return;
613
733
  }
614
- e.root.style.display = "block", e.root.style.transform = `translate(${a.x}px, ${s}px)`, e.root.style.width = `${a.width}px`, e.root.style.height = `${n}px`, e.label.textContent = o, e.label.style.top = s < 30 || s - 24 < c ? "2px" : "-24px";
734
+ e.root.style.display = "block", e.root.style.transform = `translate(${l.x}px, ${i}px)`, e.root.style.width = `${l.width}px`, e.root.style.height = `${c}px`, e.label.textContent = r, e.label.style.top = i < 30 || i - 24 < a ? "2px" : "-24px";
615
735
  }
616
- function M(e) {
736
+ function W(e) {
617
737
  e.root.style.display = "none";
618
738
  }
619
- function D(e) {
620
- const r = e.getBoundingClientRect();
621
- return `${e.tagName.toLowerCase()} · ${Math.round(r.width)}×${Math.round(r.height)}`;
739
+ function Q(e) {
740
+ const t = e.getBoundingClientRect();
741
+ return `${e.tagName.toLowerCase()} · ${Math.round(t.width)}×${Math.round(t.height)}`;
622
742
  }
623
- function me(e, r) {
624
- let o = null;
743
+ function Oe(e, t) {
744
+ let r = null;
625
745
  try {
626
- o = e.contentDocument;
746
+ r = e.contentDocument;
627
747
  } catch {
628
748
  return null;
629
749
  }
630
- const t = e.contentWindow;
631
- if (!o || !o.body || !t) return null;
632
- const a = o;
633
- let c = r.granularity, s = r.enabled, n = null, i = null;
634
- const d = H(a, "rgba(14,99,156,0.95)", "rgba(14,99,156,0.10)"), u = H(a, "rgba(35,134,54,0.95)", "rgba(35,134,54,0.07)");
635
- a.body.appendChild(d.root), a.body.appendChild(u.root);
636
- let m = [], w = 0;
637
- const p = () => {
638
- m = [];
639
- for (const f of Array.from(a.body.querySelectorAll("*"))) {
640
- if (f === d.root || f === u.root || d.root.contains(f) || u.root.contains(f)) continue;
641
- const g = t.getComputedStyle(f).position;
642
- if (g !== "fixed" && g !== "sticky") continue;
643
- const h = f.getBoundingClientRect();
644
- h.width === 0 || h.height === 0 || h.top <= 1 && h.height < t.innerHeight * 0.5 && m.push({ el: f, rect: h });
750
+ const o = e.contentWindow;
751
+ if (!r || !r.body || !o) return null;
752
+ const l = r;
753
+ let a = t.granularity, i = t.enabled, c = null, h = null;
754
+ const u = K(l, "rgba(14,99,156,0.95)", "rgba(14,99,156,0.10)"), w = K(l, "rgba(35,134,54,0.95)", "rgba(35,134,54,0.07)");
755
+ l.body.appendChild(u.root), l.body.appendChild(w.root);
756
+ let f = [], v = 0;
757
+ const N = () => {
758
+ f = [];
759
+ for (const p of Array.from(l.body.querySelectorAll("*"))) {
760
+ if (p === u.root || p === w.root || u.root.contains(p) || w.root.contains(p)) continue;
761
+ const k = o.getComputedStyle(p).position;
762
+ if (k !== "fixed" && k !== "sticky") continue;
763
+ const m = p.getBoundingClientRect();
764
+ m.width === 0 || m.height === 0 || m.top <= 1 && m.height < o.innerHeight * 0.5 && f.push({ el: p, rect: m });
645
765
  }
646
- }, v = () => {
647
- const f = Date.now();
648
- f - w < 500 || (w = f, p());
649
- }, z = (f) => {
650
- const g = f.getBoundingClientRect();
651
- let h = null;
652
- for (const y of m)
653
- y.el === f || y.el.contains(f) || f.contains(y.el) || !(g.left < y.rect.right && g.right > y.rect.left) || (h === null || y.rect.bottom > h) && (h = y.rect.bottom);
654
- return h;
655
- }, _ = () => {
656
- n && s && n.isConnected ? V(d, n, D(n), z(n)) : M(d), i && i.isConnected ? V(u, i, `선택됨 · ${D(i)}`, z(i)) : M(u);
657
- }, P = (f) => {
658
- if (c === "all") return a.body;
659
- if (i && i.isConnected && i.contains(f)) {
660
- if (i === f) return i;
661
- let g = f;
662
- for (; g.parentElement && g.parentElement !== i; )
663
- g = g.parentElement;
664
- return g;
766
+ }, g = () => {
767
+ const p = Date.now();
768
+ p - v < 500 || (v = p, N());
769
+ }, E = (p) => {
770
+ const k = p.getBoundingClientRect();
771
+ let m = null;
772
+ for (const z of f)
773
+ z.el === p || z.el.contains(p) || p.contains(z.el) || !(k.left < z.rect.right && k.right > z.rect.left) || (m === null || z.rect.bottom > m) && (m = z.rect.bottom);
774
+ return m;
775
+ }, S = () => {
776
+ c && i && c.isConnected ? Z(u, c, Q(c), E(c)) : W(u), h && h.isConnected ? Z(w, h, `선택됨 · ${Q(h)}`, E(h)) : W(w);
777
+ }, L = (p) => {
778
+ if (a === "all") return l.body;
779
+ if (h && h.isConnected && h.contains(p)) {
780
+ if (h === p) return h;
781
+ let k = p;
782
+ for (; k.parentElement && k.parentElement !== h; )
783
+ k = k.parentElement;
784
+ return k;
665
785
  }
666
- return ge(f, a, c);
667
- }, I = (f) => {
668
- if (!s) return;
669
- v();
670
- const g = f.target;
671
- if (!g || !a.body.contains(g)) return;
672
- const h = P(g);
673
- h !== n && (n = h, _());
674
- }, $ = (f) => {
675
- if (!s) return;
676
- f.preventDefault(), f.stopPropagation(), p(), w = Date.now();
677
- const g = f.target;
678
- if (!g) return;
679
- const h = P(g);
680
- if (!h) return;
681
- i = h, _();
682
- const y = h.getBoundingClientRect();
683
- r.onSelect({
684
- pagePath: r.pagePath,
685
- selector: we(h, a),
686
- tag: h.tagName.toLowerCase(),
687
- label: xe(h),
688
- rect: {
689
- x: y.x + t.scrollX,
690
- y: y.y + t.scrollY,
691
- width: y.width,
692
- height: y.height
786
+ return Le(p, l, a);
787
+ }, I = (p) => {
788
+ if (!i) return;
789
+ g();
790
+ const k = p.target;
791
+ if (!k || !l.body.contains(k)) return;
792
+ const m = L(k);
793
+ m !== c && (c = m, S());
794
+ }, M = (p) => {
795
+ if (!i) return;
796
+ p.preventDefault(), p.stopPropagation(), N(), v = Date.now();
797
+ const k = p.target;
798
+ if (!k) return;
799
+ const m = L(k);
800
+ if (!m) return;
801
+ h = m, S();
802
+ const z = m.getBoundingClientRect();
803
+ t.onSelect(
804
+ {
805
+ pagePath: t.pagePath,
806
+ selector: Pe(m, l),
807
+ tag: m.tagName.toLowerCase(),
808
+ label: Me(m),
809
+ rect: {
810
+ x: z.x + o.scrollX,
811
+ y: z.y + o.scrollY,
812
+ width: z.width,
813
+ height: z.height
814
+ },
815
+ granularity: a
693
816
  },
694
- granularity: c
695
- });
696
- }, B = () => {
697
- n = null, _();
698
- }, O = () => _(), R = () => {
699
- p(), _();
817
+ m
818
+ );
819
+ }, T = () => {
820
+ c = null, S();
821
+ }, O = () => S(), P = () => {
822
+ N(), S();
700
823
  };
701
- return p(), a.addEventListener("mousemove", I, !0), a.addEventListener("click", $, !0), a.documentElement.addEventListener("mouseleave", B), t.addEventListener("scroll", O, !0), t.addEventListener("resize", R), {
824
+ return N(), l.addEventListener("mousemove", I, !0), l.addEventListener("click", M, !0), l.documentElement.addEventListener("mouseleave", T), o.addEventListener("scroll", O, !0), o.addEventListener("resize", P), {
702
825
  destroy() {
703
826
  try {
704
- a.removeEventListener("mousemove", I, !0), a.removeEventListener("click", $, !0), a.documentElement.removeEventListener("mouseleave", B), t.removeEventListener("scroll", O, !0), t.removeEventListener("resize", R), d.root.remove(), u.root.remove();
827
+ l.removeEventListener("mousemove", I, !0), l.removeEventListener("click", M, !0), l.documentElement.removeEventListener("mouseleave", T), o.removeEventListener("scroll", O, !0), o.removeEventListener("resize", P), u.root.remove(), w.root.remove();
705
828
  } catch {
706
829
  }
707
830
  },
708
- setGranularity(f) {
709
- c = f, n = null, _();
831
+ setGranularity(p) {
832
+ a = p, c = null, S();
710
833
  },
711
- setEnabled(f) {
712
- s = f, f || (n = null), _();
834
+ setEnabled(p) {
835
+ i = p, p || (c = null), S();
713
836
  }
714
837
  };
715
838
  }
716
- function ye() {
717
- const e = x((a) => a.selection), [r, o] = C(!1), t = async () => {
718
- e && (await navigator.clipboard.writeText(e.selector), o(!0), setTimeout(() => o(!1), 1200));
839
+ const Re = {
840
+ log: "💬",
841
+ tool: "🔧",
842
+ error: "⛔",
843
+ done: "✅"
844
+ };
845
+ function Ie() {
846
+ const e = te(Y), t = y((s) => s.selection), r = y((s) => s.selectedOuterHTML), o = y((s) => s.toggleSkillDrawer), [l, a] = _(""), [i, c] = _("idle"), [h, u] = _(null), [w, f] = _([]), [v, N] = _(!1), [g, E] = _(!1), [S, L] = _(null), [I, M] = _(null), [T, O] = _(!1), [P, p] = _(!1), k = D(null), m = D(null), z = D(0);
847
+ R(() => {
848
+ z.current++, m.current?.(), m.current = null, c("idle"), u(null), f([]), N(!1), E(!1), O(!1), L(null), M(null), a("");
849
+ }, [t?.selector]), R(() => {
850
+ const s = k.current;
851
+ s && (s.scrollTop = s.scrollHeight);
852
+ }, [w]), R(() => () => {
853
+ z.current++, m.current?.(), m.current = null;
854
+ }, []);
855
+ const A = (s) => {
856
+ m.current = e.subscribePublish(s, (C) => {
857
+ f(($) => [...$, C]), C.type === "done" ? (c("done"), u(null), O(!1), m.current?.(), m.current = null) : C.type === "error" && (c("error"), L(C.text), u(null), O(!1), m.current?.(), m.current = null);
858
+ });
859
+ }, F = async () => {
860
+ if (!t || i === "running" || g) return;
861
+ const s = z.current;
862
+ N(!1), L(null), M(null), E(!0);
863
+ try {
864
+ const C = await e.isAlive();
865
+ if (s !== z.current) return;
866
+ if (!C) {
867
+ N(!0);
868
+ return;
869
+ }
870
+ const { jobId: $ } = await e.startPublish({
871
+ selection: t,
872
+ outerHTML: r ?? "",
873
+ figmaUrl: l
874
+ });
875
+ if (s !== z.current) {
876
+ e.cancelPublish($).catch(() => {
877
+ });
878
+ return;
879
+ }
880
+ u($), f([]), c("running"), A($);
881
+ } catch (C) {
882
+ if (s !== z.current) return;
883
+ c("error"), L(C instanceof Error ? C.message : String(C)), M(C instanceof oe ? C.code ?? null : null);
884
+ } finally {
885
+ E(!1);
886
+ }
887
+ }, U = async () => {
888
+ if (!(!h || T)) {
889
+ O(!0);
890
+ try {
891
+ await e.cancelPublish(h);
892
+ } catch (s) {
893
+ L(s instanceof Error ? s.message : String(s)), O(!1);
894
+ }
895
+ }
896
+ }, q = async () => {
897
+ await navigator.clipboard.writeText("npx pubuilder serve"), p(!0), setTimeout(() => p(!1), 1200);
898
+ }, H = async () => {
899
+ E(!0);
900
+ try {
901
+ const s = await e.isAlive();
902
+ N(!s);
903
+ } finally {
904
+ E(!1);
905
+ }
906
+ }, b = i === "running";
907
+ return /* @__PURE__ */ d("div", { className: "pbu-publish", children: [
908
+ /* @__PURE__ */ n("label", { children: "Figma 노드 링크" }),
909
+ /* @__PURE__ */ n(
910
+ "input",
911
+ {
912
+ value: l,
913
+ onChange: (s) => a(s.target.value),
914
+ disabled: b,
915
+ placeholder: "https://www.figma.com/design/..."
916
+ }
917
+ ),
918
+ v && /* @__PURE__ */ d("div", { className: "pbu-panel-empty", children: [
919
+ "컴패니언 서버가 꺼져 있어요",
920
+ /* @__PURE__ */ d("div", { className: "pbu-drawer-code", children: [
921
+ /* @__PURE__ */ n("code", { children: "npx pubuilder serve" }),
922
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: q, children: P ? "복사됨 ✓" : "복사" })
923
+ ] }),
924
+ /* @__PURE__ */ n("div", { className: "pbu-hint", children: 'package.json의 dev 스크립트를 "pubuilder dev -- <기존 명령>"으로 감싸면 자동 실행돼요' }),
925
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", disabled: g, onClick: H, children: "다시 확인" })
926
+ ] }),
927
+ S && !v && /* @__PURE__ */ d("div", { className: "pbu-drawer-error", children: [
928
+ /* @__PURE__ */ n("span", { children: S }),
929
+ (I === "NO_FIGMA_TOKEN" || I === "FIGMA_API_ERROR") && /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: o, children: "스킬함 열기" })
930
+ ] }),
931
+ b ? /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn pbu-btn-primary", disabled: T, onClick: U, children: T ? "중단 중..." : "중단" }) : /* @__PURE__ */ n(
932
+ "button",
933
+ {
934
+ type: "button",
935
+ className: "pbu-btn pbu-btn-primary",
936
+ disabled: g || !t,
937
+ onClick: F,
938
+ children: "이 블록 퍼블리싱"
939
+ }
940
+ ),
941
+ (w.length > 0 || b) && /* @__PURE__ */ d("div", { className: "pbu-publish-log", ref: k, children: [
942
+ b && w.length === 0 && /* @__PURE__ */ n("div", { className: "pbu-log-line pbu-log-tool", children: "실행 중..." }),
943
+ w.map((s, C) => /* @__PURE__ */ d(
944
+ "div",
945
+ {
946
+ className: s.type === "error" ? "pbu-log-line pbu-log-error" : s.type === "done" ? "pbu-log-line pbu-log-done" : s.type === "tool" ? "pbu-log-line pbu-log-tool" : "pbu-log-line",
947
+ children: [
948
+ /* @__PURE__ */ n("span", { children: Re[s.type] }),
949
+ " ",
950
+ /* @__PURE__ */ n("span", { children: s.text })
951
+ ]
952
+ },
953
+ C
954
+ ))
955
+ ] })
956
+ ] });
957
+ }
958
+ function De() {
959
+ const e = y((l) => l.selection), [t, r] = _(!1), o = async () => {
960
+ e && (await navigator.clipboard.writeText(e.selector), r(!0), setTimeout(() => r(!1), 1200));
719
961
  };
720
- return /* @__PURE__ */ b("aside", { className: "pbu-panel", children: [
721
- /* @__PURE__ */ l("div", { className: "pbu-panel-title", children: "선택된 블록" }),
722
- e ? /* @__PURE__ */ b(F, { children: [
723
- /* @__PURE__ */ b("div", { className: "pbu-field", children: [
724
- /* @__PURE__ */ l("label", { children: "페이지" }),
725
- /* @__PURE__ */ l("code", { children: e.pagePath })
962
+ return /* @__PURE__ */ d("aside", { className: "pbu-panel", children: [
963
+ /* @__PURE__ */ n("div", { className: "pbu-panel-title", children: "선택된 블록" }),
964
+ e ? /* @__PURE__ */ d(ee, { children: [
965
+ /* @__PURE__ */ d("div", { className: "pbu-field", children: [
966
+ /* @__PURE__ */ n("label", { children: "페이지" }),
967
+ /* @__PURE__ */ n("code", { children: e.pagePath })
726
968
  ] }),
727
- /* @__PURE__ */ b("div", { className: "pbu-field", children: [
728
- /* @__PURE__ */ l("label", { children: "블록" }),
729
- /* @__PURE__ */ b("div", { children: [
730
- /* @__PURE__ */ l("span", { className: "pbu-chip", children: e.tag }),
731
- /* @__PURE__ */ l("span", { children: e.label })
969
+ /* @__PURE__ */ d("div", { className: "pbu-field", children: [
970
+ /* @__PURE__ */ n("label", { children: "블록" }),
971
+ /* @__PURE__ */ d("div", { children: [
972
+ /* @__PURE__ */ n("span", { className: "pbu-chip", children: e.tag }),
973
+ /* @__PURE__ */ n("span", { children: e.label })
732
974
  ] })
733
975
  ] }),
734
- /* @__PURE__ */ b("div", { className: "pbu-field", children: [
735
- /* @__PURE__ */ l("label", { children: "Selector" }),
736
- /* @__PURE__ */ l("code", { className: "pbu-selector", children: e.selector }),
737
- /* @__PURE__ */ l("button", { type: "button", className: "pbu-btn", onClick: t, children: r ? "복사됨 ✓" : "Selector 복사" })
976
+ /* @__PURE__ */ d("div", { className: "pbu-field", children: [
977
+ /* @__PURE__ */ n("label", { children: "Selector" }),
978
+ /* @__PURE__ */ n("code", { className: "pbu-selector", children: e.selector }),
979
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: o, children: t ? "복사됨 ✓" : "Selector 복사" })
738
980
  ] }),
739
- /* @__PURE__ */ b("div", { className: "pbu-field", children: [
740
- /* @__PURE__ */ l("label", { children: "크기" }),
741
- /* @__PURE__ */ b("span", { children: [
981
+ /* @__PURE__ */ d("div", { className: "pbu-field", children: [
982
+ /* @__PURE__ */ n("label", { children: "크기" }),
983
+ /* @__PURE__ */ d("span", { children: [
742
984
  Math.round(e.rect.width),
743
985
  " × ",
744
986
  Math.round(e.rect.height),
745
987
  "px"
746
988
  ] })
747
989
  ] }),
748
- /* @__PURE__ */ b("div", { className: "pbu-field", children: [
749
- /* @__PURE__ */ l("label", { children: "단위" }),
750
- /* @__PURE__ */ l("span", { children: e.granularity === "all" ? "전체" : e.granularity === "section" ? "섹션" : "유닛" })
990
+ /* @__PURE__ */ d("div", { className: "pbu-field", children: [
991
+ /* @__PURE__ */ n("label", { children: "단위" }),
992
+ /* @__PURE__ */ n("span", { children: e.granularity === "all" ? "전체" : e.granularity === "section" ? "섹션" : "유닛" })
751
993
  ] }),
752
- /* @__PURE__ */ b("div", { className: "pbu-phase3", children: [
753
- /* @__PURE__ */ b("label", { children: [
754
- "Figma 노드 링크",
755
- /* @__PURE__ */ l("span", { className: "pbu-badge", children: "PHASE 3" })
756
- ] }),
757
- /* @__PURE__ */ l("input", { disabled: !0, placeholder: "https://figma.com/design/..." }),
758
- /* @__PURE__ */ l("button", { type: "button", disabled: !0, className: "pbu-btn pbu-btn-primary", children: "이 블록 퍼블리싱 (준비 중)" })
759
- ] })
760
- ] }) : /* @__PURE__ */ b("div", { className: "pbu-panel-empty", children: [
994
+ /* @__PURE__ */ n(Ie, {})
995
+ ] }) : /* @__PURE__ */ d("div", { className: "pbu-panel-empty", children: [
761
996
  "화면에서 블록에 마우스를 올리고 클릭해 선택하세요.",
762
- /* @__PURE__ */ l("br", {}),
997
+ /* @__PURE__ */ n("br", {}),
763
998
  "상단 토글로 ",
764
- /* @__PURE__ */ l("b", { children: "전체 / 섹션 / 유닛" }),
999
+ /* @__PURE__ */ n("b", { children: "전체 / 섹션 / 유닛" }),
765
1000
  " 단위를 바꿀 수 있어요."
766
1001
  ] })
767
1002
  ] });
768
1003
  }
769
- function _e({ ia: e }) {
770
- const r = x((p) => p.viewerPath), o = x((p) => p.closeViewer), t = x((p) => p.granularity), a = x((p) => p.setGranularity), c = x((p) => p.inspectEnabled), s = x((p) => p.setInspectEnabled), n = L(null), i = L(null), [d, u] = C(!1), m = e.nodes.find((p) => p.path === r), w = () => {
771
- i.current?.destroy(), i.current = null;
772
- const p = n.current;
773
- if (!p || !r) return;
774
- const v = x.getState(), z = me(p, {
775
- pagePath: r,
776
- granularity: v.granularity,
777
- enabled: v.inspectEnabled,
778
- onSelect: (_) => x.getState().setSelection(_)
1004
+ function $e({ ia: e }) {
1005
+ const t = y((g) => g.viewerPath), r = y((g) => g.closeViewer), o = y((g) => g.granularity), l = y((g) => g.setGranularity), a = y((g) => g.inspectEnabled), i = y((g) => g.setInspectEnabled), c = y((g) => g.toggleSkillDrawer), h = D(null), u = D(null), [w, f] = _(!1), v = e.nodes.find((g) => g.path === t), N = () => {
1006
+ u.current?.destroy(), u.current = null;
1007
+ const g = h.current;
1008
+ if (!g || !t) return;
1009
+ const E = y.getState(), S = Oe(g, {
1010
+ pagePath: t,
1011
+ granularity: E.granularity,
1012
+ enabled: E.inspectEnabled,
1013
+ onSelect: (L, I) => (
1014
+ // 20K 상한 — 프롬프트 비대화 방지
1015
+ y.getState().setSelectionWithHTML(L, I.outerHTML.slice(0, 2e4))
1016
+ )
779
1017
  });
780
- if (!z) {
781
- u(!0);
1018
+ if (!S) {
1019
+ f(!0);
782
1020
  return;
783
1021
  }
784
- u(!1), i.current = z;
1022
+ f(!1), u.current = S;
785
1023
  };
786
- return k(() => () => i.current?.destroy(), []), k(() => {
787
- i.current?.setGranularity(t);
788
- }, [t]), k(() => {
789
- i.current?.setEnabled(c);
790
- }, [c]), k(() => {
791
- const p = (v) => {
792
- v.key === "Escape" && o();
1024
+ return R(() => () => u.current?.destroy(), []), R(() => {
1025
+ u.current?.setGranularity(o);
1026
+ }, [o]), R(() => {
1027
+ u.current?.setEnabled(a);
1028
+ }, [a]), R(() => {
1029
+ const g = (E) => {
1030
+ E.key === "Escape" && (y.getState().skillDrawerOpen || r());
793
1031
  };
794
- return window.addEventListener("keydown", p), () => window.removeEventListener("keydown", p);
795
- }, [o]), m ? /* @__PURE__ */ b("div", { className: "pbu-viewer", children: [
796
- /* @__PURE__ */ b("div", { className: "pbu-bar", children: [
797
- /* @__PURE__ */ l("button", { type: "button", className: "pbu-btn", onClick: o, children: "← 맵으로" }),
798
- /* @__PURE__ */ b("span", { className: "pbu-viewer-title", children: [
799
- m.title,
800
- /* @__PURE__ */ l("code", { children: m.path })
1032
+ return window.addEventListener("keydown", g), () => window.removeEventListener("keydown", g);
1033
+ }, [r]), v ? /* @__PURE__ */ d("div", { className: "pbu-viewer", children: [
1034
+ /* @__PURE__ */ d("div", { className: "pbu-bar", children: [
1035
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: r, children: "← 맵으로" }),
1036
+ /* @__PURE__ */ d("span", { className: "pbu-viewer-title", children: [
1037
+ v.title,
1038
+ /* @__PURE__ */ n("code", { children: v.path })
801
1039
  ] }),
802
- /* @__PURE__ */ l("span", { className: "pbu-spacer" }),
803
- d && /* @__PURE__ */ l("span", { className: "pbu-hint", children: "⚠ 이 페이지는 검사할 수 없어요" }),
804
- /* @__PURE__ */ b("div", { className: "pbu-seg", role: "group", "aria-label": "블록 단위", children: [
805
- /* @__PURE__ */ l(
1040
+ /* @__PURE__ */ n("span", { className: "pbu-spacer" }),
1041
+ w && /* @__PURE__ */ n("span", { className: "pbu-hint", children: "⚠ 이 페이지는 검사할 수 없어요" }),
1042
+ /* @__PURE__ */ d("div", { className: "pbu-seg", role: "group", "aria-label": "블록 단위", children: [
1043
+ /* @__PURE__ */ n(
806
1044
  "button",
807
1045
  {
808
1046
  type: "button",
809
- className: t === "all" ? "pbu-on" : "",
810
- onClick: () => a("all"),
1047
+ className: o === "all" ? "pbu-on" : "",
1048
+ onClick: () => l("all"),
811
1049
  children: "전체"
812
1050
  }
813
1051
  ),
814
- /* @__PURE__ */ l(
1052
+ /* @__PURE__ */ n(
815
1053
  "button",
816
1054
  {
817
1055
  type: "button",
818
- className: t === "section" ? "pbu-on" : "",
819
- onClick: () => a("section"),
1056
+ className: o === "section" ? "pbu-on" : "",
1057
+ onClick: () => l("section"),
820
1058
  children: "섹션"
821
1059
  }
822
1060
  ),
823
- /* @__PURE__ */ l(
1061
+ /* @__PURE__ */ n(
824
1062
  "button",
825
1063
  {
826
1064
  type: "button",
827
- className: t === "unit" ? "pbu-on" : "",
828
- onClick: () => a("unit"),
1065
+ className: o === "unit" ? "pbu-on" : "",
1066
+ onClick: () => l("unit"),
829
1067
  children: "유닛"
830
1068
  }
831
1069
  )
832
1070
  ] }),
833
- /* @__PURE__ */ b("label", { className: "pbu-toggle", children: [
834
- /* @__PURE__ */ l(
1071
+ /* @__PURE__ */ d("label", { className: "pbu-toggle", children: [
1072
+ /* @__PURE__ */ n(
835
1073
  "input",
836
1074
  {
837
1075
  type: "checkbox",
838
- checked: c,
839
- onChange: (p) => s(p.target.checked)
1076
+ checked: a,
1077
+ onChange: (g) => i(g.target.checked)
840
1078
  }
841
1079
  ),
842
1080
  "검사 모드"
843
1081
  ] }),
844
- /* @__PURE__ */ l("button", { type: "button", className: "pbu-icon-btn", onClick: o, "aria-label": "닫기", children: "✕" })
1082
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: c, children: "🧰 스킬함" }),
1083
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-icon-btn", onClick: r, "aria-label": "닫기", children: "✕" })
845
1084
  ] }),
846
- /* @__PURE__ */ b("div", { className: "pbu-viewer-body", children: [
847
- /* @__PURE__ */ l("div", { className: "pbu-viewer-frame-wrap", children: /* @__PURE__ */ l(
1085
+ /* @__PURE__ */ d("div", { className: "pbu-viewer-body", children: [
1086
+ /* @__PURE__ */ n("div", { className: "pbu-viewer-frame-wrap", children: /* @__PURE__ */ n(
848
1087
  "iframe",
849
1088
  {
850
- ref: n,
1089
+ ref: h,
851
1090
  className: "pbu-viewer-iframe",
852
- src: m.path,
853
- title: m.title,
854
- onLoad: w
1091
+ src: v.path,
1092
+ title: v.title,
1093
+ onLoad: N
855
1094
  }
856
1095
  ) }),
857
- /* @__PURE__ */ l(ye, {})
1096
+ /* @__PURE__ */ n(De, {})
858
1097
  ] })
859
1098
  ] }) : null;
860
1099
  }
861
- function Le({ config: e, enabled: r = !0 }) {
862
- const o = r && !ee(), [t, a] = C(!1), c = x((i) => i.isMapOpen), s = x((i) => i.viewerPath), n = G(() => J(e), [e]);
863
- return U(() => {
864
- o && window.self === window.top && (ae(), a(!0));
865
- }, [o]), !t || !o ? null : X(
866
- /* @__PURE__ */ b(F, { children: [
867
- /* @__PURE__ */ l(ue, {}),
868
- c && /* @__PURE__ */ l(de, { ia: n }),
869
- s && /* @__PURE__ */ l(_e, { ia: n })
1100
+ const Ae = {
1101
+ project: "프로젝트",
1102
+ global: "글로벌",
1103
+ uploaded: "업로드"
1104
+ }, He = ["project", "global", "uploaded"];
1105
+ function Be() {
1106
+ const e = y((b) => b.toggleSkillDrawer), t = te(Y), [r, o] = _(!0), [l, a] = _(!1), [i, c] = _([]), [h, u] = _(null), [w, f] = _(""), [v, N] = _(!1), [g, E] = _(null), [S, L] = _(!1), I = D(null), M = D(0), [T, O] = _(null), P = async () => {
1107
+ const b = ++M.current;
1108
+ o(!0), E(null);
1109
+ try {
1110
+ const x = await t.isAlive();
1111
+ if (b !== M.current || (a(x), !x)) return;
1112
+ const [s, C] = await Promise.all([t.listSkills(), t.tokenStatus()]);
1113
+ if (b !== M.current) return;
1114
+ c(s), u(C), N(!C.configured);
1115
+ } catch (x) {
1116
+ if (b !== M.current) return;
1117
+ E(x instanceof Error ? x.message : String(x));
1118
+ } finally {
1119
+ b === M.current && o(!1);
1120
+ }
1121
+ };
1122
+ R(() => {
1123
+ P();
1124
+ }, []), R(() => {
1125
+ const b = (x) => {
1126
+ x.key === "Escape" && e();
1127
+ };
1128
+ return window.addEventListener("keydown", b), () => window.removeEventListener("keydown", b);
1129
+ }, [e]);
1130
+ const p = async (b, x) => {
1131
+ if (!T) {
1132
+ O(b);
1133
+ try {
1134
+ await x();
1135
+ } catch (s) {
1136
+ E(s instanceof Error ? s.message : String(s));
1137
+ } finally {
1138
+ O(null);
1139
+ }
1140
+ }
1141
+ }, k = (b, x) => p(`toggle:${b}`, async () => {
1142
+ await t.toggleSkill(b, x), await P();
1143
+ }), m = (b, x) => {
1144
+ window.confirm(`"${x}" 스킬을 삭제할까요?`) && p(`remove:${b}`, async () => {
1145
+ await t.removeSkill(b), await P();
1146
+ });
1147
+ }, z = () => I.current?.click(), A = (b) => {
1148
+ const x = b.target.files?.[0];
1149
+ b.target.value = "", x && p("upload", async () => {
1150
+ const s = new FileReader(), C = await new Promise(($, le) => {
1151
+ s.onload = () => $(String(s.result ?? "")), s.onerror = () => le(s.error ?? new Error("파일을 읽을 수 없어요")), s.readAsText(x);
1152
+ });
1153
+ await t.uploadSkill(x.name, C), await P();
1154
+ });
1155
+ }, F = () => p("token:save", async () => {
1156
+ w.trim() && (await t.saveToken(w.trim()), f(""), await P());
1157
+ }), U = () => p("token:delete", async () => {
1158
+ await t.deleteToken(), f(""), await P();
1159
+ }), q = async () => {
1160
+ await navigator.clipboard.writeText("npx pubuilder serve"), L(!0), setTimeout(() => L(!1), 1200);
1161
+ }, H = He.map((b) => ({
1162
+ source: b,
1163
+ label: Ae[b],
1164
+ items: i.filter((x) => x.source === b)
1165
+ })).filter((b) => b.items.length > 0);
1166
+ return /* @__PURE__ */ d("aside", { className: "pbu-drawer", children: [
1167
+ /* @__PURE__ */ d("div", { className: "pbu-drawer-header", children: [
1168
+ /* @__PURE__ */ n("span", { className: "pbu-panel-title", children: "스킬함" }),
1169
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-icon-btn", onClick: e, "aria-label": "닫기", children: "✕" })
1170
+ ] }),
1171
+ g && /* @__PURE__ */ d("div", { className: "pbu-drawer-error", children: [
1172
+ /* @__PURE__ */ n("span", { children: g }),
1173
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-icon-btn", onClick: () => E(null), "aria-label": "닫기", children: "✕" })
1174
+ ] }),
1175
+ r ? /* @__PURE__ */ n("div", { className: "pbu-panel-empty", children: "불러오는 중..." }) : l ? /* @__PURE__ */ d(ee, { children: [
1176
+ /* @__PURE__ */ n("div", { className: "pbu-drawer-group", children: "토큰" }),
1177
+ h?.configured && !v ? /* @__PURE__ */ d("div", { className: "pbu-field", children: [
1178
+ /* @__PURE__ */ n("span", { className: "pbu-token-masked", children: h.masked }),
1179
+ /* @__PURE__ */ d("div", { children: [
1180
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", disabled: T !== null, onClick: () => N(!0), children: "재입력" }),
1181
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", disabled: T !== null, onClick: U, children: "삭제" })
1182
+ ] })
1183
+ ] }) : /* @__PURE__ */ d("div", { className: "pbu-field", children: [
1184
+ /* @__PURE__ */ n(
1185
+ "input",
1186
+ {
1187
+ type: "password",
1188
+ value: w,
1189
+ onChange: (b) => f(b.target.value),
1190
+ placeholder: "Figma 토큰"
1191
+ }
1192
+ ),
1193
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn pbu-btn-primary", disabled: T !== null, onClick: F, children: "저장" })
1194
+ ] }),
1195
+ /* @__PURE__ */ d("div", { className: "pbu-drawer-group", children: [
1196
+ "스킬 목록",
1197
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", disabled: T !== null, onClick: z, children: "업로드" }),
1198
+ /* @__PURE__ */ n(
1199
+ "input",
1200
+ {
1201
+ ref: I,
1202
+ type: "file",
1203
+ accept: ".md",
1204
+ style: { display: "none" },
1205
+ onChange: A
1206
+ }
1207
+ )
1208
+ ] }),
1209
+ H.length === 0 ? /* @__PURE__ */ n("div", { className: "pbu-panel-empty", children: "등록된 스킬이 없어요." }) : H.map((b) => /* @__PURE__ */ d("div", { children: [
1210
+ /* @__PURE__ */ n("div", { className: "pbu-drawer-group", children: b.label }),
1211
+ b.items.map((x) => /* @__PURE__ */ d("div", { className: "pbu-skill-row", children: [
1212
+ /* @__PURE__ */ d("label", { className: "pbu-toggle", children: [
1213
+ /* @__PURE__ */ n(
1214
+ "input",
1215
+ {
1216
+ type: "checkbox",
1217
+ checked: x.enabled,
1218
+ disabled: T !== null,
1219
+ onChange: (s) => k(x.id, s.target.checked)
1220
+ }
1221
+ ),
1222
+ x.name
1223
+ ] }),
1224
+ /* @__PURE__ */ n("span", { className: "pbu-hint", title: x.description, children: x.description }),
1225
+ x.source === "uploaded" && /* @__PURE__ */ n(
1226
+ "button",
1227
+ {
1228
+ type: "button",
1229
+ className: "pbu-icon-btn",
1230
+ disabled: T !== null,
1231
+ onClick: () => m(x.id, x.name),
1232
+ "aria-label": "삭제",
1233
+ children: "🗑"
1234
+ }
1235
+ )
1236
+ ] }, x.id))
1237
+ ] }, b.source))
1238
+ ] }) : /* @__PURE__ */ d("div", { className: "pbu-panel-empty", children: [
1239
+ "컴패니언 서버가 꺼져 있어요",
1240
+ /* @__PURE__ */ d("div", { className: "pbu-drawer-code", children: [
1241
+ /* @__PURE__ */ n("code", { children: "npx pubuilder serve" }),
1242
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: q, children: S ? "복사됨 ✓" : "복사" })
1243
+ ] }),
1244
+ /* @__PURE__ */ n("div", { className: "pbu-hint", children: 'package.json의 dev 스크립트를 "pubuilder dev -- <기존 명령>"으로 감싸면 자동 실행돼요' }),
1245
+ /* @__PURE__ */ n("button", { type: "button", className: "pbu-btn", onClick: P, children: "다시 확인" })
1246
+ ] })
1247
+ ] });
1248
+ }
1249
+ function We({ config: e, enabled: t = !0, serverUrl: r }) {
1250
+ const o = t && !fe(), [l, a] = _(!1), i = y((f) => f.isMapOpen), c = y((f) => f.viewerPath), h = y((f) => f.skillDrawerOpen), u = V(() => de(e), [e]), w = V(() => new re(r), [r]);
1251
+ return ie(() => {
1252
+ o && window.self === window.top && (we(), a(!0));
1253
+ }, [o]), !l || !o ? null : se(
1254
+ /* @__PURE__ */ d(Y.Provider, { value: w, children: [
1255
+ /* @__PURE__ */ n(ze, {}),
1256
+ i && /* @__PURE__ */ n(Ne, { ia: u }),
1257
+ c && /* @__PURE__ */ n($e, { ia: u }),
1258
+ h && /* @__PURE__ */ n(Be, {})
870
1259
  ] }),
871
1260
  document.body
872
1261
  );
873
1262
  }
874
1263
  export {
875
- Le as PageMap,
876
- Se as defineIA,
877
- J as normalizeIA
1264
+ We as PageMap,
1265
+ Xe as defineIA,
1266
+ de as normalizeIA
878
1267
  };
879
1268
  //# sourceMappingURL=index.js.map