feat(extension): field-history pane visual polish — section headers + glyph buttons
This commit is contained in:
@@ -4,7 +4,7 @@ import { getState, setState, sendMessage, navigate, escapeHtml } from '../../sha
|
||||
import { colorizePassword } from '../../shared/password-coloring';
|
||||
import type { FieldHistoryView } from '../../shared/types';
|
||||
import { relativeTime } from '../../shared/relative-time';
|
||||
import { GLYPH_COPY } from '../../shared/glyphs';
|
||||
import { GLYPH_COPY, GLYPH_REVEAL, GLYPH_HIDE } from '../../shared/glyphs';
|
||||
|
||||
const revealedSet = new Set<string>();
|
||||
|
||||
@@ -58,27 +58,28 @@ export async function renderFieldHistory(app: HTMLElement): Promise<void> {
|
||||
const isRevealed = revealedSet.has(entryKey);
|
||||
const displayValue = isRevealed ? escapeHtml(value) : '••••••••••••';
|
||||
valueStore.set(entryKey, value);
|
||||
const revealGlyph = isRevealed ? GLYPH_HIDE : GLYPH_REVEAL;
|
||||
|
||||
return `
|
||||
<div class="history-entry" data-entry="${escapeHtml(entryKey)}">
|
||||
<div class="history-entry__value ${isRevealed ? 'revealed' : 'masked'}">${displayValue}</div>
|
||||
<div class="history-entry__meta">
|
||||
${isCurrent ? '<span class="history-entry__current">current</span>' : ''}
|
||||
<span>${isCurrent ? 'set' : 'changed'} ${relativeTime(timestamp)}</span>
|
||||
<div class="history-entry__meta muted">
|
||||
${isCurrent ? '<span class="history-entry__current">current · </span>' : ''}
|
||||
${isCurrent ? 'set' : 'changed'} ${escapeHtml(relativeTime(timestamp))}
|
||||
</div>
|
||||
<div class="history-entry__actions">
|
||||
<button class="glyph-btn" data-entry-reveal="${escapeHtml(entryKey)}" title="${isRevealed ? 'hide' : 'reveal'}" aria-label="${isRevealed ? 'hide' : 'reveal'}">${revealGlyph}</button>
|
||||
<button class="glyph-btn" data-entry-copy="${escapeHtml(entryKey)}" title="copy" aria-label="copy">${GLYPH_COPY}</button>
|
||||
</div>
|
||||
<button class="history-entry__copy" data-entry-copy="${escapeHtml(entryKey)}" title="Copy">${GLYPH_COPY}</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
let content = '';
|
||||
for (const field of history) {
|
||||
if (history.length > 1) {
|
||||
content += `<div class="history-field-label">${escapeHtml(field.field_name)}</div>`;
|
||||
}
|
||||
// Current value first
|
||||
const entryCount = field.entries.length + 1; // +1 for current
|
||||
content += `<div class="section-header">${escapeHtml(field.field_name.toUpperCase())} · ${entryCount} ${entryCount === 1 ? 'entry' : 'entries'}</div>`;
|
||||
content += renderEntry(field.field_id, field.current_value, item.modified, true);
|
||||
// Historical values
|
||||
for (const entry of field.entries) {
|
||||
content += renderEntry(field.field_id, entry.value, entry.changed_at, false);
|
||||
}
|
||||
@@ -108,17 +109,14 @@ export async function renderFieldHistory(app: HTMLElement): Promise<void> {
|
||||
// Wire handlers
|
||||
app.querySelector<HTMLButtonElement>('#back-btn')?.addEventListener('click', () => navigate('detail'));
|
||||
|
||||
// Toggle reveal on click
|
||||
app.querySelectorAll<HTMLElement>('.history-entry').forEach((el) => {
|
||||
el.addEventListener('click', (e) => {
|
||||
if ((e.target as HTMLElement).classList.contains('history-entry__copy')) return;
|
||||
const key = el.dataset.entry;
|
||||
// Reveal toggle via explicit glyph button (decoupled from row click)
|
||||
app.querySelectorAll<HTMLButtonElement>('[data-entry-reveal]').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const key = btn.dataset.entryReveal;
|
||||
if (!key) return;
|
||||
if (revealedSet.has(key)) {
|
||||
revealedSet.delete(key);
|
||||
} else {
|
||||
revealedSet.add(key);
|
||||
}
|
||||
if (revealedSet.has(key)) revealedSet.delete(key);
|
||||
else revealedSet.add(key);
|
||||
renderFieldHistory(app);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user