package main import ( "fmt" "os" "strings" "git.akyoto.dev/go/markdown" "git.akyoto.dev/go/web" "git.akyoto.dev/go/web/send" ) type App struct { html string posts map[string]string } func (app *App) Init() { app.html = mustLoadClean("public/app.html") css := mustLoadClean("public/app.css") app.html = strings.Replace(app.html, "{head}", fmt.Sprintf("{head}", css), 1) app.posts = loadPosts("posts") } func (app *App) Run() { s := web.NewServer() s.Use(func(ctx web.Context) error { defer func() { err := recover() if err != nil { fmt.Println("Recovered panic:", err) } }() return ctx.Next() }) s.Use(func(ctx web.Context) error { path := ctx.Request().Path() if len(path) > 1 && strings.HasSuffix(path, "/") { return ctx.Redirect(301, strings.TrimSuffix(path, "/")) } return ctx.Next() }) render := func(ctx web.Context, head string, body string) error { html := app.html html = strings.Replace(html, "{head}", head, 1) html = strings.Replace(html, "{body}", body, 1) return send.HTML(ctx, html) } s.Get("/", func(ctx web.Context) error { return render(ctx, "akyoto.dev", markdown.Render("# Frontpage")) }) s.Get("/:post", func(ctx web.Context) error { post := ctx.Request().Param("post") return render(ctx, "akyoto.dev", app.posts[post]) }) s.Run(":8080") } func mustLoadClean(path string) string { data := mustLoad(path) data = strings.ReplaceAll(data, "\t", "") data = strings.ReplaceAll(data, "\n", "") return data } func mustLoad(path string) string { dataBytes, err := os.ReadFile(path) if err != nil { panic(err) } return string(dataBytes) } func loadPosts(directory string) map[string]string { entries, err := os.ReadDir(directory) if err != nil { panic(err) } posts := map[string]string{} for _, entry := range entries { fileName := entry.Name() if !strings.HasSuffix(fileName, ".md") { continue } baseName := strings.TrimSuffix(fileName, ".md") content := mustLoad("posts/" + fileName) if strings.HasPrefix(content, "---\n") { end := strings.Index(content[4:], "---\n") + 4 content = content[end+4:] } posts[baseName] = markdown.Render(content) } return posts }