- change: document element scroll behavior smooth.
- new: hotkey supported:
  - browser navigation back and forward.
  - post grid navigation.
  - post favorites.
This commit is contained in:
defaultkavy 2024-10-17 11:43:21 +08:00
parent 84f52ed030
commit d6be4c0c62
Signed by: defaultkavy
GPG Key ID: DFBB22C4E69D7826
13 changed files with 74 additions and 11 deletions

1
dist/assets/index-BMZsSbMp.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/assets/index-ByWqsQtl.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View File

@ -16,8 +16,8 @@
gtag('config', 'G-59HBGP98WR');
</script>
<script type="module" crossorigin src="/assets/index-D8tVsP8g.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D689878Y.css">
<script type="module" crossorigin src="/assets/index-BMZsSbMp.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-ByWqsQtl.css">
</head>
<body>
</body>

View File

@ -33,7 +33,7 @@
html {
overflow-x: hidden;
font-size: 14px;
scroll-behavior: smooth;
::-webkit-scrollbar {
background-color: var(--secondary-color-1);
width: 8px;

View File

@ -2,7 +2,7 @@
"name": "danbooru-viewer",
"module": "index.ts",
"type": "module",
"version": "0.8.2",
"version": "0.9.0",
"scripts": {
"dev": "bun x vite",
"build": "bun x vite build",

View File

@ -45,10 +45,11 @@ export class $Drawer extends $Container {
$('icon-button').icon('log-in-outline').content('Logout').on('dblclick', () => Booru.used.logout()).hide(true)
.self(($div => Booru.events.on('login', () => $div.hide(false)).on('logout', () => $div.hide(true)))),
$('icon-button').icon('swap-horizontal').content('Logout').class('switch').content('Switch Booru')
$('icon-button').icon('swap-horizontal').class('switch').content('Switch Booru')
.on('click', () => {
if (Booru.used === danbooru) Booru.set(safebooru);
else Booru.set(danbooru);
this.close();
}),
])
]),

View File

