new: posts page header.
enhance: hint will show up when no posts is loaded.
fix: [css] login page `login-container` width abnormal on small width screen.
change: set route path `/posts` render same as path `/`
This commit is contained in:
defaultkavy 2024-10-08 00:24:41 +08:00
parent a992af35c2
commit 77d4f78cc2
Signed by: defaultkavy
GPG Key ID: DFBB22C4E69D7826
14 changed files with 136 additions and 87 deletions

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

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

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-La3x4wRW.js"></script> <script type="module" crossorigin src="/assets/index-Djy_8N6Q.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BkbpsU_v.css"> <link rel="stylesheet" crossorigin href="/assets/index-BW2KEYV0.css">
</head> </head>
<body> <body>
</body> </body>

View File

@ -9,17 +9,19 @@
@import '/src/route/login/$login_route'; @import '/src/route/login/$login_route';
:root { :root {
--background-color: #1e1e2c;
--background-color-lighter: #3b3b66;
--background-color-light: #24243b;
--background-color-dark: #12121f;
--background-color-darker: #07070c;
--primary-color: #d1d1ee; --primary-color: #d1d1ee;
--primary-color-dark: #9696b3; --primary-color-dark: #9696b3;
--primary-color-darker: #72728d; --primary-color-darker: #72728d;
--secondary-color: #aeaeec; --secondary-color-9: #aeaeec;
--secondary-color-dark: #6d6da1; --secondary-color-8: #9a9ad6;
--secondary-color-darker: #424268; --secondary-color-7: #7c7cb8;
--secondary-color-6: #646497;
--secondary-color-5: #545486;
--secondary-color-4: #424268;
--secondary-color-3: #3b3b66;
--secondary-color-2: #24243b;
--secondary-color-1: #1e1e2c; // background color
--secondary-color-0: #07070c;
--shadow-color: #09090e50; --shadow-color: #09090e50;
--border-radius-small: 0.4rem; --border-radius-small: 0.4rem;
@ -32,7 +34,7 @@ html {
font-size: 14px; font-size: 14px;
::-webkit-scrollbar { ::-webkit-scrollbar {
background-color: var(--background-color); background-color: var(--secondary-color-1);
width: 8px; width: 8px;
} }
@ -43,7 +45,7 @@ html {
} }
body { body {
overflow-x: hidden; overflow-x: hidden;
background-color: var(--background-color); background-color: var(--secondary-color-1);
color: var(--primary-color); color: var(--primary-color);
margin: 0; margin: 0;
font-family: Microsoft Yahei; font-family: Microsoft Yahei;
@ -56,7 +58,7 @@ nav {
position: fixed; position: fixed;
top: 0; top: 0;
z-index: 100; z-index: 100;
background-color: color-mix(in srgb, var(--background-color) 70%, transparent); background-color: color-mix(in srgb, var(--secondary-color-1) 70%, transparent);
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding-inline: 1rem; padding-inline: 1rem;
@ -69,7 +71,7 @@ nav {
gap: 0.4rem; gap: 0.4rem;
text-decoration: none; text-decoration: none;
.booru-name { .booru-name {
color: var(--secondary-color); color: var(--secondary-color-9);
margin: 0; margin: 0;
} }
@ -77,13 +79,13 @@ nav {
display: flex; display: flex;
align-items: center; align-items: center;
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
// border: 1px solid var(--secondary-color); // border: 1px solid var(--secondary-color-9);
// padding: 0.2rem 0.4rem; // padding: 0.2rem 0.4rem;
margin: 0; margin: 0;
gap: 0.4rem; gap: 0.4rem;
.version { .version {
color: var(--background-color); color: var(--secondary-color-1);
background-color: var(--secondary-color); background-color: var(--secondary-color-9);
padding: 0.2em 0.4em; padding: 0.2em 0.4em;
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
font-size: 0.8rem; font-size: 0.8rem;
@ -92,14 +94,14 @@ nav {
.app-name { .app-name {
display: none; display: none;
font-size: 1rem; font-size: 1rem;
color: var(--secondary-color); color: var(--secondary-color-9);
} }
} }
} }
div.searchbar { div.searchbar {
padding: 0.4rem 10%; padding: 0.4rem 10%;
max-width: 500px; max-width: 500px;
background-color: color-mix(in srgb, var(--background-color-light) 30%, transparent); background-color: color-mix(in srgb, var(--secondary-color-2) 30%, transparent);
border: 1px solid var(--primary-color-darker); border: 1px solid var(--primary-color-darker);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
color: var(--primary-color-dark); color: var(--primary-color-dark);
@ -114,12 +116,12 @@ nav {
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
ion-icon { ion-icon {
// background-color: var(--background-color); // background-color: var(--secondary-color-1);
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: color-mix(in srgb, var(--background-color-lighter) 50%, transparent); background-color: color-mix(in srgb, var(--secondary-color-3) 50%, transparent);
} }
} }
ion-icon.search { ion-icon.search {
@ -134,8 +136,8 @@ nav {
align-items: center; align-items: center;
border-radius: 2rem; border-radius: 2rem;
font-weight: bolder; font-weight: bolder;
color: var(--secondary-color); color: var(--secondary-color-9);
background-color: var(--secondary-color-darker); background-color: var(--secondary-color-4);
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
} }
@ -163,16 +165,26 @@ router {
} }
} }
route#posts {
header {
margin-bottom: 1rem;
h2 {
margin: 0;
}
}
}
button { button {
background-color: var(--secondary-color-darker); background-color: var(--secondary-color-4);
color: var(--secondary-color); color: var(--secondary-color-9);
padding: 0.8rem 1.2rem; padding: 0.8rem 1.2rem;
border-radius: 1rem; border-radius: 1rem;
border: none; border: none;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background-color: var(--secondary-color-dark); background-color: var(--secondary-color-6);
color: var(--primary-color); color: var(--primary-color);
} }
} }
@ -183,24 +195,24 @@ ion-icon {
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: var(--secondary-color); color: var(--secondary-color-9);
} }
} }
a { a {
color: var(--secondary-color);
text-decoration: none; text-decoration: none;
color: var(--secondary-color-9);
} }
input { input {
background-color: var(--background-color-light); background-color: var(--secondary-color-2);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
border: 1px solid var(--background-color-lighter); border: 1px solid var(--secondary-color-3);
font-size: 0.9rem; font-size: 0.9rem;
padding: 0.8rem 1.2rem; padding: 0.8rem 1.2rem;
color: var(--primary-color); color: var(--primary-color);
outline: none; outline: none;
&:focus { &:focus {
border-color: var(--secondary-color); border-color: var(--secondary-color-9);
} }
} }

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

