Skip to content

Commit

Permalink
feat(web): smooth scroll, about section, cards, scroll animations
Browse files Browse the repository at this point in the history
  • Loading branch information
ThaUnknown committed Dec 4, 2023
1 parent 2ef05e3 commit 15beef8
Show file tree
Hide file tree
Showing 11 changed files with 817 additions and 5 deletions.
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"@fontsource-variable/material-symbols-outlined": "^5.0.16",
"@fontsource-variable/nunito": "^5.0.16",
"@fontsource/roboto": "^5.0.8",
"quartermoon": "^1.2.3"
"quartermoon": "^1.2.3",
"simple-store-svelte": "^1.0.1"
},
"type": "module"
}
14 changes: 12 additions & 2 deletions web/src/lib/components/Hero.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
<div class='d-flex position-relative justify-content-center align-items-center hero flex-column'>
<script>
let hero
function about () {
document.querySelector('#about').scrollIntoView({ behavior: 'smooth', block: 'center' })
setTimeout(() => {
hero.parentNode.dispatchEvent(new PointerEvent('pointerup'))
}, 500)
}
</script>

<div class='d-flex position-relative justify-content-center align-items-center hero flex-column' bind:this={hero}>
<div class='position-absolute ghost text-nowrap font-weight-semi-bold'>
MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU MIRU
</div>
Expand All @@ -10,7 +20,7 @@
<a href='/download' class='btn btn-danger btn-lg mr-20'>
Download
</a>
<a class='btn bg-dark-light btn-lg ml-20' href='#about'>Learn More</a>
<button class='btn bg-dark-light btn-lg ml-20' on:click={about}>Learn More</button>
</div>
</div>

Expand Down
145 changes: 145 additions & 0 deletions web/src/lib/components/PreviewCard.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<script>
import { formatMap } from './anime.js'
import { click } from '@/modules/click.js'
export let media
let hide = true
function getPlayButtonText (media) {
if (media.mediaListEntry) {
const { status, progress } = media.mediaListEntry
if (progress) {
if (status === 'COMPLETED') {
return 'Rewatch Now'
} else {
return 'Continue Now'
}
}
}
return 'Watch Now'
}
const playButtonText = getPlayButtonText(media)
function volume (video) {
video.volume = 0.1
}
let muted = true
function toggleMute () {
muted = !muted
}
const noop = () => {}
</script>

