✨ Searchable tags and categories
This commit is contained in:
		| @@ -13,6 +13,7 @@ export default function PostItem(props: { | ||||
|   onReply?: (post: any) => void, | ||||
|   onEdit?: (post: any) => void, | ||||
|   onDelete?: (post: any) => void, | ||||
|   onSearch?: (filter: any) => void, | ||||
|   onError: (message: string | null) => void, | ||||
|   onReact: () => void | ||||
| }) { | ||||
| @@ -72,16 +73,22 @@ export default function PostItem(props: { | ||||
|           </a> | ||||
|         </Show> | ||||
|  | ||||
|         <div class="mt-2 flex gap-2"> | ||||
|         <div class="mt-2 mb-5 flex gap-2"> | ||||
|           <For each={props.post.categories}> | ||||
|             {item => <a class="link link-primary pb-5"> | ||||
|               #{item.name} | ||||
|             </a>} | ||||
|             {item => | ||||
|               <a href={`/search?category=${item.alias}`} class="badge badge-primary"> | ||||
|                 <i class="fa-solid fa-layer-group me-1.5"></i> | ||||
|                 {item.name} | ||||
|               </a> | ||||
|             } | ||||
|           </For> | ||||
|           <For each={props.post.tags}> | ||||
|             {item => <a class="link link-primary pb-5"> | ||||
|               #{item.name} | ||||
|             </a>} | ||||
|             {item => | ||||
|               <a href={`/search?tag=${item.alias}`} class="badge badge-accent"> | ||||
|                 <i class="fa-regular fa-tag me-1.5"></i> | ||||
|                 {item.name} | ||||
|               </a> | ||||
|             } | ||||
|           </For> | ||||
|         </div> | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ export default function PostList(props: { | ||||
|   onRepost?: (post: any) => void, | ||||
|   onReply?: (post: any) => void, | ||||
|   onEdit?: (post: any) => void, | ||||
|   onUpdate: (pn: number) => Promise<void>, | ||||
|   onUpdate: (pn: number, filter?: any) => Promise<void>, | ||||
|   onError: (message: string | null) => void | ||||
| }) { | ||||
|   const [loading, setLoading] = createSignal(true); | ||||
| @@ -21,9 +21,9 @@ export default function PostList(props: { | ||||
|   const [page, setPage] = createSignal(1); | ||||
|   const pageCount = createMemo(() => Math.ceil(postCount() / 10)); | ||||
|  | ||||
|   async function readPosts() { | ||||
|   async function readPosts(filter?: any) { | ||||
|     setLoading(true); | ||||
|     await props.onUpdate(page()); | ||||
|     await props.onUpdate(page(), filter); | ||||
|     setLoading(false); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -26,6 +26,7 @@ render(() => ( | ||||
|         <Route path="/" component={Feed}> | ||||
|           <Route path="/" component={Global} /> | ||||
|           <Route path="/posts/:postId" component={PostReference} /> | ||||
|           <Route path="/search" component={lazy(() => import("./pages/search.tsx"))} /> | ||||
|           <Route path="/realms" component={lazy(() => import("./pages/realms"))} /> | ||||
|           <Route path="/realms/:realmId" component={lazy(() => import("./pages/realms/realm.tsx"))} /> | ||||
|           <Route path="/accounts/:accountId" component={lazy(() => import("./pages/account.tsx"))} /> | ||||
|   | ||||
							
								
								
									
										123
									
								
								pkg/view/src/pages/search.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								pkg/view/src/pages/search.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| import { useNavigate, useSearchParams } from "@solidjs/router"; | ||||
| import { createSignal, Show } from "solid-js"; | ||||
| import { createStore } from "solid-js/store"; | ||||
| import PostPublish from "../components/PostPublish.tsx"; | ||||
| import PostList from "../components/PostList.tsx"; | ||||
| import { closeModel, openModel } from "../scripts/modals.ts"; | ||||
|  | ||||
| export default function SearchPage() { | ||||
|   const [searchParams] = useSearchParams(); | ||||
|  | ||||
|   const [error, setError] = createSignal<string | null>(null); | ||||
|  | ||||
|   const [page, setPage] = createSignal(0); | ||||
|   const [info, setInfo] = createSignal<any>(null); | ||||
|  | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
|   async function readPosts(pn?: number) { | ||||
|     if (pn) setPage(pn); | ||||
|     const res = await fetch("/api/posts?" + new URLSearchParams({ | ||||
|       take: (10).toString(), | ||||
|       offset: ((page() - 1) * 10).toString(), | ||||
|       ...searchParams | ||||
|     })); | ||||
|     if (res.status !== 200) { | ||||
|       setError(await res.text()); | ||||
|     } else { | ||||
|       setError(null); | ||||
|       setInfo(await res.json()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   function setMeta(data: any, field: string, open = true) { | ||||
|     const meta: { [id: string]: any } = { | ||||
|       reposting: null, | ||||
|       replying: null, | ||||
|       editing: null | ||||
|     }; | ||||
|     meta[field] = data; | ||||
|     setPublishMeta(meta); | ||||
|  | ||||
|     if (open) openModel("#post-publish"); | ||||
|     else closeModel("#post-publish"); | ||||
|   } | ||||
|  | ||||
|   const [publishMeta, setPublishMeta] = createStore<any>({ | ||||
|     replying: null, | ||||
|     reposting: null, | ||||
|     editing: null | ||||
|   }); | ||||
|  | ||||
|   function getDescribe() { | ||||
|     let builder = []; | ||||
|     if (searchParams["category"]) { | ||||
|       builder.push("category is #" + searchParams["category"]); | ||||
|     } else if (searchParams["tag"]) { | ||||
|       builder.push("tag is #" + searchParams["tag"]); | ||||
|     } | ||||
|  | ||||
|     return builder.join(" and "); | ||||
|   } | ||||
|  | ||||
|   function back() { | ||||
|     if (window.history.length > 0) { | ||||
|       window.history.back(); | ||||
|     } else { | ||||
|       navigate("/"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       <div class="flex pt-1"> | ||||
|         <button class="btn btn-ghost ml-[20px] w-12 h-12" onClick={() => back()}> | ||||
|           <i class="fa-solid fa-angle-left"></i> | ||||
|         </button> | ||||
|         <div class="px-5 flex items-center"> | ||||
|           <p>Search</p> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       <div id="alerts"> | ||||
|         <Show when={error()}> | ||||
|           <div role="alert" class="alert alert-error"> | ||||
|             <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" | ||||
|                  viewBox="0 0 24 24"> | ||||
|               <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" | ||||
|                     d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> | ||||
|             </svg> | ||||
|             <span class="capitalize">{error()}</span> | ||||
|           </div> | ||||
|         </Show> | ||||
|       </div> | ||||
|  | ||||
|       <div role="alert" class="alert alert-info px-[20px]"> | ||||
|         <i class="fa-solid fa-magnifying-glass pl-[13px]"></i> | ||||
|         <span>You will only see posts with <b>{getDescribe()}</b></span> | ||||
|       </div> | ||||
|  | ||||
|       <dialog id="post-publish" class="modal"> | ||||
|         <div class="modal-box p-0 w-[540px]"> | ||||
|           <PostPublish | ||||
|             reposting={publishMeta.reposting} | ||||
|             replying={publishMeta.replying} | ||||
|             editing={publishMeta.editing} | ||||
|             onReset={() => setMeta(null, "none", false)} | ||||
|             onError={setError} | ||||
|             onPost={() => readPosts()} | ||||
|           /> | ||||
|         </div> | ||||
|       </dialog> | ||||
|  | ||||
|       <PostList | ||||
|         info={info()} | ||||
|         onUpdate={readPosts} | ||||
|         onError={setError} | ||||
|         onRepost={(item) => setMeta(item, "reposting")} | ||||
|         onReply={(item) => setMeta(item, "replying")} | ||||
|         onEdit={(item) => setMeta(item, "editing")} | ||||
|       /> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user