Refactor: Posts Page and Preview
This commit is contained in:
parent
a9cc16e2e6
commit
8419bc248f
97
src/comp/page/post.svelte
Normal file
97
src/comp/page/post.svelte
Normal file
@ -0,0 +1,97 @@
|
||||
<script>
|
||||
import moment from "moment";
|
||||
import Mention from "$comp/mention.svelte";
|
||||
import Comment from "$comp/comment.svelte";
|
||||
import UserItem from "$comp/useritem.svelte";
|
||||
import { buildCommentTree } from "$lib/client/nodetree";
|
||||
import { getNamedId, gotoNamedId } from "$lib/util";
|
||||
import { onMount } from "svelte";
|
||||
import Rating from "$comp/rating.svelte";
|
||||
|
||||
/**
|
||||
* @type {import("$types/base").Post}
|
||||
*/
|
||||
export let post;
|
||||
|
||||
/**
|
||||
* @type {import("$types/base").CommentTreeNode[] | null}
|
||||
*/
|
||||
export let commentTree = null;
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.post {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
gap: 16px
|
||||
}
|
||||
|
||||
.postHead {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
& > .date {
|
||||
color: var(--white-dim);
|
||||
}
|
||||
}
|
||||
|
||||
.commentList {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.comments {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.commentsHead {
|
||||
width: 100%;
|
||||
border-bottom: 2px solid var(--accent-dim);
|
||||
|
||||
margin-top: 32px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="body">
|
||||
<article class="post">
|
||||
<div class="postHead">
|
||||
<UserItem user={post.author} iconSize={28}></UserItem>
|
||||
<h1 class="typeTitle">{post.name}</h1>
|
||||
<span class="date">{moment(post.postDate).fromNow()}</span>
|
||||
</div>
|
||||
|
||||
<p class="postContent">
|
||||
{post.content}
|
||||
</p>
|
||||
|
||||
<Rating rating={post.rating}></Rating>
|
||||
</article>
|
||||
|
||||
<!-- <UserItem user={post.author}></UserItem>
|
||||
|
||||
<p>{post.content}</p> -->
|
||||
|
||||
<!-- <Message message={post}></Message> -->
|
||||
|
||||
{#if commentTree}
|
||||
<section class="comments">
|
||||
<h3 class="commentsHead typeName">Comments</h3>
|
||||
|
||||
<div class="commentList">
|
||||
{#each commentTree as reply}
|
||||
<Comment commentNode={reply}></Comment>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { getNamedId } from '$lib/util';
|
||||
import Avatar from './avatar.svelte';
|
||||
import GlowFX from './fx/glowfx.svelte';
|
||||
@ -7,11 +8,21 @@
|
||||
import Rating from './rating.svelte';
|
||||
import RatingVertical from './ratingvertical.svelte';
|
||||
import Useritem from './useritem.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
/**
|
||||
* @type {import('$types/base').Post}
|
||||
*/
|
||||
export let post;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
export let opened = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
</script>
|
||||
|
||||
<style type="scss">
|
||||
@ -38,7 +49,10 @@
|
||||
}
|
||||
|
||||
.postCard {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
||||
width: 100%;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
@ -69,17 +83,26 @@
|
||||
.sidePad {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 18px 0px;
|
||||
padding-top: 14px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.mention {
|
||||
text-decoration: none;
|
||||
color: var(--accent);
|
||||
padding: 0em 0.2em;
|
||||
background: var(--accent-dim);
|
||||
border-radius: 0.2em;
|
||||
.mentionBar {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
& > .dot {
|
||||
font-size: 0.4em;
|
||||
color: var(--white-dim);
|
||||
}
|
||||
|
||||
& > .date {
|
||||
color: var(--white-dim);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="postContainer">
|
||||
@ -87,14 +110,20 @@
|
||||
<Avatar size={32}></Avatar>
|
||||
<RatingVertical rating={post.rating}></RatingVertical>
|
||||
</div>
|
||||
|
||||
<GlowFX borderRadius={18} opacity={0.7} style="flex: 1;">
|
||||
<div class="postCardOutline">
|
||||
<a class="postCard" href="/posts/{getNamedId(post.id, post.name)}">
|
||||
<div class="postCardOutline" style={opened ? "opacity: 0.0;" : "opacity: 1.0;"}>
|
||||
<button class="postCard" on:click={() => {dispatch('previewPost', {post: post});}}>
|
||||
<div class="mentionBar">
|
||||
<Mention user={post.author}></Mention>
|
||||
<span class="dot typeContent">•</span>
|
||||
<span class="date typeContent">{moment(post.postDate).fromNow()}</span>
|
||||
</div>
|
||||
|
||||
<h6 class="title taviraj-regular">{post.name}</h6>
|
||||
<p>{post.category.name}</p>
|
||||
<p>{post.content}</p>
|
||||
</a>
|
||||
<p class="typeContent">{post.category.name}</p>
|
||||
<p class="typeContent">{post.content}</p>
|
||||
</button>
|
||||
</div>
|
||||
</GlowFX>
|
||||
</div>
|
||||
|
||||
@ -1,22 +1,105 @@
|
||||
<script>
|
||||
import Postcard from './postcard.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { buildCommentTree } from '$lib/client/nodetree';
|
||||
import { getNamedId } from '$lib/util';
|
||||
import Post from './page/post.svelte';
|
||||
import PostCard from './postcard.svelte';
|
||||
|
||||
/**
|
||||
* @type {import("$types/base").Post[]}
|
||||
*/
|
||||
export let posts = [];
|
||||
|
||||
/** @type {import("$types/base").Post | null} */
|
||||
$: currentPreview = null;
|
||||
|
||||
/** @type {boolean[]} */
|
||||
$: hidden = Array(posts.length).fill(false);
|
||||
|
||||
function previewPost(/** @type {CustomEvent<>} */ e) {
|
||||
/** @type {import("$types/base").Post} */
|
||||
const post = e.detail.post;
|
||||
|
||||
currentPreview = post;
|
||||
|
||||
posts.forEach((p, index) => {
|
||||
hidden[index] = p == post;
|
||||
});
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
currentPreview = null;
|
||||
|
||||
hidden = Array(posts.length).fill(false);
|
||||
}
|
||||
|
||||
function expand() {
|
||||
if (currentPreview == null) return;
|
||||
|
||||
goto(`/posts/${getNamedId(currentPreview.id, currentPreview.name)}`, {
|
||||
replaceState: false
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.postList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.postPreview {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background: #0a0a0a80;
|
||||
backdrop-filter: blur(3px);
|
||||
|
||||
opacity: 0.0;
|
||||
pointer-events: none;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
&[data-visible] {
|
||||
opacity: 1.0;
|
||||
pointer-events: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 80vw;
|
||||
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
background: var(--background);
|
||||
|
||||
padding: 32px;
|
||||
border-radius: 16px;
|
||||
|
||||
pointer-events: all;
|
||||
|
||||
box-shadow: 0px 0px 16px var(--accent-dim);
|
||||
outline: 2px solid var(--accent-dim);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="postList">
|
||||
{#each posts as post}
|
||||
<Postcard post={post}></Postcard>
|
||||
{#each posts as post, index}
|
||||
<PostCard post={post} on:previewPost={previewPost} opened={hidden[index]}></PostCard>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<button class="postPreview" data-visible={currentPreview != null || null} on:click={dismiss}>
|
||||
<button class="preview" on:click={expand}>
|
||||
{#if currentPreview}
|
||||
<Post post={currentPreview} commentTree={null}></Post>
|
||||
{/if}
|
||||
</button>
|
||||
</button>
|
||||
|
||||
0
src/comp/postpreview.svelte
Normal file
0
src/comp/postpreview.svelte
Normal file
@ -23,6 +23,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 32px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<script>
|
||||
import Comment from "$comp/comment.svelte";
|
||||
import Mention from "$comp/mention.svelte";
|
||||
import UserItem from "$comp/useritem.svelte";
|
||||
import Post from "$comp/page/post.svelte";
|
||||
import { buildCommentTree } from "$lib/client/nodetree";
|
||||
import { getNamedId, gotoNamedId } from "$lib/util";
|
||||
import { gotoNamedId } from "$lib/util";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
/**
|
||||
@ -15,36 +13,11 @@
|
||||
export let data;
|
||||
|
||||
$: post = data.post;
|
||||
|
||||
$: commentTree = buildCommentTree(data.comments);
|
||||
|
||||
onMount(() => {
|
||||
gotoNamedId(post.id, post.name);
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.post {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="post">
|
||||
<h1 class="taviraj-light">{post.name}</h1>
|
||||
|
||||
<UserItem user={post.author}></UserItem>
|
||||
|
||||
<p>{post.content}</p>
|
||||
|
||||
<div>
|
||||
{#each commentTree as reply}
|
||||
<Comment commentNode={reply}></Comment>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<Post post={post} commentTree={commentTree}></Post>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user