mirror of
https://github.com/Damillora/Shioriko.git
synced 2024-12-05 00:53:45 +00:00
Compare commits
4 Commits
36db313d33
...
31763528bf
Author | SHA1 | Date | |
---|---|---|---|
31763528bf | |||
2c56336c4f | |||
afbdc56b71 | |||
316e52cb72 |
@ -1,9 +1,10 @@
|
||||
<script>
|
||||
import { token } from "./stores.js";
|
||||
import { isTokenExpired } from "./login-check.js";
|
||||
|
||||
let loggedIn = false;
|
||||
token.subscribe((value) => {
|
||||
loggedIn = value !== "";
|
||||
loggedIn = !isTokenExpired(value);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -2,10 +2,11 @@
|
||||
import { token } from "./stores.js";
|
||||
import { navigate } from "svelte-routing";
|
||||
import { onMount } from "svelte";
|
||||
import { isTokenExpired } from "./login-check.js";
|
||||
|
||||
let loggedIn = false;
|
||||
token.subscribe((value) => {
|
||||
loggedIn = value !== "";
|
||||
loggedIn = !isTokenExpired(value);
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
const getData = async () => {
|
||||
form.source_url = post.source_url;
|
||||
form.tags = post.tags;
|
||||
form.tags = post.tags.map(x => x.tagType+":"+x.tagName);
|
||||
};
|
||||
|
||||
const onTagChange = (value) => {
|
||||
@ -47,7 +47,29 @@
|
||||
<p class="panel-heading">Edit Post</p>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<label for="source" class="label">Source URL</label>
|
||||
<strong>Uploader:</strong>
|
||||
</div>
|
||||
<div class="row">{post.uploader}</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<strong>Original:</strong>
|
||||
</div>
|
||||
<div class="row">
|
||||
<a href={post.image_path} target="_blank">Image</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<strong>Dimensions:</strong>
|
||||
</div>
|
||||
<div class="row">
|
||||
{post.width}x{post.height}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<label for="source" class="label">Source URL:</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="field">
|
||||
@ -65,7 +87,7 @@
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<label for="tags" class="label">Tags</label>
|
||||
<label for="tags" class="label">Tags:</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="field">
|
||||
|
@ -1,12 +1,13 @@
|
||||
<script>
|
||||
import { Link } from "svelte-routing";
|
||||
import { token } from "./stores.js";
|
||||
import { isTokenExpired } from "./login-check.js";
|
||||
|
||||
let menu_shown = false;
|
||||
|
||||
let loggedIn = false;
|
||||
token.subscribe((value) => {
|
||||
loggedIn = value !== "";
|
||||
loggedIn = !isTokenExpired(value);
|
||||
});
|
||||
|
||||
const toggleMenu = () => {
|
||||
|
@ -7,7 +7,8 @@
|
||||
let tagType = tag.split(":")[0] ?? "";
|
||||
let tagName = tag.split(":")[1] ?? "";
|
||||
let tagDisplay = tagName.split("_").join(" ");
|
||||
|
||||
</script>
|
||||
|
||||
<Link to="/posts?tags={tagName}">{tagDisplay} <span class="is-pulled-right">{num}</span></Link>
|
||||
<Link to="/posts?tags={tagName}"
|
||||
>{tagDisplay} <span class="is-pulled-right">{num}</span></Link
|
||||
>
|
||||
|
@ -21,20 +21,12 @@
|
||||
</div>
|
||||
<div class="row">{post.uploader}</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<strong>Source URL:</strong>
|
||||
</div>
|
||||
<div class="row">
|
||||
<a href={post.source_url}>{trimUrl(post.source_url)}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<strong>Original:</strong>
|
||||
</div>
|
||||
<div class="row">
|
||||
<a href={post.image_path}>Image</a>
|
||||
<a href={post.image_path} target="_blank">Image</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
@ -45,6 +37,14 @@
|
||||
{post.width}x{post.height}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<strong>Source URL:</strong>
|
||||
</div>
|
||||
<div class="row">
|
||||
<a href={post.source_url}>{trimUrl(post.source_url)}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-block column">
|
||||
<div class="row">
|
||||
<p><strong>Tags:</strong></p>
|
||||
|
8
web/app/src/login-check.js
Normal file
8
web/app/src/login-check.js
Normal file
@ -0,0 +1,8 @@
|
||||
const isTokenExpired = (token) => {
|
||||
if (token === "") return true;
|
||||
|
||||
const expiry = (JSON.parse(atob(token.split('.')[1]))).exp;
|
||||
return (Math.floor((new Date).getTime() / 1000)) >= expiry;
|
||||
}
|
||||
|
||||
export { isTokenExpired }
|
@ -1,9 +1,54 @@
|
||||
<script>
|
||||
import Tags from "svelte-tags-input";
|
||||
import { getTagAutocomplete } from "../api.js";
|
||||
import { navigate } from "svelte-routing";
|
||||
|
||||
let searchTerms = [];
|
||||
|
||||
const onTagChange = (value) => {
|
||||
searchTerms = value.detail.tags;
|
||||
};
|
||||
|
||||
const onAutocomplete = async () => {
|
||||
const list = await getTagAutocomplete();
|
||||
return list;
|
||||
};
|
||||
|
||||
const onSearch = (i) => {
|
||||
if (searchTerms.length > 0) {
|
||||
navigate(`/posts?tags=${searchTerms.join("+")}`);
|
||||
} else {
|
||||
navigate(`/posts`);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<section class="hero is-primary is-medium">
|
||||
<section class="hero is-small">
|
||||
<div class="hero-body">
|
||||
<p class="title">Shioriko</p>
|
||||
<p class="subtitle">Booru-style gallery written in Go and Svelte</p>
|
||||
<div class="container has-text-centered">
|
||||
<p class="title">Shioriko</p>
|
||||
<p class="subtitle">Booru-style gallery written in Go and Svelte</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-foot">
|
||||
<div class="container has-text-centered">
|
||||
<form on:submit|preventDefault={onSearch}>
|
||||
<div class="field has-addons">
|
||||
<div class="control is-expanded">
|
||||
<div class="control" id="tags">
|
||||
<Tags
|
||||
tags={searchTerms}
|
||||
addKeys={[9, 32]}
|
||||
on:tags={onTagChange}
|
||||
autoComplete={onAutocomplete}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button type="submit" class="button is-primary"> Search </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -5,7 +5,7 @@
|
||||
let username = "";
|
||||
let password = "";
|
||||
let error = "";
|
||||
|
||||
|
||||
const doLogin = async () => {
|
||||
error = "";
|
||||
try {
|
||||
@ -24,43 +24,45 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<form on:submit|preventDefault={doLogin}>
|
||||
<div class="field">
|
||||
<label for="username" class="label">Username</label>
|
||||
<div class="control">
|
||||
<input
|
||||
id="username"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
bind:value={username}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="password" class="label">Password</label>
|
||||
<div class="control">
|
||||
<input
|
||||
id="password"
|
||||
class="input"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{#if error}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<form on:submit|preventDefault={doLogin}>
|
||||
<div class="field">
|
||||
<p class="has-text-danger">{error}</p>
|
||||
<label for="username" class="label">Username</label>
|
||||
<div class="control">
|
||||
<input
|
||||
id="username"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
bind:value={username}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-link">Login</button>
|
||||
<div class="field">
|
||||
<label for="password" class="label">Password</label>
|
||||
<div class="control">
|
||||
<input
|
||||
id="password"
|
||||
class="input"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{#if error}
|
||||
<div class="field">
|
||||
<p class="has-text-danger">{error}</p>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-link">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -40,6 +40,13 @@
|
||||
const toggleEditMenu = () => {
|
||||
editMenuShown = !editMenuShown;
|
||||
};
|
||||
|
||||
let imagePercentage = "0%";
|
||||
|
||||
$: {
|
||||
if (post)
|
||||
imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%";
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if post}
|
||||
@ -82,8 +89,10 @@
|
||||
<div class="column box">
|
||||
{#if post.width > 1000}
|
||||
<div class="notification is-info">
|
||||
The image has been resized due to size. The original
|
||||
image link is in the sidebar
|
||||
Resized to {imagePercentage} of the original image.
|
||||
<a href={post.image_path} target="_blank"
|
||||
>View original</a
|
||||
>
|
||||
</div>
|
||||
<figure class="image">
|
||||
<img alt={post.id} src={post.preview_path} />
|
||||
@ -97,5 +106,4 @@
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
|
@ -2,7 +2,6 @@
|
||||
import { onMount } from "svelte";
|
||||
import { getPostSearchTag, getTagAutocomplete } from "../api.js";
|
||||
import { Link, navigate } from "svelte-routing";
|
||||
import InfiniteScroll from "svelte-infinite-scroll";
|
||||
import TagLinkNumbered from "../TagLinkNumbered.svelte";
|
||||
import queryString from "query-string";
|
||||
import Tags from "svelte-tags-input";
|
||||
@ -17,6 +16,7 @@
|
||||
let totalPages = 1;
|
||||
let pagination = [];
|
||||
let posts = [];
|
||||
let postCount = 0;
|
||||
let tags = [];
|
||||
let categorizedTags = {};
|
||||
|
||||
@ -26,11 +26,13 @@
|
||||
posts = data.posts;
|
||||
tags = data.tags.sort((a, b) => b.postCount - a.postCount);
|
||||
totalPages = data.totalPage;
|
||||
postCount = data.postCount;
|
||||
pagination = paginate(page, totalPages);
|
||||
} else {
|
||||
posts = [];
|
||||
tags = [];
|
||||
totalPages = 0;
|
||||
postCount = 0;
|
||||
pagination = paginate(page, totalPages);
|
||||
}
|
||||
};
|
||||
@ -65,36 +67,43 @@
|
||||
};
|
||||
|
||||
const changePage = (i) => {
|
||||
page = i;
|
||||
getData();
|
||||
}
|
||||
if (i >= 1 && i <= totalPages) {
|
||||
page = i;
|
||||
getData();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<form on:submit|preventDefault={onSearch}>
|
||||
<div class="field has-addons">
|
||||
<div class="control is-expanded">
|
||||
<div class="control" id="tags">
|
||||
<Tags
|
||||
tags={searchTerms}
|
||||
addKeys={[9, 32]}
|
||||
on:tags={onTagChange}
|
||||
autoComplete={onAutocomplete}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button type="submit" class="button is-primary">
|
||||
Search
|
||||
</button>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-full">
|
||||
<div class="block">
|
||||
<form on:submit|preventDefault={onSearch}>
|
||||
<div class="field has-addons">
|
||||
<div class="control is-expanded">
|
||||
<div class="control" id="tags">
|
||||
<Tags
|
||||
tags={searchTerms}
|
||||
addKeys={[9, 32]}
|
||||
on:tags={onTagChange}
|
||||
autoComplete={onAutocomplete}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button
|
||||
type="submit"
|
||||
class="button is-primary"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="block">
|
||||
<div class="columns">
|
||||
<div class="column is-one-third">
|
||||
<div class="panel is-primary">
|
||||
<div class="panel-heading">Tags</div>
|
||||
@ -105,7 +114,9 @@
|
||||
<li>
|
||||
<TagLinkNumbered
|
||||
class=""
|
||||
tag={tag.tagType+":"+tag.tagName}
|
||||
tag={tag.tagType +
|
||||
":" +
|
||||
tag.tagName}
|
||||
num={tag.postCount}
|
||||
/>
|
||||
</li>
|
||||
@ -115,8 +126,33 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-two-thirds">
|
||||
<div class="column is-two-thirds">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-full">
|
||||
<div class="columns is-multiline">
|
||||
{#each posts as post, i (post.id)}
|
||||
<div class="column is-one-quarter">
|
||||
<div class="block">
|
||||
<div class="card">
|
||||
<div class="card-image">
|
||||
<figure class="image">
|
||||
<Link
|
||||
to="/post/{post.id}"
|
||||
>
|
||||
<img
|
||||
alt={post.id}
|
||||
src={post.thumbnail_path}
|
||||
/>
|
||||
</Link>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-full">
|
||||
<nav
|
||||
class="pagination is-centered"
|
||||
@ -126,12 +162,15 @@
|
||||
<a
|
||||
href={null}
|
||||
on:click={changePage(page - 1)}
|
||||
class="pagination-previous">Previous</a
|
||||
class="pagination-previous"
|
||||
class:is-disabled={page == 1}>Previous</a
|
||||
>
|
||||
<a
|
||||
href={null}
|
||||
on:click={changePage(page + 1)}
|
||||
class="pagination-next">Next page</a
|
||||
class="pagination-next"
|
||||
class:is-disabled={page == totalPages}
|
||||
>Next</a
|
||||
>
|
||||
<ul class="pagination-list">
|
||||
{#each pagination as pageEntry}
|
||||
@ -147,7 +186,7 @@
|
||||
<a
|
||||
href={null}
|
||||
on:click={() =>
|
||||
(changePage(pageEntry))}
|
||||
changePage(pageEntry)}
|
||||
class="pagination-link"
|
||||
class:is-current={page ==
|
||||
pageEntry}
|
||||
@ -160,39 +199,9 @@
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="column is-full">
|
||||
<div class="columns is-multiline">
|
||||
{#each posts as post, i (post.id)}
|
||||
<div class="column is-one-third">
|
||||
<div class="block">
|
||||
<div class="card">
|
||||
<div class="card-image">
|
||||
<figure class="image">
|
||||
<Link
|
||||
to="/post/{post.id}"
|
||||
>
|
||||
<img
|
||||
alt={post.id}
|
||||
src={post.thumbnail_path}
|
||||
/>
|
||||
</Link>
|
||||
</figure>
|
||||
</div>
|
||||
<div class="card-content" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if page >= totalPages}
|
||||
<div class="notification is-primary">
|
||||
<p class="has-text-centered">End of posts</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title">Tag List</h1>
|
||||
<table class="table is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -53,6 +53,7 @@
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title">Upload Image</h1>
|
||||
<form on:submit|preventDefault={onSubmit}>
|
||||
<div class="field">
|
||||
<label for="file" class="label">Image File</label>
|
||||
|
@ -4,7 +4,7 @@
|
||||
const paginate = (c, m) => {
|
||||
let current = c,
|
||||
last = m,
|
||||
delta = 2,
|
||||
delta = 1,
|
||||
left = current - delta,
|
||||
right = current + delta + 1,
|
||||
range = [],
|
||||
|
Loading…
Reference in New Issue
Block a user