add blog editor
This commit is contained in:
@@ -1,31 +1,131 @@
|
||||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
let createNewArticlePopup = $state(false);
|
||||
let loginPopup = $state(false);
|
||||
let password = $state('');
|
||||
let loginError = $state('');
|
||||
let loginLoading = $state(false);
|
||||
|
||||
async function login() {
|
||||
loginLoading = true;
|
||||
loginError = '';
|
||||
const res = await fetch('/admin/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ password })
|
||||
});
|
||||
if (res.ok) {
|
||||
loginPopup = false;
|
||||
password = '';
|
||||
await invalidateAll();
|
||||
} else {
|
||||
loginError = 'Wrong password';
|
||||
}
|
||||
loginLoading = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="text-center py-8 gap-2 flex align-center justify-center">
|
||||
<h1 class="text-2xl">Blog (Stan's yapping corner)</h1>
|
||||
<button
|
||||
onclick={() => (createNewArticlePopup = true)}
|
||||
class="bg-gray-800 rounded px-4 py-2 text-white font-bold">Write new article</button
|
||||
>
|
||||
{#if data.isAdmin}
|
||||
<button
|
||||
onclick={() => (createNewArticlePopup = true)}
|
||||
class="bg-gray-800 rounded px-4 py-2 text-white font-bold cursor-pointer"
|
||||
>Write new article</button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
onclick={() => (loginPopup = true)}
|
||||
class="text-xs text-gray-400 underline cursor-pointer">Admin login</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#each data.blogArticles as article (article.slug)}
|
||||
<div class="flex">
|
||||
<a href={resolve('/blog/{slug}', { slug: article.slug })}>{article.title}</a>
|
||||
<div class="flex gap-2 px-4">
|
||||
<a href={resolve('/blog/[slug]', { slug: article.slug })}>{article.title}</a>
|
||||
{#if data.isAdmin && article.status === 'draft'}
|
||||
<span class="text-xs uppercase text-orange-500">draft</span>
|
||||
<a href={resolve('/blog/[slug]/edit', { slug: article.slug })} class="text-xs underline"
|
||||
>edit</a
|
||||
>
|
||||
{/if}
|
||||
<p>{article.createdAt?.toDateString()}</p>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
{#if createNewArticlePopup}
|
||||
<form method="POST" use:enhance>
|
||||
<div>
|
||||
<h2>Create New Article</h2>
|
||||
</div>
|
||||
</form>
|
||||
<div class="fixed inset-0 flex items-center justify-center bg-black/40">
|
||||
<form
|
||||
method="POST"
|
||||
use:enhance={() => {
|
||||
return async ({ result }) => {
|
||||
if (result.type !== 'redirect') {
|
||||
createNewArticlePopup = false;
|
||||
}
|
||||
};
|
||||
}}
|
||||
class="w-80 rounded bg-white p-6 shadow-xl"
|
||||
>
|
||||
<h2 class="mb-4 text-lg font-bold">Create New Article</h2>
|
||||
<input
|
||||
name="title"
|
||||
placeholder="Article title"
|
||||
required
|
||||
class="mb-4 w-full rounded border border-gray-300 px-3 py-2 text-sm outline-none"
|
||||
/>
|
||||
<div class="flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (createNewArticlePopup = false)}
|
||||
class="rounded px-3 py-2 text-sm cursor-pointer">Cancel</button
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded bg-gray-800 px-3 py-2 text-sm font-bold text-white cursor-pointer"
|
||||
>Create draft</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if loginPopup}
|
||||
<div class="fixed inset-0 flex items-center justify-center bg-black/40">
|
||||
<div class="w-80 rounded bg-white p-6 shadow-xl">
|
||||
<h2 class="mb-4 text-lg font-bold">Admin login</h2>
|
||||
<input
|
||||
type="password"
|
||||
bind:value={password}
|
||||
placeholder="Password"
|
||||
onkeydown={(e) => e.key === 'Enter' && login()}
|
||||
class="mb-3 w-full rounded border border-gray-300 px-3 py-2 text-sm outline-none"
|
||||
/>
|
||||
{#if loginError}
|
||||
<p class="mb-3 text-xs text-red-500">{loginError}</p>
|
||||
{/if}
|
||||
<div class="flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
loginPopup = false;
|
||||
loginError = '';
|
||||
}}
|
||||
class="rounded px-3 py-2 text-sm cursor-pointer">Cancel</button
|
||||
>
|
||||
<button
|
||||
onclick={login}
|
||||
disabled={loginLoading}
|
||||
class="rounded bg-gray-800 px-3 py-2 text-sm font-bold text-white disabled:opacity-50 cursor-pointer disabled:cursor-not-allowed"
|
||||
>
|
||||
{loginLoading ? 'Logging in…' : 'Log in'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user