new: Post auto load
fix: zip file preview
This commit is contained in:
defaultkavy 2024-05-18 21:11:41 +08:00
parent f1d6faeb75
commit 1add8ce529
13 changed files with 50 additions and 20 deletions

File diff suppressed because one or more lines are too long

1
dist/assets/index-Cq-5lgfU.css vendored Normal file
View File

@ -0,0 +1 @@
post{display:block}post[filetype=mp4] span.duration,post[filetype=webm] span.duration,post[filetype=zip] span.duration{background-color:#fff;color:#000}post span.duration{position:absolute;background-color:#00000050;bottom:.3rem;right:.3rem;padding:2px 4px;border-radius:4px;font-size:12px;text-transform:uppercase;z-index:2}post img{border-radius:10px;height:100%;width:100%}post video{border-radius:10px;height:100%;width:100%;object-fit:cover;position:absolute}#post section{background-color:#2f2f45;border-radius:20px;padding:20px}#post div.main{width:calc(100vw - 300px - 4rem);padding-right:10px;display:flex;flex-direction:column}@media (max-width: 800px){#post div.main{width:100%}}#post div.main::-webkit-scrollbar{background-color:#000;width:4px}#post div.main::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}#post div.main>h3{padding-left:1rem;margin-block:1rem}#post div.main div.viewer{height:calc(100vh - 2rem);display:flex;justify-content:center;align-items:center;background-color:#000;border-radius:20px;overflow:hidden}#post div.main div.viewer img{max-width:100%;max-height:100%}#post div.main div.viewer video{max-width:100%;max-height:100%}#post div.main section.commentary *{text-wrap:wrap;word-break:break-word}#post div.sidebar{position:fixed;top:1rem;right:1rem;display:flex;flex-direction:column;gap:.4rem;width:300px;overflow:scroll;overflow-x:hidden;height:calc(100vh - 2rem);border-radius:20px}@media (max-width: 800px){#post div.sidebar{position:relative;width:100%;overflow:visible;height:100%;padding-inline:1rem;padding-bottom:1rem}}#post div.sidebar::-webkit-scrollbar{background-color:#000;width:0px}#post div.sidebar::-webkit-scrollbar-thumb{background-color:#aeaeec}#post div.sidebar h3{padding-left:1rem;margin-block:.6rem}#post div.sidebar .post-info{background-color:#2f2f45;border-radius:20px;padding:20px;display:flex;flex-direction:column;gap:.4rem}#post div.sidebar div.property{display:flex;gap:.6rem;align-items:center}#post div.sidebar div.property div.property-values{display:flex;gap:.4rem}#post div.sidebar div.property div.property-values span.property-value{background-color:#525278;color:#aeaeec;padding:2px 4px;border-radius:4px}#post div.sidebar div.inline{display:flex;gap:1rem}#post div.sidebar div.post-tags{display:flex;flex-direction:column;gap:.2rem}#post div.sidebar div.post-tags div.tag{align-items:center}#post div.sidebar div.post-tags div.tag a.tag-name{word-break:break-word;color:#d1d1ee;text-decoration:none}#post div.sidebar div.post-tags div.tag span.tag-post-count{background-color:#525278;color:#aeaeec;padding:0 4px;border-radius:4px;font-size:12px;margin-left:.4rem}page#root .loader{text-align:center;padding-block:2rem}body{background-color:#1e1e2c;color:#d1d1ee;margin:0;font-family:Microsoft Yahei;font-size:14px}body::-webkit-scrollbar{background-color:#000;width:8px}body::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}app{display:block}app view{display:block}app view page{min-height:100%;padding:1rem;display:block}

View File

@ -1 +0,0 @@
post{display:block}post[filetype=mp4] span.duration,post[filetype=webm] span.duration{background-color:#fff;color:#000}post span.duration{position:absolute;background-color:#00000050;bottom:.3rem;right:.3rem;padding:2px 4px;border-radius:4px;font-size:12px;text-transform:uppercase;z-index:2}post img{border-radius:10px;height:100%;width:100%}post video{border-radius:10px;height:100%;width:100%;object-fit:cover;position:absolute}#post section{background-color:#2f2f45;border-radius:20px;padding:20px}#post div.main{width:calc(100vw - 300px - 4rem);padding-right:10px;display:flex;flex-direction:column}@media (max-width: 800px){#post div.main{width:100%}}#post div.main::-webkit-scrollbar{background-color:#000;width:4px}#post div.main::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}#post div.main>h3{padding-left:1rem;margin-block:1rem}#post div.main div.viewer{height:calc(100vh - 2rem);display:flex;justify-content:center;align-items:center;background-color:#000;border-radius:20px;overflow:hidden}#post div.main div.viewer img{max-width:100%;max-height:100%}#post div.main div.viewer video{max-width:100%;max-height:100%}#post div.main section.commentary *{text-wrap:wrap;word-break:break-word}#post div.sidebar{position:fixed;top:1rem;right:1rem;display:flex;flex-direction:column;gap:.4rem;width:300px;overflow:scroll;overflow-x:hidden;height:calc(100vh - 2rem);border-radius:20px}@media (max-width: 800px){#post div.sidebar{position:relative;width:100%;overflow:visible;height:100%;padding-inline:1rem;padding-bottom:1rem}}#post div.sidebar::-webkit-scrollbar{background-color:#000;width:0px}#post div.sidebar::-webkit-scrollbar-thumb{background-color:#aeaeec}#post div.sidebar h3{padding-left:1rem;margin-block:.6rem}#post div.sidebar .post-info{background-color:#2f2f45;border-radius:20px;padding:20px;display:flex;flex-direction:column;gap:.4rem}#post div.sidebar div.property{display:flex;gap:.6rem;align-items:center}#post div.sidebar div.property div.property-values{display:flex;gap:.4rem}#post div.sidebar div.property div.property-values span.property-value{background-color:#525278;color:#aeaeec;padding:2px 4px;border-radius:4px}#post div.sidebar div.inline{display:flex;gap:1rem}#post div.sidebar div.post-tags{display:flex;flex-direction:column;gap:.2rem}#post div.sidebar div.post-tags div.tag{align-items:center}#post div.sidebar div.post-tags div.tag a.tag-name{word-break:break-word;color:#d1d1ee;text-decoration:none}#post div.sidebar div.post-tags div.tag span.tag-post-count{background-color:#525278;color:#aeaeec;padding:0 4px;border-radius:4px;font-size:12px;margin-left:.4rem}body{background-color:#1e1e2c;color:#d1d1ee;margin:0;font-family:Microsoft Yahei;font-size:14px}body::-webkit-scrollbar{background-color:#000;width:8px}body::-webkit-scrollbar-thumb{background-color:#aeaeec;border-radius:2px}app{display:block}app view{display:block}app view page{min-height:100%;padding:1rem;display:block}

4
dist/index.html vendored
View File

@ -5,8 +5,8 @@
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> --> <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Danbooru Viewer v0.1</title> <title>Danbooru Viewer v0.1</title>
<script type="module" crossorigin src="/assets/index-C_aOc7tm.js"></script> <script type="module" crossorigin src="/assets/index-BIoKxl_Q.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-bPuxyZ9T.css"> <link rel="stylesheet" crossorigin href="/assets/index-Cq-5lgfU.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/route/posts/$post'; @import '/src/route/posts/$post';
@import '/src/route/home/$home';
body { body {
background-color: #1e1e2c; background-color: #1e1e2c;

View File

@ -2,7 +2,7 @@
"name": "danbooru-viewer", "name": "danbooru-viewer",
"module": "index.ts", "module": "index.ts",
"type": "module", "type": "module",
"version": "0.2.1", "version": "0.2.2",
"devDependencies": { "devDependencies": {
"@types/bun": "latest" "@types/bun": "latest"
}, },

View File

@ -35,7 +35,7 @@ export class $PostTile extends $Container {
}) })
]) ])
.on('mouseenter', () => { .on('mouseenter', () => {
if (!this.$video?.isPlaying) this.$video?.src(this.post.file_url).hide(false).play().catch(err => undefined) if (!this.$video?.isPlaying) this.$video?.src(this.post.large_file_url).hide(false).play().catch(err => undefined)
}) })
.on('mouseleave', () => { .on('mouseleave', () => {
this.$video?.pause().currentTime(0).hide(true); this.$video?.pause().currentTime(0).hide(true);

View File

@ -1,7 +1,7 @@
post { post {
display: block; display: block;
&[filetype="mp4"], &[filetype="webm"] { &[filetype="mp4"], &[filetype="webm"], &[filetype="zip"] {
span.duration { span.duration {
background-color: #ffffff; background-color: #ffffff;
color: #000000; color: #000000;

View File

@ -6,7 +6,7 @@ import { $PostTile } from "../../component/PostTile/$PostTile";
export const home_route = new Route((path) => { export const home_route = new Route((path) => {
if (path === '/posts' || path === '/') return '/'; if (path === '/posts' || path === '/') return '/';
}, ({record, loaded}) => { }, ({record}) => {
const $page = $('page').id('root'); const $page = $('page').id('root');
async function load(tags: string) { async function load(tags: string) {
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags} : undefined, 100) const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags} : undefined, 100)
@ -14,7 +14,29 @@ export const home_route = new Route((path) => {
posts.filter(post => post.file_url).map(post => new $PostTile(post)) posts.filter(post => post.file_url).map(post => new $PostTile(post))
]).on('resize', () => { resizeCheck() }); ]).on('resize', () => { resizeCheck() });
resizeCheck(); resizeCheck();
return $grid let last_post = posts.at(-1)!;
let loaded = false;
let ended = posts.length !== 100;
const $loader = $('div').class('loader').content( ended ? `It's End` : 'Loading...');
window.addEventListener('scroll', async () => {
if (!$grid.inDOM()) return;
if (ended) return;
if (loaded) return;
if (document.documentElement.scrollTop < document.documentElement.scrollHeight - innerHeight * 3) return;
loaded = true;
const posts = await Post.fetchMultiple(booru, tags.length ? {tags: tags, id: `..${last_post.id - 1}`} : {id: `..${last_post.id - 1}`}, 100)
$grid.insert(
posts.filter(post => post.file_url).map(post => new $PostTile(post))
).render();
if (posts.length !== 100) {
$loader.content(`It's End`);
ended = true;
}
last_post = posts.at(-1)!;
loaded = false;
})
return {$grid, $loader}
function resizeCheck() { function resizeCheck() {
if (innerWidth < 350) $grid.column(1); if (innerWidth < 350) $grid.column(1);
@ -37,8 +59,11 @@ export const home_route = new Route((path) => {
} else { } else {
$page.clear(); $page.clear();
} }
const $grid = await load(tags); const {$grid, $loader} = await load(tags);
$page.content($grid); $page.content([
$grid,
$loader
]);
$grid.render(); $grid.render();
gridManager.set(tags, $grid); gridManager.set(tags, $grid);
Router.recoveryScrollPosition(); Router.recoveryScrollPosition();

View File

@ -0,0 +1,6 @@
page#root {
.loader {
text-align: center;
padding-block: 2rem;
}
}

View File

@ -27,7 +27,7 @@ export const posts_route = new Route('/posts/:id', ({params}) => {
const post = Post.manager.get(+params.id) ?? await Post.fetch(booru, +params.id); const post = Post.manager.get(+params.id) ?? await Post.fetch(booru, +params.id);
ele.$viewer.content([ ele.$viewer.content([
post.isVideo post.isVideo
? $('video').src(post.file_url).controls(true) ? $('video').src(post.file_ext === 'zip' ? post.large_file_url : post.file_url).controls(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)})
]) ])
value.uploader$.set(post.uploader$); value.uploader$.set(post.uploader$);

View File

@ -46,8 +46,6 @@ export class Post {
}); });
const userIds = [...new Set(dataArray.map(data => [data.approver_id, data.uploader_id].detype(null)).flat())]; const userIds = [...new Set(dataArray.map(data => [data.approver_id, data.uploader_id].detype(null)).flat())];
User.fetchMultiple(booru, {id: userIds}).then(() => list.forEach(post => post.update$())); User.fetchMultiple(booru, {id: userIds}).then(() => list.forEach(post => post.update$()));
// const tagNames = new Set(dataArray.map(data => data.tag_string.split(' ')).flat());
// Tag.fetchMultiple(booru, {name: {_comma: [...tagNames.values()].toString()}})
return list; return list;
} }
@ -62,7 +60,7 @@ export class Post {
get pathname() { return `/posts/${this.id}` } get pathname() { return `/posts/${this.id}` }
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' } get isVideo() { return this.file_ext === 'mp4' || this.file_ext === 'webm' || this.file_ext === 'zip' }
get tags() { get tags() {
const tag_list = this.tag_string.split(' '); const tag_list = this.tag_string.split(' ');
return [...Tag.manager.values()].filter(tag => tag_list.includes(tag.name)) return [...Tag.manager.values()].filter(tag => tag_list.includes(tag.name))

View File

@ -66,9 +66,9 @@ export interface TagSearchParams {
} }
export enum TagCategory { export enum TagCategory {
General, General = 0,
Artist, Artist = 1,
Copyright, Copyright = 3,
Character, Character = 4,
Meta Meta = 5
} }