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

View file

@ -22,9 +22,9 @@
</script> </script>
{#if $bannerSrc} {#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} {#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} {/key}
</div> </div>
{/if} {/if}

View file

@ -1,7 +1,13 @@
<script lang='ts'> <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 Wrapper from './wrapper.svelte'
import { afterNavigate } from '$app/navigation'
import native from '$lib/modules/native' import native from '$lib/modules/native'
import { click } from '$lib/modules/navigate' import { click } from '$lib/modules/navigate'
import { debug, SUPPORTS } from '$lib/modules/settings' import { debug, SUPPORTS } from '$lib/modules/settings'
@ -10,16 +16,58 @@
node.tabIndex = -1 node.tabIndex = -1
} }
let fullscreenElement: HTMLElement | null = null 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> </script>
<svelte:document bind:fullscreenElement /> <svelte:document bind:fullscreenElement />
{#if !SUPPORTS.isAndroid} {#if !SUPPORTS.isAndroid}
<Wrapper let:platform> <Wrapper let:platform>
<div class='w-[calc(100%-3.5rem)] left-[3.5rem] top-0 z-[2000] flex navbar absolute h-8'> {@const isMac = platform === 'macOS'}
<div class='w-full {fullscreenElement ? 'not-draggable' : 'draggable'}' /> <div class='w-[calc(100%-44px)] left-[44px] top-0 z-[2000] grid grid-cols-[auto_1fr_auto] absolute h-8'>
{#if platform !== 'macOS'} <div class='col-1 ml-1.5 flex gap-1.5 items-center {draggable} {!isMac ? 'w-[138px]' : ''}'>
<div class='window-controls not-draggable flex text-white backdrop-blur'> <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> <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' /> <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> </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' /> <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> </button>
</div> </div>
{:else}
<div class='w-[60px] {draggable}' />
{/if} {/if}
</div> </div>
</Wrapper> </Wrapper>
@ -47,14 +97,11 @@
transform-origin: 100% 0; transform-origin: 100% 0;
transform: translate(-29.3%) rotate(-45deg); transform: translate(-29.3%) rotate(-45deg);
} }
.window-controls {
background: rgba(24, 24, 24, 0.1);
}
.window-controls button:hover { .window-controls button:hover {
background: rgba(128, 128, 128, 0.2); background: rgba(255, 255, 255, 0.2);
} }
.window-controls button:active { .window-controls button:active {
background: rgba(128, 128, 128, 0.4); background: rgba(255, 255, 255, 0.4);
} }
.close-button:hover { .close-button:hover {
background: #e81123 !important; background: #e81123 !important;

View file

@ -28,11 +28,11 @@
$: isActive = href && matchPath(href, $page) $: isActive = href && matchPath(href, $page)
</script> </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} {#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} {/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 /> <slot />
</div> </div>
</Button> </Button>

View file

@ -30,7 +30,7 @@
<svelte:window use:outsideclick /> <svelte:window use:outsideclick />
{#if !$breakpoints.md} {#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'> <div class='p-2 grid grid-cols-3 gap-2 shrink-0'>
<slot /> <slot />
<Button variant='ghost' class='px-2 w-full relative' on:click={() => { open = !open }}> <Button variant='ghost' class='px-2 w-full relative' on:click={() => { open = !open }}>
@ -43,7 +43,7 @@
</div> </div>
</div> </div>
{:else} {: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 /> <slot />
</div> </div>
{/if} {/if}

View file

@ -10,7 +10,6 @@
import Users from 'lucide-svelte/icons/users' import Users from 'lucide-svelte/icons/users'
import Download from 'svelte-radix/Download.svelte' import Download from 'svelte-radix/Download.svelte'
import { BannerImage } from '../banner'
import { Button } from '../button' import { Button } from '../button'
import SidebarButton from './SidebarButton.svelte' import SidebarButton from './SidebarButton.svelte'
@ -40,36 +39,36 @@
<svelte:document bind:visibilityState /> <svelte:document bind:visibilityState />
<BannerImage class='absolute top-0 left-0 w-14 -z-10 hidden md:block' /> <!-- <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/')} /> <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} {#if SUPPORTS.isAndroidTV}
<SidebarButton href='/app/player/' class='hidden md:flex py-0'> <SidebarButton href='/app/player/' class='hidden md:flex py-0'>
<Play size={16} /> <Play size={14} />
</SidebarButton> </SidebarButton>
{/if} {/if}
<SidebarButton href='/app/home/'> <SidebarButton href='/app/home/'>
<House size={18} /> <House size={16} />
</SidebarButton> </SidebarButton>
<SidebarButton href='/app/search/'> <SidebarButton href='/app/search/'>
<Search size={18} /> <Search size={16} />
</SidebarButton> </SidebarButton>
<SidebarButton href='/app/schedule/'> <SidebarButton href='/app/schedule/'>
<Calendar size={18} /> <Calendar size={16} />
</SidebarButton> </SidebarButton>
<SidebarButton href='/app/w2g/'> <SidebarButton href='/app/w2g/'>
<Users size={18} /> <Users size={16} />
</SidebarButton> </SidebarButton>
<SidebarButton href='/app/chat/'> <SidebarButton href='/app/chat/'>
<MessagesSquare size={18} /> <MessagesSquare size={16} />
</SidebarButton> </SidebarButton>
<SidebarButton href='/app/client/' id='sidebar-client' data-down='#sidebar-donate'> <SidebarButton href='/app/client/' id='sidebar-client' data-down='#sidebar-donate'>
<Download size={18} /> <Download size={16} />
</SidebarButton> </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'> <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={18} fill='currentColor' class={cn('drop-shadow-[0_0_1rem_#fa68b6]', active && 'animate-[hearbeat_1s_ease-in-out_infinite_alternate]')} /> <Heart size={16} fill='currentColor' class={cn('drop-shadow-[0_0_1rem_#fa68b6]', active && 'animate-[hearbeat_1s_ease-in-out_infinite_alternate]')} />
</Button> </Button>
<SidebarButton href='/app/settings/'> <SidebarButton href='/app/settings/'>
<Settings size={18} /> <Settings size={16} />
</SidebarButton> </SidebarButton>
<!-- <SidebarButton href='/app/profile/'> --> <!-- <SidebarButton href='/app/profile/'> -->
<SidebarButton href='/app/profile/' class='hidden md:flex py-0'> <SidebarButton href='/app/profile/' class='hidden md:flex py-0'>
@ -80,6 +79,6 @@
<Avatar.Fallback>{viewer?.name}</Avatar.Fallback> <Avatar.Fallback>{viewer?.name}</Avatar.Fallback>
</Avatar.Root> </Avatar.Root>
{:else} {:else}
<LogIn size={18} /> <LogIn size={16} />
{/if} {/if}
</SidebarButton> </SidebarButton>

View file

@ -10,11 +10,12 @@
import { onNavigate } from '$app/navigation' import { onNavigate } from '$app/navigation'
import Backplate from '$lib/components/Backplate.svelte' import Backplate from '$lib/components/Backplate.svelte'
import Online from '$lib/components/Online.svelte' import Online from '$lib/components/Online.svelte'
import { bannerSrc } from '$lib/components/ui/banner'
import { Menubar } from '$lib/components/ui/menubar' import { Menubar } from '$lib/components/ui/menubar'
import { Toaster } from '$lib/components/ui/sonner' import { Toaster } from '$lib/components/ui/sonner'
import native from '$lib/modules/native' import native from '$lib/modules/native'
import { settings, SUPPORTS } from '$lib/modules/settings' import { settings, SUPPORTS } from '$lib/modules/settings'
import { cn } from '$lib/utils' import { cn, colors } from '$lib/utils'
let root: HTMLDivElement let root: HTMLDivElement
@ -46,13 +47,18 @@
}) })
}) })
}) })
$: color = $bannerSrc?.coverImage?.color
$: ({ r, g, b } = colors(color ?? undefined))
</script> </script>
<svelte:head> <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' /> <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> </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} /> <ProgressBar zIndex={100} bind:complete {displayThresholdMs} />
<Toaster position='top-right' expand={true} /> <Toaster position='top-right' expand={true} />
@ -63,3 +69,25 @@
{#if !SUPPORTS.isAndroid} {#if !SUPPORTS.isAndroid}
<Backplate {root} /> <Backplate {root} />
{/if} {/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} /> <svelte:window on:dragover|preventDefault on:drop={handleTransfer} on:paste={handleTransfer} />
<BannerImage class='absolute top-0 left-0 -z-[1]' />
<SearchModal /> <SearchModal />
<div class='flex flex-row grow h-full overflow-clip group/fullscreen min-h-0' id='episodeListTarget'> <div class='flex flex-row grow h-full overflow-clip group/fullscreen min-h-0' id='episodeListTarget'>
<Sidebar> <Sidebar>
<Sidebarlist /> <Sidebarlist />
</Sidebar> </Sidebar>
<Player /> <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)'>
<slot /> <BannerImage class='absolute top-0 left-0' />
<Player />
<slot />
</div>
</div> </div>

View file

@ -94,7 +94,7 @@
}) })
</script> </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 /> <Banner />
{#each $sectionQueries as { title, query, variables }, i (i)} {#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'> <div class='flex px-4 pt-5 items-end cursor-pointer text-muted-foreground select:text-foreground'>