Add categories feature #3

Merged
lmika merged 14 commits from feature/categories into main 2026-03-21 23:29:05 +00:00
8 changed files with 78 additions and 56 deletions
Showing only changes of commit f45bdcd83c - Show all commits

View file

@ -10,21 +10,7 @@ $container-max-widths: (
@import "bootstrap/scss/bootstrap.scss"; @import "bootstrap/scss/bootstrap.scss";
// Local classes // Post list
.post-form {
display: grid;
grid-template-rows: min-content auto min-content;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.post-form textarea {
height: 100%;
}
.postlist .post img { .postlist .post img {
max-width: 300px; max-width: 300px;
@ -32,6 +18,49 @@ $container-max-widths: (
max-height: 300px; max-height: 300px;
} }
.postlist .post-date {
font-size: 0.9rem;
}
// Post form
// Post edit page styling
.post-edit-page {
height: 100vh;
}
.post-edit-page main {
display: flex;
flex-direction: column;
overflow: hidden;
}
.post-edit-page .post-form {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.post-edit-page .post-form .row {
flex: 1;
display: flex;
min-height: 0;
}
.post-edit-page .post-form .col-md-9 {
display: flex;
flex-direction: column;
}
.post-edit-page .post-form textarea {
flex: 1;
resize: vertical;
min-height: 300px;
}
.show-upload figure img { .show-upload figure img {
max-width: 100vw; max-width: 100vw;
height: auto; height: auto;

View file

@ -53,6 +53,7 @@ func (ph PostsHandler) New(c fiber.Ctx) error {
"post": p, "post": p,
"categories": cats, "categories": cats,
"selectedCategories": map[int64]bool{}, "selectedCategories": map[int64]bool{},
"bodyClass": "post-edit-page",
}) })
} }
@ -93,6 +94,7 @@ func (ph PostsHandler) Edit(c fiber.Ctx) error {
"post": post, "post": post,
"categories": cats, "categories": cats,
"selectedCategories": selectedCategories, "selectedCategories": selectedCategories,
"bodyClass": "post-edit-page",
}) })
})) }))
} }

View file

