5 Commits

3 changed files with 55 additions and 12 deletions

View File

@@ -3,6 +3,12 @@
/// to the detail view.
import { getState, setState, sendMessage, navigate, escapeHtml, openVaultTab } from '../../shared/state';
import {
GLYPH_VAULT_TAB,
GLYPH_DEVICES, GLYPH_LOCK,
GLYPH_TYPE_LOGIN, GLYPH_TYPE_SECURE_NOTE, GLYPH_TYPE_TOTP,
GLYPH_TYPE_CARD, GLYPH_TYPE_IDENTITY, GLYPH_TYPE_KEY, GLYPH_TYPE_DOCUMENT,
} from '../../shared/glyphs';
import type { ItemId, ItemType, ManifestEntry, Item } from '../../shared/types';
/// Extract the display hostname from an icon_hint or fallback to the first tag.
@@ -12,16 +18,16 @@ function metaLine(e: ManifestEntry): string {
return '';
}
/// Emoji icon per item type. Placeholder until we ship real SVG icons.
/// Glyph icon per item type.
function typeIcon(t: ItemType): string {
switch (t) {
case 'login': return '🔑';
case 'secure_note': return '📝';
case 'identity': return '🪪';
case 'card': return '💳';
case 'key': return '🗝';
case 'document': return '📄';
case 'totp': return '⏱';
case 'login': return GLYPH_TYPE_LOGIN;
case 'secure_note': return GLYPH_TYPE_SECURE_NOTE;
case 'identity': return GLYPH_TYPE_IDENTITY;
case 'card': return GLYPH_TYPE_CARD;
case 'key': return GLYPH_TYPE_KEY;
case 'document': return GLYPH_TYPE_DOCUMENT;
case 'totp': return GLYPH_TYPE_TOTP;
}
}
@@ -31,7 +37,7 @@ function buildRowsHtml(): string {
return filtered.length > 0
? filtered.map(([id, e], i) => `
<div class="entry-row ${i === state.selectedIndex ? 'selected' : ''}" data-id="${escapeHtml(id)}" data-index="${i}">
<span class="entry-name"><span class="type-icon" aria-hidden="true">${typeIcon(e.type)}</span> ${escapeHtml(e.title)}${e.attachment_summaries.length > 0 ? ' <span class="entry-row__attach-indicator" title="has attachments">📎</span>' : ''}</span>
<span class="entry-name"><span class="type-icon" aria-hidden="true">${typeIcon(e.type)}</span> ${escapeHtml(e.title)}${e.attachment_summaries.length > 0 ? ' <span class="entry-row__attach-indicator" title="has attachments"></span>' : ''}</span>
<span class="entry-meta">${escapeHtml(metaLine(e))}</span>
</div>
`).join('')
@@ -66,7 +72,7 @@ export function renderItemList(app: HTMLElement): void {
<button class="btn" id="new-btn" style="font-size:11px;">+ new</button>
<button class="btn" id="sync-btn" style="font-size:11px;">sync</button>
<span style="flex:1;"></span>
<button class="btn" id="vault-btn" style="font-size:11px;" title="Open vault (Shift+F)">&#x2934;</button>
<button class="btn" id="vault-btn" style="font-size:11px;" title="Open vault (Shift+F)">${GLYPH_VAULT_TAB}</button>
<button class="btn" id="settings-btn" style="font-size:11px;">settings</button>
<button class="btn" id="lock-btn" style="font-size:11px;">lock</button>
</div>
@@ -253,8 +259,8 @@ function handleListKeydown(e: KeyboardEvent): void {
// ----------------------------------------------------------------------
const SETTINGS_OPTIONS: Array<{ view: 'settings' | 'settings-vault'; icon: string; label: string }> = [
{ view: 'settings', icon: '🖥', label: 'device settings' },
{ view: 'settings-vault', icon: '🔐', label: 'vault settings' },
{ view: 'settings', icon: GLYPH_DEVICES, label: 'device settings' },
{ view: 'settings-vault', icon: GLYPH_LOCK, label: 'vault settings' },
];
function showSettingsPicker(anchor: HTMLElement): void {

View File

@@ -41,3 +41,30 @@ describe('glyph constants', () => {
expect(GLYPH_NEXT).toBe('▸');
});
});
describe('Stream A glyphs (vault tab + type icons)', () => {
it('exports GLYPH_VAULT_TAB as U+29C9', () => {
expect(glyphs.GLYPH_VAULT_TAB).toBe('⧉');
});
it('exports per-type glyph constants', () => {
expect(glyphs.GLYPH_TYPE_LOGIN).toBe('◉');
expect(glyphs.GLYPH_TYPE_SECURE_NOTE).toBe('◫');
expect(glyphs.GLYPH_TYPE_TOTP).toBe('⊡');
expect(glyphs.GLYPH_TYPE_CARD).toBe('▭');
expect(glyphs.GLYPH_TYPE_IDENTITY).toBe('⌬');
expect(glyphs.GLYPH_TYPE_KEY).toBe('⊹');
expect(glyphs.GLYPH_TYPE_DOCUMENT).toBe('≡');
});
it('per-type glyphs are single codepoints (no emoji)', () => {
const typeGlyphs = [
glyphs.GLYPH_TYPE_LOGIN, glyphs.GLYPH_TYPE_SECURE_NOTE, glyphs.GLYPH_TYPE_TOTP,
glyphs.GLYPH_TYPE_CARD, glyphs.GLYPH_TYPE_IDENTITY, glyphs.GLYPH_TYPE_KEY,
glyphs.GLYPH_TYPE_DOCUMENT,
];
for (const g of typeGlyphs) {
expect([...g].length).toBe(1);
}
});
});

View File

@@ -18,6 +18,16 @@ export const GLYPH_SETTINGS = '⚙'; // sidebar settings nav
export const GLYPH_LOCK = '⏻'; // sidebar lock nav
export const GLYPH_NEXT = '▸'; // forward / next button (matches ▾/▸ disclosure family)
export const GLYPH_VAULT_TAB = '⧉'; // U+29C9 pop-out to fullscreen vault tab
export const GLYPH_TYPE_LOGIN = '◉'; // login
export const GLYPH_TYPE_SECURE_NOTE = '◫'; // secure note
export const GLYPH_TYPE_TOTP = '⊡'; // totp / 2FA
export const GLYPH_TYPE_CARD = '▭'; // card
export const GLYPH_TYPE_IDENTITY = '⌬'; // identity
export const GLYPH_TYPE_KEY = '⊹'; // SSH / API key
export const GLYPH_TYPE_DOCUMENT = '≡'; // document
/// Inline HTML snippet for the required-field pill. Use after a label's text:
/// `<label class="label" for="f-title">title ${REQUIRED_PILL_HTML}</label>`
///