@ -2,6 +2,7 @@ import { $Layout, type $LayoutEventMap } from "@elexis/layout";
import { Booru } from "../../structure/Booru";
import { Post } from "../../structure/Post";
import { $PostTile } from "../PostTile/$PostTile";
import { $Input } from "elexis/lib/node/$Input";
interface $PostGridOptions {
tags?: string
@ -13,6 +14,7 @@ export class $PostGrid extends $Layout<$PostGridEventMap> {
tags?: string;
finished = false;
limit = 100;
$focus = $.focus();
constructor(options?: $PostGridOptions) {
super();
this.tags = options?.tags;
@ -34,6 +36,29 @@ export class $PostGrid extends $Layout<$PostGridEventMap> {
this.on('resize', () => this.resize())
this.events.fire('startLoad');
this.loader();
this.$focus.layer(100).loop(false).scrollThreshold($.rem(2) + 60);
$.keys($(window))
.if(e => {
if ($(e.target) instanceof $Input) return;
if (!this.inDOM()) return;
return true;
})
.keydown('Tab', e => {
e.preventDefault();
if (e.shiftKey) this.$focus.prev();
else this.$focus.next();
})
.keydown(['w', 'W'], e => { e.preventDefault(); this.$focus.up(); })
.keydown(['s', 'S'], e => { e.preventDefault(); this.$focus.down(); })
.keydown(['d', 'D'], e => { e.preventDefault(); this.$focus.right(); })
.keydown(['a', 'A'], e => { e.preventDefault(); this.$focus.left(); })
.keydown([' ', 'Enter'], e => {
e.preventDefault();
const focused = this.$focus.currentLayer?.currentFocus;
if (focused instanceof $PostTile) $.open(`/posts/${focused.post.id}`);
})
.keydown(['Escape'], e => { e.preventDefault(); this.$focus.blur(); })
}
protected async loader() {
@ -63,7 +88,8 @@ export class $PostGrid extends $Layout<$PostGridEventMap> {
this.$posts.set(post, $post);
this.posts.add(post);
}
const $posts = [...this.orderMap.values()].map(post => this.$posts.get(post));
this.$focus.layer(100).removeAll();
const $posts = [...this.orderMap.values()].map(post => this.$posts.get(post)?.self(this.$focus.layer(100).add));
this.content($posts).render();
return this;
}

View File

@ -1,3 +1,12 @@
layout.post-grid {
margin-top: 0.4rem;
&:has(post-tile[focus]) {
post-tile:not([focus]) {
opacity: 0.5;
}
post-tile:hover {
opacity: 1;
}
}
}

View File

@ -7,7 +7,12 @@ post-tile {
overflow: hidden;
-webkit-tap-highlight-color: transparent;
user-select: none;
outline: transparent solid 2px;
&[focus] {
outline: var(--secondary-color-9) solid 2px;
transform: scale(1.02);
}
@media (hover: hover) {
&:hover {
transform: scale(1.02);

View File

@ -1,7 +1,7 @@
import 'elexis';
import '@elexis/layout';
import '@elexis/router';
import { Booru, type BooruOptions } from './structure/Booru';
import { Booru } from './structure/Booru';
import { post_route } from './route/post/$post_route';
import { $PostGrid } from './component/PostGrid/$PostGrid';
import { $Router, $RouterNavigationDirection } from '@elexis/router';
@ -10,6 +10,7 @@ import { $IonIcon } from './component/IonIcon/$IonIcon';
import { $IconButton } from './component/IconButton/$IconButton';
import { $login_route } from './route/login/$login_route';
import { $Drawer } from './component/Drawer/$Drawer';
import { $Input } from 'elexis/lib/node/$Input';
// declare elexis module
declare module 'elexis' {
export namespace $ {
@ -117,6 +118,7 @@ $(document.body).content([
const TX = 2;
e.preventDefault();
function intro() {
$(document.documentElement).css({scrollBehavior: 'auto'});
const transform = $.call(() => {
switch ($Router.navigationDirection) {
case $RouterNavigationDirection.Forward: return [`translateX(${TX}%)`, `translateX(0%)`];
@ -134,10 +136,12 @@ $(document.body).content([
easing: 'ease'
}, () => {
e.switched();
$(document.documentElement).css({scrollBehavior: ''});
e.nextContent.element?.removeClass('animated')
})
}
function outro() {
$(document.documentElement).css({scrollBehavior: 'auto'});
const transform = $.call(() => {
switch ($Router.navigationDirection) {
case $RouterNavigationDirection.Forward: return [`translateX(0%)`, `translateX(-${TX}%)`];
@ -169,3 +173,10 @@ componentState(undefined, new URL(location.href))
function componentState(beforeURL: URL | undefined, afterURL: URL) {
$searchbar.checkURL(beforeURL, afterURL); $drawer.checkURL(beforeURL, afterURL)
}
$.keys($(window))
.if(e => {
if ($(e.target) instanceof $Input) return;
return true;
})
.keydown(['q', 'Q'], e => { e.preventDefault(); if ($Router.index !== 0) $.back(); })
.keydown(['e', 'E'], e => { e.preventDefault(); if ($Router.forwardIndex !== 0) $.forward(); })

View File

@ -7,6 +7,7 @@ import type { $IonIcon } from "../../component/IonIcon/$IonIcon";
import { numberFormat } from "../../structure/Util";
import { ClientUser } from "../../structure/ClientUser";
import { $VideoController } from "../../component/VideoController/$VideoController";
import { $Input } from "elexis/lib/node/$Input";
export const post_route = $('route').path('/posts/:id').id('post').builder(({$route, params}) => {
if (!Number(params.id)) return $('h1').content('404: POST NOT FOUND');
@ -18,6 +19,16 @@ export const post_route = $('route').path('/posts/:id').id('post').builder(({$ro
original_size: [],
video_play_pause: []
}>();
$.keys($(window))
.if(e => {
if ($(e.target) instanceof $Input) return;
if (!$route.inDOM()) return;
return true;
})
.keydown(['f', 'F'], e => {
if (Booru.used.user?.favorites.has(post.id)) post.deleteFavorite();
else post.createFavorite();
})
return [
$('div').class('viewer').content(async ($viewer) => {
const $video = $('video');