mirror of
https://github.com/Damillora/phoebe.git
synced 2025-03-10 14:07:22 +00:00
feat: another UI change
This commit is contained in:
parent
4c2fb159a9
commit
1fd9e364bb
@ -112,6 +112,7 @@ func postGetOne(c *gin.Context) {
|
|||||||
Width: post.Blob.Width,
|
Width: post.Blob.Width,
|
||||||
Height: post.Blob.Height,
|
Height: post.Blob.Height,
|
||||||
Uploader: post.User.Username,
|
Uploader: post.User.Username,
|
||||||
|
UploadDate: post.CreatedAt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type PostReadModel struct {
|
type PostReadModel struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
ImagePreviewPath string `json:"preview_path"`
|
ImagePreviewPath string `json:"preview_path"`
|
||||||
@ -9,6 +11,7 @@ type PostReadModel struct {
|
|||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
Uploader string `json:"uploader"`
|
Uploader string `json:"uploader"`
|
||||||
|
UploadDate time.Time `json:"upload_date"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagReadModel struct {
|
type TagReadModel struct {
|
||||||
|
11
pkg/web/package-lock.json
generated
11
pkg/web/package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bulma": "^1.0.3",
|
"bulma": "^1.0.3",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"query-string": "^8.1.0"
|
"query-string": "^8.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -1853,6 +1854,16 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/kossnocorp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bulma": "^1.0.3",
|
"bulma": "^1.0.3",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"query-string": "^8.1.0"
|
"query-string": "^8.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
pkg/web/src/lib/components/panels/DeletePostPanel.svelte
Normal file
38
pkg/web/src/lib/components/panels/DeletePostPanel.svelte
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<script>
|
||||||
|
import { postDelete } from "$lib/api";
|
||||||
|
|
||||||
|
let { id, toggleDeleteMenu, onDelete } = $props();
|
||||||
|
let deleteLoading = $state(false);
|
||||||
|
|
||||||
|
const deletePost = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
deleteLoading = true;
|
||||||
|
const success = await postDelete({ id });
|
||||||
|
deleteLoading = false;
|
||||||
|
toggleDeleteMenu(e);
|
||||||
|
onDelete(success);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="block">
|
||||||
|
<div class="panel is-danger">
|
||||||
|
<p class="panel-heading">Delete Post</p>
|
||||||
|
{#if !deleteLoading}
|
||||||
|
<div class="panel-block">
|
||||||
|
Are you sure to delete post {id}?
|
||||||
|
</div>
|
||||||
|
<div class="panel-block column">
|
||||||
|
<button onclick={deletePost} class="button is-danger"
|
||||||
|
>Delete</button
|
||||||
|
>
|
||||||
|
<button class="button" onclick={toggleDeleteMenu}>Cancel</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="panel-block column">
|
||||||
|
<progress class="progress is-small is-danger" max="100"
|
||||||
|
></progress>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
let { isActive = $bindable(false), post, onSubmit }: Props = $props();
|
let { isActive = $bindable(false), post, onSubmit }: Props = $props();
|
||||||
|
|
||||||
|
let editLoading = $state(false);
|
||||||
|
|
||||||
const toggleEditModal = (e) => {
|
const toggleEditModal = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
isActive = !isActive;
|
isActive = !isActive;
|
||||||
@ -37,9 +39,10 @@
|
|||||||
|
|
||||||
const onFormSubmit = async (e) => {
|
const onFormSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
editLoading = true;
|
||||||
const response = await postUpdate(post.id, form);
|
const response = await postUpdate(post.id, form);
|
||||||
toggleEditModal();
|
editLoading = false;
|
||||||
|
toggleEditModal(e);
|
||||||
onSubmit();
|
onSubmit();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,6 +54,7 @@
|
|||||||
<form onsubmit={onFormSubmit}>
|
<form onsubmit={onFormSubmit}>
|
||||||
<div class="panel is-warning">
|
<div class="panel is-warning">
|
||||||
<p class="panel-heading">Edit Post</p>
|
<p class="panel-heading">Edit Post</p>
|
||||||
|
{#if !editLoading}
|
||||||
<div class="panel-block column">
|
<div class="panel-block column">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<strong>Uploader:</strong>
|
<strong>Uploader:</strong>
|
||||||
@ -115,5 +119,10 @@
|
|||||||
>Cancel</button
|
>Cancel</button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="panel-block column">
|
||||||
|
<progress class="progress is-small is-warning" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -2,16 +2,12 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { updateTagNotes } from "$lib/api";
|
import { updateTagNotes } from "$lib/api";
|
||||||
|
|
||||||
let {
|
let { tag, data, toggleEditMenu, onSubmit } = $props();
|
||||||
tag,
|
|
||||||
data,
|
|
||||||
toggleEditMenu,
|
|
||||||
onSubmit
|
|
||||||
} = $props();
|
|
||||||
|
|
||||||
let form = $state({
|
let form = $state({
|
||||||
note: "",
|
note: "",
|
||||||
});
|
});
|
||||||
|
let editNotesLoading = $state(false);
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
form.note = data.tagNote;
|
form.note = data.tagNote;
|
||||||
@ -19,7 +15,9 @@
|
|||||||
|
|
||||||
const onFormSubmit = async (e) => {
|
const onFormSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
editNotesLoading = true;
|
||||||
await updateTagNotes(tag, form);
|
await updateTagNotes(tag, form);
|
||||||
|
editNotesLoading = false;
|
||||||
toggleEditMenu();
|
toggleEditMenu();
|
||||||
|
|
||||||
onSubmit();
|
onSubmit();
|
||||||
@ -33,18 +31,21 @@
|
|||||||
<form onsubmit={onFormSubmit}>
|
<form onsubmit={onFormSubmit}>
|
||||||
<div class="panel is-warning">
|
<div class="panel is-warning">
|
||||||
<p class="panel-heading">Edit Notes</p>
|
<p class="panel-heading">Edit Notes</p>
|
||||||
<div class="panel-block column">
|
{#if !editNotesLoading}
|
||||||
<textarea
|
<div class="panel-block column">
|
||||||
bind:value={form.note}
|
<textarea bind:value={form.note} class="textarea has-fixed-size"
|
||||||
class="textarea has-fixed-size"
|
></textarea>
|
||||||
></textarea>
|
<div class="content"></div>
|
||||||
<div class="content"></div>
|
</div>
|
||||||
</div>
|
<div class="panel-block column">
|
||||||
<div class="panel-block column">
|
<button type="submit" class="button is-primary">Save</button>
|
||||||
<button type="submit" class="button is-primary">Save</button>
|
<button onclick={toggleEditMenu} class="button">Cancel</button>
|
||||||
<button onclick={toggleEditMenu} class="button"
|
</div>
|
||||||
>Cancel</button
|
{:else}
|
||||||
>
|
<div class="panel-block column">
|
||||||
</div>
|
<progress class="progress is-small is-warning" max="100"
|
||||||
|
></progress>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -2,19 +2,16 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
import { getTagTypes, updateTag } from "$lib/api";
|
import { getTagTypes, updateTag } from "$lib/api";
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
|
||||||
let {
|
let { tag, data, toggleRenameMenu, onSubmit } = $props();
|
||||||
tag,
|
|
||||||
data,
|
|
||||||
toggleRenameMenu,
|
|
||||||
onSubmit
|
|
||||||
} = $props();
|
|
||||||
|
|
||||||
let tagTypes = $state([]);
|
let tagTypes = $state([]);
|
||||||
let form = $state({
|
let form = $state({
|
||||||
name: "",
|
name: "",
|
||||||
tagTypeId: 1,
|
tagTypeId: 1,
|
||||||
});
|
});
|
||||||
|
let editTagLoading = $state(false);
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
tagTypes = await getTagTypes();
|
tagTypes = await getTagTypes();
|
||||||
@ -25,10 +22,9 @@
|
|||||||
|
|
||||||
const onFormSubmit = async (e) => {
|
const onFormSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
editTagLoading = true;
|
||||||
await updateTag(tag, form);
|
await updateTag(tag, form);
|
||||||
|
editTagLoading = false;
|
||||||
goto("/tags/" + form.name);
|
|
||||||
|
|
||||||
onSubmit(form.name);
|
onSubmit(form.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,56 +36,54 @@
|
|||||||
<form onsubmit={onFormSubmit}>
|
<form onsubmit={onFormSubmit}>
|
||||||
<div class="panel is-warning">
|
<div class="panel is-warning">
|
||||||
<p class="panel-heading">Edit Tag</p>
|
<p class="panel-heading">Edit Tag</p>
|
||||||
<div class="panel-block column">
|
{#if !editTagLoading}
|
||||||
<div class="row">
|
<div class="panel-block column">
|
||||||
<strong>Name:</strong>
|
<div class="row">
|
||||||
</div>
|
<strong>Name:</strong>
|
||||||
<div class="row">
|
</div>
|
||||||
<div class="field">
|
<div class="row">
|
||||||
<div class="control">
|
<div class="field">
|
||||||
<input
|
<div class="control">
|
||||||
class="input"
|
<input
|
||||||
type="text"
|
class="input"
|
||||||
bind:value={form.name}
|
type="text"
|
||||||
/>
|
bind:value={form.name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="panel-block column">
|
||||||
<div class="panel-block column">
|
<div class="row">
|
||||||
<div class="row">
|
<strong>Category:</strong>
|
||||||
<strong>Category:</strong>
|
</div>
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="row">
|
<div class="field">
|
||||||
<div class="field">
|
<div class="select">
|
||||||
<div class="select">
|
<select bind:value={form.tagTypeId}>
|
||||||
<select bind:value={form.tagTypeId}>
|
{#each tagTypes as tagType}
|
||||||
{#each tagTypes as tagType}
|
<option
|
||||||
<option
|
value={tagType.id}
|
||||||
value={tagType.id}
|
selected={form.tagTypeId === tagType.id}
|
||||||
selected={form.tagTypeId === tagType.id}
|
>
|
||||||
>
|
{tagType.name}
|
||||||
{tagType.name}
|
</option>
|
||||||
</option>
|
{/each}
|
||||||
{/each}
|
</select>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="panel-block column">
|
||||||
<div class="panel-block column">
|
<button class="button is-primary" type="submit">Submit</button>
|
||||||
<div class="row">
|
<button onclick={toggleRenameMenu} class="button">Cancel</button
|
||||||
<strong>Posts:</strong>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
{:else}
|
||||||
{data.postCount} (<a href="/posts?tags={tag}">Browse</a>)
|
<div class="panel-block column">
|
||||||
|
<progress class="progress is-small is-warning" max="100"
|
||||||
|
></progress>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
<div class="panel-block column">
|
|
||||||
<button class="button is-primary" type="submit">Submit</button>
|
|
||||||
<button onclick={toggleRenameMenu} class="button"
|
|
||||||
>Cancel</button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AuthCheck from "$lib/components/checks/AuthCheck.svelte";
|
import AuthCheck from "$lib/components/checks/AuthCheck.svelte";
|
||||||
import TagLinkNumbered from "$lib/components/ui/TagLinkNumbered.svelte";
|
import TagLinkNumbered from "$lib/components/ui/TagLinkNumbered.svelte";
|
||||||
let { post, toggleEditMenu, toggleDeleteMenu } = $props();
|
import { format, formatDistanceToNow } from "date-fns";
|
||||||
|
let { post } = $props();
|
||||||
|
|
||||||
|
let tabPage = $state(1);
|
||||||
|
|
||||||
|
const changeTab = (tab) => {
|
||||||
|
tabPage = tab;
|
||||||
|
}
|
||||||
const trimUrl = (str) => {
|
const trimUrl = (str) => {
|
||||||
if (str.length > 30) {
|
if (str.length > 30) {
|
||||||
return str.substring(0, 30) + "...";
|
return str.substring(0, 30) + "...";
|
||||||
@ -13,6 +19,27 @@
|
|||||||
|
|
||||||
<div class="panel is-primary">
|
<div class="panel is-primary">
|
||||||
<p class="panel-heading">Post</p>
|
<p class="panel-heading">Post</p>
|
||||||
|
<div class="panel-tabs">
|
||||||
|
<a href={"#"} class:is-active="{tabPage == 1}" onclick={() => changeTab(1)}>Tags</a>
|
||||||
|
<a href={"#"} class:is-active="{tabPage == 2}" onclick={() => changeTab(2)}>Information</a>
|
||||||
|
</div>
|
||||||
|
{#if tabPage === 1}
|
||||||
|
|
||||||
|
{#if post.tags}
|
||||||
|
{#each post.tags as tag (tag)}
|
||||||
|
<TagLinkNumbered
|
||||||
|
tag={tag.tagType + ":" + tag.tagName}
|
||||||
|
num={tag.postCount}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{:else if tabPage == 2}
|
||||||
|
<div class="panel-block column">
|
||||||
|
<div class="row">
|
||||||
|
<strong>Upload Date:</strong>
|
||||||
|
</div>
|
||||||
|
<div class="row"><time title={format(post.upload_date, "dd MMMM yyyy HH:mm:ss")} datetime={post.upload_date} >{formatDistanceToNow(post.upload_date, {addSuffix: true })}</time></div>
|
||||||
|
</div>
|
||||||
<div class="panel-block column">
|
<div class="panel-block column">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<strong>Uploader:</strong>
|
<strong>Uploader:</strong>
|
||||||
@ -43,38 +70,5 @@
|
|||||||
<a href={post.source_url}>{trimUrl(post.source_url)}</a>
|
<a href={post.source_url}>{trimUrl(post.source_url)}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-block column">
|
{/if}
|
||||||
<div class="row">
|
|
||||||
<p><strong>Tags:</strong></p>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="menu">
|
|
||||||
<ul class="menu-list">
|
|
||||||
{#if post.tags}
|
|
||||||
{#each post.tags as tag (tag)}
|
|
||||||
<li>
|
|
||||||
<TagLinkNumbered
|
|
||||||
class=""
|
|
||||||
tag={tag.tagType + ":" + tag.tagName}
|
|
||||||
num={tag.postCount}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<AuthCheck>
|
|
||||||
<p class="panel-block column">
|
|
||||||
<button
|
|
||||||
onclick={toggleEditMenu}
|
|
||||||
class="button is-primary">Edit</button
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
onclick={toggleDeleteMenu}
|
|
||||||
class="button is-danger">Delete</button
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</AuthCheck>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
let { tag, data, toggleRenameMenu } = $props();
|
let { tag, data, toggleRenameMenu } = $props();
|
||||||
let related_tags = $state([]);
|
let related_tags = $state([]);
|
||||||
|
|
||||||
|
let tabPage = $state(1);
|
||||||
|
|
||||||
|
const changeTab = (tab) => {
|
||||||
|
tabPage = tab;
|
||||||
|
};
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
related_tags = await getRelatedTags({ tag });
|
related_tags = await getRelatedTags({ tag });
|
||||||
related_tags = related_tags
|
related_tags = related_tags
|
||||||
@ -21,52 +27,45 @@
|
|||||||
|
|
||||||
<div class="panel is-primary">
|
<div class="panel is-primary">
|
||||||
<p class="panel-heading">Tag</p>
|
<p class="panel-heading">Tag</p>
|
||||||
<div class="panel-block column">
|
<div class="panel-tabs">
|
||||||
<div class="row">
|
<a
|
||||||
<strong>Name:</strong>
|
href={"#"}
|
||||||
</div>
|
class:is-active={tabPage == 1}
|
||||||
<div class="row">{data.tagName}</div>
|
onclick={() => changeTab(1)}>Information</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={"#"}
|
||||||
|
class:is-active={tabPage == 2}
|
||||||
|
onclick={() => changeTab(2)}>Related Tags</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-block column">
|
{#if tabPage === 1}
|
||||||
<div class="row">
|
<div class="panel-block column">
|
||||||
<strong>Category:</strong>
|
<div class="row">
|
||||||
|
<strong>Name:</strong>
|
||||||
|
</div>
|
||||||
|
<div class="row">{data.tagName}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row"><TagTypeIndicator tagType={data.tagType} /></div>
|
<div class="panel-block column">
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="panel-block column">
|
<strong>Category:</strong>
|
||||||
<div class="row">
|
</div>
|
||||||
<strong>Posts:</strong>
|
<div class="row"><TagTypeIndicator tagType={data.tagType} /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="panel-block column">
|
||||||
{data.postCount} (<a href="/posts?tags={tag}">Browse</a>)
|
<div class="row">
|
||||||
</div>
|
<strong>Posts:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-block column">
|
<div class="row">
|
||||||
<div class="row">
|
{data.postCount}
|
||||||
<strong>Related Tags:</strong>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="menu">
|
|
||||||
<ul class="menu-list">
|
|
||||||
{#each related_tags as tag (tag)}
|
|
||||||
<li>
|
|
||||||
<TagLinkNumbered
|
|
||||||
class=""
|
|
||||||
tag={tag.tagType + ":" + tag.tagName}
|
|
||||||
num={tag.postCount}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{:else if tabPage === 2}
|
||||||
<AuthCheck>
|
{#each related_tags as tag (tag)}
|
||||||
<div class="panel-block column">
|
<TagLinkNumbered
|
||||||
<button
|
tag={tag.tagType + ":" + tag.tagName}
|
||||||
onclick={toggleRenameMenu}
|
num={tag.postCount}
|
||||||
class="button is-primary">Rename</button
|
/>
|
||||||
>
|
{/each}
|
||||||
</div>
|
{/if}
|
||||||
</AuthCheck>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
let tagDisplay = tagName.split("_").join(" ");
|
let tagDisplay = tagName.split("_").join(" ");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a href="/posts?tags={tagName}">
|
<a class="panel-block is-block" href="/posts?tags={tagName}">
|
||||||
<span>
|
<span>
|
||||||
{tagDisplay}
|
{tagDisplay}
|
||||||
</span>
|
</span>
|
||||||
<TagTypeIndicator tagType={tagType}></TagTypeIndicator>
|
<TagTypeIndicator {tagType}></TagTypeIndicator>
|
||||||
<span class="is-pulled-right">{num}</span>
|
<span class="is-pulled-right">{num}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -7,15 +7,17 @@
|
|||||||
|
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
import ShiorikoImage from "$lib/components/ui/ShiorikoImage.svelte";
|
import ShiorikoImage from "$lib/components/ui/ShiorikoImage.svelte";
|
||||||
|
import AuthCheck from "$lib/components/checks/AuthCheck.svelte";
|
||||||
|
import DeletePostPanel from "$lib/components/panels/DeletePostPanel.svelte";
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
|
|
||||||
let post: any = $state();
|
let post: any = $state();
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
|
post = null;
|
||||||
const data = await getPost({ id });
|
const data = await getPost({ id });
|
||||||
post = data;
|
post = data;
|
||||||
imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%";
|
imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%";
|
||||||
};
|
};
|
||||||
let loading = $state(false);
|
|
||||||
let isOriginal = $state(false);
|
let isOriginal = $state(false);
|
||||||
|
|
||||||
const trimUrl = (str: string) => {
|
const trimUrl = (str: string) => {
|
||||||
@ -25,25 +27,22 @@
|
|||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let deleteMenuShown = $state(false);
|
let deleteMenuShown = $state(false);
|
||||||
|
|
||||||
const onSubmitEdit = () => {
|
const onSubmitEdit = () => {
|
||||||
getData();
|
getData();
|
||||||
editMenuShown = false;
|
editMenuShown = false;
|
||||||
}
|
};
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
getData();
|
getData();
|
||||||
});
|
});
|
||||||
|
|
||||||
const deletePost = async (e) => {
|
const onDelete = async (success) => {
|
||||||
e.preventDefault();
|
|
||||||
toggleDeleteMenu(e);
|
|
||||||
const success = await postDelete({ id });
|
|
||||||
if (success) {
|
if (success) {
|
||||||
goto("/posts");
|
goto("/posts");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleDeleteMenu = (e) => {
|
const toggleDeleteMenu = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
deleteMenuShown = !deleteMenuShown;
|
deleteMenuShown = !deleteMenuShown;
|
||||||
@ -64,68 +63,85 @@
|
|||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column is-one-third">
|
<div class="column is-one-third">
|
||||||
{#if post}
|
{#if post}
|
||||||
{#if editMenuShown == false && deleteMenuShown == false}
|
<div class="block">
|
||||||
<ViewPostPanel
|
<ViewPostPanel {post} />
|
||||||
{post}
|
</div>
|
||||||
{toggleDeleteMenu}
|
{#if editMenuShown == true && deleteMenuShown == false}
|
||||||
{toggleEditMenu}
|
<div class="block">
|
||||||
/>
|
<EditPostPanel
|
||||||
{:else if editMenuShown == true}
|
bind:isActive={editMenuShown}
|
||||||
<EditPostPanel
|
{post}
|
||||||
bind:isActive={editMenuShown}
|
onSubmit={onSubmitEdit}
|
||||||
{post}
|
/>
|
||||||
onSubmit={onSubmitEdit}
|
|
||||||
/>
|
|
||||||
{:else if deleteMenuShown == true}
|
|
||||||
<div class="panel is-danger">
|
|
||||||
<p class="panel-heading">Delete Post</p>
|
|
||||||
<div class="panel-block">
|
|
||||||
Are you sure to delete post {post.id}?
|
|
||||||
</div>
|
|
||||||
<div class="panel-block column">
|
|
||||||
<button
|
|
||||||
onclick={deletePost}
|
|
||||||
class="button is-danger">Delete</button
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="button"
|
|
||||||
onclick={toggleDeleteMenu}>Cancel</button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
{:else if deleteMenuShown == true}
|
||||||
|
<DeletePostPanel
|
||||||
|
id={post.id}
|
||||||
|
{toggleDeleteMenu}
|
||||||
|
{onDelete}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<AuthCheck>
|
||||||
|
<div class="panel is-info">
|
||||||
|
<div class="panel-heading">Post Actions</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="panel-block"
|
||||||
|
href={post.image_path}
|
||||||
|
target="_blank">View Original</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={"#"}
|
||||||
|
onclick={toggleEditMenu}
|
||||||
|
class="panel-block">Edit</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={"#"}
|
||||||
|
onclick={toggleDeleteMenu}
|
||||||
|
class="panel-block">Delete</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</AuthCheck>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="skeleton-block"></div>
|
<div class="skeleton-block"></div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="column box">
|
<div class="column is-two-thirds">
|
||||||
{#if post}
|
{#if post}
|
||||||
{#if post.width > 1000 && isOriginal == false}
|
<div class="block">
|
||||||
<div class="notification is-info">
|
{#if post.width > 1000 && isOriginal == false}
|
||||||
Resized to {imagePercentage} of the original image.
|
<div class="notification is-info">
|
||||||
<a
|
Resized to {imagePercentage} of the original image.
|
||||||
onclick={() => {
|
<a
|
||||||
isOriginal = true;
|
href={"#"}
|
||||||
}}>View original</a
|
onclick={() => {
|
||||||
>
|
isOriginal = true;
|
||||||
</div>
|
}}>View original</a
|
||||||
<figure class="image">
|
>
|
||||||
<ShiorikoImage
|
</div>
|
||||||
alt={post.id}
|
<div class="box">
|
||||||
src={post.preview_path}
|
<figure class="image">
|
||||||
/>
|
<ShiorikoImage
|
||||||
</figure>
|
alt={post.id}
|
||||||
{:else}
|
src={post.preview_path}
|
||||||
<div class="notification is-primary">
|
/>
|
||||||
Currently viewing original image.
|
</figure>
|
||||||
</div>
|
</div>
|
||||||
<figure class="image">
|
{:else}
|
||||||
<ShiorikoImage
|
<div class="notification is-primary">
|
||||||
alt={post.id}
|
Currently viewing original image.
|
||||||
src={post.image_path}
|
</div>
|
||||||
/>
|
<div class="box">
|
||||||
</figure>
|
<figure class="image">
|
||||||
{/if}
|
<ShiorikoImage
|
||||||
|
alt={post.id}
|
||||||
|
src={post.image_path}
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="skeleton-block"></div>
|
<div class="skeleton-block"></div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -127,32 +127,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-block column">
|
{#if !loading}
|
||||||
{#if !loading}
|
{#each tags as tag (tag)}
|
||||||
<div class="row">
|
<TagLinkNumbered
|
||||||
<strong>Tags:</strong>
|
class=""
|
||||||
</div>
|
tag={tag.tagType + ":" + tag.tagName}
|
||||||
<div class="row">
|
num={tag.postCount}
|
||||||
<div class="menu">
|
/>
|
||||||
<ul class="menu-list">
|
{/each}
|
||||||
{#each tags as tag (tag)}
|
{:else}
|
||||||
<li>
|
<div class="skeleton-block"></div>
|
||||||
<TagLinkNumbered
|
{/if}
|
||||||
class=""
|
|
||||||
tag={tag.tagType +
|
|
||||||
":" +
|
|
||||||
tag.tagName}
|
|
||||||
num={tag.postCount}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div class="skeleton-block"></div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{#if tagInfo}
|
{#if tagInfo}
|
||||||
<div class="panel is-info">
|
<div class="panel is-info">
|
||||||
|
@ -1,52 +1,63 @@
|
|||||||
<script>
|
<script>
|
||||||
import { run } from 'svelte/legacy';
|
import { run } from "svelte/legacy";
|
||||||
|
|
||||||
import { getTags } from "$lib/api";
|
import { getTags } from "$lib/api";
|
||||||
import { afterNavigate } from '$app/navigation';
|
import { afterNavigate } from "$app/navigation";
|
||||||
import TagTypeIndicator from '$lib/components/ui/TagTypeIndicator.svelte';
|
import TagTypeIndicator from "$lib/components/ui/TagTypeIndicator.svelte";
|
||||||
|
|
||||||
let tags = $state([]);
|
let tags = $state([]);
|
||||||
let loading = $state(false);
|
let loading = $state(false);
|
||||||
|
let highestCount = $state(1);
|
||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const data = await getTags();
|
const data = await getTags();
|
||||||
tags = data;
|
tags = data;
|
||||||
loading = false;
|
loading = false;
|
||||||
|
highestCount = Math.max(...data.map((x) => x.postCount));
|
||||||
|
if (highestCount <= 0) {
|
||||||
|
highestCount = 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
afterNavigate(() => {
|
afterNavigate(() => {
|
||||||
loading = true;
|
loading = true;
|
||||||
getData();
|
getData();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="title">Tag List</h1>
|
<h1 class="title">Tag List</h1>
|
||||||
{#if !loading}
|
{#if !loading}
|
||||||
<table class="table is-fullwidth">
|
<table class="table is-fullwidth">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
|
||||||
<th >Tag</th>
|
|
||||||
<th style="width: 30%;">Tag Type</th>
|
|
||||||
<th style="width: 10%;">Post Count</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each tags as tag}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<th>Tag</th>
|
||||||
<a href="/tags/{tag.tagName}">{tag.tagName}</a>
|
<th>Post Count</th>
|
||||||
</td>
|
|
||||||
<td><TagTypeIndicator tagType={tag.tagType} /></td>
|
|
||||||
<td>{tag.postCount}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{#each tags as tag}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/tags/{tag.tagName}"
|
||||||
|
>{tag.tagName}
|
||||||
|
<TagTypeIndicator
|
||||||
|
tagType={tag.tagType}
|
||||||
|
/></a
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="is-pulled-right"
|
||||||
|
>{tag.postCount}</span
|
||||||
|
></td
|
||||||
|
>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="skeleton-block"></div>
|
<div class="skeleton-block"></div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
@ -9,6 +9,7 @@
|
|||||||
import PostGallery from "$lib/components/ui/PostGallery.svelte";
|
import PostGallery from "$lib/components/ui/PostGallery.svelte";
|
||||||
|
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
|
import AuthCheck from "$lib/components/checks/AuthCheck.svelte";
|
||||||
let { tag } = $state($page.params);
|
let { tag } = $state($page.params);
|
||||||
|
|
||||||
let data = $state();
|
let data = $state();
|
||||||
@ -16,6 +17,7 @@
|
|||||||
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
|
data = null;
|
||||||
data = await getTag({ tag });
|
data = await getTag({ tag });
|
||||||
const response = await getPosts({
|
const response = await getPosts({
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -40,6 +42,7 @@
|
|||||||
|
|
||||||
const onTagSubmit = (newName) => {
|
const onTagSubmit = (newName) => {
|
||||||
tag = newName;
|
tag = newName;
|
||||||
|
toggleEditMenu();
|
||||||
getData();
|
getData();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,15 +56,28 @@
|
|||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column is-one-third">
|
<div class="column is-one-third">
|
||||||
{#if data}
|
{#if data}
|
||||||
|
<div class="block">
|
||||||
|
<ViewTagPanel {tag} {data} />
|
||||||
|
</div>
|
||||||
{#if renameMenuShown}
|
{#if renameMenuShown}
|
||||||
|
<div class="block">
|
||||||
<EditTagPanel
|
<EditTagPanel
|
||||||
{tag}
|
{tag}
|
||||||
{data}
|
{data}
|
||||||
{toggleRenameMenu}
|
{toggleRenameMenu}
|
||||||
onSubmit={onTagSubmit}
|
onSubmit={onTagSubmit}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<ViewTagPanel {tag} {data} {toggleRenameMenu} />
|
<AuthCheck>
|
||||||
|
<div class="panel is-info">
|
||||||
|
<div class="panel-heading">Tag Actions</div>
|
||||||
|
<a class="panel-block" href="/posts?tags={tag}">Browse Posts</a>
|
||||||
|
<a onclick={toggleRenameMenu} class="panel-block"
|
||||||
|
>Rename</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</AuthCheck>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="skeleton-block"></div>
|
<div class="skeleton-block"></div>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
let fileName = $state("");
|
let fileName = $state("");
|
||||||
let similar = $state([]);
|
let similar = $state([]);
|
||||||
let previewUrl = $state("");
|
let previewUrl = $state("");
|
||||||
|
let loading = $state(false);
|
||||||
|
|
||||||
let form = $state({
|
let form = $state({
|
||||||
blob_id: "",
|
blob_id: "",
|
||||||
@ -23,6 +24,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFileChange = async (e) => {
|
const onFileChange = async (e) => {
|
||||||
|
loading = true;
|
||||||
var file = e.target.files[0];
|
var file = e.target.files[0];
|
||||||
fileName = "";
|
fileName = "";
|
||||||
previewUrl = "";
|
previewUrl = "";
|
||||||
@ -38,6 +40,7 @@
|
|||||||
fileName = file.name;
|
fileName = file.name;
|
||||||
previewUrl = response.previewUrl;
|
previewUrl = response.previewUrl;
|
||||||
}
|
}
|
||||||
|
loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTagChange = (value) => {
|
const onTagChange = (value) => {
|
||||||
@ -94,6 +97,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{#if currentProgress > 0 && currentProgress < 100}
|
||||||
|
<div class="panel-block column">
|
||||||
|
<progress
|
||||||
|
class="progress is-primary is-small"
|
||||||
|
value={currentProgress}
|
||||||
|
max="100"
|
||||||
|
>
|
||||||
|
{currentProgress}%
|
||||||
|
</progress>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="panel-block column">
|
<div class="panel-block column">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="source" class="label"
|
<label for="source" class="label"
|
||||||
@ -143,7 +157,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-two-thirds">
|
<div class="column is-two-thirds">
|
||||||
<div class="box">
|
<div class="block">
|
||||||
{#if fileName}
|
{#if fileName}
|
||||||
{#if similar.length > 0}
|
{#if similar.length > 0}
|
||||||
<div class="notification is-warning">
|
<div class="notification is-warning">
|
||||||
@ -157,21 +171,11 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="notification is-primary">
|
<div class="notification is-success">
|
||||||
{fileName} has been succesfully uploaded.
|
{fileName} has been succesfully uploaded.
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<figure class="image">
|
|
||||||
<ShiorikoImage alt={fileName} src={previewUrl} />
|
|
||||||
</figure>
|
|
||||||
{:else if currentProgress > 0 && currentProgress < 100}
|
{:else if currentProgress > 0 && currentProgress < 100}
|
||||||
<progress
|
|
||||||
class="progress is-primary"
|
|
||||||
value={currentProgress}
|
|
||||||
max="100"
|
|
||||||
>
|
|
||||||
{currentProgress}%
|
|
||||||
</progress>
|
|
||||||
<div class="notification is-info">
|
<div class="notification is-info">
|
||||||
Your image is currently uploading...
|
Your image is currently uploading...
|
||||||
</div>
|
</div>
|
||||||
@ -181,6 +185,15 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if fileName}
|
||||||
|
<div class="box">
|
||||||
|
<figure class="image">
|
||||||
|
<ShiorikoImage alt={fileName} src={previewUrl} />
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
{:else if loading && !(currentProgress > 0 && currentProgress < 100)}
|
||||||
|
<div class="skeleton-block"></div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user