/*
* Dev-only Impeccable Live state gallery.
*
* This is a static state harness, not a second implementation of Live. It
* mirrors the exact chrome vocabulary and state wording from:
* skill/scripts/live-browser.js
* skill/scripts/live/ui-core.mjs
* Command labels/icons are injected by LiveUiGallery.astro from the canonical
* skill/scripts/live/vocabulary.mjs export.
*/
const ICONS = Object.freeze({
pick: '',
insert: '',
detect: '',
chat: '',
voice: '',
submit: '',
tune: '',
edit: '',
trash: '',
exit: '',
});
function parseJson(root, selector, fallback = []) {
try {
return JSON.parse(root.querySelector(selector)?.textContent || '[]');
} catch {
return fallback;
}
}
function escapeHtml(value) {
return String(value ?? '')
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", ''');
}
function brandMark() {
return '';
}
function designMark() {
return '';
}
function hostPage({ edited = false, insert = false } = {}) {
return `
Northstar field journal · Edition 08
${edited ? 'Useful observations, refined.' : 'Useful observations from the long way around.'}
Four routes, annotated maps, and practical details for unhurried weekends.
`;
}
function selectionOutline() {
return '';
}
function dots({ arrived = 0, visible = 0, expected = 3, clickable = false } = {}) {
let html = '';
for (let index = 1; index <= expected; index += 1) {
const active = index === visible;
const pending = index > arrived;
const className = `lvg-dot${active ? ' is-active' : ''}${pending ? ' is-pending' : ''}`;
if (clickable && !pending) {
const target = index === 1 ? 'cycling-progressive' : 'cycling-second';
html += ``;
} else {
html += ``;
}
}
return html + '';
}
function configureBar({ actionLabel, count, listening = false, locked = false, insert = false, picker = '' } = {}) {
const inputValue = insert
? 'Add a compact proof strip'
: listening
? 'Tighten the hierarchy'
: locked
? ''
: 'Make this feel more confident';
const actionControl = insert ? '' : `
`;
return `
`;
}
function actionPicker(commands, selectedAction) {
return `
${commands.map((command) => `
`).join('')}
`;
}
function generatingBar(recovery = false, actionLabel = 'Freeform') {
return `
${escapeHtml(actionLabel)}
${dots({ expected: 3 })}
${recovery ? 'Variants ready. Reveal the selected element to resume.' : 'Source ready. Generating...'}
`;
}
function tuneButton(open) {
return `
`;
}
function cyclingBar({ arrived = 1, visible = 1, tune = false } = {}) {
const remaining = 3 - arrived;
return `
${dots({ arrived, visible, expected: 3, clickable: true })}
${visible}/3
${tuneButton(tune)}
${remaining > 0 ? `${remaining} more arriving...` : ''}
${tune ? tunePanel() : ''}
`;
}
function tunePanel() {
return `
`;
}
function statusBar(kind) {
if (kind === 'confirmed') {
return '';
}
return '';
}
function editBadge(editing = false) {
if (!editing) {
return ``;
}
return '';
}
function annotationLayer() {
return `
Keep this line on one row
`;
}
function pendingDock(kind) {
if (kind === 'attention') {
return `
`;
}
const applying = kind === 'applying';
return `
`;
}
function designPanel(tab = 'visual') {
const raw = tab === 'raw';
return `
`;
}
function globalBar({ connected = true, active = 'pick', steer = 'collapsed', detectCount = 0, designActive = false } = {}) {
const modeButton = (key, icon, label, target, extra = '') => {
const isActive = active === key || (key === 'design' && designActive);
return ``;
};
const steerHtml = steer === 'processing'
? `${ICONS.chat}
`
: steer === 'expanded'
? `${ICONS.chat}
`
: ``;
return `
${brandMark()}${connected ? '' : ''}
${modeButton('pick', ICONS.pick, 'Pick', 'configure-replace')}
${modeButton('insert', ICONS.insert, 'Insert', 'insert-placeholder')}
${modeButton('detect', ICONS.detect, 'Detect', 'global-tools', detectCount ? `${detectCount}` : '')}
${modeButton('design', designMark(), 'DESIGN.md', 'design-panel')}
${steerHtml}
`;
}
function sceneFor(state, context) {
const actionLabel = context.commands.find((command) => command.value === context.selectedAction)?.label || 'Freeform';
const commonGlobal = (opts = {}) => globalBar({ active: 'pick', ...opts });
switch (state) {
case 'global-disconnected':
return hostPage() + 'Agent disconnected - run live-poll.mjs to connect
' + commonGlobal({ connected: false });
case 'global-tools':
return hostPage() + commonGlobal({ active: 'detect', detectCount: 7, designActive: true });
case 'steer-expanded':
return hostPage() + commonGlobal({ steer: 'expanded' });
case 'steer-processing':
return hostPage() + commonGlobal({ steer: 'processing' });
case 'configure-replace':
return hostPage() + selectionOutline() + editBadge(false) + configureBar({ actionLabel, count: context.count }) + commonGlobal();
case 'action-picker':
return hostPage() + selectionOutline() + editBadge(false) + configureBar({ actionLabel, count: context.count, picker: actionPicker(context.commands, context.selectedAction) }) + commonGlobal();
case 'configure-listening':
return hostPage() + selectionOutline() + editBadge(false) + configureBar({ actionLabel, count: context.count, listening: true }) + commonGlobal();
case 'configure-locked':
return hostPage({ edited: true }) + selectionOutline() + editBadge(false) + configureBar({ actionLabel, count: context.count, locked: true }) + pendingDock('applying') + commonGlobal();
case 'annotation':
return hostPage() + selectionOutline() + annotationLayer() + configureBar({ actionLabel, count: context.count }) + commonGlobal();
case 'insert-placeholder':
return hostPage({ insert: true }) + '' + configureBar({ count: context.count, insert: true }) + globalBar({ active: 'insert' });
case 'generating':
return hostPage() + selectionOutline() + generatingBar(false, actionLabel) + commonGlobal();
case 'generation-recovery':
return hostPage() + generatingBar(true, actionLabel) + commonGlobal();
case 'cycling-progressive':
return hostPage() + selectionOutline() + cyclingBar({ arrived: 1, visible: 1 }) + commonGlobal();
case 'cycling-second':
return hostPage() + selectionOutline() + cyclingBar({ arrived: 2, visible: 2 }) + commonGlobal();
case 'tune-open':
return hostPage() + selectionOutline() + cyclingBar({ arrived: 3, visible: 2, tune: true }) + commonGlobal();
case 'applying':
return hostPage() + selectionOutline() + statusBar('applying') + commonGlobal();
case 'confirmed':
return hostPage({ edited: true }) + statusBar('confirmed') + commonGlobal();
case 'edit-copy':
return hostPage({ edited: true }) + selectionOutline() + editBadge(true) + configureBar({ actionLabel, count: context.count }) + commonGlobal();
case 'copy-pending':
return hostPage({ edited: true }) + pendingDock('pending') + commonGlobal();
case 'copy-applying':
return hostPage({ edited: true }) + pendingDock('applying') + commonGlobal();
case 'copy-attention':
return hostPage({ edited: true }) + pendingDock('attention') + commonGlobal();
case 'design-panel':
return hostPage() + designPanel(context.designTab) + globalBar({ active: 'design', designActive: true });
case 'toast-error':
return hostPage() + 'No variants were mounted. Please try again.
' + commonGlobal();
case 'global-ready':
default:
return hostPage() + commonGlobal();
}
}
function initLiveUiGallery(root) {
if (!root || root.dataset.galleryReady === 'true') return;
root.dataset.galleryReady = 'true';
const states = parseJson(root, '[data-live-gallery-states]');
const commands = parseJson(root, '[data-live-gallery-vocabulary]');
if (states.length === 0 || commands.length === 0) return;
const select = root.querySelector('[data-gallery-state]');
const groupReadout = root.querySelector('[data-gallery-state-group]');
const labelReadout = root.querySelector('[data-gallery-state-label]');
const quickNav = root.querySelector('.live-ui-gallery__quick-nav');
const previews = [...root.querySelectorAll('[data-live-gallery-preview]')];
let selectedAction = 'impeccable';
let count = 3;
let designTab = 'visual';
const stateIndex = (key) => Math.max(0, states.findIndex((state) => state.key === key));
const currentState = () => select?.value || states[0].key;
function render(nextState = currentState(), { focusSelect = false } = {}) {
const state = states[stateIndex(nextState)] || states[0];
if (select) select.value = state.key;
if (groupReadout) groupReadout.textContent = state.group;
if (labelReadout) labelReadout.textContent = state.label;
let activeStateButton = null;
root.querySelectorAll('[data-gallery-state-button]').forEach((button) => {
const active = button.dataset.galleryStateButton === state.key;
button.setAttribute('aria-current', active ? 'true' : 'false');
if (active) activeStateButton = button;
});
for (const preview of previews) {
preview.dataset.galleryState = state.key;
preview.setAttribute('aria-label', `${preview.dataset.liveGalleryPreview} host — ${state.label}`);
preview.innerHTML = sceneFor(state.key, { commands, selectedAction, count, designTab });
}
if (quickNav && activeStateButton) {
requestAnimationFrame(() => {
const navRect = quickNav.getBoundingClientRect();
const buttonRect = activeStateButton.getBoundingClientRect();
if (buttonRect.left < navRect.left) quickNav.scrollLeft -= navRect.left - buttonRect.left + 8;
if (buttonRect.right > navRect.right) quickNav.scrollLeft += buttonRect.right - navRect.right + 8;
});
}
if (focusSelect) select?.focus();
}
function step(delta) {
const next = (stateIndex(currentState()) + delta + states.length) % states.length;
render(states[next].key, { focusSelect: true });
}
select?.addEventListener('change', () => render(select.value));
root.addEventListener('click', (event) => {
const stepButton = event.target.closest('[data-gallery-step]');
if (stepButton) {
step(Number(stepButton.dataset.galleryStep) || 1);
return;
}
const stateButton = event.target.closest('[data-gallery-state-button]');
if (stateButton) {
render(stateButton.dataset.galleryStateButton);
return;
}
const actionButton = event.target.closest('[data-gallery-action]');
if (actionButton) {
selectedAction = actionButton.dataset.galleryAction || 'impeccable';
render('configure-replace');
return;
}
const countButton = event.target.closest('[data-gallery-count]');
if (countButton) {
count = count >= 4 ? 1 : count + 1;
render(currentState());
return;
}
const densityButton = event.target.closest('[data-gallery-density]');
if (densityButton) {
const value = densityButton.dataset.galleryDensity;
root.querySelectorAll('[data-gallery-density]').forEach((button) => {
button.setAttribute('aria-pressed', button.dataset.galleryDensity === value ? 'true' : 'false');
});
root.querySelectorAll('[data-gallery-density-output]').forEach((output) => { output.textContent = value; });
return;
}
const toggleButton = event.target.closest('[data-gallery-param-toggle]');
if (toggleButton) {
const next = toggleButton.getAttribute('aria-pressed') !== 'true';
root.querySelectorAll('[data-gallery-param-toggle]').forEach((button) => button.setAttribute('aria-pressed', String(next)));
root.querySelectorAll('[data-gallery-toggle-output]').forEach((output) => { output.textContent = next ? 'On' : 'Off'; });
return;
}
const designTabButton = event.target.closest('[data-gallery-design-tab]');
if (designTabButton) {
designTab = designTabButton.dataset.galleryDesignTab === 'raw' ? 'raw' : 'visual';
render('design-panel');
return;
}
const trigger = event.target.closest('[data-gallery-go]');
if (trigger && !trigger.disabled) render(trigger.dataset.galleryGo);
});
root.addEventListener('input', (event) => {
const range = event.target.closest('[data-gallery-range]');
if (!range) return;
const value = Number(range.value).toFixed(2);
root.querySelectorAll('[data-gallery-range]').forEach((input) => { if (input !== range) input.value = range.value; });
root.querySelectorAll('[data-gallery-range-output]').forEach((output) => { output.textContent = value; });
});
root.addEventListener('keydown', (event) => {
if (event.target.matches('[data-gallery-steer-input]') && event.key === 'Enter') {
event.preventDefault();
render('steer-processing');
return;
}
const stateButton = event.target.closest('[data-gallery-state-button]');
if (stateButton && ['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {
event.preventDefault();
const current = stateIndex(stateButton.dataset.galleryStateButton);
const next = event.key === 'Home'
? 0
: event.key === 'End'
? states.length - 1
: (current + (event.key === 'ArrowLeft' ? -1 : 1) + states.length) % states.length;
render(states[next].key);
root.querySelector(`[data-gallery-state-button="${states[next].key}"]`)?.focus();
return;
}
const panel = event.target.closest('.live-ui-gallery__control-panel');
if (!panel || event.target.matches('input')) return;
if (event.key === 'ArrowLeft') {
event.preventDefault();
step(-1);
} else if (event.key === 'ArrowRight') {
event.preventDefault();
step(1);
} else if (event.key === 'Home') {
event.preventDefault();
render(states[0].key, { focusSelect: true });
} else if (event.key === 'End') {
event.preventDefault();
render(states[states.length - 1].key, { focusSelect: true });
}
});
render(states[0].key);
}
function initLiveUiGalleries() {
document.querySelectorAll('[data-live-ui-gallery]').forEach(initLiveUiGallery);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initLiveUiGalleries, { once: true });
} else {
initLiveUiGalleries();
}
document.addEventListener('astro:page-load', initLiveUiGalleries);