@ -180,6 +180,7 @@ func (b *Builder) renderFeeds(ctx buildContext, postIter iter.Seq[models.Maybe[*
Title: postTitle, Title: postTitle,
Link: &feedhub.Link{Href: renderedPost.PostURL}, Link: &feedhub.Link{Href: renderedPost.PostURL},
Content: string(renderedPost.HTML), Content: string(renderedPost.HTML),
// TO FIX: Why the heck does this only include the first category?
Category: catName, Category: catName,
// TO FIX: Created should be first published // TO FIX: Created should be first published
Created: post.PublishedAt, Created: post.PublishedAt,

View file

@ -1,6 +1,6 @@
<main class="container"> <main class="container">
<div class="my-4"> <div class="my-4">
<h4>{{ if .isNew }}New Category{{ else }}Edit Category{{ end }}</h4> <h5>{{ if .isNew }}New Category{{ else }}Edit Category{{ end }}</h5>
</div> </div>
{{ if .isNew }} {{ if .isNew }}
@ -10,27 +10,27 @@
{{ end }} {{ end }}
<input type="hidden" name="guid" value="{{ .category.GUID }}"> <input type="hidden" name="guid" value="{{ .category.GUID }}">
<div class="row mb-3"> <div class="row mb-3">
<label for="catName" class="col-sm-2 col-form-label">Name</label> <label for="catName" class="col-sm-3 col-form-label text-end">Name</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" id="catName" name="name" value="{{ .category.Name }}"> <input type="text" class="form-control" id="catName" name="name" value="{{ .category.Name }}">
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="catSlug" class="col-sm-2 col-form-label">Slug</label> <label for="catSlug" class="col-sm-3 col-form-label text-end">Slug</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" id="catSlug" name="slug" value="{{ .category.Slug }}"> <input type="text" class="form-control" id="catSlug" name="slug" value="{{ .category.Slug }}">
<div class="form-text">Auto-generated from name if left blank.</div> <div class="form-text">Auto-generated from name if left blank.</div>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="catDesc" class="col-sm-2 col-form-label">Description</label> <label for="catDesc" class="col-sm-3 col-form-label text-end">Description</label>
<div class="col-sm-9"> <div class="col-sm-9">
<textarea class="form-control" id="catDesc" name="description" rows="5">{{ .category.Description }}</textarea> <textarea class="form-control" id="catDesc" name="description" rows="5">{{ .category.Description }}</textarea>
<div class="form-text">Markdown supported. Displayed on the category archive page.</div> <div class="form-text">Markdown supported. Displayed on the category archive page.</div>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-sm-2"></div> <div class="col-sm-3"></div>
<div class="col-sm-9"> <div class="col-sm-9">
<button type="submit" class="btn btn-primary">{{ if .isNew }}Create{{ else }}Save{{ end }}</button> <button type="submit" class="btn btn-primary">{{ if .isNew }}Create{{ else }}Save{{ end }}</button>
{{ if not .isNew }} {{ if not .isNew }}

View file

@ -1,35 +1,30 @@
<main class="container"> <main class="container">
<div class="my-4 d-flex justify-content-between align-items-baseline"> <div class="my-4 d-flex justify-content-between align-items-baseline">
<h4>Categories</h4>
<div> <div>
<a href="/sites/{{ .site.ID }}/categories/new" class="btn btn-success">New Category</a> <a href="/sites/{{ .site.ID }}/categories/new" class="btn btn-success">New Category</a>
</div> </div>
</div> </div>
{{ range .categories }}
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Slug</th> <th>Slug</th>
<th>Posts</th> <th>Posts</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{ range .categories }}
<tr> <tr>
<td><a href="/sites/{{ $.site.ID }}/categories/{{ .ID }}">{{ .Name }}</a></td> <td><a href="/sites/{{ $.site.ID }}/categories/{{ .ID }}">{{ .Name }}</a></td>
<td><code>{{ .Slug }}</code></td> <td><code>{{ .Slug }}</code></td>
<td>{{ .PostCount }}</td> <td>{{ .PostCount }}</td>
<td>
<a href="/sites/{{ $.site.ID }}/categories/{{ .ID }}" class="btn btn-outline-secondary btn-sm">Edit</a>
</td>
</tr> </tr>
{{ else }}
<tr>
<td colspan="4" class="text-center text-muted py-4">No categories yet.</td>
</tr>
{{ end }}
</tbody> </tbody>
</table> </table>
{{ else }}
<div class="h4 m-3 text-center">
<div class="position-absolute top-50 start-50 translate-middle">📚<br>No categories yet.</div>
</div>
{{ end }}
</main> </main>

View file

@ -7,7 +7,7 @@
<link rel="stylesheet" href="/static/assets/main.css"> <link rel="stylesheet" href="/static/assets/main.css">
<script src="/static/assets/main.js" type="module"></script> <script src="/static/assets/main.js" type="module"></script>
</head> </head>
<body class="min-vh-100 d-flex flex-column"> <body class="d-flex flex-column {{.bodyClass}}">
{{ template "_common/nav" . }} {{ template "_common/nav" . }}
{{ embed }} {{ embed }}

View file

@ -1,6 +1,6 @@
{{ $isPublished := ne .post.State 1 }} {{ $isPublished := ne .post.State 1 }}
<main class="flex-grow-1 position-relative"> <main class="flex-grow-1 position-relative">
<form action="/sites/{{.site.ID}}/posts" method="post" class="container-fluid post-form p-2" <form action="/sites/{{.site.ID}}/posts" method="post" class="container-fluid post-form py-2"
data-controller="postedit" data-controller="postedit"
data-action="keydown.meta+s->postedit#save keydown.meta+enter->postedit#publish" data-action="keydown.meta+s->postedit#save keydown.meta+enter->postedit#publish"
data-postedit-save-action-value="{{ if $isPublished }}Update{{ else }}Save Draft{{ end }}"> data-postedit-save-action-value="{{ if $isPublished }}Update{{ else }}Save Draft{{ end }}">
@ -10,9 +10,7 @@
<div class="mb-2"> <div class="mb-2">
<input type="text" name="title" class="form-control" placeholder="Title" value="{{ .post.Title }}"> <input type="text" name="title" class="form-control" placeholder="Title" value="{{ .post.Title }}">
</div> </div>
<div> <textarea data-postedit-target="bodyTextEdit" name="body" class="form-control flex-grow-1" rows="3">{{.post.Body}}</textarea>
<textarea data-postedit-target="bodyTextEdit" name="body" class="form-control" rows="3">{{.post.Body}}</textarea>
</div>
<div> <div>
{{ if $isPublished }} {{ if $isPublished }}
<input type="submit" name="action" class="btn btn-primary mt-2" value="Update"> <input type="submit" name="action" class="btn btn-primary mt-2" value="Update">

View file

@ -28,12 +28,9 @@
<div class="mb-3 d-flex align-items-center flex-wrap gap-1"> <div class="mb-3 d-flex align-items-center flex-wrap gap-1">
{{ if eq $p.State 1 }} {{ if eq $p.State 1 }}
<span class="text-muted">{{ $.user.FormatTime $p.UpdatedAt }}</span> <span class="ms-3 badge text-primary-emphasis bg-primary-subtle border border-primary-subtle">Draft</span> <span class="text-muted post-date">{{ $.user.FormatTime $p.UpdatedAt }}</span> <span class="ms-3 badge text-primary-emphasis bg-primary-subtle border border-primary-subtle">Draft</span>
{{ else }} {{ else }}
<span class="text-muted">{{ $.user.FormatTime $p.PublishedAt }}</span> <span class="text-muted post-date">{{ $.user.FormatTime $p.PublishedAt }}</span>
{{ end }}
{{ range $p.Categories }}
<span class="ms-1 badge bg-secondary-subtle text-secondary-emphasis border border-secondary-subtle">{{ .Name }}</span>
{{ end }} {{ end }}
</div> </div>