Typstify /calendar endpoint

This commit is contained in:
Joscha 2025-03-01 22:21:45 +01:00
parent 42f0885b43
commit 5f2dcf81d3
8 changed files with 93 additions and 126 deletions

View file

@ -1,5 +1,6 @@
use showbits_typst::Typst; use showbits_typst::Typst;
pub mod calendar;
pub mod cells; pub mod cells;
pub mod egg; pub mod egg;
pub mod image; pub mod image;

View file

@ -0,0 +1,5 @@
{
"year": 2025,
"month": 3,
"feed": false
}

View file

@ -0,0 +1 @@
../lib

View file

@ -0,0 +1,36 @@
#import "@preview/oxifmt:0.2.1": strfmt
#import "lib/main.typ" as lib;
#show: it => lib.init(it)
#let data = json("data.json")
#let date = datetime(year: data.year, month: data.month, day: 1)
#let month_length = 32 - (date + duration(days: 31)).day()
#let head(name) = text(size: 32pt, name)
#let empty = box()
#let day(n) = box(
width: 100%,
height: 100%,
stroke: 2pt + black,
strfmt("{:02}", n),
)
#align(center + horizon)[
#set par(spacing: 8pt)
Ankreuzkalender #strfmt("{:04}-{:02}", date.year(), date.month())
#grid(
columns: (50pt,) * 7,
rows: 50pt,
gutter: 4pt,
head[Mo], head[Di], head[Mi], head[Do], head[Fr], head[Sa], head[So],
..for _ in range(date.weekday() - 1) { (empty,) },
..for i in range(month_length) { (day(i + 1),) },
)
]
#if data.feed {
lib.feed
}

View file

@ -0,0 +1,43 @@
use axum::{Form, extract::State};
use jiff::Zoned;
use serde::{Deserialize, Serialize};
use crate::{
drawer::{Command, NewTypstDrawing},
server::{Server, somehow},
};
#[derive(Serialize)]
struct Data {
year: i16,
month: i8,
feed: bool,
}
#[derive(Deserialize)]
pub struct FormData {
pub year: Option<i16>,
pub month: Option<i8>,
pub feed: Option<bool>,
}
pub async fn post(server: State<Server>, Form(form): Form<FormData>) -> somehow::Result<()> {
let date = Zoned::now().date();
let data = Data {
year: form.year.unwrap_or(date.year()),
month: form.month.unwrap_or(date.month()),
feed: form.feed.unwrap_or(true),
};
let typst = super::typst_with_lib()
.with_json("/data.json", &data)
.with_main_file(include_str!("main.typ"));
let _ = server
.tx
.send(Command::draw(NewTypstDrawing::new(typst)))
.await;
Ok(())
}

View file

@ -1,5 +1,4 @@
mod backlog; mod backlog;
mod calendar;
mod chat_message; mod chat_message;
mod new_typst; mod new_typst;
mod photo; mod photo;
@ -12,9 +11,8 @@ use tokio::sync::mpsc;
use crate::persistent_printer::PersistentPrinter; use crate::persistent_printer::PersistentPrinter;
pub use self::{ pub use self::{
backlog::BacklogDrawing, calendar::CalendarDrawing, chat_message::ChatMessageDrawing, backlog::BacklogDrawing, chat_message::ChatMessageDrawing, new_typst::NewTypstDrawing,
new_typst::NewTypstDrawing, photo::PhotoDrawing, tictactoe::TicTacToeDrawing, photo::PhotoDrawing, tictactoe::TicTacToeDrawing, typst::TypstDrawing,
typst::TypstDrawing,
}; };
pub const FEED: f32 = 96.0; pub const FEED: f32 = 96.0;

View file

