From 9777ae167694ab367805b1374df487c26f2f6577 Mon Sep 17 00:00:00 2001 From: Khairul Hidayat Date: Thu, 22 Feb 2024 12:14:58 +0000 Subject: [PATCH] feat: rebuild app using vike --- .eslintrc.json | 3 - .gitignore | 43 +- .swcrc | 23 + README.md | 36 - components.json | 8 +- components/containers/error-boundary.tsx | 45 + .../ui/action-button.tsx | 4 +- {src/components => components}/ui/button.tsx | 2 +- .../ui/code-editor.tsx | 4 +- {src/components => components}/ui/dialog.tsx | 2 +- .../ui/dropdown-menu.tsx | 2 +- .../ui/file-icon.tsx | 2 +- .../ui/form-error-message.tsx | 2 +- {src/components => components}/ui/input.tsx | 12 +- {src/components => components}/ui/panel.tsx | 2 +- .../ui/resizable.tsx | 2 +- components/ui/spinner.tsx | 12 + {src/components => components}/ui/tabs.tsx | 2 +- drizzle.config.ts | 7 +- {src/hooks => hooks}/useCommandKey.ts | 0 {src/hooks => hooks}/useDebounce.ts | 0 {src/hooks => hooks}/useDisclose.ts | 0 {src/hooks => hooks}/useForm.ts | 0 {src/hooks => hooks}/usePortrait.ts | 0 lib/consts.ts | 2 + {src/lib => lib}/trpc.ts | 2 +- {src/lib => lib}/utils.ts | 0 next.config.mjs | 4 - package.json | 71 +- pages/@id/+Page.tsx | 17 + pages/@id/+data.ts | 12 + pages/_error/+Page.tsx | 20 + pages/index/+Page.tsx | 24 + pages/index/+data.ts | 9 + .../page.tsx => pages/project/@slug/+Page.tsx | 37 +- .../@slug/components/console-logger.tsx | 42 + .../@slug/components}/createfile-dialog.tsx | 9 +- .../project/@slug/components}/editor.tsx | 28 +- .../@slug/components}/file-listing.tsx | 18 +- .../project/@slug/components}/file-viewer.tsx | 4 +- .../project/@slug/components}/sidebar.tsx | 2 +- .../project/@slug/components/web-preview.tsx | 67 + .../project/@slug}/context/editor.tsx | 2 +- .../project/@slug}/context/project.tsx | 1 + pages/project/@slug/stores/web-preview.ts | 9 + pnpm-lock.yaml | 3509 +++++++---------- postcss.config.js => postcss.config.cjs | 0 public/favicon.ico | Bin 0 -> 4286 bytes public/js/debug-console.js | 18 - public/js/hook-console.js | 1 + public/next.svg | 1 - public/vercel.svg | 1 - renderer/+config.ts | 15 + renderer/+onPageTransitionEnd.ts | 5 + renderer/+onPageTransitionStart.ts | 5 + renderer/+onRenderClient.tsx | 38 + renderer/+onRenderHtml.tsx | 44 + renderer/client-only.tsx | 34 + renderer/context.tsx | 26 + {src/app => renderer}/globals.css | 2 +- renderer/hooks.ts | 16 + renderer/layout.tsx | 23 + renderer/link.tsx | 19 + {src/app => renderer}/providers.tsx | 7 +- renderer/types.ts | 19 + renderer/utils.ts | 11 + server/api/index.ts | 10 + server/api/preview/index.ts | 51 + .../api/preview}/serve-html.ts | 8 +- server/api/preview/serve-js.ts | 11 + server/api/trpc/context.ts | 10 + server/api/trpc/handler.ts | 10 + .../trpc.ts => server/api/trpc/index.ts | 0 server/api/trpc/trpc.ts | 7 + {src/server => server}/db/index.ts | 0 {src/server => server}/db/migrate.ts | 0 {src/server => server}/db/schema/_schema.ts | 0 {src/server => server}/db/schema/file.ts | 0 {src/server => server}/db/schema/user.ts | 0 {src/server => server}/db/seed.ts | 7 +- server/index.ts | 54 + server/lib/consts.ts | 2 + {src/server => server}/lib/crypto.ts | 0 server/lib/transform-js.ts | 19 + {src/server => server}/routers/_app.ts | 2 +- {src/server => server}/routers/file.ts | 2 +- src/app/api/trpc/[trpc]/route.ts | 13 - src/app/favicon.ico | Bin 25931 -> 0 bytes src/app/layout.tsx | 28 - .../[slug]/_components/console-logger.tsx | 63 - .../[slug]/_components/web-preview.tsx | 48 - .../project/[slug]/file/[...path]/route.ts | 50 - .../project/[slug]/file/[...path]/serve-js.ts | 41 - src/lib/consts.ts | 2 - src/server/context.ts | 10 - src/server/db/drizzle/0000_loud_hex.sql | 26 - src/server/db/drizzle/meta/0000_snapshot.json | 191 - src/server/db/drizzle/meta/_journal.json | 13 - src/server/index.ts | 5 - src/server/transformer/server.ts | 46 - tailwind.config.ts | 13 +- tsconfig-server.json | 18 - tsconfig.json | 29 +- vite.config.js | 14 + 104 files changed, 2214 insertions(+), 2976 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .swcrc delete mode 100644 README.md create mode 100644 components/containers/error-boundary.tsx rename {src/components => components}/ui/action-button.tsx (90%) rename {src/components => components}/ui/button.tsx (98%) rename {src/components => components}/ui/code-editor.tsx (97%) rename {src/components => components}/ui/dialog.tsx (99%) rename {src/components => components}/ui/dropdown-menu.tsx (99%) rename {src/components => components}/ui/file-icon.tsx (89%) rename {src/components => components}/ui/form-error-message.tsx (93%) rename {src/components => components}/ui/input.tsx (87%) rename {src/components => components}/ui/panel.tsx (95%) rename {src/components => components}/ui/resizable.tsx (97%) create mode 100644 components/ui/spinner.tsx rename {src/components => components}/ui/tabs.tsx (99%) rename {src/hooks => hooks}/useCommandKey.ts (100%) rename {src/hooks => hooks}/useDebounce.ts (100%) rename {src/hooks => hooks}/useDisclose.ts (100%) rename {src/hooks => hooks}/useForm.ts (100%) rename {src/hooks => hooks}/usePortrait.ts (100%) create mode 100644 lib/consts.ts rename {src/lib => lib}/trpc.ts (82%) rename {src/lib => lib}/utils.ts (100%) delete mode 100644 next.config.mjs create mode 100644 pages/@id/+Page.tsx create mode 100644 pages/@id/+data.ts create mode 100644 pages/_error/+Page.tsx create mode 100644 pages/index/+Page.tsx create mode 100644 pages/index/+data.ts rename src/app/project/[slug]/page.tsx => pages/project/@slug/+Page.tsx (62%) create mode 100644 pages/project/@slug/components/console-logger.tsx rename {src/app/project/[slug]/_components => pages/project/@slug/components}/createfile-dialog.tsx (91%) rename {src/app/project/[slug]/_components => pages/project/@slug/components}/editor.tsx (90%) rename {src/app/project/[slug]/_components => pages/project/@slug/components}/file-listing.tsx (93%) rename {src/app/project/[slug]/_components => pages/project/@slug/components}/file-viewer.tsx (92%) rename {src/app/project/[slug]/_components => pages/project/@slug/components}/sidebar.tsx (92%) create mode 100644 pages/project/@slug/components/web-preview.tsx rename {src/app/project/[slug] => pages/project/@slug}/context/editor.tsx (89%) rename {src/app/project/[slug] => pages/project/@slug}/context/project.tsx (95%) create mode 100644 pages/project/@slug/stores/web-preview.ts rename postcss.config.js => postcss.config.cjs (100%) create mode 100644 public/favicon.ico delete mode 100644 public/js/debug-console.js create mode 100644 public/js/hook-console.js delete mode 100644 public/next.svg delete mode 100644 public/vercel.svg create mode 100644 renderer/+config.ts create mode 100644 renderer/+onPageTransitionEnd.ts create mode 100644 renderer/+onPageTransitionStart.ts create mode 100644 renderer/+onRenderClient.tsx create mode 100644 renderer/+onRenderHtml.tsx create mode 100644 renderer/client-only.tsx create mode 100644 renderer/context.tsx rename {src/app => renderer}/globals.css (92%) create mode 100644 renderer/hooks.ts create mode 100644 renderer/layout.tsx create mode 100644 renderer/link.tsx rename {src/app => renderer}/providers.tsx (81%) create mode 100644 renderer/types.ts create mode 100644 renderer/utils.ts create mode 100644 server/api/index.ts create mode 100644 server/api/preview/index.ts rename {src/app/project/[slug]/file/[...path] => server/api/preview}/serve-html.ts (84%) create mode 100644 server/api/preview/serve-js.ts create mode 100644 server/api/trpc/context.ts create mode 100644 server/api/trpc/handler.ts rename src/server/trpc.ts => server/api/trpc/index.ts (100%) create mode 100644 server/api/trpc/trpc.ts rename {src/server => server}/db/index.ts (100%) rename {src/server => server}/db/migrate.ts (100%) rename {src/server => server}/db/schema/_schema.ts (100%) rename {src/server => server}/db/schema/file.ts (100%) rename {src/server => server}/db/schema/user.ts (100%) rename {src/server => server}/db/seed.ts (85%) create mode 100644 server/index.ts create mode 100644 server/lib/consts.ts rename {src/server => server}/lib/crypto.ts (100%) create mode 100644 server/lib/transform-js.ts rename {src/server => server}/routers/_app.ts (79%) rename {src/server => server}/routers/file.ts (98%) delete mode 100644 src/app/api/trpc/[trpc]/route.ts delete mode 100644 src/app/favicon.ico delete mode 100644 src/app/layout.tsx delete mode 100644 src/app/project/[slug]/_components/console-logger.tsx delete mode 100644 src/app/project/[slug]/_components/web-preview.tsx delete mode 100644 src/app/project/[slug]/file/[...path]/route.ts delete mode 100644 src/app/project/[slug]/file/[...path]/serve-js.ts delete mode 100644 src/lib/consts.ts delete mode 100644 src/server/context.ts delete mode 100644 src/server/db/drizzle/0000_loud_hex.sql delete mode 100644 src/server/db/drizzle/meta/0000_snapshot.json delete mode 100644 src/server/db/drizzle/meta/_journal.json delete mode 100644 src/server/index.ts delete mode 100644 src/server/transformer/server.ts delete mode 100644 tsconfig-server.json create mode 100644 vite.config.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index bffb357..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/.gitignore b/.gitignore index 415298f..4758373 100644 --- a/.gitignore +++ b/.gitignore @@ -1,42 +1,5 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts - +node_modules/ +dist/ +build/ storage/**/* !.gitkeep - -.env -dist/ diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000..33ec03d --- /dev/null +++ b/.swcrc @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "ecmascript", + "jsx": false, + "dynamicImport": false, + "privateMethod": false, + "functionBind": false, + "exportDefaultFrom": false, + "exportNamespaceFrom": false, + "decorators": false, + "decoratorsBeforeExport": false, + "topLevelAwait": false, + "importMeta": false + }, + "target": "es2020", + "loose": false, + "externalHelpers": false, + "keepClassNames": false + }, + "minify": false +} diff --git a/README.md b/README.md deleted file mode 100644 index c403366..0000000 --- a/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/components.json b/components.json index 097c990..e1f62f6 100644 --- a/components.json +++ b/components.json @@ -5,13 +5,13 @@ "tsx": true, "tailwind": { "config": "tailwind.config.ts", - "css": "src/app/globals.css", + "css": "renderer/globals.css", "baseColor": "slate", "cssVariables": false, "prefix": "" }, "aliases": { - "components": "@/components", - "utils": "@/lib/utils" + "components": "~/components", + "utils": "~/lib/utils" } -} \ No newline at end of file +} diff --git a/components/containers/error-boundary.tsx b/components/containers/error-boundary.tsx new file mode 100644 index 0000000..ebb6e94 --- /dev/null +++ b/components/containers/error-boundary.tsx @@ -0,0 +1,45 @@ +import React from "react"; + +type ErrorBoundaryProps = { + fallback?: React.ReactNode; + children?: React.ReactNode; +}; + +type ErrorBoundaryState = { + error?: Error | null; +}; + +class ErrorBoundary extends React.Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { error: null }; + } + + static getDerivedStateFromError(error: unknown) { + return { error }; + } + + render() { + const { children, fallback } = this.props; + const { error } = this.state; + + if (error) { + if (!fallback) { + return ( +
+

An error occured!

+
+ ); + } + + return fallback; + } + + return children; + } +} + +export default ErrorBoundary; diff --git a/src/components/ui/action-button.tsx b/components/ui/action-button.tsx similarity index 90% rename from src/components/ui/action-button.tsx rename to components/ui/action-button.tsx index 4410287..9a73e21 100644 --- a/src/components/ui/action-button.tsx +++ b/components/ui/action-button.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/display-name */ -import { Button } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; +import { Button } from "~/components/ui/button"; +import { cn } from "~/lib/utils"; import React, { forwardRef } from "react"; import { IconType } from "react-icons/lib"; diff --git a/src/components/ui/button.tsx b/components/ui/button.tsx similarity index 98% rename from src/components/ui/button.tsx rename to components/ui/button.tsx index 70148ad..b2b567e 100644 --- a/src/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "~/lib/utils"; const buttonVariants = cva( "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300", diff --git a/src/components/ui/code-editor.tsx b/components/ui/code-editor.tsx similarity index 97% rename from src/components/ui/code-editor.tsx rename to components/ui/code-editor.tsx index 9dc181c..a821cbe 100644 --- a/src/components/ui/code-editor.tsx +++ b/components/ui/code-editor.tsx @@ -17,8 +17,8 @@ import prettierCssPlugin from "prettier/plugins/postcss"; import prettierBabelPlugin from "prettier/plugins/babel"; import * as prettierPluginEstree from "prettier/plugins/estree"; import { abbreviationTracker } from "@emmetio/codemirror6-plugin"; -import { useDebounce } from "@/hooks/useDebounce"; -import useCommandKey from "@/hooks/useCommandKey"; +import { useDebounce } from "~/hooks/useDebounce"; +import useCommandKey from "~/hooks/useCommandKey"; type Props = { lang?: string; diff --git a/src/components/ui/dialog.tsx b/components/ui/dialog.tsx similarity index 99% rename from src/components/ui/dialog.tsx rename to components/ui/dialog.tsx index e2fbd4f..6bc160b 100644 --- a/src/components/ui/dialog.tsx +++ b/components/ui/dialog.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { X } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "~/lib/utils"; const Dialog = DialogPrimitive.Root; diff --git a/src/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx similarity index 99% rename from src/components/ui/dropdown-menu.tsx rename to components/ui/dropdown-menu.tsx index 98a2093..8da56a9 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/components/ui/dropdown-menu.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import { Check, ChevronRight, Circle } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "~/lib/utils"; const DropdownMenu = DropdownMenuPrimitive.Root; diff --git a/src/components/ui/file-icon.tsx b/components/ui/file-icon.tsx similarity index 89% rename from src/components/ui/file-icon.tsx rename to components/ui/file-icon.tsx index c32d069..873f2df 100644 --- a/src/components/ui/file-icon.tsx +++ b/components/ui/file-icon.tsx @@ -1,4 +1,4 @@ -import { FileSchema } from "@/server/db/schema/file"; +import { FileSchema } from "~/server/db/schema/file"; import { ComponentProps } from "react"; import { FiFile, FiFolder } from "react-icons/fi"; diff --git a/src/components/ui/form-error-message.tsx b/components/ui/form-error-message.tsx similarity index 93% rename from src/components/ui/form-error-message.tsx rename to components/ui/form-error-message.tsx index f30d22c..8f6ab15 100644 --- a/src/components/ui/form-error-message.tsx +++ b/components/ui/form-error-message.tsx @@ -1,4 +1,4 @@ -import { useForm } from "@/hooks/useForm"; +import { useForm } from "~/hooks/useForm"; import { FieldValues } from "react-hook-form"; import React from "react"; diff --git a/src/components/ui/input.tsx b/components/ui/input.tsx similarity index 87% rename from src/components/ui/input.tsx rename to components/ui/input.tsx index 3792d8b..5e33a2a 100644 --- a/src/components/ui/input.tsx +++ b/components/ui/input.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "~/lib/utils"; export interface InputProps extends React.InputHTMLAttributes {} @@ -17,9 +17,9 @@ const Input = React.forwardRef( ref={ref} {...props} /> - ) + ); } -) -Input.displayName = "Input" +); +Input.displayName = "Input"; -export { Input } +export { Input }; diff --git a/src/components/ui/panel.tsx b/components/ui/panel.tsx similarity index 95% rename from src/components/ui/panel.tsx rename to components/ui/panel.tsx index b5143ad..7faf594 100644 --- a/src/components/ui/panel.tsx +++ b/components/ui/panel.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils"; +import { cn } from "~/lib/utils"; import React from "react"; type Props = { diff --git a/src/components/ui/resizable.tsx b/components/ui/resizable.tsx similarity index 97% rename from src/components/ui/resizable.tsx rename to components/ui/resizable.tsx index 28caa02..53fdab1 100644 --- a/src/components/ui/resizable.tsx +++ b/components/ui/resizable.tsx @@ -3,7 +3,7 @@ import { GripVertical } from "lucide-react"; import * as ResizablePrimitive from "react-resizable-panels"; -import { cn } from "@/lib/utils"; +import { cn } from "~/lib/utils"; const ResizablePanelGroup = ({ className, diff --git a/components/ui/spinner.tsx b/components/ui/spinner.tsx new file mode 100644 index 0000000..1c1b5e5 --- /dev/null +++ b/components/ui/spinner.tsx @@ -0,0 +1,12 @@ +import { Loader2 } from "lucide-react"; +import { cn } from "~/lib/utils"; + +type Spinner = { + className?: string; +}; + +const Spinner = ({ className }: Spinner) => { + return ; +}; + +export default Spinner; diff --git a/src/components/ui/tabs.tsx b/components/ui/tabs.tsx similarity index 99% rename from src/components/ui/tabs.tsx rename to components/ui/tabs.tsx index 7320f12..d1acd94 100644 --- a/src/components/ui/tabs.tsx +++ b/components/ui/tabs.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils"; +import { cn } from "~/lib/utils"; import React, { useEffect, useMemo, useRef } from "react"; import ActionButton from "./action-button"; import { FiX } from "react-icons/fi"; diff --git a/drizzle.config.ts b/drizzle.config.ts index 73fa6cb..9d6659a 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,11 +1,10 @@ -import path from "node:path"; import type { Config } from "drizzle-kit"; export default { - schema: "./src/server/db/schema/_schema.ts", - out: "./src/server/db/drizzle", + schema: "./server/db/schema/_schema.ts", + out: "./server/db/drizzle", driver: "better-sqlite", dbCredentials: { - url: path.join(process.cwd(), "storage/database.db"), + url: "./storage/database.db", }, } satisfies Config; diff --git a/src/hooks/useCommandKey.ts b/hooks/useCommandKey.ts similarity index 100% rename from src/hooks/useCommandKey.ts rename to hooks/useCommandKey.ts diff --git a/src/hooks/useDebounce.ts b/hooks/useDebounce.ts similarity index 100% rename from src/hooks/useDebounce.ts rename to hooks/useDebounce.ts diff --git a/src/hooks/useDisclose.ts b/hooks/useDisclose.ts similarity index 100% rename from src/hooks/useDisclose.ts rename to hooks/useDisclose.ts diff --git a/src/hooks/useForm.ts b/hooks/useForm.ts similarity index 100% rename from src/hooks/useForm.ts rename to hooks/useForm.ts diff --git a/src/hooks/usePortrait.ts b/hooks/usePortrait.ts similarity index 100% rename from src/hooks/usePortrait.ts rename to hooks/usePortrait.ts diff --git a/lib/consts.ts b/lib/consts.ts new file mode 100644 index 0000000..4d11320 --- /dev/null +++ b/lib/consts.ts @@ -0,0 +1,2 @@ +export const BASE_URL = + typeof window !== "undefined" ? location.protocol + "//" + location.host : ""; diff --git a/src/lib/trpc.ts b/lib/trpc.ts similarity index 82% rename from src/lib/trpc.ts rename to lib/trpc.ts index 34332a2..8ff9d89 100644 --- a/src/lib/trpc.ts +++ b/lib/trpc.ts @@ -1,5 +1,5 @@ import { createTRPCReact } from "@trpc/react-query"; -import type { AppRouter } from "@/server/routers/_app"; +import type { AppRouter } from "~/server/routers/_app"; export const getBaseUrl = () => { if (typeof window !== "undefined") return ""; diff --git a/src/lib/utils.ts b/lib/utils.ts similarity index 100% rename from src/lib/utils.ts rename to lib/utils.ts diff --git a/next.config.mjs b/next.config.mjs deleted file mode 100644 index 4678774..0000000 --- a/next.config.mjs +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; - -export default nextConfig; diff --git a/package.json b/package.json index b46c6c7..aac5756 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,41 @@ { - "name": "code-share", - "version": "0.1.0", - "private": true, + "name": "vike", + "version": "1.0.0", + "description": "", + "main": "server/index.ts", + "type": "module", "scripts": { - "dev": "concurrently --kill-others \"next dev\" \"npm run transformer:dev\"", - "build": "next build && npm run transformer:build", - "start": "concurrently --kill-others \"next start\" \"npm run transformer:start\"", - "lint": "next lint", + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "tsx watch --ignore *.mjs server/index.ts", + "start": "NODE_ENV=production tsx server/index.ts", + "build": "vite build", "generate": "drizzle-kit generate:sqlite", "drop": "drizzle-kit drop", "push": "drizzle-kit push:sqlite", - "migrate": "tsx src/server/db/migrate.ts", - "seed": "tsx src/server/db/seed.ts", - "reset": "rm -f storage/database.db && npm run push && npm run seed", - "transformer:start": "node dist/transformer/server.js", - "transformer:dev": "tsx --watch src/server/transformer/server.ts", - "transformer:build": "tsc --project tsconfig-server.json" + "migrate": "tsx server/db/migrate.ts", + "seed": "tsx server/db/seed.ts", + "reset": "rm -f storage/database.db && npm run push && npm run seed" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@swc/cli": "^0.3.9", + "@types/express": "^4.17.21", + "@types/node": "^20.11.19", + "@types/nprogress": "^0.2.3", + "@types/react": "^18.2.57", + "@types/react-dom": "^18.2.19", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.0.1", + "drizzle-kit": "^0.20.14", + "postcss": "^8", + "tailwindcss": "^3.3.0", + "tsx": "^4.7.1", + "typescript": "^5.3.3", + "vite": "^5.1.4" }, "dependencies": { - "@babel/preset-typescript": "^7.23.3", "@codemirror/lang-css": "^6.2.1", "@codemirror/lang-html": "^6.4.8", "@codemirror/lang-javascript": "^6.2.1", @@ -32,49 +49,33 @@ "@swc/core": "^1.4.2", "@tanstack/react-query": "^5.21.7", "@trpc/client": "11.0.0-next-beta.289", - "@trpc/next": "11.0.0-next-beta.289", "@trpc/react-query": "11.0.0-next-beta.289", "@trpc/server": "11.0.0-next-beta.289", - "@types/express": "^4.17.21", "@uiw/codemirror-theme-tokyo-night": "^4.21.22", "@uiw/react-codemirror": "^4.21.22", "bcrypt": "^5.1.1", "better-sqlite3": "^9.4.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "console-feed": "^3.5.0", "copy-to-clipboard": "^3.3.3", "drizzle-orm": "^0.29.3", "drizzle-zod": "^0.5.1", "express": "^4.18.2", "lucide-react": "^0.331.0", "mime": "^4.0.1", - "next": "14.1.0", + "nprogress": "^0.2.0", "prettier": "^3.2.5", - "react": "^18", - "react-dom": "^18", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-hook-form": "^7.50.1", "react-icons": "^5.0.1", "react-resizable-panels": "^2.0.9", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", "usehooks-ts": "^2.14.0", + "vike": "^0.4.162", "zod": "^3.22.4", "zustand": "^4.5.1" - }, - "devDependencies": { - "@types/bcrypt": "^5.0.2", - "@types/better-sqlite3": "^7.6.9", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "autoprefixer": "^10.0.1", - "concurrently": "^8.2.2", - "drizzle-kit": "^0.20.14", - "eslint": "^8", - "eslint-config-next": "14.1.0", - "postcss": "^8", - "tailwindcss": "^3.3.0", - "tsx": "^4.7.1", - "typescript": "^5" } } diff --git a/pages/@id/+Page.tsx b/pages/@id/+Page.tsx new file mode 100644 index 0000000..0db676b --- /dev/null +++ b/pages/@id/+Page.tsx @@ -0,0 +1,17 @@ +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 new file mode 100644 index 0000000..6362bc7 --- /dev/null +++ b/pages/@id/+data.ts @@ -0,0 +1,12 @@ +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/_error/+Page.tsx b/pages/_error/+Page.tsx new file mode 100644 index 0000000..964b6ee --- /dev/null +++ b/pages/_error/+Page.tsx @@ -0,0 +1,20 @@ +import { usePageContext } from "~/renderer/context"; + +const Page = () => { + const pageContext = usePageContext(); + let { abortReason } = pageContext; + + if (!abortReason) { + abortReason = pageContext.is404 + ? "Page not found." + : "Something went wrong."; + } + + return ( +
+

{abortReason}

+
+ ); +}; + +export default Page; diff --git a/pages/index/+Page.tsx b/pages/index/+Page.tsx new file mode 100644 index 0000000..d335975 --- /dev/null +++ b/pages/index/+Page.tsx @@ -0,0 +1,24 @@ +import type { Data } from "./+data"; +import { useData } from "~/renderer/hooks"; +import Link from "~/renderer/link"; + +const HomePage = () => { + const { posts } = useData(); + if (!posts?.length) { + return

No posts.

; + } + + return ( +
+

Posts

+ + {posts.map((post: any) => ( + + {post.title} + + ))} +
+ ); +}; + +export default HomePage; diff --git a/pages/index/+data.ts b/pages/index/+data.ts new file mode 100644 index 0000000..dde8e69 --- /dev/null +++ b/pages/index/+data.ts @@ -0,0 +1,9 @@ +export const data = async () => { + const posts = await fetch( + "https://jsonplaceholder.typicode.com/posts?_limit=20" + ).then((response) => response.json()); + + return { posts }; +}; + +export type Data = Awaited>; diff --git a/src/app/project/[slug]/page.tsx b/pages/project/@slug/+Page.tsx similarity index 62% rename from src/app/project/[slug]/page.tsx rename to pages/project/@slug/+Page.tsx index 4a54a86..e3faf59 100644 --- a/src/app/project/[slug]/page.tsx +++ b/pages/project/@slug/+Page.tsx @@ -1,39 +1,32 @@ -"use client"; - -import React, { useCallback, useEffect, useRef, useState } from "react"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, -} from "@/components/ui/resizable"; -import WebPreview from "./_components/web-preview"; -import { usePortrait } from "@/hooks/usePortrait"; -import Editor from "./_components/editor"; +} from "~/components/ui/resizable"; +import WebPreview from "./components/web-preview"; +import { usePortrait } from "~/hooks/usePortrait"; +import Editor from "./components/editor"; import ProjectContext from "./context/project"; -import { cn } from "@/lib/utils"; -import { useSearchParams } from "next/navigation"; +import { cn } from "~/lib/utils"; +import { withClientOnly } from "~/renderer/client-only"; +import { useParams, useSearchParams } from "~/renderer/hooks"; +import { BASE_URL } from "~/lib/consts"; const ViewProjectPage = () => { - const [isMounted, setMounted] = useState(false); const isPortrait = usePortrait(); const searchParams = useSearchParams(); + const params = useParams(); const isCompact = searchParams.get("compact") === "1" || searchParams.get("embed") === "1"; - - useEffect(() => { - setMounted(true); - }, []); - - if (!isMounted) { - return null; - } + const slug = params["slug"]; + const previewUrl = BASE_URL + `/api/preview/${slug}/index.html`; return ( - + { collapsedSize={0} minSize={10} > - + ); }; -export default ViewProjectPage; +export default withClientOnly(ViewProjectPage); diff --git a/pages/project/@slug/components/console-logger.tsx b/pages/project/@slug/components/console-logger.tsx new file mode 100644 index 0000000..bc1354b --- /dev/null +++ b/pages/project/@slug/components/console-logger.tsx @@ -0,0 +1,42 @@ +import { useEffect, useState } from "react"; +import { Console, Decode } from "console-feed"; +import type { Message } from "console-feed/lib/definitions/Console"; +import ErrorBoundary from "~/components/containers/error-boundary"; + +const ConsoleLogger = () => { + const [logs, setLogs] = useState([]); + + useEffect(() => { + const onMessage = (event: MessageEvent) => { + const { data: eventData } = event; + if (!eventData || eventData.type !== "console") { + return; + } + + const data = Decode(eventData.data); + if (!data || !data.method || !data.data) { + return; + } + + setLogs((i) => [data, ...i]); + }; + + window.addEventListener("message", onMessage); + return () => { + window.removeEventListener("message", onMessage); + }; + }, []); + + return ( +
+

Console

+ +
+ +
+
+
+ ); +}; + +export default ConsoleLogger; diff --git a/src/app/project/[slug]/_components/createfile-dialog.tsx b/pages/project/@slug/components/createfile-dialog.tsx similarity index 91% rename from src/app/project/[slug]/_components/createfile-dialog.tsx rename to pages/project/@slug/components/createfile-dialog.tsx index 334c0e0..090eb0b 100644 --- a/src/app/project/[slug]/_components/createfile-dialog.tsx +++ b/pages/project/@slug/components/createfile-dialog.tsx @@ -1,18 +1,17 @@ -import React, { useMemo } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "../../../../components/ui/dialog"; -import { UseDiscloseReturn } from "@/hooks/useDisclose"; +import { UseDiscloseReturn } from "~/hooks/useDisclose"; import { Input } from "../../../../components/ui/input"; import { Button } from "../../../../components/ui/button"; -import { useForm } from "@/hooks/useForm"; +import { useForm } from "~/hooks/useForm"; import { z } from "zod"; import FormErrorMessage from "../../../../components/ui/form-error-message"; -import trpc from "@/lib/trpc"; -import type { FileSchema } from "@/server/db/schema/file"; +import trpc from "~/lib/trpc"; +import type { FileSchema } from "~/server/db/schema/file"; import { useWatch } from "react-hook-form"; type Props = { diff --git a/src/app/project/[slug]/_components/editor.tsx b/pages/project/@slug/components/editor.tsx similarity index 90% rename from src/app/project/[slug]/_components/editor.tsx rename to pages/project/@slug/components/editor.tsx index da7b332..c1dd0f2 100644 --- a/src/app/project/[slug]/_components/editor.tsx +++ b/pages/project/@slug/components/editor.tsx @@ -1,28 +1,22 @@ -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, -} from "@/components/ui/resizable"; -import Tabs, { Tab } from "@/components/ui/tabs"; +} from "~/components/ui/resizable"; +import Tabs, { Tab } from "~/components/ui/tabs"; import FileViewer from "./file-viewer"; -import trpc from "@/lib/trpc"; +import trpc from "~/lib/trpc"; import EditorContext from "../context/editor"; -import type { FileSchema } from "@/server/db/schema/file"; -import { usePortrait } from "@/hooks/usePortrait"; -import Panel from "@/components/ui/panel"; -import { previewStore } from "./web-preview"; +import type { FileSchema } from "~/server/db/schema/file"; +import { usePortrait } from "~/hooks/usePortrait"; +import Panel from "~/components/ui/panel"; +import { previewStore } from "../stores/web-preview"; import { useProjectContext } from "../context/project"; import { ImperativePanelHandle } from "react-resizable-panels"; import Sidebar from "./sidebar"; -import useCommandKey from "@/hooks/useCommandKey"; -import { Button } from "@/components/ui/button"; +import useCommandKey from "~/hooks/useCommandKey"; +import { Button } from "~/components/ui/button"; import { FaCompress, FaCompressArrowsAlt } from "react-icons/fa"; import ConsoleLogger from "./console-logger"; @@ -194,7 +188,7 @@ const Editor = () => { autoCapitalize="code-editor" direction="vertical" > - + { const { onOpenFile, onFileChanged } = useEditorContext(); @@ -175,14 +175,14 @@ const FileItem = ({ file, createFileDlg }: FileItemProps) => { Copy Path copy(getUrl(`project/${slug}/file`, file.path))} + onClick={() => copy(getUrl(`api/preview/${slug}`, file.path))} > Copy URL window.open( - getUrl(`project/${slug}/file`, file.path), + getUrl(`api/preview/${slug}`, file.path), "_blank" ) } diff --git a/src/app/project/[slug]/_components/file-viewer.tsx b/pages/project/@slug/components/file-viewer.tsx similarity index 92% rename from src/app/project/[slug]/_components/file-viewer.tsx rename to pages/project/@slug/components/file-viewer.tsx index ae37fd3..d4454bb 100644 --- a/src/app/project/[slug]/_components/file-viewer.tsx +++ b/pages/project/@slug/components/file-viewer.tsx @@ -1,9 +1,9 @@ "use client"; -import { getFileExt } from "@/lib/utils"; +import { getFileExt } from "~/lib/utils"; import React from "react"; import CodeEditor from "../../../../components/ui/code-editor"; -import trpc from "@/lib/trpc"; +import trpc from "~/lib/trpc"; type Props = { id: number; diff --git a/src/app/project/[slug]/_components/sidebar.tsx b/pages/project/@slug/components/sidebar.tsx similarity index 92% rename from src/app/project/[slug]/_components/sidebar.tsx rename to pages/project/@slug/components/sidebar.tsx index 464368e..9e31aae 100644 --- a/src/app/project/[slug]/_components/sidebar.tsx +++ b/pages/project/@slug/components/sidebar.tsx @@ -1,7 +1,7 @@ import React from "react"; import FileListing from "./file-listing"; import { FaUserCircle } from "react-icons/fa"; -import { Button } from "@/components/ui/button"; +import { Button } from "~/components/ui/button"; const Sidebar = () => { return ( diff --git a/pages/project/@slug/components/web-preview.tsx b/pages/project/@slug/components/web-preview.tsx new file mode 100644 index 0000000..dc2f40b --- /dev/null +++ b/pages/project/@slug/components/web-preview.tsx @@ -0,0 +1,67 @@ +/* eslint-disable react/display-name */ +import Panel from "~/components/ui/panel"; +import { useCallback, useEffect, useRef } from "react"; +import { useProjectContext } from "../context/project"; +import { Button } from "~/components/ui/button"; +import { FaEllipsisV, FaRedo } from "react-icons/fa"; +import { Input } from "~/components/ui/input"; +import { previewStore } from "../stores/web-preview"; + +type WebPreviewProps = { + url?: string | null; +}; + +const WebPreview = ({ url }: WebPreviewProps) => { + const frameRef = useRef(null); + const project = useProjectContext(); + + const refresh = useCallback(() => { + if (frameRef.current) { + frameRef.current.src = `${url}?t=${Date.now()}`; + } + }, [url]); + + useEffect(() => { + previewStore.setState({ refresh }); + refresh(); + }, [refresh]); + + const PanelComponent = !project.isCompact ? Panel : "div"; + + return ( + +
+ + + +
+ + {url != null ? ( +