View File

@ -15,18 +15,18 @@ drawer {
width: 300px; width: 300px;
max-width: 70%; max-width: 70%;
height: 100%; height: 100%;
background-color: var(--background-color); background-color: var(--secondary-color-1);
border-radius: var(--border-radius-large); border-radius: var(--border-radius-large);
z-index: 1; z-index: 1;
overflow: hidden; overflow: hidden;
div.user-info { div.user-info {
background-color: var(--background-color-light); background-color: var(--secondary-color-2);
padding: 2rem; padding: 2rem;
.username { .username {
margin: 0; margin: 0;
color: var(--secondary-color); color: var(--secondary-color-9);
cursor: pointer; cursor: pointer;
} }
@ -68,8 +68,8 @@ drawer {
height: 100%; height: 100%;
width: 100%; width: 100%;
background: linear-gradient(90deg, background: linear-gradient(90deg,
color-mix(in srgb, var(--background-color-dark) 50%, transparent) 0%, color-mix(in srgb, var(--secondary-color-1) 50%, transparent) 0%,
color-mix(in srgb, var(--background-color-darker) 70%, transparent) 100% color-mix(in srgb, var(--secondary-color-0) 70%, transparent) 100%
); );
} }
} }

View File

@ -1,4 +1,4 @@
import { $Layout } from "@elexis/layout"; import { $Layout, type $LayoutEventMap } from "@elexis/layout";
import { Booru } from "../../structure/Booru"; import { Booru } from "../../structure/Booru";
import { Post } from "../../structure/Post"; import { Post } from "../../structure/Post";
import { $PostTile } from "../PostTile/$PostTile"; import { $PostTile } from "../PostTile/$PostTile";
@ -6,7 +6,7 @@ import { $PostTile } from "../PostTile/$PostTile";
interface $PostGridOptions { interface $PostGridOptions {
tags?: string tags?: string
} }
export class $PostGrid extends $Layout { export class $PostGrid extends $Layout<$PostGridEventMap> {
posts = new Set<Post>(); posts = new Set<Post>();
$posts = new Set<$PostTile>(); $posts = new Set<$PostTile>();
tags?: string; tags?: string;
@ -25,10 +25,12 @@ export class $PostGrid extends $Layout {
this.removeAll(); this.removeAll();
if (this.finished) { if (this.finished) {
this.finished = false; this.finished = false;
this.events.fire('startLoad');
this.loader(); this.loader();
} }
}) })
this.on('resize', () => this.resize()) this.on('resize', () => this.resize())
this.events.fire('startLoad');
this.loader(); this.loader();
} }
@ -36,11 +38,19 @@ export class $PostGrid extends $Layout {
if (!this.inDOM()) return setTimeout(() => this.loader(), 100);; if (!this.inDOM()) return setTimeout(() => this.loader(), 100);;
while (this.inDOM() && document.documentElement.scrollHeight <= innerHeight * 2) { while (this.inDOM() && document.documentElement.scrollHeight <= innerHeight * 2) {
const posts = await this.getPosts(); const posts = await this.getPosts();
if (!posts.length) return this.finished = true; if (!posts.length) {
this.finished = true;
if (!this.posts.size) this.events.fire('noPost');
return
}
} }
if (document.documentElement.scrollTop + innerHeight > document.documentElement.scrollHeight - innerHeight * 2) { if (document.documentElement.scrollTop + innerHeight > document.documentElement.scrollHeight - innerHeight * 2) {
const posts = await this.getPosts(); const posts = await this.getPosts();
if (!posts.length) return this.finished = true; if (!posts.length) {
this.finished = true;
this.events.fire('endPost');
return
}
} }
setTimeout(() => this.loader(), 100); setTimeout(() => this.loader(), 100);
} }
@ -88,3 +98,9 @@ export class $PostGrid extends $Layout {
get sortedPosts() { return this.posts.array.sort((a, b) => +b.createdDate - +a.createdDate); } get sortedPosts() { return this.posts.array.sort((a, b) => +b.createdDate - +a.createdDate); }
} }
interface $PostGridEventMap extends $LayoutEventMap {
startLoad: [];
noPost: [];
endPost: [];
}

