Files
summercms/admin/src/components/ui/Button.vue
Jakub Zych 49accf675e feat(quick-261022-k9k): admin save shortcuts and Create and new on record forms
- 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)
2026-10-22 21:00:57 +02:00

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>