From 0a5f64c60499763ff75a6e5b27c5038f5d2a5cdb Mon Sep 17 00:00:00 2001 From: mkelvers Date: Wed, 15 Apr 2026 00:07:56 +0200 Subject: [PATCH] refactor: migrate templates to tailwind utilities --- internal/shared/ui/anime_card.templ | 22 +- internal/shared/ui/anime_list.templ | 6 +- internal/shared/ui/empty_state.templ | 6 +- internal/shared/ui/loading.templ | 8 +- internal/shared/ui/sort_filter.templ | 16 +- internal/templates/anime.templ | 184 ++-- internal/templates/auth.templ | 192 ++-- internal/templates/catalog.templ | 10 +- internal/templates/discovery.templ | 16 +- internal/templates/index.templ | 4 +- internal/templates/layout.templ | 38 +- internal/templates/not_found.templ | 8 +- internal/templates/notifications.templ | 72 +- internal/templates/watchlist.templ | 69 +- static/css/style.css | 1285 ------------------------ static/js/anime.js | 10 + static/js/anime.ts | 10 + static/js/discover.js | 10 +- static/js/discover.ts | 10 +- static/js/search.js | 2 +- static/js/search.ts | 2 +- static/js/timezone.js | 4 +- static/js/timezone.ts | 4 +- 23 files changed, 374 insertions(+), 1614 deletions(-) diff --git a/internal/shared/ui/anime_card.templ b/internal/shared/ui/anime_card.templ index dfaf847..993449c 100644 --- a/internal/shared/ui/anime_card.templ +++ b/internal/shared/ui/anime_card.templ @@ -15,37 +15,37 @@ type AnimeCardProps struct { templ AnimeCard(props AnimeCardProps) { if props.CurrentNode { -
+
if props.ImageURL != "" { - { + { } else { -
No image
+
No image
} -
+
{ props.Title }
{ children... }
} else { - + if props.Class == "notification-card" || props.Class == "schedule-card" { -
+
if props.ImageURL != "" { - { + { } else { -
No image
+
No image
}
} else { if props.ImageURL != "" { - { + { } else { -
No image
+
No image
} } if props.Class != "notification-card" && props.Class != "schedule-card" { -
+
{ props.Title }
} diff --git a/internal/shared/ui/anime_list.templ b/internal/shared/ui/anime_list.templ index 6f8d4c9..8d86bd2 100644 --- a/internal/shared/ui/anime_list.templ +++ b/internal/shared/ui/anime_list.templ @@ -7,12 +7,12 @@ import ( templ InfiniteAnimeList(animes []jikan.Anime, hasNext bool, nextURL string, containerID string) { for _, anime := range animes { -
+
@CatalogItem(anime)
} if hasNext { -
+
} @@ -18,32 +17,35 @@ templ Layout(title string, showHeader bool) { - + if showHeader { -
-
-
-
} -
+
{ children... }
diff --git a/internal/templates/not_found.templ b/internal/templates/not_found.templ index 8eb548f..5375d18 100644 --- a/internal/templates/not_found.templ +++ b/internal/templates/not_found.templ @@ -2,11 +2,11 @@ package templates templ NotFoundPage() { @Layout("mal - not found", false) { -
-

404

+
+

404

Page not found

-

The page you requested does not exist, or it was moved.

-

Back to catalog

+

The page you requested does not exist, or it was moved.

+

Back to catalog

} } diff --git a/internal/templates/notifications.templ b/internal/templates/notifications.templ index 6f0de80..a65a033 100644 --- a/internal/templates/notifications.templ +++ b/internal/templates/notifications.templ @@ -13,11 +13,11 @@ type WatchingAnimeWithDetails struct { templ Notifications(watching []WatchingAnimeWithDetails, activeTab string) { @Layout("mal - notifications", true) { -
+

Notifications

-
- Tracking - Sequels + if activeTab == "sequels" { @@ -25,13 +25,13 @@ templ Notifications(watching []WatchingAnimeWithDetails, activeTab string) { @ui.LoadingIndicator("Syncing sequel graphs...")
} else { -

Shows you're currently watching or planning to watch.

+

Shows you're currently watching or planning to watch.

if len(watching) == 0 { @ui.EmptyState("No airing anime in your watching list.") { - Add currently airing shows to your watching list to see upcoming episodes here. + Add currently airing shows to your watching list to see upcoming episodes here. } } else { -
+
for _, item := range watching { @NotificationCard(item) } @@ -56,7 +56,7 @@ func splitUpcomingSeasons(items []database.GetUpcomingSeasonsRow) (airing []data templ UpcomingSeasonsList(upcomingSeasons []database.GetUpcomingSeasonsRow) { if len(upcomingSeasons) == 0 { @ui.EmptyState("No upcoming seasons for anime you've watched.") { - As you watch more shows, new seasons will appear here. + As you watch more shows, new seasons will appear here. } } else { @renderSplitSeasons(upcomingSeasons) @@ -66,10 +66,10 @@ templ UpcomingSeasonsList(upcomingSeasons []database.GetUpcomingSeasonsRow) { templ renderSplitSeasons(upcomingSeasons []database.GetUpcomingSeasonsRow) { if airing, upcoming := splitUpcomingSeasons(upcomingSeasons); true { if len(airing) > 0 { -
-

Airing now

-

These are the currently airing anime, but you're not tracking any of these.

-
+
+

Airing now

+

These are the currently airing anime, but you're not tracking any of these.

+
for _, item := range airing { @UpcomingSeasonCard(item) } @@ -78,10 +78,10 @@ templ renderSplitSeasons(upcomingSeasons []database.GetUpcomingSeasonsRow) { } if len(upcoming) > 0 { -
-

Announced & upcoming

-

Newly announced or upcoming seasons related to anime you've watched.

-
+
+

Announced & upcoming

+

Newly announced or upcoming seasons related to anime you've watched.

+
for _, item := range upcoming { @UpcomingSeasonCard(item) } @@ -96,19 +96,19 @@ templ UpcomingSeasonCard(item database.GetUpcomingSeasonsRow) { ID: int(item.ID), Title: displaySeasonTitle(item), ImageURL: item.ImageUrl, - Class: "notification-card", - ImgClass: "notification-image", + Class: "notification-card min-w-0 flex flex-col bg-transparent text-inherit no-underline", + ImgClass: "flex aspect-[2/3] max-h-[var(--poster-max-height)] w-full items-end justify-center overflow-hidden", }) { -
-
+
+
{ displaySeasonTitle(item) }
-
+
if item.Status.Valid { - { seasonStatusLabel(item.Status.String) } + { seasonStatusLabel(item.Status.String) } } if strings.TrimSpace(item.PrequelTitle) != "" { - { fmt.Sprintf("Sequel to %s", item.PrequelTitle) } + { fmt.Sprintf("Sequel to %s", item.PrequelTitle) } }
@@ -124,20 +124,20 @@ templ NotificationCard(item WatchingAnimeWithDetails) { ID: int(item.Entry.AnimeID), Title: displayTitle(item.Entry), ImageURL: item.Entry.ImageUrl, - Class: "notification-card", - ImgClass: "notification-image", + Class: "notification-card min-w-0 flex flex-col bg-transparent text-inherit no-underline", + ImgClass: "flex aspect-[2/3] max-h-[var(--poster-max-height)] w-full items-end justify-center overflow-hidden", }) { -
-
+
+
{ displayTitle(item.Entry) }
-
+
if item.Anime.Broadcast.String != "" { - { item.Anime.Broadcast.String } - Calculating next episode time... + { item.Anime.Broadcast.String } + Calculating next episode time... } if item.Anime.Episodes > 0 { - + if item.Entry.CurrentEpisode.Valid { { fmt.Sprintf("%d / %d eps", item.Entry.CurrentEpisode.Int64, item.Anime.Episodes) } } else { @@ -145,7 +145,7 @@ templ NotificationCard(item WatchingAnimeWithDetails) { } } else if item.Entry.CurrentEpisode.Valid && item.Entry.CurrentEpisode.Int64 > 0 { - + { fmt.Sprintf("%d eps watched", item.Entry.CurrentEpisode.Int64) } } @@ -174,3 +174,11 @@ func seasonStatusLabel(status string) string { return statusText } + +func statusTabClass(active bool) string { + base := "shrink-0 whitespace-nowrap bg-[var(--panel-soft)] px-[0.45rem] py-[0.24rem] text-[0.76rem] text-[var(--text-muted)] no-underline hover:bg-[var(--surface-tab-hover)] hover:text-[var(--text)] hover:no-underline" + if active { + return "shrink-0 whitespace-nowrap bg-[var(--surface-tab-active)] px-[0.45rem] py-[0.24rem] text-[0.76rem] text-[var(--accent)] no-underline hover:no-underline" + } + return base +} diff --git a/internal/templates/watchlist.templ b/internal/templates/watchlist.templ index fa30217..7910d17 100644 --- a/internal/templates/watchlist.templ +++ b/internal/templates/watchlist.templ @@ -8,31 +8,31 @@ import ( templ Watchlist(entries []database.GetUserWatchListRow, layout string, currentStatus string, sortBy string, sortOrder string) { @Layout("My Watchlist", true) { -
-
+
+

Watchlist

-

Track what you're watching with less noise.

+

Track what you're watching with less noise.

-
- Export - - -
- All - Watching - Continuing - On hold - Plan to watch - Dropped - Completed + @ui.SortFilter(ui.SortFilterOptions{Sort: sortBy, Order: sortOrder, View: layout, Status: currentStatus}) if len(entries) == 0 { @@ -47,16 +47,16 @@ templ Watchlist(entries []database.GetUserWatchListRow, layout string, currentSt } } else { if layout == "grid" { -
+
for _, entry := range entries { -
+
@ui.AnimeCard(ui.AnimeCardProps{ ID: int(entry.AnimeID), Title: entry.DisplayTitle(), ImageURL: entry.ImageUrl, })