feat: add project schema

This commit is contained in:
2024-02-22 20:59:20 +00:00
parent b232410d83
commit d579c1b7c5
27 changed files with 338 additions and 147 deletions
-17
View File
@@ -1,17 +0,0 @@
import { useData } from "~/renderer/hooks";
import { Data } from "./+data";
import Link from "~/renderer/link";
const ViewPostPage = () => {
const { post } = useData<Data>();
return (
<div>
<Link href="/">Go Back</Link>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
);
};
export default ViewPostPage;
-12
View File
@@ -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<ReturnType<typeof data>>;
+4 -8
View File
@@ -3,19 +3,15 @@ import { useData } from "~/renderer/hooks";
import Link from "~/renderer/link";
const HomePage = () => {
const { posts } = useData<Data>();
if (!posts?.length) {
return <p>No posts.</p>;
}
const { projects } = useData<Data>();
return (
<div>
<h1>Posts</h1>
{posts.map((post: any) => (
<Link key={post.id} href={`/${post.id}`}>
{post.title}
{projects.map((project: any) => (
<Link key={project.id} href={`/${project.slug}`}>
{project.title}
</Link>
))}
</div>
+8 -5
View File
@@ -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<ReturnType<typeof data>>;
+6 -7
View File
@@ -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<Data>();
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 (
<ProjectContext.Provider value={{ slug, isCompact }}>
<ProjectContext.Provider value={{ project, isCompact }}>
<ResizablePanelGroup
autoSaveId="main-panel"
direction={{ sm: "vertical", md: "horizontal" }}
+16 -3
View File
@@ -1,12 +1,25 @@
import { PageContext } from "vike/types";
import { render } from "vike/abort";
import trpcServer from "~/server/api/trpc/trpc";
export const data = async (ctx: PageContext) => {
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<ReturnType<typeof data>>;
+1
View File
@@ -0,0 +1 @@
export default "/@slug";
+4 -4
View File
@@ -23,9 +23,9 @@ import { Data } from "../+data";
import { useBreakpoint } from "~/hooks/useBreakpoint";
const Editor = () => {
const { pinnedFiles } = useData<Data>();
const { project, pinnedFiles } = useData<Data>();
const trpcUtils = trpc.useUtils();
const project = useProjectContext();
const projectCtx = useProjectContext();
const sidebarPanel = useRef<ImperativePanelHandle>(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<any[]>(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 (
<EditorContext.Provider
+12 -16
View File
@@ -1,6 +1,4 @@
"use client";
import React, { Fragment, useMemo, useState } from "react";
import { Fragment, useMemo, useState } from "react";
import { UseDiscloseReturn, useDisclose } from "~/hooks/useDisclose";
import {
FiChevronRight,
@@ -21,27 +19,28 @@ import {
DropdownMenuTrigger,
DropdownMenuSeparator,
} from "~/components/ui/dropdown-menu";
import { cn, getUrl } from "~/lib/utils";
import { cn, getPreviewUrl } from "~/lib/utils";
import FileIcon from "~/components/ui/file-icon";
import copy from "copy-to-clipboard";
import { useData, useParams } from "~/renderer/hooks";
import { useData } from "~/renderer/hooks";
import Spinner from "~/components/ui/spinner";
import { Data } from "../+data";
const FileListing = () => {
const pageData = useData<Data>();
const { project, files: initialFiles } = useData<Data>();
const { onOpenFile, onFileChanged } = useEditorContext();
const createFileDlg = useDisclose<CreateFileSchema>();
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 (
<Fragment>
<div className="h-10 flex items-center pl-4 pr-1">
<p className="text-xs uppercase truncate flex-1">My Project</p>
<p className="text-xs uppercase truncate flex-1">{project.title}</p>
<ActionButton
icon={FiFilePlus}
onClick={() => createFileDlg.onOpen()}
@@ -104,7 +103,7 @@ type FileItemProps = {
};
const FileItem = ({ file, createFileDlg }: FileItemProps) => {
const { slug } = useParams();
const { project } = useData<Data>();
const { onOpenFile, onDeleteFile } = useEditorContext();
const [isCollapsed, setCollapsed] = useState(false);
const trpcUtils = trpc.useUtils();
@@ -186,16 +185,13 @@ const FileItem = ({ file, createFileDlg }: FileItemProps) => {
Copy Path
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => copy(getUrl(`api/preview/${slug}`, file.path))}
onClick={() => copy(getPreviewUrl(project, file))}
>
Copy URL
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
window.open(
getUrl(`api/preview/${slug}`, file.path),
"_blank"
)
window.open(getPreviewUrl(project, file), "_blank")
}
>
Open in new tab
@@ -1,5 +1,3 @@
"use client";
import { getFileExt } from "~/lib/utils";
import CodeEditor from "../../../../components/ui/code-editor";
import trpc from "~/lib/trpc";
+1 -1
View File
@@ -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 (
<aside className="flex flex-col items-stretch h-full">
<FileListing />
<div className="h-12 bg-[#1a1b26] pl-12">
<Button
variant="ghost"
+2 -1
View File
@@ -1,7 +1,8 @@
import { createContext, useContext } from "react";
import type { ProjectSchema } from "~/server/db/schema/project";
type TProjectContext = {
slug: string;
project: ProjectSchema;
isCompact?: boolean;
};