Ver código fonte

Add public user shared posts page

jerryliao 2 dias atrás
pai
commit
f4c4d6b46e
2 arquivos alterados com 123 adições e 18 exclusões
  1. 32 18
      islands/PostList.tsx
  2. 91 0
      routes/user/[name].tsx

+ 32 - 18
islands/PostList.tsx

@@ -1,7 +1,14 @@
 import Button from "../components/form/Button.tsx";
 
 interface PostListProps {
-  posts: { id: string; title: string; content: string; shared: boolean }[];
+  posts: {
+    id: string;
+    title: string;
+    content: string;
+    shared: boolean;
+    hasPassword?: boolean;
+  }[];
+  readOnly?: boolean;
 }
 
 export default function PostList(props: PostListProps) {
@@ -44,26 +51,33 @@ export default function PostList(props: PostListProps) {
           className="w-full min-w-[180px] border border-gray-200 dark:border-gray-700 dark:bg-gray-800 rounded box-border relative p-4 text-base flex flex-col"
           key={post.id}
         >
-          <span className="font-medium mb-2">{post.title || "Untitled"}</span>
-          <div className="absolute right-4 top-3 text-2xl z-[1]">
-            <i
-              className="bi bi-x cursor-pointer"
-              onClick={() => {
-                onDelete(post.id, post.title);
-              }}
-            />
-          </div>
+          <span className="font-medium mb-2">
+            {post.hasPassword && <i className="bi bi-lock-fill text-sm mr-1" />}
+            <a href={`/${post.id}`}>{post.title || "Untitled"}</a>
+          </span>
+          {!props.readOnly && (
+            <div className="absolute right-4 top-3 text-2xl z-[1]">
+              <i
+                className="bi bi-x cursor-pointer"
+                onClick={() => {
+                  onDelete(post.id, post.title);
+                }}
+              />
+            </div>
+          )}
           <span className="overflow-hidden text-ellipsis whitespace-nowrap mb-2">
             {post.content || "No content"}
           </span>
-          <Button
-            type="button"
-            onClick={() => {
-              onEdit(post.id);
-            }}
-          >
-            Edit
-          </Button>
+          {!props.readOnly && (
+            <Button
+              type="button"
+              onClick={() => {
+                onEdit(post.id);
+              }}
+            >
+              Edit
+            </Button>
+          )}
         </div>
       ))}
     </div>

+ 91 - 0
routes/user/[name].tsx

@@ -0,0 +1,91 @@
+import { Head } from "fresh/runtime";
+import { page, type PageProps } from "fresh";
+import { find } from "utils/db.ts";
+import { define } from "utils/state.ts";
+import PostList from "../../islands/PostList.tsx";
+import ThemeToggle from "../../islands/ThemeToggle.tsx";
+import PageContainer from "../../components/layout/PageContainer.tsx";
+
+interface UserPageProps {
+  userName: string;
+  posts: {
+    id: string;
+    title: string;
+    content: string;
+    shared: boolean;
+    hasPassword: boolean;
+  }[];
+  notFound: boolean;
+}
+
+export const handler = define.handlers({
+  GET(ctx) {
+    const name = ctx.params.name;
+    const user = find("User", { name }, ["id"]);
+    if (user.length === 0) {
+      return page({ userName: name, posts: [], notFound: true });
+    }
+
+    const userId = user[0]["id"] as number;
+    const posts = find("Post", { user_id: userId, shared: 1 }, [
+      "id",
+      "title",
+      "content",
+      "shared",
+      "share_password",
+    ]);
+
+    if (posts.length === 0) {
+      return page({ userName: name, posts: [], notFound: true });
+    }
+
+    return page({
+      userName: name,
+      posts: posts.map((post) => ({
+        id: post["id"] as string,
+        title: post["title"] as string,
+        content: post["content"] as string,
+        shared: post["shared"] === 1,
+        hasPassword: Boolean(post["share_password"]),
+      })),
+      notFound: false,
+    });
+  },
+});
+
+export default define.page((props: PageProps<UserPageProps>) => {
+  const { userName, posts, notFound } = props.data;
+
+  if (notFound) {
+    return (
+      <>
+        <Head>
+          <title>Not Found</title>
+        </Head>
+        <PageContainer centered>
+          <div className="absolute top-3 right-3">
+            <ThemeToggle />
+          </div>
+          <span className="text-xl text-gray-500 dark:text-gray-400">
+            Page not found
+          </span>
+        </PageContainer>
+      </>
+    );
+  }
+
+  return (
+    <>
+      <Head>
+        <title>{userName}'s Shared Posts</title>
+      </Head>
+      <PageContainer>
+        <div className="absolute top-3 right-3">
+          <ThemeToggle />
+        </div>
+        <h1 className="text-2xl font-bold mt-2">{userName}'s Shared Posts</h1>
+        <PostList posts={posts} readOnly />
+      </PageContainer>
+    </>
+  );
+});