diff --git a/lib/utils.ts b/lib/utils.ts index 1bf04cc..ea44560 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,6 +1,8 @@ import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; import { BASE_URL } from "./consts"; +import type { ProjectSchema } from "~/server/db/schema/project"; +import type { FileSchema } from "~/server/db/schema/file"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); @@ -13,3 +15,13 @@ export function getFileExt(filename: string) { export function getUrl(...path: string[]) { return BASE_URL + ("/" + path.join("/")).replace(/\/\/+/g, "/"); } + +export function getPreviewUrl( + project: Pick, + file: string | Pick +) { + return getUrl( + `api/preview/${project.slug}`, + typeof file === "string" ? file : file.path + ); +} diff --git a/package.json b/package.json index b0436ed..50a193c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dev": "tsx watch --ignore *.mjs server/index.ts", + "dev": "tsx server/index.ts", + "dev:watch": "tsx watch --ignore *.mjs server/index.ts", "start": "NODE_ENV=production tsx server/index.ts", "build": "vite build", "generate": "drizzle-kit generate:sqlite", @@ -42,6 +43,7 @@ "@codemirror/lang-json": "^6.0.1", "@emmetio/codemirror6-plugin": "^0.3.0", "@hookform/resolvers": "^3.3.4", + "@paralleldrive/cuid2": "^2.2.2", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-slot": "^1.0.2", diff --git a/pages/@id/+Page.tsx b/pages/@id/+Page.tsx deleted file mode 100644 index 0db676b..0000000 --- a/pages/@id/+Page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { useData } from "~/renderer/hooks"; -import { Data } from "./+data"; -import Link from "~/renderer/link"; - -const ViewPostPage = () => { - const { post } = useData(); - - return ( -
- Go Back -

{post.title}

-

{post.body}

-
- ); -}; - -export default ViewPostPage; diff --git a/pages/@id/+data.ts b/pages/@id/+data.ts deleted file mode 100644 index 6362bc7..0000000 --- a/pages/@id/+data.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PageContext } from "vike/types"; - -export const data = async (ctx: PageContext) => { - const id = ctx.routeParams?.id; - const post = await fetch( - "https://jsonplaceholder.typicode.com/posts/" + id - ).then((response) => response.json()); - - return { post, title: post?.title }; -}; - -export type Data = Awaited>; diff --git a/pages/index/+Page.tsx b/pages/index/+Page.tsx index ccc6579..32e8b08 100644 --- a/pages/index/+Page.tsx +++ b/pages/index/+Page.tsx @@ -3,19 +3,15 @@ import { useData } from "~/renderer/hooks"; import Link from "~/renderer/link"; const HomePage = () => { - const { posts } = useData(); - - if (!posts?.length) { - return

No posts.

; - } + const { projects } = useData(); return (

Posts

- {posts.map((post: any) => ( - - {post.title} + {projects.map((project: any) => ( + + {project.title} ))}
diff --git a/pages/index/+data.ts b/pages/index/+data.ts index dde8e69..9f827ea 100644 --- a/pages/index/+data.ts +++ b/pages/index/+data.ts @@ -1,9 +1,12 @@ -export const data = async () => { - const posts = await fetch( - "https://jsonplaceholder.typicode.com/posts?_limit=20" - ).then((response) => response.json()); +import { PageContext } from "vike/types"; +import trpcServer from "~/server/api/trpc/trpc"; - return { posts }; +export const data = async (ctx: PageContext) => { + const trpc = await trpcServer(ctx); + + const projects = await trpc.project.getAll(); + + return { projects }; }; export type Data = Awaited>; diff --git a/pages/project/@slug/+Page.tsx b/pages/project/@slug/+Page.tsx index 8ef4d63..4b25176 100644 --- a/pages/project/@slug/+Page.tsx +++ b/pages/project/@slug/+Page.tsx @@ -6,22 +6,21 @@ import { import WebPreview from "./components/web-preview"; import Editor from "./components/editor"; import ProjectContext from "./context/project"; -import { cn } from "~/lib/utils"; -import { useParams, useSearchParams } from "~/renderer/hooks"; -import { BASE_URL } from "~/lib/consts"; +import { cn, getPreviewUrl } from "~/lib/utils"; +import { useData, useSearchParams } from "~/renderer/hooks"; import { withClientOnly } from "~/renderer/client-only"; import Spinner from "~/components/ui/spinner"; +import { Data } from "./+data"; const ViewProjectPage = () => { + const { project } = useData(); const searchParams = useSearchParams(); - const params = useParams(); const isCompact = searchParams.get("compact") === "1" || searchParams.get("embed") === "1"; - const slug = params["slug"]; - const previewUrl = BASE_URL + `/api/preview/${slug}/index.html`; + const previewUrl = getPreviewUrl(project, "index.html"); return ( - + { const trpc = await trpcServer(ctx); - const pinnedFiles = await trpc.file.getAll({ isPinned: true }); - const files = await trpc.file.getAll(); - return { files, pinnedFiles }; + const project = await trpc.project.getById(ctx.routeParams?.slug!); + if (!project) { + throw render(404, "Project not found!"); + } + + const files = await trpc.file.getAll({ projectId: project.id }); + const pinnedFiles = files.filter((i) => i.isPinned); + + return { + title: project.title, + description: `Check ${project.title} on CodeShare!`, + project, + files, + pinnedFiles, + }; }; export type Data = Awaited>; diff --git a/pages/project/@slug/+route.ts b/pages/project/@slug/+route.ts new file mode 100644 index 0000000..67fc061 --- /dev/null +++ b/pages/project/@slug/+route.ts @@ -0,0 +1 @@ +export default "/@slug"; diff --git a/pages/project/@slug/components/editor.tsx b/pages/project/@slug/components/editor.tsx index d04212f..b5c2b63 100644 --- a/pages/project/@slug/components/editor.tsx +++ b/pages/project/@slug/components/editor.tsx @@ -23,9 +23,9 @@ import { Data } from "../+data"; import { useBreakpoint } from "~/hooks/useBreakpoint"; const Editor = () => { - const { pinnedFiles } = useData(); + const { project, pinnedFiles } = useData(); const trpcUtils = trpc.useUtils(); - const project = useProjectContext(); + const projectCtx = useProjectContext(); const sidebarPanel = useRef(null); const [breakpoint] = useBreakpoint(); @@ -36,7 +36,7 @@ const Editor = () => { ); const openedFilesData = trpc.file.getAll.useQuery( - { id: curOpenFiles }, + { projectId: project.id, id: curOpenFiles }, { enabled: curOpenFiles.length > 0, initialData: pinnedFiles } ); const [openedFiles, setOpenedFiles] = useState(pinnedFiles); @@ -156,7 +156,7 @@ const Editor = () => { }) satisfies Tab[]; }, [curOpenFiles, openedFiles, refreshPreview]); - const PanelComponent = !project.isCompact ? Panel : "div"; + const PanelComponent = !projectCtx.isCompact ? Panel : "div"; return ( { - const pageData = useData(); + const { project, files: initialFiles } = useData(); const { onOpenFile, onFileChanged } = useEditorContext(); const createFileDlg = useDisclose(); - const files = trpc.file.getAll.useQuery(undefined, { - initialData: pageData.files, - }); + const files = trpc.file.getAll.useQuery( + { projectId: project.id }, + { initialData: initialFiles } + ); const fileList = useMemo(() => groupFiles(files.data, null), [files.data]); return (
-

My Project

+

{project.title}

createFileDlg.onOpen()} @@ -104,7 +103,7 @@ type FileItemProps = { }; const FileItem = ({ file, createFileDlg }: FileItemProps) => { - const { slug } = useParams(); + const { project } = useData(); const { onOpenFile, onDeleteFile } = useEditorContext(); const [isCollapsed, setCollapsed] = useState(false); const trpcUtils = trpc.useUtils(); @@ -186,16 +185,13 @@ const FileItem = ({ file, createFileDlg }: FileItemProps) => { Copy Path copy(getUrl(`api/preview/${slug}`, file.path))} + onClick={() => copy(getPreviewUrl(project, file))} > Copy URL - window.open( - getUrl(`api/preview/${slug}`, file.path), - "_blank" - ) + window.open(getPreviewUrl(project, file), "_blank") } > Open in new tab diff --git a/pages/project/@slug/components/file-viewer.tsx b/pages/project/@slug/components/file-viewer.tsx index b18c755..e80be35 100644 --- a/pages/project/@slug/components/file-viewer.tsx +++ b/pages/project/@slug/components/file-viewer.tsx @@ -1,5 +1,3 @@ -"use client"; - import { getFileExt } from "~/lib/utils"; import CodeEditor from "../../../../components/ui/code-editor"; import trpc from "~/lib/trpc"; diff --git a/pages/project/@slug/components/sidebar.tsx b/pages/project/@slug/components/sidebar.tsx index 9e31aae..a0d7049 100644 --- a/pages/project/@slug/components/sidebar.tsx +++ b/pages/project/@slug/components/sidebar.tsx @@ -1,4 +1,3 @@ -import React from "react"; import FileListing from "./file-listing"; import { FaUserCircle } from "react-icons/fa"; import { Button } from "~/components/ui/button"; @@ -7,6 +6,7 @@ const Sidebar = () => { return (