feat: reskin admin pages to zine design system

Migrate the entire admin section from the dark guild-* Tailwind theme
to the zine design system (dashed borders, CSS custom properties,
Brygada 1918 + Commit Mono, cream/dark mode palette).

- Replace admin top-nav layout with sidebar matching default layout
- Reskin dashboard, members, events, series management pages
- Reskin events/create and series/create form pages
- Add dev-only test login endpoint (GET /api/dev/test-login)
- Redirect duplicate admin/dashboard.vue to /admin
- Update CLAUDE.md design system docs
This commit is contained in:
Jennie Robinson Faber 2026-04-03 10:56:01 +01:00
parent f16f9ada64
commit fcd6f4cdf4
23 changed files with 3845 additions and 3827 deletions

View file

@ -1,62 +1,64 @@
<template>
<div v-if="shouldShowBanner" class="w-full">
<div
:class="[
'backdrop-blur-sm border rounded-lg p-4 flex items-start gap-4',
statusConfig.bgColor,
statusConfig.borderColor,
]"
>
<Icon
:name="statusConfig.icon"
:class="['w-5 h-5 flex-shrink-0 mt-0.5', statusConfig.textColor]"
/>
<ClientOnly>
<div v-if="shouldShowBanner" class="w-full">
<div
:class="[
'backdrop-blur-sm border rounded-lg p-4 flex items-start gap-4',
statusConfig.bgColor,
statusConfig.borderColor,
]"
>
<Icon
:name="statusConfig.icon"
:class="['w-5 h-5 flex-shrink-0 mt-0.5', statusConfig.textColor]"
/>
<div class="flex-1 min-w-0">
<h3 :class="['font-semibold mb-1', statusConfig.textColor]">
{{ statusConfig.label }}
</h3>
<p :class="['text-sm', statusConfig.textColor, 'opacity-90']">
{{ bannerMessage }}
</p>
</div>
<div class="flex-1 min-w-0">
<h3 :class="['font-semibold mb-1', statusConfig.textColor]">
{{ statusConfig.label }}
</h3>
<p :class="['text-sm', statusConfig.textColor, 'opacity-90']">
{{ bannerMessage }}
</p>
</div>
<div class="flex items-center gap-2 flex-shrink-0">
<!-- Payment button for pending payment status -->
<UButton
v-if="isPendingPayment && nextAction"
:color="getButtonColor(nextAction.color)"
size="sm"
:loading="isProcessingPayment"
@click="handleActionClick"
class="whitespace-nowrap"
>
{{ isProcessingPayment ? "Processing..." : nextAction.label }}
</UButton>
<div class="flex items-center gap-2 flex-shrink-0">
<!-- Payment button for pending payment status -->
<UButton
v-if="isPendingPayment && nextAction"
:color="getButtonColor(nextAction.color)"
size="sm"
:loading="isProcessingPayment"
@click="handleActionClick"
class="whitespace-nowrap"
>
{{ isProcessingPayment ? "Processing..." : nextAction.label }}
</UButton>
<!-- Link button for other actions -->
<NuxtLink
v-else-if="nextAction && nextAction.link"
:to="nextAction.link"
:class="[
'px-4 py-2 rounded-lg font-medium text-sm whitespace-nowrap transition-all',
getActionButtonClass(nextAction.color),
]"
>
{{ nextAction.label }}
</NuxtLink>
<!-- Link button for other actions -->
<NuxtLink
v-else-if="nextAction && nextAction.link"
:to="nextAction.link"
:class="[
'px-4 py-2 rounded-lg font-medium text-sm whitespace-nowrap transition-all',
getActionButtonClass(nextAction.color),
]"
>
{{ nextAction.label }}
</NuxtLink>
<button
v-if="dismissible"
@click="isDismissed = true"
class="text-guild-400 hover:text-guild-200 transition-colors"
:aria-label="`Dismiss ${statusConfig.label} banner`"
>
<Icon name="heroicons:x-mark" class="w-5 h-5" />
</button>
<button
v-if="dismissible"
@click="isDismissed = true"
class="text-guild-400 hover:text-guild-200 transition-colors"
:aria-label="`Dismiss ${statusConfig.label} banner`"
>
<Icon name="heroicons:x-mark" class="w-5 h-5" />
</button>
</div>
</div>
</div>
</div>
</ClientOnly>
</template>
<script setup>

View file

@ -78,7 +78,7 @@ const props = defineProps({
default: 'e.g., "tomorrow at 3pm", "next Friday at 9am", "in 2 hours"',
},
inputClass: {
type: String,
type: [String, Object],
default: "",
},
required: {

View file

@ -23,7 +23,7 @@
.parchment-inset :deep(p) {
font-size: 13px;
color: #b8ae98;
color: var(--parch-text-dim);
line-height: 1.75;
max-width: 560px;
margin-bottom: 12px;

View file

@ -5,15 +5,20 @@
</span>
<span>
<slot name="right">
<template v-if="memberData">
Signed in as {{ memberData.name }}
<template v-if="memberData.circle">
&middot; {{ memberData.circle }}
<ClientOnly>
<template v-if="memberData">
Signed in as {{ memberData.name }}
<template v-if="memberData.circle">
&middot; {{ memberData.circle }}
</template>
</template>
</template>
<template v-else>
A cooperative for game developers
</template>
<template v-else>
A cooperative for game developers
</template>
<template #fallback>
A cooperative for game developers
</template>
</ClientOnly>
</slot>
</span>
</div>