View File

@ -12,7 +12,7 @@ post-tile {
&:hover { &:hover {
transform: scale(1.02); transform: scale(1.02);
z-index: 1; z-index: 1;
box-shadow: 0 0 10px color-mix(in srgb, var(--background-color) 50%, transparent) box-shadow: 0 0 10px color-mix(in srgb, var(--secondary-color-1) 50%, transparent)
} }
} }
@ -25,7 +25,7 @@ post-tile {
} }
div.video-detail, div.gif-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(--secondary-color-3);//color-mix(in srgb, var(--secondary-color-3) 80%, transparent);
color: var(--primary-color); color: var(--primary-color);
bottom: 0.3rem; bottom: 0.3rem;
right: 0.3rem; right: 0.3rem;
@ -37,7 +37,7 @@ post-tile {
align-items: center; align-items: center;
gap: 0.2rem; gap: 0.2rem;
z-index: 2; z-index: 2;
// text-shadow: 0 0 0.5em var(--background-color); // text-shadow: 0 0 0.5em var(--secondary-color-1);
ion-icon { ion-icon {
font-size: 1.4rem; font-size: 1.4rem;
@ -53,17 +53,23 @@ post-tile {
z-index: 2; z-index: 2;
} }
} }
img {
height: 100%; a {
width: 100%; background-color: transparent;
vertical-align: top; padding: 0;
background-color: var(--background-color); border-radius: 0;
} img {
video { height: 100%;
height: 100%; width: 100%;
width: 100%; vertical-align: top;
object-fit: cover; background-color: var(--secondary-color-1);
position: absolute; }
z-index: 1; video {
height: 100%;
width: 100%;
object-fit: cover;
position: absolute;
z-index: 1;
}
} }
} }

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) 100%, transparent); background-color: color-mix(in srgb, var(--secondary-color-2) 100%, transparent);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
font-size: 1rem; font-size: 1rem;
width: 500px; width: 500px;
@ -20,7 +20,7 @@ searchbar {
z-index: 201; z-index: 201;
display: flex; display: flex;
align-items: center; align-items: center;
border: 1px solid var(--secondary-color-darker); border: 1px solid var(--secondary-color-4);
&:focus-within { &:focus-within {
outline: none; outline: none;
@ -39,8 +39,8 @@ searchbar {
tag { tag {
display: inline-block; display: inline-block;
padding: 0.2rem 0.4rem; padding: 0.2rem 0.4rem;
background-color: var(--secondary-color-darker); background-color: var(--secondary-color-4);
color: var(--secondary-color); color: var(--secondary-color-9);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
cursor: pointer; cursor: pointer;
} }
@ -48,10 +48,10 @@ searchbar {
ion-icon { ion-icon {
font-size: 20px; font-size: 20px;
color: var(--secondary-color-darker); color: var(--secondary-color-4);
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: var(--secondary-color); color: var(--secondary-color-9);
} }
} }
} }
@ -59,7 +59,7 @@ searchbar {
div.selection-list-container { div.selection-list-container {
overflow: hidden; overflow: hidden;
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
background-color: var(--background-color); background-color: var(--secondary-color-1);
z-index: 201; z-index: 201;
max-width: calc(100% - 2rem); max-width: calc(100% - 2rem);
width: 500px; width: 500px;
@ -84,10 +84,10 @@ searchbar {
gap: 1rem; gap: 1rem;
&:hover { &:hover {
background-color: color-mix(in srgb, var(--background-color-lighter) 50%, transparent); background-color: color-mix(in srgb, var(--secondary-color-3) 50%, transparent);
} }
&.active { &.active {
background-color: var(--background-color-lighter); background-color: var(--secondary-color-3);
} }
div.selection-label { div.selection-label {
display: flex; display: flex;
@ -116,8 +116,8 @@ searchbar {
padding: 0.1rem 0.4rem; padding: 0.1rem 0.4rem;
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
font-size: 0.9rem; font-size: 0.9rem;
background-color: var(--secondary-color-darker); background-color: var(--secondary-color-4);
color: var(--secondary-color); color: var(--secondary-color-9);
} }
} }
@ -125,7 +125,7 @@ searchbar {
} }
div.filter { div.filter {
background-color: var(--background-color); background-color: var(--secondary-color-1);
opacity: 0.5; opacity: 0.5;
position: fixed; position: fixed;
top: 0; top: 0;
@ -137,7 +137,7 @@ searchbar {
.input-wrapper { .input-wrapper {
color: var(--primary-color); color: var(--primary-color);
border: 1px solid var(--secondary-color); border: 1px solid var(--secondary-color-9);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;

View File

@ -84,9 +84,23 @@ $(document.body).content([
// Base Router // Base Router
$('router').base('/').map([ $('router').base('/').map([
// Home Page // Home Page
$('route').id('posts').path('/').builder(() => new $PostGrid()), $('route').id('posts').path(['/', '/posts']).builder(() => new $PostGrid()),
// Posts Page // Posts Page
$('route').id('posts').path('/posts?tags').builder(({query}) => new $PostGrid({tags: query.tags})), $('route').id('posts').path('/posts?tags').builder(({query}) => {
const $postGrid = new $PostGrid({tags: query.tags});
return [
$('header').content([
$('h2').content('Posts'),
$('div').class('tags').self($div => {
query.tags.split('+').forEach(tag => {
$div.insert($('a').class('tag').content(decodeURIComponent(tag)).href(`posts?tags=${tag}`))
})
})
]),
$('div').class('no-post').content('No Posts').hide(true).self($div => $postGrid.on('noPost', () => $div.hide(false)).on('startLoad', () => $div.hide(true))),
$postGrid
]
}),
// Post Page // Post Page
post_route, post_route,
// Login Page // Login Page

View File

@ -6,12 +6,16 @@ route#login {
.login-container { .login-container {
padding: 2rem; padding: 2rem;
border: 1px solid var(--secondary-color); border: 1px solid var(--secondary-color-9);
border-radius: var(--border-radius-large); border-radius: var(--border-radius-large);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
gap: 1rem; gap: 1rem;
max-width: 400px;
width: 100%;
box-sizing: border-box;
h1 { h1 {
margin: 0; margin: 0;
} }
@ -20,7 +24,7 @@ route#login {
flex-direction: column; flex-direction: column;
gap: 0.5rem; gap: 0.5rem;
input { input {
width: 300px; display: block;
} }
} }
} }

View File

@ -139,17 +139,15 @@
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
span.property-value { span.property-value {
padding: 2px 4px; padding: 0.2rem 0.4rem;
background-color: var(--secondary-color-darker); background-color: var(--secondary-color-1);
color: var(--secondary-color); color: var(--primary-color-dark);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
justify-content: space-between; justify-content: space-between;
flex-shrink: 1; flex-shrink: 1;
display: flex;
&:has(*) { align-items: center;
overflow: hidden; overflow: hidden;
padding: 0;
}
&:has(ion-icon) { &:has(ion-icon) {
flex-shrink: 0; flex-shrink: 0;
@ -157,12 +155,12 @@
* { * {
display: block; display: block;
padding: 2px 4px;
overflow: hidden; overflow: hidden;
text-wrap: nowrap; text-wrap: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
flex-shrink: 1; flex-shrink: 1;
} }
ion-icon { ion-icon {
font-size: 1rem; font-size: 1rem;
padding: 4px; padding: 4px;
@ -183,12 +181,11 @@
align-items: center; align-items: center;
a.tag-name { a.tag-name {
word-break: break-word; word-break: break-word;
color: #d1d1ee;
text-decoration: none; text-decoration: none;
} }
span.tag-post-count { span.tag-post-count {
background-color: var(--secondary-color-darker); background-color: var(--secondary-color-3);
color: var(--secondary-color); color: var(--secondary-color-8);
padding: 0px 4px; padding: 0px 4px;
border-radius: var(--border-radius-small); border-radius: var(--border-radius-small);
font-size: 12px; font-size: 12px;