- Vite + Vue 3.5 + Pinia + vue-router + Tailwind (brand accent #F5C518), dark-mode aware, deterministic package-lock.json for `npm ci`. - Session store (fetchMe/login/register/logout) over a credentials:'include' fetch client; router guards (requiresAuth / guestOnly) with lazy /me resolve. - BaseButton + BaseInput primitives (focus rings, loading, error states). - LoginView, RegisterView, and an authed BoardView shell with an empty state for the M1 masonry board — all at v1 polish (rule 24). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
35 lines
1.1 KiB
Vue
35 lines
1.1 KiB
Vue
<script setup lang="ts">
|
|
withDefaults(
|
|
defineProps<{
|
|
type?: "button" | "submit";
|
|
variant?: "primary" | "ghost";
|
|
loading?: boolean;
|
|
disabled?: boolean;
|
|
}>(),
|
|
{ type: "button", variant: "primary", loading: false, disabled: false },
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<button
|
|
:type="type"
|
|
:disabled="disabled || loading"
|
|
class="inline-flex items-center justify-center gap-2 rounded-lg px-4 py-2.5 text-sm font-semibold transition
|
|
focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2
|
|
focus-visible:ring-offset-neutral-50 dark:focus-visible:ring-offset-neutral-950
|
|
disabled:cursor-not-allowed disabled:opacity-60"
|
|
:class="
|
|
variant === 'primary'
|
|
? 'bg-brand text-neutral-900 shadow-sm hover:bg-brand-600 active:bg-brand-700'
|
|
: 'text-neutral-700 hover:bg-neutral-200/70 dark:text-neutral-200 dark:hover:bg-neutral-800'
|
|
"
|
|
>
|
|
<span
|
|
v-if="loading"
|
|
class="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"
|
|
aria-hidden="true"
|
|
/>
|
|
<slot />
|
|
</button>
|
|
</template>
|