mirror of
https://github.com/khairul169/code-share.git
synced 2025-04-28 16:49:36 +07:00
fix: typescript support fix, add some params to editor, etc
This commit is contained in:
parent
7bdd995394
commit
543260479a
@ -130,13 +130,18 @@ function getLangMetadata(lang: string) {
|
||||
case "js":
|
||||
case "ts":
|
||||
case "tsx":
|
||||
const isTypescript = ["tsx", "ts"].includes(lang);
|
||||
extensions = [
|
||||
javascript({
|
||||
jsx: ["jsx", "tsx"].includes(lang),
|
||||
typescript: ["tsx", "ts"].includes(lang),
|
||||
typescript: isTypescript,
|
||||
}),
|
||||
];
|
||||
formatter = ["babel", prettierBabelPlugin, prettierPluginEstree];
|
||||
formatter = [
|
||||
isTypescript ? "babel-ts" : "babel",
|
||||
prettierBabelPlugin,
|
||||
prettierPluginEstree,
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
"@types/cookie-parser": "^1.4.6",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jsonwebtoken": "^9.0.5",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/react": "^18.2.57",
|
||||
@ -74,6 +75,7 @@
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.331.0",
|
||||
"mime": "^4.0.1",
|
||||
"morgan": "^1.10.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"nprogress": "^0.2.0",
|
||||
"postcss": "^8",
|
||||
|
@ -15,20 +15,23 @@ import { Data } from "./+data";
|
||||
const ViewProjectPage = () => {
|
||||
const { project } = useData<Data>();
|
||||
const searchParams = useSearchParams();
|
||||
const isCompact = !!(
|
||||
searchParams.get("compact") || searchParams.get("embed")
|
||||
);
|
||||
const isCompact = Boolean(searchParams.get("compact"));
|
||||
const isEmbed = Boolean(searchParams.get("embed"));
|
||||
const hidePreview = searchParams.get("preview") === "0";
|
||||
const previewUrl = getPreviewUrl(project, "index.html");
|
||||
|
||||
return (
|
||||
<ProjectContext.Provider value={{ project, isCompact }}>
|
||||
<ProjectContext.Provider value={{ project, isCompact, isEmbed }}>
|
||||
<ResizablePanelGroup
|
||||
autoSaveId="main-panel"
|
||||
direction={{ sm: "vertical", md: "horizontal" }}
|
||||
className={cn("w-full !h-dvh bg-slate-600", !isCompact ? "md:p-4" : "")}
|
||||
className={cn(
|
||||
"w-full !h-dvh bg-slate-600",
|
||||
!isCompact && !isEmbed ? "md:p-4" : ""
|
||||
)}
|
||||
>
|
||||
<ResizablePanel
|
||||
defaultSize={60}
|
||||
defaultSize={hidePreview ? 100 : 60}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
minSize={30}
|
||||
@ -38,13 +41,14 @@ const ViewProjectPage = () => {
|
||||
<ResizableHandle
|
||||
withHandle
|
||||
className={
|
||||
!isCompact
|
||||
!isCompact && !isEmbed
|
||||
? "bg-slate-800 md:bg-transparent hover:bg-slate-500 transition-colors md:mx-1 w-2 md:data-[panel-group-direction=vertical]:h-2 md:rounded-lg"
|
||||
: "bg-slate-800"
|
||||
}
|
||||
/>
|
||||
<WebPreview
|
||||
defaultSize={40}
|
||||
defaultCollapsed={hidePreview}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
minSize={10}
|
||||
|
@ -86,6 +86,7 @@ const APIManager = () => {
|
||||
|
||||
const Actions = ({ stats }: any) => {
|
||||
const { project } = useProjectContext();
|
||||
|
||||
const restart = useMutation({
|
||||
mutationFn: () => {
|
||||
return api(`/sandbox/${project.slug}/restart`, { method: "POST" });
|
||||
|
@ -73,10 +73,10 @@ const Editor = () => {
|
||||
}
|
||||
}, [openedFilesData.data]);
|
||||
|
||||
useEffect(() => {
|
||||
// start API sandbox
|
||||
api(`/sandbox/${project.slug}/start`, { method: "POST" }).catch(() => {});
|
||||
}, [project]);
|
||||
// useEffect(() => {
|
||||
// // start API sandbox
|
||||
// api(`/sandbox/${project.slug}/start`, { method: "POST" }).catch(() => {});
|
||||
// }, [project]);
|
||||
|
||||
const onOpenFile = useCallback(
|
||||
(fileId: number, autoSwitchTab = true) => {
|
||||
@ -154,17 +154,18 @@ const Editor = () => {
|
||||
});
|
||||
}
|
||||
|
||||
tabs.push({
|
||||
title: "API",
|
||||
icon: <FiServer />,
|
||||
render: () => <APIManager />,
|
||||
locked: true,
|
||||
});
|
||||
// tabs.push({
|
||||
// title: "API",
|
||||
// icon: <FiServer />,
|
||||
// render: () => <APIManager />,
|
||||
// locked: true,
|
||||
// });
|
||||
|
||||
return tabs;
|
||||
}, [curOpenFiles, openedFiles, breakpoint]);
|
||||
|
||||
const PanelComponent = !projectCtx.isCompact ? Panel : "div";
|
||||
const PanelComponent =
|
||||
!projectCtx.isCompact || !projectCtx.isEmbed ? Panel : "div";
|
||||
|
||||
return (
|
||||
<EditorContext.Provider
|
||||
@ -181,8 +182,8 @@ const Editor = () => {
|
||||
className="flex-1 order-2 md:order-1"
|
||||
>
|
||||
<Sidebar
|
||||
defaultSize={{ sm: 50, md: 25 }}
|
||||
defaultCollapsed={{ sm: true, md: false }}
|
||||
defaultSize={{ md: 50, lg: 25 }}
|
||||
defaultCollapsed={{ md: true, lg: false }}
|
||||
minSize={10}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
@ -190,7 +191,7 @@ const Editor = () => {
|
||||
|
||||
<ResizableHandle className="w-0" />
|
||||
|
||||
<ResizablePanel defaultSize={{ sm: 100, md: 75 }}>
|
||||
<ResizablePanel defaultSize={{ md: 100, lg: 75 }}>
|
||||
<ResizablePanelGroup autoSaveId="code-editor" direction="vertical">
|
||||
<ResizablePanel defaultSize={{ sm: 100, md: 80 }} minSize={20}>
|
||||
<Tabs
|
||||
|
@ -56,7 +56,7 @@ const WebPreview = ({ url, ...props }: WebPreviewProps) => {
|
||||
refresh();
|
||||
}, [refresh, togglePanel]);
|
||||
|
||||
const PanelComponent = !project.isCompact ? Panel : "div";
|
||||
const PanelComponent = !project.isCompact || !project.isEmbed ? Panel : "div";
|
||||
|
||||
return (
|
||||
<ResizablePanel
|
||||
@ -89,7 +89,7 @@ const WebPreview = ({ url, ...props }: WebPreviewProps) => {
|
||||
id="web-preview"
|
||||
ref={frameRef}
|
||||
className="border-none w-full flex-1 overflow-hidden bg-white"
|
||||
sandbox="allow-scripts"
|
||||
sandbox="allow-scripts allow-forms"
|
||||
/>
|
||||
) : null}
|
||||
</PanelComponent>
|
||||
|
@ -4,6 +4,7 @@ import type { ProjectSchema } from "~/server/db/schema/project";
|
||||
type TProjectContext = {
|
||||
project: ProjectSchema;
|
||||
isCompact?: boolean;
|
||||
isEmbed?: boolean;
|
||||
};
|
||||
|
||||
const ProjectContext = createContext<TProjectContext | null>(null);
|
||||
|
48
pnpm-lock.yaml
generated
48
pnpm-lock.yaml
generated
@ -110,6 +110,9 @@ dependencies:
|
||||
mime:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
morgan:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
node-fetch:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
@ -178,6 +181,9 @@ devDependencies:
|
||||
'@types/jsonwebtoken':
|
||||
specifier: ^9.0.5
|
||||
version: 9.0.5
|
||||
'@types/morgan':
|
||||
specifier: ^1.9.9
|
||||
version: 1.9.9
|
||||
'@types/node':
|
||||
specifier: ^20.11.19
|
||||
version: 20.11.19
|
||||
@ -2338,6 +2344,12 @@ packages:
|
||||
resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
|
||||
dev: true
|
||||
|
||||
/@types/morgan@1.9.9:
|
||||
resolution: {integrity: sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==}
|
||||
dependencies:
|
||||
'@types/node': 20.11.19
|
||||
dev: true
|
||||
|
||||
/@types/node@20.11.19:
|
||||
resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==}
|
||||
dependencies:
|
||||
@ -2703,6 +2715,13 @@ packages:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
dev: false
|
||||
|
||||
/basic-auth@2.0.1:
|
||||
resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
safe-buffer: 5.1.2
|
||||
dev: false
|
||||
|
||||
/basic-ftp@5.0.4:
|
||||
resolution: {integrity: sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@ -4846,6 +4865,19 @@ packages:
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/morgan@1.10.0:
|
||||
resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
basic-auth: 2.0.1
|
||||
debug: 2.6.9
|
||||
depd: 2.0.0
|
||||
on-finished: 2.3.0
|
||||
on-headers: 1.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/mrmime@2.0.0:
|
||||
resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
|
||||
engines: {node: '>=10'}
|
||||
@ -5022,6 +5054,13 @@ packages:
|
||||
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
|
||||
dev: false
|
||||
|
||||
/on-finished@2.3.0:
|
||||
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
ee-first: 1.1.1
|
||||
dev: false
|
||||
|
||||
/on-finished@2.4.1:
|
||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@ -5029,6 +5068,11 @@ packages:
|
||||
ee-first: 1.1.1
|
||||
dev: false
|
||||
|
||||
/on-headers@1.0.2:
|
||||
resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
dependencies:
|
||||
@ -5883,6 +5927,10 @@ packages:
|
||||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
|
||||
/safe-buffer@5.1.2:
|
||||
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||
dev: false
|
||||
|
||||
/safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
|
||||
|
@ -3,11 +3,12 @@ import preview from "./preview";
|
||||
import trpc from "./trpc/handler";
|
||||
import { thumbnail } from "./thumbnail";
|
||||
import sandbox from "./sandbox";
|
||||
import { nocache } from "../middlewares/nocache";
|
||||
|
||||
const api = Router();
|
||||
|
||||
api.use("/trpc", trpc);
|
||||
api.use("/preview", preview);
|
||||
api.use("/preview", nocache, preview);
|
||||
api.use("/sandbox", sandbox);
|
||||
|
||||
api.get("/thumbnail/:slug", thumbnail);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { getFileExt } from "~/lib/utils";
|
||||
import { FileSchema } from "~/server/db/schema/file";
|
||||
import { ProjectSettingsSchema } from "~/server/db/schema/project";
|
||||
import { transformJs } from "~/server/lib/transform-js";
|
||||
@ -10,7 +11,9 @@ export const serveJs = async (
|
||||
|
||||
// transpile to es5
|
||||
if (cfg?.transpiler === "swc") {
|
||||
content = await transformJs(content);
|
||||
const ext = getFileExt(file.filename);
|
||||
const typescript = ["ts", "tsx"].includes(ext);
|
||||
content = await transformJs(content, typescript ? "ts" : "js");
|
||||
}
|
||||
|
||||
return content;
|
||||
|
@ -5,7 +5,6 @@ import { IS_DEV } from "./lib/consts";
|
||||
import cookieParser from "cookie-parser";
|
||||
import api from "./api";
|
||||
import { authMiddleware } from "./middlewares/auth";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
async function createServer() {
|
||||
const app = express();
|
||||
@ -24,8 +23,12 @@ async function createServer() {
|
||||
} else {
|
||||
// serve client assets
|
||||
app.use(express.static(root + "/dist/client"));
|
||||
|
||||
const { default: morgan } = await import("morgan");
|
||||
app.use(morgan("combined"));
|
||||
}
|
||||
|
||||
app.set("etag", false);
|
||||
app.use(cookieParser());
|
||||
app.use(authMiddleware);
|
||||
|
||||
@ -42,9 +45,11 @@ async function createServer() {
|
||||
}
|
||||
|
||||
const { body, statusCode, headers, earlyHints } = httpResponse;
|
||||
if (res.writeEarlyHints) {
|
||||
res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) });
|
||||
}
|
||||
|
||||
// FIXME: SSL cloudflare gak bisa digunakan kalo ada ini..
|
||||
// if (res.writeEarlyHints) {
|
||||
// res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) });
|
||||
// }
|
||||
|
||||
headers.forEach(([name, value]) => res.setHeader(name, value));
|
||||
res.status(statusCode).send(body);
|
||||
|
@ -3,7 +3,7 @@ import standardTypes from "mime/types/standard.js";
|
||||
import otherTypes from "mime/types/other.js";
|
||||
|
||||
const mime = new Mime(standardTypes, otherTypes);
|
||||
mime.define({ "text/javascript": ["jsx", "tsx"] }, true);
|
||||
mime.define({ "text/javascript": ["jsx", "tsx", "ts"] }, true);
|
||||
|
||||
export const getMimeType = (
|
||||
ext: string,
|
||||
|
@ -1,12 +1,13 @@
|
||||
import * as swc from "@swc/core";
|
||||
|
||||
export const transformJs = async (code: string) => {
|
||||
export const transformJs = async (code: string, type: "js" | "ts" = "js") => {
|
||||
try {
|
||||
const result = await swc.transform(code, {
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: type === "js" ? "ecmascript" : "typescript",
|
||||
jsx: true,
|
||||
syntax: "ecmascript",
|
||||
tsx: true,
|
||||
},
|
||||
target: "es5",
|
||||
},
|
||||
@ -14,6 +15,7 @@ export const transformJs = async (code: string) => {
|
||||
|
||||
return result.code;
|
||||
} catch (err) {
|
||||
// console.log(err);
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
@ -17,6 +17,7 @@ export const unpackProject = async (
|
||||
) => {
|
||||
const files = await db.query.file.findMany({
|
||||
where: and(
|
||||
eq(file.projectId, projectData.id),
|
||||
eq(file.isDirectory, false),
|
||||
eq(file.isFile, false),
|
||||
isNull(file.deletedAt)
|
||||
|
12
server/middlewares/nocache.ts
Normal file
12
server/middlewares/nocache.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
export const nocache = (_req: Request, res: Response, next: NextFunction) => {
|
||||
res.setHeader("Surrogate-Control", "no-store");
|
||||
res.setHeader(
|
||||
"Cache-Control",
|
||||
"no-store, no-cache, must-revalidate, proxy-revalidate"
|
||||
);
|
||||
res.setHeader("Expires", "0");
|
||||
|
||||
next();
|
||||
};
|
@ -116,6 +116,17 @@ const projectRouter = router({
|
||||
const projectId = projectData.id;
|
||||
|
||||
if (input.forkFromId) {
|
||||
const forkProject = await tx.query.project.findFirst({
|
||||
where: and(
|
||||
eq(project.id, input.forkFromId),
|
||||
isNull(project.deletedAt)
|
||||
),
|
||||
});
|
||||
|
||||
if (!forkProject) {
|
||||
throw new Error("Fork Project not found!");
|
||||
}
|
||||
|
||||
const forkFiles = await tx.query.file.findMany({
|
||||
where: and(
|
||||
eq(file.projectId, input.forkFromId),
|
||||
@ -132,6 +143,11 @@ const projectRouter = router({
|
||||
await tx
|
||||
.insert(file)
|
||||
.values(forkFiles.map((file) => ({ ...file, projectId })));
|
||||
|
||||
await tx
|
||||
.update(project)
|
||||
.set({ settings: forkProject.settings })
|
||||
.where(eq(project.id, projectData.id));
|
||||
} else {
|
||||
await tx.insert(file).values([
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user