diff --git a/frontend/src/components/partials/PostDetail.tsx b/frontend/src/components/partials/PostDetail.tsx
new file mode 100644
index 0000000..407fea3
--- /dev/null
+++ b/frontend/src/components/partials/PostDetail.tsx
@@ -0,0 +1,308 @@
+import { useState, useRef, useEffect } from "react";
+import { Helmet } from "react-helmet-async";
+import { useNavigate } from "react-router-dom";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Button } from "@/components/ui/button";
+import { ArrowLeft, ChevronDown, ChevronUp, Download } from "lucide-react";
+import { relativeTime, getFirstGrapheme } from "@/lib/utils";
+import { getFileUrl } from "@/services/api";
+import { Document, Page, pdfjs } from "react-pdf";
+import "react-pdf/dist/esm/Page/AnnotationLayer.css";
+import "react-pdf/dist/esm/Page/TextLayer.css";
+
+// Import the worker as an asset with Vite
+import workerSrc from "pdfjs-dist/build/pdf.worker.min.mjs?url";
+pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
+
+// For CMaps (if needed)
+const cMapsUrl = "pdfjs-dist/cmaps/";
+
+interface PostDetailProps {
+ post: {
+ post_id: string;
+ mature: boolean;
+ title: {
+ [key: string]: string;
+ };
+ description: {
+ [key: string]: string;
+ };
+ creator: {
+ [key: string]: string;
+ };
+ source_site: {
+ name: string;
+ };
+ date: {
+ [key: string]: string;
+ };
+ tags: string[];
+ media: Array<{
+ type: string;
+ mimetype: string;
+ hash: string;
+ }>;
+ };
+}
+
+// Media Renderer component to render different media types
+const MediaRenderer = ({ item, index, alt }) => {
+ const [numPages, setNumPages] = useState(null);
+ const [pageNumber, setPageNumber] = useState(1);
+ const [pdfError, setPdfError] = useState(false);
+ const containerRef = useRef(null);
+ const [width, setWidth] = useState(null);
+
+ // Update container width when it changes
+ const updateWidth = () => {
+ if (containerRef.current) {
+ setWidth(containerRef.current.clientWidth);
+ }
+ };
+
+ // Setup resize listener
+ useEffect(() => {
+ updateWidth(); // Initial width
+ window.addEventListener('resize', updateWidth);
+ return () => window.removeEventListener('resize', updateWidth);
+ }, []);
+
+ // Event handlers for react-pdf
+ const onDocumentLoadSuccess = ({ numPages }) => {
+ setNumPages(numPages);
+ updateWidth(); // Update width after document loads
+ };
+
+ const onDocumentLoadError = (error) => {
+ console.error("Error loading PDF:", error);
+ setPdfError(true);
+ };
+
+ const changePage = (offset) => {
+ const newPage = pageNumber + offset;
+ if (newPage >= 1 && newPage <= numPages) {
+ setPageNumber(newPage);
+ }
+ };
+
+ switch (item.type) {
+ case "image":
+ return (
+
+ );
+ case "video":
+ return (
+
+ );
+ case "pdf":
+ return (
+
Unable to display PDF in browser
+ +Loading PDF...
+Error loading PDF
+Unsupported file format
+ +{post.description.content}
++ Posted: {relativeTime(post.date.created)} +
++ Imported: {relativeTime(post.date.imported)} +
++ Tags: {post.tags.map((tag) => tag).join(", ")} +
++ Mature: {post.mature ? 'Yes' : 'No'} +
+