change: navigation bar app version link to home page.
change: gif format $PostTile preview action will same as video format.
new: gif format $PostTile will display format detail.
change: navigation bar background change to transparency blur.
change: searchbar selection list scrollbar width smaller.
This commit is contained in:
defaultkavy 2024-10-06 16:39:33 +08:00
parent 1a6d0e580f
commit 6104d9003f
Signed by: defaultkavy
GPG Key ID: DFBB22C4E69D7826
15 changed files with 91 additions and 61 deletions

1
dist/assets/index-BfZu1R1a.js 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

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

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View File

@ -7,8 +7,8 @@
<title>Danbooru Viewer v0.2.5</title> <title>Danbooru Viewer v0.2.5</title>
<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script> <script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script> <script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
<script type="module" crossorigin src="/assets/index-C8Fnii2g.js"></script> <script type="module" crossorigin src="/assets/index-BfZu1R1a.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CbgOs0Kp.css"> <link rel="stylesheet" crossorigin href="/assets/index-qRel_iFf.css">
</head> </head>
<body> <body>
</body> </body>

View File

@ -45,47 +45,56 @@ nav {
position: fixed; position: fixed;
top: 0; top: 0;
z-index: 100; z-index: 100;
background-color: var(--background-color); background-color: color-mix(in srgb, var(--background-color) 70%, transparent);
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding-inline: 1rem; padding-inline: 1rem;
box-sizing: border-box; box-sizing: border-box;
backdrop-filter: blur(3px);
div.title { a.title {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.4rem; gap: 0.4rem;
a.booru-name { text-decoration: none;
.booru-name {
color: var(--secondary-color); color: var(--secondary-color);
text-decoration: none; margin: 0;
h1 { }
margin: 0;
.app {
display: flex;
align-items: center;
border-radius: 0.4rem;
// border: 1px solid var(--secondary-color);
// padding: 0.2rem 0.4rem;
margin: 0;
gap: 0.4rem;
.version {
color: var(--background-color);
background-color: var(--secondary-color);
padding: 0.2em 0.4em;
border-radius: 0.4rem;
font-size: 0.8rem;
font-weight: bold;
}
.app-name {
display: none;
font-size: 1rem;
color: var(--secondary-color);
} }
} }
a.version {
color: var(--background-color);
background-color: var(--secondary-color);
padding: 0.2em 0.4em;
border-radius: 0.4rem;
font-size: 0.8rem;
text-decoration: none;
}
}
button {
padding: 2px 4px;
border-radius: 0.4rem;
border: none;
} }
div.searchbar { div.searchbar {
padding: 0.4rem 10%; padding: 0.4rem 10%;
max-width: 500px; max-width: 500px;
background-color: var(--background-color); background-color: color-mix(in srgb, var(--background-color-light) 30%, transparent);
border: 1px solid var(--primary-color-darker); border: 1px solid var(--primary-color-darker);
border-radius: 0.4rem; border-radius: 0.4rem;
color: var(--primary-color-dark); color: var(--primary-color-dark);
transition: 0.3s all ease;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background-color: var(--background-color-light);
color: var(--primary-color); color: var(--primary-color);
} }
} }
@ -94,12 +103,12 @@ nav {
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
ion-icon { ion-icon {
background-color: var(--background-color); // background-color: var(--background-color);
transition: all 0.3s ease; transition: all 0.3s ease;
border-radius: 1rem; border-radius: 1rem;
padding: 0.4rem; padding: 0.4rem;
&:hover { &:hover {
background-color: var(--background-color-lighter); background-color: color-mix(in srgb, var(--background-color-lighter) 50%, transparent);
} }
} }
ion-icon.search { ion-icon.search {
@ -120,12 +129,12 @@ nav {
router { router {
display: block; display: block;
position: relative; position: relative;
padding-top: var(--nav-height);
route { route {
display: block; display: block;
position: relative; position: relative;
padding-inline: 10px; padding-inline: 10px;
padding-top: var(--nav-height);
} }
} }

View File

@ -2,7 +2,7 @@
"name": "danbooru-viewer", "name": "danbooru-viewer",
"module": "index.ts", "module": "index.ts",
"type": "module", "type": "module",
"version": "0.3.1", "version": "0.3.2",
"devDependencies": { "devDependencies": {
"@types/bun": "latest", "@types/bun": "latest",
"vite": "^5.4.8" "vite": "^5.4.8"

View File

@ -1,2 +1,3 @@
layout.post-grid { layout.post-grid {
margin-top: 1rem;
} }

View File

@ -1,4 +1,4 @@
import { $Container, $State, $Video } from "elexis"; import { $Container, $Image, $State, $Video } from "elexis";
import type { Post } from "../../structure/Post"; import type { Post } from "../../structure/Post";
import { time } from "../../structure/Util"; import { time } from "../../structure/Util";
export class $PostTile extends $Container { export class $PostTile extends $Container {
@ -8,7 +8,7 @@ export class $PostTile extends $Container {
constructor(post: Post) { constructor(post: Post) {
super('post-tile'); super('post-tile');
this.post = post; this.post = post;
this.$video = this.post.isVideo ? $('video').width(this.post.image_width).height(this.post.image_height).disablePictureInPicture(true).loop(true).muted(true).hide(true) : null; this.$video = this.post.isVideo ? $('video').width(this.post.image_width).height(this.post.image_height).disablePictureInPicture(true).loop(true).muted(true).hide(true).on('mousedown', (e) => e.preventDefault()) : null;
this.attribute('filetype', this.post.file_ext); this.attribute('filetype', this.post.file_ext);
this.durationUpdate(); this.durationUpdate();
this.build(); this.build();
@ -32,33 +32,27 @@ export class $PostTile extends $Container {
this.post.hasSound ? $('ion-icon').name('volume-medium-outline') : null, this.post.hasSound ? $('ion-icon').name('volume-medium-outline') : null,
$('span').class('duration').content(this.duration$) $('span').class('duration').content(this.duration$)
]) : null, ]) : null,
// Gif
this.post.isGif
? $('div').class('gif-detail').content([
$('span').content('GIF')
]) : null,
// Tile // Tile
$('a').href(this.post.pathname).content(() => [ $('a').href(this.post.pathname).content(() => [
this.$video, this.$video,
$('img').draggable(false).css({opacity: '0'}).width(this.post.image_width).height(this.post.image_height).src(this.post.previewURL).loading('lazy') $('img').draggable(false).css({opacity: '0'}).width(this.post.image_width).height(this.post.image_height).src(this.post.previewURL).loading('lazy')
.on('mousedown', (e) => e.preventDefault()) .on('mousedown', (e) => e.preventDefault())
.once('load', (e, $img) => { .once('load', (e, $img) => {
if (!this.post.isVideo) $img.src(this.post.previewURL); $img
$img.animate({opacity: [0, 1]}, {duration: 300, fill: 'both'}); .src(this.post.previewURL)
this.removeClass('loading') .on(['mouseenter', 'touchstart'], () => { if (this.post.isGif) { $img.src(this.post.large_file_url) } })
.on(['mouseleave', 'touchend', 'touchcancel'], () => { if (this.post.isGif) { $img.src(this.post.previewURL) } })
.animate({opacity: [0, 1]}, {duration: 300, fill: 'both'});
this.removeClass('loading');
}) })
]) ])
.on('mouseenter', () => { .on(['mouseenter', 'touchstart'], () => { if (!this.$video?.isPlaying) { this.$video?.src(this.post.large_file_url).hide(false).play().catch(err => undefined) } })
if (!this.$video?.isPlaying) { .on(['mouseleave', 'touchend', 'touchcancel'], () => { this.$video?.pause().currentTime(0).hide(true); })
this.$video?.src(this.post.large_file_url).hide(false).play().catch(err => undefined)
}
})
.on('mouseleave', () => {
this.$video?.pause().currentTime(0).hide(true);
})
.on('touchstart', () => {
if (!this.$video?.isPlaying) {
this.$video?.src(this.post.large_file_url).hide(false).play().catch(err => undefined)
}
})
.on('touchend', () => {
this.$video?.pause().currentTime(0).hide(true);
})
]) ])
} }

View File

@ -23,7 +23,7 @@ post-tile {
&:active { &:active {
transform: scale(0.95); transform: scale(0.95);
} }
div.video-detail { div.video-detail, div.gif-detail {
position: absolute; position: absolute;
background-color: var(--background-color-lighter);//color-mix(in srgb, var(--background-color-lighter) 80%, transparent); background-color: var(--background-color-lighter);//color-mix(in srgb, var(--background-color-lighter) 80%, transparent);
color: var(--primary-color); color: var(--primary-color);

View File

@ -10,7 +10,7 @@ searchbar {
div.input-container { div.input-container {
margin-top: 0.4rem; margin-top: 0.4rem;
background-color: var(--background-color-light); background-color: color-mix(in srgb, var(--background-color-light) 70%, transparent);
border-radius: 0.4rem; border-radius: 0.4rem;
font-size: 1rem; font-size: 1rem;
width: 500px; width: 500px;
@ -71,6 +71,10 @@ searchbar {
overflow-x: hidden; overflow-x: hidden;
position: relative; position: relative;
&::-webkit-scrollbar {
width: 4px;
}
selection { selection {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View File

@ -31,9 +31,12 @@ $(document.body).content([
// Navigation Bar // Navigation Bar
$('nav').content([ $('nav').content([
// Title // Title
$('div').class('title').content([ $('a').class('title').href('/').content([
$('a').class('booru-name').content([$('h1').content(Booru.name$)]).href('/'), $('h1').class('booru-name').content(Booru.name$),
$('a').class('version').target('_blank').content(`v${__APP_VERSION__}`).href(`https://git.defaultkavy.com/defaultkavy/danbooru-viewer`) $('h2').class('app').content([
$('span').class('app-name').content(`Viewer`),
$('span').class('version').content(`v${__APP_VERSION__}`)
])
]), ]),
// Searchbar // Searchbar
$('div').class('searchbar').content(['Search in ', Booru.name$]) $('div').class('searchbar').content(['Search in ', Booru.name$])
@ -65,13 +68,21 @@ $(document.body).content([
post_route post_route
]).on('beforeSwitch', (e) => { ]).on('beforeSwitch', (e) => {
const DURATION = 300; const DURATION = 300;
const TX = 2;
e.preventDefault(); e.preventDefault();
function intro() { function intro() {
const transform = $.call(() => {
switch ($Router.navigationDirection) {
case $RouterNavigationDirection.Forward: return [`translateX(${TX}%)`, `translateX(0%)`];
case $RouterNavigationDirection.Back: return [`translateX(-${TX}%)`, `translateX(0%)`];
case $RouterNavigationDirection.Replace: return undefined;
}
})
e.$view.content(e.nextContent); e.$view.content(e.nextContent);
e.rendered(); e.rendered();
e.nextContent.element?.class('animated').animate({ e.nextContent.element?.class('animated').animate({
opacity: [0, 1], opacity: [0, 1],
transform: $Router.navigationDirection === $RouterNavigationDirection.Forward ? [`translateX(40%)`, `translateX(0%)`] : [`translateX(-40%)`, `translateX(0%)`] transform
}, { }, {
duration: DURATION, duration: DURATION,
easing: 'ease' easing: 'ease'
@ -81,9 +92,17 @@ $(document.body).content([
}) })
} }
function outro() { function outro() {
const transform = $.call(() => {
switch ($Router.navigationDirection) {
case $RouterNavigationDirection.Forward: return [`translateX(0%)`, `translateX(-${TX}%)`];
case $RouterNavigationDirection.Back: return [`translateX(0%)`, `translateX(${TX}%)`];
case $RouterNavigationDirection.Replace: return undefined;
}
})
e.previousContent?.element?.class('animated').animate({ e.previousContent?.element?.class('animated').animate({
opacity: [1, 0], opacity: [1, 0],
transform: $Router.navigationDirection === $RouterNavigationDirection.Forward ? [`translateX(0%)`, `translateX(-40%)`] : [`translateX(0%)`, `translateX(40%)`] transform
}, { }, {
duration: DURATION, duration: DURATION,
easing: 'ease' easing: 'ease'

View File

@ -31,7 +31,7 @@ export const post_route = $('route').path('/posts/:id').id('post').builder(({$ro
let scrollTop = 0; let scrollTop = 0;
addEventListener('scroll', () => { if ($sidebar.inDOM()) scrollTop = document.documentElement.scrollTop }) addEventListener('scroll', () => { if ($sidebar.inDOM()) scrollTop = document.documentElement.scrollTop })
$route $route
.on('beforeShift', () => { if (innerWidth > 800) $sidebar.css({position: `absolute`, top: `${scrollTop}px`}) }) .on('beforeShift', () => { if (innerWidth > 800) $sidebar.css({position: `absolute`, top: `calc(${scrollTop}px + var(--nav-height) + var(--padding))`}) })
.on('afterShift', () => $sidebar.css({position: '', top: ''})) .on('afterShift', () => $sidebar.css({position: '', top: ''}))
}) })
.content([ .content([

View File

@ -1,5 +1,6 @@
#post { #post {
padding: 0; padding: 0;
padding-top: var(--nav-height);
section { section {
background-color: #2f2f45; background-color: #2f2f45;
border-radius: 20px; border-radius: 20px;
@ -39,7 +40,7 @@
} }
div.content { div.content {
width: calc(100vw - 300px - 4rem); width: calc(100vw - 300px - 2rem);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 1rem; padding: 1rem;
@ -73,9 +74,10 @@
} }
div.sidebar { div.sidebar {
--padding: 1rem;
position: fixed; position: fixed;
top: calc(var(--nav-height) + 1rem); top: calc(var(--nav-height) + var(--padding));
right: 1rem; right: var(--padding);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.4rem; gap: 0.4rem;

View File

@ -95,6 +95,7 @@ export class Post extends $EventManager<{update: []}> {
get uploader() { return User.manager.get(this.uploader_id); } get uploader() { return User.manager.get(this.uploader_id); }
get approver() { if (this.approver_id) return User.manager.get(this.approver_id); else return null } get approver() { if (this.approver_id) return User.manager.get(this.approver_id); else return null }
get isVideo() { return this.file_ext === 'mp4' || this.file_ext === 'webm' || this.file_ext === 'zip' } get isVideo() { return this.file_ext === 'mp4' || this.file_ext === 'webm' || this.file_ext === 'zip' }
get isGif() { return this.file_ext === 'gif' }
get hasSound() { return this.tag_string_meta.includes('sound') } get hasSound() { return this.tag_string_meta.includes('sound') }
get tags() { get tags() {
const tag_list = this.tag_string.split(' '); const tag_list = this.tag_string.split(' ');