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>
|
<script>
|
||||||
|
import moment from 'moment';
|
||||||
import { getNamedId } from '$lib/util';
|
import { getNamedId } from '$lib/util';
|
||||||
import Avatar from './avatar.svelte';
|
import Avatar from './avatar.svelte';
|
||||||
import GlowFX from './fx/glowfx.svelte';
|
import GlowFX from './fx/glowfx.svelte';
|
||||||
@ -7,11 +8,21 @@
|
|||||||
import Rating from './rating.svelte';
|
import Rating from './rating.svelte';
|
||||||
import RatingVertical from './ratingvertical.svelte';
|
import RatingVertical from './ratingvertical.svelte';
|
||||||
import Useritem from './useritem.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}
|
* @type {import('$types/base').Post}
|
||||||
*/
|
*/
|
||||||
export let post;
|
export let post;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
export let opened = false;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style type="scss">
|
<style type="scss">
|
||||||
@ -38,7 +49,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.postCard {
|
.postCard {
|
||||||
display: block;
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
@ -69,17 +83,26 @@
|
|||||||
.sidePad {
|
.sidePad {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
padding: 18px 0px;
|
padding-top: 14px;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mention {
|
.mentionBar {
|
||||||
text-decoration: none;
|
display: flex;
|
||||||
color: var(--accent);
|
flex-flow: row nowrap;
|
||||||
padding: 0em 0.2em;
|
gap: 8px;
|
||||||
background: var(--accent-dim);
|
align-items: center;
|
||||||
border-radius: 0.2em;
|
|
||||||
|
& > .dot {
|
||||||
|
font-size: 0.4em;
|
||||||
|
color: var(--white-dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > .date {
|
||||||
|
color: var(--white-dim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="postContainer">
|
<div class="postContainer">
|
||||||
@ -87,14 +110,20 @@
|
|||||||
<Avatar size={32}></Avatar>
|
<Avatar size={32}></Avatar>
|
||||||
<RatingVertical rating={post.rating}></RatingVertical>
|
<RatingVertical rating={post.rating}></RatingVertical>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<GlowFX borderRadius={18} opacity={0.7} style="flex: 1;">
|
<GlowFX borderRadius={18} opacity={0.7} style="flex: 1;">
|
||||||
<div class="postCardOutline">
|
<div class="postCardOutline" style={opened ? "opacity: 0.0;" : "opacity: 1.0;"}>
|
||||||
<a class="postCard" href="/posts/{getNamedId(post.id, post.name)}">
|
<button class="postCard" on:click={() => {dispatch('previewPost', {post: post});}}>
|
||||||
|
<div class="mentionBar">
|
||||||
<Mention user={post.author}></Mention>
|
<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>
|
<h6 class="title taviraj-regular">{post.name}</h6>
|
||||||
<p>{post.category.name}</p>
|
<p class="typeContent">{post.category.name}</p>
|
||||||
<p>{post.content}</p>
|
<p class="typeContent">{post.content}</p>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</GlowFX>
|
</GlowFX>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,22 +1,105 @@
|
|||||||
<script>
|
<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[]}
|
* @type {import("$types/base").Post[]}
|
||||||
*/
|
*/
|
||||||
export let posts = [];
|
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>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss">
|
||||||
.postList {
|
.postList {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
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>
|
</style>
|
||||||
|
|
||||||
<div class="postList">
|
<div class="postList">
|
||||||
{#each posts as post}
|
{#each posts as post, index}
|
||||||
<Postcard post={post}></Postcard>
|
<PostCard post={post} on:previewPost={previewPost} opened={hidden[index]}></PostCard>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
padding: 32px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import Comment from "$comp/comment.svelte";
|
import Post from "$comp/page/post.svelte";
|
||||||
import Mention from "$comp/mention.svelte";
|
|
||||||
import UserItem from "$comp/useritem.svelte";
|
|
||||||
import { buildCommentTree } from "$lib/client/nodetree";
|
import { buildCommentTree } from "$lib/client/nodetree";
|
||||||
import { getNamedId, gotoNamedId } from "$lib/util";
|
import { gotoNamedId } from "$lib/util";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,36 +13,11 @@
|
|||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
$: post = data.post;
|
$: post = data.post;
|
||||||
|
|
||||||
$: commentTree = buildCommentTree(data.comments);
|
$: commentTree = buildCommentTree(data.comments);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
gotoNamedId(post.id, post.name);
|
gotoNamedId(post.id, post.name);
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<Post post={post} commentTree={commentTree}></Post>
|
||||||
.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>
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user