- app/hotkeys.ts: dependency-free data-hotkey core (Ctrl/Cmd+S, Ctrl/Cmd+Enter, Ctrl/Cmd+Shift+S, Esc, / and ?), innermost-modal root, capture-phase modifier listener, platform labels and the help-dialog state - Button hotkey prop (data-hotkey, aria-keyshortcuts); shortcuts installed by AppShell - FormView: save keys and tooltips, Create and new on create forms via remountView - phrasebook: form.create_and_new and the shortcuts group (en, pl)
62 lines
2.1 KiB
Vue
62 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import { computed, type Component } from 'vue'
|
|
import { RouterLink, type RouteLocationRaw } from 'vue-router'
|
|
import { ariaKeyshortcuts } from '../../app/hotkeys'
|
|
|
|
// One button for the whole admin (design tokens): primary, outline, ghost and
|
|
// danger (outline). With `to` it renders a router link styled the same way.
|
|
// A hotkey prop marks the button for the admin's keyboard shortcuts
|
|
// (data-hotkey tokens, see app/hotkeys.ts).
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
variant?: 'primary' | 'outline' | 'ghost' | 'danger'
|
|
size?: 'md' | 'sm'
|
|
type?: 'button' | 'submit'
|
|
disabled?: boolean
|
|
icon?: Component
|
|
to?: RouteLocationRaw
|
|
hotkey?: string
|
|
}>(),
|
|
{ variant: 'outline', size: 'md', type: 'button', disabled: false, icon: undefined, to: undefined, hotkey: undefined },
|
|
)
|
|
|
|
const variants: Record<NonNullable<typeof props.variant>, string> = {
|
|
primary: 'bg-primary text-on-primary hover:opacity-90',
|
|
outline: 'border border-border-strong bg-surface text-text hover:bg-hover',
|
|
ghost: 'text-muted hover:bg-hover hover:text-text',
|
|
danger: 'border border-danger bg-surface text-danger hover:bg-danger-soft',
|
|
}
|
|
|
|
const keyshortcuts = computed(() => (props.hotkey ? ariaKeyshortcuts(props.hotkey) : undefined))
|
|
|
|
const classes = computed(() => [
|
|
'inline-flex shrink-0 items-center justify-center gap-2 rounded-control px-4 font-semibold whitespace-nowrap no-underline transition-colors duration-150 ease-out disabled:cursor-not-allowed disabled:opacity-60',
|
|
props.size === 'sm' ? 'h-[38px]' : 'h-button',
|
|
variants[props.variant],
|
|
])
|
|
</script>
|
|
|
|
<template>
|
|
<RouterLink
|
|
v-if="to !== undefined"
|
|
:to="to"
|
|
:class="classes"
|
|
:data-hotkey="hotkey"
|
|
:aria-keyshortcuts="keyshortcuts"
|
|
>
|
|
<component :is="icon" v-if="icon" :size="16" aria-hidden="true" />
|
|
<slot />
|
|
</RouterLink>
|
|
<button
|
|
v-else
|
|
:type="type"
|
|
:disabled="disabled"
|
|
:class="classes"
|
|
:data-hotkey="hotkey"
|
|
:aria-keyshortcuts="keyshortcuts"
|
|
>
|
|
<component :is="icon" v-if="icon" :size="16" aria-hidden="true" />
|
|
<slot />
|
|
</button>
|
|
</template>
|