Initial implementation

This commit is contained in:
2025-12-10 11:10:52 +01:00
parent cff9defc4a
commit 4cb97a25ba
26 changed files with 2714 additions and 1 deletions

14
internal/models/diary.go Normal file
View File

@@ -0,0 +1,14 @@
package models
import "time"
// DiaryEntry represents a journal entry for a specific day.
type DiaryEntry struct {
Date time.Time
Text string
}
// DateString returns the date formatted as YYYY-MM-DD.
func (d *DiaryEntry) DateString() string {
return d.Date.Format("2006-01-02")
}

37
internal/models/event.go Normal file
View File

@@ -0,0 +1,37 @@
// Package models defines the core data structures for the application.
package models
import "time"
// Event represents a calendar event.
type Event struct {
ID string
Title string
Description string
Start time.Time
End time.Time
AllDay bool
Location string
Source EventSource
}
// EventSource indicates where an event originated from.
type EventSource string
const (
SourceLocal EventSource = "local"
SourceCalDAV EventSource = "caldav"
)
// IsOnDate checks if the event occurs on the given date.
func (e *Event) IsOnDate(date time.Time) bool {
eventDate := e.Start.Truncate(24 * time.Hour)
checkDate := date.Truncate(24 * time.Hour)
if e.AllDay {
endDate := e.End.Truncate(24 * time.Hour)
return !checkDate.Before(eventDate) && checkDate.Before(endDate)
}
return eventDate.Equal(checkDate)
}

30
internal/models/photo.go Normal file
View File

@@ -0,0 +1,30 @@
package models
import (
"path/filepath"
"time"
)
// Photo represents a photo with its metadata.
type Photo struct {
Date time.Time
Year string
Filename string
Description string
FullPath string
}
// DateString returns the date formatted as YYYY-MM-DD.
func (p *Photo) DateString() string {
return p.Date.Format("2006-01-02")
}
// URLPath returns the URL path to access this photo.
func (p *Photo) URLPath() string {
return filepath.Join("/photos", p.Year, p.Filename)
}
// ThumbURLPath returns the URL path to access this photo's thumbnail.
func (p *Photo) ThumbURLPath() string {
return filepath.Join("/photos/thumb", p.Year, p.Filename)
}

104
internal/models/timeline.go Normal file
View File

@@ -0,0 +1,104 @@
package models
import (
"sort"
"time"
)
// TimelineEntry represents any item that can appear in the timeline.
type TimelineEntry struct {
Date time.Time
Type EntryType
Event *Event
Diary *DiaryEntry
Photo *Photo
}
// EntryType indicates what kind of entry this is.
type EntryType string
const (
EntryTypeEvent EntryType = "event"
EntryTypeDiary EntryType = "diary"
EntryTypePhoto EntryType = "photo"
)
// DayContent aggregates all content for a specific day.
type DayContent struct {
Date time.Time
Events []*Event
Diary *DiaryEntry
Photos []*Photo
}
// HasContent returns true if there is any content for this day.
func (d *DayContent) HasContent() bool {
return len(d.Events) > 0 || d.Diary != nil || len(d.Photos) > 0
}
// HasEvents returns true if there are events on this day.
func (d *DayContent) HasEvents() bool {
return len(d.Events) > 0
}
// HasDiary returns true if there is a diary entry for this day.
func (d *DayContent) HasDiary() bool {
return d.Diary != nil
}
// HasPhotos returns true if there are photos for this day.
func (d *DayContent) HasPhotos() bool {
return len(d.Photos) > 0
}
// ToTimelineEntries converts day content to a sorted slice of timeline entries.
func (d *DayContent) ToTimelineEntries() []TimelineEntry {
var entries []TimelineEntry
for _, event := range d.Events {
entries = append(entries, TimelineEntry{
Date: event.Start,
Type: EntryTypeEvent,
Event: event,
})
}
if d.Diary != nil {
entries = append(entries, TimelineEntry{
Date: d.Diary.Date,
Type: EntryTypeDiary,
Diary: d.Diary,
})
}
for _, photo := range d.Photos {
entries = append(entries, TimelineEntry{
Date: photo.Date,
Type: EntryTypePhoto,
Photo: photo,
})
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].Date.Before(entries[j].Date)
})
return entries
}
// MonthData holds all data for a specific month.
type MonthData struct {
Year int
Month time.Month
Days map[int]*DayContent
}
// GetDay returns the day content for a specific day number.
func (m *MonthData) GetDay(day int) *DayContent {
if content, ok := m.Days[day]; ok {
return content
}
return &DayContent{
Date: time.Date(m.Year, m.Month, day, 0, 0, 0, 0, time.Local),
}
}