diff --git a/projects/client/i18n/meta/en.json b/projects/client/i18n/meta/en.json index 29aa170b20..d81daa9c00 100644 --- a/projects/client/i18n/meta/en.json +++ b/projects/client/i18n/meta/en.json @@ -6963,6 +6963,75 @@ } } }, + "list_summary_range_up_to": { + "default": "Up to {value}", + "description": "Smart list filter summary for an upper-bound-only range, e.g. 'Up to 90'.", + "variables": { + "value": { + "type": "string" + } + } + }, + "list_summary_range_labeled_up_to": { + "default": "{label} up to {value}", + "description": "Smart list filter summary for a labeled upper-bound-only range, e.g. 'Trakt up to 80%'.", + "variables": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "list_summary_range_between": { + "default": "{min} to {max}", + "description": "Smart list filter summary for a range with both bounds, e.g. '60 to 80'.", + "variables": { + "min": { + "type": "string" + }, + "max": { + "type": "string" + } + } + }, + "list_summary_range_labeled_between": { + "default": "{label} {min} to {max}", + "description": "Smart list filter summary for a labeled range with both bounds, e.g. 'Trakt 60% to 80%'.", + "variables": { + "label": { + "type": "string" + }, + "min": { + "type": "string" + }, + "max": { + "type": "string" + } + } + }, + "list_summary_range_from": { + "default": "{value} and up", + "description": "Smart list filter summary for a lower-bound-only range, e.g. '60 and up'.", + "variables": { + "value": { + "type": "string" + } + } + }, + "list_summary_range_labeled_from": { + "default": "{label} {value} and up", + "description": "Smart list filter summary for a labeled lower-bound-only range, e.g. 'Trakt 60% and up'.", + "variables": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "warning_smart_lists_limit": { "default": "You've reached your smart list limit", "description": "Warning text shown when a user has reached their smart list limit and attempts to create a new smart list." diff --git a/projects/client/src/lib/sections/lists/components/ListSummaryCard.svelte b/projects/client/src/lib/sections/lists/components/ListSummaryCard.svelte new file mode 100644 index 0000000000..89c46a2de2 --- /dev/null +++ b/projects/client/src/lib/sections/lists/components/ListSummaryCard.svelte @@ -0,0 +1,61 @@ + + + +
+ {@render children()} +
+
+ + diff --git a/projects/client/src/lib/sections/lists/components/list-summary/ListSummaryItem.svelte b/projects/client/src/lib/sections/lists/components/list-summary/ListSummaryItem.svelte index 8667ac6af6..b613cdbf53 100644 --- a/projects/client/src/lib/sections/lists/components/list-summary/ListSummaryItem.svelte +++ b/projects/client/src/lib/sections/lists/components/list-summary/ListSummaryItem.svelte @@ -1,7 +1,7 @@ - -
- - -
-
- - + + + + diff --git a/projects/client/src/lib/sections/lists/smart/SmartLists.svelte b/projects/client/src/lib/sections/lists/smart/SmartLists.svelte index 2e3b778d4b..7f7bf1e9b3 100644 --- a/projects/client/src/lib/sections/lists/smart/SmartLists.svelte +++ b/projects/client/src/lib/sections/lists/smart/SmartLists.svelte @@ -1,24 +1,22 @@ @@ -26,38 +24,26 @@ {/snippet} -{#if $list.length === 0} - - {#snippet item(_)}{/snippet} - {#snippet empty()} - - {/snippet} - -{:else} -
- - {#snippet icon()} - - {/snippet} - - - -
-{/if} + + {#snippet item(list)} + + {/snippet} - + {#snippet empty()} + {#if !$isLoading} + + {/if} + {/snippet} + diff --git a/projects/client/src/lib/sections/lists/smart/_internal/SmartListSummaryItem.svelte b/projects/client/src/lib/sections/lists/smart/_internal/SmartListSummaryItem.svelte new file mode 100644 index 0000000000..e7737e6410 --- /dev/null +++ b/projects/client/src/lib/sections/lists/smart/_internal/SmartListSummaryItem.svelte @@ -0,0 +1,294 @@ + + + +
+ + +
+ +

{list.title}

+ +

+ {filterSummary} +

+
+ + +
+ + +
+ {#each $posters as poster, index (`${list.id}_poster_${index}`)} +
+ +
+ {/each} +
+ +
+ + diff --git a/projects/client/src/lib/sections/lists/smart/_internal/useSmartListPreview.ts b/projects/client/src/lib/sections/lists/smart/_internal/useSmartListPreview.ts new file mode 100644 index 0000000000..296734e31c --- /dev/null +++ b/projects/client/src/lib/sections/lists/smart/_internal/useSmartListPreview.ts @@ -0,0 +1,48 @@ +import { map, of } from 'rxjs'; +import type { SmartList } from '$lib/requests/queries/users/smartListQuery.ts'; +import { useAnticipatedList } from '../../anticipated/useAnticipatedList.ts'; +import { usePopularList } from '../../popular/usePopularList.ts'; +import { useTrendingList } from '../../trending/useTrendingList.ts'; + +const previewLimit = 8; + +function smartListToPreviewQuery(list: SmartList) { + const params = { + limit: previewLimit, + search: list.params, + type: list.type, + }; + + switch (list.target) { + case 'trending': + return useTrendingList(params); + case 'popular': + return usePopularList(params); + case 'anticipated': + return useAnticipatedList(params); + case 'unknown': + return undefined; + } +} + +export function useSmartListPreview(list: SmartList) { + const query = smartListToPreviewQuery(list); + + if (!query) { + return { + isLoading: of(false), + posters: of([]), + }; + } + + return { + isLoading: query.isLoading, + posters: query.list.pipe( + map((items) => + items + .map((item) => item.poster.url.thumb) + .slice(0, previewLimit) + ), + ), + }; +} diff --git a/projects/client/src/lib/sections/lists/user/PersonalLists.svelte b/projects/client/src/lib/sections/lists/user/PersonalLists.svelte index dccec18d0e..c3f52494d2 100644 --- a/projects/client/src/lib/sections/lists/user/PersonalLists.svelte +++ b/projects/client/src/lib/sections/lists/user/PersonalLists.svelte @@ -19,12 +19,19 @@ import UserList from "./UserList.svelte"; const previewLimit = 3; + type PersonalListsDisplay = "auto" | "compact"; const { type, slug, mode, - }: { type: PersonalListType; slug: string; mode?: DiscoverMode } = $props(); + display = "auto", + }: { + type: PersonalListType; + slug: string; + mode?: DiscoverMode; + display?: PersonalListsDisplay; + } = $props(); const { list: lists, @@ -35,13 +42,20 @@ const { isMe } = $derived(useIsMe(slug)); const variant = $derived.by(() => { + if (display === "compact") { + return "summary"; + } + const shouldShowSummary = $hasNextPage || $lists.length === 0 || $lists.length > previewLimit; return shouldShowSummary ? "summary" : "preview"; }); const isMine = $derived(type === "personal" && $isMe); - const isPresentable = $derived(isMine || (!$isLoading && $lists.length > 0)); + const isPresentable = $derived( + (display === "compact" ? $isMe : isMine) || + (!$isLoading && $lists.length > 0), + ); const title = $derived.by(() => { switch (type) { @@ -111,6 +125,7 @@ href: UrlBuilder.lists.all(slug, type), label: m.button_label_view_all_lists(), source: { id: "personal-lists", type }, + mode: "always", }} --height-list="var(--height-lists-list)" --height-override-list={$lists.length === 0 @@ -148,6 +163,6 @@ .trakt-lists-preview { display: flex; flex-direction: column; - gap: var(--gap-micro); + gap: var(--content-gap); } diff --git a/projects/client/src/routes/users/[user]/lists/+page.svelte b/projects/client/src/routes/users/[user]/lists/+page.svelte index 15d25f17e4..0c41a8406e 100644 --- a/projects/client/src/routes/users/[user]/lists/+page.svelte +++ b/projects/client/src/routes/users/[user]/lists/+page.svelte @@ -9,6 +9,7 @@ import TraktPageCoverSetter from "$lib/sections/layout/TraktPageCoverSetter.svelte"; import SmartLists from "$lib/sections/lists/smart/SmartLists.svelte"; import PersonalLists from "$lib/sections/lists/user/PersonalLists.svelte"; + import type { PersonalListType } from "$lib/sections/lists/user/models/PersonalListType.ts"; import WatchList from "$lib/sections/lists/watchlist/WatchList.svelte"; import NavbarStateSetter from "$lib/sections/navbar/NavbarStateSetter.svelte"; import { DEFAULT_SHARE_COVER } from "$lib/utils/assets"; @@ -21,6 +22,12 @@ const { user } = useUser(); const { isMe } = $derived(useIsMe(params.user)); + + const personalListTypes: PersonalListType[] = [ + "personal", + "liked", + "collaboration", + ]; - - - + {#each personalListTypes as type (type)} + + {/each}