make upvotes work
This commit is contained in:
parent
248555f7ad
commit
11deee34a7
4 changed files with 93 additions and 25 deletions
|
|
@ -1,25 +1,62 @@
|
|||
<script lang="ts">
|
||||
import { DateTime } from "luxon";
|
||||
import { RiHashtag, RiHistoryLine, RiUserLine } from "svelte-remixicon";
|
||||
import type { PostEntry } from "./backend";
|
||||
import PostMeta from "./PostMeta.svelte";
|
||||
import { SvelteShowdown } from "svelte-showdown";
|
||||
import VoteButton from "./VoteButton.svelte";
|
||||
|
||||
let { post }: { post: PostEntry } = $props();
|
||||
let { id, title, created_at, content } = post;
|
||||
let { id, title, content = "", votes, my_vote } = post;
|
||||
|
||||
</script>
|
||||
|
||||
<card class="post-frame">
|
||||
<h3 class="post-title">
|
||||
<a href="/={id}">{title}</a>
|
||||
</h3>
|
||||
<PostMeta {post} />
|
||||
<!-- TODO pist content -->
|
||||
<div class="post-content shorten">
|
||||
<SvelteShowdown content={ content || "" } />
|
||||
<article class="card">
|
||||
<div class="post-frame">
|
||||
<h3 class="post-title">
|
||||
<a href="/={id}">{title}</a>
|
||||
</h3>
|
||||
<PostMeta {post} />
|
||||
<div class="post-content shorten">
|
||||
<SvelteShowdown { content } />
|
||||
</div>
|
||||
<aside class="message-stats">
|
||||
<VoteButton score={votes} vote={my_vote} {id} />
|
||||
</aside>
|
||||
</div>
|
||||
</card>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.post-frame {
|
||||
padding-left: 2em;
|
||||
position: relative;
|
||||
}
|
||||
.message-stats {
|
||||
position: absolute;
|
||||
inset-inline-start: 0;
|
||||
top: 0;
|
||||
width: 2em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.shorten {
|
||||
max-height: 18em;
|
||||
overflow-y: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.shorten::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: 16em;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2em;
|
||||
display: block;
|
||||
background: linear-gradient(to bottom, rgba(0,0,0,0) 0%, var(--background) 100%);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
let { post }: { post: PostEntry } = $props();
|
||||
|
||||
let me = getMe();
|
||||
let { title, created_at, id, content = '', to } = post;
|
||||
let { title, id, content = '', to, votes, my_vote } = post;
|
||||
</script>
|
||||
|
||||
<SLayout title={to.display_name + (to.type === 'guild' ? ` (+${to.name})` : to.type === 'user' ? ` (@${to.username})` : '')}>
|
||||
|
|
@ -34,10 +34,10 @@ let { title, created_at, id, content = '', to } = post;
|
|||
<!-- content, formatted as markdown -->
|
||||
</div>
|
||||
</div><!-- .post-body -->
|
||||
<div class="message-stats">
|
||||
<aside class="message-stats">
|
||||
<!-- upvotes / downvotes -->
|
||||
<VoteButton />
|
||||
</div>
|
||||
<VoteButton score={votes} vote={my_vote} {id} />
|
||||
</aside>
|
||||
<ul class="message-options row">
|
||||
{#if me && me.id !== post.author?.id}
|
||||
<li><a href="/report/post/{id}"><RiFlagLine/> Report</a></li>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,46 @@
|
|||
<script lang="ts">
|
||||
import { RiHeartFill, RiHeartLine, RiThumbDownFill, RiThumbDownLine } from "svelte-remixicon";
|
||||
import { backend } from "./backend";
|
||||
|
||||
|
||||
let vote = $state(0);
|
||||
let { score } : { score?: number | null } = $props();
|
||||
let { score = $bindable(null), vote = $bindable(0), id } : { score?: number | null, vote?: 0 | 1 | -1, id: string } = $props();
|
||||
|
||||
async function castVote(v: 0 | 1 | -1) {
|
||||
let readyBackend = await backend.withEvent(null).oath();
|
||||
let result = await readyBackend.submitJson(`post/${id}/upvote`, {
|
||||
vote: v
|
||||
});
|
||||
if (score === null) { return; }
|
||||
if (result.status >= 400) {
|
||||
// TODO toast error?
|
||||
console.error("error:", (await result.json()));
|
||||
return;
|
||||
}
|
||||
let {votes} = await result.json();
|
||||
vote = v;
|
||||
score = votes;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="upvote-button">
|
||||
{#if vote > 0}
|
||||
<button class="inline">
|
||||
<button class="inline up" onclick={() => { castVote(0).then(() => {}); }}>
|
||||
<RiHeartFill />
|
||||
</button>
|
||||
{:else}
|
||||
<button class="inline">
|
||||
<button class="inline" onclick={() => { castVote(1).then(() => {}); }}>
|
||||
<RiHeartLine />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<strong>{score ?? '-'}</strong>
|
||||
|
||||
{#if vote > 0}
|
||||
<button class="inline">
|
||||
{#if vote < 0}
|
||||
<button class="inline down" onclick={() => { castVote(0).then(() => {}); }}>
|
||||
<RiThumbDownFill />
|
||||
</button>
|
||||
{:else}
|
||||
<button class="inline">
|
||||
<button class="inline" onclick={() => { castVote(-1).then(() => {}); }}>
|
||||
<RiThumbDownLine />
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -37,5 +52,18 @@ let { score } : { score?: number | null } = $props();
|
|||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button.inline {
|
||||
color: var(--border);
|
||||
}
|
||||
button.inline.up {
|
||||
color: var(--accent);
|
||||
}
|
||||
button.inline.down {
|
||||
color: var(--c11-accent);
|
||||
}
|
||||
:global(.color-theme-11) button.inline.down, :global(.color-theme-9) button.inline.down {
|
||||
color: var(--c14-accent);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@ export type PostEntry = {
|
|||
author?: UserEntry | null,
|
||||
content?: string,
|
||||
to: UserEntry | GuildEntry ,
|
||||
privacy?: number
|
||||
privacy?: number,
|
||||
votes?: number | null,
|
||||
my_vote?: 1 | -1 | 0,
|
||||
comment_count?: number | null
|
||||
};
|
||||
|
||||
export type ServerHealth = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue