diff --git a/assets/diary/diary-day.html b/assets/diary/diary-day.html
index 7c069c6..42a5bd6 100644
--- a/assets/diary/diary-day.html
+++ b/assets/diary/diary-day.html
@@ -1,7 +1,7 @@
{{if .Photos}}
{{range .Photos}}
-

+

{{end}}
{{end}}
diff --git a/assets/diary/diary-month.html b/assets/diary/diary-month.html
index 74f5475..bc3ef0e 100644
--- a/assets/diary/diary-month.html
+++ b/assets/diary/diary-month.html
@@ -7,7 +7,7 @@
{{if .Photos}}
{{range .Photos}}
-

+

{{end}}
{{end}}
diff --git a/assets/diary/diary-year.html b/assets/diary/diary-year.html
index f7b609b..6ea8ab5 100644
--- a/assets/diary/diary-year.html
+++ b/assets/diary/diary-year.html
@@ -1,4 +1,4 @@
-Months
+Monate
{{range .Months}}
{{.Name}}
@@ -6,7 +6,7 @@
{{if .Photos}}
{{range .Photos}}
-

+

{{end}}
{{end}}
diff --git a/assets/icons/thumb-placeholder.svg b/assets/icons/thumb-placeholder.svg
new file mode 100644
index 0000000..7364d89
--- /dev/null
+++ b/assets/icons/thumb-placeholder.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/style.css b/assets/style.css
index 462c8cf..65f5530 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -374,6 +374,7 @@ textarea {
height: 140px;
object-fit: cover;
display: block;
+ background: var(--bg-panel) url("/_/icons/thumb-placeholder.svg") center/2rem no-repeat;
}
/* === Empty state === */
diff --git a/diary.go b/diary.go
index 85f348a..7c69cf2 100644
--- a/diary.go
+++ b/diary.go
@@ -401,20 +401,36 @@ func renderDiaryYear(fsPath, urlPath string) template.HTML {
photos := yearPhotos(fsPath, urlPath)
- entries, err := os.ReadDir(fsPath)
- if err != nil {
- return ""
- }
-
- var months []diaryMonthSummary
+ // Collect month numbers from both subdirectories and photo filenames so
+ // years that contain only photos (no diary entries) still list months.
+ monthSet := map[int]bool{}
+ monthDirs := map[int]string{}
+ entries, _ := os.ReadDir(fsPath)
for _, e := range entries {
if !e.IsDir() {
continue
}
- monthNum, err := strconv.Atoi(e.Name())
- if err != nil || monthNum < 1 || monthNum > 12 {
+ n, err := strconv.Atoi(e.Name())
+ if err != nil || n < 1 || n > 12 {
continue
}
+ monthSet[n] = true
+ monthDirs[n] = e.Name()
+ }
+ for _, p := range photos {
+ if p.Date.Year() == year {
+ monthSet[int(p.Date.Month())] = true
+ }
+ }
+
+ monthNums := make([]int, 0, len(monthSet))
+ for m := range monthSet {
+ monthNums = append(monthNums, m)
+ }
+ sort.Ints(monthNums)
+
+ var months []diaryMonthSummary
+ for _, monthNum := range monthNums {
var monthPhotos []diaryPhoto
for _, p := range photos {
if p.Date.Year() == year && int(p.Date.Month()) == monthNum {
@@ -422,10 +438,14 @@ func renderDiaryYear(fsPath, urlPath string) template.HTML {
}
}
monthDate := time.Date(year, time.Month(monthNum), 1, 0, 0, 0, 0, time.UTC)
+ dirName, ok := monthDirs[monthNum]
+ if !ok {
+ dirName = fmt.Sprintf("%02d", monthNum)
+ }
months = append(months, diaryMonthSummary{
ID: monthDate.Format("2006-01"),
Name: fmt.Sprintf("%s %d", germanMonths[monthDate.Month()], year),
- URL: path.Join(urlPath, e.Name()) + "/",
+ URL: path.Join(urlPath, dirName) + "/",
Photos: monthPhotos,
})
}