feat: greatly improve setup screen

This commit is contained in:
ThaUnknown 2025-05-27 23:17:03 +02:00
parent c4ee54beba
commit 0037dc2231
No known key found for this signature in database
12 changed files with 59 additions and 39 deletions

View file

@ -1,6 +1,6 @@
{
"name": "ui",
"version": "6.3.26",
"version": "6.3.27",
"license": "BUSL-1.1",
"private": true,
"packageManager": "pnpm@9.14.4",

View file

@ -316,6 +316,16 @@ body {
}
}
@keyframes bg-grid-animate {
from {
background-position: 0 100%;
}
to {
background-position: 100% 0;
}
}
.animate-marquee {
animation: marquee 80s infinite linear;
}

View file

@ -32,10 +32,10 @@
let importPromise = Promise.resolve()
function importExtension () {
export function importExtension (ext = extensionInput) {
importPromise = (async () => {
try {
await storage.import(extensionInput)
await storage.import(ext)
} catch (err) {
const error = err as Error
toast.error(error.cause as string, { description: error.message })
@ -132,7 +132,7 @@
Importing extensions....
</Button>
{:then _}
<Button class='font-bold flex items-center justify-center w-full sm:w-56 max-w-full shrink-0' size='default' on:click={importExtension}>
<Button class='font-bold flex items-center justify-center w-full sm:w-56 max-w-full shrink-0' size='default' on:click={() => importExtension()}>
<Plus size={iconSizes.lg} class='mr-2' />
Import Extensions
</Button>

View file

@ -178,7 +178,7 @@
function seek (time: number) {
// WARN: this causes all subscriptions to video to re-run!!!
video.currentTime = currentTime = currentTime + time
currentTime = currentTime + time
// currentTime = currentTime + time
playAnimation(time > 0 ? 'seekforw' : 'seekback')
}
function seekTo (time: number) {

View file

@ -1,12 +1,12 @@
// TODO: update these
import { writable } from 'simple-store-svelte'
import type { Media } from './modules/anilist'
// TODO: update these
export const CHANGELOG_URL = 'https://api.github.com/repos/ThaUnknown/miru/releases'
export const WEB_URL = 'https://miru.watch'
export const DEFAULT_EXTENSIONS = 'gh:hayase-app/extensions'
export const SETUP_VERSION = 2
export const SETUP_VERSION = 3
// episode is optional here, but is actually always defined
export const searchStore = writable<{episode?: number, media?: Media}>({})

View file

@ -66,7 +66,7 @@ export default Object.assign<Native, Partial<Native>>({
setPlayBackState: async e => { navigator.mediaSession.playbackState = e },
setActionHandler: async (...args) => navigator.mediaSession.setActionHandler(...args as [action: MediaSessionAction, handler: MediaSessionActionHandler | null]),
checkAvailableSpace: () => new Promise(resolve => setTimeout(() => resolve(Math.floor(Math.random() * (1e10 - 1e8 + 1) + 1e8)), 1000)),
checkIncomingConnections: () => new Promise(resolve => setTimeout(() => resolve(Math.random() > 0.5), 5000)),
checkIncomingConnections: () => new Promise(resolve => setTimeout(() => resolve(false), 1000)),
updatePeerCounts: async () => [],
isApp: false,
playTorrent: async () => dummyFiles,

View file

@ -1,5 +1,6 @@
<div class='w-full h-full flex items-center justify-center md:py-20 md:px-4 lg:px-10'>
<div class='md:bg-neutral-950 w-full md:max-w-[1140px] h-full md:max-h-[720px] rounded-lg flex-col md:border border-border flex items-center justify-center overflow-clip'>
<div class='absolute opacity-25 w-full h-[130%] -z-[1] bg-cover bg-no-repeat bg-[url(/bg_grid.jpg)] animate-[bg-grid-animate_60s_linear_infinite_alternate]' />
<div class='w-full md:max-w-[1140px] h-full md:max-h-[720px] flex-col flex items-center justify-center overflow-clip'>
<slot />
</div>
</div>

View file

@ -5,18 +5,20 @@
import { Checkbox } from '$lib/components/ui/checkbox'
import { Label } from '$lib/components/ui/label'
import native from '$lib/modules/native'
import { click } from '$lib/modules/navigate'
import { click, dragScroll } from '$lib/modules/navigate'
let checked = false
</script>
<Logo class='w-52 h-52 object-contain mb-14' />
<div class='font-bold text-5xl'>Welcome to Hayase</div>
<div class='text-muted-foreground pt-6'>Let's set up your perfect streaming environment.</div>
<div class='flex items-center space-x-2 pt-12'>
<Checkbox id='terms' bind:checked />
<Label for='terms' class='text-md font-medium leading-none text-muted-foreground'>
I agree to the <a use:click={() => native.openURL(`${WEB_URL}/terms`)} class='text-primary underline'>Terms of Service</a> and <a use:click={() => native.openURL(`${WEB_URL}/privacy`)} class='text-primary underline'>Privacy Policy</a>
</Label>
<div class='space-y-3 lg:max-w-4xl h-full overflow-y-auto w-full py-8 flex flex-col items-center justify-center' use:dragScroll>
<Logo class='w-52 h-52 object-contain mb-14 shrink-0' />
<div class='font-bold text-5xl'>Welcome to Hayase</div>
<div class='text-muted-foreground pt-3'>Let's set up your perfect streaming environment.</div>
<div class='flex items-center space-x-2 pt-12 pb-3'>
<Checkbox id='terms' bind:checked />
<Label for='terms' class='text-md font-medium leading-none text-muted-foreground'>
I agree to the <a use:click={() => native.openURL(`${WEB_URL}/terms`)} class='text-primary underline'>Terms of Service</a> and <a use:click={() => native.openURL(`${WEB_URL}/privacy`)} class='text-primary underline'>Privacy Policy</a>
</Label>
</div>
<Button class='text-lg font-bold shrink-0' disabled={!checked} size='lg' href={checked ? './storage' : undefined}>Start Setup</Button>
</div>
<Button class='mt-8 text-lg font-bold' disabled={!checked} size='lg' href={checked ? './storage' : undefined}>Start Setup</Button>

View file

@ -3,6 +3,7 @@
promise: Promise<{
status: 'warning' | 'success' | 'error'
text: string
slot?: string
}>
title: string
pending: string
@ -41,7 +42,7 @@
<div class='w-4 h-4 border-2 rounded-[50%] border-neutral-700 border-b-border' />
</div>
{title} -&nbsp;<span class='text-muted-foreground text-xs text-wrap'>{pending}</span>
{:then { status, text }}
{:then { status, text, slot }}
<Badge variant={status} class='w-4 h-4 rounded-[50%] p-[3px] justify-center items-center mr-2.5'>
{#if status === 'success'}
<Check strokeWidth='4px' />
@ -54,13 +55,18 @@
<X strokeWidth='4px' />
{/if}
</Badge>
{title} -&nbsp;<span class='text-muted-foreground text-xs text-wrap'>{text}</span>
{title} -&nbsp;<span class='text-muted-foreground text-xs text-wrap flex'>
{text}
{#if slot}
<slot />
{/if}
</span>
{/await}
</div>
{/each}
</div>
</div>
<div class='flex flex-row items-center justify-between w-full bg-neutral-950 border-t border-border py-4 px-8'>
<div class='flex flex-row items-center justify-between w-full bg-neutral-950 border-t md:border md:rounded-lg border-border py-4 px-8'>
<Button variant='secondary' class='w-24' href='../{PREV[step]}'>Prev</Button>
{#await settled}
<Tooltip.Root>

View file

@ -1,6 +1,6 @@
<script lang='ts'>
import { onMount } from 'svelte'
import { persisted } from 'svelte-persisted-store'
import { toast } from 'svelte-sonner'
import Footer, { type Checks } from '../Footer.svelte'
import Progress from '../Progress.svelte'
@ -11,7 +11,8 @@
import SettingCard from '$lib/components/SettingCard.svelte'
import { SingleCombo } from '$lib/components/ui/combobox'
import { Extensions } from '$lib/components/ui/extensions'
import { saved, options, storage } from '$lib/modules/extensions'
import { saved, options } from '$lib/modules/extensions'
import { dragScroll } from '$lib/modules/navigate'
import { lookupPreferences, settings, SUPPORTS } from '$lib/modules/settings'
function checkExtensions (svd: Record<string, ExtensionConfig>, opts: Record<string, {
@ -36,29 +37,24 @@
pending: 'Waiting for at least one extension to be installed...'
}]
async function importDefault () {
try {
await storage.import(DEFAULT_EXTENSIONS)
} catch (err) {
const error = err as Error
toast.error(error.cause as string, { description: error.message })
}
}
if (!SUPPORTS.isAndroid && !Object.keys($saved).length) importDefault()
onMount(() => {
if (!SUPPORTS.isAndroid && !Object.keys($saved).length) importExtension(DEFAULT_EXTENSIONS)
})
const hasForwarding = persisted('torrent-port-forwarding', false)
$settings.lookupPreference = $hasForwarding ? 'quality' : 'seeders'
let importExtension: ((ext?: string) => void)
</script>
<Progress step={2} />
<div class='space-y-3 lg:max-w-4xl h-full overflow-y-auto w-full py-8'>
<SettingCard title='Lookup Preference' description='What to prioritize when looking for and sorting results. Quality will focus on the best quality available which often means big file sizes, Size will focus on the smallest file size available, and Availability will pick results with the most peers regardless of size and quality.'>
<div class='space-y-3 lg:max-w-4xl h-full overflow-y-auto w-full py-8' use:dragScroll>
<SettingCard class='bg-transparent' title='Lookup Preference' description='What to prioritize when looking for and sorting results. Quality will focus on the best quality available which often means big file sizes, Size will focus on the smallest file size available, and Availability will pick results with the most peers regardless of size and quality.'>
<SingleCombo bind:value={$settings.lookupPreference} items={lookupPreferences} class='w-32 shrink-0 border-input border' />
</SettingCard>
<div class='px-6'>
<Extensions />
<Extensions bind:importExtension />
</div>
</div>

View file

@ -29,6 +29,7 @@
</script>
<script lang='ts'>
import CircleHelp from 'lucide-svelte/icons/circle-help'
import { persisted } from 'svelte-persisted-store'
import Footer from '../Footer.svelte'
@ -49,7 +50,7 @@
const res = await native.checkIncomingConnections(port)
$hasForwarding = res
if (res) return { status: 'success', text: 'Port forwarding is available.' }
return { status: 'error', text: 'Not available. Peer discovery will suffer. Streaming old, poorly seeded anime might be impossible.' }
return { status: 'error', text: 'Not available. Peer discovery will suffer. Streaming old, poorly seeded anime might be impossible.', slot: 'port' }
}
$: port = $settings.torrentPort
@ -81,4 +82,8 @@
</SettingCard>
</div>
<Footer step={1} {checks} />
<Footer step={1} {checks}>
<div class='contents' on:click={() => native.openURL('https://thewiki.moe/getting-started/torrenting/#port-forwarding')}>
<CircleHelp class='size-4 ml-2 shrink-0 inline cursor-pointer' />
</div>
</Footer>

BIN
static/bg_grid.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB