update: $Router package.
new: open in original site button.
change: searchbar input background remove transparency.
change: post page video player disable picture in picture.
new: post page sidebar detail add copy file link button and copy webm link button.
new: ugoria format will show icon on $PostTile.
new: $IconButton
new: Post.isUgoria
This commit is contained in:
defaultkavy 2024-10-06 18:00:35 +08:00
parent 6104d9003f
commit 86c2d5aa9f
Signed by: defaultkavy
GPG Key ID: DFBB22C4E69D7826
15 changed files with 115 additions and 23 deletions

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

@ -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-BfZu1R1a.js"></script> <script type="module" crossorigin src="/assets/index-C21fHnwq.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-qRel_iFf.css"> <link rel="stylesheet" crossorigin href="/assets/index-B240dcNf.css">
</head> </head>
<body> <body>
</body> </body>

View File

@ -1,6 +1,7 @@
@import '/src/component/PostGrid/$PostGrid'; @import '/src/component/PostGrid/$PostGrid';
@import '/src/component/PostTile/$PostTile'; @import '/src/component/PostTile/$PostTile';
@import '/src/component/Searchbar/$Searchbar'; @import '/src/component/Searchbar/$Searchbar';
@import '/src/component/IconButton/$IconButton';
@import '/src/route/post/$post'; @import '/src/route/post/$post';
@import '/src/route/gallery/$gallery'; @import '/src/route/gallery/$gallery';
@ -139,9 +140,10 @@ router {
} }
button { button {
background-color: #aeaeec; background-color: var(--secondary-color-dark);
padding: 2px 4px; color: var(--secondary-color);
border-radius: 0.4rem; padding: 0.8rem 1.2rem;
border-radius: 1rem;
border: none; border: none;
cursor: pointer; cursor: pointer;
} }

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.2", "version": "0.3.3",
"devDependencies": { "devDependencies": {
"@types/bun": "latest", "@types/bun": "latest",
"vite": "^5.4.8" "vite": "^5.4.8"

View File

@ -0,0 +1,28 @@
import { $Button, type $ContainerContentBuilder } from "elexis";
export class $IconButton extends $Button {
$icon = $('ion-icon');
$label = $('span');
constructor() {
super();
this.addStaticClass('icon')
this.build();
}
private build() {
super.content([
this.$icon,
this.$label
])
}
content(children: $ContainerContentBuilder<typeof this.$label>): this {
this.$label.content(children);
return this;
}
icon(name: string) {
this.$icon.name(name);
return this;
}
}

View File

@ -0,0 +1,19 @@
button.icon {
display: flex;
justify-content: center;
align-items: center;
gap: 0.4rem;
padding: 0.4rem;
background-color: transparent;
ion-icon {
font-size: 1.5rem;
}
&:hover {
background-color: var(--background-color-light);
}
&.vertical {
flex-direction: column;
}
}

View File

@ -30,6 +30,7 @@ export class $PostTile extends $Container {
this.post.isVideo this.post.isVideo
? $('div').class('video-detail').content([ ? $('div').class('video-detail').content([
this.post.hasSound ? $('ion-icon').name('volume-medium-outline') : null, this.post.hasSound ? $('ion-icon').name('volume-medium-outline') : null,
this.post.isUgoria ? $('ion-icon').name('images-outline') : null,
$('span').class('duration').content(this.duration$) $('span').class('duration').content(this.duration$)
]) : null, ]) : null,
// Gif // Gif

View File

@ -29,7 +29,8 @@ post-tile {
color: var(--primary-color); color: var(--primary-color);
bottom: 0.3rem; bottom: 0.3rem;
right: 0.3rem; right: 0.3rem;
padding: 2px 4px; padding: 0.2em 0.4em;
height: 1rem;
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 12px;
display: flex; display: flex;
@ -39,7 +40,12 @@ post-tile {
// text-shadow: 0 0 0.5em var(--background-color); // text-shadow: 0 0 0.5em var(--background-color);
ion-icon { ion-icon {
font-size: 1.5em; font-size: 1.4rem;
&[name="images-outline"] {
padding: 0.1rem;
font-size: 1rem;
}
} }
span.duration { span.duration {

View File

@ -10,7 +10,7 @@ searchbar {
div.input-container { div.input-container {
margin-top: 0.4rem; margin-top: 0.4rem;
background-color: color-mix(in srgb, var(--background-color-light) 70%, transparent); background-color: color-mix(in srgb, var(--background-color-light) 100%, transparent);
border-radius: 0.4rem; border-radius: 0.4rem;
font-size: 1rem; font-size: 1rem;
width: 500px; width: 500px;

View File

@ -7,15 +7,18 @@ import { $PostGrid } from './component/PostGrid/$PostGrid';
import { $Router, $RouterNavigationDirection } from '@elexis/router'; import { $Router, $RouterNavigationDirection } from '@elexis/router';
import { $Searchbar } from './component/Searchbar/$Searchbar'; import { $Searchbar } from './component/Searchbar/$Searchbar';
import { $IonIcon } from './component/IonIcon/$IonIcon'; import { $IonIcon } from './component/IonIcon/$IonIcon';
import { $IconButton } from './component/IconButton/$IconButton';
// declare elexis module // declare elexis module
declare module 'elexis' { declare module 'elexis' {
export namespace $ { export namespace $ {
export interface TagNameElementMap { export interface TagNameElementMap {
'ion-icon': typeof $IonIcon 'ion-icon': typeof $IonIcon;
'icon-button': typeof $IconButton;
} }
} }
} }
$.registerTagName('ion-icon', $IonIcon) $.registerTagName('ion-icon', $IonIcon)
$.registerTagName('icon-button', $IconButton)
$.anchorHandler = ($a) => { $.open($a.href(), $a.target())} $.anchorHandler = ($a) => { $.open($a.href(), $a.target())}
// settings // settings
export const [danbooru, safebooru]: Booru[] = [ export const [danbooru, safebooru]: Booru[] = [
@ -48,12 +51,15 @@ $(document.body).content([
$('ion-icon').class('search').name('search-outline').title('Search') $('ion-icon').class('search').name('search-outline').title('Search')
.self($self => $Router.events.on('stateChange', ({beforeURL, afterURL}) => {if (beforeURL.hash === '#search') $self.hide(false); if (afterURL.hash === '#search') $self.hide(true)})) .self($self => $Router.events.on('stateChange', ({beforeURL, afterURL}) => {if (beforeURL.hash === '#search') $self.hide(false); if (afterURL.hash === '#search') $self.hide(true)}))
.on('click', () => $.open(location.href + '#search')), .on('click', () => $.open(location.href + '#search')),
// Switch Button // Switch Booru
$('ion-icon').class('switch').name('swap-horizontal').title('Switch Booru') $('ion-icon').class('switch').name('swap-horizontal').title('Switch Booru')
.on('click', () => { .on('click', () => {
if (Booru.used === danbooru) Booru.set(safebooru); if (Booru.used === danbooru) Booru.set(safebooru);
else Booru.set(danbooru); else Booru.set(danbooru);
}) }),
// Open Booru
$('ion-icon').class('open').name('open-outline').title('Open in Original Site')
.on('click', () => $.open(location.href.replace(location.origin, Booru.used.origin))),
]) ])
]), ]),
// Searchbar // Searchbar

View File

@ -11,7 +11,7 @@ export const post_route = $('route').path('/posts/:id').id('post').builder(({$ro
$('div').class('viewer').content(async () => { $('div').class('viewer').content(async () => {
await post.ready; await post.ready;
return post.isVideo return post.isVideo
? $('video').height(post.image_height).width(post.image_width).src(post.file_ext === 'zip' ? post.large_file_url : post.file_url).controls(true).autoplay(true).loop(true) ? $('video').height(post.image_height).width(post.image_width).src(post.file_ext === 'zip' ? post.large_file_url : post.file_url).controls(true).autoplay(true).loop(true).disablePictureInPicture(true)
: $('img').src(post.large_file_url)//.once('load', (e, $img) => { $img.src(post.file_url)}) : $('img').src(post.large_file_url)//.once('load', (e, $img) => { $img.src(post.file_url)})
}), }),
$('div').class('content').content([ $('div').class('content').content([
@ -46,14 +46,36 @@ export const post_route = $('route').path('/posts/:id').id('post').builder(({$ro
new $Property('favorites').name('Favorites').value(post.favorites$), new $Property('favorites').name('Favorites').value(post.favorites$),
new $Property('score').name('Score').value(post.score$) new $Property('score').name('Score').value(post.score$)
]), ]),
$('button').content('Copy link').on('click', (e, $button) => { $('div').class('buttons').content([
e.preventDefault(); $('icon-button').class('vertical').icon('link-outline').content(Booru.name$)
navigator.clipboard.writeText(`${Booru.used.origin}${location.pathname}`); .on('click', (e, $button) => {
$button.content('Copied!'); e.preventDefault();
setTimeout(() => { navigator.clipboard.writeText(`${Booru.used.origin}${location.pathname}`);
$button.content('Copy link') $button.content('Copied!');
}, 2000); setTimeout(() => {
}) $button.content(Booru.name$)
}, 2000);
}),
$('icon-button').class('vertical').icon('link-outline').content(`File`)
.on('click', (e, $button) => {
e.preventDefault();
navigator.clipboard.writeText(post.file_url);
$button.content('Copied!');
setTimeout(() => {
$button.content('File')
}, 2000);
}),
$('icon-button').class('vertical').icon('link-outline').content(`Webm`)
.on('click', (e, $button) => {
e.preventDefault();
navigator.clipboard.writeText(post.previewURL);
$button.content('Copied!');
setTimeout(() => {
$button.content('Webm')
}, 2000);
})
.hide(true).self(async ($button) => { await post.ready; if (post.file_ext === 'zip') $button.hide(false) })
]),
]), ]),
$('div').class('post-tags').content(async $tags => { $('div').class('post-tags').content(async $tags => {
const tags = await post.fetchTags(); const tags = await post.fetchTags();

View File

@ -116,6 +116,13 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.4rem; gap: 0.4rem;
.buttons {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
margin-top: 1rem;
}
} }
div.property { div.property {

View File

@ -96,6 +96,7 @@ export class Post extends $EventManager<{update: []}> {
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 isGif() { return this.file_ext === 'gif' }
get isUgoria() { return this.file_ext === 'zip' }
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(' ');