@agentprojectcontext/apx 1.40.1 → 1.42.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/package.json +1 -1
- package/src/interfaces/desktop/renderer.js +43 -34
- package/src/interfaces/desktop/style.css +30 -0
- package/src/interfaces/web/dist/assets/{index-DW7j3cXB.js → index-BReF4_xV.js} +21 -21
- package/src/interfaces/web/dist/assets/{index-DW7j3cXB.js.map → index-BReF4_xV.js.map} +1 -1
- package/src/interfaces/web/dist/index.html +1 -1
- package/src/interfaces/web/package-lock.json +3 -3
package/package.json
CHANGED
|
@@ -132,9 +132,8 @@
|
|
|
132
132
|
<div class="center" id="cap-center"></div>
|
|
133
133
|
<div class="cap-actions" id="cap-actions"></div>
|
|
134
134
|
</div>
|
|
135
|
-
<div id="caption-slot"></div>
|
|
136
135
|
<div id="conv-slot"></div>
|
|
137
|
-
<div id="
|
|
136
|
+
<div id="footer-slot"></div>
|
|
138
137
|
`;
|
|
139
138
|
const $cap = $root.querySelector("#cap");
|
|
140
139
|
const $capBadge = $root.querySelector("#cap-badge");
|
|
@@ -142,9 +141,14 @@
|
|
|
142
141
|
const $badgeTxt = $root.querySelector("#badge-txt");
|
|
143
142
|
const $capCenter = $root.querySelector("#cap-center");
|
|
144
143
|
const $capActions = $root.querySelector("#cap-actions");
|
|
145
|
-
const $captionSlot = $root.querySelector("#caption-slot");
|
|
146
144
|
const $convSlot = $root.querySelector("#conv-slot");
|
|
147
|
-
const $
|
|
145
|
+
const $footerSlot = $root.querySelector("#footer-slot");
|
|
146
|
+
|
|
147
|
+
// Footer (hint + session actions) state: the shortcut to display and a
|
|
148
|
+
// signature guard so render() doesn't rebuild the bar (and re-trigger the
|
|
149
|
+
// pill animation) on every keystroke.
|
|
150
|
+
let captionShortcut = "CommandOrControl+G";
|
|
151
|
+
let footerSig = "";
|
|
148
152
|
|
|
149
153
|
$badgeMic.innerHTML = ICON.mic();
|
|
150
154
|
$badgeTxt.innerHTML = ICON.text();
|
|
@@ -172,7 +176,7 @@
|
|
|
172
176
|
}
|
|
173
177
|
document.documentElement.setAttribute("data-theme", theme);
|
|
174
178
|
setPosition(position);
|
|
175
|
-
|
|
179
|
+
captionShortcut = shortcut || "CommandOrControl+G";
|
|
176
180
|
configReady = true;
|
|
177
181
|
// If render() already fired the bootstrap paint (because the IPC was
|
|
178
182
|
// slow), the existing input has the stale placeholder. Patch it in
|
|
@@ -184,7 +188,7 @@
|
|
|
184
188
|
}).catch(() => {
|
|
185
189
|
document.documentElement.setAttribute("data-theme", "light");
|
|
186
190
|
setPosition("right");
|
|
187
|
-
|
|
191
|
+
captionShortcut = "CommandOrControl+G";
|
|
188
192
|
configReady = true;
|
|
189
193
|
render();
|
|
190
194
|
});
|
|
@@ -208,12 +212,36 @@
|
|
|
208
212
|
.replace(/\+/g, "");
|
|
209
213
|
}
|
|
210
214
|
|
|
211
|
-
function
|
|
212
|
-
const sc = formatShortcut(
|
|
213
|
-
|
|
214
|
-
<
|
|
215
|
-
|
|
215
|
+
function captionHtml() {
|
|
216
|
+
const sc = formatShortcut(captionShortcut);
|
|
217
|
+
return `<div class="caption">Mantené <span class="kbd">${sc}</span> para hablar
|
|
218
|
+
<span class="kbd">⌥ /</span> para escribir</div>`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Unified bottom bar: the "Mantené ⌘G…" hint on the LEFT, session actions on
|
|
222
|
+
// the RIGHT — small translucent pills in the same glass language as the hint
|
|
223
|
+
// (not the old big white buttons). "Cerrar ventana" is always present so the
|
|
224
|
+
// empty-idle window can be dismissed; "Nueva sesión" joins once a session
|
|
225
|
+
// exists. The conversation card sits above this bar (input → messages → bar).
|
|
226
|
+
function renderFooter() {
|
|
227
|
+
const hasSession = messages.length > 0;
|
|
228
|
+
// "Cerrar ventana" while it's alone (empty state); shortened to "Cerrar"
|
|
229
|
+
// once "Nueva sesión" joins so all three pills fit on one line.
|
|
230
|
+
const closeLabel = hasSession ? "Cerrar" : "Cerrar ventana";
|
|
231
|
+
const sig = `${hasSession}|${captionShortcut}`;
|
|
232
|
+
if (sig === footerSig && $footerSlot.firstChild) return; // no churn per keystroke
|
|
233
|
+
footerSig = sig;
|
|
234
|
+
$footerSlot.innerHTML = `
|
|
235
|
+
<div class="footer-bar">
|
|
236
|
+
${captionHtml()}
|
|
237
|
+
<div class="footer-actions">
|
|
238
|
+
${hasSession ? `<button class="cap-pill act-new" id="btn-new"><span class="ic">${ICON.plus()}</span> Nueva sesión</button>` : ""}
|
|
239
|
+
<button class="cap-pill act-close" id="btn-close"><span class="ic">${ICON.close()}</span> ${closeLabel}</button>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
216
242
|
`;
|
|
243
|
+
$footerSlot.querySelector("#btn-new")?.addEventListener("click", newSession);
|
|
244
|
+
$footerSlot.querySelector("#btn-close")?.addEventListener("click", closeWindow);
|
|
217
245
|
}
|
|
218
246
|
|
|
219
247
|
// ── Render: capsule center + actions vary by mode ────────────────────────
|
|
@@ -338,15 +366,9 @@
|
|
|
338
366
|
addBtn("ghost", "Detener", ICON.stop(), () => stopSpeaking());
|
|
339
367
|
}
|
|
340
368
|
|
|
341
|
-
//
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// session bar visible when there are messages
|
|
345
|
-
if (messages.length > 0 || mode !== "idle") {
|
|
346
|
-
renderSessionBar();
|
|
347
|
-
} else {
|
|
348
|
-
$sessionSlot.innerHTML = "";
|
|
349
|
-
}
|
|
369
|
+
// Unified bottom bar (hint on the left + session actions on the right) —
|
|
370
|
+
// always present, so there's always a way to close the window.
|
|
371
|
+
renderFooter();
|
|
350
372
|
|
|
351
373
|
// conv card visible when there's any content
|
|
352
374
|
const wantConv = messages.length > 0 || mode === "transcribing" || mode === "thinking" || mode === "speaking";
|
|
@@ -356,18 +378,6 @@
|
|
|
356
378
|
requestWindowResize();
|
|
357
379
|
}
|
|
358
380
|
|
|
359
|
-
function renderSessionBar() {
|
|
360
|
-
if ($sessionSlot.querySelector(".session-bar")) return; // keep DOM stable
|
|
361
|
-
$sessionSlot.innerHTML = `
|
|
362
|
-
<div class="session-bar">
|
|
363
|
-
<button class="sbtn new" id="btn-new"><span class="ic">${ICON.plus()}</span> Nueva sesión</button>
|
|
364
|
-
<button class="sbtn close" id="btn-close"><span class="ic">${ICON.close()}</span> Cerrar</button>
|
|
365
|
-
</div>
|
|
366
|
-
`;
|
|
367
|
-
$sessionSlot.querySelector("#btn-new").addEventListener("click", newSession);
|
|
368
|
-
$sessionSlot.querySelector("#btn-close").addEventListener("click", closeWindow);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
381
|
// ── Conversation card ────────────────────────────────────────────────────
|
|
372
382
|
let $convScroll = null;
|
|
373
383
|
function ensureConv() {
|
|
@@ -1115,9 +1125,8 @@
|
|
|
1115
1125
|
toolPillsByName = {};
|
|
1116
1126
|
pendingUserText = "";
|
|
1117
1127
|
$convSlot.innerHTML = "";
|
|
1118
|
-
$sessionSlot.innerHTML = "";
|
|
1119
1128
|
mode = "idle";
|
|
1120
|
-
render();
|
|
1129
|
+
render(); // footer rebuilds (drops "Nueva sesión" now that there's no session)
|
|
1121
1130
|
}
|
|
1122
1131
|
function closeWindow() { window.apx?.close?.(); }
|
|
1123
1132
|
|
|
@@ -193,6 +193,36 @@ button { font-family: inherit; }
|
|
|
193
193
|
}
|
|
194
194
|
[data-theme="dark"] .kbd { color: color-mix(in oklch, var(--accent) 60%, white); }
|
|
195
195
|
|
|
196
|
+
/* Bottom bar: the "Mantené ⌘G…" hint on the left, small session-action pills
|
|
197
|
+
on the right. The conversation card (when present) sits above this bar. */
|
|
198
|
+
.footer-bar {
|
|
199
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
200
|
+
gap: 10px; flex-wrap: wrap;
|
|
201
|
+
}
|
|
202
|
+
.footer-bar .caption { align-self: auto; }
|
|
203
|
+
.footer-actions { display: flex; align-items: center; gap: 7px; flex-shrink: 0; margin-left: auto; }
|
|
204
|
+
|
|
205
|
+
/* Translucent action pill — same glass language as .caption so the bar reads
|
|
206
|
+
as one hint layer rather than the old big white buttons. */
|
|
207
|
+
.cap-pill {
|
|
208
|
+
display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
|
|
209
|
+
font: inherit; font-size: 11px; font-weight: 600; color: rgba(255,255,255,.92);
|
|
210
|
+
padding: 5px 12px; border-radius: 9px;
|
|
211
|
+
background: rgba(20,22,32,.28); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
|
212
|
+
border: 1px solid rgba(255,255,255,.14);
|
|
213
|
+
text-shadow: 0 0.5px 1.5px rgba(0,0,0,.3);
|
|
214
|
+
transition: transform .14s ease, background .15s ease, border-color .15s ease, color .15s ease;
|
|
215
|
+
animation: captionIn .4s ease both;
|
|
216
|
+
white-space: nowrap;
|
|
217
|
+
}
|
|
218
|
+
.cap-pill .ic { display: inline-flex; align-items: center; }
|
|
219
|
+
.cap-pill svg { width: 13px; height: 13px; opacity: .9; }
|
|
220
|
+
.cap-pill:hover { transform: translateY(-1px); background: rgba(20,22,32,.42); }
|
|
221
|
+
.cap-pill:active { transform: scale(.96); }
|
|
222
|
+
.cap-pill.act-new:hover { border-color: color-mix(in oklch, var(--accent) 55%, transparent); }
|
|
223
|
+
.cap-pill.act-close:hover { border-color: rgba(255,120,110,.5); color: #fff; }
|
|
224
|
+
[data-theme="dark"] .cap-pill { background: rgba(0,0,0,.34); }
|
|
225
|
+
|
|
196
226
|
/* ============================================================
|
|
197
227
|
Conversation card
|
|
198
228
|
============================================================ */
|