@rimelight/cms 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/package.json +16 -14
- package/src/admin/api/media-file.ts +39 -0
- package/src/admin/api/media.ts +199 -0
- package/src/admin/layouts/CMSDashboardLayout.astro +178 -0
- package/src/admin/layouts/DefaultParentLayout.astro +50 -0
- package/src/admin/pages/assets.astro +424 -0
- package/src/admin/pages/byline-schema.astro +62 -0
- package/src/admin/pages/bylines.astro +16 -0
- package/src/admin/pages/categories.astro +21 -0
- package/src/admin/pages/content-types.astro +55 -0
- package/src/admin/pages/dashboard.astro +61 -0
- package/src/admin/pages/pages-edit.astro +595 -0
- package/src/admin/pages/pages-index.astro +146 -0
- package/src/admin/pages/pages-new.astro +130 -0
- package/src/admin/pages/pages-preview.astro +111 -0
- package/src/admin/pages/pages-review.astro +236 -0
- package/src/admin/pages/settings.astro +203 -0
- package/src/admin/pages/tags.astro +21 -0
- package/src/admin/pages/templates-edit.astro +234 -0
- package/src/admin/pages/templates-index.astro +95 -0
- package/src/admin/pages/templates-new.astro +193 -0
- package/src/admin/pages/users.astro +74 -0
- package/src/admin/pages/versions.astro +74 -0
- package/src/astro/BlockRenderer.astro +44 -96
- package/src/astro/PageRenderer.astro +9 -2
- package/src/astro/blocks/CalloutBlock.astro +7 -7
- package/src/astro/blocks/CardBlock.astro +5 -5
- package/src/astro/blocks/CodeBlock.astro +2 -2
- package/src/astro/blocks/FileTreeBlock.astro +7 -7
- package/src/astro/blocks/ImageBlock.astro +2 -2
- package/src/astro/blocks/OrderedListBlock.astro +2 -2
- package/src/astro/blocks/ParagraphBlock.astro +3 -3
- package/src/astro/blocks/SectionBlock.astro +6 -6
- package/src/astro/blocks/StepItemBlock.astro +3 -3
- package/src/astro/blocks/StepsBlock.astro +1 -1
- package/src/astro/blocks/TableBlock.astro +6 -6
- package/src/astro/blocks/TabsBlock.astro +9 -9
- package/src/astro/blocks/UnorderedListBlock.astro +2 -2
- package/src/astro/blocks/index.ts +35 -0
- package/src/client/components/RimelightBlock.tsx +19 -19
- package/src/client/components/RimelightBlockPicker.tsx +9 -13
- package/src/client/components/RimelightBylinesManager.tsx +438 -0
- package/src/client/components/RimelightEditor.tsx +3 -3
- package/src/client/components/RimelightPreview.tsx +37 -45
- package/src/client/components/RimelightPropertiesPanel.tsx +368 -26
- package/src/client/components/RimelightTaxonomyManager.tsx +369 -0
- package/src/client/components/RimelightTaxonomyMasterDetail.tsx +412 -0
- package/src/client/components/RimelightTemplateEditor.tsx +6 -8
- package/src/client/components/editors/CalloutEditor.tsx +2 -4
- package/src/client/components/editors/CardsEditor.tsx +2 -4
- package/src/client/components/editors/CodeEditor.tsx +1 -3
- package/src/client/components/editors/FileTreeEditor.tsx +2 -4
- package/src/client/components/editors/ImageEditor.tsx +3 -3
- package/src/client/components/editors/ParagraphEditor.tsx +2 -2
- package/src/client/components/editors/SceneEditor.tsx +6 -12
- package/src/client/components/editors/ScriptEditor.tsx +8 -16
- package/src/client/components/editors/SectionEditor.tsx +4 -4
- package/src/client/components/editors/StepItemEditor.tsx +2 -2
- package/src/client/components/editors/StepsEditor.tsx +2 -4
- package/src/client/components/editors/TabItemEditor.tsx +3 -3
- package/src/client/components/editors/TableEditor.tsx +5 -5
- package/src/client/components/editors/TabsEditor.tsx +2 -4
- package/src/client/components/index.ts +3 -0
- package/src/client/loader.ts +3 -0
- package/src/core/diff.ts +145 -0
- package/src/core/excerpt.ts +159 -0
- package/src/core/preview.ts +87 -0
- package/src/core/registry.ts +0 -39
- package/src/core/types/blocks.ts +83 -6
- package/src/core/types/bylines.ts +14 -0
- package/src/core/types/media.ts +13 -0
- package/src/core/types/taxonomies.ts +20 -0
- package/src/cron/scheduled.ts +57 -0
- package/src/docs/agent.ts +116 -0
- package/src/docs/config.ts +25 -0
- package/src/docs/index.ts +5 -0
- package/src/docs/routing.ts +104 -0
- package/src/docs/sidebar.ts +251 -0
- package/src/docs/toc.ts +47 -0
- package/src/env.d.ts +13 -0
- package/src/index.ts +40 -6
- package/src/integration.ts +196 -0
- package/src/loader/live.ts +254 -0
- package/src/markdown/index.ts +0 -1
- package/src/mcp/index.ts +228 -0
- package/src/schema/bylines.ts +23 -0
- package/src/schema/index.ts +3 -0
- package/src/schema/page_versions.ts +2 -0
- package/src/schema/pages.ts +2 -0
- package/src/schema/site_settings.ts +41 -0
- package/src/schema/taxonomies.ts +49 -0
- package/src/services/bylines.ts +74 -0
- package/src/services/search-indexer.ts +61 -0
- package/src/services/site-settings.ts +108 -0
- package/src/services/taxonomies.ts +276 -0
- package/src/storage/index.ts +253 -0
- package/src/astro/blocks/DialogueBlock.astro +0 -23
- package/src/astro/blocks/SceneBlock.astro +0 -65
- package/src/astro/blocks/ScriptBlock.astro +0 -59
- package/src/core/template-sync.ts +0 -75
- package/src/markdown/parser.ts +0 -347
- package/src/migration.ts +0 -155
- package/src/search/sync.ts +0 -32
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { createSignal, onMount, For, Show, type Component } from "solid-js"
|
|
2
|
+
import RLSInput from "@rimelight/ui/components/input/RLSInput.tsx"
|
|
3
|
+
import RLSButton from "@rimelight/ui/components/button/RLSButton.tsx"
|
|
4
|
+
import RLSBadge from "@rimelight/ui/components/badge/RLSBadge.tsx"
|
|
5
|
+
import RLSModal from "@rimelight/ui/components/modal/RLSModal.tsx"
|
|
6
|
+
import RLSIcon from "@rimelight/ui/components/icon/RLSIcon.tsx"
|
|
7
|
+
|
|
8
|
+
export interface TaxonomyTermRecord {
|
|
9
|
+
id: string
|
|
10
|
+
taxonomy: string
|
|
11
|
+
name: string
|
|
12
|
+
slug: string
|
|
13
|
+
description?: string
|
|
14
|
+
parentId?: string | null
|
|
15
|
+
postCount?: number
|
|
16
|
+
children?: TaxonomyTermRecord[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RimelightTaxonomyManagerProps {
|
|
20
|
+
initialTaxonomy?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const RimelightTaxonomyManager: Component<RimelightTaxonomyManagerProps> = (props) => {
|
|
24
|
+
const [activeTaxonomy, setActiveTaxonomy] = createSignal<string>(
|
|
25
|
+
props.initialTaxonomy || "category"
|
|
26
|
+
)
|
|
27
|
+
const [terms, setTerms] = createSignal<TaxonomyTermRecord[]>([])
|
|
28
|
+
const [isLoading, setIsLoading] = createSignal(false)
|
|
29
|
+
const [error, setError] = createSignal<string | null>(null)
|
|
30
|
+
|
|
31
|
+
// Add / Edit Modal State
|
|
32
|
+
const [isModalOpen, setIsModalOpen] = createSignal(false)
|
|
33
|
+
const [editingTermId, setEditingTermId] = createSignal<string | null>(null)
|
|
34
|
+
const [termForm, setTermForm] = createSignal<{
|
|
35
|
+
name: string
|
|
36
|
+
slug: string
|
|
37
|
+
parentId: string
|
|
38
|
+
description: string
|
|
39
|
+
}>({
|
|
40
|
+
name: "",
|
|
41
|
+
slug: "",
|
|
42
|
+
parentId: "",
|
|
43
|
+
description: ""
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const loadTerms = async () => {
|
|
47
|
+
setIsLoading(true)
|
|
48
|
+
setError(null)
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch(`/api/cms/taxonomies/${activeTaxonomy()}/terms?includeCounts=true`)
|
|
51
|
+
if (!res.ok) throw new Error("Failed to load taxonomy terms")
|
|
52
|
+
const data = await res.json()
|
|
53
|
+
setTerms(Array.isArray(data) ? data : [])
|
|
54
|
+
} catch (err: any) {
|
|
55
|
+
setError(err.message || "Failed to load terms")
|
|
56
|
+
} finally {
|
|
57
|
+
setIsLoading(false)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onMount(() => {
|
|
62
|
+
void loadTerms()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const handleTaxonomyTabChange = (tax: string) => {
|
|
66
|
+
setActiveTaxonomy(tax)
|
|
67
|
+
void loadTerms()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const openAddModal = (parentId: string = "") => {
|
|
71
|
+
setEditingTermId(null)
|
|
72
|
+
setTermForm({ name: "", slug: "", parentId, description: "" })
|
|
73
|
+
setIsModalOpen(true)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const openEditModal = (term: TaxonomyTermRecord) => {
|
|
77
|
+
setEditingTermId(term.id)
|
|
78
|
+
setTermForm({
|
|
79
|
+
name: term.name,
|
|
80
|
+
slug: term.slug,
|
|
81
|
+
parentId: term.parentId || "",
|
|
82
|
+
description: term.description || ""
|
|
83
|
+
})
|
|
84
|
+
setIsModalOpen(true)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const handleSaveTerm = async () => {
|
|
88
|
+
const form = termForm()
|
|
89
|
+
if (!form.name.trim()) return
|
|
90
|
+
|
|
91
|
+
const slug =
|
|
92
|
+
form.slug.trim() ||
|
|
93
|
+
form.name
|
|
94
|
+
.toLowerCase()
|
|
95
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
96
|
+
.replace(/(^-|-$)/g, "")
|
|
97
|
+
|
|
98
|
+
const payload = {
|
|
99
|
+
name: form.name.trim(),
|
|
100
|
+
slug,
|
|
101
|
+
parentId: form.parentId ? form.parentId : null,
|
|
102
|
+
description: form.description.trim()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
if (editingTermId()) {
|
|
107
|
+
const res = await fetch(
|
|
108
|
+
`/api/cms/taxonomies/${activeTaxonomy()}/terms/${editingTermId()}`,
|
|
109
|
+
{
|
|
110
|
+
method: "PUT",
|
|
111
|
+
headers: { "Content-Type": "application/json" },
|
|
112
|
+
body: JSON.stringify(payload)
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
if (!res.ok) throw new Error("Failed to update term")
|
|
116
|
+
} else {
|
|
117
|
+
const res = await fetch(`/api/cms/taxonomies/${activeTaxonomy()}/terms`, {
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: { "Content-Type": "application/json" },
|
|
120
|
+
body: JSON.stringify(payload)
|
|
121
|
+
})
|
|
122
|
+
if (!res.ok) throw new Error("Failed to create term")
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
setIsModalOpen(false)
|
|
126
|
+
void loadTerms()
|
|
127
|
+
} catch (err: any) {
|
|
128
|
+
alert(err.message || "Failed to save term")
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const handleDeleteTerm = async (id: string, name: string) => {
|
|
133
|
+
if (!confirm(`Are you sure you want to delete term "${name}"?`)) return
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const res = await fetch(`/api/cms/taxonomies/${activeTaxonomy()}/terms/${id}`, {
|
|
137
|
+
method: "DELETE"
|
|
138
|
+
})
|
|
139
|
+
if (!res.ok) throw new Error("Failed to delete term")
|
|
140
|
+
void loadTerms()
|
|
141
|
+
} catch (err: any) {
|
|
142
|
+
alert(err.message || "Failed to delete term")
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div class="flex flex-col gap-6 w-full">
|
|
148
|
+
{/* Header & Tabs */}
|
|
149
|
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 border-b border-default pb-4">
|
|
150
|
+
<div class="flex flex-col">
|
|
151
|
+
<h2 class="text-xl font-bold text-highlighted">Taxonomy Manager</h2>
|
|
152
|
+
<p class="text-xs text-muted mt-0.5">
|
|
153
|
+
Organize posts and pages with hierarchical categories and flat tags.
|
|
154
|
+
</p>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div class="flex items-center gap-2">
|
|
158
|
+
<div class="flex p-1 bg-elevated rounded-lg border border-default">
|
|
159
|
+
<button
|
|
160
|
+
type="button"
|
|
161
|
+
onClick={() => handleTaxonomyTabChange("category")}
|
|
162
|
+
class={`px-3 py-1.5 text-xs font-semibold rounded-md transition ${
|
|
163
|
+
activeTaxonomy() === "category"
|
|
164
|
+
? "bg-background text-primary shadow-sm"
|
|
165
|
+
: "text-muted hover:text-highlighted bg-transparent"
|
|
166
|
+
}`}
|
|
167
|
+
>
|
|
168
|
+
Categories
|
|
169
|
+
</button>
|
|
170
|
+
<button
|
|
171
|
+
type="button"
|
|
172
|
+
onClick={() => handleTaxonomyTabChange("tag")}
|
|
173
|
+
class={`px-3 py-1.5 text-xs font-semibold rounded-md transition ${
|
|
174
|
+
activeTaxonomy() === "tag"
|
|
175
|
+
? "bg-background text-primary shadow-sm"
|
|
176
|
+
: "text-muted hover:text-highlighted bg-transparent"
|
|
177
|
+
}`}
|
|
178
|
+
>
|
|
179
|
+
Tags
|
|
180
|
+
</button>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<RLSButton
|
|
184
|
+
variant="solid"
|
|
185
|
+
color="primary"
|
|
186
|
+
size="sm"
|
|
187
|
+
onClick={() => openAddModal()}
|
|
188
|
+
leadingIcon="plus"
|
|
189
|
+
label={`Add ${activeTaxonomy() === "category" ? "Category" : "Tag"}`}
|
|
190
|
+
/>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
{/* Content Table / Tree */}
|
|
195
|
+
<div class="bg-elevated/40 border border-default rounded-xl overflow-hidden">
|
|
196
|
+
<Show when={isLoading()}>
|
|
197
|
+
<div class="p-8 text-center text-sm text-muted animate-pulse">Loading terms...</div>
|
|
198
|
+
</Show>
|
|
199
|
+
|
|
200
|
+
<Show when={error()}>
|
|
201
|
+
<div class="p-4 text-center text-sm text-error-500">{error()}</div>
|
|
202
|
+
</Show>
|
|
203
|
+
|
|
204
|
+
<Show when={!isLoading() && terms().length === 0}>
|
|
205
|
+
<div class="p-12 text-center flex flex-col items-center justify-center gap-2">
|
|
206
|
+
<RLSIcon name="folder" size="lg" class="text-muted/50" />
|
|
207
|
+
<span class="text-sm font-semibold text-highlighted">
|
|
208
|
+
No {activeTaxonomy()} terms found
|
|
209
|
+
</span>
|
|
210
|
+
<p class="text-xs text-muted max-w-sm">
|
|
211
|
+
Create your first {activeTaxonomy()} term to classify articles and documentation.
|
|
212
|
+
</p>
|
|
213
|
+
<RLSButton
|
|
214
|
+
variant="outline"
|
|
215
|
+
color="primary"
|
|
216
|
+
size="xs"
|
|
217
|
+
onClick={() => openAddModal()}
|
|
218
|
+
label="Create Term"
|
|
219
|
+
class="mt-2"
|
|
220
|
+
/>
|
|
221
|
+
</div>
|
|
222
|
+
</Show>
|
|
223
|
+
|
|
224
|
+
<Show when={!isLoading() && terms().length > 0}>
|
|
225
|
+
<div class="overflow-x-auto">
|
|
226
|
+
<table class="w-full text-left text-sm border-collapse">
|
|
227
|
+
<thead>
|
|
228
|
+
<tr class="border-b border-default bg-elevated/70 text-xs font-semibold text-muted uppercase tracking-wider">
|
|
229
|
+
<th class="py-3 px-4">Name</th>
|
|
230
|
+
<th class="py-3 px-4">Slug</th>
|
|
231
|
+
<th class="py-3 px-4">Description</th>
|
|
232
|
+
<th class="py-3 px-4 text-center">Posts</th>
|
|
233
|
+
<th class="py-3 px-4 text-right">Actions</th>
|
|
234
|
+
</tr>
|
|
235
|
+
</thead>
|
|
236
|
+
<tbody class="divide-y divide-default/50">
|
|
237
|
+
<For each={terms()}>
|
|
238
|
+
{(term) => (
|
|
239
|
+
<tr class="hover:bg-elevated/50 transition">
|
|
240
|
+
<td class="py-3 px-4 font-medium text-highlighted flex items-center gap-2">
|
|
241
|
+
{activeTaxonomy() === "tag" ? (
|
|
242
|
+
<RLSBadge variant="soft" color="neutral" size="sm">
|
|
243
|
+
#{term.name}
|
|
244
|
+
</RLSBadge>
|
|
245
|
+
) : (
|
|
246
|
+
<span>{term.name}</span>
|
|
247
|
+
)}
|
|
248
|
+
</td>
|
|
249
|
+
<td class="py-3 px-4 font-mono text-xs text-muted">{term.slug}</td>
|
|
250
|
+
<td class="py-3 px-4 text-xs text-muted max-w-xs truncate">
|
|
251
|
+
{term.description || "—"}
|
|
252
|
+
</td>
|
|
253
|
+
<td class="py-3 px-4 text-center">
|
|
254
|
+
<span class="inline-flex items-center justify-center px-2 py-0.5 text-xs font-semibold rounded-full bg-primary/10 text-primary">
|
|
255
|
+
{term.postCount ?? 0}
|
|
256
|
+
</span>
|
|
257
|
+
</td>
|
|
258
|
+
<td class="py-3 px-4 text-right">
|
|
259
|
+
<div class="inline-flex items-center gap-1">
|
|
260
|
+
<RLSButton
|
|
261
|
+
variant="ghost"
|
|
262
|
+
color="neutral"
|
|
263
|
+
size="xs"
|
|
264
|
+
square={true}
|
|
265
|
+
onClick={() => openEditModal(term)}
|
|
266
|
+
title="Edit"
|
|
267
|
+
leading={<RLSIcon name="edit" size="xs" />}
|
|
268
|
+
/>
|
|
269
|
+
<RLSButton
|
|
270
|
+
variant="ghost"
|
|
271
|
+
color="neutral"
|
|
272
|
+
size="xs"
|
|
273
|
+
square={true}
|
|
274
|
+
onClick={() => handleDeleteTerm(term.id, term.name)}
|
|
275
|
+
title="Delete"
|
|
276
|
+
class="!text-error-500 hover:!text-error-600"
|
|
277
|
+
leading={<RLSIcon name="trash" size="xs" />}
|
|
278
|
+
/>
|
|
279
|
+
</div>
|
|
280
|
+
</td>
|
|
281
|
+
</tr>
|
|
282
|
+
)}
|
|
283
|
+
</For>
|
|
284
|
+
</tbody>
|
|
285
|
+
</table>
|
|
286
|
+
</div>
|
|
287
|
+
</Show>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
{/* Add / Edit Modal */}
|
|
291
|
+
<RLSModal
|
|
292
|
+
open={isModalOpen()}
|
|
293
|
+
onClose={() => setIsModalOpen(false)}
|
|
294
|
+
title={editingTermId() ? `Edit ${activeTaxonomy()}` : `Add New ${activeTaxonomy()}`}
|
|
295
|
+
footerSlot={
|
|
296
|
+
<>
|
|
297
|
+
<RLSButton
|
|
298
|
+
variant="outline"
|
|
299
|
+
color="neutral"
|
|
300
|
+
size="sm"
|
|
301
|
+
onClick={() => setIsModalOpen(false)}
|
|
302
|
+
label="Cancel"
|
|
303
|
+
/>
|
|
304
|
+
<RLSButton
|
|
305
|
+
variant="solid"
|
|
306
|
+
color="primary"
|
|
307
|
+
size="sm"
|
|
308
|
+
onClick={handleSaveTerm}
|
|
309
|
+
label={editingTermId() ? "Update Term" : "Create Term"}
|
|
310
|
+
/>
|
|
311
|
+
</>
|
|
312
|
+
}
|
|
313
|
+
>
|
|
314
|
+
<div class="flex flex-col gap-4 py-2">
|
|
315
|
+
<div class="flex flex-col gap-1">
|
|
316
|
+
<span class="text-xs font-semibold text-muted">Name *</span>
|
|
317
|
+
<RLSInput
|
|
318
|
+
value={termForm().name}
|
|
319
|
+
onInput={(e: InputEvent & { currentTarget: HTMLInputElement }) =>
|
|
320
|
+
setTermForm({ ...termForm(), name: e.currentTarget.value })
|
|
321
|
+
}
|
|
322
|
+
placeholder="e.g. Engineering, Guides, Releases"
|
|
323
|
+
/>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
<div class="flex flex-col gap-1">
|
|
327
|
+
<span class="text-xs font-semibold text-muted">Slug (URL identifier)</span>
|
|
328
|
+
<RLSInput
|
|
329
|
+
value={termForm().slug}
|
|
330
|
+
onInput={(e: InputEvent & { currentTarget: HTMLInputElement }) =>
|
|
331
|
+
setTermForm({ ...termForm(), slug: e.currentTarget.value })
|
|
332
|
+
}
|
|
333
|
+
placeholder="Auto-generated if left empty"
|
|
334
|
+
/>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<Show when={activeTaxonomy() === "category"}>
|
|
338
|
+
<div class="flex flex-col gap-1">
|
|
339
|
+
<span class="text-xs font-semibold text-muted">Parent Category</span>
|
|
340
|
+
<select
|
|
341
|
+
value={termForm().parentId}
|
|
342
|
+
onChange={(e) => setTermForm({ ...termForm(), parentId: e.currentTarget.value })}
|
|
343
|
+
class="w-full text-sm py-2 px-3 rounded-lg border border-default bg-background text-highlighted focus:outline-none focus:ring-1 focus:ring-primary"
|
|
344
|
+
>
|
|
345
|
+
<option value="">(None - Top Level)</option>
|
|
346
|
+
<For each={terms().filter((t) => t.id !== editingTermId())}>
|
|
347
|
+
{(cat) => <option value={cat.id}>{cat.name}</option>}
|
|
348
|
+
</For>
|
|
349
|
+
</select>
|
|
350
|
+
</div>
|
|
351
|
+
</Show>
|
|
352
|
+
|
|
353
|
+
<div class="flex flex-col gap-1">
|
|
354
|
+
<span class="text-xs font-semibold text-muted">Description</span>
|
|
355
|
+
<textarea
|
|
356
|
+
value={termForm().description}
|
|
357
|
+
onInput={(e: InputEvent & { currentTarget: HTMLTextAreaElement }) =>
|
|
358
|
+
setTermForm({ ...termForm(), description: e.currentTarget.value })
|
|
359
|
+
}
|
|
360
|
+
rows={3}
|
|
361
|
+
placeholder="Optional description of this taxonomy term..."
|
|
362
|
+
class="w-full text-sm py-2 px-3 rounded-lg border border-default bg-background text-highlighted focus:outline-none focus:ring-1 focus:ring-primary resize-none"
|
|
363
|
+
/>
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</RLSModal>
|
|
367
|
+
</div>
|
|
368
|
+
)
|
|
369
|
+
}
|