wip: mediocre redesign

This commit is contained in:
ThaUnknown 2025-08-27 21:53:56 +02:00
parent 3e94d66b29
commit 962c8fd0ac
No known key found for this signature in database
9 changed files with 121 additions and 37 deletions

View file

@ -148,6 +148,12 @@
src: url("/twemoji-subset.woff2") format("woff2");
}
@property --bg-color {
syntax: '<color>';
initial-value: #111;
inherits: false;
}
html,
body {
height: 100vh !important;
@ -302,7 +308,9 @@ body {
}
#root {
transition: transform 0.5s;
/* transition: transform 0.5s; */
transition-property: transform, --bg-color;
transition-duration: 0.5s;
transform: perspective(100vw) translate3d(0, 0, 0vw) rotateY(0deg) rotateX(0deg);
}

View file

@ -22,9 +22,9 @@
</script>
{#if $bannerSrc}
<div class={cn('object-cover w-screen absolute top-0 left-0 h-full overflow-hidden pointer-events-none bg-black banner', className)}>
<div class={cn('object-cover w-full absolute top-0 left-0 h-full overflow-hidden pointer-events-none banner', className)}>
{#key $bannerSrc.id}
<Banner media={$bannerSrc} class='min-w-[100vw] w-screen h-[23rem] object-cover {$hideBanner ? 'opacity-10' : 'opacity-100'} transition-opacity duration-500 banner-gr relative' />
<Banner media={$bannerSrc} class='min-w-[100vw] w-full h-[23rem] object-cover {$hideBanner ? 'opacity-10' : 'opacity-100'} transition-opacity duration-500 banner-gr relative' />
{/key}
</div>
{/if}

View file

@ -1,7 +1,13 @@
<script lang='ts'>
import ArrowLeft from 'lucide-svelte/icons/arrow-left'
import ArrowRight from 'lucide-svelte/icons/arrow-right'
import MagnifyingGlass from 'svelte-radix/MagnifyingGlass.svelte'
import { Button } from '../button'
import Wrapper from './wrapper.svelte'
import { afterNavigate } from '$app/navigation'
import native from '$lib/modules/native'
import { click } from '$lib/modules/navigate'
import { debug, SUPPORTS } from '$lib/modules/settings'
@ -10,16 +16,58 @@
node.tabIndex = -1
}
let fullscreenElement: HTMLElement | null = null
$: draggable = fullscreenElement ? 'not-draggable' : 'draggable'
let currentPosition = history.length
let totalPositions = 0
$: hasNext = currentPosition < totalPositions
$: hasPrevious = currentPosition > 1
afterNavigate(({ delta }) => {
currentPosition += delta ?? 1
totalPositions = history.length
})
function next () {
if (hasNext) history.forward()
}
function previous () {
if (hasPrevious) history.back()
}
</script>
<svelte:document bind:fullscreenElement />
{#if !SUPPORTS.isAndroid}
<Wrapper let:platform>
<div class='w-[calc(100%-3.5rem)] left-[3.5rem] top-0 z-[2000] flex navbar absolute h-8'>
<div class='w-full {fullscreenElement ? 'not-draggable' : 'draggable'}' />
{#if platform !== 'macOS'}
<div class='window-controls not-draggable flex text-white backdrop-blur'>
{@const isMac = platform === 'macOS'}
<div class='w-[calc(100%-44px)] left-[44px] top-0 z-[2000] grid grid-cols-[auto_1fr_auto] absolute h-8'>
<div class='col-1 ml-1.5 flex gap-1.5 items-center {draggable} {!isMac ? 'w-[138px]' : ''}'>
<Button size='icon-sm' variant='ghost' disabled={!hasPrevious} class='w-6 h-6 p-1 shrink-0 not-draggable text-white' on:click={previous}>
<ArrowLeft />
</Button>
<Button size='icon-sm' variant='ghost' disabled={!hasNext} class='w-6 h-6 p-1 shrink-0 not-draggable text-white' on:click={next}>
<ArrowRight />
</Button>
</div>
<div class='w-full flex items-center justify-center {draggable}'>
<Button size='sm' variant='ghost' class='h-[25px] p-1 shrink-0 not-draggable text-white pl-5 pr-6 gap-2 py-0 text-xs'>
<MagnifyingGlass class='size-4 shrink-0' />
<div>
Search...
</div>
</Button>
<!-- <div class='flex items-center scale-parent relative not-draggable'>
<Input
class='pl-9 border-0 bg-background select:bg-accent select:text-accent-foreground shadow-sm no-scale placeholder:opacity-50 capitalize max-w-60'
placeholder='Search' />
<MagnifyingGlass class='h-4 w-4 shrink-0 opacity-50 absolute left-3 text-muted-foreground z-10 pointer-events-none' />
</div> -->
</div>
{#if !isMac}
<div class='window-controls not-draggable flex text-white'>
<button class='max-button flex items-center justify-center h-8 w-[46px]' use:click={native.minimise} use:tabindex>
<svg class='svg-controls w-3 h-3' role='img' viewBox='0 0 12 12'><rect fill='currentColor' height='1' width='10' x='1' y='6' />
</button>
@ -30,6 +78,8 @@
<svg class='svg-controls w-3 h-3' role='img' viewBox='0 0 12 12'><polygon fill='currentColor' fill-rule='evenodd' points='11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1' />
</button>
</div>
{:else}
<div class='w-[60px] {draggable}' />
{/if}
</div>
</Wrapper>
@ -47,14 +97,11 @@
transform-origin: 100% 0;
transform: translate(-29.3%) rotate(-45deg);
}
.window-controls {
background: rgba(24, 24, 24, 0.1);
}
.window-controls button:hover {
background: rgba(128, 128, 128, 0.2);
background: rgba(255, 255, 255, 0.2);
}
.window-controls button:active {
background: rgba(128, 128, 128, 0.4);
background: rgba(255, 255, 255, 0.4);
}
.close-button:hover {
background: #e81123 !important;

View file

@ -28,11 +28,11 @@
$: isActive = href && matchPath(href, $page)
</script>
<Button variant='ghost' {href} class={cn(className, 'px-2 w-10 relative md:pl-4 md:w-12 md:rounded-l-none group/sidebar')} {...$$restProps}>
<Button variant='ghost' {href} class={cn(className, 'size-[34px] relative group/sidebar')} {...$$restProps}>
{#if isActive}
<div class='bg-white absolute inset-0 rounded-md md:rounded-l-none group-select/sidebar:bg-primary/70' in:send={{ key }} out:receive={{ key }} />
<div class='bg-primary/30 absolute inset-0 rounded-md' in:send={{ key }} out:receive={{ key }} />
{/if}
<div class='relative text-white transition-colors duration-300 pointer-events-none' class:!text-black={isActive}>
<div class='relative text-primary transition-colors duration-300 pointer-events-none'>
<slot />
</div>
</Button>

View file

@ -30,7 +30,7 @@
<svelte:window use:outsideclick />
{#if !$breakpoints.md}
<div class='shrink-0 z-50 bg-black absolute left-4 bottom-4 w-14 h-[52px] flex rounded-md items-end justify-end overflow-clip transition-[width,height] group-fullscreen/fullscreen:hidden' class:!w-[152px]={open} class:!h-[140px]={open} bind:this={container}>
<div class='shrink-0 z-50 absolute left-4 bottom-4 w-14 h-[52px] flex rounded-md items-end justify-end overflow-clip transition-[width,height] group-fullscreen/fullscreen:hidden' class:!w-[152px]={open} class:!h-[140px]={open} bind:this={container}>
<div class='p-2 grid grid-cols-3 gap-2 shrink-0'>
<slot />
<Button variant='ghost' class='px-2 w-full relative' on:click={() => { open = !open }}>
@ -43,7 +43,7 @@
</div>
</div>
{:else}
<div class='w-14 p-2 md:pl-0 flex flex-col z-10 shrink-0 bg-black gap-2 group-fullscreen/fullscreen:hidden'>
<div class='w-12 flex flex-col items-center pb-2 z-10 shrink-0 gap-1.5 group-fullscreen/fullscreen:hidden'>
<slot />
</div>
{/if}

View file

@ -10,7 +10,6 @@
import Users from 'lucide-svelte/icons/users'
import Download from 'svelte-radix/Download.svelte'
import { BannerImage } from '../banner'
import { Button } from '../button'
import SidebarButton from './SidebarButton.svelte'
@ -40,36 +39,36 @@
<svelte:document bind:visibilityState />
<BannerImage class='absolute top-0 left-0 w-14 -z-10 hidden md:block' />
<Logo class={cn('mb-3 h-10 object-contain px-2.5 hidden md:block text-white ml-2 cursor-pointer', isMac && 'mt-3')} on:click={() => goto('/app/home/')} />
<!-- <BannerImage class='absolute top-0 left-0 w-14 -z-10 hidden md:block' /> -->
<Logo class={cn('h-10 object-contain w-4 hidden md:block text-white cursor-pointer', isMac && 'mt-3')} on:click={() => goto('/app/home/')} />
{#if SUPPORTS.isAndroidTV}
<SidebarButton href='/app/player/' class='hidden md:flex py-0'>
<Play size={16} />
<Play size={14} />
</SidebarButton>
{/if}
<SidebarButton href='/app/home/'>
<House size={18} />
<House size={16} />
</SidebarButton>
<SidebarButton href='/app/search/'>
<Search size={18} />
<Search size={16} />
</SidebarButton>
<SidebarButton href='/app/schedule/'>
<Calendar size={18} />
<Calendar size={16} />
</SidebarButton>
<SidebarButton href='/app/w2g/'>
<Users size={18} />
<Users size={16} />
</SidebarButton>
<SidebarButton href='/app/chat/'>
<MessagesSquare size={18} />
<MessagesSquare size={16} />
</SidebarButton>
<SidebarButton href='/app/client/' id='sidebar-client' data-down='#sidebar-donate'>
<Download size={18} />
<Download size={16} />
</SidebarButton>
<Button variant='ghost' id='sidebar-donate' data-up='#sidebar-client' on:click={() => native.openURL('https://github.com/sponsors/ThaUnknown/')} class='px-2 w-full relative mt-auto select:!bg-transparent text-[#fa68b6] select:text-[#fa68b6] md:pl-4 md:w-12 md:rounded-l-none'>
<Heart size={18} fill='currentColor' class={cn('drop-shadow-[0_0_1rem_#fa68b6]', active && 'animate-[hearbeat_1s_ease-in-out_infinite_alternate]')} />
<Button variant='ghost' id='sidebar-donate' data-up='#sidebar-client' on:click={() => native.openURL('https://github.com/sponsors/ThaUnknown/')} class='w-10 relative mt-auto select:!bg-transparent text-[#fa68b6] select:text-[#fa68b6] md:pl-4 md:w-12 md:rounded-l-none'>
<Heart size={16} fill='currentColor' class={cn('drop-shadow-[0_0_1rem_#fa68b6]', active && 'animate-[hearbeat_1s_ease-in-out_infinite_alternate]')} />
</Button>
<SidebarButton href='/app/settings/'>
<Settings size={18} />
<Settings size={16} />
</SidebarButton>
<!-- <SidebarButton href='/app/profile/'> -->
<SidebarButton href='/app/profile/' class='hidden md:flex py-0'>
@ -80,6 +79,6 @@
<Avatar.Fallback>{viewer?.name}</Avatar.Fallback>
</Avatar.Root>
{:else}
<LogIn size={18} />
<LogIn size={16} />
{/if}
</SidebarButton>

View file

@ -10,11 +10,12 @@
import { onNavigate } from '$app/navigation'
import Backplate from '$lib/components/Backplate.svelte'
import Online from '$lib/components/Online.svelte'
import { bannerSrc } from '$lib/components/ui/banner'
import { Menubar } from '$lib/components/ui/menubar'
import { Toaster } from '$lib/components/ui/sonner'
import native from '$lib/modules/native'
import { settings, SUPPORTS } from '$lib/modules/settings'
import { cn } from '$lib/utils'
import { cn, colors } from '$lib/utils'
let root: HTMLDivElement
@ -46,13 +47,18 @@
})
})
})
$: color = $bannerSrc?.coverImage?.color
$: ({ r, g, b } = colors(color ?? undefined))
</script>
<svelte:head>
<meta name='viewport' content='width=device-width, initial-scale={SUPPORTS.isAndroidTV ? $settings.uiScale / devicePixelRatio : SUPPORTS.isAndroid ? $settings.uiScale : 1}, maximum-scale=2, user-scalable=0, viewport-fit=cover' />
</svelte:head>
<div class={cn('w-full h-full flex flex-col backface-hidden bg-black relative overflow-clip [border-image:linear-gradient(to_bottom,white_var(--progress),#2dcf58_var(--progress))_1] preserve-3d', !SUPPORTS.isAndroid && 'md:border-l-2')} bind:this={root} id='root' style:--progress='{100 - updateProgress}%'>
<div class={cn('w-full h-full flex flex-col backface-hidden relative overflow-clip preserve-3d grain')} bind:this={root} id='root' style:--progress='{100 - updateProgress}%' style:--bg-color={color}
style:--custom={color ?? '#fff'} style:--red={r} style:--green={g} style:--blue={b}>
<ProgressBar zIndex={100} bind:complete {displayThresholdMs} />
<Toaster position='top-right' expand={true} />
@ -63,3 +69,25 @@
{#if !SUPPORTS.isAndroid}
<Backplate {root} />
{/if}
<style>
.grain {
/* background-blend-mode: multiply; */
--darken-color: hsl(from var(--bg-color) h calc(s * 0.6) calc(l * 0.4));
background: linear-gradient(135deg, var(--darken-color), color-mix(in srgb, var(--darken-color) 95%, red 5%));
}
/* .grain:before {
content: "";
z-index: -1;
background-color: transparent;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 600'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 182px;
opacity: 0.2;
top: 0;
left: 0;
position: absolute;
width: 100%;
height: 100%;
} */
</style>

View file

@ -49,12 +49,14 @@
<svelte:window on:dragover|preventDefault on:drop={handleTransfer} on:paste={handleTransfer} />
<BannerImage class='absolute top-0 left-0 -z-[1]' />
<SearchModal />
<div class='flex flex-row grow h-full overflow-clip group/fullscreen min-h-0' id='episodeListTarget'>
<Sidebar>
<Sidebarlist />
</Sidebar>
<Player />
<slot />
<div class='bg-black rounded-lg flex flex-col min-w-0 min-h-0 w-full mt-8 mb-2.5 mr-2.5 overflow-clip shadow relative' style:--tw-shadow='0 0 16px color-mix(in oklab, color-mix(in oklab, #000 50%, transparent) 100%, transparent)'>
<BannerImage class='absolute top-0 left-0' />
<Player />
<slot />
</div>
</div>

View file

@ -94,7 +94,7 @@
})
</script>
<div class='grow h-full min-w-0 -ml-14 pl-14 overflow-y-scroll' use:dragScroll on:scroll={handleScroll}>
<div class='grow h-full min-w-0 -ml-14 pl-16 overflow-y-scroll' use:dragScroll on:scroll={handleScroll}>
<Banner />
{#each $sectionQueries as { title, query, variables }, i (i)}
<div class='flex px-4 pt-5 items-end cursor-pointer text-muted-foreground select:text-foreground'>