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