feat: Add frontmatter editor and enhance page management with YAML support; update dependencies and improve UI interactions
Some checks failed
SteamWarCI Build failed
Some checks failed
SteamWarCI Build failed
This commit is contained in:
122
src/components/moderator/pages/pages/FrontmatterEditor.svelte
Normal file
122
src/components/moderator/pages/pages/FrontmatterEditor.svelte
Normal file
@@ -0,0 +1,122 @@
|
||||
<script lang="ts">
|
||||
import { X } from "lucide-svelte";
|
||||
import { manager } from "./page.svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
</script>
|
||||
|
||||
<details class="group">
|
||||
<summary class="flex items-center justify-between p-3 cursor-pointer hover:bg-neutral-800">
|
||||
<span class="font-medium">Frontmatter</span>
|
||||
<svg class="w-4 h-4 transition-transform group-open:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</summary>
|
||||
<div class="p-3 border-t bg-neutral-900">
|
||||
{#each Object.entries(manager.selectedPage?.frontmatter || {}) as [key, value]}
|
||||
<div class="flex flex-col gap-2 mb-3 p-2 border rounded bg-neutral-800">
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={key}
|
||||
onchange={(e) => {
|
||||
const newKey = (e.target as HTMLInputElement).value;
|
||||
if (newKey !== key) {
|
||||
manager.selectedPage!.frontmatter[newKey] = manager.selectedPage!.frontmatter[key];
|
||||
delete manager.selectedPage?.frontmatter[key];
|
||||
manager.selectedPage!.dirty = true;
|
||||
}
|
||||
}}
|
||||
class="px-2 py-1 border rounded text-sm flex-shrink-0 w-32 bg-neutral-900"
|
||||
placeholder="Key"
|
||||
/>
|
||||
<span>:</span>
|
||||
{#if Array.isArray(value)}
|
||||
<span class="text-xs text-muted-foreground">Array ({value.length} items)</span>
|
||||
{:else if value instanceof Date || key === "created"}
|
||||
<input
|
||||
type="date"
|
||||
value={value instanceof Date ? value.toISOString().split("T")[0] : typeof value === "string" ? value : ""}
|
||||
onchange={(e) => {
|
||||
const dateValue = (e.target as HTMLInputElement).value;
|
||||
manager.selectedPage!.frontmatter[key] = dateValue ? new Date(dateValue) : "";
|
||||
manager.selectedPage!.dirty = true;
|
||||
}}
|
||||
class="px-2 py-1 border rounded text-sm flex-1 bg-neutral-900"
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
type="text"
|
||||
bind:value={manager.selectedPage!.frontmatter[key]}
|
||||
onchange={() => (manager.selectedPage!.dirty = true)}
|
||||
class="px-2 py-1 border rounded text-sm flex-1 bg-neutral-900"
|
||||
placeholder="Value"
|
||||
/>
|
||||
{/if}
|
||||
<button
|
||||
onclick={() => {
|
||||
delete manager.selectedPage!.frontmatter[key];
|
||||
manager.selectedPage!.dirty = true;
|
||||
}}
|
||||
class="text-red-500 hover:text-red-700 p-1"
|
||||
>
|
||||
<X class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
{#if Array.isArray(value)}
|
||||
<div class="ml-4 space-y-1">
|
||||
{#each value as item, index}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-muted-foreground w-6">[{index}]</span>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={manager.selectedPage!.frontmatter[key][index]}
|
||||
onchange={() => (manager.selectedPage!.dirty = true)}
|
||||
class="px-2 py-1 border rounded text-sm flex-1 bg-neutral-900"
|
||||
placeholder="Array item"
|
||||
/>
|
||||
<button
|
||||
onclick={() => {
|
||||
manager.selectedPage!.frontmatter[key].splice(index, 1);
|
||||
manager.selectedPage!.dirty = true;
|
||||
}}
|
||||
class="text-red-500 hover:text-red-700 p-1"
|
||||
>
|
||||
<X class="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
<button
|
||||
onclick={() => {
|
||||
manager.selectedPage!.frontmatter[key].push("");
|
||||
manager.selectedPage!.dirty = true;
|
||||
}}
|
||||
class="text-xs text-blue-500 hover:text-blue-700 ml-8"
|
||||
>
|
||||
+ Add item
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
onclick={() => {
|
||||
manager.selectedPage!.frontmatter[`new_key_${Object.keys(manager.selectedPage!.frontmatter).length}`] = "";
|
||||
manager.selectedPage!.dirty = true;
|
||||
}}
|
||||
class="text-sm text-blue-500 hover:text-blue-700"
|
||||
>
|
||||
+ Add field
|
||||
</button>
|
||||
<button
|
||||
onclick={() => {
|
||||
manager.selectedPage!.frontmatter[`new_array_${Object.keys(manager.selectedPage!.frontmatter).length}`] = [];
|
||||
manager.selectedPage!.dirty = true;
|
||||
}}
|
||||
class="text-sm text-green-500 hover:text-green-700"
|
||||
>
|
||||
+ Add array
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
Reference in New Issue
Block a user