fix: rename node not found, A11y warnings cleanup
- fix renameId cleared before RenameNode API call (submitRename) - add role, tabindex, keydown handlers to all interactive divs - associate labels with inputs (wrap in label + .label-text) - remove autofocus, unused CSS selectors, old root build.sh - update frontend-dist assets
This commit is contained in:
parent
23b3d07071
commit
7d81250ebd
26
build.sh
26
build.sh
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Load NVM for Node.js
|
||||
export NVM_DIR="${NVM_DIR:-$HOME/.config/nvm}"
|
||||
if [ -s "$NVM_DIR/nvm.sh" ]; then
|
||||
. "$NVM_DIR/nvm.sh"
|
||||
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
||||
. "$HOME/.nvm/nvm.sh"
|
||||
fi
|
||||
|
||||
BUILD_DIR="build"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
echo "==> Building frontend..."
|
||||
cd frontend && npm run build && cd ..
|
||||
cp -r frontend/dist/* cmd/verstak-gui/frontend-dist/
|
||||
|
||||
echo "==> Building GUI binary..."
|
||||
go build -tags "webkit2_41 desktop production" -ldflags="-s -w" -o "$BUILD_DIR/verstak-gui-linux-amd64" ./cmd/verstak-gui/
|
||||
|
||||
echo "==> Building server binary..."
|
||||
go build -ldflags="-s -w" -o "$BUILD_DIR/verstak-server-linux-amd64" ./cmd/verstak-server/
|
||||
|
||||
echo "==> Done. Binaries in $BUILD_DIR/:"
|
||||
ls -lh "$BUILD_DIR/"
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -16,8 +16,8 @@
|
|||
background: #13131f;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/main-BH7waEiY.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BzI_Zj56.css">
|
||||
<script type="module" crossorigin src="/assets/main-CWWXp5bW.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BBKDbfa7.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
let clipboard = { items: [], mode: 'copy' }
|
||||
let selectedIds = []
|
||||
let dragIds = []
|
||||
let dropRootValid = false
|
||||
|
||||
let showConfirm = false
|
||||
let confirmTitle = ''
|
||||
|
|
@ -565,11 +566,17 @@
|
|||
return
|
||||
}
|
||||
showRename = false
|
||||
const id = renameId
|
||||
renameId = ''
|
||||
try {
|
||||
await wailsCall('RenameNode', renameId, name)
|
||||
const parentId = currentFolderId || selectedNode.id
|
||||
await loadFolder(parentId)
|
||||
await wailsCall('RenameNode', id, name)
|
||||
if (selectedNode && selectedNode.id === id) {
|
||||
selectedNode = { ...selectedNode, title: name }
|
||||
}
|
||||
await reloadTreePreservingExpanded()
|
||||
if (currentFolderId) {
|
||||
await loadFolder(currentFolderId)
|
||||
}
|
||||
} catch (e) {
|
||||
error = String(e)
|
||||
}
|
||||
|
|
@ -729,11 +736,11 @@
|
|||
function handleDragOverRoot(e) {
|
||||
e.preventDefault()
|
||||
e.dataTransfer.dropEffect = 'move'
|
||||
e.currentTarget.classList.add('drop-valid')
|
||||
dropRootValid = true
|
||||
}
|
||||
|
||||
function handleDragLeaveRoot(e) {
|
||||
e.currentTarget.classList.remove('drop-valid')
|
||||
dropRootValid = false
|
||||
}
|
||||
|
||||
// ===== Node operations from context menu =====
|
||||
|
|
@ -1172,6 +1179,15 @@
|
|||
}
|
||||
syncLoading = false
|
||||
}
|
||||
|
||||
function onKeyActivate(fn) {
|
||||
return (e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
|
|
@ -1198,6 +1214,8 @@
|
|||
</div>
|
||||
{#if workspaceTree.length > 0}
|
||||
<div class="workspace-tree-area"
|
||||
class:drop-valid={dropRootValid}
|
||||
role="region" aria-label={t('nav.workspace')}
|
||||
on:dragover|preventDefault={handleDragOverRoot}
|
||||
on:dragleave={handleDragLeaveRoot}
|
||||
on:drop={handleDropRoot}>
|
||||
|
|
@ -1252,7 +1270,7 @@
|
|||
</header>
|
||||
|
||||
{#if error}
|
||||
<div class="error-banner" on:click={() => error = ''}>
|
||||
<div class="error-banner" role="button" tabindex="0" on:click={() => error = ''} on:keydown={onKeyActivate(() => error = '')}>
|
||||
{error}
|
||||
<button class="dismiss-btn" on:click|stopPropagation={() => error = ''} aria-label="Dismiss">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
|
|
@ -1315,7 +1333,7 @@
|
|||
<div class="recent-section">
|
||||
<h3>{t('overview.recentNotes')}</h3>
|
||||
{#each notes.slice(0, 5) as note}
|
||||
<div class="recent-note" on:click={() => openNote(note)}>
|
||||
<div class="recent-note" role="button" tabindex="0" on:click={() => openNote(note)} on:keydown={onKeyActivate(() => openNote(note))}>
|
||||
<span>{note.title}</span><span class="recent-date">{formatDate(note.createdAt)}</span>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
@ -1351,7 +1369,7 @@
|
|||
{:else}
|
||||
<div class="notes-list">
|
||||
{#each notes as note}
|
||||
<div class="note-card" on:click={() => openNote(note)}>
|
||||
<div class="note-card" role="button" tabindex="0" on:click={() => openNote(note)} on:keydown={onKeyActivate(() => openNote(note))}>
|
||||
<div class="note-card-title">{note.title}</div>
|
||||
<div class="note-card-date">{formatDate(note.createdAt)}</div>
|
||||
</div>
|
||||
|
|
@ -1620,15 +1638,15 @@
|
|||
{/if}
|
||||
|
||||
{#if showCreateNode}
|
||||
<div class="modal-overlay" on:click|self={cancelCreateNode}>
|
||||
<div class="modal-overlay" role="button" tabindex="0" on:click|self={cancelCreateNode} on:keydown={onKeyActivate(cancelCreateNode)}>
|
||||
<div class="modal modal-create">
|
||||
<h3>{t('nav.createNode')}</h3>
|
||||
{#if createInNode}
|
||||
<div class="create-context">{t('nav.createInside')} «{createInNode.title}»</div>
|
||||
{/if}
|
||||
<div class="form-group">
|
||||
<label>{t('template.select')}</label>
|
||||
<div class="template-cards">
|
||||
<span class="form-label">{t('template.select')}</span>
|
||||
<div class="template-cards" role="group" aria-label={t('template.select')}>
|
||||
<button class="template-card" class:selected={createWithTemplate === null}
|
||||
on:click={() => createWithTemplate = null}>
|
||||
<TemplateIcon kind="folder" size={24} />
|
||||
|
|
@ -1650,9 +1668,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{t('common.name')}</label>
|
||||
<label><span class="label-text">{t('common.name')}</span>
|
||||
<input type="text" placeholder={t('case.namePlaceholder')} bind:value={newNodeTitle}
|
||||
on:keydown={(e) => e.key === 'Enter' && submitCreateNode()} autofocus />
|
||||
on:keydown={(e) => e.key === 'Enter' && submitCreateNode()} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-primary" on:click={submitCreateNode}
|
||||
|
|
@ -1664,7 +1683,7 @@
|
|||
{/if}
|
||||
|
||||
{#if contextMenu.visible}
|
||||
<div class="context-menu-backdrop" on:click={closeContextMenu} on:contextmenu|preventDefault={closeContextMenu}>
|
||||
<div class="context-menu-backdrop" role="button" tabindex="0" on:click={closeContextMenu} on:contextmenu|preventDefault={closeContextMenu} on:keydown={onKeyActivate(closeContextMenu)}>
|
||||
<div class="context-menu" style="left: {contextMenu.x}px; top: {contextMenu.y}px">
|
||||
{#if contextMenu.node && ['folder','project','client','document','recipe'].includes(contextMenu.node.type)}
|
||||
<div class="context-menu-section">{t('common.create')}</div>
|
||||
|
|
@ -1696,27 +1715,30 @@
|
|||
{/if}
|
||||
|
||||
{#if showCreateAction}
|
||||
<div class="modal-overlay" on:click|self={cancelCreateAction}>
|
||||
<div class="modal-overlay" role="button" tabindex="0" on:click|self={cancelCreateAction} on:keydown={onKeyActivate(cancelCreateAction)}>
|
||||
<div class="modal">
|
||||
<h3>{t('action.newAction')}</h3>
|
||||
<div class="form-group">
|
||||
<label>{t('common.name')}</label>
|
||||
<label><span class="label-text">{t('common.name')}</span>
|
||||
<input type="text" placeholder={t('action.namePlaceholder')} bind:value={newActionTitle}
|
||||
on:keydown={(e) => e.key === 'Enter' && submitCreateAction()} autofocus />
|
||||
on:keydown={(e) => e.key === 'Enter' && submitCreateAction()} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{t('common.type')}</label>
|
||||
<label><span class="label-text">{t('common.type')}</span>
|
||||
<select bind:value={newActionKind}>
|
||||
{#each actionKinds as k}
|
||||
<option value={k.id}>{k.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{newActionKind === 'open_url' ? t('action.dataUrl') : newActionKind === 'open_folder' || newActionKind === 'open_file' ? t('action.dataPath') : t('action.dataCommand')}</label>
|
||||
<label><span class="label-text">{newActionKind === 'open_url' ? t('action.dataUrl') : newActionKind === 'open_folder' || newActionKind === 'open_file' ? t('action.dataPath') : t('action.dataCommand')}</span>
|
||||
<input type="text" placeholder={newActionKind === 'open_url' ? t('action.urlPlaceholder') : newActionKind === 'open_folder' || newActionKind === 'open_file' ? t('action.pathPlaceholder') : t('action.commandPlaceholder')}
|
||||
bind:value={newActionData}
|
||||
on:keydown={(e) => e.key === 'Enter' && submitCreateAction()} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-primary" on:click={submitCreateAction}>{t('common.create')}</button>
|
||||
|
|
@ -1727,7 +1749,7 @@
|
|||
{/if}
|
||||
|
||||
{#if showImportDialog && importSummary}
|
||||
<div class="modal-overlay" on:click|self={cancelImport}>
|
||||
<div class="modal-overlay" role="button" tabindex="0" on:click|self={cancelImport} on:keydown={onKeyActivate(cancelImport)}>
|
||||
<div class="modal">
|
||||
<h3>{t('file.importTitle')} «{selectedNode ? selectedNode.title : ''}»</h3>
|
||||
<div class="import-summary">
|
||||
|
|
@ -1751,13 +1773,14 @@
|
|||
{/if}
|
||||
|
||||
{#if showRename}
|
||||
<div class="modal-overlay" on:click|self={cancelRename}>
|
||||
<div class="modal-overlay" role="button" tabindex="0" on:click|self={cancelRename} on:keydown={onKeyActivate(cancelRename)}>
|
||||
<div class="modal">
|
||||
<h3>{t('rename.title')}</h3>
|
||||
<div class="form-group">
|
||||
<label>{t('common.newName')}</label>
|
||||
<label><span class="label-text">{t('common.newName')}</span>
|
||||
<input type="text" bind:value={renameValue}
|
||||
on:keydown={onRenameKeydown} />
|
||||
</label>
|
||||
</div>
|
||||
{#if renameError}
|
||||
<div class="rename-error">{renameError}</div>
|
||||
|
|
@ -1782,7 +1805,7 @@
|
|||
{/if}
|
||||
|
||||
{#if showSettings}
|
||||
<div class="modal-overlay" on:click|self={closeSettings}>
|
||||
<div class="modal-overlay" role="button" tabindex="0" on:click|self={closeSettings} on:keydown={onKeyActivate(closeSettings)}>
|
||||
<div class="modal modal-sync">
|
||||
<h3>{t('sync.settings')}</h3>
|
||||
{#if syncStatus}
|
||||
|
|
@ -1824,16 +1847,19 @@
|
|||
</div>
|
||||
{:else}
|
||||
<div class="form-group">
|
||||
<label>{t('sync.serverUrl')}</label>
|
||||
<label><span class="label-text">{t('sync.serverUrl')}</span>
|
||||
<input type="text" placeholder={t('sync.serverUrlPlaceholder')} bind:value={syncServerUrl} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{t('sync.username')}</label>
|
||||
<label><span class="label-text">{t('sync.username')}</span>
|
||||
<input type="text" placeholder={t('sync.usernamePlaceholder')} bind:value={syncUsername} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{t('sync.password')}</label>
|
||||
<label><span class="label-text">{t('sync.password')}</span>
|
||||
<input type="password" placeholder={t('sync.passwordPlaceholder')} bind:value={syncPassword} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions" style="margin-top:12px">
|
||||
<button class="btn" on:click={testConnection} disabled={syncLoading || !syncServerUrl}>{t('sync.test')}</button>
|
||||
|
|
@ -1843,8 +1869,9 @@
|
|||
|
||||
<div style="margin-top:16px;padding-top:16px;border-top:1px solid #2a2a3c">
|
||||
<div class="form-group">
|
||||
<label>{t('sync.autoSync')}</label>
|
||||
<label><span class="label-text">{t('sync.autoSync')}</span>
|
||||
<input type="number" placeholder="0" bind:value={syncInterval} min="0" />
|
||||
</label>
|
||||
</div>
|
||||
<button class="btn" on:click={saveSyncInterval} disabled={syncLoading}>{t('sync.saveInterval')}</button>
|
||||
</div>
|
||||
|
|
@ -1884,16 +1911,6 @@
|
|||
.nav-add-btn { background: none; border: none; color: #666; cursor: pointer; font-size: 16px; padding: 0 4px; font-family: inherit; line-height: 1; }
|
||||
.nav-add-btn:hover { color: #ccc; }
|
||||
|
||||
/* Tree items in sidebar */
|
||||
.tree-item { display: flex; align-items: center; padding: 4px 8px 4px 0; cursor: default; font-size: 13px; color: #ccc; }
|
||||
.tree-item:hover { background: #222233; }
|
||||
.tree-item.selected { background: #2a2a4a; color: #fff; font-weight: 500; }
|
||||
.tree-toggle { background: none; border: none; color: #666; cursor: pointer; padding: 2px 4px; font-size: 10px; width: 20px; text-align: center; flex-shrink: 0; font-family: inherit; line-height: 1; }
|
||||
.tree-toggle:hover { color: #888; }
|
||||
.tree-arrow { display: inline-block; }
|
||||
.tree-spacer { display: inline-block; width: 12px; }
|
||||
.tree-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 2px 4px; cursor: pointer; }
|
||||
|
||||
/* Context menu */
|
||||
.context-menu-backdrop { position: fixed; inset: 0; z-index: 200; }
|
||||
.context-menu { position: fixed; background: #1a1a28; border: 1px solid #2a2a3c; border-radius: 8px; padding: 4px; min-width: 180px; box-shadow: 0 8px 24px rgba(0,0,0,0.4); }
|
||||
|
|
@ -1999,7 +2016,6 @@
|
|||
.empty-state .empty-icon { margin-bottom: 12px; color: #444; }
|
||||
.empty-state .hint { font-size: 12px; color: #555; margin-top: 6px; }
|
||||
.empty-state .empty-actions { display: flex; gap: 8px; justify-content: center; margin-top: 16px; }
|
||||
.empty-note { font-size: 12px; color: #444; margin-top: 16px; }
|
||||
|
||||
/* Welcome */
|
||||
.welcome { padding: 48px 24px; text-align: center; }
|
||||
|
|
@ -2007,16 +2023,13 @@
|
|||
.welcome p { color: #666; font-size: 14px; }
|
||||
.error-text { color: #ff8888; }
|
||||
|
||||
/* FAB */
|
||||
.fab { position: fixed; bottom: 24px; right: 24px; width: 56px; height: 56px; border-radius: 50%; background: #6366f1; color: #fff; font-size: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4); }
|
||||
.fab:hover { background: #4f46e5; }
|
||||
|
||||
/* Modal */
|
||||
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); display: flex; align-items: center; justify-content: center; z-index: 100; }
|
||||
.modal { background: #1a1a28; border: 1px solid #2a2a3c; border-radius: 12px; padding: 24px; width: 400px; max-width: 90vw; }
|
||||
.modal h3 { font-size: 18px; margin-bottom: 16px; }
|
||||
.form-group { margin-bottom: 12px; }
|
||||
.form-group label { display: block; font-size: 12px; color: #666; margin-bottom: 4px; }
|
||||
.form-group label { display: block; }
|
||||
.form-group .label-text, .form-group .form-label { display: block; font-size: 12px; color: #666; margin-bottom: 4px; }
|
||||
.form-group input, .form-group select { width: 100%; padding: 8px 12px; border: 1px solid #2a2a3c; background: #13131f; color: #e4e4ef; border-radius: 4px; font-size: 14px; font-family: inherit; }
|
||||
.form-group select { appearance: none; -webkit-appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888' d='M2 4l4 4 4-4'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; padding-right: 32px; }
|
||||
.form-group input:focus, .form-group select:focus { outline: none; border-color: #6366f1; }
|
||||
|
|
|
|||
|
|
@ -114,6 +114,13 @@
|
|||
menuY = Math.min(e.clientY, window.innerHeight - 320)
|
||||
menuOpen = true
|
||||
}
|
||||
|
||||
function handleRowKeydown(e) {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
handleClick(e)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:click={closeMenu}/>
|
||||
|
|
@ -124,6 +131,7 @@
|
|||
tabindex="0"
|
||||
draggable="true"
|
||||
on:click={handleClick}
|
||||
on:keydown={handleRowKeydown}
|
||||
on:contextmenu={oncontextmenu}
|
||||
on:dragstart={handleDragStart}
|
||||
on:dragover={handleDragOver}
|
||||
|
|
@ -194,7 +202,7 @@
|
|||
{#if menuOpen}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="menu-backdrop" on:click|stopPropagation={closeMenu} role="presentation"></div>
|
||||
<div class="menu" style="left: {menuX}px; top: {menuY}px; position: fixed;" on:click|stopPropagation role="menu">
|
||||
<div class="menu" style="left: {menuX}px; top: {menuY}px; position: fixed;" on:click|stopPropagation on:keydown={(e) => { if (e.key === 'Escape') { e.stopPropagation(); closeMenu() } }} role="menu" tabindex="-1">
|
||||
<button class="menu-item" on:click={handleOpen} role="menuitem">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
{t('common.open')}
|
||||
|
|
|
|||
|
|
@ -201,11 +201,33 @@
|
|||
if (shouldShowToggle(node) && onToggle) onToggle(node.id)
|
||||
}
|
||||
|
||||
function handleRowKeydown(e, node) {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
if (onSelect) onSelect(node)
|
||||
}
|
||||
}
|
||||
|
||||
function handleIconClick(e, node) {
|
||||
e.stopPropagation()
|
||||
if (shouldShowToggle(node) && onToggle) onToggle(node.id)
|
||||
}
|
||||
|
||||
function handleIconKeydown(e, node) {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (shouldShowToggle(node) && onToggle) onToggle(node.id)
|
||||
}
|
||||
}
|
||||
|
||||
function handleLabelKeydown(e, node) {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
if (onSelect) onSelect(node)
|
||||
}
|
||||
}
|
||||
|
||||
function computeDropInfo(allNodes, draggedId, pMap) {
|
||||
const info = {}
|
||||
function walk(list) {
|
||||
|
|
@ -232,11 +254,14 @@
|
|||
class:drop-invalid={dragOverNodeId === node.id && !dropAllowed[node.id]}
|
||||
style="padding-left: {level * 16 + 4}px"
|
||||
draggable="true"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
on:dragstart={(e) => handleDragStart(e, node)}
|
||||
on:dragover={(e) => handleDragOver(e, node)}
|
||||
on:dragleave={(e) => handleDragLeave(e, node)}
|
||||
on:drop={(e) => handleDrop(e, node)}
|
||||
on:click={(e) => handleRowClick(e, node)}
|
||||
on:keydown={(e) => handleRowKeydown(e, node)}
|
||||
on:dblclick={(e) => handleRowDblClick(e, node)}
|
||||
on:contextmenu|preventDefault={(e) => onContextMenu && onContextMenu(e, node)}>
|
||||
{#if shouldShowToggle(node)}
|
||||
|
|
@ -246,10 +271,15 @@
|
|||
{:else}
|
||||
<span class="tree-toggle-placeholder"></span>
|
||||
{/if}
|
||||
<span class="tree-icon" on:click={(e) => handleIconClick(e, node)} on:dblclick|stopPropagation>
|
||||
<span class="tree-icon" role="button" tabindex="-1"
|
||||
on:click={(e) => handleIconClick(e, node)}
|
||||
on:keydown={(e) => handleIconKeydown(e, node)}
|
||||
on:dblclick|stopPropagation>
|
||||
<TemplateIcon kind={iconKind(node)} size={16} />
|
||||
</span>
|
||||
<span class="tree-label" on:click|stopPropagation={() => onSelect && onSelect(node)}>
|
||||
<span class="tree-label" role="button" tabindex="-1"
|
||||
on:click|stopPropagation={() => onSelect && onSelect(node)}
|
||||
on:keydown={(e) => handleLabelKeydown(e, node)}>
|
||||
{node.title}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="overlay" on:click|self={() => dispatch('cancel')} role="dialog" aria-modal="true" aria-label={title}>
|
||||
<div class="overlay" on:click|self={() => dispatch('cancel')} on:keydown={(e) => { if (e.key === 'Escape') { e.preventDefault(); dispatch('cancel') } }} role="presentation">
|
||||
<div class="modal">
|
||||
<h3>{title}</h3>
|
||||
<p class="message">{message}</p>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
})
|
||||
</script>
|
||||
|
||||
<div class="overlay" on:click|self={() => dispatch('close')} role="dialog" aria-modal="true" aria-label={`Preview: ${item.name}`}>
|
||||
<div class="overlay" on:click|self={() => dispatch('close')} on:keydown={(e) => { if (e.key === 'Escape') { e.preventDefault(); dispatch('close') } }} role="presentation">
|
||||
<div class="modal">
|
||||
<header class="preview-header">
|
||||
<div class="preview-title">
|
||||
|
|
|
|||
Loading…
Reference in New Issue