fix: improve navigating tabs, threads, menubar, player with keyboard

This commit is contained in:
ThaUnknown 2025-05-31 02:01:58 +02:00
parent df57e3bc60
commit 9a230b302d
No known key found for this signature in database
11 changed files with 42 additions and 31 deletions

View file

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

View file

@ -166,18 +166,24 @@ a {
color: #737373 !important;
}
a[href]:active,
button:not([disabled], .no-scale):active,
.scale-parent:has(.no-scale:active),
fieldset:not([disabled]):active,
input:not([disabled], [type='range'], .no-scale):active,
optgroup:not([disabled]):active,
option:not([disabled]):active,
select:not([disabled]):active,
textarea:not([disabled]):active,
details:active,
[tabindex]:not([tabindex="-1"]):active,
[contenteditable]:active {
a[href],
button,
fieldset,
input,
optgroup,
option,
select,
textarea,
details,
[tabindex],
[contenteditable] {
&:active:not([disabled], [type='range'], .no-scale, [tabindex="-1"]) {
transition: all 0.1s ease-in-out;
transform: scale(0.98);
}
}
.scale-parent:has(.no-scale:active) {
transition: all 0.1s ease-in-out;
transform: scale(0.98);
}

View file

@ -8,8 +8,8 @@
import Pagination from '../../Pagination.svelte'
import { Button } from '../button'
import { Profile } from '../profile'
import * as Avatar from '$lib/components/ui/avatar'
import * as Tooltip from '$lib/components/ui/tooltip'
import { client, type Media } from '$lib/modules/anilist'
import { isMobile, since } from '$lib/utils'
@ -56,7 +56,7 @@
<div class='flex-grow py-3 px-4 flex flex-col'>
<div class='flex w-full justify-between text-[12.8px]'>
<Tooltip.Root>
<Tooltip.Trigger class='font-bold mb-2 line-clamp-1'>
<Tooltip.Trigger class='font-bold mb-2 line-clamp-1' tabindex={-1}>
{thread.title ?? 'Thread ' + (thread.id)}
</Tooltip.Trigger>
<Tooltip.Content>
@ -78,7 +78,10 @@
<div class='flex w-full justify-between mt-auto text-[9.6px]'>
<div class='pt-2 flex items-end'>
{#if thread.user}
<Profile user={thread.user} class='size-4 mr-2' />
<Avatar.Root class='size-4 mr-2'>
<Avatar.Image src={thread.user.avatar?.medium} alt='avatar' />
<Avatar.Fallback>{thread.user.name}</Avatar.Fallback>
</Avatar.Root>
{/if}
{since(new Date(thread.createdAt * 1000))}
</div>

View file

@ -10,13 +10,13 @@
<div class='w-[calc(100%-3.5rem)] left-[3.5rem] top-0 z-[2000] flex navbar absolute h-8'>
<div class='draggable w-full' />
<div class='window-controls flex text-white backdrop-blur'>
<button class='max-button flex items-center justify-center h-8 w-[46px]' use:click={native.minimise}>
<button class='max-button flex items-center justify-center h-8 w-[46px]' use:click={native.minimise} tabindex={-1}>
<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 class='restore-button flex items-center justify-center h-8 w-[46px]' use:click={native.maximise}>
<button class='restore-button flex items-center justify-center h-8 w-[46px]' use:click={native.maximise} tabindex={-1}>
<svg class='svg-controls w-3 h-3' role='img' viewBox='0 0 12 12'><rect fill='none' height='9' stroke='currentColor' width='9' x='1.5' y='1.5' />
</button>
<button class='close-button flex items-center justify-center h-8 w-[46px]' use:click={native.close}>
<button class='close-button flex items-center justify-center h-8 w-[46px]' use:click={native.close} tabindex={-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>
</div>

View file

@ -206,7 +206,6 @@
if (subtitles?.renderer) {
subtitles.renderer.resize(video.videoWidth, video.videoHeight)
await new Promise(resolve => setTimeout(resolve, 500)) // this is hacky, but TLDR wait for canvas to update and re-render, in practice this will take at MOST 100ms, but just to be safe
// @ts-expect-error internal call on canvas
context.drawImage(subtitles.renderer._canvas, 0, 0, canvas.width, canvas.height)
subtitles.renderer.resize(0, 0, 0, 0) // undo resize
}
@ -736,7 +735,7 @@
</div>
{/if}
<Options {wrapper} bind:openSubs {video} {seekTo} {selectAudio} {selectVideo} {fullscreen} {chapters} {subtitles} {videoFiles} {selectFile} {pip} bind:playbackRate
class='{$settings.minimalPlayerUI ? 'inline-flex' : 'mobile:inline-flex hidden'} p-3 w-12 h-12 absolute top-10 right-10 backdrop-blur-lg border-white/15 border bg-black/20 pointer-events-auto transition-opacity select:opacity-100 {immersed && 'opacity-0'}' />
class='{$settings.minimalPlayerUI ? 'inline-flex' : 'mobile:inline-flex hidden'} p-3 w-12 h-12 absolute top-4 left-4 backdrop-blur-lg border-white/15 border bg-black/20 pointer-events-auto transition-opacity select:opacity-100 {immersed && 'opacity-0'}' />
{#if ff}
<div class='absolute top-10 font-bold text-sm animate-[fade-in_.4s_ease] flex items-center leading-none bg-black/60 px-4 py-2 rounded-2xl'>x2 <FastForward class='ml-2' size='12' fill='currentColor' /></div>
{/if}

View file

@ -367,6 +367,8 @@ export default class Subtitles {
const { name, url } = LANGUAGE_OVERRIDES[track.meta.language ?? '']!
this.addFont(url)
this.renderer.setDefaultFont(name)
} else {
this.renderer.setDefaultFont('roboto medium')
}
this.renderer.resize()
}

View file

@ -12,7 +12,7 @@
user: ResultOf<typeof UserFrag>
}
let className: $$Props['class'] = 'inline-block ring-4 ring-black size-8 bg-black'
let className: $$Props['class'] = 'inline-block ring-4 ring-black size-8 bg-black group-focus-visible/profile:ring-neutral-100 !border-0'
export { className as class }
export let user: ResultOf<typeof UserFrag>
@ -25,8 +25,8 @@
<div class='flex'>
<Popover.Root>
<Popover.Trigger class='flex'>
<Avatar.Root class={className}>
<Popover.Trigger class='flex group/profile'>
<Avatar.Root class={cn('group-focus-visible/profile:border border-white', className)}>
<Avatar.Image src={avatar} alt={name} />
<Avatar.Fallback>{name}</Avatar.Fallback>
</Avatar.Root>

View file

@ -5,7 +5,7 @@
type $$Props = TabsPrimitive.ListProps
let className: $$Props['class']
let className: $$Props['class'] = undefined
export { className as class }
</script>

View file

@ -1,7 +1,7 @@
<script lang='ts'>
import { Tabs as TabsPrimitive } from 'bits-ui'
import { cn } from '$lib/utils.js'
import { cn } from '$lib/utils'
type $$Props = TabsPrimitive.TriggerProps
type $$Events = TabsPrimitive.TriggerEvents
@ -21,6 +21,7 @@
on:click
on:keydown
on:focus
on:keydown={e => e.preventDefault()}
>
<slot />
</TabsPrimitive.Trigger>

View file

@ -159,7 +159,7 @@ function getDistance (anchor: ElementPosition, relative: ElementPosition) {
* Gets keyboard-focusable elements within a specified element.
*/
function getKeyboardFocusableElements (element: Element = document.body) {
return [...element.querySelectorAll<HTMLElement>('a[href], button:not([disabled]), fieldset:not([disabled]), input:not([disabled], [readonly]), optgroup:not([disabled]), option:not([disabled]), select:not([disabled]), textarea:not([disabled]), details, [tabindex]:not([tabindex="-1"], [disabled]), [contenteditable], [controls]')].filter(
return [...element.querySelectorAll<HTMLElement>('a[href], button:not([disabled], [tabindex="-1"]), fieldset:not([disabled]), input:not([disabled], [readonly]), optgroup:not([disabled]), option:not([disabled]), select:not([disabled]), textarea:not([disabled]), details, [tabindex]:not([tabindex="-1"], [disabled]), [contenteditable], [controls]')].filter(
el => !el.getAttribute('aria-hidden')
)
}

View file

@ -60,12 +60,12 @@
</div>
</div>
{/if}
<Tabs.Root bind:value class='w-full'>
<Tabs.Root bind:value class='w-full' activateOnFocus={false}>
<div class='flex justify-between items-center gap-3 sm:flex-row flex-col'>
<Tabs.List class='flex'>
<Tabs.Trigger value='episodes' class='px-8 data-[state=active]:font-bold'>Episodes</Tabs.Trigger>
<Tabs.Trigger value='threads' class='px-8 data-[state=active]:font-bold'>Threads</Tabs.Trigger>
<Tabs.Trigger value='themes' class='px-8 data-[state=active]:font-bold'>Themes</Tabs.Trigger>
<Tabs.Trigger value='episodes' tabindex={0} class='px-8 data-[state=active]:font-bold'>Episodes</Tabs.Trigger>
<Tabs.Trigger value='threads' tabindex={0} class='px-8 data-[state=active]:font-bold'>Threads</Tabs.Trigger>
<Tabs.Trigger value='themes' tabindex={0} class='px-8 data-[state=active]:font-bold'>Themes</Tabs.Trigger>
</Tabs.List>
</div>
<Tabs.Content value='episodes' tabindex={-1}>