mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-20 19:02:18 +00:00
fix: improve navigating tabs, threads, menubar, player with keyboard
This commit is contained in:
parent
df57e3bc60
commit
9a230b302d
11 changed files with 42 additions and 31 deletions
|
|
@ -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",
|
||||
|
|
|
|||
30
src/app.css
30
src/app.css
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
type $$Props = TabsPrimitive.ListProps
|
||||
|
||||
let className: $$Props['class']
|
||||
let className: $$Props['class'] = undefined
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}>
|
||||
|
|
|
|||
Loading…
Reference in a new issue