diff options
Diffstat (limited to 'src/lib/Schedule')
| -rw-r--r-- | src/lib/Schedule/CoverBypass.svelte | 90 | ||||
| -rw-r--r-- | src/lib/Schedule/Crunchyroll.svelte | 164 | ||||
| -rw-r--r-- | src/lib/Schedule/Days.svelte | 366 | ||||
| -rw-r--r-- | src/lib/Schedule/container.css | 2 |
4 files changed, 311 insertions, 311 deletions
diff --git a/src/lib/Schedule/CoverBypass.svelte b/src/lib/Schedule/CoverBypass.svelte index 1b7cce17..e94ddd40 100644 --- a/src/lib/Schedule/CoverBypass.svelte +++ b/src/lib/Schedule/CoverBypass.svelte @@ -1,55 +1,55 @@ <script lang="ts" ts> - import type { Media } from '$lib/Data/AniList/media'; - import MediaTitleDisplay from '$lib/List/MediaTitleDisplay.svelte'; - import type { SubsPleaseEpisode } from '$lib/Media/Anime/Airing/Subtitled/subsPlease'; + import type { Media } from '$lib/Data/AniList/media'; + import MediaTitleDisplay from '$lib/List/MediaTitleDisplay.svelte'; + import type { SubsPleaseEpisode } from '$lib/Media/Anime/Airing/Subtitled/subsPlease'; - import { outboundLink } from '$lib/Media/links'; - import tooltip from '$lib/Tooltip/tooltip'; - import { abbreviate } from '$lib/Utility/string'; - import settings from '$stores/settings'; + import { outboundLink } from '$lib/Media/links'; + import tooltip from '$lib/Tooltip/tooltip'; + import { abbreviate } from '$lib/Utility/string'; + import settings from '$stores/settings'; - export let media: Media | null; - export let entry: SubsPleaseEpisode; - export let cover = true; - export let showTooltip = true; + export let media: Media | null; + export let entry: SubsPleaseEpisode; + export let cover = true; + export let showTooltip = true; - const abbreviateTo = 40; + const abbreviateTo = 40; - const titleSelect = (media: Media | null) => - media ? media.title.english || media.title.romaji || media.title.native : null; + const titleSelect = (media: Media | null) => + media ? media.title.english || media.title.romaji || media.title.native : null; </script> <a - href={media - ? outboundLink(media, 'anime', $settings.displayOutboundLinksTo) - : outboundLink( - null, - 'anime', - $settings.displayOutboundLinksTo, - true, - titleSelect(media) || entry.title - )} - target="_blank" - title={`<img src="${ - $settings.displayDataSaver ? media?.coverImage.medium : media?.coverImage.extraLarge - }" style="width: 250px; object-fit: cover; border-radius: 8px;" />`} - use:tooltip - data-tooltip-disable={media && cover ? false : true} + href={media + ? outboundLink(media, 'anime', $settings.displayOutboundLinksTo) + : outboundLink( + null, + 'anime', + $settings.displayOutboundLinksTo, + true, + titleSelect(media) || entry.title + )} + target="_blank" + title={`<img src="${ + $settings.displayDataSaver ? media?.coverImage.medium : media?.coverImage.extraLarge + }" style="width: 250px; object-fit: cover; border-radius: 8px;" />`} + use:tooltip + data-tooltip-disable={media && cover ? false : true} > - {#if media} - <MediaTitleDisplay - title={media.title} - abbreviate - {abbreviateTo} - tooltip={showTooltip - ? media.title.english?.length > abbreviateTo || - media.title.romaji?.length > abbreviateTo || - media.title.native?.length > abbreviateTo - : false} - /> - {:else} - <span title={entry.title} use:tooltip> - {abbreviate(entry.title, abbreviateTo)} - </span> - {/if} + {#if media} + <MediaTitleDisplay + title={media.title} + abbreviate + {abbreviateTo} + tooltip={showTooltip + ? media.title.english?.length > abbreviateTo || + media.title.romaji?.length > abbreviateTo || + media.title.native?.length > abbreviateTo + : false} + /> + {:else} + <span title={entry.title} use:tooltip> + {abbreviate(entry.title, abbreviateTo)} + </span> + {/if} </a> diff --git a/src/lib/Schedule/Crunchyroll.svelte b/src/lib/Schedule/Crunchyroll.svelte index 0cfd0811..d22cff42 100644 --- a/src/lib/Schedule/Crunchyroll.svelte +++ b/src/lib/Schedule/Crunchyroll.svelte @@ -1,100 +1,100 @@ <script lang="ts"> - import crunchyroll from '$lib/Data/Static/crunchyroll.json'; - import './container.css'; + import crunchyroll from '$lib/Data/Static/crunchyroll.json'; + import './container.css'; - interface CrunchyrollMedia<T = number | 'soon' | 'continuing'> { - year: number; - month: number; - day: T; - title: string; - } + interface CrunchyrollMedia<T = number | 'soon' | 'continuing'> { + year: number; + month: number; + day: T; + title: string; + } - type KnownMedia = { [key: string]: CrunchyrollMedia<number>[] }; + type KnownMedia = { [key: string]: CrunchyrollMedia<number>[] }; - const days: KnownMedia = crunchyroll - .filter((media) => media.day !== 'soon' && media.day !== 'continuing') - .reduce((acc: KnownMedia, media) => { - const date = new Date(media.year, media.month - 1, media.day as number).toLocaleDateString(); + const days: KnownMedia = crunchyroll + .filter((media) => media.day !== 'soon' && media.day !== 'continuing') + .reduce((acc: KnownMedia, media) => { + const date = new Date(media.year, media.month - 1, media.day as number).toLocaleDateString(); - if (!acc[date]) acc[date] = []; + if (!acc[date]) acc[date] = []; - acc[date].push(media as CrunchyrollMedia<number>); + acc[date].push(media as CrunchyrollMedia<number>); - return acc; - }, {}); - const continuing: CrunchyrollMedia<number | string>[] = crunchyroll.filter( - (media) => media.day === 'continuing' - ); - const soon: CrunchyrollMedia<number | string>[] = crunchyroll.filter( - (media) => media.day === 'soon' - ); + return acc; + }, {}); + const continuing: CrunchyrollMedia<number | string>[] = crunchyroll.filter( + (media) => media.day === 'continuing' + ); + const soon: CrunchyrollMedia<number | string>[] = crunchyroll.filter( + (media) => media.day === 'soon' + ); - $: columnCount = Math.ceil(Object.keys(days).length / 2); + $: columnCount = Math.ceil(Object.keys(days).length / 2); - const ordinalSuffix = (i: number) => { - const j = i % 10; - const k = i % 100; + const ordinalSuffix = (i: number) => { + const j = i % 10; + const k = i % 100; - if (j === 1 && k !== 11) return i + 'st'; - if (j === 2 && k !== 12) return i + 'nd'; - if (j === 3 && k !== 13) return i + 'rd'; + if (j === 1 && k !== 11) return i + 'st'; + if (j === 2 && k !== 12) return i + 'nd'; + if (j === 3 && k !== 13) return i + 'rd'; - return i + 'th'; - }; + return i + 'th'; + }; </script> <div class="list-container" id="crunchyroll" style={`column-count: ${columnCount};`}> - {#each Object.values(days) as day} - {@const date = new Date(day[0].year, day[0].month - 1, day[0].day)} - - <div class="card day"> - <details open class="details-unstyled"> - <summary> - {date.toLocaleString('default', { month: 'long' })} - {ordinalSuffix(day[0].day)}, {day[0].year} - </summary> - <ol> - {#each day as media} - <li>{media.title}</li> - {/each} - </ol> - </details> - </div> - - <p /> - {/each} - - <div class="card day"> - <details open class="details-unstyled"> - <summary>Coming soon</summary> - - <ol> - {#each soon as media} - <li>{media.title}</li> - {/each} - </ol> - </details> - </div> - - <p /> - - <div class="card day"> - <details open class="details-unstyled"> - <summary>Continuing from previous season</summary> - - <ol> - {#each continuing as media} - <li>{media.title}</li> - {/each} - </ol> - </details> - </div> + {#each Object.values(days) as day} + {@const date = new Date(day[0].year, day[0].month - 1, day[0].day)} + + <div class="card day"> + <details open class="details-unstyled"> + <summary> + {date.toLocaleString('default', { month: 'long' })} + {ordinalSuffix(day[0].day)}, {day[0].year} + </summary> + <ol> + {#each day as media} + <li>{media.title}</li> + {/each} + </ol> + </details> + </div> + + <p /> + {/each} + + <div class="card day"> + <details open class="details-unstyled"> + <summary>Coming soon</summary> + + <ol> + {#each soon as media} + <li>{media.title}</li> + {/each} + </ol> + </details> + </div> + + <p /> + + <div class="card day"> + <details open class="details-unstyled"> + <summary>Continuing from previous season</summary> + + <ol> + {#each continuing as media} + <li>{media.title}</li> + {/each} + </ol> + </details> + </div> </div> <style> - .day { - overflow-y: auto; - break-inside: avoid; - page-break-inside: avoid; - } + .day { + overflow-y: auto; + break-inside: avoid; + page-break-inside: avoid; + } </style> diff --git a/src/lib/Schedule/Days.svelte b/src/lib/Schedule/Days.svelte index 59f64e4a..f4075313 100644 --- a/src/lib/Schedule/Days.svelte +++ b/src/lib/Schedule/Days.svelte @@ -1,191 +1,191 @@ <script lang="ts"> - import { browser } from '$app/environment'; - import type { Media } from '$lib/Data/AniList/media'; - import { findClosestMedia } from '$lib/Media/Anime/Airing/Subtitled/match'; - import type { SubsPlease, SubsPleaseEpisode } from '$lib/Media/Anime/Airing/Subtitled/subsPlease'; - import { outboundLink } from '$lib/Media/links'; - import { parseOrDefault } from '$lib/Utility/parameters'; - import settings from '$stores/settings'; - import CoverBypass from './CoverBypass.svelte'; - import '$lib/List/covers.css'; - import ParallaxImage from '$lib/Image/ParallaxImage.svelte'; - import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte'; - - export let subsPlease: SubsPlease; - export let scheduledMedia: Partial<Media[]>; - export let forceListMode = false; - - const urlParameters = browser ? new URLSearchParams(window.location.search) : null; - let day: string | null = parseOrDefault(urlParameters, 'day', null); - - const shiftSubsPleaseSchedule = (schedule: SubsPlease['schedule']) => { - const shiftedSchedule: { [key: string]: SubsPleaseEpisode[] } = {}; - - if (day && Object.keys(schedule).includes(day)) { - shiftedSchedule[day] = schedule[ - day as keyof typeof schedule - ] as unknown as SubsPleaseEpisode[]; - - return shiftedSchedule; - } - - const days = Object.keys(schedule); - const currentDayIndex = days.indexOf(new Date().toLocaleString('en-us', { weekday: 'long' })); - - days - .slice(currentDayIndex) - .concat(days.slice(0, currentDayIndex)) - .forEach((day) => { - const scheduleEntry = schedule[day as keyof typeof schedule]; - - shiftedSchedule[day] = Array.isArray(scheduleEntry) - ? scheduleEntry - : ([scheduleEntry] as unknown as SubsPleaseEpisode[]); - }); - - Object.entries(shiftedSchedule).forEach(([day, scheduleEntry]) => { - if (scheduleEntry.length === 0) { - delete shiftedSchedule[day]; - } - }); - - return shiftedSchedule; - }; - - const associateMedia = (media: (Media | undefined)[], title: string) => - findClosestMedia(media as Media[], title); - - const episode = (media: Media, weekday: string) => { - if (media.nextAiringEpisode?.episode === 1) return 1; - - if ( - media.nextAiringEpisode?.airingAt && - weekday === new Date().toLocaleString('en-us', { weekday: 'long' }) && - new Date(media.nextAiringEpisode.airingAt * 1000).getTime() - new Date().getTime() > - 24 * 60 * 60 * 1000 - ) - return media.nextAiringEpisode?.episode - 1; - - return media.nextAiringEpisode?.episode || 1; - }; + import { browser } from '$app/environment'; + import type { Media } from '$lib/Data/AniList/media'; + import { findClosestMedia } from '$lib/Media/Anime/Airing/Subtitled/match'; + import type { SubsPlease, SubsPleaseEpisode } from '$lib/Media/Anime/Airing/Subtitled/subsPlease'; + import { outboundLink } from '$lib/Media/links'; + import { parseOrDefault } from '$lib/Utility/parameters'; + import settings from '$stores/settings'; + import CoverBypass from './CoverBypass.svelte'; + import '$lib/List/covers.css'; + import ParallaxImage from '$lib/Image/ParallaxImage.svelte'; + import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte'; + + export let subsPlease: SubsPlease; + export let scheduledMedia: Partial<Media[]>; + export let forceListMode = false; + + const urlParameters = browser ? new URLSearchParams(window.location.search) : null; + let day: string | null = parseOrDefault(urlParameters, 'day', null); + + const shiftSubsPleaseSchedule = (schedule: SubsPlease['schedule']) => { + const shiftedSchedule: { [key: string]: SubsPleaseEpisode[] } = {}; + + if (day && Object.keys(schedule).includes(day)) { + shiftedSchedule[day] = schedule[ + day as keyof typeof schedule + ] as unknown as SubsPleaseEpisode[]; + + return shiftedSchedule; + } + + const days = Object.keys(schedule); + const currentDayIndex = days.indexOf(new Date().toLocaleString('en-us', { weekday: 'long' })); + + days + .slice(currentDayIndex) + .concat(days.slice(0, currentDayIndex)) + .forEach((day) => { + const scheduleEntry = schedule[day as keyof typeof schedule]; + + shiftedSchedule[day] = Array.isArray(scheduleEntry) + ? scheduleEntry + : ([scheduleEntry] as unknown as SubsPleaseEpisode[]); + }); + + Object.entries(shiftedSchedule).forEach(([day, scheduleEntry]) => { + if (scheduleEntry.length === 0) { + delete shiftedSchedule[day]; + } + }); + + return shiftedSchedule; + }; + + const associateMedia = (media: (Media | undefined)[], title: string) => + findClosestMedia(media as Media[], title); + + const episode = (media: Media, weekday: string) => { + if (media.nextAiringEpisode?.episode === 1) return 1; + + if ( + media.nextAiringEpisode?.airingAt && + weekday === new Date().toLocaleString('en-us', { weekday: 'long' }) && + new Date(media.nextAiringEpisode.airingAt * 1000).getTime() - new Date().getTime() > + 24 * 60 * 60 * 1000 + ) + return media.nextAiringEpisode?.episode - 1; + + return media.nextAiringEpisode?.episode || 1; + }; </script> {#each Object.entries(shiftSubsPleaseSchedule(subsPlease.schedule)) as [day, scheduleEntry], dayIndex} - <details - open - class="list" - class:today={day === new Date().toLocaleString('en-us', { weekday: 'long' })} - > - <summary>{day}</summary> - - {#if !$settings.displayScheduleListMode && !forceListMode} - <div - class="covers" - style={`grid-template-columns: repeat(auto-fill, minmax(${$settings.displayCoverWidth}px, 1fr))`} - > - {#each Object.values(scheduleEntry) as entry, entryIndex} - {@const media = associateMedia(scheduledMedia, entry.title)} - - <div class="cover-card" id={`cover-${dayIndex}-${entryIndex}`}> - <LinkedTooltip - content={media ? media.title.english || media.title.romaji : entry.title} - pin={`cover-${dayIndex}-${entryIndex}`} - > - <a - href={outboundLink( - media ? media : null, - 'anime', - $settings.displayOutboundLinksTo, - media === null, - entry.title - )} - target="_blank" - > - <div class="cover-card-image"> - <ParallaxImage - source={media - ? $settings.displayDataSaver - ? media.coverImage.medium - : media.coverImage.extraLarge - : `https://subsplease.org${entry.image_url}`} - limit={12.5} - alternativeText="Cover" - /> - </div> - </a> - - <div class="cover-title"> - <div class="cover-title-element"> - <CoverBypass {media} {entry} cover={false} showTooltip={false} /> - </div> - - <span class:countdown={$settings.displayCountdownRightAligned}> - {#if media && media.nextAiringEpisode} - <span class="opaque"> - {episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at - </span> - {/if} - {entry.time} - </span> - </div> - </LinkedTooltip> - </div> - {/each} - </div> - {:else} - <ol> - {#each Object.values(scheduleEntry) as entry} - {@const media = associateMedia(scheduledMedia, entry.title)} - - <li class="entry"> - <CoverBypass {media} {entry} /> - {#if !$settings.displayCountdownRightAligned} - <span class="opaque">|</span> - {/if} - <span class:countdown={$settings.displayCountdownRightAligned}> - {#if media && media.nextAiringEpisode} - <span class="opaque"> - {episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at - </span> - {/if} - {entry.time} - </span> - </li> - {/each} - </ol> - {/if} - </details> + <details + open + class="list" + class:today={day === new Date().toLocaleString('en-us', { weekday: 'long' })} + > + <summary>{day}</summary> + + {#if !$settings.displayScheduleListMode && !forceListMode} + <div + class="covers" + style={`grid-template-columns: repeat(auto-fill, minmax(${$settings.displayCoverWidth}px, 1fr))`} + > + {#each Object.values(scheduleEntry) as entry, entryIndex} + {@const media = associateMedia(scheduledMedia, entry.title)} + + <div class="cover-card" id={`cover-${dayIndex}-${entryIndex}`}> + <LinkedTooltip + content={media ? media.title.english || media.title.romaji : entry.title} + pin={`cover-${dayIndex}-${entryIndex}`} + > + <a + href={outboundLink( + media ? media : null, + 'anime', + $settings.displayOutboundLinksTo, + media === null, + entry.title + )} + target="_blank" + > + <div class="cover-card-image"> + <ParallaxImage + source={media + ? $settings.displayDataSaver + ? media.coverImage.medium + : media.coverImage.extraLarge + : `https://subsplease.org${entry.image_url}`} + limit={12.5} + alternativeText="Cover" + /> + </div> + </a> + + <div class="cover-title"> + <div class="cover-title-element"> + <CoverBypass {media} {entry} cover={false} showTooltip={false} /> + </div> + + <span class:countdown={$settings.displayCountdownRightAligned}> + {#if media && media.nextAiringEpisode} + <span class="opaque"> + {episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at + </span> + {/if} + {entry.time} + </span> + </div> + </LinkedTooltip> + </div> + {/each} + </div> + {:else} + <ol> + {#each Object.values(scheduleEntry) as entry} + {@const media = associateMedia(scheduledMedia, entry.title)} + + <li class="entry"> + <CoverBypass {media} {entry} /> + {#if !$settings.displayCountdownRightAligned} + <span class="opaque">|</span> + {/if} + <span class:countdown={$settings.displayCountdownRightAligned}> + {#if media && media.nextAiringEpisode} + <span class="opaque"> + {episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at + </span> + {/if} + {entry.time} + </span> + </li> + {/each} + </ol> + {/if} + </details> {/each} <style> - .countdown { - white-space: nowrap; - float: right; - } - - .today { - box-shadow: 0 2.5px 10px var(--base01), 0 0 0 5px var(--base0E), 0 4px 30px var(--base01); - } - - .list { - overflow-y: auto; - break-inside: avoid-column; - page-break-inside: avoid; - } - - @media (max-width: 800px) { - .cover-title-element { - display: none; - } - - .cover-card-image { - margin-bottom: 0em; - } - } - - @media (max-width: 1600px) { - .cover-title-element { - display: none; - } - } + .countdown { + white-space: nowrap; + float: right; + } + + .today { + box-shadow: 0 2.5px 10px var(--base01), 0 0 0 5px var(--base0E), 0 4px 30px var(--base01); + } + + .list { + overflow-y: auto; + break-inside: avoid-column; + page-break-inside: avoid; + } + + @media (max-width: 800px) { + .cover-title-element { + display: none; + } + + .cover-card-image { + margin-bottom: 0em; + } + } + + @media (max-width: 1600px) { + .cover-title-element { + display: none; + } + } </style> diff --git a/src/lib/Schedule/container.css b/src/lib/Schedule/container.css index 3a3beb1f..8690629d 100644 --- a/src/lib/Schedule/container.css +++ b/src/lib/Schedule/container.css @@ -1,3 +1,3 @@ .list-container { - column-width: 250px; + column-width: 250px; } |