stammtisch-hersbruck/frontend/src/lib/components/CreateTeamDialog.svelte
Daniel Michelberger 66e351e54f feat: Team wird zum Menuepunkt mit Submenue
Das Teamdropdown stand als eigenes Bedienelement neben dem Namen — ein
zweiter Schalter fuer eine Sache, die schon einen Menuepunkt hat. Jetzt
klappt der Menuepunkt Team beim Ueberfahren auf: die eigenen Teams, ein
Klick wechselt und oeffnet die Teamseite, darunter "Team erstellen".

Die Zeiger- und Tastenhandler von bits-ui werden am Trigger bewusst
ueberschrieben. Deren onclick ruft preventDefault und macht den Link
tot, ihr pointerdown klappt zu, was der Hover gerade aufgeklappt hat —
zwei Herren ueber dasselbe open, das Ergebnis war Flackern statt
Navigation. Das Menue verzichtet zudem auf Fokusfang und Scrollsperre;
beides gehoert zu einem Dialog, nicht zu etwas, ueber das der Zeiger nur
streift.

Der Anlegedialog liegt jetzt als CreateTeamDialog vor: Es gibt zwei
Einstiege, und ein neues Team muss an beiden dasselbe bedeuten — Team
anlegen, Standardsatz Flag-Typen dazu, ab dann ist es das aktive.

Das Logo ragt mit -my-3 leicht ueber die Kopfleiste hinaus, verlinkt
aufs Dashboard und teilt sich den Hover mit dessen Menuepunkt. Der
aktive Menuepunkt traegt das Primary-Design.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P32KoesVtABd6xWsqMKzhr
2026-09-07 22:11:28 +02:00

76 lines
2.7 KiB
Svelte

<script lang="ts">
/**
* Dialog „Neues Team". Liegt als eigene Komponente vor, weil es zwei
* Einstiege gibt — den Teamwechsler im Kopf und die Teamseite — und ein
* neues Team an beiden Stellen dasselbe bedeuten muss: Team anlegen, den
* Standardsatz Flag-Typen dazu, und ab dann ist es das aktive Team.
*
* Ein Team ohne Flag-Typen kann zwar Marker aufnehmen, aber nichts
* einordnen. Deshalb kommt der Standardsatz gleich mit — änderbar und,
* wie alle Flag-Typen, allein Sache dieses Teams.
*/
import { getTeamContext } from '$lib/stores/teams.svelte'
import { getTrailFlagContext } from '$lib/stores/trailFlags.svelte'
import { Button } from '@/components/ui/button'
import * as Dialog from '@/components/ui/dialog'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
let { open = $bindable(false) }: { open?: boolean } = $props()
const teams = getTeamContext()
const flags = getTrailFlagContext()
let name = $state('')
let error = $state<string | null>(null)
let busy = $state(false)
async function submit() {
if (!name.trim() || busy) return
busy = true
error = null
try {
const created = await teams.create(name.trim())
try {
await flags.seedDefaults(created.id)
} catch (e: any) {
error =
'Das Team wurde angelegt, die Standard-Flag-Typen aber nicht: ' +
(e.message ?? 'unbekannter Fehler') +
' Du kannst sie unter „Flag-Typen" nachholen.'
return
}
open = false
name = ''
} catch (e: any) {
error = e.message ?? 'Das Team konnte nicht angelegt werden.'
} finally {
busy = false
}
}
</script>
<Dialog.Root bind:open>
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>Neues Team</Dialog.Title>
<Dialog.Description>Du wirst automatisch Owner.</Dialog.Description>
</Dialog.Header>
<div class="space-y-4">
<div class="space-y-2">
<Label for="team-name">Name</Label>
<Input id="team-name" bind:value={name} placeholder="Mein Team" onkeydown={(e) => e.key === 'Enter' && submit()} />
</div>
{#if error}
<p class="text-sm text-destructive">{error}</p>
{/if}
</div>
<Dialog.Footer>
<Button variant="ghost" onclick={() => (open = false)}>Abbrechen</Button>
<Button onclick={submit} disabled={!name.trim() || busy}>Erstellen</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>