mirror of
https://github.com/khairul169/code-share.git
synced 2025-04-28 08:39:35 +07:00
feat: fix panel persist over server rendering, etc
This commit is contained in:
parent
2c9faa332a
commit
efe51a9b5e
@ -50,6 +50,7 @@ const CodeEditor = (props: Props) => {
|
||||
parser,
|
||||
plugins,
|
||||
cursorOffset: cursor,
|
||||
printWidth: 64,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
|
@ -1,5 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||
|
@ -1,24 +1,82 @@
|
||||
"use client";
|
||||
|
||||
import { GripVertical } from "lucide-react";
|
||||
import { createContext, forwardRef, useContext } from "react";
|
||||
import * as ResizablePrimitive from "react-resizable-panels";
|
||||
import cookieJs from "cookiejs";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { usePageContext } from "~/renderer/context";
|
||||
import { useDebounce } from "~/hooks/useDebounce";
|
||||
|
||||
const ResizableContext = createContext<{ initialSize: number[] }>(null!);
|
||||
|
||||
const ResizablePanelGroup = ({
|
||||
className,
|
||||
autoSaveId,
|
||||
direction,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
|
||||
<ResizablePrimitive.PanelGroup
|
||||
className={cn(
|
||||
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => {
|
||||
const { cookies } = usePageContext();
|
||||
const [debouncePersistLayout] = useDebounce((sizes: number[]) => {
|
||||
if (autoSaveId && typeof window !== "undefined") {
|
||||
cookieJs.set(panelKey, JSON.stringify(sizes));
|
||||
}
|
||||
}, 500);
|
||||
|
||||
const ResizablePanel = ResizablePrimitive.Panel;
|
||||
const panelKey = ["panel", direction, autoSaveId].join(":");
|
||||
let initialSize: number[] = [];
|
||||
|
||||
if (autoSaveId && cookies && cookies[panelKey]) {
|
||||
initialSize = JSON.parse(cookies[panelKey]) || [];
|
||||
}
|
||||
|
||||
const onLayout = (sizes: number[]) => {
|
||||
if (props.onLayout) {
|
||||
props.onLayout(sizes);
|
||||
}
|
||||
debouncePersistLayout(sizes);
|
||||
};
|
||||
|
||||
return (
|
||||
<ResizableContext.Provider value={{ initialSize }}>
|
||||
<ResizablePrimitive.PanelGroup
|
||||
className={cn(
|
||||
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
direction={direction}
|
||||
onLayout={onLayout}
|
||||
/>
|
||||
</ResizableContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
type ResizablePanelProps = React.ComponentProps<
|
||||
typeof ResizablePrimitive.Panel
|
||||
> & {
|
||||
panelId: number;
|
||||
};
|
||||
|
||||
const ResizablePanel = forwardRef((props: ResizablePanelProps, ref: any) => {
|
||||
const { panelId, defaultSize, ...restProps } = props;
|
||||
const ctx = useContext(ResizableContext);
|
||||
let initialSize = defaultSize;
|
||||
|
||||
if (panelId != null) {
|
||||
const size = ctx?.initialSize[panelId];
|
||||
if (size != null) {
|
||||
initialSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ResizablePrimitive.Panel
|
||||
ref={ref}
|
||||
defaultSize={initialSize}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const ResizableHandle = ({
|
||||
withHandle,
|
||||
|
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
@ -21,6 +21,7 @@
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.3.9",
|
||||
"@types/cookie-parser": "^1.4.6",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
@ -29,7 +30,6 @@
|
||||
"@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",
|
||||
@ -58,13 +58,17 @@
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"console-feed": "^3.5.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cookiejs": "^2.1.3",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"cssnano": "^6.0.3",
|
||||
"drizzle-orm": "^0.29.3",
|
||||
"drizzle-zod": "^0.5.1",
|
||||
"express": "^4.18.2",
|
||||
"lucide-react": "^0.331.0",
|
||||
"mime": "^4.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.2.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
@ -8,7 +8,6 @@ import { usePortrait } from "~/hooks/usePortrait";
|
||||
import Editor from "./components/editor";
|
||||
import ProjectContext from "./context/project";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { withClientOnly } from "~/renderer/client-only";
|
||||
import { useParams, useSearchParams } from "~/renderer/hooks";
|
||||
import { BASE_URL } from "~/lib/consts";
|
||||
|
||||
@ -29,6 +28,7 @@ const ViewProjectPage = () => {
|
||||
className={cn("w-full !h-dvh bg-slate-600", !isCompact ? "md:p-4" : "")}
|
||||
>
|
||||
<ResizablePanel
|
||||
panelId={0}
|
||||
defaultSize={isPortrait ? 50 : 60}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
@ -45,6 +45,7 @@ const ViewProjectPage = () => {
|
||||
}
|
||||
/>
|
||||
<ResizablePanel
|
||||
panelId={1}
|
||||
defaultSize={isPortrait ? 50 : 40}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
@ -57,4 +58,4 @@ const ViewProjectPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withClientOnly(ViewProjectPage);
|
||||
export default ViewProjectPage;
|
||||
|
12
pages/project/@slug/+data.ts
Normal file
12
pages/project/@slug/+data.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { PageContext } from "vike/types";
|
||||
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 };
|
||||
};
|
||||
|
||||
export type Data = Awaited<ReturnType<typeof data>>;
|
@ -9,7 +9,6 @@ import FileViewer from "./file-viewer";
|
||||
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 "../stores/web-preview";
|
||||
import { useProjectContext } from "../context/project";
|
||||
@ -19,27 +18,26 @@ import useCommandKey from "~/hooks/useCommandKey";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { FaCompress, FaCompressArrowsAlt } from "react-icons/fa";
|
||||
import ConsoleLogger from "./console-logger";
|
||||
import { useData } from "~/renderer/hooks";
|
||||
import { Data } from "../+data";
|
||||
|
||||
const Editor = () => {
|
||||
const isPortrait = usePortrait();
|
||||
const { pinnedFiles } = useData<Data>();
|
||||
const trpcUtils = trpc.useUtils();
|
||||
const [isMounted, setMounted] = useState(false);
|
||||
const project = useProjectContext();
|
||||
const sidebarPanel = useRef<ImperativePanelHandle>(null);
|
||||
|
||||
const [sidebarExpanded, setSidebarExpanded] = useState(false);
|
||||
const [curTabIdx, setCurTabIdx] = useState(0);
|
||||
const [curOpenFiles, setOpenFiles] = useState<number[]>([]);
|
||||
|
||||
const pinnedFiles = trpc.file.getAll.useQuery(
|
||||
{ isPinned: true },
|
||||
{ enabled: !isMounted }
|
||||
const [curOpenFiles, setOpenFiles] = useState<number[]>(
|
||||
pinnedFiles.map((i) => i.id)
|
||||
);
|
||||
|
||||
const openedFilesData = trpc.file.getAll.useQuery(
|
||||
{ id: curOpenFiles },
|
||||
{ enabled: curOpenFiles.length > 0 }
|
||||
{ enabled: curOpenFiles.length > 0, initialData: pinnedFiles }
|
||||
);
|
||||
const [openedFiles, setOpenedFiles] = useState<any[]>([]);
|
||||
const [openedFiles, setOpenedFiles] = useState<any[]>(pinnedFiles);
|
||||
|
||||
const deleteFile = trpc.file.delete.useMutation({
|
||||
onSuccess: (file) => {
|
||||
@ -53,10 +51,6 @@ const Editor = () => {
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const toggleSidebar = useCallback(() => {
|
||||
const sidebar = sidebarPanel.current;
|
||||
if (!sidebar) {
|
||||
@ -74,15 +68,19 @@ const Editor = () => {
|
||||
useCommandKey("b", toggleSidebar);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pinnedFiles.data?.length || curOpenFiles.length > 0) {
|
||||
if (!pinnedFiles?.length || curOpenFiles.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pinnedFiles.data.forEach((file) => {
|
||||
pinnedFiles.forEach((file) => {
|
||||
onOpenFile(file.id, false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
setOpenFiles([]);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pinnedFiles.data]);
|
||||
}, [pinnedFiles]);
|
||||
|
||||
useEffect(() => {
|
||||
if (openedFilesData.data) {
|
||||
@ -170,7 +168,8 @@ const Editor = () => {
|
||||
<ResizablePanelGroup autoSaveId="veditor-panel" direction="horizontal">
|
||||
<ResizablePanel
|
||||
ref={sidebarPanel}
|
||||
defaultSize={isPortrait ? 0 : 25}
|
||||
panelId={0}
|
||||
defaultSize={25}
|
||||
minSize={10}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
@ -183,12 +182,9 @@ const Editor = () => {
|
||||
|
||||
<ResizableHandle className="bg-slate-900" />
|
||||
|
||||
<ResizablePanel defaultSize={isPortrait ? 100 : 75}>
|
||||
<ResizablePanelGroup
|
||||
autoCapitalize="code-editor"
|
||||
direction="vertical"
|
||||
>
|
||||
<ResizablePanel defaultSize={isPortrait ? 100 : 80} minSize={20}>
|
||||
<ResizablePanel panelId={1} defaultSize={75}>
|
||||
<ResizablePanelGroup autoSaveId="code-editor" direction="vertical">
|
||||
<ResizablePanel panelId={0} defaultSize={80} minSize={20}>
|
||||
<Tabs
|
||||
tabs={openFileList}
|
||||
current={curTabIdx}
|
||||
@ -197,19 +193,16 @@ const Editor = () => {
|
||||
/>
|
||||
</ResizablePanel>
|
||||
|
||||
{!isPortrait ? (
|
||||
<>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel
|
||||
defaultSize={20}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
minSize={10}
|
||||
>
|
||||
<ConsoleLogger />
|
||||
</ResizablePanel>
|
||||
</>
|
||||
) : null}
|
||||
<ResizableHandle />
|
||||
<ResizablePanel
|
||||
panelId={1}
|
||||
defaultSize={20}
|
||||
collapsible
|
||||
collapsedSize={0}
|
||||
minSize={10}
|
||||
>
|
||||
<ConsoleLogger />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
|
@ -24,12 +24,17 @@ import {
|
||||
import { cn, getUrl } from "~/lib/utils";
|
||||
import FileIcon from "~/components/ui/file-icon";
|
||||
import copy from "copy-to-clipboard";
|
||||
import { useParams } from "~/renderer/hooks";
|
||||
import { useData, useParams } from "~/renderer/hooks";
|
||||
import Spinner from "~/components/ui/spinner";
|
||||
import { Data } from "../+data";
|
||||
|
||||
const FileListing = () => {
|
||||
const pageData = useData<Data>();
|
||||
const { onOpenFile, onFileChanged } = useEditorContext();
|
||||
const createFileDlg = useDisclose<CreateFileSchema>();
|
||||
const files = trpc.file.getAll.useQuery();
|
||||
const files = trpc.file.getAll.useQuery(undefined, {
|
||||
initialData: pageData.files,
|
||||
});
|
||||
|
||||
const fileList = useMemo(() => groupFiles(files.data, null), [files.data]);
|
||||
|
||||
@ -62,11 +67,17 @@ const FileListing = () => {
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-stretch flex-1 overflow-y-auto">
|
||||
{fileList.map((file) => (
|
||||
<FileItem key={file.id} file={file} createFileDlg={createFileDlg} />
|
||||
))}
|
||||
</div>
|
||||
{files.isLoading ? (
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-stretch flex-1 overflow-y-auto">
|
||||
{fileList.map((file) => (
|
||||
<FileItem key={file.id} file={file} createFileDlg={createFileDlg} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<CreateFileDialog
|
||||
disclose={createFileDlg}
|
||||
|
@ -4,6 +4,10 @@ import { getFileExt } from "~/lib/utils";
|
||||
import React from "react";
|
||||
import CodeEditor from "../../../../components/ui/code-editor";
|
||||
import trpc from "~/lib/trpc";
|
||||
import { useData } from "~/renderer/hooks";
|
||||
import { Data } from "../+data";
|
||||
import ClientOnly from "~/renderer/client-only";
|
||||
import Spinner from "~/components/ui/spinner";
|
||||
|
||||
type Props = {
|
||||
id: number;
|
||||
@ -11,7 +15,12 @@ type Props = {
|
||||
};
|
||||
|
||||
const FileViewer = ({ id, onFileContentChange }: Props) => {
|
||||
const { data, isLoading, refetch } = trpc.file.getById.useQuery(id);
|
||||
const { pinnedFiles } = useData<Data>();
|
||||
const initialData = pinnedFiles.find((i) => i.id === id);
|
||||
|
||||
const { data, isLoading, refetch } = trpc.file.getById.useQuery(id, {
|
||||
initialData,
|
||||
});
|
||||
const updateFileContent = trpc.file.update.useMutation({
|
||||
onSuccess: () => {
|
||||
if (onFileContentChange) onFileContentChange();
|
||||
@ -20,8 +29,9 @@ const FileViewer = ({ id, onFileContentChange }: Props) => {
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return <p>Loading...</p>;
|
||||
return <LoadingLayout />;
|
||||
}
|
||||
|
||||
if (!data || data.isDirectory) {
|
||||
return <p>File not found.</p>;
|
||||
}
|
||||
@ -32,16 +42,36 @@ const FileViewer = ({ id, onFileContentChange }: Props) => {
|
||||
const ext = getFileExt(filename);
|
||||
|
||||
return (
|
||||
<CodeEditor
|
||||
lang={ext}
|
||||
value={data?.content || ""}
|
||||
formatOnSave
|
||||
onChange={(val) => updateFileContent.mutate({ id, content: val })}
|
||||
/>
|
||||
<ClientOnly fallback={<SSRCodeEditor value={data?.content} />}>
|
||||
<CodeEditor
|
||||
lang={ext}
|
||||
value={data?.content || ""}
|
||||
formatOnSave
|
||||
onChange={(val) => updateFileContent.mutate({ id, content: val })}
|
||||
/>
|
||||
</ClientOnly>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const LoadingLayout = () => {
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const SSRCodeEditor = ({ value }: { value?: string | null }) => {
|
||||
return (
|
||||
<textarea
|
||||
className="w-full h-full py-3 pl-11 pr-2 overflow-x-auto text-nowrap font-mono text-sm md:text-[16px] md:leading-[22px] bg-[#1a1b26] text-[#787c99]"
|
||||
value={value || ""}
|
||||
readOnly
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileViewer;
|
||||
|
@ -31,6 +31,7 @@ const WebPreview = ({ url }: WebPreviewProps) => {
|
||||
return (
|
||||
<PanelComponent className="h-full flex flex-col bg-slate-800">
|
||||
<div className="h-10 flex items-center">
|
||||
<p className="flex-1 truncate text-xs uppercase pl-4">Preview</p>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="dark:hover:bg-slate-700"
|
||||
@ -38,18 +39,6 @@ const WebPreview = ({ url }: WebPreviewProps) => {
|
||||
>
|
||||
<FaRedo />
|
||||
</Button>
|
||||
<Input
|
||||
className="flex-1 dark:bg-gray-900 dark:hover:bg-gray-950 h-8 rounded-full"
|
||||
value={url || ""}
|
||||
readOnly
|
||||
/>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="dark:hover:bg-slate-700"
|
||||
onClick={() => {}}
|
||||
>
|
||||
<FaEllipsisV />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{url != null ? (
|
||||
|
536
pnpm-lock.yaml
generated
536
pnpm-lock.yaml
generated
@ -71,9 +71,18 @@ dependencies:
|
||||
console-feed:
|
||||
specifier: ^3.5.0
|
||||
version: 3.5.0(jquery@3.7.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
cookie-parser:
|
||||
specifier: ^1.4.6
|
||||
version: 1.4.6
|
||||
cookiejs:
|
||||
specifier: ^2.1.3
|
||||
version: 2.1.3
|
||||
copy-to-clipboard:
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
cssnano:
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(postcss@8.4.35)
|
||||
drizzle-orm:
|
||||
specifier: ^0.29.3
|
||||
version: 0.29.3(@types/react@18.2.57)(better-sqlite3@9.4.2)(react@18.2.0)
|
||||
@ -92,6 +101,9 @@ dependencies:
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
postcss:
|
||||
specifier: ^8
|
||||
version: 8.4.35
|
||||
prettier:
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5
|
||||
@ -133,6 +145,9 @@ devDependencies:
|
||||
'@swc/cli':
|
||||
specifier: ^0.3.9
|
||||
version: 0.3.9(@swc/core@1.4.2)
|
||||
'@types/cookie-parser':
|
||||
specifier: ^1.4.6
|
||||
version: 1.4.6
|
||||
'@types/express':
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
@ -157,9 +172,6 @@ devDependencies:
|
||||
drizzle-kit:
|
||||
specifier: ^0.20.14
|
||||
version: 0.20.14
|
||||
postcss:
|
||||
specifier: ^8
|
||||
version: 8.4.35
|
||||
tailwindcss:
|
||||
specifier: ^3.3.0
|
||||
version: 3.4.1
|
||||
@ -2145,6 +2157,11 @@ packages:
|
||||
resolution: {integrity: sha512-HfBVYUShvktA6M78jrCsRLyeE6l2NdaPJxKg095h4vk0bgWVfz0MgEOCQR/hjGdw0EFLEVcZANhqTZaHEzr36w==}
|
||||
dev: false
|
||||
|
||||
/@trysound/sax@0.2.0:
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
dev: false
|
||||
|
||||
/@types/babel__core@7.20.5:
|
||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||
dependencies:
|
||||
@ -2196,6 +2213,12 @@ packages:
|
||||
'@types/node': 20.11.19
|
||||
dev: true
|
||||
|
||||
/@types/cookie-parser@1.4.6:
|
||||
resolution: {integrity: sha512-KoooCrD56qlLskXPLGUiJxOMnv5l/8m7cQD2OxJ73NPMhuSz9PmvwRD6EpjDyKBVrdJDdQ4bQK7JFNHnNmax0w==}
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
dev: true
|
||||
|
||||
/@types/estree@1.0.5:
|
||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||
|
||||
@ -2608,6 +2631,10 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/boolbase@1.0.0:
|
||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||
dev: false
|
||||
|
||||
/brace-expansion@1.1.11:
|
||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||
dependencies:
|
||||
@ -2635,7 +2662,6 @@ packages:
|
||||
electron-to-chromium: 1.4.678
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.0.13(browserslist@4.23.0)
|
||||
dev: true
|
||||
|
||||
/buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
@ -2700,9 +2726,17 @@ packages:
|
||||
engines: {node: '>=14.16'}
|
||||
dev: true
|
||||
|
||||
/caniuse-api@3.0.0:
|
||||
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
caniuse-lite: 1.0.30001588
|
||||
lodash.memoize: 4.1.2
|
||||
lodash.uniq: 4.5.0
|
||||
dev: false
|
||||
|
||||
/caniuse-lite@1.0.30001588:
|
||||
resolution: {integrity: sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==}
|
||||
dev: true
|
||||
|
||||
/chalk@2.4.2:
|
||||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||
@ -2809,6 +2843,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
dev: false
|
||||
|
||||
/commander@4.1.1:
|
||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -2816,7 +2854,6 @@ packages:
|
||||
/commander@7.2.0:
|
||||
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||
engines: {node: '>= 10'}
|
||||
dev: true
|
||||
|
||||
/commander@9.5.0:
|
||||
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
|
||||
@ -2866,15 +2903,32 @@ packages:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
dev: true
|
||||
|
||||
/cookie-parser@1.4.6:
|
||||
resolution: {integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
cookie: 0.4.1
|
||||
cookie-signature: 1.0.6
|
||||
dev: false
|
||||
|
||||
/cookie-signature@1.0.6:
|
||||
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
||||
dev: false
|
||||
|
||||
/cookie@0.4.1:
|
||||
resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/cookie@0.5.0:
|
||||
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/cookiejs@2.1.3:
|
||||
resolution: {integrity: sha512-pA/nRQVka2eTXm1/Dq8pNt1PN+e1PJNItah0vL15qwpet81/tUfrAp8e0iiVM8WEAzDcTGK5/1hDyR6BdBZMVg==}
|
||||
dev: false
|
||||
|
||||
/copy-anything@3.0.5:
|
||||
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
|
||||
engines: {node: '>=12.13'}
|
||||
@ -2919,11 +2973,116 @@ packages:
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
/css-declaration-sorter@7.1.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==}
|
||||
engines: {node: ^14 || ^16 || >=18}
|
||||
peerDependencies:
|
||||
postcss: ^8.0.9
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/css-select@5.1.0:
|
||||
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
css-what: 6.1.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.1.0
|
||||
nth-check: 2.1.1
|
||||
dev: false
|
||||
|
||||
/css-tree@2.2.1:
|
||||
resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||
dependencies:
|
||||
mdn-data: 2.0.28
|
||||
source-map-js: 1.0.2
|
||||
dev: false
|
||||
|
||||
/css-tree@2.3.1:
|
||||
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||
dependencies:
|
||||
mdn-data: 2.0.30
|
||||
source-map-js: 1.0.2
|
||||
dev: false
|
||||
|
||||
/css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: false
|
||||
|
||||
/cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
/cssnano-preset-default@6.0.3(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-4y3H370aZCkT9Ev8P4SO4bZbt+AExeKhh8wTbms/X7OLDo5E7AYUUy6YPxa/uF5Grf+AJwNcCnxKhZynJ6luBA==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
css-declaration-sorter: 7.1.1(postcss@8.4.35)
|
||||
cssnano-utils: 4.0.1(postcss@8.4.35)
|
||||
postcss: 8.4.35
|
||||
postcss-calc: 9.0.1(postcss@8.4.35)
|
||||
postcss-colormin: 6.0.2(postcss@8.4.35)
|
||||
postcss-convert-values: 6.0.2(postcss@8.4.35)
|
||||
postcss-discard-comments: 6.0.1(postcss@8.4.35)
|
||||
postcss-discard-duplicates: 6.0.1(postcss@8.4.35)
|
||||
postcss-discard-empty: 6.0.1(postcss@8.4.35)
|
||||
postcss-discard-overridden: 6.0.1(postcss@8.4.35)
|
||||
postcss-merge-longhand: 6.0.2(postcss@8.4.35)
|
||||
postcss-merge-rules: 6.0.3(postcss@8.4.35)
|
||||
postcss-minify-font-values: 6.0.1(postcss@8.4.35)
|
||||
postcss-minify-gradients: 6.0.1(postcss@8.4.35)
|
||||
postcss-minify-params: 6.0.2(postcss@8.4.35)
|
||||
postcss-minify-selectors: 6.0.2(postcss@8.4.35)
|
||||
postcss-normalize-charset: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-display-values: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-positions: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-repeat-style: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-string: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-timing-functions: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-unicode: 6.0.2(postcss@8.4.35)
|
||||
postcss-normalize-url: 6.0.1(postcss@8.4.35)
|
||||
postcss-normalize-whitespace: 6.0.1(postcss@8.4.35)
|
||||
postcss-ordered-values: 6.0.1(postcss@8.4.35)
|
||||
postcss-reduce-initial: 6.0.2(postcss@8.4.35)
|
||||
postcss-reduce-transforms: 6.0.1(postcss@8.4.35)
|
||||
postcss-svgo: 6.0.2(postcss@8.4.35)
|
||||
postcss-unique-selectors: 6.0.2(postcss@8.4.35)
|
||||
dev: false
|
||||
|
||||
/cssnano-utils@4.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/cssnano@6.0.3(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-MRq4CIj8pnyZpcI2qs6wswoYoDD1t0aL28n+41c1Ukcpm56m1h6mCexIHBGjfZfnTqtGSSCP4/fB1ovxgjBOiw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
cssnano-preset-default: 6.0.3(postcss@8.4.35)
|
||||
lilconfig: 3.1.1
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/csso@5.0.5:
|
||||
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
|
||||
dependencies:
|
||||
css-tree: 2.2.1
|
||||
dev: false
|
||||
|
||||
/csstype@2.6.21:
|
||||
resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
|
||||
dev: false
|
||||
@ -3020,6 +3179,33 @@ packages:
|
||||
/dlv@1.1.3:
|
||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||
|
||||
/dom-serializer@2.0.0:
|
||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
entities: 4.5.0
|
||||
dev: false
|
||||
|
||||
/domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
dev: false
|
||||
|
||||
/domhandler@5.0.3:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
dev: false
|
||||
|
||||
/domutils@3.1.0:
|
||||
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
|
||||
dependencies:
|
||||
dom-serializer: 2.0.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
dev: false
|
||||
|
||||
/dreamopt@0.8.0:
|
||||
resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
@ -3144,7 +3330,6 @@ packages:
|
||||
|
||||
/electron-to-chromium@1.4.678:
|
||||
resolution: {integrity: sha512-NbdGC2p0O5Q5iVhLEsNBSfytaw7wbEFJlIvaF71wi6QDtLAph5/rVogjyOpf/QggJIt8hNK3KdwNJnc2bzckbw==}
|
||||
dev: true
|
||||
|
||||
/emmet@2.4.6:
|
||||
resolution: {integrity: sha512-dJfbdY/hfeTyf/Ef7Y7ubLYzkBvPQ912wPaeVYpAxvFxkEBf/+hJu4H6vhAvFN6HlxqedlfVn2x1S44FfQ97pg==}
|
||||
@ -3182,6 +3367,11 @@ packages:
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
|
||||
/entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
dev: false
|
||||
|
||||
/env-paths@3.0.0:
|
||||
resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@ -3317,7 +3507,6 @@ packages:
|
||||
/escalade@3.1.2:
|
||||
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/escape-html@1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
@ -3982,10 +4171,18 @@ packages:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
dev: false
|
||||
|
||||
/lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
dev: false
|
||||
|
||||
/lodash.throttle@4.1.1:
|
||||
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
|
||||
dev: true
|
||||
|
||||
/lodash.uniq@4.5.0:
|
||||
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
|
||||
dev: false
|
||||
|
||||
/loose-envify@1.4.0:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
@ -4042,6 +4239,14 @@ packages:
|
||||
semver: 6.3.1
|
||||
dev: false
|
||||
|
||||
/mdn-data@2.0.28:
|
||||
resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
|
||||
dev: false
|
||||
|
||||
/mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
dev: false
|
||||
|
||||
/media-typer@0.3.0:
|
||||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@ -4269,7 +4474,6 @@ packages:
|
||||
|
||||
/node-releases@2.0.14:
|
||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||
dev: true
|
||||
|
||||
/nopt@5.0.0:
|
||||
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
||||
@ -4320,6 +4524,12 @@ packages:
|
||||
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
|
||||
dev: false
|
||||
|
||||
/nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
dev: false
|
||||
|
||||
/object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -4449,6 +4659,77 @@ packages:
|
||||
nice-napi: 1.0.2
|
||||
dev: true
|
||||
|
||||
/postcss-calc@9.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.2.2
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-selector-parser: 6.0.15
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-colormin@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-TXKOxs9LWcdYo5cgmcSHPkyrLAh86hX1ijmyy6J8SbOhyv6ua053M3ZAM/0j44UsnQNIWdl8gb5L7xX2htKeLw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
caniuse-api: 3.0.0
|
||||
colord: 2.9.3
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-convert-values@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-aeBmaTnGQ+NUSVQT8aY0sKyAD/BaLJenEKZ03YK0JnDE1w1Rr8XShoxdal2V2H26xTJKr3v5haByOhJuyT4UYw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-discard-comments@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/postcss-discard-duplicates@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-1hvUs76HLYR8zkScbwyJ8oJEugfPV+WchpnA+26fpJ7Smzs51CzGBHC32RS03psuX/2l0l0UKh2StzNxOrKCYg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/postcss-discard-empty@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-yitcmKwmVWtNsrrRqGJ7/C0YRy53i0mjexBDQ9zYxDwTWVBgbU4+C9jIZLmQlTDT9zhml+u0OMFJh8+31krmOg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/postcss-discard-overridden@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/postcss-import@15.1.0(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@ -4485,6 +4766,74 @@ packages:
|
||||
postcss: 8.4.35
|
||||
yaml: 2.3.4
|
||||
|
||||
/postcss-merge-longhand@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-+yfVB7gEM8SrCo9w2lCApKIEzrTKl5yS1F4yGhV3kSim6JzbfLGJyhR1B6X+6vOT0U33Mgx7iv4X9MVWuaSAfw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
stylehacks: 6.0.2(postcss@8.4.35)
|
||||
dev: false
|
||||
|
||||
/postcss-merge-rules@6.0.3(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-yfkDqSHGohy8sGYIJwBmIGDv4K4/WrJPX355XrxQb/CSsT4Kc/RxDi6akqn5s9bap85AWgv21ArcUWwWdGNSHA==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
caniuse-api: 3.0.0
|
||||
cssnano-utils: 4.0.1(postcss@8.4.35)
|
||||
postcss: 8.4.35
|
||||
postcss-selector-parser: 6.0.15
|
||||
dev: false
|
||||
|
||||
/postcss-minify-font-values@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-tIwmF1zUPoN6xOtA/2FgVk1ZKrLcCvE0dpZLtzyyte0j9zUeB8RTbCqrHZGjJlxOvNWKMYtunLrrl7HPOiR46w==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-minify-gradients@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-M1RJWVjd6IOLPl1hYiOd5HQHgpp6cvJVLrieQYS9y07Yo8itAr6jaekzJphaJFR0tcg4kRewCk3kna9uHBxn/w==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
colord: 2.9.3
|
||||
cssnano-utils: 4.0.1(postcss@8.4.35)
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-minify-params@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-zwQtbrPEBDj+ApELZ6QylLf2/c5zmASoOuA4DzolyVGdV38iR2I5QRMsZcHkcdkZzxpN8RS4cN7LPskOkTwTZw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
cssnano-utils: 4.0.1(postcss@8.4.35)
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-minify-selectors@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-0b+m+w7OAvZejPQdN2GjsXLv5o0jqYHX3aoV0e7RBKPCsB7TYG5KKWBFhGnB/iP3213Ts8c5H4wLPLMm7z28Sg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-selector-parser: 6.0.15
|
||||
dev: false
|
||||
|
||||
/postcss-nested@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
|
||||
engines: {node: '>=12.0'}
|
||||
@ -4494,6 +4843,128 @@ packages:
|
||||
postcss: 8.4.35
|
||||
postcss-selector-parser: 6.0.15
|
||||
|
||||
/postcss-normalize-charset@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-display-values@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-positions@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-repeat-style@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-string@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-timing-functions@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-unicode@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-Ff2VdAYCTGyMUwpevTZPZ4w0+mPjbZzLLyoLh/RMpqUqeQKZ+xMm31hkxBavDcGKcxm6ACzGk0nBfZ8LZkStKA==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-url@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-normalize-whitespace@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-ordered-values@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
cssnano-utils: 4.0.1(postcss@8.4.35)
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-reduce-initial@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-YGKalhNlCLcjcLvjU5nF8FyeCTkCO5UtvJEt0hrPZVCTtRLSOH4z00T1UntQPj4dUmIYZgMj8qK77JbSX95hSw==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
caniuse-api: 3.0.0
|
||||
postcss: 8.4.35
|
||||
dev: false
|
||||
|
||||
/postcss-reduce-transforms@6.0.1(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-selector-parser@6.0.15:
|
||||
resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==}
|
||||
engines: {node: '>=4'}
|
||||
@ -4501,6 +4972,27 @@ packages:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
/postcss-svgo@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-IH5R9SjkTkh0kfFOQDImyy1+mTCb+E830+9SV1O+AaDcoHTvfsvt6WwJeo7KwcHbFnevZVCsXhDmjFiGVuwqFQ==}
|
||||
engines: {node: ^14 || ^16 || >= 18}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-value-parser: 4.2.0
|
||||
svgo: 3.2.0
|
||||
dev: false
|
||||
|
||||
/postcss-unique-selectors@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-8IZGQ94nechdG7Y9Sh9FlIY2b4uS8/k8kdKRX040XHsS3B6d1HrJAkXrBSsSu4SuARruSsUjW3nlSw8BHkaAYQ==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
postcss: 8.4.35
|
||||
postcss-selector-parser: 6.0.15
|
||||
dev: false
|
||||
|
||||
/postcss-value-parser@4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
|
||||
@ -5080,6 +5572,17 @@ packages:
|
||||
resolution: {integrity: sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==}
|
||||
dev: false
|
||||
|
||||
/stylehacks@6.0.2(postcss@8.4.35):
|
||||
resolution: {integrity: sha512-00zvJGnCu64EpMjX8b5iCZ3us2Ptyw8+toEkb92VdmkEaRaSGBNKAoK6aWZckhXxmQP8zWiTaFaiMGIU8Ve8sg==}
|
||||
engines: {node: ^14 || ^16 || >=18.0}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
dependencies:
|
||||
browserslist: 4.23.0
|
||||
postcss: 8.4.35
|
||||
postcss-selector-parser: 6.0.15
|
||||
dev: false
|
||||
|
||||
/sucrase@3.35.0:
|
||||
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
@ -5110,6 +5613,20 @@ packages:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
/svgo@3.2.0:
|
||||
resolution: {integrity: sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@trysound/sax': 0.2.0
|
||||
commander: 7.2.0
|
||||
css-select: 5.1.0
|
||||
css-tree: 2.3.1
|
||||
css-what: 6.1.0
|
||||
csso: 5.0.5
|
||||
picocolors: 1.0.0
|
||||
dev: false
|
||||
|
||||
/tailwind-merge@2.2.1:
|
||||
resolution: {integrity: sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==}
|
||||
dependencies:
|
||||
@ -5310,7 +5827,6 @@ packages:
|
||||
browserslist: 4.23.0
|
||||
escalade: 3.1.2
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/use-callback-ref@1.3.1(@types/react@18.2.57)(react@18.2.0):
|
||||
resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==}
|
||||
|
@ -2,7 +2,7 @@ import type { Config } from "vike/types";
|
||||
|
||||
export default {
|
||||
clientRouting: true,
|
||||
passToClient: ["routeParams"],
|
||||
passToClient: ["routeParams", "cookies"],
|
||||
meta: {
|
||||
title: {
|
||||
env: { server: true, client: true },
|
||||
|
@ -1,4 +1,5 @@
|
||||
//
|
||||
import type { Request } from "express";
|
||||
|
||||
declare global {
|
||||
namespace Vike {
|
||||
interface PageContext {
|
||||
@ -12,6 +13,8 @@ declare global {
|
||||
description?: string;
|
||||
};
|
||||
abortReason?: string;
|
||||
req: Request;
|
||||
cookies: Record<string, string>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
import { type Request, type Response, Router } from "express";
|
||||
import { getFileExt } from "~/lib/utils";
|
||||
import db from "~/server/db";
|
||||
import { file } from "~/server/db/schema/file";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { serveHtml } from "./serve-html";
|
||||
import { Mime } from "mime/lite";
|
||||
import standardTypes from "mime/types/standard.js";
|
||||
import otherTypes from "mime/types/other.js";
|
||||
import { serveJs } from "./serve-js";
|
||||
import { type Request, type Response, Router } from "express";
|
||||
|
||||
const mime = new Mime(standardTypes, otherTypes);
|
||||
mime.define({ "text/javascript": ["jsx", "tsx"] }, true);
|
||||
import { getMimeType } from "~/server/lib/mime";
|
||||
import { postcss } from "./postcss";
|
||||
|
||||
const get = async (req: Request, res: Response) => {
|
||||
const { slug, ...pathParams } = req.params as any;
|
||||
@ -35,10 +31,11 @@ const get = async (req: Request, res: Response) => {
|
||||
content = await serveJs(fileData);
|
||||
}
|
||||
|
||||
res.setHeader(
|
||||
"Content-Type",
|
||||
mime.getType(fileData.filename) || "application/octet-stream"
|
||||
);
|
||||
if (["css"].includes(ext)) {
|
||||
content = await postcss(fileData);
|
||||
}
|
||||
|
||||
res.setHeader("Content-Type", getMimeType(fileData.filename));
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
||||
|
34
server/api/preview/postcss.ts
Normal file
34
server/api/preview/postcss.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import postcssPlugin from "postcss";
|
||||
import tailwindcss from "tailwindcss";
|
||||
import cssnano from "cssnano";
|
||||
import { fileExists, getProjectDir } from "~/server/lib/utils";
|
||||
import { FileSchema } from "~/server/db/schema/file";
|
||||
import { unpackProject } from "~/server/lib/unpack-project";
|
||||
|
||||
export const postcss = async (fileData: FileSchema) => {
|
||||
const content = fileData.content || "";
|
||||
|
||||
const projectDir = getProjectDir();
|
||||
if (!fileExists(projectDir)) {
|
||||
return content;
|
||||
}
|
||||
|
||||
try {
|
||||
await unpackProject({ ext: "ts,tsx,js,jsx,html" });
|
||||
|
||||
const result = await postcssPlugin([
|
||||
tailwindcss({
|
||||
content: [projectDir + "/**/*.{ts,tsx,js,jsx,html}"],
|
||||
}),
|
||||
cssnano({
|
||||
preset: ["default", { discardComments: { removeAll: true } }],
|
||||
}),
|
||||
]).process(content, {
|
||||
from: undefined,
|
||||
});
|
||||
|
||||
return result.css;
|
||||
} catch (err) {
|
||||
return content;
|
||||
}
|
||||
};
|
@ -2,6 +2,8 @@ import db from "~/server/db";
|
||||
import { FileSchema, file } from "~/server/db/schema/file";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
|
||||
const preventHtmlDirectAccess = `<script>if (window === window.parent) {window.location.href = '/';}</script>`;
|
||||
|
||||
export const serveHtml = async (fileData: FileSchema) => {
|
||||
const layout = await db.query.file.findFirst({
|
||||
where: and(
|
||||
@ -14,15 +16,16 @@ export const serveHtml = async (fileData: FileSchema) => {
|
||||
});
|
||||
|
||||
let content = fileData.content || "";
|
||||
if (!layout?.content) {
|
||||
return content;
|
||||
if (layout?.content != null) {
|
||||
content = layout.content.replace("{CONTENT}", content);
|
||||
}
|
||||
|
||||
content = layout.content.replace("{CONTENT}", content);
|
||||
|
||||
const bodyOpeningTagIdx = content.indexOf("<body");
|
||||
const firstScriptTagIdx = content.indexOf("<script", bodyOpeningTagIdx);
|
||||
const injectScripts = ['<script src="/js/hook-console.js"></script>'];
|
||||
const injectScripts = [
|
||||
'<script src="/js/hook-console.js"></script>',
|
||||
preventHtmlDirectAccess,
|
||||
];
|
||||
|
||||
const importMaps = [
|
||||
{ name: "react", url: "https://esm.sh/react@18.2.0" },
|
||||
@ -45,7 +48,5 @@ export const serveHtml = async (fileData: FileSchema) => {
|
||||
content.substring(firstScriptTagIdx);
|
||||
}
|
||||
|
||||
// content = content.replace(/ {2}|\r\n|\n|\r/gm, "");
|
||||
|
||||
return content;
|
||||
};
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { CreateExpressContextOptions } from "@trpc/server/adapters/express";
|
||||
import { Request } from "express";
|
||||
|
||||
export const createContext = async ({
|
||||
req,
|
||||
res,
|
||||
}: CreateExpressContextOptions) => {
|
||||
export const createContext = async ({ req }: { req: Request }) => {
|
||||
return {};
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { createContext } from "./context";
|
||||
import { appRouter } from "../../routers/_app";
|
||||
import { createCallerFactory } from ".";
|
||||
import { PageContext } from "vike/types";
|
||||
|
||||
const trpcServer = createCallerFactory(appRouter)(createContext);
|
||||
const trpcServer = async (ctx: PageContext) => {
|
||||
const createCaller = createCallerFactory(appRouter);
|
||||
const context = await createContext({ req: ctx.req });
|
||||
return createCaller(context);
|
||||
};
|
||||
|
||||
export default trpcServer;
|
||||
|
@ -12,6 +12,52 @@ const main = async () => {
|
||||
})
|
||||
.returning();
|
||||
|
||||
// await db
|
||||
// .insert(file)
|
||||
// .values([
|
||||
// {
|
||||
// userId: adminUser.id,
|
||||
// path: "index.html",
|
||||
// filename: "index.html",
|
||||
// content: '<p class="text-lg text-red-500">Hello world!</p>',
|
||||
// },
|
||||
// {
|
||||
// userId: adminUser.id,
|
||||
// path: "styles.css",
|
||||
// filename: "styles.css",
|
||||
// content: "body { padding: 16px; }",
|
||||
// },
|
||||
// {
|
||||
// userId: adminUser.id,
|
||||
// path: "script.js",
|
||||
// filename: "script.js",
|
||||
// content: "console.log('hello world!');",
|
||||
// },
|
||||
// {
|
||||
// userId: adminUser.id,
|
||||
// path: "_layout.html",
|
||||
// filename: "_layout.html",
|
||||
// content: `<!DOCTYPE html>
|
||||
// <html lang="en">
|
||||
// <head>
|
||||
// <meta charset="UTF-8">
|
||||
// <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
// <title>Document</title>
|
||||
|
||||
// <link rel="stylesheet" href="styles.css">
|
||||
|
||||
// <script src="https://cdn.tailwindcss.com"></script>
|
||||
// </head>
|
||||
// <body>
|
||||
// {CONTENT}
|
||||
// <script src="script.js" type="module" defer></script>
|
||||
// </body>
|
||||
// </html>`,
|
||||
// },
|
||||
// ])
|
||||
// .execute();
|
||||
|
||||
// react template
|
||||
await db
|
||||
.insert(file)
|
||||
.values([
|
||||
@ -19,40 +65,69 @@ const main = async () => {
|
||||
userId: adminUser.id,
|
||||
path: "index.html",
|
||||
filename: "index.html",
|
||||
content: '<p class="text-lg text-red-500">Hello world!</p>',
|
||||
content: `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0"
|
||||
/>
|
||||
<title>React + Tailwind Template</title>
|
||||
<link rel="stylesheet" href="globals.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="index.jsx" type="module" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
{
|
||||
userId: adminUser.id,
|
||||
path: "styles.css",
|
||||
filename: "styles.css",
|
||||
content: "body { padding: 16px; }",
|
||||
},
|
||||
{
|
||||
userId: adminUser.id,
|
||||
path: "script.js",
|
||||
filename: "script.js",
|
||||
content: "console.log('hello world!');",
|
||||
},
|
||||
{
|
||||
userId: adminUser.id,
|
||||
path: "_layout.html",
|
||||
filename: "_layout.html",
|
||||
content: `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
path: "globals.css",
|
||||
filename: "globals.css",
|
||||
content: `@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
body {
|
||||
@apply p-4;
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
userId: adminUser.id,
|
||||
path: "index.jsx",
|
||||
filename: "index.jsx",
|
||||
content: `import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.jsx";
|
||||
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body>
|
||||
{CONTENT}
|
||||
<script src="script.js" type="module" defer></script>
|
||||
</body>
|
||||
</html>`,
|
||||
const root = createRoot(document.getElementById("app"));
|
||||
root.render(<App />);
|
||||
`,
|
||||
},
|
||||
{
|
||||
userId: adminUser.id,
|
||||
path: "App.jsx",
|
||||
filename: "App.jsx",
|
||||
isPinned: true,
|
||||
content: `import React from "react";
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1 class="text-xl font-medium text-blue-500">
|
||||
React + Tailwind Template!
|
||||
</h1>
|
||||
<p>Open App.jsx to edit this text.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
},
|
||||
])
|
||||
.execute();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import express from "express";
|
||||
import { renderPage } from "vike/server";
|
||||
import { IS_DEV } from "./lib/consts";
|
||||
import cookieParser from "cookie-parser";
|
||||
import api from "./api";
|
||||
|
||||
async function createServer() {
|
||||
@ -22,11 +23,13 @@ async function createServer() {
|
||||
app.use(express.static(root + "/dist/client"));
|
||||
}
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use("/api", api);
|
||||
|
||||
app.use("*", async (req, res, next) => {
|
||||
const url = req.originalUrl;
|
||||
const pageContext = {};
|
||||
const pageContext = { req, cookies: req.cookies };
|
||||
const ctx = await renderPage({ urlOriginal: url, ...pageContext });
|
||||
|
||||
const { httpResponse } = ctx;
|
||||
|
11
server/lib/mime.ts
Normal file
11
server/lib/mime.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Mime } from "mime/lite";
|
||||
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);
|
||||
|
||||
export const getMimeType = (
|
||||
ext: string,
|
||||
defaultMime: string = "application/octet-stream"
|
||||
) => mime.getType(ext) || defaultMime;
|
50
server/lib/unpack-project.ts
Normal file
50
server/lib/unpack-project.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import db from "../db";
|
||||
import { file } from "../db/schema/file";
|
||||
import { fileExists, getProjectDir } from "./utils";
|
||||
import { getFileExt } from "~/lib/utils";
|
||||
|
||||
type UnpackProjectOptions = {
|
||||
ext: string;
|
||||
};
|
||||
|
||||
export const unpackProject = async (
|
||||
opt: Partial<UnpackProjectOptions> = {}
|
||||
) => {
|
||||
const files = await db.query.file.findMany({
|
||||
where: and(
|
||||
eq(file.isDirectory, false),
|
||||
eq(file.isFile, false),
|
||||
isNull(file.deletedAt)
|
||||
),
|
||||
});
|
||||
|
||||
const projectDir = getProjectDir();
|
||||
if (!fileExists(projectDir)) {
|
||||
await fs.mkdir(projectDir, { recursive: true });
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
const ext = getFileExt(file.filename);
|
||||
|
||||
// skip file if not in included extension list
|
||||
if (opt.ext && opt.ext.length > 0 && !opt.ext.split(",").includes(ext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const fpath = path.resolve(
|
||||
projectDir,
|
||||
file.path.replace(/(\.{2})(\/+)/g, "")
|
||||
);
|
||||
const dir = path.dirname(fpath);
|
||||
if (!fileExists(dir)) {
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
}
|
||||
|
||||
await fs.writeFile(fpath, file.content || "");
|
||||
}
|
||||
|
||||
return projectDir;
|
||||
};
|
15
server/lib/utils.ts
Normal file
15
server/lib/utils.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
export const fileExists = (path: string) => {
|
||||
try {
|
||||
fs.accessSync(path, fs.constants.F_OK);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getProjectDir = () => {
|
||||
return path.resolve(process.cwd(), "storage/tmp/project1");
|
||||
};
|
@ -21,7 +21,7 @@ const fileRouter = router({
|
||||
opt?.isPinned ? eq(file.isPinned, true) : undefined
|
||||
),
|
||||
orderBy: [desc(file.isDirectory), asc(file.filename)],
|
||||
columns: { content: false },
|
||||
columns: !file.isPinned ? { content: true } : undefined,
|
||||
});
|
||||
|
||||
return files;
|
||||
|
@ -9,6 +9,11 @@ const config = {
|
||||
"~": path.resolve("./"),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
watch: {
|
||||
ignored: [path.resolve(__dirname, "storage/**")],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
Loading…
x
Reference in New Issue
Block a user