@ -1,100 +0,0 @@
use jiff::civil;
use showbits_common::{
Node, Tree, WidgetExt,
color::{BLACK, WHITE},
widgets::{Block, Text},
};
use taffy::{
AlignContent, AlignItems, Display, FlexDirection,
style_helpers::{length, percent, repeat},
};
use crate::persistent_printer::PersistentPrinter;
use super::{Context, Drawing, FEED};
pub struct CalendarDrawing {
pub year: i16,
pub month: i8,
}
impl Drawing for CalendarDrawing {
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
let mut date = civil::Date::new(self.year, self.month, 1)?;
let mut tree = Tree::<Context>::new(WHITE);
let mut grid = Node::empty()
.with_display(Display::Grid)
.with_grid_template_columns(vec![repeat(7, vec![length(50.0)])])
.with_grid_auto_rows(vec![length(50.0)])
.with_gap(length(2.0));
for weekday in ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"] {
let text = Text::new()
.with_metrics(Text::default_metrics().scale(2.0))
.and_plain(weekday)
.widget(&mut ctx.font_stuff)
.node()
.with_justify_self(Some(AlignItems::Center))
.with_align_self(Some(AlignItems::Center))
.register(&mut tree)?;
grid = grid.and_child(text);
}
let placeholders = date.weekday().to_monday_zero_offset();
for _ in 0..placeholders {
let empty = Node::empty().register(&mut tree)?;
grid = grid.and_child(empty);
}
loop {
let day = Text::new()
.and_plain(date.day().to_string())
.widget(&mut ctx.font_stuff)
.node()
.register(&mut tree)?;
let block = Block::new()
.with_border(BLACK)
.node()
.with_border(length(2.0))
.with_display(Display::Flex)
.with_justify_content(Some(AlignContent::Center))
.with_align_items(Some(AlignItems::Center))
.and_child(day)
.register(&mut tree)?;
grid = grid.and_child(block);
let next_day = date.tomorrow()?;
if date.month() != next_day.month() {
break;
}
date = next_day;
}
let title = Text::new()
.and_plain(format!(
"Ankreuzkalender {:04}-{:02}",
self.year, self.month
))
.widget(&mut ctx.font_stuff)
.node()
.register(&mut tree)?;
let root = Node::empty()
.with_size_width(percent(1.0))
.with_padding_bottom(length(FEED))
.with_display(Display::Flex)
.with_flex_direction(FlexDirection::Column)
.with_align_items(Some(AlignItems::Center))
.and_child(title)
.and_child(grid.register(&mut tree)?)
.register(&mut tree)?;
printer.print_tree(&mut tree, ctx, root)?;
Ok(())
}
}

View file

@ -14,9 +14,7 @@ use tokio::{net::TcpListener, sync::mpsc};
use crate::{ use crate::{
documents, documents,
drawer::{ drawer::{ChatMessageDrawing, Command, PhotoDrawing, TicTacToeDrawing, TypstDrawing},
CalendarDrawing, ChatMessageDrawing, Command, PhotoDrawing, TicTacToeDrawing, TypstDrawing,
},
}; };
use self::{r#static::get_static_file, statuscode::status_code}; use self::{r#static::get_static_file, statuscode::status_code};
@ -28,7 +26,10 @@ pub struct Server {
pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()> { pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()> {
let app = Router::new() let app = Router::new()
.route("/calendar", post(post_calendar)) .route(
"/calendar",
post(documents::calendar::post).fallback(get_static_file),
)
.route( .route(
"/cells", "/cells",
post(documents::cells::post).fallback(get_static_file), post(documents::cells::post).fallback(get_static_file),
@ -55,24 +56,6 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
Ok(()) Ok(())
} }
// /calendar
#[derive(Deserialize)]
struct PostCalendarForm {
year: i16,
month: i8,
}
async fn post_calendar(server: State<Server>, request: Form<PostCalendarForm>) {
let _ = server
.tx
.send(Command::draw(CalendarDrawing {
year: request.0.year,
month: request.0.month,
}))
.await;
}
// /chat_message // /chat_message
#[derive(Deserialize)] #[derive(Deserialize)]