diff --git a/internal/category/category_test.go b/internal/category/category_test.go index 5dba354..9cfea1c 100644 --- a/internal/category/category_test.go +++ b/internal/category/category_test.go @@ -14,8 +14,10 @@ import ( func mockHandler(response string, statusCode int) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(statusCode) - if _, err := fmt.Fprintln(w, response); err != nil { - panic(err) + if statusCode != http.StatusNoContent { + if _, err := fmt.Fprintln(w, response); err != nil { + panic(err) + } } } } @@ -42,7 +44,7 @@ func TestFetchData(t *testing.T) { panic(err) } case "/v1/feeds/1/icon": - if _, err := fmt.Fprintln(w, `{"data": "icon-data", "mime_type": "image/png"}`); err != nil { + if _, err := fmt.Fprintln(w, `{"data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHElEQVQ4T2Nksr/85wADGGYw4oBMAHkAAAD//wMA/wEAP2D3e/gAAAAASUVORK5CYII=", "mime_type": "image/png"}`); err != nil { panic(err) } } @@ -73,8 +75,8 @@ func TestFetchData(t *testing.T) { t.Errorf("Expected 1 feed icon, got %d", len(data.FeedIcons)) } - if data.FeedIcons[0].Data != "icon-data" { - t.Errorf("Expected feed icon data 'icon-data', got %s", data.FeedIcons[0].Data) + if data.FeedIcons[0].Data != "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHElEQVQ4T2Nksr/85wADGGYw4oBMAHkAAAD//wMA/wEAP2D3e/gAAAAASUVORK5CYII=" { + t.Errorf("Expected feed icon data 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHElEQVQ4T2Nksr/85wADGGYw4oBMAHkAAAD//wMA/wEAP2D3e/gAAAAASUVORK5CYII=', got %s", data.FeedIcons[0].Data) } } @@ -94,7 +96,7 @@ func TestStreamData(t *testing.T) { panic(err) } case "/v1/feeds/1/icon": - if _, err := fmt.Fprintln(w, `{"data": "icon-data", "mime_type": "image/png"}`); err != nil { + if _, err := fmt.Fprintln(w, `{"data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAHElEQVQ4T2Nksr/85wADGGYw4oBMAHkAAAD//wMA/wEAP2D3e/gAAAAASUVORK5CYII=", "mime_type": "image/png"}`); err != nil { panic(err) } } diff --git a/internal/templates/entries.gohtml b/internal/templates/entries.gohtml index 30ef8e6..6669bac 100644 --- a/internal/templates/entries.gohtml +++ b/internal/templates/entries.gohtml @@ -42,7 +42,7 @@ section.entry { background-color: #f9fafb; border-radius: 0.5rem; - padding: 0.5rem; + padding: 0; margin-bottom: 1rem; border: 1px solid #e5e7eb; } @@ -55,7 +55,7 @@ summary.entry { font-size: 1.25rem; font-weight: 600; - margin-bottom: 0.5rem; + padding: 0.5rem; cursor: pointer; color: #1d4ed8; text-decoration: none; @@ -86,6 +86,23 @@ gap: 0.25rem; align-items: center; justify-content: start; + border-top: 1px solid #e5e7eb; + } + + .entry-meta-tab { + padding: 0.25rem 0.5rem; + border-right: 1px solid #e5e7eb; + display: flex; + } + + .entry-meta-tab-feed { + display: flex; + align-items: center; + gap: 0.25rem; + } + + .entry-meta-tab:last-child { + border-right: none; } .entry-content { @@ -125,14 +142,25 @@ background-color: rgba(59, 130, 246, 0.1); } + details.entry { + } + details.entry h1 { font-size: 1.5rem; margin-top: 1rem; margin-bottom: 0.5rem; } + details summary { + cursor: pointer; + } + + details summary > * { + display: inline; + } + {{range .FeedIcons}} - div.feed-icon-{{.FeedID}} { + div.feed-icon-{{.FeedID}} { background-image: url("data:{{.Data}}"); background-size: contain; width: 16px; @@ -162,21 +190,22 @@
-
-
- external | + -
+ + + -
- | -
-
- | {{.Date.Format "Jan 2"}} +
@@ -226,7 +255,7 @@ document.addEventListener('click', (event) => { - if (event.target.matches('button[data-button-mark]')) { + if (event.target.matches('a[data-button-mark]')) { const entry = event.target.closest('section.entry'); const index = entries.indexOf(entry); diff --git a/internal/testutil/images/green.png b/internal/testutil/images/green.png new file mode 100644 index 0000000..b3b3f74 Binary files /dev/null and b/internal/testutil/images/green.png differ diff --git a/internal/testutil/images/red.png b/internal/testutil/images/red.png new file mode 100644 index 0000000..d9e0a9e Binary files /dev/null and b/internal/testutil/images/red.png differ diff --git a/internal/testutil/images/yellow.png b/internal/testutil/images/yellow.png new file mode 100644 index 0000000..1e8d08e Binary files /dev/null and b/internal/testutil/images/yellow.png differ diff --git a/internal/testutil/mock_data.go b/internal/testutil/mock_data.go index a61c2dd..8091d6f 100644 --- a/internal/testutil/mock_data.go +++ b/internal/testutil/mock_data.go @@ -1,13 +1,29 @@ package testutil import ( + "encoding/base64" + "io/ioutil" + "log" "miniflux-digest/internal/category" "time" miniflux "miniflux.app/v2/client" ) +func loadImageAsBase64(path string) string { + file, err := ioutil.ReadFile(path) + if err != nil { + log.Fatalf("Failed to read image file: %v", err) + } + + return base64.StdEncoding.EncodeToString(file) +} + func NewMockCategoryData() *category.CategoryData { + redSquare := loadImageAsBase64("internal/testutil/images/red.png") + yellowSquare := loadImageAsBase64("internal/testutil/images/yellow.png") + greenSquare := loadImageAsBase64("internal/testutil/images/green.png") + return &category.CategoryData{ Category: &miniflux.Category{ ID: 1, @@ -15,26 +31,27 @@ func NewMockCategoryData() *category.CategoryData { }, Entries: &miniflux.Entries{ { - ID: 1, - UserID: 1, - FeedID: 1, - Status: miniflux.EntryStatusUnread, - Hash: "test-hash-1", - Title: "A Short and Sweet Title", - URL: "https://example.com/1", + ID: 1, + UserID: 1, + FeedID: 1, + Status: miniflux.EntryStatusUnread, + Hash: "test-hash-1", + Title: "A Short and Sweet Title", + URL: "https://example.com/1", CommentsURL: "https://example.com/1/comments", - Date: time.Now().Add(-1 * time.Hour), + Date: time.Now().Add(-1 * time.Hour), CreatedAt: time.Now().Add(-2 * time.Hour), Content: "This is a short and sweet entry.", - Author: "Test Author 1", + Author: "Test Author 1", ShareCode: "test-share-code-1", Starred: true, ReadingTime: 1, - Enclosures: []*miniflux.Enclosure{{URL: "https://example.com/image.jpg", MimeType: "image/jpeg"}}, - Feed: &miniflux.Feed{ID: 1, Title: "Test Feed 1"}, + Enclosures: []*miniflux.Enclosure{{URL: "https://example.com/image.jpg", MimeType: "image/jpeg"}}, + Feed: &miniflux.Feed{ID: 1, Title: "Test Feed 1"}, }, { - ID: 2, + ID: 2, + FeedID: 2, Title: "A Longer Entry with a Paragraph of Text", URL: "https://example.com/2", Date: time.Now().Add(-3 * time.Hour), @@ -43,7 +60,8 @@ func NewMockCategoryData() *category.CategoryData { Feed: &miniflux.Feed{ID: 2, Title: "Test Feed 2"}, }, { - ID: 3, + ID: 3, + FeedID: 3, Title: "An Entry with HTML Content", URL: "https://example.com/3", Date: time.Now().Add(-4 * time.Hour), @@ -52,5 +70,10 @@ func NewMockCategoryData() *category.CategoryData { }, }, GeneratedDate: time.Date(2025, 7, 21, 12, 0, 0, 0, time.UTC), + FeedIcons: []*category.FeedIcon{ + {FeedID: 1, Data: "image/png;base64," + redSquare}, + {FeedID: 2, Data: "image/png;base64," + yellowSquare}, + {FeedID: 3, Data: "image/png;base64," + greenSquare}, + }, } } \ No newline at end of file diff --git a/scripts/preview/main.go b/scripts/preview/main.go index 53bb71e..5395b2e 100644 --- a/scripts/preview/main.go +++ b/scripts/preview/main.go @@ -26,4 +26,4 @@ func main() { } log.Println("Successfully generated web/preview.html") -} +} \ No newline at end of file