<div class='position-absolute w-350 h-400 absolute-container top-0 bottom-0 m-auto bg-dark-light z-30 rounded overflow-hidden pointer'>
<div class='banner position-relative overflow-hidden bg-black'>
<img src={media.bannerImage || ' '} alt='banner' class='img-cover w-full h-full' />
{#if media.trailer?.id}
<div class='material-symbols-outlined filled position-absolute z-10 top-0 right-0 p-15 font-size-22' class:d-none={hide} use:click={toggleMute}>{muted ? 'volume_off' : 'volume_up'}</div>
<!-- for now we use some invidious instance, would be nice to somehow get these links outselves, this redirects straight to some google endpoint -->
<!-- eslint-disable-next-line svelte/valid-compile -->
<video src={`https://yewtu.be/latest_version?id=${media.trailer.id}&itag=18`}
class='w-full position-absolute left-0'
class:d-none={hide}
playsinline
preload='none'
loop
use:volume
bind:muted
on:loadeddata={() => { hide = false }}
autoplay />
{/if}
</div>
<div class='w-full px-20'>
<div class='font-size-24 font-weight-bold text-truncate d-inline-block w-full text-white' title={media.title.userPreferred}>
{media.title.userPreferred}
</div>
<div class='d-flex flex-row pt-5'>
<button class='btn btn-secondary flex-grow-1 text-dark font-weight-bold shadow-none border-0 d-flex align-items-center justify-content-center'
use:click={noop}
disabled={media.status === 'NOT_YET_RELEASED'}>
<span class='material-symbols-outlined font-size-20 filled pr-10'>
play_arrow
</span>
{playButtonText}
</button>
<button class='btn btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.isFavourite} use:click={noop}>
favorite
</button>
<button class='btn btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.mediaListEntry} use:click={noop}>
bookmark
</button>
</div>
<div class='details text-white text-capitalize pt-15 pb-10 d-flex'>
<span class='text-nowrap d-flex align-items-center'>
{#if media.format}
{formatMap[media.format]}
{/if}
</span>
{#if media.episodes && media.episodes !== 1}
<span class='text-nowrap d-flex align-items-center'>
{#if media.mediaListEntry?.status === 'CURRENT' && media.mediaListEntry?.progress }
{media.mediaListEntry.progress} / {media.episodes} Episodes
{:else}
{media.episodes} Episodes
{/if}
</span>
{:else if media.duration}
<span class='text-nowrap d-flex align-items-center'>
{media.duration + ' Minutes'}
</span>
{/if}
{#if media.season || media.seasonYear}
<span class='text-nowrap d-flex align-items-center'>
{[media.season?.toLowerCase(), media.seasonYear].filter(s => s).join(' ')}
</span>
{/if}
</div>
<div class='w-full h-full text-muted description overflow-hidden'>
{media.description?.replace(/<[^>]*>/g, '')}
</div>
</div>
</div>

<style>
.description {
display: -webkit-box !important;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
}
.details span + span::before {
content: '';
padding: 0 .5rem;
font-size: .6rem;
align-self: center;
white-space: normal;
color: var(--dm-muted-text-color) !important;
}
.banner {
height: 45%
}
.banner::after {
content: '';
position: absolute;
left: 0 ; bottom: 0;
width: 100%; height: 100% ;
background: linear-gradient(180deg, #0000 0%, #25292f00 80%, #25292fe3 95%, #25292f 100%);
}
@keyframes load-in {
from {
bottom: -1.2rem;
opacity: 0;
transform: scale(0.95);
}
to {
bottom: 0;
opacity: 1;
transform: scale(1);
}
}
.absolute-container {
animation: 0.3s ease 0s 1 load-in;
left: -100%;
right: -100%;
}
</style>
66 changes: 66 additions & 0 deletions web/src/lib/components/SmallCard.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<script>
import PreviewCard from './PreviewCard.svelte'
import { formatMap, statusColorMap } from './anime.js'
import { hoverClick } from '@/modules/click.js'
export let media
export let preview = false
const noop = () => {}
function setHoverState (state) {
preview = state
}
</script>

<div class='d-flex p-20 position-relative first-check' use:hoverClick={[noop, setHoverState]}>
{#if preview}
<PreviewCard {media} />
{/if}
<div class='item d-flex flex-column h-full pointer content-visibility-auto'>
<img loading='lazy' src={media.coverImage.extraLarge || ''} alt='cover' class='cover-img w-full rounded' style:--color={media.coverImage.color || '#1890ff'} />
<div class='text-white font-weight-very-bold font-size-16 pt-15 title overflow-hidden'>
{#if media.mediaListEntry?.status}
<div style:--statusColor={statusColorMap[media.mediaListEntry.status]} class='list-status-circle d-inline-flex overflow-hidden mr-5' title={media.mediaListEntry.status} />
{/if}
{media.title.userPreferred}
</div>
<div class='d-flex flex-row mt-auto pt-10 font-weight-medium justify-content-between w-full text-muted'>
<div class='d-flex align-items-center' style='margin-left: -3px'>
<span class='material-symbols-outlined font-size-24 pr-5'>calendar_month</span>
{media.seasonYear || 'N/A'}
</div>
<div class='d-flex align-items-center'>
{formatMap[media.format]}
<span class='material-symbols-outlined font-size-24 pl-5'>monitor</span>
</div>
</div>
</div>
</div>

<style>
.first-check:first-child :global(.absolute-container) {
left: -48% !important
}
.title {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
img {
height: 27rem;
}
.item {
animation: 0.3s ease 0s 1 load-in;
width: 19rem;
contain-intrinsic-height: 36.7rem;
}
.cover-img {
background-color: var(--color) !important;
}
.list-status-circle {
background: var(--statusColor);
height: 1.1rem;
width: 1.1rem;
border-radius: 50%;
}
</style>
20 changes: 20 additions & 0 deletions web/src/lib/components/anime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const formatMap = {
TV: 'TV Series',
TV_SHORT: 'TV Short',
MOVIE: 'Movie',
SPECIAL: 'Special',
OVA: 'OVA',
ONA: 'ONA',
MUSIC: 'Music',
undefined: 'N/A',
null: 'N/A'
}

export const statusColorMap = {
CURRENT: 'rgb(61,180,242)',
PLANNING: 'rgb(247,154,99)',
COMPLETED: 'rgb(123,213,85)',
PAUSED: 'rgb(250,122,122)',
REPEATING: '#3baeea',
DROPPED: 'rgb(232,93,117)'
}
4 changes: 4 additions & 0 deletions web/src/lib/css.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ hr {

.h-vh-half {
height: 50vh;
}

:root {
--container-xl-max-width: 150rem
}
Loading

0 comments on commit 15beef8

Please sign in to comment.