thomaswilson-sveltekit/src/routes/blog/new/+page.svelte

144 lines
3.2 KiB
Svelte
Raw Normal View History

2023-02-12 10:16:13 +00:00
<script lang="ts">
import { format as formatDate } from "date-fns";
import { BlogPost } from "$lib/blog/BlogPost.js";
2025-01-04 15:35:07 +00:00
let title = $state("");
let author = $state("Thomas Wilson");
let date = new Date();
2025-01-04 15:35:07 +00:00
let content = $state("");
let slug = $state("");
let blogPost: BlogPost | null = null;
2023-02-12 10:16:13 +00:00
function slugifyString(originalString: string): string {
return originalString
.toLowerCase()
.replaceAll(/ /g, "-")
.replaceAll(/[^a-zA-Z0-9-]+/g, "")
.replaceAll(/-+/g, "-");
}
function handleTitleChange() {
const dateAsString = formatDate(date, "yyyy-MM-dd");
const slugifiedTitle = slugifyString(title);
slug = `${dateAsString}-${slugifiedTitle}`;
}
function handleContentChange(value: string) {
const maybeTitle = value.trim();
if (maybeTitle.startsWith(`#`) && !title) {
title = content.split("\n")[0].replace("#", "").trim();
handleTitleChange();
}
}
2023-02-12 10:16:13 +00:00
</script>
<section class="new-blog-post">
<a href="/blog">Back to Blog</a>
2023-02-12 10:16:13 +00:00
<h1>New Blog Post</h1>
2025-01-16 19:56:49 +00:00
<form method="POST" action="/blog/new">
<div class="field">
<label class="field__label" for="title">Title</label>
<input
type="text"
id="title"
2025-01-09 14:08:29 +00:00
name="title"
required
2024-08-26 09:57:05 +00:00
bind:value={title}
2025-01-04 15:35:07 +00:00
onchange={handleTitleChange}
/>
</div>
<div class="field">
<label class="field__label" for="author">Author</label>
2025-01-09 14:08:29 +00:00
<input
type="text"
name="author"
id="author"
required
bind:value={author}
/>
</div>
<div class="field">
<label class="field__label" for="slug">Slug</label>
2025-01-09 14:08:29 +00:00
<input type="text" name="slug" id="slug" required bind:value={slug} />
</div>
<div class="field">
<label class="field__label" for="content">Content</label>
2025-01-09 14:08:29 +00:00
<textarea
name="content"
id="content"
rows="10"
cols="50"
bind:value={content}
onchange={(e) => handleContentChange(e.currentTarget.value ?? "")}
2025-01-09 14:08:29 +00:00
></textarea>
</div>
<div class="submit">
2025-01-09 14:08:29 +00:00
<button type="submit" class="create-button">Publish</button>
</div>
</form>
2023-02-12 10:16:13 +00:00
</section>
{#if blogPost}
<section class="preview">
<h2>Preview</h2>
<article>
{@html blogPost.html}
</article>
</section>
{/if}
2023-02-12 10:16:13 +00:00
<style>
section {
--gap: 8px;
--padding: 8px;
--padding-md: 16px;
}
.new-blog-post {
display: grid;
grid-template-columns: 100%;
grid-template-rows: min-content min-content min-content 1fr;
gap: var(--gap);
place-items: center;
}
.field {
width: 100%;
max-width: 600px;
display: flex;
flex-direction: column;
}
.field__label {
font-family: var(--font-family-title);
font-size: 1.15rem;
color: var(--grey-600);
}
.create-button {
background-color: var(--brand-orange);
color: var(--white);
border: none;
border-radius: 4px;
padding: var(--padding) var(--padding-md);
font-family: var(--font-family-title);
font-size: 1.15rem;
cursor: pointer;
}
.preview {
display: grid;
grid-template-columns: 100%;
grid-template-rows: min-content 1fr;
gap: var(--gap);
place-items: center;
}
.preview article {
width: 100%;
max-width: 65ch;
}
2023-02-12 10:16:13 +00:00
</style>