@8ux-co/eelzap 0.0.0-stage → 0.10.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.
@@ -0,0 +1,283 @@
1
+ // src/preview/site/messages.ts
2
+ var plural = (count, one, other) => (count === 1 ? one : other).replace("{n}", String(count));
3
+ var SIGNIN_MESSAGES = {
4
+ es: {
5
+ launcher: "Editar o comentar",
6
+ hintBefore: "Pulsa",
7
+ hintAfter: "para editar o comentar",
8
+ title: "Edita o comenta esta p\xE1gina",
9
+ body: "Escribe sobre el texto de la p\xE1gina o deja un comentario. Lo que edites queda en el borrador y se publica desde Zap.",
10
+ signIn: "Entrar con Eel",
11
+ note: "Solo para personas con Zap en este sitio. Los visitantes no ven nada de esto.",
12
+ waiting: "Esperando a Eel",
13
+ waitingHelp: "Termina en la ventana de Eel. Si la cerraste, vuelve a intentarlo.",
14
+ retry: "Intentar de nuevo",
15
+ close: "Cerrar",
16
+ expired: "Tu sesi\xF3n termin\xF3. Entra de nuevo para seguir.",
17
+ failed: "No pudimos completar la entrada. Intenta de nuevo."
18
+ },
19
+ en: {
20
+ launcher: "Edit or comment",
21
+ hintBefore: "Press",
22
+ hintAfter: "to edit or comment",
23
+ title: "Edit or comment on this page",
24
+ body: "Type over the text on the page or leave a comment. What you edit goes to the draft and is published from Zap.",
25
+ signIn: "Sign in with Eel",
26
+ note: "Only for people with Zap on this site. Visitors see none of this.",
27
+ waiting: "Waiting for Eel",
28
+ waitingHelp: "Finish in the Eel window. If you closed it, try again.",
29
+ retry: "Try again",
30
+ close: "Close",
31
+ expired: "Your session ended. Sign in again to keep going.",
32
+ failed: "We could not finish signing you in. Try again."
33
+ }
34
+ };
35
+ var SUGGEST_MESSAGES = {
36
+ es: {
37
+ toolbar: "Zap en esta p\xE1gina",
38
+ tools: "Herramienta",
39
+ navigate: "Navegar",
40
+ edit: "Editar",
41
+ comment: "Comentar",
42
+ editOff: "Desactivado por un administrador",
43
+ open: (n) => plural(n, "{n} abierto", "{n} abiertos"),
44
+ openTitle: "Comentarios abiertos en esta p\xE1gina",
45
+ noneOpen: "No hay comentarios abiertos en esta p\xE1gina.",
46
+ changeRequest: "Solicitud de cambio",
47
+ exit: "Salir",
48
+ newComment: "Nuevo comentario",
49
+ commentTitle: "Comentario",
50
+ selected: (n) => plural(n, "{n} elemento seleccionado", "{n} elementos seleccionados"),
51
+ clearSelection: "Cancelar",
52
+ commentLabel: "Comentario",
53
+ commentPlaceholder: "Escribe tu comentario",
54
+ requestChange: "Solicitar cambio",
55
+ requestHelp: "Queda abierta hasta que alguien la resuelva o aplique el texto propuesto.",
56
+ recipient: "La recibe la persona responsable en Zap.",
57
+ propose: "Proponer texto",
58
+ proposalFor: "Texto propuesto para",
59
+ removeProposal: "Quitar texto propuesto",
60
+ now: "Ahora:",
61
+ proposal: "Texto propuesto",
62
+ cancel: "Cancelar",
63
+ close: "Cerrar",
64
+ sending: "Enviando",
65
+ save: "Guardar",
66
+ sentComment: "Comentario enviado",
67
+ sentCommentBody: "Tu equipo lo ver\xE1 en Zap.",
68
+ sentRequest: "Solicitud de cambio enviada",
69
+ sentRequestBody: (name, proposal) => `${name ? `${name} la ver\xE1` : "La persona responsable la ver\xE1"} en Zap${proposal ? " con tu texto propuesto" : ""}. La p\xE1gina no cambia hasta que se publique.`,
70
+ saving: "Guardando",
71
+ saved: "Guardado en el borrador",
72
+ notEditable: "Esto no se edita aqu\xED",
73
+ notEditableBody: "Usa Comentar para pedir el cambio.",
74
+ editOffBody: "Un administrador desactiv\xF3 Editar en este sitio.",
75
+ renewed: "Sesi\xF3n renovada",
76
+ renewedAs: (name) => `Sigues como ${name}`,
77
+ renewedBody: "Sigues donde ibas.",
78
+ dismiss: "Cerrar aviso",
79
+ someone: "Alguien",
80
+ refusedTitle: "No puedes editar ni comentar en este sitio",
81
+ refusedBody: "Tu cuenta no tiene acceso a Zap aqu\xED, o el sitio dej\xF3 de permitirlo.",
82
+ rateLimited: (n) => plural(
83
+ n,
84
+ "Enviaste muchos seguidos. Intenta de nuevo en {n} segundo.",
85
+ "Enviaste muchos seguidos. Intenta de nuevo en {n} segundos."
86
+ ),
87
+ failed: "No se pudo enviar. Revisa el texto e intenta de nuevo.",
88
+ saveFailed: "No se pudo guardar. El texto volvi\xF3 a como estaba.",
89
+ noRecord: "Esta parte de la p\xE1gina no es contenido de Zap.",
90
+ invalidNumber: "Escribe un n\xFAmero."
91
+ },
92
+ en: {
93
+ toolbar: "Zap on this page",
94
+ tools: "Tool",
95
+ navigate: "Browse",
96
+ edit: "Edit",
97
+ comment: "Comment",
98
+ editOff: "Turned off by an administrator",
99
+ open: (n) => plural(n, "{n} open", "{n} open"),
100
+ openTitle: "Open comments on this page",
101
+ noneOpen: "No open comments on this page.",
102
+ changeRequest: "Change request",
103
+ exit: "Sign out",
104
+ newComment: "New comment",
105
+ commentTitle: "Comment",
106
+ selected: (n) => plural(n, "{n} element selected", "{n} elements selected"),
107
+ clearSelection: "Cancel",
108
+ commentLabel: "Comment",
109
+ commentPlaceholder: "Write your comment",
110
+ requestChange: "Request a change",
111
+ requestHelp: "It stays open until someone resolves it or applies the proposed text.",
112
+ recipient: "The person responsible in Zap receives it.",
113
+ propose: "Propose text",
114
+ proposalFor: "Proposed text for",
115
+ removeProposal: "Remove proposed text",
116
+ now: "Now:",
117
+ proposal: "Proposed text",
118
+ cancel: "Cancel",
119
+ close: "Close",
120
+ sending: "Sending",
121
+ save: "Save",
122
+ sentComment: "Comment sent",
123
+ sentCommentBody: "Your team will see it in Zap.",
124
+ sentRequest: "Change request sent",
125
+ sentRequestBody: (name, proposal) => `${name ?? "The person responsible"} will see it in Zap${proposal ? " with your proposed text" : ""}. The page does not change until it is published.`,
126
+ saving: "Saving",
127
+ saved: "Saved to the draft",
128
+ notEditable: "This is not edited here",
129
+ notEditableBody: "Use Comment to ask for the change.",
130
+ editOffBody: "An administrator turned off Edit for this site.",
131
+ renewed: "Session renewed",
132
+ renewedAs: (name) => `You are still ${name}`,
133
+ renewedBody: "Pick up where you left off.",
134
+ dismiss: "Dismiss",
135
+ someone: "Someone",
136
+ refusedTitle: "You cannot edit or comment on this site",
137
+ refusedBody: "Your account has no Zap access here, or the site stopped allowing it.",
138
+ rateLimited: (n) => plural(
139
+ n,
140
+ "You sent many in a row. Try again in {n} second.",
141
+ "You sent many in a row. Try again in {n} seconds."
142
+ ),
143
+ failed: "Could not send. Check the text and try again.",
144
+ saveFailed: "Could not save. The text is back to what it was.",
145
+ noRecord: "This part of the page is not Zap content.",
146
+ invalidNumber: "Enter a number."
147
+ }
148
+ };
149
+
150
+ // src/preview/site/ui.ts
151
+ var SITE_HOST_TAG = "eel-zap-site";
152
+ var ZAP_BOLT = '<svg viewBox="0 0 512 512"><g transform="matrix(27.611111,0,0,24.833333,-74.833333,-42)"><path d="M13,2L3,14L10.036,11.906L10,22L20.964,9.235L12.913,11.973L13,2Z" fill="#F1A10D" stroke="#F1A10D" stroke-width="0.5"/><path d="M13,2L6.518,12.953L10.036,11.906L12.913,11.973L13,2Z" fill="#FFC03A"/><path d="M10.036,11.906L10,22L20.964,9.235L12.913,11.973L10.036,11.906Z" fill="#D98A05"/><path d="M10,22L20.964,9.235L16.939,10.604L10,22Z" fill="#BF7500"/></g></svg>';
153
+ var EEL_MARK = '<svg viewBox="0 0 3000 3000" fill="currentColor"><g transform="matrix(1.01772,-0.122618,0.122163,1.013948,-241.899218,117.348723)"><g transform="matrix(1.192409,0,0,1.144788,-367.077609,-248.030951)"><path d="M2789.774,1920.921C2642.929,2454.806 2170.478,2846 1611,2846C934.352,2846 385,2273.795 385,1569C385,864.205 934.352,292 1611,292C1849.726,292 2072.607,363.224 2261.109,486.366C2132.562,436.833 1991.613,409.484 1843.83,409.484C1242.576,409.484 754.435,862.18 754.435,1419.774C754.435,1977.368 1242.576,2430.064 1843.83,2430.064C2248.492,2430.064 2601.918,2225.006 2789.774,1920.921Z"/></g><g transform="matrix(1.434867,0,-0,0.933341,-1232.183743,68.591241)"><path d="M2196.648,369.772C2557.019,431.746 2832,753.678 2832,1141C2832,1572.598 2490.559,1923 2070,1923C1813.847,1923 1587.045,1793.01 1448.867,1593.857C1561.131,1687.675 1700.963,1743.353 1852.482,1743.353C2222.082,1743.353 2522.15,1412.061 2522.15,1004.003C2522.15,734.845 2391.596,499.086 2196.648,369.772Z"/></g></g></svg>';
154
+ var stroke = (paths) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${paths}</svg>`;
155
+ var ICONS = {
156
+ zap: ZAP_BOLT,
157
+ eel: EEL_MARK,
158
+ x: stroke('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>'),
159
+ lock: stroke(
160
+ '<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>'
161
+ ),
162
+ pointer: stroke(
163
+ '<path d="M12.586 12.586 19 19"/><path d="M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z"/>'
164
+ ),
165
+ pencil: stroke(
166
+ '<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/>'
167
+ ),
168
+ commentPlus: stroke(
169
+ '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M12 7v6"/><path d="M9 10h6"/>'
170
+ ),
171
+ thread: stroke(
172
+ '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M13 8H7"/><path d="M17 12H7"/>'
173
+ ),
174
+ exit: stroke(
175
+ '<path d="m16 17 5-5-5-5"/><path d="M21 12H9"/><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>'
176
+ ),
177
+ check: stroke('<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>'),
178
+ alert: stroke('<circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/>'),
179
+ field: stroke('<path d="M4 7V4h16v3"/><path d="M9 20h6"/><path d="M12 4v16"/>')
180
+ };
181
+ function icon(doc, name, size = 15) {
182
+ const span = doc.createElement("span");
183
+ span.className = "icon";
184
+ span.style.width = `${size}px`;
185
+ span.style.height = `${size}px`;
186
+ span.setAttribute("aria-hidden", "true");
187
+ span.innerHTML = ICONS[name];
188
+ return span;
189
+ }
190
+ function el(doc, tag, props = {}, children = []) {
191
+ const node = doc.createElement(tag);
192
+ if (props.class) node.className = props.class;
193
+ for (const [name, value] of Object.entries(props.attrs ?? {})) {
194
+ if (value !== null && value !== void 0) node.setAttribute(name, value);
195
+ }
196
+ if (props.text !== void 0) node.textContent = props.text;
197
+ for (const [type, handler] of Object.entries(props.on ?? {})) {
198
+ if (handler) node.addEventListener(type, handler);
199
+ }
200
+ for (const child of children) {
201
+ if (child === null || child === void 0 || child === false) continue;
202
+ node.append(typeof child === "string" || typeof child === "number" ? String(child) : child);
203
+ }
204
+ return node;
205
+ }
206
+ function mountHost(doc, css) {
207
+ const host = doc.createElement(SITE_HOST_TAG);
208
+ const style = {
209
+ all: "initial",
210
+ position: "fixed",
211
+ inset: "0",
212
+ "pointer-events": "none",
213
+ "z-index": "2147483647",
214
+ display: "block"
215
+ };
216
+ for (const [name, value] of Object.entries(style))
217
+ host.style.setProperty(name, value, "important");
218
+ const root = host.attachShadow({ mode: "closed" });
219
+ const sheet = doc.createElement("style");
220
+ sheet.textContent = BASE_CSS + css;
221
+ root.append(sheet);
222
+ doc.documentElement.appendChild(host);
223
+ return { host, root, destroy: () => host.remove() };
224
+ }
225
+ function initials(name) {
226
+ const words = (name ?? "").trim().split(/\s+/).filter(Boolean);
227
+ return words.slice(0, 2).map((word) => word.charAt(0).toUpperCase()).join("");
228
+ }
229
+ var TOKENS = {
230
+ fg: "#010313",
231
+ muted: "#5A6C85",
232
+ border: "#E2E8F0",
233
+ bg: "#FFFFFF",
234
+ subtle: "#EAEEF3",
235
+ primary: "#287CCF",
236
+ primaryBorder: "#4B97DE",
237
+ dark: "#0F172B",
238
+ gold: "#9A6200",
239
+ goldTint: "#FDF3E1",
240
+ goldText: "#7A4D00",
241
+ danger: "#C62828",
242
+ focus: "rgba(144,161,185,0.5)"
243
+ };
244
+ var T = TOKENS;
245
+ var FONT = "Poppins, ui-sans-serif, system-ui, sans-serif";
246
+ var BASE_CSS = `
247
+ :host { all: initial; }
248
+ * { box-sizing: border-box; }
249
+ .layer { position: fixed; inset: 0; pointer-events: none; font-family: ${FONT}; color: ${T.fg};
250
+ font-size: 13px; line-height: 1.45; -webkit-font-smoothing: antialiased; }
251
+ .icon { display: inline-flex; flex-shrink: 0; }
252
+ .icon svg { width: 100%; height: 100%; display: block; }
253
+ button { font: 500 13px ${FONT}; color: inherit; cursor: pointer; border: 0; background: transparent;
254
+ display: inline-flex; align-items: center; gap: 6px; padding: 0; margin: 0; }
255
+ button:focus-visible, textarea:focus-visible, input:focus-visible { outline: none; box-shadow: 0 0 0 3px ${T.focus}; }
256
+ button:disabled { opacity: .55; cursor: default; }
257
+ .card { pointer-events: auto; position: fixed; background: ${T.bg}; border: 1px solid ${T.border};
258
+ border-radius: 15px; box-shadow: 0 20px 25px -5px rgba(15,23,42,.12), 0 8px 10px -6px rgba(15,23,42,.08); }
259
+ .muted { color: ${T.muted}; }
260
+ h2 { margin: 0; font: 600 15px ${FONT}; color: ${T.fg}; display: flex; align-items: center; gap: 8px; }
261
+ p { margin: 0; }
262
+ .iconbtn { width: 28px; height: 28px; justify-content: center; border-radius: 7px; color: ${T.muted}; }
263
+ .iconbtn:hover { background: ${T.subtle}; }
264
+ .btn { height: 34px; padding: 0 14px 0 11px; border-radius: 9px; white-space: nowrap; flex-shrink: 0;
265
+ box-shadow: 0 1px 2px rgba(15,23,42,.05); }
266
+ .btn-outline { border: 1px solid ${T.border}; background: ${T.bg}; color: ${T.fg}; }
267
+ .btn-primary { border: 1px solid ${T.primaryBorder}; background: ${T.primary}; color: #FAFAFA; }
268
+ .btn-dark { width: 100%; height: 38px; justify-content: center; gap: 8px; border-radius: 9px;
269
+ background: ${T.dark}; color: #FFFFFF; }
270
+ .error { color: ${T.danger}; font-size: 12px; }
271
+ @media (max-width: 480px) { .card.sheet { left: 8px !important; right: 8px !important; width: auto !important; } }
272
+ `;
273
+
274
+ export {
275
+ SIGNIN_MESSAGES,
276
+ SUGGEST_MESSAGES,
277
+ icon,
278
+ el,
279
+ mountHost,
280
+ initials,
281
+ TOKENS
282
+ };
283
+ //# sourceMappingURL=chunk-2IUU53QA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/preview/site/messages.ts","../src/preview/site/ui.ts"],"sourcesContent":["/**\n * The site tools' own words («Editar» and «Comentar», zap-cms-v2 §3.4), Spanish and English (Spanish by default, as\n * the suite; `<html lang=\"en…\">` or `initZap({ locale: 'en' })` picks\n * English). Two objects, one per chunk, so each chunk carries only its own\n * copy. Plain strings and functions: the core has no i18n runtime, and these\n * never reach the server. Copy rules (`.docs/ui-patterns/copy.md`): no\n * ellipses, em dashes, middots or parentheses.\n */\n\ntype Locale = 'es' | 'en'\n\nconst plural = (count: number, one: string, other: string) =>\n (count === 1 ? one : other).replace('{n}', String(count))\n\nexport const SIGNIN_MESSAGES = {\n es: {\n launcher: 'Editar o comentar',\n hintBefore: 'Pulsa',\n hintAfter: 'para editar o comentar',\n title: 'Edita o comenta esta página',\n body: 'Escribe sobre el texto de la página o deja un comentario. Lo que edites queda en el borrador y se publica desde Zap.',\n signIn: 'Entrar con Eel',\n note: 'Solo para personas con Zap en este sitio. Los visitantes no ven nada de esto.',\n waiting: 'Esperando a Eel',\n waitingHelp: 'Termina en la ventana de Eel. Si la cerraste, vuelve a intentarlo.',\n retry: 'Intentar de nuevo',\n close: 'Cerrar',\n expired: 'Tu sesión terminó. Entra de nuevo para seguir.',\n failed: 'No pudimos completar la entrada. Intenta de nuevo.',\n },\n en: {\n launcher: 'Edit or comment',\n hintBefore: 'Press',\n hintAfter: 'to edit or comment',\n title: 'Edit or comment on this page',\n body: 'Type over the text on the page or leave a comment. What you edit goes to the draft and is published from Zap.',\n signIn: 'Sign in with Eel',\n note: 'Only for people with Zap on this site. Visitors see none of this.',\n waiting: 'Waiting for Eel',\n waitingHelp: 'Finish in the Eel window. If you closed it, try again.',\n retry: 'Try again',\n close: 'Close',\n expired: 'Your session ended. Sign in again to keep going.',\n failed: 'We could not finish signing you in. Try again.',\n },\n} satisfies Record<Locale, Record<string, string>>\n\nexport const SUGGEST_MESSAGES = {\n es: {\n toolbar: 'Zap en esta página',\n tools: 'Herramienta',\n navigate: 'Navegar',\n edit: 'Editar',\n comment: 'Comentar',\n editOff: 'Desactivado por un administrador',\n open: (n: number) => plural(n, '{n} abierto', '{n} abiertos'),\n openTitle: 'Comentarios abiertos en esta página',\n noneOpen: 'No hay comentarios abiertos en esta página.',\n changeRequest: 'Solicitud de cambio',\n exit: 'Salir',\n newComment: 'Nuevo comentario',\n commentTitle: 'Comentario',\n selected: (n: number) => plural(n, '{n} elemento seleccionado', '{n} elementos seleccionados'),\n clearSelection: 'Cancelar',\n commentLabel: 'Comentario',\n commentPlaceholder: 'Escribe tu comentario',\n requestChange: 'Solicitar cambio',\n requestHelp: 'Queda abierta hasta que alguien la resuelva o aplique el texto propuesto.',\n recipient: 'La recibe la persona responsable en Zap.',\n propose: 'Proponer texto',\n proposalFor: 'Texto propuesto para',\n removeProposal: 'Quitar texto propuesto',\n now: 'Ahora:',\n proposal: 'Texto propuesto',\n cancel: 'Cancelar',\n close: 'Cerrar',\n sending: 'Enviando',\n save: 'Guardar',\n sentComment: 'Comentario enviado',\n sentCommentBody: 'Tu equipo lo verá en Zap.',\n sentRequest: 'Solicitud de cambio enviada',\n sentRequestBody: (name: string | null, proposal: boolean) =>\n `${name ? `${name} la verá` : 'La persona responsable la verá'} en Zap${\n proposal ? ' con tu texto propuesto' : ''\n }. La página no cambia hasta que se publique.`,\n saving: 'Guardando',\n saved: 'Guardado en el borrador',\n notEditable: 'Esto no se edita aquí',\n notEditableBody: 'Usa Comentar para pedir el cambio.',\n editOffBody: 'Un administrador desactivó Editar en este sitio.',\n renewed: 'Sesión renovada',\n renewedAs: (name: string) => `Sigues como ${name}`,\n renewedBody: 'Sigues donde ibas.',\n dismiss: 'Cerrar aviso',\n someone: 'Alguien',\n refusedTitle: 'No puedes editar ni comentar en este sitio',\n refusedBody: 'Tu cuenta no tiene acceso a Zap aquí, o el sitio dejó de permitirlo.',\n rateLimited: (n: number) =>\n plural(\n n,\n 'Enviaste muchos seguidos. Intenta de nuevo en {n} segundo.',\n 'Enviaste muchos seguidos. Intenta de nuevo en {n} segundos.',\n ),\n failed: 'No se pudo enviar. Revisa el texto e intenta de nuevo.',\n saveFailed: 'No se pudo guardar. El texto volvió a como estaba.',\n noRecord: 'Esta parte de la página no es contenido de Zap.',\n invalidNumber: 'Escribe un número.',\n },\n en: {\n toolbar: 'Zap on this page',\n tools: 'Tool',\n navigate: 'Browse',\n edit: 'Edit',\n comment: 'Comment',\n editOff: 'Turned off by an administrator',\n open: (n: number) => plural(n, '{n} open', '{n} open'),\n openTitle: 'Open comments on this page',\n noneOpen: 'No open comments on this page.',\n changeRequest: 'Change request',\n exit: 'Sign out',\n newComment: 'New comment',\n commentTitle: 'Comment',\n selected: (n: number) => plural(n, '{n} element selected', '{n} elements selected'),\n clearSelection: 'Cancel',\n commentLabel: 'Comment',\n commentPlaceholder: 'Write your comment',\n requestChange: 'Request a change',\n requestHelp: 'It stays open until someone resolves it or applies the proposed text.',\n recipient: 'The person responsible in Zap receives it.',\n propose: 'Propose text',\n proposalFor: 'Proposed text for',\n removeProposal: 'Remove proposed text',\n now: 'Now:',\n proposal: 'Proposed text',\n cancel: 'Cancel',\n close: 'Close',\n sending: 'Sending',\n save: 'Save',\n sentComment: 'Comment sent',\n sentCommentBody: 'Your team will see it in Zap.',\n sentRequest: 'Change request sent',\n sentRequestBody: (name: string | null, proposal: boolean) =>\n `${name ?? 'The person responsible'} will see it in Zap${\n proposal ? ' with your proposed text' : ''\n }. The page does not change until it is published.`,\n saving: 'Saving',\n saved: 'Saved to the draft',\n notEditable: 'This is not edited here',\n notEditableBody: 'Use Comment to ask for the change.',\n editOffBody: 'An administrator turned off Edit for this site.',\n renewed: 'Session renewed',\n renewedAs: (name: string) => `You are still ${name}`,\n renewedBody: 'Pick up where you left off.',\n dismiss: 'Dismiss',\n someone: 'Someone',\n refusedTitle: 'You cannot edit or comment on this site',\n refusedBody: 'Your account has no Zap access here, or the site stopped allowing it.',\n rateLimited: (n: number) =>\n plural(\n n,\n 'You sent many in a row. Try again in {n} second.',\n 'You sent many in a row. Try again in {n} seconds.',\n ),\n failed: 'Could not send. Check the text and try again.',\n saveFailed: 'Could not save. The text is back to what it was.',\n noRecord: 'This part of the page is not Zap content.',\n invalidNumber: 'Enter a number.',\n },\n}\n\nexport type SuggestMessages = (typeof SUGGEST_MESSAGES)['es']\nexport type SigninMessages = (typeof SIGNIN_MESSAGES)['es']\n","/**\n * The site tools' building blocks, shared by the `signin` and `suggest`\n * chunks (zap-cms-v2 §2.7, §7.3):\n *\n * - **A closed Shadow DOM** on a custom element appended to `<html>`, styled\n * `all: initial` with `!important` inline, so the site's CSS cannot restyle\n * it, it cannot restyle the site, and site scripts get no `shadowRoot`.\n * - **Eel tokens inlined** (`TOKENS`): the boards' colours, radii and Poppins\n * with system fallbacks; nothing is fetched.\n * - **Text only.** `el()` takes text as text: strings become text nodes, never\n * markup. The single `innerHTML` is `icon()`, which reads a constant SVG from\n * `ICONS` by name; no network string ever reaches it.\n */\n\nexport const SITE_HOST_TAG = 'eel-zap-site'\n\nconst ZAP_BOLT =\n '<svg viewBox=\"0 0 512 512\"><g transform=\"matrix(27.611111,0,0,24.833333,-74.833333,-42)\"><path d=\"M13,2L3,14L10.036,11.906L10,22L20.964,9.235L12.913,11.973L13,2Z\" fill=\"#F1A10D\" stroke=\"#F1A10D\" stroke-width=\"0.5\"/><path d=\"M13,2L6.518,12.953L10.036,11.906L12.913,11.973L13,2Z\" fill=\"#FFC03A\"/><path d=\"M10.036,11.906L10,22L20.964,9.235L12.913,11.973L10.036,11.906Z\" fill=\"#D98A05\"/><path d=\"M10,22L20.964,9.235L16.939,10.604L10,22Z\" fill=\"#BF7500\"/></g></svg>'\n\nconst EEL_MARK =\n '<svg viewBox=\"0 0 3000 3000\" fill=\"currentColor\"><g transform=\"matrix(1.01772,-0.122618,0.122163,1.013948,-241.899218,117.348723)\"><g transform=\"matrix(1.192409,0,0,1.144788,-367.077609,-248.030951)\"><path d=\"M2789.774,1920.921C2642.929,2454.806 2170.478,2846 1611,2846C934.352,2846 385,2273.795 385,1569C385,864.205 934.352,292 1611,292C1849.726,292 2072.607,363.224 2261.109,486.366C2132.562,436.833 1991.613,409.484 1843.83,409.484C1242.576,409.484 754.435,862.18 754.435,1419.774C754.435,1977.368 1242.576,2430.064 1843.83,2430.064C2248.492,2430.064 2601.918,2225.006 2789.774,1920.921Z\"/></g><g transform=\"matrix(1.434867,0,-0,0.933341,-1232.183743,68.591241)\"><path d=\"M2196.648,369.772C2557.019,431.746 2832,753.678 2832,1141C2832,1572.598 2490.559,1923 2070,1923C1813.847,1923 1587.045,1793.01 1448.867,1593.857C1561.131,1687.675 1700.963,1743.353 1852.482,1743.353C2222.082,1743.353 2522.15,1412.061 2522.15,1004.003C2522.15,734.845 2391.596,499.086 2196.648,369.772Z\"/></g></g></svg>'\n\nconst stroke = (paths: string) =>\n `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${paths}</svg>`\n\n/** Constant markup only. Adding an icon means adding a literal here. */\nexport const ICONS = {\n zap: ZAP_BOLT,\n eel: EEL_MARK,\n x: stroke('<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>'),\n lock: stroke(\n '<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>',\n ),\n pointer: stroke(\n '<path d=\"M12.586 12.586 19 19\"/><path d=\"M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z\"/>',\n ),\n pencil: stroke(\n '<path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\"/>',\n ),\n commentPlus: stroke(\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/><path d=\"M12 7v6\"/><path d=\"M9 10h6\"/>',\n ),\n thread: stroke(\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/><path d=\"M13 8H7\"/><path d=\"M17 12H7\"/>',\n ),\n exit: stroke(\n '<path d=\"m16 17 5-5-5-5\"/><path d=\"M21 12H9\"/><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/>',\n ),\n check: stroke('<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m9 12 2 2 4-4\"/>'),\n alert: stroke('<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 8v4\"/><path d=\"M12 16h.01\"/>'),\n field: stroke('<path d=\"M4 7V4h16v3\"/><path d=\"M9 20h6\"/><path d=\"M12 4v16\"/>'),\n} as const\n\nexport type IconName = keyof typeof ICONS\n\nexport function icon(doc: Document, name: IconName, size = 15): HTMLElement {\n const span = doc.createElement('span')\n span.className = 'icon'\n span.style.width = `${size}px`\n span.style.height = `${size}px`\n span.setAttribute('aria-hidden', 'true')\n // A constant from ICONS, never network data (§7.3).\n span.innerHTML = ICONS[name]\n return span\n}\n\ntype Child = Node | string | number | null | undefined | false\n\nexport interface ElProps {\n class?: string\n attrs?: Record<string, string | null | undefined>\n text?: string\n on?: Partial<Record<string, (event: Event) => void>>\n}\n\n/** An element whose children are nodes or TEXT. Strings are never parsed as markup. */\nexport function el<K extends keyof HTMLElementTagNameMap>(\n doc: Document,\n tag: K,\n props: ElProps = {},\n children: Child[] = [],\n): HTMLElementTagNameMap[K] {\n const node = doc.createElement(tag)\n if (props.class) node.className = props.class\n for (const [name, value] of Object.entries(props.attrs ?? {})) {\n if (value !== null && value !== undefined) node.setAttribute(name, value)\n }\n if (props.text !== undefined) node.textContent = props.text\n for (const [type, handler] of Object.entries(props.on ?? {})) {\n if (handler) node.addEventListener(type, handler)\n }\n for (const child of children) {\n if (child === null || child === undefined || child === false) continue\n node.append(typeof child === 'string' || typeof child === 'number' ? String(child) : child)\n }\n return node\n}\n\nexport interface SiteHost {\n host: HTMLElement\n root: ShadowRoot\n destroy(): void\n}\n\n/** The closed shadow host, on `<html>` so a site that replaces `<body>` keeps it. */\nexport function mountHost(doc: Document, css: string): SiteHost {\n const host = doc.createElement(SITE_HOST_TAG)\n const style: Record<string, string> = {\n all: 'initial',\n position: 'fixed',\n inset: '0',\n 'pointer-events': 'none',\n 'z-index': '2147483647',\n display: 'block',\n }\n for (const [name, value] of Object.entries(style))\n host.style.setProperty(name, value, 'important')\n const root = host.attachShadow({ mode: 'closed' })\n const sheet = doc.createElement('style')\n sheet.textContent = BASE_CSS + css\n root.append(sheet)\n doc.documentElement.appendChild(host)\n return { host, root, destroy: () => host.remove() }\n}\n\n/** Initials for an avatar: first letters of the first two words. */\nexport function initials(name: string | null | undefined): string {\n const words = (name ?? '').trim().split(/\\s+/).filter(Boolean)\n return words\n .slice(0, 2)\n .map((word) => word.charAt(0).toUpperCase())\n .join('')\n}\n\n/** Eel tokens, inlined (boards SitioLanzador to SitioRenovacion). */\nexport const TOKENS = {\n fg: '#010313',\n muted: '#5A6C85',\n border: '#E2E8F0',\n bg: '#FFFFFF',\n subtle: '#EAEEF3',\n primary: '#287CCF',\n primaryBorder: '#4B97DE',\n dark: '#0F172B',\n gold: '#9A6200',\n goldTint: '#FDF3E1',\n goldText: '#7A4D00',\n danger: '#C62828',\n focus: 'rgba(144,161,185,0.5)',\n}\n\nconst T = TOKENS\nconst FONT = 'Poppins, ui-sans-serif, system-ui, sans-serif'\n\nconst BASE_CSS = `\n:host { all: initial; }\n* { box-sizing: border-box; }\n.layer { position: fixed; inset: 0; pointer-events: none; font-family: ${FONT}; color: ${T.fg};\n font-size: 13px; line-height: 1.45; -webkit-font-smoothing: antialiased; }\n.icon { display: inline-flex; flex-shrink: 0; }\n.icon svg { width: 100%; height: 100%; display: block; }\nbutton { font: 500 13px ${FONT}; color: inherit; cursor: pointer; border: 0; background: transparent;\n display: inline-flex; align-items: center; gap: 6px; padding: 0; margin: 0; }\nbutton:focus-visible, textarea:focus-visible, input:focus-visible { outline: none; box-shadow: 0 0 0 3px ${T.focus}; }\nbutton:disabled { opacity: .55; cursor: default; }\n.card { pointer-events: auto; position: fixed; background: ${T.bg}; border: 1px solid ${T.border};\n border-radius: 15px; box-shadow: 0 20px 25px -5px rgba(15,23,42,.12), 0 8px 10px -6px rgba(15,23,42,.08); }\n.muted { color: ${T.muted}; }\nh2 { margin: 0; font: 600 15px ${FONT}; color: ${T.fg}; display: flex; align-items: center; gap: 8px; }\np { margin: 0; }\n.iconbtn { width: 28px; height: 28px; justify-content: center; border-radius: 7px; color: ${T.muted}; }\n.iconbtn:hover { background: ${T.subtle}; }\n.btn { height: 34px; padding: 0 14px 0 11px; border-radius: 9px; white-space: nowrap; flex-shrink: 0;\n box-shadow: 0 1px 2px rgba(15,23,42,.05); }\n.btn-outline { border: 1px solid ${T.border}; background: ${T.bg}; color: ${T.fg}; }\n.btn-primary { border: 1px solid ${T.primaryBorder}; background: ${T.primary}; color: #FAFAFA; }\n.btn-dark { width: 100%; height: 38px; justify-content: center; gap: 8px; border-radius: 9px;\n background: ${T.dark}; color: #FFFFFF; }\n.error { color: ${T.danger}; font-size: 12px; }\n@media (max-width: 480px) { .card.sheet { left: 8px !important; right: 8px !important; width: auto !important; } }\n`\n"],"mappings":"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","names":[]}
@@ -0,0 +1,64 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/preview/site/config.ts
6
+ var NEST_PRODUCTION_ORIGIN = "https://auth.eel.software";
7
+ var SITE_CLIENT_SCOPE = "zap:suggest:write";
8
+ var SIGNIN_CHANNEL = "eel-zap";
9
+ var STATE_PREFIX = "zap1.";
10
+ var TOKEN_STORAGE_KEY = "eelzap:site-token";
11
+ var PENDING_STORAGE_KEY = "eelzap:signin";
12
+ function siteClientId(zapOrigin, siteId) {
13
+ return `${zapOrigin}/oauth/clients/${siteId.toLowerCase()}.json`;
14
+ }
15
+
16
+ // src/preview/site/token.ts
17
+ var EXPIRY_MARGIN_MS = 3e4;
18
+ function store(win) {
19
+ try {
20
+ return win.sessionStorage;
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+ function readToken(win, siteId, now = Date.now()) {
26
+ const storage = store(win);
27
+ try {
28
+ const raw = storage?.getItem(TOKEN_STORAGE_KEY);
29
+ if (!raw) return null;
30
+ const value = JSON.parse(raw);
31
+ if (typeof value.token === "string" && value.token.startsWith("eel_at_") && typeof value.exp === "number" && value.exp - EXPIRY_MARGIN_MS > now && value.site === siteId) {
32
+ return { token: value.token, exp: value.exp, site: value.site };
33
+ }
34
+ storage?.removeItem(TOKEN_STORAGE_KEY);
35
+ } catch {
36
+ }
37
+ return null;
38
+ }
39
+ function writeToken(win, value) {
40
+ try {
41
+ store(win)?.setItem(TOKEN_STORAGE_KEY, JSON.stringify(value));
42
+ } catch {
43
+ }
44
+ }
45
+ function clearToken(win) {
46
+ try {
47
+ store(win)?.removeItem(TOKEN_STORAGE_KEY);
48
+ } catch {
49
+ }
50
+ }
51
+
52
+ export {
53
+ __publicField,
54
+ NEST_PRODUCTION_ORIGIN,
55
+ SITE_CLIENT_SCOPE,
56
+ SIGNIN_CHANNEL,
57
+ STATE_PREFIX,
58
+ PENDING_STORAGE_KEY,
59
+ siteClientId,
60
+ readToken,
61
+ writeToken,
62
+ clearToken
63
+ };
64
+ //# sourceMappingURL=chunk-QN53G5P7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/preview/site/config.ts","../src/preview/site/token.ts"],"sourcesContent":["/**\n * «Editar» and «Comentar» on the customer's site (zap-cms-v2 §3.4, ADR 041):\n * the constants and the context the core hands its two lazy chunks.\n *\n * Three pieces, so an ordinary visitor downloads nothing beyond the core:\n *\n * - the core (`boot.ts`, in the `./preview` budget): the opt-in trigger\n * (`?zap` in the URL, or Shift Z), the OAuth callback relay on `{origin}/`,\n * and the loader;\n * - `signin` (loaded only on the trigger): the launcher, «Entrar con Eel», PKCE,\n * the popup or full-page redirect and the code exchange at Nest;\n * - `suggest` (loaded only after sign-in; the name is the file's, kept): the\n * toolbar, Navegar, Editar and Comentar, the composer, the numbered pins\n * and the calls to Zap.\n *\n * No directive, no imports: pure values both chunks and the core share.\n */\n\n/** Nest, the suite's OAuth issuer (ADR 024). Compiled in; `authOrigin` is the dev opt-in. */\nexport const NEST_PRODUCTION_ORIGIN = 'https://auth.eel.software'\n\n/**\n * The scope a site client asks for, by name (ADR 041 §2). `zap:preview:read`\n * is not asked for until a «Ver borradores» feature needs it (Manager,\n * 2026-10-05); Nest would drop it anyway.\n */\nexport const SITE_CLIENT_SCOPE = 'zap:suggest:write'\n\n/** The popup hands the code to the opener tab over this channel (same origin). */\nexport const SIGNIN_CHANNEL = 'eel-zap'\n\n/** Every `state` this client mints starts with it, so a site's own `?code=` is never ours. */\nexport const STATE_PREFIX = 'zap1.'\n\n/** sessionStorage only (ADR 041 §7): the token, and a pending full-page sign-in. */\nexport const TOKEN_STORAGE_KEY = 'eelzap:site-token'\nexport const PENDING_STORAGE_KEY = 'eelzap:signin'\n\nexport type ChunkName = 'signin' | 'suggest'\n\n/** What a callback page carries back from Nest (`{origin}/?code&state&iss`). */\nexport interface CallbackParams {\n code: string\n state: string\n iss: string\n}\n\nexport interface StartOptions {\n /**\n * signin: open the panel at once, and why (`expired` after a 401 or the\n * hour). suggest: `renewed` after a sign-in that followed an expiry, which\n * says «Sesión renovada» (board SitioRenovacion).\n */\n reason?: 'expired' | 'trigger' | 'renewed'\n /** signin: finish a full-page sign-in that landed on this page. */\n callback?: CallbackParams\n}\n\nexport interface ChunkHandle {\n destroy(): void\n}\n\nexport interface ChunkModule {\n start(ctx: SiteContext, options?: StartOptions): ChunkHandle\n}\n\n/** Everything a chunk needs, decided once by the core. */\nexport interface SiteContext {\n win: Window\n doc: Document\n /** The Zap site's id (`data-site-id`); names its OAuth client. */\n siteId: string\n /** Where Zap's API and the client's CIMD document live. */\n zapOrigin: string\n /** Nest, the issuer: `/oauth/authorize`, `/api/oauth/token`, and the `iss` to expect. */\n authOrigin: string\n /** `{zapOrigin}/oauth/clients/{siteId}.json` (ADR 041 §1). */\n clientId: string\n /** `{page origin}/`, exactly as the CIMD document lists it. */\n redirectUri: string\n locale: 'es' | 'en'\n /** The letter pressed with Shift to open the tools, for the launcher's hint; false when off. */\n shortcut: string | false\n /** Replace whatever chunk is showing with `name`. */\n open(name: ChunkName, options?: StartOptions): Promise<void>\n /** Close the showing chunk; the trigger works again. */\n close(): void\n}\n\n/** The client id of one site, the same string `@eel/api-keys` `zapSiteClientId` builds. */\nexport function siteClientId(zapOrigin: string, siteId: string): string {\n return `${zapOrigin}/oauth/clients/${siteId.toLowerCase()}.json`\n}\n","import { TOKEN_STORAGE_KEY } from './config'\n\n/**\n * The site client's access token (ADR 041 §7): in memory and in\n * `sessionStorage`, never in `localStorage` or a cookie. It lives one hour and\n * comes with no refresh token, so when it is gone the person signs in again.\n *\n * Stored with its expiry and the site it was issued for: a token for another\n * site, a malformed entry or an expired one reads as nothing and is removed.\n */\n\nexport interface SiteToken {\n /** The `eel_at_` access token. */\n token: string\n /** Epoch ms when it stops working. */\n exp: number\n /** The site it was issued for. */\n site: string\n}\n\n/** How long before the real expiry we stop using a token, so a call never races it. */\nconst EXPIRY_MARGIN_MS = 30_000\n\nfunction store(win: Window): Storage | null {\n try {\n return win.sessionStorage\n } catch {\n return null\n }\n}\n\nexport function readToken(win: Window, siteId: string, now = Date.now()): SiteToken | null {\n const storage = store(win)\n try {\n const raw = storage?.getItem(TOKEN_STORAGE_KEY)\n if (!raw) return null\n const value = JSON.parse(raw) as Partial<SiteToken>\n if (\n typeof value.token === 'string' &&\n value.token.startsWith('eel_at_') &&\n typeof value.exp === 'number' &&\n value.exp - EXPIRY_MARGIN_MS > now &&\n value.site === siteId\n ) {\n return { token: value.token, exp: value.exp, site: value.site }\n }\n storage?.removeItem(TOKEN_STORAGE_KEY)\n } catch {\n // Unreadable entry or blocked storage: no token.\n }\n return null\n}\n\nexport function writeToken(win: Window, value: SiteToken): void {\n try {\n store(win)?.setItem(TOKEN_STORAGE_KEY, JSON.stringify(value))\n } catch {\n // Blocked storage: the token lives in memory for this page only.\n }\n}\n\nexport function clearToken(win: Window): void {\n try {\n store(win)?.removeItem(TOKEN_STORAGE_KEY)\n } catch {\n // Nothing to clear.\n }\n}\n"],"mappings":";;;;;AAmBO,IAAM,yBAAyB;AAO/B,IAAM,oBAAoB;AAG1B,IAAM,iBAAiB;AAGvB,IAAM,eAAe;AAGrB,IAAM,oBAAoB;AAC1B,IAAM,sBAAsB;AAsD5B,SAAS,aAAa,WAAmB,QAAwB;AACtE,SAAO,GAAG,SAAS,kBAAkB,OAAO,YAAY,CAAC;AAC3D;;;ACvEA,IAAM,mBAAmB;AAEzB,SAAS,MAAM,KAA6B;AAC1C,MAAI;AACF,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,KAAa,QAAgB,MAAM,KAAK,IAAI,GAAqB;AACzF,QAAM,UAAU,MAAM,GAAG;AACzB,MAAI;AACF,UAAM,MAAM,SAAS,QAAQ,iBAAiB;AAC9C,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QACE,OAAO,MAAM,UAAU,YACvB,MAAM,MAAM,WAAW,SAAS,KAChC,OAAO,MAAM,QAAQ,YACrB,MAAM,MAAM,mBAAmB,OAC/B,MAAM,SAAS,QACf;AACA,aAAO,EAAE,OAAO,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,MAAM,KAAK;AAAA,IAChE;AACA,aAAS,WAAW,iBAAiB;AAAA,EACvC,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEO,SAAS,WAAW,KAAa,OAAwB;AAC9D,MAAI;AACF,UAAM,GAAG,GAAG,QAAQ,mBAAmB,KAAK,UAAU,KAAK,CAAC;AAAA,EAC9D,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,WAAW,KAAmB;AAC5C,MAAI;AACF,UAAM,GAAG,GAAG,WAAW,iBAAiB;AAAA,EAC1C,QAAQ;AAAA,EAER;AACF;","names":[]}