✨ Reply & Repost
This commit is contained in:
		| @@ -1,7 +1,16 @@ | ||||
| import { createSignal, Show } from "solid-js"; | ||||
| import { getAtk, useUserinfo } from "../stores/userinfo.tsx"; | ||||
|  | ||||
| export default function PostItem(props: { post: any, onError: (message: string | null) => void, onReact: () => void }) { | ||||
| export default function PostItem(props: { | ||||
|   post: any, | ||||
|   noAuthor?: boolean, | ||||
|   noControl?: boolean, | ||||
|   onRepost?: (post: any) => void, | ||||
|   onReply?: (post: any) => void, | ||||
|   onEdit?: (post: any) => void, | ||||
|   onError: (message: string | null) => void, | ||||
|   onReact: () => void | ||||
| }) { | ||||
|   const [reacting, setReacting] = createSignal(false); | ||||
|  | ||||
|   const userinfo = useUserinfo(); | ||||
| @@ -23,79 +32,111 @@ export default function PostItem(props: { post: any, onError: (message: string | | ||||
|  | ||||
|   return ( | ||||
|     <div class="post-item"> | ||||
|  | ||||
|       <a href={`/accounts/${props.post.author.id}`}> | ||||
|         <div class="flex bg-base-200"> | ||||
|           <div class="avatar pl-[20px]"> | ||||
|             <div class="w-12"> | ||||
|               <Show when={props.post.author.avatar} | ||||
|                     fallback={<span class="text-3xl">{props.post.author.name.substring(0, 1)}</span>}> | ||||
|                 <img alt="avatar" src={props.post.author.avatar} /> | ||||
|               </Show> | ||||
|       <Show when={!props.noAuthor}> | ||||
|         <a href={`/accounts/${props.post.author.id}`}> | ||||
|           <div class="flex bg-base-200"> | ||||
|             <div class="avatar pl-[20px]"> | ||||
|               <div class="w-12"> | ||||
|                 <Show when={props.post.author.avatar} | ||||
|                       fallback={<span class="text-3xl">{props.post.author.name.substring(0, 1)}</span>}> | ||||
|                   <img alt="avatar" src={props.post.author.avatar} /> | ||||
|                 </Show> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="flex items-center px-5"> | ||||
|               <div> | ||||
|                 <h3 class="font-bold text-sm">{props.post.author.name}</h3> | ||||
|                 <p class="text-xs">{props.post.author.description}</p> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="flex items-center px-5"> | ||||
|             <div> | ||||
|               <h3 class="font-bold text-sm">{props.post.author.name}</h3> | ||||
|               <p class="text-xs">{props.post.author.description}</p> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </a> | ||||
|         </a> | ||||
|       </Show> | ||||
|  | ||||
|       <article class="py-5 px-7"> | ||||
|       <div class="py-5 px-7"> | ||||
|         <h2 class="card-title">{props.post.title}</h2> | ||||
|         <article class="prose">{props.post.content}</article> | ||||
|       </article> | ||||
|  | ||||
|       <div class="grid grid-cols-3 border-y border-base-200"> | ||||
|  | ||||
|         <div class="grid grid-cols-2"> | ||||
|           <div class="tooltip" data-tip="Daisuki"> | ||||
|             <button type="button" class="btn btn-ghost btn-block" disabled={reacting()} | ||||
|                     onClick={() => reactPost(props.post, "like")}> | ||||
|               <i class="fa-solid fa-thumbs-up"></i> | ||||
|               <code class="font-mono">{props.post.like_count}</code> | ||||
|             </button> | ||||
|         <Show when={props.post.repost_to}> | ||||
|           <p class="text-xs mt-3 mb-2"> | ||||
|             <i class="fa-solid fa-retweet me-2"></i> | ||||
|             Reposted a post | ||||
|           </p> | ||||
|           <div class="border border-base-200"> | ||||
|             <PostItem | ||||
|               noControl | ||||
|               post={props.post.repost_to} | ||||
|               onError={props.onError} | ||||
|               onReact={props.onReact} | ||||
|             /> | ||||
|           </div> | ||||
|  | ||||
|           <div class="tooltip" data-tip="Daikirai"> | ||||
|             <button type="button" class="btn btn-ghost btn-block" disabled={reacting()} | ||||
|                     onClick={() => reactPost(props.post, "dislike")}> | ||||
|               <i class="fa-solid fa-thumbs-down"></i> | ||||
|               <code class="font-mono">{props.post.dislike_count}</code> | ||||
|             </button> | ||||
|         </Show> | ||||
|         <Show when={props.post.reply_to}> | ||||
|           <p class="text-xs mt-3 mb-2"> | ||||
|             <i class="fa-solid fa-reply me-2"></i> | ||||
|             Replied a post | ||||
|           </p> | ||||
|           <div class="border border-base-200"> | ||||
|             <PostItem | ||||
|               noControl | ||||
|               post={props.post.reply_to} | ||||
|               onError={props.onError} | ||||
|               onReact={props.onReact} | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div class="col-span-2 flex justify-end"> | ||||
|           <div class="tooltip" data-tip="Reply"> | ||||
|             <button type="button" class="btn btn-ghost btn-block"> | ||||
|               <i class="fa-solid fa-reply"></i> | ||||
|             </button> | ||||
|           </div> | ||||
|  | ||||
|           <div class="tooltip" data-tip="Repost"> | ||||
|             <button type="button" class="btn btn-ghost btn-block"> | ||||
|               <i class="fa-solid fa-retweet"></i> | ||||
|             </button> | ||||
|           </div> | ||||
|  | ||||
|           <div class="dropdown dropdown-end"> | ||||
|             <div tabIndex="0" role="button" class="btn btn-ghost w-12"> | ||||
|               <i class="fa-solid fa-ellipsis-vertical"></i> | ||||
|             </div> | ||||
|             <ul tabIndex="0" class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"> | ||||
|               <Show when={userinfo?.profiles?.id === props.post.author_id}> | ||||
|                 <li><a>Edit</a></li> | ||||
|               </Show> | ||||
|               <li><a>Report</a></li> | ||||
|             </ul> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         </Show> | ||||
|       </div> | ||||
|  | ||||
|       <Show when={!props.noControl}> | ||||
|         <div class="grid grid-cols-3 border-y border-base-200"> | ||||
|           <div class="grid grid-cols-2"> | ||||
|             <div class="tooltip" data-tip="Daisuki"> | ||||
|               <button type="button" class="btn btn-ghost btn-block" disabled={reacting()} | ||||
|                       onClick={() => reactPost(props.post, "like")}> | ||||
|                 <i class="fa-solid fa-thumbs-up"></i> | ||||
|                 <code class="font-mono">{props.post.like_count}</code> | ||||
|               </button> | ||||
|             </div> | ||||
|  | ||||
|             <div class="tooltip" data-tip="Daikirai"> | ||||
|               <button type="button" class="btn btn-ghost btn-block" disabled={reacting()} | ||||
|                       onClick={() => reactPost(props.post, "dislike")}> | ||||
|                 <i class="fa-solid fa-thumbs-down"></i> | ||||
|                 <code class="font-mono">{props.post.dislike_count}</code> | ||||
|               </button> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           <div class="col-span-2 flex justify-end"> | ||||
|             <div class="tooltip" data-tip="Reply"> | ||||
|               <button type="button" class="btn btn-ghost btn-block" | ||||
|                       onClick={() => props.onReply && props.onReply(props.post)}> | ||||
|                 <i class="fa-solid fa-reply"></i> | ||||
|               </button> | ||||
|             </div> | ||||
|  | ||||
|             <div class="tooltip" data-tip="Repost"> | ||||
|               <button type="button" class="btn btn-ghost btn-block" | ||||
|                       onClick={() => props.onRepost && props.onRepost(props.post)}> | ||||
|                 <i class="fa-solid fa-retweet"></i> | ||||
|               </button> | ||||
|             </div> | ||||
|  | ||||
|             <div class="dropdown dropdown-end"> | ||||
|               <div tabIndex="0" role="button" class="btn btn-ghost w-12"> | ||||
|                 <i class="fa-solid fa-ellipsis-vertical"></i> | ||||
|               </div> | ||||
|               <ul tabIndex="0" class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"> | ||||
|                 <Show when={userinfo?.profiles?.id === props.post.author_id}> | ||||
|                   <li><a onClick={() => props.onEdit && props.onEdit(props.post)}>Edit</a></li> | ||||
|                 </Show> | ||||
|                 <li><a>Report</a></li> | ||||
|               </ul> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </Show> | ||||
|  | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| @@ -5,13 +5,16 @@ import PostItem from "./PostItem.tsx"; | ||||
|  | ||||
| export default function PostList(props: { | ||||
|   info: { data: any[], count: number } | null, | ||||
|   onRepost?: (post: any) => void, | ||||
|   onReply?: (post: any) => void, | ||||
|   onEdit?: (post: any) => void, | ||||
|   onUpdate: (pn: number) => Promise<void>, | ||||
|   onError: (message: string | null) => void | ||||
| }) { | ||||
|   const [loading, setLoading] = createSignal(true); | ||||
|  | ||||
|   const posts = createMemo(() => props.info?.data) | ||||
|   const postCount = createMemo<number>(() => props.info?.count ?? 0) | ||||
|   const posts = createMemo(() => props.info?.data); | ||||
|   const postCount = createMemo<number>(() => props.info?.count ?? 0); | ||||
|  | ||||
|   const [page, setPage] = createSignal(1); | ||||
|   const pageCount = createMemo(() => Math.ceil(postCount() / 10)); | ||||
| @@ -35,7 +38,14 @@ export default function PostList(props: { | ||||
|     <div id="post-list"> | ||||
|       <div id="posts"> | ||||
|         <For each={posts()}> | ||||
|           {item => <PostItem post={item} onReact={() => readPosts()} onError={props.onError} />} | ||||
|           {item => <PostItem | ||||
|             post={item} | ||||
|             onRepost={props.onRepost} | ||||
|             onReply={props.onReply} | ||||
|             onEdit={props.onEdit} | ||||
|             onReact={() => readPosts()} | ||||
|             onError={props.onError} | ||||
|           />} | ||||
|         </For> | ||||
|  | ||||
|         <div class="flex justify-center"> | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import styles from "./PostPublish.module.css"; | ||||
| export default function PostPublish(props: { | ||||
|   replying?: any, | ||||
|   reposting?: any, | ||||
|   editing?: any, | ||||
|   onError: (message: string | null) => void, | ||||
|   onPost: () => void | ||||
| }) { | ||||
| @@ -30,7 +31,9 @@ export default function PostPublish(props: { | ||||
|       body: JSON.stringify({ | ||||
|         alias: data.alias ?? crypto.randomUUID().replace(/-/g, ""), | ||||
|         title: data.title, | ||||
|         content: data.content | ||||
|         content: data.content, | ||||
|         repost_to: props.reposting?.id, | ||||
|         reply_to: props.replying?.id, | ||||
|       }) | ||||
|     }); | ||||
|     if (res.status !== 200) { | ||||
| @@ -60,6 +63,26 @@ export default function PostPublish(props: { | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       <Show when={props.reposting}> | ||||
|         <div role="alert" class="px-5 py-3 bg-base-200"> | ||||
|           <i class="fa-solid fa-circle-info me-3"></i> | ||||
|           You are reposting a post from <b>{props.reposting?.author?.name}</b> | ||||
|         </div> | ||||
|       </Show> | ||||
|       <Show when={props.replying}> | ||||
|         <div role="alert" class="px-5 py-3 bg-base-200"> | ||||
|           <i class="fa-solid fa-circle-info me-3"></i> | ||||
|           You are replying a post from <b>{props.replying?.author?.name}</b> | ||||
|         </div> | ||||
|       </Show> | ||||
|       <Show when={props.editing}> | ||||
|         <div role="alert" class="px-5 py-3 bg-base-200"> | ||||
|           <i class="fa-solid fa-circle-info me-3"></i> | ||||
|           You are editing a post published at{" "} | ||||
|           <b>{new Date(props.editing?.created_at).toLocaleString()}</b> | ||||
|         </div> | ||||
|       </Show> | ||||
|  | ||||
|       <textarea name="content" class={`${styles.publishInput} textarea w-full`} | ||||
|                 placeholder="What's happend?!" /> | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { createSignal, Show } from "solid-js"; | ||||
|  | ||||
| import PostList from "../components/PostList.tsx"; | ||||
| import PostPublish from "../components/PostPublish.tsx"; | ||||
| import { createStore } from "solid-js/store"; | ||||
|  | ||||
| export default function DashboardPage() { | ||||
|   const [error, setError] = createSignal<string | null>(null); | ||||
| @@ -23,6 +24,12 @@ export default function DashboardPage() { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   const [publishMeta, setPublishMeta] = createStore<any>({ | ||||
|     replying: null, | ||||
|     reposting: null, | ||||
|     editing: null | ||||
|   }); | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       <div id="alerts"> | ||||
| @@ -38,9 +45,22 @@ export default function DashboardPage() { | ||||
|         </Show> | ||||
|       </div> | ||||
|  | ||||
|       <PostPublish onPost={() => readPosts()} onError={setError} /> | ||||
|       <PostPublish | ||||
|         replying={publishMeta.replying} | ||||
|         reposting={publishMeta.reposting} | ||||
|         editing={publishMeta.editing} | ||||
|         onPost={() => readPosts()} | ||||
|         onError={setError} | ||||
|       /> | ||||
|  | ||||
|       <PostList info={info()} onUpdate={readPosts} onError={setError} /> | ||||
|       <PostList | ||||
|         info={info()} | ||||
|         onUpdate={readPosts} | ||||
|         onError={setError} | ||||
|         onRepost={(item) => setPublishMeta({ reposting: item, replying: null, editing: null })} | ||||
|         onReply={(item) => setPublishMeta({ reposting: null, replying: item, editing: null })} | ||||
|         onEdit={(item) => setPublishMeta({ reposting: null, replying: null, editing: item })} | ||||
|       /> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user