mirror of
https://github.com/Damillora/Shioriko.git
synced 2024-11-21 20:07:33 +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
|
RUN mkdir -p /web && cp -r web/static web/template /web
|
||||||
|
|
||||||
FROM scratch AS runtime
|
FROM scratch AS runtime
|
||||||
|
|
||||||
|
WORKDIR /
|
||||||
COPY --from=build /shioriko /
|
COPY --from=build /shioriko /
|
||||||
COPY --from=build /web /
|
COPY --from=build /web /web
|
||||||
|
|
||||||
ENTRYPOINT ["/shioriko"]
|
ENTRYPOINT ["/shioriko"]
|
||||||
|
@ -2,6 +2,7 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/Damillora/Shioriko/pkg/config"
|
"github.com/Damillora/Shioriko/pkg/config"
|
||||||
@ -32,9 +33,18 @@ func uploadBlob(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
id := uuid.NewString()
|
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)
|
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 {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
@ -44,7 +54,7 @@ func uploadBlob(c *gin.Context) {
|
|||||||
|
|
||||||
blob := database.Blob{
|
blob := database.Blob{
|
||||||
ID: id,
|
ID: id,
|
||||||
FilePath: filename,
|
FilePath: filepath.Join(folder1, folder2, filename),
|
||||||
}
|
}
|
||||||
database.DB.Create(&blob)
|
database.DB.Create(&blob)
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"svelte": "^3.0.0"
|
"svelte": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"query-string": "^7.0.0",
|
||||||
"sirv-cli": "^1.0.0",
|
"sirv-cli": "^1.0.0",
|
||||||
"svelte-routing": "^1.6.0"
|
"svelte-routing": "^1.6.0"
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,13 @@
|
|||||||
post = data;
|
post = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const trimUrl = (str) => {
|
||||||
|
if(str.length > 30) {
|
||||||
|
return str.substring(0,30) + "...";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {getData()});
|
onMount(() => {getData()});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -25,19 +32,23 @@
|
|||||||
{#if post}
|
{#if post}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="tile is-ancestor">
|
<div class="columns">
|
||||||
<div class="tile is-child is-4 box">
|
<div class="column is-one-third box">
|
||||||
<p>
|
<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>
|
||||||
<p>
|
<p>
|
||||||
Tags:
|
Tags:
|
||||||
{#each post.tags as tag (tag)}
|
{#each post.tags as tag (tag)}
|
||||||
<Link to="/tag/{tag}">{tag}</Link>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<Link to="/tag/{tag}">{tag}</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
{/each}
|
{/each}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="tile is-child">
|
<div class="column">
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img src="{post.image_path}">
|
<img src="{post.image_path}">
|
||||||
</figure>
|
</figure>
|
||||||
|
@ -2,16 +2,34 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { getPosts } from "../api.js";
|
import { getPosts } from "../api.js";
|
||||||
import { Link} from "svelte-routing";
|
import { Link} from "svelte-routing";
|
||||||
|
import queryString from "query-string";
|
||||||
|
|
||||||
|
export let location;
|
||||||
|
|
||||||
let page = 1;
|
let page = 1;
|
||||||
let totalPages = 1;
|
let totalPages = 1;
|
||||||
let posts = [];
|
let posts = [];
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const data = await getPosts({page});
|
const data = await getPosts({page});
|
||||||
posts = data.posts;
|
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>
|
</script>
|
||||||
|
|
||||||
<section class="hero is-primary">
|
<section class="hero is-primary">
|
||||||
@ -24,9 +42,48 @@
|
|||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="container">
|
<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)}
|
{#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">
|
<div class="card-image">
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<Link to="/post/{post.id}">
|
<Link to="/post/{post.id}">
|
||||||
@ -37,7 +94,9 @@
|
|||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{#each post.tags as tag (tag)}
|
{#each post.tags as tag (tag)}
|
||||||
<Link to="/tag/{tag}">{tag}</Link>
|
<p>
|
||||||
|
<Link to="/tag/{tag}">{tag}</Link>
|
||||||
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { getPostsTag } from "../api.js";
|
import { getPostsTag } from "../api.js";
|
||||||
import { Link} from "svelte-routing";
|
import { Link} from "svelte-routing";
|
||||||
|
import queryString from "query-string";
|
||||||
|
|
||||||
|
export let location;
|
||||||
|
|
||||||
export let id;
|
export let id;
|
||||||
|
|
||||||
@ -10,10 +13,25 @@
|
|||||||
let posts = [];
|
let posts = [];
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const data = await getPostsTag({page, tag: id});
|
const data = await getPostsTag({page, tag: id});
|
||||||
posts = data.posts;
|
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>
|
</script>
|
||||||
|
|
||||||
<section class="hero is-primary">
|
<section class="hero is-primary">
|
||||||
@ -22,16 +40,55 @@
|
|||||||
{id}
|
{id}
|
||||||
</p>
|
</p>
|
||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
Tag
|
Tag
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="container">
|
<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)}
|
{#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">
|
<div class="card-image">
|
||||||
<figure class="image">
|
<figure class="image">
|
||||||
<Link to="/post/{post.id}">
|
<Link to="/post/{post.id}">
|
||||||
@ -42,7 +99,9 @@
|
|||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{#each post.tags as tag (tag)}
|
{#each post.tags as tag (tag)}
|
||||||
<Link to="/tag/{tag}">{tag}</Link>
|
<p>
|
||||||
|
<Link to="/tag/{tag}">{tag}</Link>
|
||||||
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</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"
|
resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7"
|
||||||
integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==
|
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:
|
dedent-js@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/dedent-js/-/dedent-js-1.0.1.tgz#bee5fb7c9e727d85dffa24590d10ec1ab1255305"
|
resolved "https://registry.yarnpkg.com/dedent-js/-/dedent-js-1.0.1.tgz#bee5fb7c9e727d85dffa24590d10ec1ab1255305"
|
||||||
@ -235,6 +240,11 @@ fill-range@^7.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range "^5.0.1"
|
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:
|
fs.realpath@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
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"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
|
||||||
integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==
|
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:
|
randombytes@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
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"
|
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
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:
|
supports-color@^5.3.0:
|
||||||
version "5.5.0"
|
version "5.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
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