Initial implementation
This commit is contained in:
14
internal/models/diary.go
Normal file
14
internal/models/diary.go
Normal 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
37
internal/models/event.go
Normal 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
30
internal/models/photo.go
Normal 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
104
internal/models/timeline.go
Normal 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),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user