mirror of
https://github.com/Damillora/Shioriko.git
synced 2024-11-24 21:27:31 +00:00
feat: Post indexes
This commit is contained in:
parent
ba4ebe1793
commit
9624a408b2
@ -8,7 +8,9 @@ RUN CGO_ENABLED=0 GOOS=linux go build -o /shioriko
|
||||
RUN mkdir -p /web && cp -r web/static web/template /web
|
||||
|
||||
FROM scratch AS runtime
|
||||
|
||||
WORKDIR /
|
||||
COPY --from=build /shioriko /
|
||||
COPY --from=build /web /
|
||||
COPY --from=build /web /web
|
||||
|
||||
ENTRYPOINT ["/shioriko"]
|
||||
|
@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Damillora/Shioriko/pkg/config"
|
||||
@ -32,9 +33,18 @@ func uploadBlob(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
id := uuid.NewString()
|
||||
folder1 := id[0:2]
|
||||
if _, err := os.Stat(filepath.Join(dataDir, folder1)); os.IsNotExist(err) {
|
||||
os.Mkdir(filepath.Join(dataDir, folder1), 0755)
|
||||
}
|
||||
folder2 := id[2:4]
|
||||
if _, err := os.Stat(filepath.Join(dataDir, folder1, folder2)); os.IsNotExist(err) {
|
||||
os.Mkdir(filepath.Join(dataDir, folder1, folder2), 0755)
|
||||
}
|
||||
|
||||
filename := id + filepath.Ext(file.Filename)
|
||||
|
||||
err = c.SaveUploadedFile(file, filepath.Join(dataDir, filename))
|
||||
err = c.SaveUploadedFile(file, filepath.Join(dataDir, folder1, folder2, filename))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
@ -44,7 +54,7 @@ func uploadBlob(c *gin.Context) {
|
||||
|
||||
blob := database.Blob{
|
||||
ID: id,
|
||||
FilePath: filename,
|
||||
FilePath: filepath.Join(folder1, folder2, filename),
|
||||
}
|
||||
database.DB.Create(&blob)
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
"svelte": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": "^7.0.0",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"svelte-routing": "^1.6.0"
|
||||
}
|
||||
|
@ -9,6 +9,13 @@
|
||||
post = data;
|
||||
}
|
||||
|
||||
const trimUrl = (str) => {
|
||||
if(str.length > 30) {
|
||||
return str.substring(0,30) + "...";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
onMount(() => {getData()});
|
||||
</script>
|
||||
|
||||
@ -25,19 +32,23 @@
|
||||
{#if post}
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<div class="tile is-ancestor">
|
||||
<div class="tile is-child is-4 box">
|
||||
<div class="columns">
|
||||
<div class="column is-one-third box">
|
||||
<p>
|
||||
Source URL: <a href="//{post.source_url}">{post.source_url}</a>
|
||||
Source URL: <a href="{post.source_url}">{trimUrl(post.source_url)}</a>
|
||||
</p>
|
||||
<p>
|
||||
Tags:
|
||||
{#each post.tags as tag (tag)}
|
||||
<ul>
|
||||
<li>
|
||||
<Link to="/tag/{tag}">{tag}</Link>
|
||||
</li>
|
||||
</ul>
|
||||
{/each}
|
||||
</p>
|
||||
</div>
|
||||
<div class="tile is-child">
|
||||
<div class="column">
|
||||
<figure class="image">
|
||||
<img src="{post.image_path}">
|
||||
</figure>
|
||||
|
@ -2,16 +2,34 @@
|
||||
import { onMount } from "svelte";
|
||||
import { getPosts } from "../api.js";
|
||||
import { Link} from "svelte-routing";
|
||||
import queryString from "query-string";
|
||||
|
||||
export let location;
|
||||
|
||||
let page = 1;
|
||||
let totalPages = 1;
|
||||
let posts = [];
|
||||
const getData = async () => {
|
||||
const data = await getPosts({page});
|
||||
if(Array.isArray(data.posts)) {
|
||||
posts = data.posts;
|
||||
}
|
||||
onMount(() => { getData(); })
|
||||
}
|
||||
onMount(() => {
|
||||
let queryParams;
|
||||
$: queryParams = queryString.parse(location.search);
|
||||
if(queryParams.page) {
|
||||
page = queryParams.page;
|
||||
}
|
||||
getData();
|
||||
})
|
||||
|
||||
const handlePage = (i) => {
|
||||
return () => {
|
||||
page = 1;
|
||||
getData();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="hero is-primary">
|
||||
@ -24,9 +42,48 @@
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="tile is-ancestor">
|
||||
<nav class="pagination" role="navigation" aria-label="pagination">
|
||||
{#if page > 1}
|
||||
<a class="pagination-previous">Previous</a>
|
||||
{/if}
|
||||
{#if page < totalPages}
|
||||
<a class="pagination-next">Next page</a>
|
||||
{/if}
|
||||
<ul class="pagination-list">
|
||||
{#if page > 2}
|
||||
<li>
|
||||
<Link on:click="{handlePage(1)}" to="/posts?page={1}" class="pagination-link" aria-label="Goto page 1">1</Link>
|
||||
</li>
|
||||
<li>
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
</li>
|
||||
{/if}
|
||||
{#each [...Array(5).keys()].map(x => x + page - 2) as i }
|
||||
{#if i >= 1 && i <= totalPages}
|
||||
{#if i == page}
|
||||
<li>
|
||||
<Link on:click="{handlePage(i)}" to="/posts?page={i}" class="pagination-link is-current" aria-label="Goto page {i}">{i}</Link>
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
<Link on:click="{handlePage(i)}" to="/posts?page={i}" class="pagination-link" aria-label="Goto page {i}">{i}</Link>
|
||||
</li>
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
{#if (totalPages - page) > 2}
|
||||
<li>
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link on:click="{handlePage(totalPages)}" to="/posts?page={totalPages}" class="pagination-link" aria-label="Goto page {totalPages}">{totalPages}</Link>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="columns is-multiline">
|
||||
{#each posts as post (post.id)}
|
||||
<div class="tile is-child is-4 card">
|
||||
<div class="column is-one-quarter card">
|
||||
<div class="card-image">
|
||||
<figure class="image">
|
||||
<Link to="/post/{post.id}">
|
||||
@ -37,7 +94,9 @@
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
{#each post.tags as tag (tag)}
|
||||
<p>
|
||||
<Link to="/tag/{tag}">{tag}</Link>
|
||||
</p>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,9 @@
|
||||
import { onMount } from "svelte";
|
||||
import { getPostsTag } from "../api.js";
|
||||
import { Link} from "svelte-routing";
|
||||
import queryString from "query-string";
|
||||
|
||||
export let location;
|
||||
|
||||
export let id;
|
||||
|
||||
@ -10,10 +13,25 @@
|
||||
let posts = [];
|
||||
const getData = async () => {
|
||||
const data = await getPostsTag({page, tag: id});
|
||||
if(Array.isArray(data.posts)) {
|
||||
posts = data.posts;
|
||||
}
|
||||
onMount(() => { getData(); })
|
||||
}
|
||||
onMount(() => {
|
||||
let queryParams;
|
||||
queryParams = queryString.parse(location.search);
|
||||
if(queryParams.page) {
|
||||
page = queryParams.page;
|
||||
}
|
||||
getData();
|
||||
})
|
||||
|
||||
const handlePage = (i) => {
|
||||
return () => {
|
||||
page = 1;
|
||||
getData();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="hero is-primary">
|
||||
@ -29,9 +47,48 @@
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="tile is-ancestor">
|
||||
<nav class="pagination" role="navigation" aria-label="pagination">
|
||||
{#if page > 1}
|
||||
<a class="pagination-previous">Previous</a>
|
||||
{/if}
|
||||
{#if page < totalPages}
|
||||
<a class="pagination-next">Next page</a>
|
||||
{/if}
|
||||
<ul class="pagination-list">
|
||||
{#if page > 2}
|
||||
<li>
|
||||
<Link on:click="{handlePage(1)}" to="/tag/{id}?page={1}" class="pagination-link" aria-label="Goto page 1">1</Link>
|
||||
</li>
|
||||
<li>
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
</li>
|
||||
{/if}
|
||||
{#each [...Array(5).keys()].map(x => x + page - 2) as i }
|
||||
{#if i >= 1 && i <= totalPages}
|
||||
{#if i == page}
|
||||
<li>
|
||||
<Link on:click="{handlePage(i)}" to="/tag/{id}?page={i}" class="pagination-link is-current" aria-label="Goto page {i}">{i}</Link>
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
<Link on:click="{handlePage(i)}" to="/tag/{id}?page={i}" class="pagination-link" aria-label="Goto page {i}">{i}</Link>
|
||||
</li>
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
{#if (totalPages - page) > 2}
|
||||
<li>
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link on:click="{handlePage(totalPages)}" to="/tag/{id}?page={totalPages}" class="pagination-link" aria-label="Goto page {totalPages}">{totalPages}</Link>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="columns is-multiline">
|
||||
{#each posts as post (post.id)}
|
||||
<div class="tile is-child is-4 card">
|
||||
<div class="column is-one-quarter card">
|
||||
<div class="card-image">
|
||||
<figure class="image">
|
||||
<Link to="/post/{post.id}">
|
||||
@ -42,7 +99,9 @@
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
{#each post.tags as tag (tag)}
|
||||
<p>
|
||||
<Link to="/tag/{tag}">{tag}</Link>
|
||||
</p>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -198,6 +198,11 @@ console-clear@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7"
|
||||
integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==
|
||||
|
||||
decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
|
||||
|
||||
dedent-js@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dedent-js/-/dedent-js-1.0.1.tgz#bee5fb7c9e727d85dffa24590d10ec1ab1255305"
|
||||
@ -235,6 +240,11 @@ fill-range@^7.0.1:
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
filter-obj@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
|
||||
integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs=
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
@ -470,6 +480,16 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
|
||||
integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==
|
||||
|
||||
query-string@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.0.0.tgz#aaad2c8d5c6a6d0c6afada877fecbd56af79e609"
|
||||
integrity sha512-Iy7moLybliR5ZgrK/1R3vjrXq03S13Vz4Rbm5Jg3EFq1LUmQppto0qtXz4vqZ386MSRjZgnTSZ9QC+NZOSd/XA==
|
||||
dependencies:
|
||||
decode-uri-component "^0.2.0"
|
||||
filter-obj "^1.1.0"
|
||||
split-on-first "^1.0.0"
|
||||
strict-uri-encode "^2.0.0"
|
||||
|
||||
randombytes@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||
@ -613,6 +633,16 @@ sourcemap-codec@^1.4.4:
|
||||
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||
|
||||
split-on-first@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
|
4707
web/static/bundle.js
4707
web/static/bundle.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user