diff --git a/cmd/blog/main.go b/cmd/blog/main.go index 0167ed5..074cd16 100644 --- a/cmd/blog/main.go +++ b/cmd/blog/main.go @@ -74,7 +74,7 @@ func main() { http.NotFound(w, r) return } - if err := tplList.ExecuteTemplate(w, "base", articles); err != nil { + if err := tplList.ExecuteTemplate(w, "layout", articles); err != nil { http.Error(w, err.Error(), 500) } }) @@ -83,7 +83,7 @@ func main() { slug := strings.TrimPrefix(r.URL.Path, "/post/") for _, a := range articles { if a.Slug == slug { - if err := tplArticle.ExecuteTemplate(w, "base", a); err != nil { + if err := tplArticle.ExecuteTemplate(w, "layout", a); err != nil { http.Error(w, err.Error(), 500) } return diff --git a/content/2025/demo.md b/content/2025/demo.md new file mode 100644 index 0000000..8e958d9 --- /dev/null +++ b/content/2025/demo.md @@ -0,0 +1,3 @@ + +# Hello Gophers 🤖 +*(Markdown‑Inhalt)* diff --git a/content/2025/test.md b/content/2025/test.md index 6d23997..b1e657a 100644 --- a/content/2025/test.md +++ b/content/2025/test.md @@ -1,4 +1,4 @@ - + # Hello Markdown 🌟 diff --git a/internal/article/load.go b/internal/article/load.go index f4a24d5..e091171 100644 --- a/internal/article/load.go +++ b/internal/article/load.go @@ -26,7 +26,6 @@ func LoadDir(root string) ([]Article, error) { // gültige Extension‑Maske exts := parser.CommonExtensions | parser.AutoHeadingIDs | parser.DefinitionLists - mdParser := parser.NewWithExtensions(exts) mdRenderer := html.NewRenderer(html.RendererOptions{ Flags: html.CommonFlags | html.HrefTargetBlank, }) @@ -57,6 +56,7 @@ func LoadDir(root string) ([]Article, error) { Title string `json:"title"` Date string `json:"date"` Slug string `json:"slug"` + Cover string `json:"cover"` // NEW } clean := strings.TrimSpace(string(headerLine)) @@ -80,14 +80,19 @@ func LoadDir(root string) ([]Article, error) { htmlBody := bodyBytes if ext == ".md" { + mdParser := parser.NewWithExtensions(exts) htmlBody = md.ToHTML(bodyBytes, mdParser, mdRenderer) } - date, _ := time.Parse("2006-01-02", meta.Date) + date, err := time.Parse("2006-01-02", meta.Date) + if err != nil { + fmt.Println("Time", err, date) + } out = append(out, Article{ Title: meta.Title, Slug: meta.Slug, Date: date, + Cover: meta.Cover, // NEW Body: template.HTML(htmlBody), }) return nil diff --git a/internal/article/model.go b/internal/article/model.go index b11a434..fe00b45 100644 --- a/internal/article/model.go +++ b/internal/article/model.go @@ -10,5 +10,6 @@ type Article struct { Title string Slug string Date time.Time + Cover string //  NEW Body template.HTML // already trusted } diff --git a/internal/web/static/img/#placeholder.png b/internal/web/static/img/#placeholder.png new file mode 100644 index 0000000..e39d5fd Binary files /dev/null and b/internal/web/static/img/#placeholder.png differ diff --git a/internal/web/static/img/placeholder.png b/internal/web/static/img/placeholder.png new file mode 100644 index 0000000..443948a Binary files /dev/null and b/internal/web/static/img/placeholder.png differ diff --git a/internal/web/static/main.css b/internal/web/static/main.css new file mode 100644 index 0000000..77c00e8 --- /dev/null +++ b/internal/web/static/main.css @@ -0,0 +1,133 @@ +/* ---------- Farbpalette (Feel‑free to tune) ---------- */ +:root { + --bg: #0d1117; + --bg‑alt: #161b22; + --text: #c9d1d9; + --text‑muted: #8b949e; + --accent: #3b82f6; /* Blau */ + --accent‑light:#60a5fa; + --code‑bg: #1e242c; + --code‑border: #30363d; + --radius: 0.6rem; + --gap: 1.5rem; + font‑size: 16px; + font‑family: system‑ui, "Segoe UI", Roboto, sans‑serif; + color‑scheme: dark; + } + + /* ---------- Globale Elemente ---------- */ + * { box‑sizing: border‑box; } + body { + margin: 0; + background: var(--bg); + color: var(--text); + line‑height: 1.6; + } + a { + color: var(--accent); + text‑decoration: none; + } + a:hover { text‑decoration: underline; } + + /* ---------- Layout ---------- */ + .wrapper { + max‑width: 768px; + margin: 0 auto; + padding: var(--gap); + } + header, footer { + display: flex; + align‑items: center; + justify‑content: space-between; + background: var(--bg‑alt); + padding: 1rem var(--gap); + border‑bottom: 1px solid var(--code‑border); + } + header h1 { + margin: 0; + font‑size: 1.4rem; + letter‑spacing: 0.5px; + } + header a { color: var(--text); } + + footer { + border‑top: 1px solid var(--code‑border); + font‑size: 0.9rem; + color: var(--text‑muted); + } + + /* ---------- Artikelliste ---------- */ + .post‑list li { + margin: 0; + padding: 1rem 0; + border‑bottom: 1px solid var(--code‑border); + } + .post‑list li:last‑child { border‑bottom: none; } + .post‑list time { color: var(--text‑muted); font‑size: 0.9rem; } + + /* ---------- Einzelartikel ---------- */ + article h1 { margin‑top: 0; font‑size: 2rem; } + article time { color: var(--text‑muted); font‑size: 0.9rem; } + article img, article video { + max‑width: 100%; height: auto; border‑radius: var(--radius); + } + article pre, article code { + font‑family: "Fira Code", Consolas, monospace; + } + article pre { + background: var(--code‑bg); + border: 1px solid var(--code‑border); + padding: 1rem; + border‑radius: var(--radius); + overflow: auto; + } + article blockquote { + margin: 1rem 0; + padding: 0.5rem 1rem; + border‑left: 4px solid var(--accent‑light); + background: var(--bg‑alt); + color: var(--text‑muted); + } + /* ---------- Karten‑Layout für Artikelliste ---------- */ +.card { + display: grid; + grid-template-columns: 160px 1fr; + gap: 1rem; + padding: 1rem; + border: 1px solid var(--code-border); + border-radius: var(--radius); + background: var(--bg-alt); + transition: transform .15s ease, border-color .15s ease; +} +.card:hover { + transform: translateY(-4px); + border-color: var(--accent); +} +.card img { + width: 160px; + height: 100px; + object-fit: cover; + border-radius: var(--radius); +} +.card h2 { + margin: 0 0 .4rem; + font-size: 1.2rem; +} +.card time { color: var(--text-muted); font-size: .9rem; } + +/* ---------- Hero‑Bild im Artikel ---------- */ +.hero { + width: 100%; + max-height: 340px; + object-fit: cover; + border-radius: var(--radius); + margin-bottom: 1rem; +} + + + /* ---------- Responsive ---------- */ + @media (max‑width: 600px) { + :root { font‑size: 15px; } + header, footer { flex‑direction: column; gap: 0.5rem; } + } + \ No newline at end of file diff --git a/internal/web/templates/article.html b/internal/web/templates/article.html index b0834e2..386a251 100644 --- a/internal/web/templates/article.html +++ b/internal/web/templates/article.html @@ -1,20 +1,20 @@ -{{ define "article" }} - {{ template "base.html" . }} -{{ end }} - -{{ define "title" }}{{ .Title }} – B1tsblog{{ end }} +{{ define "title" }}{{ .Title }} – B1tsblog{{ end }} {{ define "body" }} -
-
-

{{ .Title }}

- -
+
+ {{ if .Cover }} + + {{ end }} + +

{{ .Title }}

+
{{ .Body }}
-

← Alle Artikel

+

← Zurück zur Übersicht

{{ end }} + +{{ define "article" }}{{ template "layout" . }}{{ end }} diff --git a/internal/web/templates/base.html b/internal/web/templates/base.html index 3188e7e..f4c2b4f 100644 --- a/internal/web/templates/base.html +++ b/internal/web/templates/base.html @@ -1,15 +1,30 @@ - - - - - {{ block "title" . }}B1tsblog{{ end }} - - - - - - -

B1tsblog

-
{{ block "body" . }}{{ end }}
- - +{{ define "layout" }} + + + + + + {{ block "title" . }}B1tsblog{{ end }} + + + + + + +
+

B1tsblog

+ +
+ +
+ {{ template "body" . }} +
+ + + + +{{ end }} \ No newline at end of file diff --git a/internal/web/templates/list.html b/internal/web/templates/list.html index 18417d5..c6cd59d 100644 --- a/internal/web/templates/list.html +++ b/internal/web/templates/list.html @@ -1,16 +1,23 @@ -{{ define "list" }} {{/* ‑‑ ausführbarer Entry‑Point */}} - {{ template "base.html" . }} {{/* ruft das Layout auf */}} -{{ end }} - {{ define "title" }}Alle Artikel{{ end }} {{ define "body" }} -