mirror of
https://github.com/NoCrypt/migu.git
synced 2026-08-17 20:55:48 +00:00
feat: touchpad and keyboard support
This commit is contained in:
parent
eebb8128d3
commit
dc307ddb84
26 changed files with 156 additions and 114 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Miru",
|
||||
"version": "4.1.10",
|
||||
"version": "4.1.11",
|
||||
"author": "ThaUnknown_ <ThaUnknown@users.noreply.github.com>",
|
||||
"description": "Stream anime torrents, real-time with no waiting for downloads.",
|
||||
"main": "build/main.js",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
const { app, BrowserWindow, protocol, shell, ipcMain, dialog, MessageChannelMain } = require('electron')
|
||||
const path = require('path')
|
||||
const { Client } = require('discord-rpc')
|
||||
const log = require('electron-log')
|
||||
const { autoUpdater } = require('electron-updater')
|
||||
import { app, BrowserWindow, protocol, shell, ipcMain, dialog, MessageChannelMain } from 'electron'
|
||||
import path from 'path'
|
||||
import { Client } from 'discord-rpc'
|
||||
import log from 'electron-log'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
|
||||
const flags = [
|
||||
['enable-gpu-rasterization'],
|
||||
|
|
@ -144,7 +144,7 @@ function createWindow () {
|
|||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.webRequest.onHeadersReceived({ urls: ['https://sneedex.moe/api/public/nyaa'] }, ({ responseHeaders, url }, fn) => {
|
||||
mainWindow.webContents.session.webRequest.onHeadersReceived({ urls: ['https://sneedex.moe/api/public/nyaa', 'http://animetosho.org/storage/torrent/*'] }, ({ responseHeaders }, fn) => {
|
||||
responseHeaders['Access-Control-Allow-Origin'] = '*'
|
||||
|
||||
fn({ responseHeaders })
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { getContext } from 'svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
export let page
|
||||
const view = getContext('view')
|
||||
|
|
@ -14,7 +15,7 @@
|
|||
<div class='w-full z-50 navbar bg-transparent border-0 p-0 d-flex'>
|
||||
<div class='d-flex h-full draggable align-items-center text-center'>
|
||||
{#if window.version.platform !== 'darwin'}
|
||||
<img src='./logo.ico' class='position-absolute w-50 h-50 m-10 pointer' alt='ico' on:pointerdown={close} />
|
||||
<img src='./logo.ico' class='position-absolute w-50 h-50 m-10 pointer' alt='ico' use:click={close} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class='h-full bg-dark flex-grow-1' />
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<script>
|
||||
import { traceAnime } from '@/modules/anime.js'
|
||||
import { set } from '../views/Settings.svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
export let search
|
||||
let searchTextInput
|
||||
|
|
@ -179,7 +180,7 @@
|
|||
</div>
|
||||
<div class='col-auto p-10 d-flex'>
|
||||
<div class='align-self-end'>
|
||||
<button class='btn btn-square bg-dark-light material-symbols-outlined font-size-18 px-5 align-self-end border-0' type='button' on:click={searchClear} class:text-primary={!!sanitisedSearch?.length}>
|
||||
<button class='btn btn-square bg-dark-light material-symbols-outlined font-size-18 px-5 align-self-end border-0' type='button' use:click={searchClear} class:text-primary={!!sanitisedSearch?.length}>
|
||||
delete
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -192,8 +193,8 @@
|
|||
<span class='badge bg-light border-0 py-5 px-10 text-capitalize mr-20 text-white text-nowrap'>{('' + badge).replace(/_/g, ' ').toLowerCase()}</span>
|
||||
{/each}
|
||||
{/if}
|
||||
<span class='material-symbols-outlined font-size-24 mr-10 filled ml-auto text-dark-light pointer' class:text-muted={set.cards === 'small'} on:click={() => changeCardMode('small')}>grid_on</span>
|
||||
<span class='material-symbols-outlined font-size-24 filled text-dark-light pointer' class:text-muted={set.cards === 'full'} on:click={() => changeCardMode('full')}>grid_view</span>
|
||||
<span class='material-symbols-outlined font-size-24 mr-10 filled ml-auto text-dark-light pointer' class:text-muted={set.cards === 'small'} use:click={() => changeCardMode('small')}>grid_on</span>
|
||||
<span class='material-symbols-outlined font-size-24 filled text-dark-light pointer' class:text-muted={set.cards === 'full'} use:click={() => changeCardMode('full')}>grid_view</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import { media } from '../views/Player/MediaHandler.svelte'
|
||||
import { platformMap } from '../views/Settings.svelte'
|
||||
import { addToast } from './Toasts.svelte'
|
||||
import { wrapEnter } from '@/modules/util.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
const view = getContext('view')
|
||||
export let page
|
||||
const links = [
|
||||
|
|
@ -97,13 +97,10 @@
|
|||
|
||||
<div class='sidebar z-30'>
|
||||
<div class='sidebar-menu h-full d-flex flex-column justify-content-center align-items-center m-0 pb-5' class:animate={page !== 'player'}>
|
||||
{#each links as { click, icon, text, image, css, page: _page }, i (i)}
|
||||
{#each links as { click: _click, icon, text, image, css, page: _page }, i (i)}
|
||||
<div
|
||||
class='sidebar-link sidebar-link-with-icon pointer overflow-hidden {css}'
|
||||
tabindex='0'
|
||||
role='button'
|
||||
on:click={click}
|
||||
on:keydown={wrapEnter(click)}>
|
||||
use:click={_click}>
|
||||
<span class='text-nowrap d-flex align-items-center w-full h-full'>
|
||||
{#if image}
|
||||
<span class='material-symbols-outlined rounded' class:filled={page === _page}>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { getContext } from 'svelte'
|
||||
import { TABS } from './Tabs.svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
const tab = {}
|
||||
const { registerTab, selectTab, selectedTab } = getContext(TABS)
|
||||
|
|
@ -8,6 +9,6 @@
|
|||
registerTab(tab)
|
||||
</script>
|
||||
|
||||
<div class={'pointer border-bottom ' + ($selectedTab === tab ? 'bg-dark-light' : '')} on:click={() => selectTab(tab)}>
|
||||
<div class={'pointer border-bottom ' + ($selectedTab === tab ? 'bg-dark-light' : '')} use:click={() => selectTab(tab)}>
|
||||
<slot />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script context='module'>
|
||||
import { writable } from 'svelte/store'
|
||||
import { click } from '@/modules/click.js'
|
||||
const toasts = writable({})
|
||||
let index = 0
|
||||
export function addToast (opts) {
|
||||
|
|
@ -25,8 +26,8 @@
|
|||
|
||||
<div class='sticky-alerts d-flex flex-column-reverse'>
|
||||
{#each Object.entries($toasts) as [index, toast] (index)}
|
||||
<div class='alert alert-{toast.type} filled' class:pointer={toast.click} on:click={toast.click}>
|
||||
<button class='close' type='button' on:click={() => close(index)}><span aria-hidden='true'>×</span></button>
|
||||
<div class='alert alert-{toast.type} filled' class:pointer={toast.click} use:click={toast.click}>
|
||||
<button class='close' type='button' use:click={() => close(index)}><span aria-hidden='true'>×</span></button>
|
||||
<h4 class='alert-heading'>{toast.title}</h4>
|
||||
{@html toast.text}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { formatMap, setStatus, playMedia } from '@/modules/anime.js'
|
||||
import { alRequest } from '@/modules/anilist.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
export let media
|
||||
|
||||
async function toggleStatus () {
|
||||
|
|
@ -68,13 +69,13 @@
|
|||
</div>
|
||||
<div class='d-flex flex-row pb-20'>
|
||||
<button class='btn bg-dark-light px-20 shadow-none border-0'
|
||||
on:pointerdown|stopPropagation={() => playMedia(media)}>
|
||||
use:click={() => playMedia(media)}>
|
||||
Watch Now
|
||||
</button>
|
||||
<button class='btn bg-dark-light btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.isFavourite} on:pointerdown|stopPropagation={() => toggleFavourite(media)}>
|
||||
<button class='btn bg-dark-light btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.isFavourite} use:click={toggleFavourite}>
|
||||
favorite
|
||||
</button>
|
||||
<button class='btn bg-dark-light btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.mediaListEntry} on:pointerdown|stopPropagation={() => toggleStatus(media)}>
|
||||
<button class='btn bg-dark-light btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.mediaListEntry} use:click={toggleStatus}>
|
||||
bookmark
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { statusColorMap } from '@/modules/anime.js'
|
||||
import EpisodePreviewCard from './EpisodePreviewCard.svelte'
|
||||
import { hoverClick } from '@/modules/click.js'
|
||||
import { since } from '@/modules/util'
|
||||
export let data
|
||||
|
||||
|
|
@ -9,7 +10,7 @@
|
|||
const episodeThumbnail = data.episodeData?.image || data.media?.bannerImage || data.media?.coverImage?.extraLarge || ' '
|
||||
</script>
|
||||
|
||||
<div class='d-flex pt-20 px-20 position-relative' on:pointerenter={() => { preview = true }} on:pointerleave={() => { preview = false }} on:pointerdown={data.onclick}>
|
||||
<div class='d-flex pt-20 px-20 position-relative' on:pointerenter={() => { preview = true }} on:custom-pointerleave={() => { preview = false }} use:hoverClick={data.onclick}>
|
||||
{#if preview}
|
||||
<EpisodePreviewCard {data} />
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { getContext } from 'svelte'
|
||||
import PreviewCard from './PreviewCard.svelte'
|
||||
import { formatMap, statusColorMap } from '@/modules/anime.js'
|
||||
import { hoverClick } from '@/modules/click.js'
|
||||
export let media
|
||||
let preview = false
|
||||
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class='d-flex px-20 py-10 position-relative' on:pointerenter={() => { preview = true }} on:pointerleave={() => { preview = false }} on:pointerdown={viewMedia}>
|
||||
<div class='d-flex px-20 py-10 position-relative' on:pointerenter={() => { preview = true }} on:custom-pointerleave={() => { preview = false }} use:hoverClick={viewMedia}>
|
||||
{#if preview}
|
||||
<PreviewCard {media} />
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { formatMap, setStatus, playMedia } from '@/modules/anime.js'
|
||||
import { alRequest } from '@/modules/anilist.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
export let media
|
||||
|
||||
let hide = true
|
||||
|
|
@ -40,6 +41,10 @@
|
|||
})
|
||||
media.isFavourite = !media.isFavourite
|
||||
}
|
||||
function play () {
|
||||
if (media.status === 'NOT_YET_RELEASED') return
|
||||
playMedia(media)
|
||||
}
|
||||
// TODO: add a volume toggle icon for trailer
|
||||
function volume (video) {
|
||||
video.volume = 0.05
|
||||
|
|
@ -78,14 +83,14 @@
|
|||
</div>
|
||||
<div class='d-flex flex-row pt-5'>
|
||||
<button class='btn btn-secondary flex-grow-1 text-dark font-weight-bold shadow-none border-0'
|
||||
on:pointerdown|stopPropagation={() => media.status !== 'NOT_YET_RELEASED' && playMedia(media)}
|
||||
use:click={play}
|
||||
disabled={media.status === 'NOT_YET_RELEASED'}>
|
||||
{playButtonText}
|
||||
</button>
|
||||
<button class='btn btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.isFavourite} on:pointerdown|stopPropagation={toggleFavourite}>
|
||||
<button class='btn btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.isFavourite} use:click={toggleFavourite}>
|
||||
favorite
|
||||
</button>
|
||||
<button class='btn btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.mediaListEntry} on:pointerdown|stopPropagation={toggleStatus}>
|
||||
<button class='btn btn-square ml-10 material-symbols-outlined font-size-16 shadow-none border-0' class:filled={media.mediaListEntry} use:click={toggleStatus}>
|
||||
bookmark
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { getContext } from 'svelte'
|
||||
import PreviewCard from './PreviewCard.svelte'
|
||||
import { formatMap, statusColorMap } from '@/modules/anime.js'
|
||||
import { hoverClick } from '@/modules/click.js'
|
||||
export let media
|
||||
let preview = false
|
||||
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class='d-flex p-20 position-relative first-check' on:pointerenter={() => { preview = true }} on:pointerleave={() => { preview = false }} on:pointerdown={viewMedia}>
|
||||
<div class='d-flex p-20 position-relative first-check' on:pointerenter={() => { preview = true }} on:custom-pointerleave={() => { preview = false }} use:hoverClick={viewMedia}>
|
||||
{#if preview}
|
||||
<PreviewCard {media} />
|
||||
{/if}
|
||||
|
|
|
|||
38
src/renderer/modules/click.js
Normal file
38
src/renderer/modules/click.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
let lastTapElement = null
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
document.addEventListener('pointerup', () => {
|
||||
lastTapElement?.dispatchEvent(new Event('custom-pointerleave'))
|
||||
lastTapElement = null
|
||||
})
|
||||
|
||||
export function click (node, cb = noop) {
|
||||
node.tabIndex = 0
|
||||
node.role = 'button'
|
||||
node.addEventListener('pointerup', e => {
|
||||
e.stopPropagation()
|
||||
cb(e)
|
||||
})
|
||||
node.addEventListener('keydown', e => { if (e.key === 'Enter') cb(e) })
|
||||
}
|
||||
|
||||
export function hoverClick (node, cb = noop) {
|
||||
node.tabIndex = 0
|
||||
node.role = 'button'
|
||||
node.addEventListener('pointerup', e => {
|
||||
if (e.pointerType === 'mouse') return cb(e)
|
||||
e.stopPropagation()
|
||||
lastTapElement?.dispatchEvent(new Event('custom-pointerleave'))
|
||||
if (lastTapElement === node) {
|
||||
lastTapElement = null
|
||||
cb(e)
|
||||
} else {
|
||||
lastTapElement = node
|
||||
}
|
||||
})
|
||||
node.addEventListener('keydown', e => { if (e.key === 'Enter') cb(e) })
|
||||
node.addEventListener('pointerleave', ({ pointerType }) => {
|
||||
if (pointerType === 'mouse') node.dispatchEvent(new Event('custom-pointerleave'))
|
||||
})
|
||||
}
|
||||
|
|
@ -119,12 +119,6 @@ export function debounce (fn, time) {
|
|||
}
|
||||
};
|
||||
|
||||
export function wrapEnter (fn) {
|
||||
return ({ key }) => {
|
||||
if (key === 'Enter') fn()
|
||||
}
|
||||
}
|
||||
|
||||
export function binarySearch (arr, el) {
|
||||
let left = 0
|
||||
let right = arr.length - 1
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import Card from '@/components/cards/Card.svelte'
|
||||
import { search } from '../Search.svelte'
|
||||
import { page } from '@/App.svelte'
|
||||
import { wrapEnter } from '@/modules/util.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
export let opts
|
||||
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
observer.observe(element)
|
||||
}
|
||||
|
||||
function click () {
|
||||
function _click () {
|
||||
$search = {
|
||||
...opts.variables,
|
||||
load: opts.load
|
||||
|
|
@ -31,10 +31,8 @@
|
|||
</script>
|
||||
|
||||
<span class='d-flex px-20 align-items-end pointer text-decoration-none text-muted'
|
||||
on:click={click} on:keydown={wrapEnter(click)}
|
||||
tabindex='0'
|
||||
use:deferredLoad
|
||||
role='button'>
|
||||
use:click={_click}
|
||||
use:deferredLoad>
|
||||
<div class='font-size-24 font-weight-semi-bold'>{opts.title}</div>
|
||||
<div class='pr-10 ml-auto font-size-12'>View More</div>
|
||||
</span>
|
||||
|
|
@ -57,4 +55,7 @@
|
|||
background: linear-gradient(270deg, #17191cff 0%, #17191c00 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.gallery {
|
||||
overflow-x: clip
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { set } from './Settings.svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
let block = false
|
||||
|
||||
async function testConnection () {
|
||||
|
|
@ -25,11 +26,11 @@
|
|||
<div class='font-size-16'>Most features of Miru will not function correctly without being able to connect to Tosho.</div>
|
||||
<div class='font-size-16'>If you enable a VPN a restart might be required for it to take effect.</div>
|
||||
<!-- eslint-disable-next-line svelte/valid-compile -->
|
||||
<div class='font-size-16'>Visit <a class='text-primary pointer' on:click={() => { window.IPC.emit('open', 'https://thewiki.moe/tutorials/unblock/') }}>this guide</a> for a tutorial on how to bypass ISP blocks.</div>
|
||||
<div class='font-size-16'>Visit <a class='text-primary pointer' use:click={() => { window.IPC.emit('open', 'https://thewiki.moe/tutorials/unblock/') }}>this guide</a> for a tutorial on how to bypass ISP blocks.</div>
|
||||
<div class='d-flex w-full mt-20 pt-20'>
|
||||
<button class='btn ml-auto mr-5' type='button' on:click={() => { block = false }}>I Understand</button>
|
||||
<button class='btn btn-primary mr-5' type='button' on:click={() => { window.IPC.emit('open', 'https://thewiki.moe/tutorials/unblock/') }}>Open Guide</button>
|
||||
<button class='btn btn-primary' type='button' on:click={testConnection}>Reconnect</button>
|
||||
<button class='btn ml-auto mr-5' type='button' use:click={() => { block = false }}>I Understand</button>
|
||||
<button class='btn btn-primary mr-5' type='button' use:click={() => { window.IPC.emit('open', 'https://thewiki.moe/tutorials/unblock/') }}>Open Guide</button>
|
||||
<button class='btn btn-primary' type='button' use:click={testConnection}>Reconnect</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
import { createEventDispatcher } from 'svelte'
|
||||
import { alEntry } from '@/modules/anilist.js'
|
||||
import Subtitles from '@/modules/subtitles.js'
|
||||
import { toTS, videoRx, fastPrettyBytes, wrapEnter } from '@/modules/util.js'
|
||||
import { toTS, videoRx, fastPrettyBytes } from '@/modules/util.js'
|
||||
import { addToast } from '../../components/Toasts.svelte'
|
||||
import { getChaptersAniSkip } from '@/modules/anime.js'
|
||||
import Seekbar from 'perfect-seekbar'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
import { w2gEmitter } from '../WatchTogether/WatchTogether.svelte'
|
||||
import Keybinds, { loadWithDefaults, condition } from 'svelte-keybinds'
|
||||
|
|
@ -880,8 +881,8 @@
|
|||
on:keypress={resetImmerse}
|
||||
on:mouseleave={immersePlayer}>
|
||||
{#if showKeybinds && !miniplayer}
|
||||
<div class='position-absolute bg-tp w-full h-full z-50 font-size-12 p-20 d-flex align-items-center justify-content-center' on:click|self={() => (showKeybinds = false)} on:keydown={wrapEnter(() => (showKeybinds = false))}>
|
||||
<button class='btn btn-square rounded-circle bg-dark font-size-16 top-0 right-0 m-10 position-absolute' type='button' on:click={() => (showKeybinds = false)} on:keydown={wrapEnter(() => (showKeybinds = false))}>×</button>
|
||||
<div class='position-absolute bg-tp w-full h-full z-50 font-size-12 p-20 d-flex align-items-center justify-content-center'>
|
||||
<button class='btn btn-square rounded-circle bg-dark font-size-16 top-0 right-0 m-10 position-absolute' type='button' use:click={() => (showKeybinds = false)}>×</button>
|
||||
<Keybinds let:prop={item} autosave={true} clickable={true}>
|
||||
<div class:material-symbols-outlined={item?.type} class='bind'>{item?.id || ''}</div>
|
||||
</Keybinds>
|
||||
|
|
@ -925,7 +926,7 @@
|
|||
on:leavepictureinpicture={() => (pip = false)} />
|
||||
{#if stats}
|
||||
<div class='position-absolute top-0 bg-tp p-10 m-15 text-monospace rounded z-50'>
|
||||
<button class='close' type='button' on:click={toggleStats}><span>×</span></button>
|
||||
<button class='close' type='button' use:click={toggleStats}><span>×</span></button>
|
||||
FPS: {stats.fps}<br />
|
||||
Presented frames: {stats.presented}<br />
|
||||
Dropped frames: {stats.dropped}<br />
|
||||
|
|
@ -950,15 +951,15 @@
|
|||
<div class='col-4' />
|
||||
</div>
|
||||
<div class='middle d-flex align-items-center justify-content-center flex-grow-1 position-relative'>
|
||||
<div class='w-full h-full position-absolute' on:dblclick={toggleFullscreen} on:click|self={() => { if (page === 'player') playPause(); page = 'player' }} on:keydown={wrapEnter(() => { if (page === 'player') playPause(); page = 'player' })} />
|
||||
<span class='material-symbols-outlined ctrl' class:text-muted={!hasLast} class:disabled={!hasLast} data-name='playLast' on:pointerdown={playLast}> skip_previous </span>
|
||||
<span class='material-symbols-outlined ctrl' data-name='rewind' on:pointerdown={rewind}> fast_rewind </span>
|
||||
<span class='material-symbols-outlined ctrl' data-name='playPause' on:pointerdown={playPause}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
|
||||
<span class='material-symbols-outlined ctrl' data-name='forward' on:pointerdown={forward}> fast_forward </span>
|
||||
<span class='material-symbols-outlined ctrl' class:text-muted={!hasNext} class:disabled={!hasNext} data-name='playNext' on:pointerdown={playNext}> skip_next </span>
|
||||
<div class='w-full h-full position-absolute' on:dblclick={toggleFullscreen} on:click|self={() => { if (page === 'player') playPause(); page = 'player' }} />
|
||||
<span class='material-symbols-outlined ctrl' class:text-muted={!hasLast} class:disabled={!hasLast} data-name='playLast' use:click={playLast}> skip_previous </span>
|
||||
<span class='material-symbols-outlined ctrl' data-name='rewind' use:click={rewind}> fast_rewind </span>
|
||||
<span class='material-symbols-outlined ctrl' data-name='playPause' use:click={playPause}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
|
||||
<span class='material-symbols-outlined ctrl' data-name='forward' use:click={forward}> fast_forward </span>
|
||||
<span class='material-symbols-outlined ctrl' class:text-muted={!hasNext} class:disabled={!hasNext} data-name='playNext' use:click={playNext}> skip_next </span>
|
||||
<div class='position-absolute bufferingDisplay' />
|
||||
{#if currentSkippable}
|
||||
<button class='skip btn text-dark position-absolute bottom-0 right-0 mr-20 mb-5 font-weight-bold' on:click={skip}>
|
||||
<button class='skip btn text-dark position-absolute bottom-0 right-0 mr-20 mb-5 font-weight-bold' use:click={skip}>
|
||||
Skip {currentSkippable}
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -978,28 +979,28 @@
|
|||
/>
|
||||
</div>
|
||||
<div class='d-flex'>
|
||||
<span class='material-symbols-outlined ctrl' title='Play/Pause [Space]' data-name='playPause' on:click={playPause} on:keydown={wrapEnter(playPause)}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
|
||||
<span class='material-symbols-outlined ctrl' title='Play/Pause [Space]' data-name='playPause' use:click={playPause}> {ended ? 'replay' : paused ? 'play_arrow' : 'pause'} </span>
|
||||
{#if hasLast}
|
||||
<span class='material-symbols-outlined ctrl' title='Last [B]' data-name='playLast' on:click={playLast} on:keydown={wrapEnter(playLast)}> skip_previous </span>
|
||||
<span class='material-symbols-outlined ctrl' title='Last [B]' data-name='playLast' use:click={playLast}> skip_previous </span>
|
||||
{/if}
|
||||
{#if hasNext}
|
||||
<span class='material-symbols-outlined ctrl' title='Next [N]' data-name='playNext' on:click={playNext} on:keydown={wrapEnter(playNext)}> skip_next </span>
|
||||
<span class='material-symbols-outlined ctrl' title='Next [N]' data-name='playNext' use:click={playNext}> skip_next </span>
|
||||
{/if}
|
||||
<div class='d-flex w-auto volume'>
|
||||
<span class='material-symbols-outlined ctrl' title='Mute [M]' data-name='toggleMute' on:click={toggleMute} on:keydown={wrapEnter(toggleMute)}> {muted ? 'volume_off' : 'volume_up'} </span>
|
||||
<span class='material-symbols-outlined ctrl' title='Mute [M]' data-name='toggleMute' use:click={toggleMute}> {muted ? 'volume_off' : 'volume_up'} </span>
|
||||
<input class='ctrl h-full custom-range' type='range' min='0' max='1' step='any' data-name='setVolume' bind:value={volume} />
|
||||
</div>
|
||||
<div class='ts mr-auto'>{toTS(targetTime, safeduration > 3600 ? 2 : 3)} / {toTS(safeduration - targetTime, safeduration > 3600 ? 2 : 3)}</div>
|
||||
<span class='material-symbols-outlined ctrl' title='Keybinds [`]' on:pointerdown={() => (showKeybinds = true)}> keyboard </span>
|
||||
<span class='material-symbols-outlined ctrl' title='Keybinds [`]' use:click={() => (showKeybinds = true)}> keyboard </span>
|
||||
{#if 'audioTracks' in HTMLVideoElement.prototype && video?.audioTracks?.length > 1}
|
||||
<div class='dropdown dropup with-arrow' on:click={toggleDropdown} on:keydown={wrapEnter(toggleDropdown)}>
|
||||
<div class='dropdown dropup with-arrow' use:click={toggleDropdown}>
|
||||
<span class='material-symbols-outlined ctrl' title='Audio Tracks'>
|
||||
queue_music
|
||||
</span>
|
||||
<div class='dropdown-menu dropdown-menu-left ctrl custom-radio p-10 pb-5 text-capitalize'>
|
||||
{#each video.audioTracks as track}
|
||||
<input name='audio-radio-set' type='radio' id='audio-{track.id}-radio' value={track.id} checked={track.enabled} />
|
||||
<label for='audio-{track.id}-radio' on:pointerdown|stopPropagation={() => selectAudio(track.id)} class='text-truncate pb-5'>
|
||||
<label for='audio-{track.id}-radio' use:click={() => selectAudio(track.id)} class='text-truncate pb-5'>
|
||||
{(track.language || (!Object.values(video.audioTracks).some(track => track.language === 'eng' || track.language === 'en') ? 'eng' : track.label)) + (track.label ? ' - ' + track.label : '')}
|
||||
</label>
|
||||
{/each}
|
||||
|
|
@ -1014,7 +1015,7 @@
|
|||
<div class='dropdown-menu dropdown-menu-left ctrl custom-radio p-10 pb-5 text-capitalize'>
|
||||
{#each video.videoTracks as track}
|
||||
<input name='video-radio-set' type='radio' id='video-{track.id}-radio' value={track.id} checked={track.selected} />
|
||||
<label for='video-{track.id}-radio' on:click|stopPropagation={() => selectVideo(track.id)} class='text-truncate pb-5' on:keydown={wrapEnter(() => selectVideo(track.id))}>
|
||||
<label for='video-{track.id}-radio' use:click={() => selectVideo(track.id)} class='text-truncate pb-5'>
|
||||
{(track.language || (!Object.values(video.videoTracks).some(track => track.language === 'eng' || track.language === 'en') ? 'eng' : track.label)) + (track.label ? ' - ' + track.label : '')}
|
||||
</label>
|
||||
{/each}
|
||||
|
|
@ -1022,17 +1023,17 @@
|
|||
</div>
|
||||
{/if}
|
||||
{#if subHeaders?.length}
|
||||
<div class='subtitles dropdown dropup with-arrow' on:click={toggleDropdown} on:keydown={wrapEnter(toggleDropdown)}>
|
||||
<div class='subtitles dropdown dropup with-arrow' use:click={toggleDropdown}>
|
||||
<span class='material-symbols-outlined ctrl' title='Subtitles [C]'>
|
||||
subtitles
|
||||
</span>
|
||||
<div class='dropdown-menu dropdown-menu-right ctrl custom-radio p-10 pb-5 text-capitalize w-200'>
|
||||
<input name='subtitle-radio-set' type='radio' id='subtitle-off-radio' value='off' checked={subHeaders && subs?.current === -1} />
|
||||
<label for='subtitle-off-radio' on:click|stopPropagation={() => subs.selectCaptions(-1)} class='text-truncate pb-5' on:keydown={wrapEnter(() => subs.selectCaptions(-1))}> OFF </label>
|
||||
<label for='subtitle-off-radio' use:click={() => subs.selectCaptions(-1)} class='text-truncate pb-5'> OFF </label>
|
||||
{#each subHeaders as track}
|
||||
{#if track}
|
||||
<input name='subtitle-radio-set' type='radio' id='subtitle-{track.number}-radio' value={track.numer} checked={track.number === subs.current} />
|
||||
<label for='subtitle-{track.nubmer}-radio' on:click={() => subs.selectCaptions(track.number)} on:keydown={wrapEnter(() => subs.selectCaptions(track.number))} class='text-truncate pb-5'>
|
||||
<label for='subtitle-{track.nubmer}-radio' use:click={() => subs.selectCaptions(track.number)} class='text-truncate pb-5'>
|
||||
{(track.language || (!Object.values(subs.headers).some(header => header.language === 'eng' || header.language === 'en') ? 'eng' : track.type)) + (track.name ? ' - ' + track.name : '')}
|
||||
</label>
|
||||
{/if}
|
||||
|
|
@ -1042,16 +1043,16 @@
|
|||
</div>
|
||||
{/if}
|
||||
{#if 'PresentationRequest' in window && canCast && current}
|
||||
<span class='material-symbols-outlined ctrl' title='Cast Video [D]' data-name='toggleCast' on:click={toggleCast} on:keydown={wrapEnter(toggleCast)}>
|
||||
<span class='material-symbols-outlined ctrl' title='Cast Video [D]' data-name='toggleCast' use:click={toggleCast}>
|
||||
{presentationConnection ? 'cast_connected' : 'cast'}
|
||||
</span>
|
||||
{/if}
|
||||
{#if 'pictureInPictureEnabled' in document}
|
||||
<span class='material-symbols-outlined ctrl' title='Popout Window [P]' data-name='togglePopout' on:click={togglePopout} on:keydown={wrapEnter(togglePopout)}>
|
||||
<span class='material-symbols-outlined ctrl' title='Popout Window [P]' data-name='togglePopout' use:click={togglePopout}>
|
||||
{pip ? 'featured_video' : 'picture_in_picture'}
|
||||
</span>
|
||||
{/if}
|
||||
<span class='material-symbols-outlined ctrl' title='Fullscreen [F]' data-name='toggleFullscreen' on:click={toggleFullscreen} on:keydown={wrapEnter(toggleFullscreen)}>
|
||||
<span class='material-symbols-outlined ctrl' title='Fullscreen [F]' data-name='toggleFullscreen' use:click={toggleFullscreen}>
|
||||
{isFullscreen ? 'fullscreen_exit' : 'fullscreen'}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<script context='module'>
|
||||
import { wrapEnter, since } from '@/modules/util.js'
|
||||
import { since } from '@/modules/util.js'
|
||||
import { set } from './Settings.svelte'
|
||||
import { addToast } from '../components/Toasts.svelte'
|
||||
import { findInCurrent } from './Player/MediaHandler.svelte'
|
||||
import getRSSEntries from '@/modules/providers/tosho.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
|
|
@ -72,11 +73,11 @@
|
|||
$: table && modal?.focus()
|
||||
</script>
|
||||
|
||||
<div class='modal z-40' class:show={table} id='viewAnime' on:keydown={checkClose} tabindex='-1' bind:this={modal}>
|
||||
<div class='modal z-40' class:show={table} id='viewAnime'>
|
||||
{#if table}
|
||||
<div class='modal-dialog p-20' role='document' on:click|self={close} on:keydown|self={wrapEnter(close)}>
|
||||
<div class='modal-dialog p-20' on:pointerup|self={close} on:keydown={checkClose} tabindex='-1' role='button' bind:this={modal}>
|
||||
<div class='modal-content w-auto'>
|
||||
<button class='close pointer z-30 right-0 position-absolute' type='button' on:click={close}> × </button>
|
||||
<button class='close pointer z-30 right-0 position-absolute' type='button' use:click={close}> × </button>
|
||||
<table class='table table-hover'>
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -92,7 +93,7 @@
|
|||
</thead>
|
||||
<tbody class='results pointer'>
|
||||
{#each table as row, index}
|
||||
<tr class:text-primary={row.best} on:click={() => play(row)} on:keydown={wrapEnter(() => play(row))} tabindex='0' role='button'>
|
||||
<tr class:text-primary={row.best} use:click={() => play(row)}>
|
||||
<th>{index + 1}</th>
|
||||
<td>{row.title}</td>
|
||||
<td>{row.size}</td>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script context='module'>
|
||||
import { addToast } from '../components/Toasts.svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
export let alToken = localStorage.getItem('ALtoken') || null
|
||||
const defaults = {
|
||||
playerAutoplay: true,
|
||||
|
|
@ -183,7 +184,7 @@
|
|||
</TabLabel>
|
||||
{/each}
|
||||
<button
|
||||
on:click={() => window.IPC.emit('open', 'https://github.com/sponsors/ThaUnknown/')}
|
||||
use:click={() => window.IPC.emit('open', 'https://github.com/sponsors/ThaUnknown/')}
|
||||
class='btn btn-primary mx-20 mt-auto'
|
||||
type='button'
|
||||
data-toggle='tooltip'
|
||||
|
|
@ -192,7 +193,7 @@
|
|||
Donate
|
||||
</button>
|
||||
<button
|
||||
on:click={checkUpdate}
|
||||
use:click={checkUpdate}
|
||||
class='btn btn-primary mx-20 mt-10'
|
||||
type='button'
|
||||
data-toggle='tooltip'
|
||||
|
|
@ -201,7 +202,7 @@
|
|||
Check For Updates
|
||||
</button>
|
||||
<button
|
||||
on:click={restoreSettings}
|
||||
use:click={restoreSettings}
|
||||
class='btn btn-danger mx-20 mt-10'
|
||||
type='button'
|
||||
data-toggle='tooltip'
|
||||
|
|
@ -357,12 +358,12 @@
|
|||
<option value='Erai-raws [Multi-Sub]'>{set.toshoURL + 'rss2?qx=1&q="[Erai-raws] "'}</option>
|
||||
</datalist>
|
||||
<div class='input-group-append'>
|
||||
<button type='button' on:click={() => { settings.rssFeedsNew.splice(i, 1); settings.rssFeedsNew = settings.rssFeedsNew }} class='btn btn-danger btn-lg input-group-append'>Remove</button>
|
||||
<button type='button' use:click={() => { settings.rssFeedsNew.splice(i, 1); settings.rssFeedsNew = settings.rssFeedsNew }} class='btn btn-danger btn-lg input-group-append'>Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
<div class='input-group input-group-lg form-control-lg mb-10 w-500'>
|
||||
<button type='button' on:click={() => { settings.rssFeedsNew[settings.rssFeedsNew.length] = ['New Releases', null] }} class='btn btn-lg btn-primary mb-10'>Add Feed</button>
|
||||
<button type='button' use:click={() => { settings.rssFeedsNew[settings.rssFeedsNew.length] = ['New Releases', null] }} class='btn btn-lg btn-primary mb-10'>Add Feed</button>
|
||||
</div>
|
||||
<div class='input-group mb-10 w-300 form-control-lg' data-toggle='tooltip' data-placement='top' data-title='What Quality To Find Torrents In'>
|
||||
<div class='input-group-prepend'>
|
||||
|
|
@ -422,7 +423,7 @@
|
|||
data-placement='bottom'
|
||||
data-title='Path To Folder Which To Use To Store Torrent Files'>
|
||||
<div class='input-group-prepend'>
|
||||
<button type='button' on:click={handleFolder} class='btn btn-primary input-group-append'>Select Folder</button>
|
||||
<button type='button' use:click={handleFolder} class='btn btn-primary input-group-append'>Select Folder</button>
|
||||
</div>
|
||||
<input type='text' class='form-control' bind:value={settings.torrentPath} placeholder='Folder Path' />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { getContext } from 'svelte'
|
||||
import { getMediaMaxEp } from '@/modules/anime.js'
|
||||
import { playAnime } from '../RSSView.svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
export let media = null
|
||||
|
||||
const toggleStatusMap = {
|
||||
|
|
@ -106,12 +107,12 @@
|
|||
<button
|
||||
class='btn btn-primary d-flex align-items-center font-weight-bold font-size-24 h-50 mb-5'
|
||||
type='button'
|
||||
on:click={() => play(media)}>
|
||||
use:click={() => play(media)}>
|
||||
<span class='material-symbols-outlined mr-10 font-size-24 w-30'> play_arrow </span>
|
||||
<span>{getPlayText(media)}</span>
|
||||
</button>
|
||||
{#if alToken}
|
||||
<button class='btn d-flex align-items-center mb-5 font-weight-bold font-size-16 btn-primary' on:click={toggleStatus}>
|
||||
<button class='btn d-flex align-items-center mb-5 font-weight-bold font-size-16 btn-primary' use:click={toggleStatus}>
|
||||
<span class='material-symbols-outlined mr-10 font-size-18 w-30'> {(media.mediaListEntry?.status in toggleStatusMap) ? 'remove' : 'add'} </span>
|
||||
{getStatusText(media)}
|
||||
</button>
|
||||
|
|
@ -135,17 +136,17 @@
|
|||
</div>
|
||||
{/if}
|
||||
{#if media.trailer}
|
||||
<button class='btn d-flex align-items-center mb-5 font-weight-bold font-size-16' on:click={() => viewTrailer(media)}>
|
||||
<button class='btn d-flex align-items-center mb-5 font-weight-bold font-size-16' use:click={() => viewTrailer(media)}>
|
||||
<span class='material-symbols-outlined mr-15 font-size-18 w-30'> live_tv </span>
|
||||
Trailer
|
||||
</button>
|
||||
{/if}
|
||||
<div class='d-flex mb-5 w-full'>
|
||||
<button class='btn flex-fill font-weight-bold font-size-16 d-flex align-items-center' on:click={() => { openInBrowser(`https://anilist.co/anime/${media.id}`) }}>
|
||||
<button class='btn flex-fill font-weight-bold font-size-16 d-flex align-items-center' use:click={() => { openInBrowser(`https://anilist.co/anime/${media.id}`) }}>
|
||||
<span class='material-symbols-outlined mr-15 font-size-18 w-30'> open_in_new </span>
|
||||
Open
|
||||
</button>
|
||||
<button class='btn flex-fill font-weight-bold font-size-16 ml-5 d-flex align-items-center' on:click={() => { copyToClipboard(`https://miru.watch/anime/${media.id}`) }}>
|
||||
<button class='btn flex-fill font-weight-bold font-size-16 ml-5 d-flex align-items-center' use:click={() => { copyToClipboard(`https://miru.watch/anime/${media.id}`) }}>
|
||||
<span class='material-symbols-outlined mr-15 font-size-18 w-30'> share </span>
|
||||
Share
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { alToken } from '../../views/Settings.svelte'
|
||||
import { alRequest } from '@/modules/anilist.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
export let media = null
|
||||
let following = null
|
||||
async function updateFollowing (media) {
|
||||
|
|
@ -28,7 +29,7 @@
|
|||
<img src={friend.user.avatar.medium} alt='avatar' class='w-30 h-30 img-fluid rounded cover-img' />
|
||||
<span class='my-0 pl-10 mr-auto text-truncate'>{friend.user.name}</span>
|
||||
<span class='my-0 px-10 text-capitalize'>{statusMap[friend.status]}</span>
|
||||
<span class='material-symbols-outlined pointer text-primary font-size-18' on:click={() => window.IPC.emit('open', 'https://anilist.co/user/' + friend.user.name)}> open_in_new </span>
|
||||
<span class='material-symbols-outlined pointer text-primary font-size-18' use:click={() => window.IPC.emit('open', 'https://anilist.co/user/' + friend.user.name)}> open_in_new </span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { click } from '@/modules/click.js'
|
||||
export let list = null
|
||||
let showMore = false
|
||||
function toggleList () {
|
||||
|
|
@ -7,7 +8,7 @@
|
|||
export let title = 'Relations'
|
||||
</script>
|
||||
{#if list?.length}
|
||||
<span class='d-flex align-items-end pointer text-decoration-none pt-20' on:click={toggleList}>
|
||||
<span class='d-flex align-items-end pointer text-decoration-none pt-20' use:click={toggleList}>
|
||||
<h1 class='font-weight-bold text-white'>{title}</h1>
|
||||
{#if list.length > 4}
|
||||
<h6 class='ml-auto font-size-12 more text-muted'>{showMore ? 'Show Less' : 'Show More'}</h6>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
import { playAnime } from '../RSSView.svelte'
|
||||
import { alRequest } from '@/modules/anilist.js'
|
||||
import { getMediaMaxEp } from '@/modules/anime.js'
|
||||
import { wrapEnter } from '@/modules/util.js'
|
||||
import { getContext } from 'svelte'
|
||||
import Details from './Details.svelte'
|
||||
import Following from './Following.svelte'
|
||||
import Controls from './Controls.svelte'
|
||||
import ToggleList from './ToggleList.svelte'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
const view = getContext('view')
|
||||
const trailer = getContext('trailer')
|
||||
|
|
@ -24,10 +24,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class='modal modal-full z-40' class:show={media} on:keydown={checkClose} tabindex='-1' bind:this={modal}>
|
||||
<div class='modal modal-full z-40' class:show={media} on:keydown={checkClose} tabindex='-1' role='button' bind:this={modal}>
|
||||
{#if media}
|
||||
<div class='h-full modal-content bg-very-dark p-0 overflow-y-auto'>
|
||||
<button class='close pointer z-30 bg-dark top-20 right-0 position-absolute' type='button' on:click={close}> × </button>
|
||||
<button class='close pointer z-30 bg-dark top-20 right-0 position-absolute' type='button' use:click={close}> × </button>
|
||||
<div class='h-md-half w-full position-relative z-20'>
|
||||
<div class='h-full w-full position-absolute bg-dark-light banner' style:--bannerurl={`url('${media.bannerImage || ''}')`} />
|
||||
<div class='d-flex h-full top w-full'>
|
||||
|
|
@ -91,9 +91,7 @@
|
|||
</div>
|
||||
<ToggleList list={media.relations?.edges?.filter(({ node }) => node.type === 'ANIME')} let:item title='Relations'>
|
||||
<div class='w-150 mx-15 my-10 rel pointer'
|
||||
on:click={async () => { $view = null; $view = (await alRequest({ method: 'SearchIDSingle', id: item.node.id })).data.Media }}
|
||||
on:keydown={wrapEnter(async () => { $view = null; $view = (await alRequest({ method: 'SearchIDSingle', id: item.node.id })).data.Media })}
|
||||
tabindex='0' role='button'>
|
||||
use:click={async () => { $view = null; $view = (await alRequest({ method: 'SearchIDSingle', id: item.node.id })).data.Media }}>
|
||||
<img loading='lazy' src={item.node.coverImage.medium || ''} alt='cover' class='cover-img w-full h-200 rel-img rounded' />
|
||||
<div class='pt-5'>{item.relationType.replace(/_/g, ' ').toLowerCase()}</div>
|
||||
<h5 class='font-weight-bold text-white mb-5'>{item.node.title.userPreferred}</h5>
|
||||
|
|
@ -107,16 +105,10 @@
|
|||
{#each Array(maxPlayEp) as _, i}
|
||||
{@const ep = maxPlayEp - i}
|
||||
<tr class="font-size-20 py-10 pointer {ep <= media.mediaListEntry?.progress ? 'text-muted' : 'text-white'}"
|
||||
on:click={() => {
|
||||
use:click={() => {
|
||||
playAnime(media, ep)
|
||||
close()
|
||||
}}
|
||||
on:keydown={wrapEnter(() => {
|
||||
playAnime(media, ep)
|
||||
close()
|
||||
})}
|
||||
tabindex='0' role='button'
|
||||
>
|
||||
}}>
|
||||
<td class='w-full font-weight-semi-bold'>Episode {ep}</td>
|
||||
<td class='material-symbols-outlined text-right h-full d-table-cell'>play_arrow</td>
|
||||
</tr>
|
||||
|
|
@ -127,9 +119,7 @@
|
|||
{/if}
|
||||
<ToggleList list={media.recommendations.edges.filter(edge => edge.node.mediaRecommendation)} let:item title='Recommendations'>
|
||||
<div class='w-150 mx-15 my-10 rel pointer'
|
||||
on:click={async () => { $view = null; $view = (await alRequest({ method: 'SearchIDSingle', id: item.node.mediaRecommendation.id })).data.Media }}
|
||||
on:keydown={wrapEnter(async () => { $view = null; $view = (await alRequest({ method: 'SearchIDSingle', id: item.node.mediaRecommendation.id })).data.Media })}
|
||||
tabindex='0' role='button'>
|
||||
use:click={async () => { $view = null; $view = (await alRequest({ method: 'SearchIDSingle', id: item.node.mediaRecommendation.id })).data.Media }}>
|
||||
<img loading='lazy' src={item.node.mediaRecommendation.coverImage.medium || ''} alt='cover' class='cover-img w-full h-200 rel-img rounded' />
|
||||
<h5 class='font-weight-bold text-white mb-5'>{item.node.mediaRecommendation.title.userPreferred}</h5>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { getContext } from 'svelte'
|
||||
import { wrapEnter } from '@/modules/util.js'
|
||||
import { click } from '@/modules/click.js'
|
||||
|
||||
const url = getContext('trailer')
|
||||
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
$: $url && modal?.focus()
|
||||
</script>
|
||||
|
||||
<div class='modal z-40' class:show={$url} on:keydown={checkClose} tabindex='-1' bind:this={modal}>
|
||||
<div class='modal z-40'>
|
||||
{#if $url}
|
||||
<div class='modal-dialog' role='document' on:click|self={close} on:keydown|self={wrapEnter(close)}>
|
||||
<div class='modal-dialog' on:pointerup|self={close} on:keydown={checkClose} tabindex='-1' role='button' bind:this={modal}>
|
||||
<div class='modal-content w-three-quarter h-full bg-transparent d-flex justify-content-center flex-column'>
|
||||
<button class='close pointer z-30 top-20 right-0 position-absolute' type='button' on:click={close}> × </button>
|
||||
<button class='close pointer z-30 top-20 right-0 position-absolute' type='button' use:click={close}> × </button>
|
||||
<div class='trailer w-full position-relative'>
|
||||
<iframe
|
||||
id='trailerVideo'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { click } from '@/modules/click.js'
|
||||
export let peers
|
||||
export let invite
|
||||
export let cleanup
|
||||
|
|
@ -7,8 +8,8 @@
|
|||
<div class='d-flex flex-column py-20 root container card'>
|
||||
<div class='d-flex align-items-center w-full'>
|
||||
<h1 class='font-weight-bold mr-auto'>Lobby</h1>
|
||||
<button class='btn btn-success btn-lg ml-20' type='button' on:click={invite}>Invite To Lobby</button>
|
||||
<button class='btn btn-danger ml-20 btn-lg' type='button' on:click={cleanup}>Leave lobby</button>
|
||||
<button class='btn btn-success btn-lg ml-20' type='button' use:click={invite}>Invite To Lobby</button>
|
||||
<button class='btn btn-danger ml-20 btn-lg' type='button' use:click={cleanup}>Leave lobby</button>
|
||||
</div>
|
||||
{#each Object.values(peers) as peer}
|
||||
<div class='d-flex align-items-center pb-10'>
|
||||
|
|
@ -19,10 +20,10 @@
|
|||
{/if}
|
||||
<h4 class='my-0 pl-20 mr-auto'>{peer.user?.name || 'Anonymous'}</h4>
|
||||
{#if peer.user?.name}
|
||||
<span class='material-symbols-outlined pointer text-primary' on:pointerdown={() => window.IPC.emit('open', 'https://anilist.co/user/' + peer.user?.name)}> open_in_new </span>
|
||||
<span class='material-symbols-outlined pointer text-primary' use:click={() => window.IPC.emit('open', 'https://anilist.co/user/' + peer.user?.name)}> open_in_new </span>
|
||||
{/if}
|
||||
<!-- {#if state === 'host'}
|
||||
<span class='material-symbols-outlined ml-15 pointer text-danger' on:click={() => peer.peer.pc.close()}> logout </span>
|
||||
<span class='material-symbols-outlined ml-15 pointer text-danger' use:click={() => peer.peer.pc.close()}> logout </span>
|
||||
{/if} -->
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import { addToast } from '../../components/Toasts.svelte'
|
||||
import { page } from '@/App.svelte'
|
||||
import P2PT from 'p2pt'
|
||||
import { click } from '@/modules/click.js'
|
||||
import 'browser-event-target-emitter'
|
||||
|
||||
export const w2gEmitter = new EventTarget()
|
||||
|
|
@ -176,7 +177,7 @@
|
|||
<div class='d-flex flex-row flex-wrap justify-content-center align-items-center h-full mb-20 pb-20 root'>
|
||||
<div class='card d-flex flex-column align-items-center w-300 h-300 justify-content-end'>
|
||||
<span class='font-size-80 material-symbols-outlined d-flex align-items-center h-full'>add</span>
|
||||
<button class='btn btn-primary btn-lg mt-10 btn-block' type='button' on:click={() => joinLobby()}>Create Lobby</button>
|
||||
<button class='btn btn-primary btn-lg mt-10 btn-block' type='button' use:click={joinLobby}>Create Lobby</button>
|
||||
</div>
|
||||
<div class='card d-flex flex-column align-items-center w-300 h-300 justify-content-end'>
|
||||
<span class='font-size-80 material-symbols-outlined d-flex align-items-center h-full'>group_add</span>
|
||||
|
|
|
|||
Loading…
Reference in a new issue