web: focus modal, slice 8 of M3
Clicking a panel's network (cursor zoom-in, a real button for keyboard users) or its menu's Focus item opens the modal: the same SVG at the same global round rendered up to 90vw/85vh over the spec scrim, with a second PlayerBar docked in the footer sharing the store. Only the page PlayerBar owns the global keyboard map, so keys are never handled twice. role=dialog with aria-modal, labelled by the panel name, focus moves in and is trapped, Esc/X/scrim close, and focus returns to the opener. focusPanelId already lives in the URL, so shared links open pre-focused; on mobile the modal becomes a full-screen sheet.
This commit is contained in:
parent
eb1f7427c4
commit
8929eeddb0
4 changed files with 260 additions and 3 deletions
|
|
@ -22,6 +22,7 @@ const failed = computed(() => store.state.failedPanelIds.has(props.panel.id))
|
|||
const menuItems = computed<PanelMenuItem[]>(() => [
|
||||
{ key: 'edit', label: 'Edit' },
|
||||
{ key: 'rename', label: 'Rename' },
|
||||
{ key: 'focus', label: 'Focus' },
|
||||
{ key: 'duplicate', label: 'Duplicate', disabled: store.state.panels.length >= MAX_PANELS },
|
||||
{ key: 'remove', label: 'Remove', disabled: store.state.panels.length <= 1 },
|
||||
])
|
||||
|
|
@ -34,6 +35,9 @@ function onMenuSelect(itemKey: string) {
|
|||
focusLabelOnOpen.value = itemKey === 'rename'
|
||||
store.state.editingPanelId = props.panel.id
|
||||
break
|
||||
case 'focus':
|
||||
store.setFocusPanel(props.panel.id)
|
||||
break
|
||||
case 'duplicate':
|
||||
store.duplicatePanel(props.panel.id)
|
||||
kebabButton.value?.focus()
|
||||
|
|
@ -136,7 +140,14 @@ const dimmed = computed(() => store.state.runState === 'running' && result.value
|
|||
<div class="chips">
|
||||
<span v-for="chip in chips" :key="chip.key" class="chip">{{ chip.text }}</span>
|
||||
</div>
|
||||
<NetworkView :panel="panel" />
|
||||
<button
|
||||
class="netbtn"
|
||||
type="button"
|
||||
:aria-label="`Enlarge ${panel.label}`"
|
||||
@click="store.setFocusPanel(panel.id)"
|
||||
>
|
||||
<NetworkView :panel="panel" />
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="skeleton" aria-hidden="true">
|
||||
|
|
@ -273,6 +284,16 @@ const dimmed = computed(() => store.state.runState === 'running' && result.value
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.netbtn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
cursor: zoom-in;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.chip {
|
||||
font-size: 11.5px;
|
||||
font-weight: 550;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue