diff options
Diffstat (limited to 'src/lib/Hololive')
| -rw-r--r-- | src/lib/Hololive/Lives.svelte | 130 | ||||
| -rw-r--r-- | src/lib/Hololive/Stream.svelte | 290 | ||||
| -rw-r--r-- | src/lib/Hololive/hololive.ts | 18 |
3 files changed, 219 insertions, 219 deletions
diff --git a/src/lib/Hololive/Lives.svelte b/src/lib/Hololive/Lives.svelte index 7281b18f..9e762df9 100644 --- a/src/lib/Hololive/Lives.svelte +++ b/src/lib/Hololive/Lives.svelte @@ -1,93 +1,93 @@ <script lang="ts"> - import Message from '$lib/Loading/Message.svelte'; - import root from '$lib/Utility/root'; - import type { Live, ParseResult } from './hololive'; - import Stream from './Stream.svelte'; + import Message from '$lib/Loading/Message.svelte'; + import root from '$lib/Utility/root'; + import type { Live, ParseResult } from './hololive'; + import Stream from './Stream.svelte'; - export let schedule: ParseResult; - export let pinnedStreams: string[]; - export let getPinnedStreams: () => void; - export let filter: string | undefined; + export let schedule: ParseResult; + export let pinnedStreams: string[]; + export let getPinnedStreams: () => void; + export let filter: string | undefined; - const pinStream = (streamer: string) => - fetch(root(`/api/preferences/pin?stream=${encodeURIComponent(streamer)}`), { - method: 'PUT', - headers: { - 'Content-Type': 'application/json' - } - }).then(getPinnedStreams); + const pinStream = (streamer: string) => + fetch(root(`/api/preferences/pin?stream=${encodeURIComponent(streamer)}`), { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + } + }).then(getPinnedStreams); - $: categorisedStreams = schedule.lives - .filter((live) => (filter ? live.streamer === filter : true)) - .sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime()) - .sort((a, b) => { - const aPinned = pinnedStreams.includes(a.streamer); - const bPinned = pinnedStreams.includes(b.streamer); + $: categorisedStreams = schedule.lives + .filter((live) => (filter ? live.streamer === filter : true)) + .sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime()) + .sort((a, b) => { + const aPinned = pinnedStreams.includes(a.streamer); + const bPinned = pinnedStreams.includes(b.streamer); - if (aPinned && !bPinned) return -1; - if (!aPinned && bPinned) return 1; + if (aPinned && !bPinned) return -1; + if (!aPinned && bPinned) return 1; - return 0; - }) - .reduce( - ( - acc: { - live: Live[]; - upcoming: Live[]; - ended: Live[]; - }, - live - ) => { - const now = Date.now(); - const time = new Date(live.time).getTime(); - const isLive = live.streaming; - const isUpcoming = time > now && !isLive; - const isEnded = time < now && !isLive; + return 0; + }) + .reduce( + ( + acc: { + live: Live[]; + upcoming: Live[]; + ended: Live[]; + }, + live + ) => { + const now = Date.now(); + const time = new Date(live.time).getTime(); + const isLive = live.streaming; + const isUpcoming = time > now && !isLive; + const isEnded = time < now && !isLive; - if (isLive) { - acc.live.push(live); - } else if (isUpcoming) { - acc.upcoming.push(live); - } else if (isEnded) { - acc.ended.push(live); - } + if (isLive) { + acc.live.push(live); + } else if (isUpcoming) { + acc.upcoming.push(live); + } else if (isEnded) { + acc.ended.push(live); + } - return acc; - }, - { live: [], upcoming: [], ended: [] } - ); + return acc; + }, + { live: [], upcoming: [], ended: [] } + ); </script> {#if schedule.lives.length === 0} - <Message message="No upcoming streams." loader="ripple" /> + <Message message="No upcoming streams." loader="ripple" /> {/if} <div class="container"> - {#each categorisedStreams.live as live} - <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} /> - {/each} + {#each categorisedStreams.live as live} + <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} /> + {/each} </div> <p /> <div class="container"> - {#each categorisedStreams.upcoming as live} - <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} /> - {/each} + {#each categorisedStreams.upcoming as live} + <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} /> + {/each} </div> <p /> <div class="container"> - {#each categorisedStreams.ended as live} - <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} /> - {/each} + {#each categorisedStreams.ended as live} + <Stream {live} {pinStream} {pinnedStreams} icon={schedule.dict[live.streamer]} /> + {/each} </div> <style lang="scss"> - .container { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(22em, 1fr)); - gap: 0.5em; - } + .container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(22em, 1fr)); + gap: 0.5em; + } </style> diff --git a/src/lib/Hololive/Stream.svelte b/src/lib/Hololive/Stream.svelte index cde3be68..12681acb 100644 --- a/src/lib/Hololive/Stream.svelte +++ b/src/lib/Hololive/Stream.svelte @@ -1,153 +1,153 @@ <script lang="ts"> - import ParallaxImage from '$lib/Image/ParallaxImage.svelte'; - import root from '$lib/Utility/root'; - import identity from '$stores/identity'; - import locale from '$stores/locale'; - import Icon from '@iconify/svelte'; - - export let live: any; - export let pinStream: (streamer: string) => void; - export let pinnedStreams: string[]; - export let icon: string; + import ParallaxImage from '$lib/Image/ParallaxImage.svelte'; + import root from '$lib/Utility/root'; + import identity from '$stores/identity'; + import locale from '$stores/locale'; + import Icon from '@iconify/svelte'; + + export let live: any; + export let pinStream: (streamer: string) => void; + export let pinnedStreams: string[]; + export let icon: string; </script> <div class="stream card"> - {#if $identity.id !== -2} - <div class="pin-icon"> - <a - href={'#'} - on:click={(e) => { - e.preventDefault(); - pinStream(live.streamer); - }} - > - <Icon - icon={`pajamas:thumbtack${pinnedStreams.includes(live.streamer) ? '-solid' : ''}`} - width="1em" - /> - </a> - </div> - {/if} - - <p class="stream-heading"> - {#if live.streaming} - <b class="live">{$locale().hololive.live}</b - >{:else if new Date(live.time).getTime() < Date.now()} - <span class="ended">{$locale().hololive.ended}</span>{:else} - <span class="upcoming">{$locale().hololive.upcoming}</span>{/if} - <span class="opaque">|</span> - {#if icon} - <a href={root(`/hololive/${encodeURIComponent(live.streamer)}`)}> - <img src={icon} alt="Avatar" class="stream-icon" /> - </a> - {/if} - <a href={root(`/hololive/${encodeURIComponent(live.streamer)}`)} class="streamer-link"> - <b>{live.streamer}</b> - </a> - <br /> - {$locale().hololive.dateFormatter(new Date(live.time))} - {#if live.guests.length > 0} - {$locale().hololive.with}{live.guests - .join($locale().hololive.comma) - .replace( - new RegExp(`${$locale().hololive.comma}([^${$locale().hololive.commaNoSpace}]+)$`, 'g'), - `${$locale().hololive.comma}${$locale().hololive.ampersand}$1` - )} - {/if} - </p> - - <a href={live.link} class="preview" target="_blank"> - <span class="preview-image"> - <ParallaxImage - source={live.livePreviewImage} - alternativeText="Stream Thumbnail" - limit={12.5} - duration={2750} - /> - </span> - </a> + {#if $identity.id !== -2} + <div class="pin-icon"> + <a + href={'#'} + on:click={(e) => { + e.preventDefault(); + pinStream(live.streamer); + }} + > + <Icon + icon={`pajamas:thumbtack${pinnedStreams.includes(live.streamer) ? '-solid' : ''}`} + width="1em" + /> + </a> + </div> + {/if} + + <p class="stream-heading"> + {#if live.streaming} + <b class="live">{$locale().hololive.live}</b + >{:else if new Date(live.time).getTime() < Date.now()} + <span class="ended">{$locale().hololive.ended}</span>{:else} + <span class="upcoming">{$locale().hololive.upcoming}</span>{/if} + <span class="opaque">|</span> + {#if icon} + <a href={root(`/hololive/${encodeURIComponent(live.streamer)}`)}> + <img src={icon} alt="Avatar" class="stream-icon" /> + </a> + {/if} + <a href={root(`/hololive/${encodeURIComponent(live.streamer)}`)} class="streamer-link"> + <b>{live.streamer}</b> + </a> + <br /> + {$locale().hololive.dateFormatter(new Date(live.time))} + {#if live.guests.length > 0} + {$locale().hololive.with}{live.guests + .join($locale().hololive.comma) + .replace( + new RegExp(`${$locale().hololive.comma}([^${$locale().hololive.commaNoSpace}]+)$`, 'g'), + `${$locale().hololive.comma}${$locale().hololive.ampersand}$1` + )} + {/if} + </p> + + <a href={live.link} class="preview" target="_blank"> + <span class="preview-image"> + <ParallaxImage + source={live.livePreviewImage} + alternativeText="Stream Thumbnail" + limit={12.5} + duration={2750} + /> + </span> + </a> </div> <style lang="scss"> - $transition: transform 0.3s ease; - - .preview { - // margin: 0.15rem; - - :global(img) { - border-radius: 8px; - height: 20vh; - object-fit: cover; - } - - .preview-image { - transition: $transition; - } - - &:hover { - .preview-image { - position: relative; - z-index: 2; - transition: $transition; - transform: scale(1.025) !important; - } - } - - display: flex; - justify-content: center; - align-items: center; - } - - .live { - color: var(--base0F); - } - - .upcoming { - color: var(--base0C); - } - - .ended { - color: var(--base0D); - } - - .pin-icon { - position: absolute; - right: 0; - top: 0; - padding: 0.75rem; - } - - .stream { - position: relative; - } - - .stream-heading { - padding-right: 2em; - padding-left: 2.5em; - } - - .stream-icon { - $size: 2em; - - position: absolute; - top: 0; - left: 0; - border-radius: 8px; - width: $size; - height: $size; - margin: 0.75rem; - object-fit: cover; - transition: $transition; - - &:hover { - z-index: 2; - transition: $transition; - transform: scale(1.1); - } - } - - .streamer-link { - color: var(--fg); - text-decoration: none; - } + $transition: transform 0.3s ease; + + .preview { + // margin: 0.15rem; + + :global(img) { + border-radius: 8px; + height: 20vh; + object-fit: cover; + } + + .preview-image { + transition: $transition; + } + + &:hover { + .preview-image { + position: relative; + z-index: 2; + transition: $transition; + transform: scale(1.025) !important; + } + } + + display: flex; + justify-content: center; + align-items: center; + } + + .live { + color: var(--base0F); + } + + .upcoming { + color: var(--base0C); + } + + .ended { + color: var(--base0D); + } + + .pin-icon { + position: absolute; + right: 0; + top: 0; + padding: 0.75rem; + } + + .stream { + position: relative; + } + + .stream-heading { + padding-right: 2em; + padding-left: 2.5em; + } + + .stream-icon { + $size: 2em; + + position: absolute; + top: 0; + left: 0; + border-radius: 8px; + width: $size; + height: $size; + margin: 0.75rem; + object-fit: cover; + transition: $transition; + + &:hover { + z-index: 2; + transition: $transition; + transform: scale(1.1); + } + } + + .streamer-link { + color: var(--fg); + text-decoration: none; + } </style> diff --git a/src/lib/Hololive/hololive.ts b/src/lib/Hololive/hololive.ts index 4b9ed25e..f348567c 100644 --- a/src/lib/Hololive/hololive.ts +++ b/src/lib/Hololive/hololive.ts @@ -1,16 +1,16 @@ export interface Live { - time: Date; - link: string; - videoId: string; - streamer: string; - livePreviewImage: string; - guests: string[]; - streaming: boolean; + time: Date; + link: string; + videoId: string; + streamer: string; + livePreviewImage: string; + guests: string[]; + streaming: boolean; } export interface ParseResult { - lives: Live[]; - dict: Record<string, string>; + lives: Live[]; + dict: Record<string, string>; } export const typeSchedule = (schedule: object) => schedule as ParseResult; |