clusev/resources/views/components/command-palette.blade.php

90 lines
4.8 KiB
PHP

{{--
Command palette + keyboard shortcuts. Mounted ONCE in the persistent layout so it
survives wire:navigate and its global keydown listener is registered only once.
Strg/-K opens it; "g" + a key navigates; "/" focuses the page search; "?" shows help.
--}}
@php
$chords = [
['Strg / ⌘ K', 'Befehle öffnen'],
['/', 'Suche auf der Seite fokussieren'],
['?', 'Diese Hilfe anzeigen'],
['g d', 'Dashboard'],
['g s', 'Server'],
['g i', 'Dienste'],
['g f', 'Dateien'],
['g l', 'Audit-Log'],
['g e', 'Einstellungen'],
['g y', 'System'],
['g v', 'Version'],
];
$kbd = 'rounded border border-line bg-inset px-1.5 py-0.5 font-mono text-[10px] text-ink-2';
@endphp
<div x-data="cmdk"
@keydown.window="onKey($event)"
@keydown.escape.window="close()"
@cmdk-open.window="toggle(true)">
{{-- Command palette --}}
<div x-show="open" x-cloak class="fixed inset-0 z-50 flex items-start justify-center px-4 pt-[12vh]" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-void/70 backdrop-blur-sm" @click="close()" aria-hidden="true"></div>
<div x-show="open" x-transition
class="relative w-full max-w-xl overflow-hidden rounded-lg border border-line bg-surface shadow-pop">
<div class="flex items-center gap-2.5 border-b border-line px-4">
<x-icon name="search" class="h-4 w-4 shrink-0 text-ink-3" />
<input x-ref="input" x-model="query" type="text" autocomplete="off" spellcheck="false"
placeholder="Befehl oder Seite…"
@input="active = 0"
@keydown.down.prevent="move(1)"
@keydown.up.prevent="move(-1)"
@keydown.enter.prevent="run()"
class="h-12 w-full bg-transparent font-mono text-sm text-ink placeholder:text-ink-4 focus:outline-none" />
<span class="shrink-0 font-mono text-[10px] uppercase tracking-wider text-ink-4">Esc</span>
</div>
<ul class="max-h-80 overflow-y-auto py-1.5">
<template x-for="(item, idx) in items" :key="item.label">
<li>
<button type="button"
@click="run(item)"
@mouseenter="active = idx"
:class="active === idx ? 'bg-accent/10 text-accent-text' : 'text-ink-2'"
class="flex w-full items-center justify-between gap-3 px-4 py-2 text-left">
<span class="truncate font-mono text-sm" x-text="item.label"></span>
<span class="shrink-0 font-mono text-[10px] uppercase tracking-wider text-ink-4" x-text="item.hint"></span>
</button>
</li>
</template>
<li x-show="items.length === 0" class="px-4 py-3 font-mono text-[11px] text-ink-4">Kein Treffer.</li>
</ul>
<div class="flex items-center justify-between border-t border-line px-4 py-2 font-mono text-[10px] text-ink-4">
<span class="flex items-center gap-1.5"><x-icon name="corner-down-left" class="h-3 w-3" /> öffnen</span>
<button type="button" @click="open = false; help = true" class="hover:text-ink-2">? Tastenkürzel</button>
</div>
</div>
</div>
{{-- Shortcut help --}}
<div x-show="help" x-cloak class="fixed inset-0 z-50 flex items-start justify-center px-4 pt-[12vh]" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-void/70 backdrop-blur-sm" @click="help = false" aria-hidden="true"></div>
<div x-show="help" x-transition class="relative w-full max-w-md overflow-hidden rounded-lg border border-line bg-surface shadow-pop">
<div class="flex items-center gap-2.5 border-b border-line px-4 py-3">
<x-icon name="command" class="h-4 w-4 shrink-0 text-accent-text" />
<h2 class="font-display text-sm font-semibold text-ink">Tastenkürzel</h2>
<button type="button" @click="help = false" class="ml-auto text-ink-4 hover:text-ink" aria-label="Schließen">
<x-icon name="x" class="h-4 w-4" />
</button>
</div>
<dl class="divide-y divide-line">
@foreach ($chords as [$chord, $desc])
<div class="flex items-center justify-between gap-3 px-4 py-2">
<dt class="text-sm text-ink-2">{{ $desc }}</dt>
<dd class="shrink-0"><span class="{{ $kbd }}">{{ $chord }}</span></dd>
</div>
@endforeach
</dl>
</div>
</div>
</div>