[READ-ONLY] Mirror of https://github.com/danielroe/roe.dev. This is the code and content for my personal website, built in Nuxt.
roe.dev
2.6 kB
102 lines
1<script setup lang="ts">
2import type { DevRoeUsesCategory } from '#shared/lex'
3import type { Strict } from '#shared/cms/strict'
4
5type UsesCategoryValue = Omit<Strict<DevRoeUsesCategory.Record>, '$type'>
6
7const props = defineProps<{
8 initial?: Partial<UsesCategoryValue>
9 submitLabel?: string
10}>()
11
12const emit = defineEmits<{
13 (e: 'submit', value: UsesCategoryValue): void
14}>()
15
16const form = reactive({
17 title: props.initial?.title ?? '',
18 order: props.initial?.order ?? 100,
19 displayAsGrid: props.initial?.displayAsGrid ?? false,
20})
21
22const submitting = ref(false)
23const error = ref<string | null>(null)
24
25async function onSubmit () {
26 error.value = null
27 submitting.value = true
28 try {
29 const value: UsesCategoryValue = {
30 title: form.title,
31 order: form.order,
32 displayAsGrid: form.displayAsGrid,
33 ...(props.initial?.createdAt ? { createdAt: props.initial.createdAt } : { createdAt: new Date().toISOString() }),
34 }
35 emit('submit', value)
36 }
37 catch (err) {
38 error.value = err instanceof Error ? err.message : String(err)
39 }
40 finally {
41 submitting.value = false
42 }
43}
44</script>
45
46<template>
47 <form
48 class="flex flex-col gap-4 max-w-lg"
49 @submit.prevent="onSubmit"
50 >
51 <p
52 v-if="error"
53 class="text-sm text-red-500"
54 >
55 {{ error }}
56 </p>
57
58 <label class="flex flex-col gap-1 text-sm">
59 <span class="text-muted">Title <span class="text-red-500">*</span></span>
60 <input
61 v-model="form.title"
62 required
63 type="text"
64 class="bg-accent px-3 py-2"
65 >
66 </label>
67
68 <label class="flex flex-col gap-1 text-sm">
69 <span class="text-muted">Order</span>
70 <input
71 v-model.number="form.order"
72 type="number"
73 class="bg-accent px-3 py-2"
74 >
75 <span class="text-xs text-muted">Lower numbers render first. Defaults to 100.</span>
76 </label>
77
78 <label class="flex items-center gap-2 text-sm">
79 <input
80 v-model="form.displayAsGrid"
81 type="checkbox"
82 >
83 <span>Display items as a grid (with images) rather than a list</span>
84 </label>
85
86 <div class="flex gap-3">
87 <button
88 type="submit"
89 :disabled="submitting"
90 class="bg-primary text-background px-4 py-2 hover:bg-primary/90 transition-colors disabled:opacity-60"
91 >
92 {{ submitting ? 'Saving…' : (submitLabel ?? 'Save') }}
93 </button>
94 <NuxtLink
95 to="/admin/uses"
96 class="text-muted hover:text-primary self-center text-sm"
97 >
98 Cancel
99 </NuxtLink>
100 </div>
101 </form>
102</template>