updates
This commit is contained in:
parent
056b8918d3
commit
d0a8d8d969
BIN
public/banner.jpg
Normal file
BIN
public/banner.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 126 KiB |
@ -6,6 +6,7 @@ pub const Blog = jetquery.Model(
|
||||
struct {
|
||||
id: i32,
|
||||
title: []const u8,
|
||||
blob: []const u8,
|
||||
content: ?[]const u8,
|
||||
created_at: jetquery.DateTime,
|
||||
updated_at: jetquery.DateTime,
|
||||
|
@ -9,6 +9,7 @@ pub fn up(repo: anytype) !void {
|
||||
t.primaryKey("id", .{}),
|
||||
t.column("title", .string, .{}),
|
||||
t.column("content", .text, .{ .optional = true }),
|
||||
t.column("blob", .text, .{}),
|
||||
t.timestamps(.{}),
|
||||
},
|
||||
.{},
|
||||
|
72
src/app/rss.zig
Normal file
72
src/app/rss.zig
Normal file
@ -0,0 +1,72 @@
|
||||
const std = @import("std");
|
||||
const jetzig = @import("jetzig");
|
||||
|
||||
const RssItem = struct {
|
||||
id: i32,
|
||||
title: []const u8,
|
||||
blob: []const u8,
|
||||
content: []const u8,
|
||||
created_at: jetzig.jetquery.DateTime,
|
||||
updated_at: jetzig.jetquery.DateTime,
|
||||
};
|
||||
|
||||
fn generateRss(items: []const RssItem, allocator: std.mem.Allocator) ![]u8 {
|
||||
var list = std.ArrayList(u8).init(allocator);
|
||||
const writer = list.writer();
|
||||
|
||||
try writer.print(
|
||||
\\<?xml version="1.0" encoding="UTF-8"?>
|
||||
\\<rss version="2.0">
|
||||
\\<channel>
|
||||
\\<title>yuzucchii.xyz</title>
|
||||
\\<link>yuzucchii.xyz</link>
|
||||
\\<description>Personal blog of Yuzu with all kinds of different articles</description>
|
||||
, .{});
|
||||
|
||||
for (items) |item| {
|
||||
try writer.print(
|
||||
\\<item>
|
||||
\\<title>{s}</title>
|
||||
\\<link>yuzucchii.xyz/blogs/{d}</link>
|
||||
\\<description>{s}</description>
|
||||
, .{ item.title, item.id, item.blob });
|
||||
|
||||
try item.created_at.strftime(writer, "<pubDate>Day, DD Mon YYYY HH:MM:SS GMT</pubDate>");
|
||||
|
||||
try writer.print(
|
||||
\\</item>
|
||||
, .{});
|
||||
}
|
||||
|
||||
try writer.writeAll("</channel></rss>");
|
||||
return list.toOwnedSlice();
|
||||
}
|
||||
|
||||
|
||||
// we'll send xml instead
|
||||
pub fn index(request: *jetzig.Request) !void {
|
||||
try request.headers.append("Content-Type", "application/rss+xml");
|
||||
|
||||
const query = jetzig.database.Query(.Blog).orderBy(.{.created_at = .desc});
|
||||
|
||||
const blogs = try request.repo.all(query);
|
||||
|
||||
var items: std.ArrayList(RssItem) = .init(request.allocator);
|
||||
|
||||
for (blogs) |blog| {
|
||||
try items.append(RssItem{
|
||||
.id = blog.id,
|
||||
.title = blog.title,
|
||||
.blob = blog.blob,
|
||||
.content = blog.content orelse "<empty>",
|
||||
.created_at = blog.created_at,
|
||||
.updated_at = blog.updated_at,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: wait until jetzig adds xml support
|
||||
_ = try generateRss(try items.toOwnedSlice(), request.allocator);
|
||||
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
@ -153,7 +153,15 @@ pub fn post(request: *jetzig.Request) !jetzig.View {
|
||||
return request.fail(.unprocessable_entity);
|
||||
};
|
||||
|
||||
try request.repo.insert(.Blog, .{ .title = title, .content = content });
|
||||
const preview = params.getT(.string, "preview") orelse {
|
||||
return request.fail(.unprocessable_entity);
|
||||
};
|
||||
|
||||
try request.repo.insert(.Blog, .{
|
||||
.title = title,
|
||||
.blob = preview,
|
||||
.content = content,
|
||||
});
|
||||
|
||||
return request.redirect("/blogs", .moved_permanently);
|
||||
} else {
|
||||
|
@ -1,6 +1,24 @@
|
||||
@args allowed: bool
|
||||
<div>
|
||||
@for (.blogs) |blog| {
|
||||
@if ($.allowed)
|
||||
<button id="delete-post">
|
||||
Delete post
|
||||
</button>
|
||||
<script>
|
||||
document.getElementById('delete-post').addEventListener('click', function () {
|
||||
fetch(`/blogs/${blog.id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during logout:', error);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@end
|
||||
<a href="/blogs/{{blog.id}}">{{blog.title}}</a>
|
||||
{{zmpl.fmt.datetime(blog.get("created_at"), "%Y-%m-%d %H:%M")}}
|
||||
<br/>
|
||||
|
@ -1,11 +1,12 @@
|
||||
<div>
|
||||
<form action="/blogs" method="POST">
|
||||
{{context.authenticityFormElement()}}
|
||||
<label>Title</label>
|
||||
<input name="title" />
|
||||
|
||||
<label>Content</label>
|
||||
<textarea name="content"></textarea>
|
||||
|
||||
<label>Preview</label>
|
||||
<textarea name="preview"></textarea>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</div>
|
||||
|
@ -61,6 +61,10 @@ pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
|
||||
try root.put("allowed", allowed);
|
||||
|
||||
try root.put("bsky_link", "empty for now");
|
||||
try root.put("discord_link", "https://discord.gg/pvraBkepUP");
|
||||
try root.put("codeberg_link", "https://codeberg.org/yuzu");
|
||||
|
||||
try root.put("message_param", params.get("message"));
|
||||
|
||||
// Set arbitrary response headers as required. `content-type` is automatically assigned for
|
||||
|
@ -1,4 +1,8 @@
|
||||
@args title: []const u8
|
||||
@args title: []const u8, id: i32, blob: []const u8
|
||||
<div class="mb-4">
|
||||
<h2 class="text-2xl font-semibold mb-2">{{title}}</h2>
|
||||
<div class="text-gray-700">
|
||||
{{blob}}
|
||||
</div>
|
||||
<a href="/blogs/{{id}}" class="text-blue-600 underline">Read more</a>
|
||||
</div>
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
<body>
|
||||
<div class="mx-auto max-w-3xl mt-sm">
|
||||
<br/>
|
||||
<h1 class="text-3xl font-bold mb-4">Hello, I like doing things.</h1>
|
||||
<p class="text-lg mb-6">I created this website using Jetzig in order to store things I do.</p>
|
||||
|
||||
<div class="mb-8">
|
||||
<a href="/blogs" class="text-blue-500 hover:underline">Blog</a>
|
||||
@ -21,10 +21,11 @@
|
||||
@else
|
||||
<a href="/login" class="text-blue-500 hover:underline ml-4">Login</a>
|
||||
@end
|
||||
<a href="#" class="text-blue-500 hover:underline ml-4">Gitea instance</a>
|
||||
<a href="#" class="text-blue-500 hover:underline ml-4">IRC</a>
|
||||
<a href="#" class="text-blue-500 hover:underline ml-4">Tor url</a>
|
||||
<a href="#" class="text-blue-500 hover:underline ml-4">RSS feed</a>
|
||||
<a href="git.yuzucchii.xyz" class="text-blue-500 hover:underline ml-4">Gitea instance</a>
|
||||
<a href="chat.yuzucchii.xyz" class="text-blue-500 hover:underline ml-4">IRC</a>
|
||||
<a href="/rss" class="text-blue-500 hover:underline ml-4">RSS feed</a>
|
||||
<a href="searx.yuzucchii.xyz" class="text-blue-500 hover:underline ml-4">SearX</a>
|
||||
<a href="yuzucchii.xyz/files" class="text-blue-500 hover:underline ml-4">Files</a>
|
||||
<a href="mailto:me@yuzucchii.xyz" class="text-blue-500 hover:underline ml-4">E-mail</a>
|
||||
<button
|
||||
id="copy-button"
|
||||
@ -49,11 +50,34 @@
|
||||
</noscript>
|
||||
|
||||
</div>
|
||||
<!-- Banner Image -->
|
||||
<div class="mb-6">
|
||||
<img src="/banner.jpg" alt="Banner" class="w-full rounded-xl shadow-md">
|
||||
</div>
|
||||
<p class="text-lg mb-6">I created this website in order to store things I do, but don't be scared of the simple layout, this website is featureful and full of things to do, please enjoy your visit.</p>
|
||||
|
||||
@for (.articles) |article| {
|
||||
@partial root/article_blob(title: article.title, blob: article.content)
|
||||
@partial root/article_blob(title: article.title, blob: article.content, id: article.id)
|
||||
}
|
||||
</div>
|
||||
<footer class="mt-12 border-t pt-6 text-center text-sm text-gray-600">
|
||||
<div class="max-w-xl mx-auto px-4">
|
||||
<div class="bg-yellow-100 text-yellow-800 border border-yellow-200 rounded-md px-4 py-3 mb-6">
|
||||
<p class="text-sm md:text-base">
|
||||
This website is not reliant on JavaScript, and all scripts are optional and publicly available.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center flex-wrap gap-4 mb-4 text-blue-500">
|
||||
<a href="{{.bsky_link}}" class="hover:underline" target="_blank" rel="noopener">Bluesky</a>
|
||||
<a href="{{.discord_link}}" class="hover:underline" target="_blank" rel="noopener">Discord</a>
|
||||
<a href="{{.codeberg_link}}" class="hover:underline" target="_blank" rel="noopener">Codeberg</a>
|
||||
<a href="https://yuzucchii.xyz" class="hover:underline" target="_blank" rel="noopener">yuzucchii.xyz</a>
|
||||
</div>
|
||||
|
||||
<p class="text-xs text-gray-500">© 2025 yuzucchii.xyz</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
|
@ -215,8 +215,6 @@ pub const jetzig_options = struct {
|
||||
|
||||
pub fn init(app: *jetzig.App) !void {
|
||||
_ = app;
|
||||
// Example custom route:
|
||||
// app.route(.GET, "/custom/:id/foo/bar", @import("app/views/custom/foo.zig"), .bar);
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
Loading…
x
Reference in New Issue
Block a user