diff --git a/package.json b/package.json index 53cb3e8..a623525 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,15 @@ "@sveltejs/adapter-node": "^5.0.1", "@sveltejs/kit": "^2.5.10", "@sveltejs/vite-plugin-svelte": "^3.1.1", - "@tailwindcss/typography": "^0.5.13", + "@tailwindcss/typography": "^0.5.14", "@types/eslint": "^8.56.10", "@types/luxon": "^3.4.2", "@types/nprogress": "^0.2.3", "@types/uuid": "^9.0.8", "@types/ws": "^8.5.12", - "autoprefixer": "^10.4.19", + "autoprefixer": "^10.4.20", + "bits-ui": "^0.21.16", + "clsx": "^2.1.1", "eslint": "^9.4.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.39.0", @@ -33,11 +35,13 @@ "postcss": "^8.4.38", "prettier": "^3.3.1", "prettier-plugin-svelte": "^3.2.4", - "prettier-plugin-tailwindcss": "^0.5.14", + "prettier-plugin-tailwindcss": "^0.6.5", "svelte": "^4.2.19", "svelte-check": "^3.8.0", "sveltekit-sse": "^0.13.5", - "tailwindcss": "^3.4.4", + "tailwind-merge": "^2.5.4", + "tailwind-variants": "^0.2.1", + "tailwindcss": "^3.4.9", "tslib": "^2.6.3", "typescript": "^5.4.5", "typescript-eslint": "8.0.0-alpha.28", @@ -47,8 +51,6 @@ "type": "module", "dependencies": { "@hey-api/client-fetch": "^0.4.0", - "bits-ui": "^0.21.10", - "clsx": "^2.1.1", "cmdk-sv": "^0.0.17", "embla-carousel-autoplay": "^8.1.5", "embla-carousel-svelte": "^8.1.5", @@ -60,8 +62,6 @@ "nprogress": "^0.2.0", "svelte-sonner": "^0.3.24", "sveltekit-superforms": "^2.14.0", - "tailwind-merge": "^2.3.0", - "tailwind-variants": "^0.2.1", "uuid": "^9.0.1", "vaul-svelte": "^0.3.2", "ws": "^8.18.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e20c4f4..33e2346 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,6 @@ importers: '@hey-api/client-fetch': specifier: ^0.4.0 version: 0.4.2 - bits-ui: - specifier: ^0.21.10 - version: 0.21.16(svelte@4.2.19) - clsx: - specifier: ^2.1.1 - version: 2.1.1 cmdk-sv: specifier: ^0.0.17 version: 0.0.17(svelte@4.2.19) @@ -50,12 +44,6 @@ importers: sveltekit-superforms: specifier: ^2.14.0 version: 2.20.0(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.9(@types/node@22.7.6)))(svelte@4.2.19)(vite@5.4.9(@types/node@22.7.6)))(@types/json-schema@7.0.15)(svelte@4.2.19)(typescript@5.6.3) - tailwind-merge: - specifier: ^2.3.0 - version: 2.5.4 - tailwind-variants: - specifier: ^0.2.1 - version: 0.2.1(tailwindcss@3.4.14) uuid: specifier: ^9.0.1 version: 9.0.1 @@ -86,7 +74,7 @@ importers: specifier: ^3.1.1 version: 3.1.2(svelte@4.2.19)(vite@5.4.9(@types/node@22.7.6)) '@tailwindcss/typography': - specifier: ^0.5.13 + specifier: ^0.5.14 version: 0.5.15(tailwindcss@3.4.14) '@types/eslint': specifier: ^8.56.10 @@ -104,8 +92,14 @@ importers: specifier: ^8.5.12 version: 8.5.12 autoprefixer: - specifier: ^10.4.19 + specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) + bits-ui: + specifier: ^0.21.16 + version: 0.21.16(svelte@4.2.19) + clsx: + specifier: ^2.1.1 + version: 2.1.1 eslint: specifier: ^9.4.0 version: 9.12.0(jiti@2.3.3) @@ -128,8 +122,8 @@ importers: specifier: ^3.2.4 version: 3.2.7(prettier@3.3.3)(svelte@4.2.19) prettier-plugin-tailwindcss: - specifier: ^0.5.14 - version: 0.5.14(prettier-plugin-svelte@3.2.7(prettier@3.3.3)(svelte@4.2.19))(prettier@3.3.3) + specifier: ^0.6.5 + version: 0.6.8(prettier-plugin-svelte@3.2.7(prettier@3.3.3)(svelte@4.2.19))(prettier@3.3.3) svelte: specifier: ^4.2.19 version: 4.2.19 @@ -139,8 +133,14 @@ importers: sveltekit-sse: specifier: ^0.13.5 version: 0.13.9(@microsoft/fetch-event-source@2.0.1)(@sveltejs/kit@2.7.1(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.19)(vite@5.4.9(@types/node@22.7.6)))(svelte@4.2.19)(vite@5.4.9(@types/node@22.7.6)))(svelte@4.2.19) + tailwind-merge: + specifier: ^2.5.4 + version: 2.5.4 + tailwind-variants: + specifier: ^0.2.1 + version: 0.2.1(tailwindcss@3.4.14) tailwindcss: - specifier: ^3.4.4 + specifier: ^3.4.9 version: 3.4.14 tslib: specifier: ^2.6.3 @@ -1991,8 +1991,8 @@ packages: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 - prettier-plugin-tailwindcss@0.5.14: - resolution: {integrity: sha512-Puaz+wPUAhFp8Lo9HuciYKM2Y2XExESjeT+9NQoVFXZsPPnc9VYss2SpxdQ6vbatmt8/4+SN0oe0I1cPDABg9Q==} + prettier-plugin-tailwindcss@0.6.8: + resolution: {integrity: sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==} engines: {node: '>=14.21.3'} peerDependencies: '@ianvs/prettier-plugin-sort-imports': '*' @@ -2006,6 +2006,7 @@ packages: prettier-plugin-import-sort: '*' prettier-plugin-jsdoc: '*' prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' prettier-plugin-organize-attributes: '*' prettier-plugin-organize-imports: '*' prettier-plugin-sort-imports: '*' @@ -2032,6 +2033,8 @@ packages: optional: true prettier-plugin-marko: optional: true + prettier-plugin-multiline-arrays: + optional: true prettier-plugin-organize-attributes: optional: true prettier-plugin-organize-imports: @@ -4327,7 +4330,7 @@ snapshots: prettier: 3.3.3 svelte: 4.2.19 - prettier-plugin-tailwindcss@0.5.14(prettier-plugin-svelte@3.2.7(prettier@3.3.3)(svelte@4.2.19))(prettier@3.3.3): + prettier-plugin-tailwindcss@0.6.8(prettier-plugin-svelte@3.2.7(prettier@3.3.3)(svelte@4.2.19))(prettier@3.3.3): dependencies: prettier: 3.3.3 optionalDependencies: diff --git a/src/app.css b/src/app.css index 6741ba8..e53a729 100644 --- a/src/app.css +++ b/src/app.css @@ -60,6 +60,11 @@ } } -.no-scrollbar::-webkit-scrollbar { +*::-webkit-scrollbar { display: none; } + +* { + -ms-overflow-style: none; + scrollbar-width: none; +} diff --git a/src/lib/components/header.svelte b/src/lib/components/header.svelte index ef8a1eb..b1c964d 100644 --- a/src/lib/components/header.svelte +++ b/src/lib/components/header.svelte @@ -1,44 +1,72 @@ -
- - {data.title} - -
-
- {data.type} - • - - {state === 'PartiallyCompleted' ? 'Partial' : statesName[state]} - -
-
{data.title}
+ {data.title} +
+

{data.title}

+
+ {data.type} + + {data.state === 'PartiallyCompleted' ? 'Partial' : statesName[data.state]} +
diff --git a/src/lib/components/media-tmdb-carousel.svelte b/src/lib/components/media-tmdb-carousel.svelte index 1984130..42c1248 100644 --- a/src/lib/components/media-tmdb-carousel.svelte +++ b/src/lib/components/media-tmdb-carousel.svelte @@ -1,10 +1,11 @@ {#each results as result} - +
- {result.id} + + + {data.title +
+

{data.title || data.name}

+
+
diff --git a/src/lib/components/ui/popover/index.ts b/src/lib/components/ui/popover/index.ts new file mode 100644 index 0000000..5db432e --- /dev/null +++ b/src/lib/components/ui/popover/index.ts @@ -0,0 +1,17 @@ +import { Popover as PopoverPrimitive } from 'bits-ui'; +import Content from './popover-content.svelte'; +const Root = PopoverPrimitive.Root; +const Trigger = PopoverPrimitive.Trigger; +const Close = PopoverPrimitive.Close; + +export { + Root, + Content, + Trigger, + Close, + // + Root as Popover, + Content as PopoverContent, + Trigger as PopoverTrigger, + Close as PopoverClose +}; diff --git a/src/lib/components/ui/popover/popover-content.svelte b/src/lib/components/ui/popover/popover-content.svelte new file mode 100644 index 0000000..89402d9 --- /dev/null +++ b/src/lib/components/ui/popover/popover-content.svelte @@ -0,0 +1,22 @@ + + + + + diff --git a/src/lib/tmdb.ts b/src/lib/tmdb.ts index b5bf627..d2387e8 100644 --- a/src/lib/tmdb.ts +++ b/src/lib/tmdb.ts @@ -1,3 +1,5 @@ +import type { TMDBSearchResponse } from './types'; + const TMDB_READ_ACCESS_TOKEN: string = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJlNTkxMmVmOWFhM2IxNzg2Zjk3ZTE1NWY1YmQ3ZjY1MSIsInN1YiI6IjY1M2NjNWUyZTg5NGE2MDBmZjE2N2FmYyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.xrIXsMFJpI1o1j5g2QpQcFP1X3AfRjFA5FlBFO5Naw8'; const HEADERS: Record = { @@ -299,7 +301,7 @@ export async function getMovieSearch( page: number = 1, region: string | null = null, year: number | null = null -) { +): Promise { const params = { query, include_adult, language, primary_release_year, page, region, year }; const queryString = dictToQueryString(params); @@ -319,7 +321,7 @@ export async function getMultiSearch( include_adult: boolean = false, language: string = 'en-US', page: number = 1 -) { +): Promise { const params = { query, include_adult, language, page }; const queryString = dictToQueryString(params); diff --git a/src/lib/types.ts b/src/lib/types.ts index efc88ec..cf3a113 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -97,3 +97,38 @@ export interface RivenEpisode extends RivenBaseItem { } export type RivenItem = RivenMovie | RivenShow | RivenSeason | RivenEpisode; + +export interface RivenGetItemsResponse { + success: boolean; + items: RivenItem[]; + page: number; + limit: number; + total_items: number; + total_pages: number; +} + +export type TMDBItem = { + backdrop_path: string | null; + id: number; + title: string | null; + name: string | null; + original_title: string; + overview: string; + poster_path: string | null; + media_type: 'movie' | 'tv' | 'person'; + adult: boolean; + original_language: string; + genre_ids: number[]; + popularity: number; + release_date: string; + video: boolean; + vote_average: number; + vote_count: number; +}; + +export interface TMDBSearchResponse { + page: number; + results: TMDBItem[]; + total_pages: number; + total_results: number; +} diff --git a/src/lib/utils/search.ts b/src/lib/utils/search.ts new file mode 100644 index 0000000..910a15f --- /dev/null +++ b/src/lib/utils/search.ts @@ -0,0 +1,174 @@ +import { getMultiSearch } from '$lib/tmdb'; + +interface ComponentInfo { + id: string; + title: string; + content: string; + path: string; +} + +export interface SearchResult { + title: string; + media_type: string; + path: string; + excerpt: string; + type: 'component' | 'media' | 'action'; +} + +export const componentRegistry: ComponentInfo[] = [ + { + id: 'settings-about', + title: 'About Settings', + content: + 'View information about Riven, including version numbers, support links, and contributors.', + path: '/settings/about' + }, + { + id: 'settings-content', + title: 'Content Settings', + content: 'Configure content providers for Riven.', + path: '/settings/content' + }, + { + id: 'settings-general', + title: 'General Settings', + content: 'Configure global and default settings for Riven.', + path: '/settings/general' + }, + { + id: 'settings-mediaserver', + title: 'Media Server Settings', + content: 'Configure media server settings for Riven.', + path: '/settings/mediaserver' + }, + { + id: 'settings-ranking', + title: 'Ranking Settings', + content: 'Configure ranking settings for Riven, including profiles and custom ranks.', + path: '/settings/ranking' + }, + { + id: 'settings-scrapers', + title: 'Scraper Settings', + content: 'Configure scraper settings for Riven.', + path: '/settings/scrapers' + }, + { + id: 'settings-layout', + title: 'Settings Layout', + content: 'Navigate between different settings pages in Riven.', + path: '/settings' + }, + { + id: 'backend-version', + title: 'Backend Version', + content: 'View and check for updates to the Riven backend.', + path: '/settings/about#backend-version' + }, + { + id: 'frontend-version', + title: 'Frontend Version', + content: 'View and check for updates to the Riven frontend.', + path: '/settings/about#frontend-version' + }, + { + id: 'rclone-path', + title: 'Rclone Path', + content: 'View the configured Rclone path for Riven.', + path: '/settings/about#rclone-path' + }, + { + id: 'library-path', + title: 'Library Path', + content: 'View the configured library path for Riven.', + path: '/settings/about#library-path' + }, + { + id: 'support-discord', + title: 'Discord Support', + content: 'Get support for Riven through the Discord community.', + path: '/settings/about#discord' + }, + { + id: 'support-github', + title: 'GitHub Support', + content: 'Report issues or contribute to Riven on GitHub.', + path: '/settings/about#github' + }, + { + id: 'contributors', + title: 'Contributors', + content: 'View the contributors to the Riven project.', + path: '/settings/about#contributors' + }, + { + id: 'ranking-profiles', + title: 'Ranking Profiles', + content: + 'Learn about the different ranking profiles available in Riven: default, best, and custom.', + path: '/settings/ranking#profiles' + }, + { + id: 'ranking-wiki', + title: 'Ranking Wiki', + content: 'Access detailed information about Riven ranking settings.', + path: '/settings/ranking#wiki' + } +]; + +export async function searchContent(query: string): Promise { + const lowercaseQuery = query.toLowerCase(); + + const results: SearchResult[] = [ + { + title: `Search as media: "${query}"`, + media_type: '', + path: '#', + excerpt: `Search for "${query}" in TMDB`, + type: 'action' + } + ]; + + // Search through componentRegistry + const componentResults = componentRegistry + .filter( + (component) => + component.id.toLowerCase().includes(lowercaseQuery) || + component.title.toLowerCase().includes(lowercaseQuery) || + component.content.toLowerCase().includes(lowercaseQuery) + ) + .map((result) => ({ + title: result.title, + media_type: '', + path: result.path, + excerpt: result.content.substring(0, 100) + '...', + type: 'component' as const + })); + + results.push(...componentResults); + + return results; +} + +export async function searchTMDB(query: string): Promise { + try { + const data = await getMultiSearch(fetch, query); + return data.results + .filter((item) => item.media_type === 'movie' || item.media_type === 'tv') + .map((item) => ({ + title: item.title || item.name || '', + media_type: item.media_type === 'tv' ? 'Show' : 'Movie', + path: `/${item.media_type}/${item.id}`, + excerpt: item.overview + ? item.overview.substring(0, 100) + '...' + : 'No description available', + type: 'media' as const, + posterPath: item.poster_path + ? `https://image.tmdb.org/t/p/w92${item.poster_path}` + : undefined + })); + } catch (error) { + console.error('Error searching TMDB:', error); + return []; + } +} diff --git a/src/nprogress.css b/src/nprogress.css index 5e41a27..67bef9e 100644 --- a/src/nprogress.css +++ b/src/nprogress.css @@ -4,7 +4,7 @@ } #nprogress .bar { - background: red; + background: grey; position: fixed; z-index: 1031; @@ -12,7 +12,7 @@ left: 0; width: 100%; - height: 3px; + height: 2px; } /* Fancy blur effect */ @@ -23,8 +23,8 @@ width: 100px; height: 100%; box-shadow: - 0 0 10px red, - 0 0 5px red; + 0 0 10px grey, + 0 0 5px grey; opacity: 1; -webkit-transform: rotate(3deg) translate(0px, -4px); @@ -47,8 +47,8 @@ box-sizing: border-box; border: solid 2px transparent; - border-top-color: red; - border-left-color: red; + border-top-color: grey; + border-left-color: grey; border-radius: 50%; -webkit-animation: nprogress-spinner 400ms linear infinite; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 0a31a8e..2497d57 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -8,26 +8,6 @@ import { setContext } from 'svelte'; import { dev } from '$app/environment'; import { writable, type Writable } from 'svelte/store'; - import { source } from 'sveltekit-sse'; - import { toast } from 'svelte-sonner'; - - // function handleSSE(message: string) { - // const data = JSON.parse(message); - - // if (data.type === 'health') { - // toast.info('Websocket is connected'); - // } - - // if (data.type === 'item_update') { - // const item = JSON.parse(data.item); - // toast.info(`${item.type} ${item.title} has been updated to ${item.state}`); - // } - // } - - // const value = source('/api/sse').select('message'); - // $: if ($value) { - // handleSSE($value); - // } const showMenu: Writable = writable(false); @@ -45,7 +25,7 @@ }); - +
diff --git a/src/routes/[type]/[id]/+page.svelte b/src/routes/[type]/[id]/+page.svelte index 172c9c3..89108b1 100644 --- a/src/routes/[type]/[id]/+page.svelte +++ b/src/routes/[type]/[id]/+page.svelte @@ -37,7 +37,7 @@ let productionCompanies = 4; let magnetLink = ''; let magnetLoading = false; - let isShow = data.riven ? isRivenShow(data.riven) : false; + let isShow = data.details.media_type === 'tv'; let selectedMagnetItem: Selected<{ id: string; file?: string; folder?: string }>; $: buttonEnabled = magnetLink && !magnetLoading && (isShow ? selectedMagnetItem : true); @@ -710,6 +710,7 @@ {/if} diff --git a/src/routes/browse/+page.svelte b/src/routes/browse/+page.svelte index 11607cb..b197f7c 100644 --- a/src/routes/browse/+page.svelte +++ b/src/routes/browse/+page.svelte @@ -1,60 +1,231 @@ + + Browse | Riven + +
-
-
- -
- - {#if loading} -
- -

Loading...

-
- {:else if query.length > 0} -

Search results for {query}

+
+
+
+ + + + { + if (s) { + $formData.state = s.value; + handleFilterChange(); + } + }} + > + + + + + + {#each Object.entries(states) as [value, label]} + + {/each} + + + + + - {#if movies.length > 0} - - {/if} + + + + { + if (s) { + $formData.type = s.value; + handleFilterChange(); + } + }} + > + + + + + + {#each Object.entries(types) as [value, label]} + + {/each} + + + + + - {#if shows.length > 0} - - {/if} - {/if} + + + + { + if (s) { + $formData.sort = s.value; + handleFilterChange(); + } + }} + > + + + + + + {#each Object.entries(sortOptions) as [value, label]} + + {/each} + + + + + + + + + +
+ {#each items as item (item.id)} +
+ +
+ {/each} +
+ +
+ { + pageNumber = page; + fetchItems(); + }} + > + + + + + {#each pages as page (page.key)} + {#if page.type === 'ellipsis'} + + + + {:else} + + + {page.value} + + + {/if} + {/each} + + + + + +
+
diff --git a/src/routes/browse/+page.ts b/src/routes/browse/+page.ts index d2a5256..76c8536 100644 --- a/src/routes/browse/+page.ts +++ b/src/routes/browse/+page.ts @@ -1,23 +1,44 @@ -import type { PageLoad } from './$types'; -import { getMovieSearch, getTVSearch, getCollectionSearch } from '$lib/tmdb'; +import { superValidate } from 'sveltekit-superforms/client'; +import { schema } from './schema'; +import { ItemsService } from '$lib/client'; +import { zod } from 'sveltekit-superforms/adapters'; +import type { PageLoad } from '../$types'; +import type { RivenGetItemsResponse } from '$lib/types'; -export const load = (async ({ fetch, url }) => { - const query = url.searchParams.get('query'); +export const load = (async () => { + const form = await superValidate({}, zod(schema)); + const page = 1; + const limit = 12; - if (query && query.length > 0) { - const moviesRes = await getMovieSearch(fetch, query, false, 'en-US', null, 1, null, null); - const tvRes = await getTVSearch(fetch, query, null, false, 'en-US', 1, null); - const collectionRes = await getCollectionSearch(fetch, query, false, 'en-US', 1, null); + async function getItems(): Promise { + try { + const { data, error } = await ItemsService.getItems({ + query: { + page, + sort: form.data.sort, + limit, + type: form.data.type, + states: form.data.state + } + }); - return { - movies: moviesRes.results, - shows: tvRes.results, - collections: collectionRes.results - }; - } else { - return { - movies: [], - shows: [] - }; + if (error) { + console.error('Error fetching items:', error); + return { success: true, items: [], page: 0, limit: 0, total_items: 0, total_pages: 0 }; + } + + return data as unknown as RivenGetItemsResponse; + } catch (err) { + console.error('Error in getItems:', err); + return { success: true, items: [], page: 0, limit: 0, total_items: 0, total_pages: 0 }; + } } + + const itemsData = await getItems(); + + return { + form, + page, + itemsData + }; }) satisfies PageLoad; diff --git a/src/routes/browse/schema.ts b/src/routes/browse/schema.ts new file mode 100644 index 0000000..ceaa450 --- /dev/null +++ b/src/routes/browse/schema.ts @@ -0,0 +1,52 @@ +import { z } from 'zod'; + +export const schema = z.object({ + state: z + .enum([ + '', + 'Unknown', + 'Unreleased', + 'Ongoing', + 'Requested', + 'Indexed', + 'Scraped', + 'Downloaded', + 'Symlinked', + 'Completed', + 'PartiallyCompleted', + 'Failed' + ]) + .default(''), + type: z.enum(['movie', 'show', 'movie,show']).default('movie,show'), + sort: z.enum(['date_desc', 'date_asc', 'title_asc', 'title_desc']).default('date_desc') +}); + +export const states = { + '': 'Any State', + Unknown: 'Unknown', + Unreleased: 'Unreleased', + Ongoing: 'Ongoing', + Requested: 'Requested', + Indexed: 'Indexed', + Scraped: 'Scraped', + Downloaded: 'Downloaded', + Symlinked: 'Symlinked', + Completed: 'Completed', + PartiallyCompleted: 'Partially Completed', + Failed: 'Failed' +}; + +export const types = { + movie: 'Movies', + show: 'Shows', + 'movie,show': 'Movies & Shows' +}; + +export const sortOptions = { + date_desc: 'Date (Newest)', + date_asc: 'Date (Oldest)', + title_asc: 'Title (A-Z)', + title_desc: 'Title (Z-A)' +}; + +export type FormSchema = typeof schema; diff --git a/src/routes/collection/[id]/+page.svelte b/src/routes/collection/[id]/+page.svelte index b5b0b74..a1c7138 100644 --- a/src/routes/collection/[id]/+page.svelte +++ b/src/routes/collection/[id]/+page.svelte @@ -28,7 +28,7 @@
{#each data.details.parts as item}
- import type { PageData } from './$types'; - import { writable, type Writable } from 'svelte/store'; - import { page } from '$app/stores'; - import Header from '$lib/components/header.svelte'; - import MediaItem from '$lib/components/media-item.svelte'; - import * as Pagination from '$lib/components/ui/pagination'; - import { goto } from '$app/navigation'; - import { Input } from '$lib/components/ui/input'; - import * as Select from '$lib/components/ui/select/index.js'; - import { statesName } from '$lib/constants'; - import { Button } from '$lib/components/ui/button'; - import { onMount } from 'svelte'; - - export let data: PageData; - - $: pageSize = writable(Number($page.url.searchParams.get('limit') || 24)); - $: totalDataItems = writable(Number($page.data.total)); - $: library = writable(data.library); - - $: limit = writable(Number($page.url.searchParams.get('limit')) || 24) as Writable; - $: query = writable($page.url.searchParams.get('query') || undefined) as Writable< - string | undefined - >; - $: types = writable($page.url.searchParams.get('types') || undefined) as Writable< - string | undefined - >; - $: states = writable($page.url.searchParams.get('states') || undefined) as Writable< - string | undefined - >; - - function submitQueries() { - const queries = new URLSearchParams(); - - if ($query) queries.set('query', $query); - if ($limit) queries.set('limit', $limit.toString()); - - if ($types) { - queries.set('types', $types); - } - - if ($states) { - queries.set('states', $states); - } - - goto(`?${queries.toString()}`, { replaceState: true }); - } - - function resetQueries() { - $limit = 24; - $query = undefined; - $types = undefined; - $states = undefined; - - goto(`?`, { replaceState: true }); - } - - onMount(() => { - function handleKeydown(e: KeyboardEvent) { - if (e.key === 'Enter') { - e.preventDefault(); - submitQueries(); - } - } - - document.addEventListener('keydown', handleKeydown); - return () => { - document.removeEventListener('keydown', handleKeydown); - }; - }); - - - - Library | Riven - - -
- -
-
-
- { - $limit = Number(selected?.value); - }} - selected={{ - value: $limit, - label: $limit?.toString() || 'Select limit' - }} - > - - - - - - {#each [12, 24, 48, 96] as limit} - {limit} - {/each} - - - - { - $types = selected?.map((type) => type.value).join(',') || undefined; - }} - selected={($types || '') - .split(',') - .filter((type) => type.trim() !== '') - .map((type) => ({ - value: type, - label: type - }))} - multiple={true} - > - - - - - - Movie - Show - Anime - - - - { - $states = selected?.map((state) => state.value).join(',') || undefined; - }} - selected={($states || '') - .split(',') - .filter((state) => state.trim() !== '') - .map((state) => ({ - value: state, - label: statesName[state] - }))} - multiple={true} - > - - - - - - {#each Object.keys(statesName) as state} - {statesName[state]} - {/each} - - - - - - -
- -
- -
-
- -
- {#each $library as item (item.id)} - - {/each} -
- - {#if $totalDataItems > 0} - { - const params = new URLSearchParams(window.location.search); - params.set('page', page.toString()); - goto(`?${params.toString()}`, { replaceState: true }); - }} - > - - - - - {#each pages as page (page.key)} - {#if page.type === 'ellipsis'} - - - - {:else} - - - {page.value} - - - {/if} - {/each} - - - - - - {/if} -
diff --git a/src/routes/library/+page.ts b/src/routes/library/+page.ts deleted file mode 100644 index a357a2f..0000000 --- a/src/routes/library/+page.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { PageLoad } from './$types'; -import { ItemsService, type ItemsResponse } from '$lib/client'; -import { error } from '@sveltejs/kit'; - -export const load: PageLoad = async ({ url }) => { - async function getLibraryApi(): Promise { - const limit = Number(url.searchParams.get('limit')) || 24; - const page = Number(url.searchParams.get('page')) || 1; - const types = url.searchParams.get('types'); - const query = url.searchParams.get('query'); - const states = url.searchParams.get('states'); - - const { data, error: itemsError } = await ItemsService.getItems({ - query: { - limit, - page, - states, - type: types ?? 'movie,show', - search: query, - sort: 'date_desc' - } - }); - - if (data) { - return data; - } else { - console.log(itemsError); - throw error(500, "Couldn't reach backend to get library items"); - } - } - - const { items, total_items } = await getLibraryApi(); - - return { - library: items, - total: total_items - }; -}; diff --git a/src/routes/people/[id]/+page.svelte b/src/routes/people/[id]/+page.svelte index ab3f747..21729b6 100644 --- a/src/routes/people/[id]/+page.svelte +++ b/src/routes/people/[id]/+page.svelte @@ -84,7 +84,7 @@
{#each data.details.combined_credits.cast as item}
{#each data.details.combined_credits.crew as item}