fix: break import cycle by moving Layout to shared package and fix import paths
This commit is contained in:
@@ -9,10 +9,11 @@ import (
|
||||
"mal/web/components"
|
||||
watchlistcomponents "mal/web/components/watchlist"
|
||||
"mal/web/shared"
|
||||
"mal/web/shared/layout"
|
||||
)
|
||||
|
||||
templ AnimeDetails(anime jikan.Anime, currentStatus string, nextEpisode int) {
|
||||
@Layout("mal - " + anime.DisplayTitle(), true) {
|
||||
@layout.Layout("mal - " + anime.DisplayTitle(), true) {
|
||||
<div class="grid items-start gap-5 xl:grid-cols-[minmax(0,1fr)_300px]">
|
||||
<div class="grid min-w-0 gap-8">
|
||||
<div class="grid gap-5 lg:grid-cols-[220px_minmax(0,1fr)]">
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package templates
|
||||
|
||||
import "mal/web/shared/layout"
|
||||
|
||||
templ Login(formError string, username string) {
|
||||
@Layout("Login", false) {
|
||||
@layout.Layout("Login", false) {
|
||||
<div class="w-full max-w-xl">
|
||||
<div class="mx-auto w-full bg-(--panel) p-6">
|
||||
<h2 class="m-0 text-2xl">Sign in</h2>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package templates
|
||||
|
||||
import "mal/internal/jikan"
|
||||
import "mal/internal/shared/ui"
|
||||
import "mal/integrations/jikan"
|
||||
import "mal/web/components"
|
||||
import "fmt"
|
||||
import "mal/web/shared/layout"
|
||||
|
||||
templ Catalog() {
|
||||
@Layout("mal - catalog", true) {
|
||||
@layout.Layout("mal - catalog", true) {
|
||||
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3 md:gap-4 lg:grid-cols-4 xl:grid-cols-5" id="catalog-content">
|
||||
<div class="col-span-full" hx-get="/api/catalog?page=1" hx-trigger="load" hx-swap="outerHTML">
|
||||
@ui.LoadingIndicator("Loading catalog")
|
||||
|
||||
@@ -2,12 +2,13 @@ package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mal/internal/database"
|
||||
"mal/internal/shared/ui"
|
||||
"mal/internal/db"
|
||||
"mal/web/components"
|
||||
"mal/web/shared/layout"
|
||||
)
|
||||
|
||||
templ ContinueWatching(entries []database.GetContinueWatchingEntriesRow) {
|
||||
@Layout("mal - continue watching", true) {
|
||||
templ ContinueWatching(entries []db.GetContinueWatchingEntriesRow) {
|
||||
@layout.Layout("mal - continue watching", true) {
|
||||
<div class="grid gap-4">
|
||||
<h1>Continue watching</h1>
|
||||
<p class="m-0 text-sm text-(--text-muted)">Pick up where you left off.</p>
|
||||
@@ -53,7 +54,7 @@ templ ContinueWatching(entries []database.GetContinueWatchingEntriesRow) {
|
||||
}
|
||||
}
|
||||
|
||||
func continueWatchingURL(entry database.GetContinueWatchingEntriesRow) string {
|
||||
func continueWatchingURL(entry db.GetContinueWatchingEntriesRow) string {
|
||||
episode := 1
|
||||
if entry.CurrentEpisode.Valid && entry.CurrentEpisode.Int64 > 0 {
|
||||
episode = int(entry.CurrentEpisode.Int64)
|
||||
@@ -62,6 +63,6 @@ func continueWatchingURL(entry database.GetContinueWatchingEntriesRow) string {
|
||||
return fmt.Sprintf("/watch/%d/%d", entry.AnimeID, episode)
|
||||
}
|
||||
|
||||
func displayContinueWatchingTitle(entry database.GetContinueWatchingEntriesRow) string {
|
||||
return database.DisplayTitle(entry.TitleEnglish, entry.TitleJapanese, entry.TitleOriginal)
|
||||
func displayContinueWatchingTitle(entry db.GetContinueWatchingEntriesRow) string {
|
||||
return db.DisplayTitle(entry.TitleEnglish, entry.TitleJapanese, entry.TitleOriginal)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package templates
|
||||
|
||||
import "mal/internal/jikan"
|
||||
import "mal/internal/shared/ui"
|
||||
import "mal/integrations/jikan"
|
||||
import "mal/web/components"
|
||||
import "fmt"
|
||||
import "mal/web/shared/layout"
|
||||
|
||||
templ Discover() {
|
||||
@Layout("mal - discover", true) {
|
||||
@layout.Layout("mal - discover", true) {
|
||||
<div class="grid gap-4">
|
||||
<div class="grid gap-4">
|
||||
<h1>Discover</h1>
|
||||
|
||||
@@ -2,13 +2,14 @@ package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mal/internal/jikan"
|
||||
"mal/internal/shared/ui"
|
||||
"mal/integrations/jikan"
|
||||
"mal/web/components"
|
||||
"mal/web/shared/layout"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
templ Search(q string) {
|
||||
@Layout("mal - search", true) {
|
||||
@layout.Layout("mal - search", true) {
|
||||
if q != "" {
|
||||
<div id="loading" class="hidden htmx-request:inline-flex">
|
||||
@ui.LoadingIndicator("Searching...")
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package templates
|
||||
|
||||
import "mal/web/components/icons"
|
||||
|
||||
templ Layout(title string, showHeader bool) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>{ title }</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg"/>
|
||||
<link rel="stylesheet" href="/dist/tailwind.css"/>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
|
||||
<script src="/dist/discover.js" defer></script>
|
||||
<script src="/dist/anime.js" defer></script>
|
||||
<script src="/dist/timezone.js" defer></script>
|
||||
<script src="/dist/player.js" defer></script>
|
||||
</head>
|
||||
<body
|
||||
class="min-h-screen bg-(--bg) text-(--text) font-(--font) text-sm leading-normal"
|
||||
>
|
||||
if showHeader {
|
||||
<header class="sticky top-0 z-100 bg-(--header)">
|
||||
<div
|
||||
class="mx-auto flex w-full max-w-screen-2xl items-center gap-4 px-4 py-3 max-lg:flex-wrap max-lg:gap-3"
|
||||
>
|
||||
<div
|
||||
class="flex min-w-0 items-center gap-5 max-lg:w-full max-lg:flex-wrap max-lg:gap-3"
|
||||
data-search-root
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="inline-flex items-center text-(--accent)"
|
||||
aria-label="mal logo"
|
||||
>
|
||||
@icons.LogoIcon("h-7 w-7")
|
||||
</a>
|
||||
<div class="flex flex-wrap gap-3 text-sm max-lg:w-full max-lg:gap-2">
|
||||
<a
|
||||
class="text-(--text-muted) no-underline hover:text-(--text) hover:no-underline"
|
||||
href="/discover"
|
||||
>
|
||||
Discover
|
||||
</a>
|
||||
<a
|
||||
class="text-(--text-muted) no-underline hover:text-(--text) hover:no-underline"
|
||||
href="/continue-watching"
|
||||
>
|
||||
Continue watching
|
||||
</a>
|
||||
<a
|
||||
class="text-(--text-muted) no-underline hover:text-(--text) hover:no-underline"
|
||||
href="/watchlist"
|
||||
>
|
||||
Watchlist
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="relative ml-auto min-w-60 w-full max-w-md max-lg:ml-0"
|
||||
data-search-root
|
||||
>
|
||||
<form action="/search" method="GET" class="w-full" id="search-form">
|
||||
<input
|
||||
type="text"
|
||||
id="search-input"
|
||||
name="q"
|
||||
class="h-9 w-full border border-transparent bg-(--surface-search) px-3 text-(--text) transition-colors duration-120 placeholder:text-(--text-faint) focus:border-(--surface-search-focus-border) focus:outline-none"
|
||||
placeholder="Search anime..."
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div
|
||||
id="search-dropdown"
|
||||
class="absolute inset-x-0 top-full mt-0.5 z-50 max-h-screen overflow-y-auto bg-(--panel)"
|
||||
data-search-results-container
|
||||
></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
}
|
||||
<main class={
|
||||
"mx-auto w-full max-w-screen-2xl px-4 pt-5 pb-8 max-lg:px-3 max-lg:pb-6",
|
||||
templ.KV("flex min-h-screen items-center justify-center px-4 py-0", !showHeader),
|
||||
}>
|
||||
{ children... }
|
||||
</main>
|
||||
<script src="/dist/search.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package templates
|
||||
|
||||
import "mal/web/shared/layout"
|
||||
|
||||
templ NotFoundPage() {
|
||||
@Layout("mal - not found", false) {
|
||||
@layout.Layout("mal - not found", false) {
|
||||
<section class="w-full max-w-3xl min-h-dvh mx-auto grid content-center justify-items-center gap-3 px-7 py-8 text-center">
|
||||
<p class="m-0 text-6xl leading-none tracking-wider text-(--text-muted) sm:text-7xl md:text-8xl lg:text-9xl">404</p>
|
||||
<h1 class="m-0 text-3xl sm:text-4xl md:text-5xl">Page not found</h1>
|
||||
|
||||
@@ -6,10 +6,11 @@ import (
|
||||
"mal/integrations/jikan"
|
||||
"mal/web/components"
|
||||
"mal/web/shared"
|
||||
"mal/web/shared/layout"
|
||||
)
|
||||
|
||||
templ StudioDetails(producer jikan.ProducerResponse, animes []jikan.Anime, hasNext bool, nextPage int) {
|
||||
@Layout("mal - "+shared.GetProducerName(producer), true) {
|
||||
@layout.Layout("mal - "+shared.GetProducerName(producer), true) {
|
||||
<div class="grid gap-5">
|
||||
<div class="grid gap-4 bg-(--panel) p-4">
|
||||
<div class="flex items-start gap-4">
|
||||
|
||||
@@ -9,10 +9,11 @@ import (
|
||||
"mal/web/components/watch"
|
||||
"mal/web/components/watchlist"
|
||||
"mal/web/shared"
|
||||
"mal/web/shared/layout"
|
||||
)
|
||||
|
||||
templ WatchPage(anime jikan.Anime, data shared.WatchPageData) {
|
||||
@Layout(fmt.Sprintf("%s - episode %s", anime.DisplayTitle(), data.CurrentEpisode), true) {
|
||||
@layout.Layout(fmt.Sprintf("%s - episode %s", anime.DisplayTitle(), data.CurrentEpisode), true) {
|
||||
<div class="w-full overflow-x-clip">
|
||||
<div class="mx-auto grid w-full gap-4 lg:gap-5 lg:grid-cols-[220px_minmax(0,1fr)_250px] xl:grid-cols-[240px_minmax(0,1fr)_280px]">
|
||||
<!-- Left sidebar: Episodes -->
|
||||
|
||||
@@ -7,16 +7,17 @@ import (
|
||||
"mal/web/components"
|
||||
"mal/web/components/watchlist"
|
||||
"mal/web/shared"
|
||||
"mal/web/shared/layout"
|
||||
)
|
||||
|
||||
templ Watchlist(
|
||||
entries []db.GetUserWatchListRow,
|
||||
layout string,
|
||||
viewLayout string,
|
||||
currentStatus string,
|
||||
sortBy string,
|
||||
sortOrder string,
|
||||
) {
|
||||
@Layout("mal - watchlist", true) {
|
||||
@layout.Layout("mal - watchlist", true) {
|
||||
<div
|
||||
class="mb-4 flex items-end justify-between gap-4 max-lg:flex-col max-lg:items-start"
|
||||
>
|
||||
@@ -60,14 +61,14 @@ templ Watchlist(
|
||||
class="flex flex-wrap gap-2 max-md:flex-nowrap max-md:overflow-x-auto max-md:pb-1"
|
||||
>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL("grid", currentStatus, sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(layout == "grid") }
|
||||
>
|
||||
Grid
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL("table", currentStatus, sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(layout == "table") }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "all", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(viewLayout == "grid") }
|
||||
>
|
||||
Grid
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "table", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(viewLayout == "table") }
|
||||
>
|
||||
Table
|
||||
</a>
|
||||
@@ -78,48 +79,48 @@ templ Watchlist(
|
||||
class="mb-3 flex flex-wrap gap-2 max-md:flex-nowrap max-md:overflow-x-auto max-md:pb-1"
|
||||
>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(layout, "all", sortBy, sortOrder)) }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "all", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(currentStatus == "all") }
|
||||
>
|
||||
All
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(layout, "watching", sortBy, sortOrder)) }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "watching", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(currentStatus == "watching") }
|
||||
>
|
||||
Watching
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(layout, "on_hold", sortBy, sortOrder)) }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "on_hold", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(currentStatus == "on_hold") }
|
||||
>
|
||||
On hold
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(layout, "plan_to_watch", sortBy, sortOrder)) }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "plan_to_watch", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(currentStatus == "plan_to_watch") }
|
||||
>
|
||||
Plan to watch
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(layout, "dropped", sortBy, sortOrder)) }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "dropped", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(currentStatus == "dropped") }
|
||||
>
|
||||
Dropped
|
||||
</a>
|
||||
<a
|
||||
href={ templ.URL(shared.WatchlistURL(layout, "completed", sortBy, sortOrder)) }
|
||||
href={ templ.URL(shared.WatchlistURL(viewLayout, "completed", sortBy, sortOrder)) }
|
||||
class={ shared.TabClass(currentStatus == "completed") }
|
||||
>
|
||||
Completed
|
||||
</a>
|
||||
</div>
|
||||
@components.SortFilter(components.SortFilterOptions{
|
||||
Sort: sortBy,
|
||||
Order: sortOrder,
|
||||
View: layout,
|
||||
Status: currentStatus,
|
||||
})
|
||||
@components.SortFilter(components.SortFilterOptions{
|
||||
Sort: sortBy,
|
||||
Order: sortOrder,
|
||||
View: viewLayout,
|
||||
Status: currentStatus,
|
||||
})
|
||||
if len(entries) == 0 {
|
||||
@components.EmptyState("Nothing here yet") {
|
||||
if currentStatus == "all" {
|
||||
@@ -129,7 +130,7 @@ templ Watchlist(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if layout == "grid" {
|
||||
if viewLayout == "grid" {
|
||||
<div
|
||||
class="grid grid-cols-2 gap-3 sm:grid-cols-3 md:gap-4 lg:grid-cols-4 xl:grid-cols-5"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user