mirror of
https://github.com/Nezumi-2711/next-gdrive-index.git
synced 2026-09-22 13:38:38 +00:00
v2.4.2
v2.4.2
This commit is contained in:
+7
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "next-gdrive-index",
|
"name": "next-gdrive-index",
|
||||||
"version": "2.0.4",
|
"version": "2.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"lint:fix": "next lint --fix",
|
"lint:fix": "next lint --fix",
|
||||||
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json}\" --cache",
|
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json}\" --cache",
|
||||||
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json}\" --cache"
|
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json}\" --cache",
|
||||||
|
"cli": "node ./scripts/cli.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.10.0",
|
"@hookform/resolvers": "^3.10.0",
|
||||||
@@ -88,12 +89,16 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
||||||
"@typescript-eslint/parser": "^8.1.0",
|
"@typescript-eslint/parser": "^8.1.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
|
"chalk": "^5.4.1",
|
||||||
|
"commander": "^13.1.0",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-next": "^15.0.1",
|
"eslint-config-next": "^15.0.1",
|
||||||
|
"ora": "^8.2.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"prettier": "3.0.0",
|
"prettier": "3.0.0",
|
||||||
"prettier-plugin-tailwindcss": "0.5.12",
|
"prettier-plugin-tailwindcss": "0.5.12",
|
||||||
|
"prompts": "^2.4.2",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5.5.3"
|
"typescript": "^5.5.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
import { encryptionService } from "~/lib/utils.server";
|
||||||
|
|
||||||
|
import config from "~/config/gIndex.config";
|
||||||
|
|
||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
if (process.env.NODE_ENV !== "development") {
|
||||||
|
throw new Error("This route is only available in development environment");
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootId = await encryptionService.decrypt(config.apiConfig.rootFolder);
|
||||||
|
const sharedDriveId = config.apiConfig.sharedDrive
|
||||||
|
? await encryptionService.decrypt(config.apiConfig.sharedDrive)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
rootId,
|
||||||
|
sharedDriveId,
|
||||||
|
},
|
||||||
|
{ status: 200 },
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
const e = error as Error;
|
||||||
|
console.error(e);
|
||||||
|
return new Response(e.message, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import { type NextRequest, NextResponse } from "next/server";
|
|
||||||
import stream from "stream";
|
|
||||||
import { promisify } from "util";
|
|
||||||
|
|
||||||
import { gdrive } from "~/lib/utils.server";
|
|
||||||
|
|
||||||
const pipeline = promisify(stream.pipeline);
|
|
||||||
const fileId = "1KvMU9sy8fQKKmVKU5xf_u3Y2JZefe0kt";
|
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const start = Date.now();
|
|
||||||
console.log("Fetching metadata", Date.now() - start);
|
|
||||||
const meta = await gdrive.files.get({
|
|
||||||
fileId,
|
|
||||||
fields: "size,mimeType,name",
|
|
||||||
supportsAllDrives: true,
|
|
||||||
});
|
|
||||||
const { data: metadata } = meta;
|
|
||||||
|
|
||||||
console.log("Fetching file", Date.now() - start);
|
|
||||||
// const data = await gdrive.files.get(
|
|
||||||
// {
|
|
||||||
// fileId: fileId,
|
|
||||||
// alt: "media",
|
|
||||||
// acknowledgeAbuse: true,
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// responseType: "stream",
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
|
|
||||||
console.log("Setting headers", Date.now() - start);
|
|
||||||
const headers = new Headers();
|
|
||||||
headers.set("Content-Type", metadata.mimeType ?? "application/octet-stream");
|
|
||||||
if (metadata.size) headers.set("Content-Length", metadata.size.toString());
|
|
||||||
headers.set("Content-Disposition", `attachment; filename="${metadata.name}"`);
|
|
||||||
|
|
||||||
// console.log("Streaming file", Date.now() - start);
|
|
||||||
// const contentStream = data.data;
|
|
||||||
// const webStream = new ReadableStream({
|
|
||||||
// async start(controller) {
|
|
||||||
// contentStream.on("data", (chunk) => {
|
|
||||||
// controller.enqueue(chunk);
|
|
||||||
// });
|
|
||||||
// contentStream.on("end", () => {
|
|
||||||
// controller.close();
|
|
||||||
// });
|
|
||||||
// contentStream.on("error", (err) => {
|
|
||||||
// console.error(err);
|
|
||||||
// controller.error(err);
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// cancel() {
|
|
||||||
// contentStream.destroy();
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// console.log("Returning response", Date.now() - start);
|
|
||||||
return new Response(
|
|
||||||
new ReadableStream({
|
|
||||||
async start(controller) {
|
|
||||||
try {
|
|
||||||
gdrive.files.get(
|
|
||||||
{
|
|
||||||
fileId: fileId,
|
|
||||||
alt: "media",
|
|
||||||
acknowledgeAbuse: true,
|
|
||||||
supportsAllDrives: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
responseType: "stream",
|
|
||||||
},
|
|
||||||
(err, res) => {
|
|
||||||
if (err) throw err;
|
|
||||||
res?.data
|
|
||||||
.on("data", (chunk) => {
|
|
||||||
controller.enqueue(chunk);
|
|
||||||
})
|
|
||||||
.on("end", () => {
|
|
||||||
controller.close();
|
|
||||||
})
|
|
||||||
.on("error", (err) => {
|
|
||||||
console.error(err);
|
|
||||||
controller.error(err);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
controller.error(error);
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
headers,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
const e = error as Error;
|
|
||||||
console.error(e);
|
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
error: e.message,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 500,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -906,6 +906,7 @@ function FooterField({ form, onResetField }: FormProps) {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setContent(formatFooterContent(form.watch("site.footer"), form.getValues("site")));
|
setContent(formatFooterContent(form.watch("site.footer"), form.getValues("site")));
|
||||||
}}
|
}}
|
||||||
|
type='button'
|
||||||
>
|
>
|
||||||
Reload Preview
|
Reload Preview
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ export default function Navbar() {
|
|||||||
className='mx-2 my-auto h-6'
|
className='mx-2 my-auto h-6'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!!config.showGuideButton && (
|
{!!config.showGuideButton ? (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -291,6 +291,8 @@ export default function Navbar() {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import "@vidstack/react/player/styles/default/layouts/audio.css";
|
|||||||
import "@vidstack/react/player/styles/default/layouts/video.css";
|
import "@vidstack/react/player/styles/default/layouts/video.css";
|
||||||
import "@vidstack/react/player/styles/default/theme.css";
|
import "@vidstack/react/player/styles/default/theme.css";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { useCallback, useRef, useState } from "react";
|
import { useCallback, useRef, useState } from "react";
|
||||||
import { type z } from "zod";
|
import { type z } from "zod";
|
||||||
|
|
||||||
@@ -28,7 +29,8 @@ import { PageLoader } from "~/components/layout";
|
|||||||
import Icon from "~/components/ui/icon";
|
import Icon from "~/components/ui/icon";
|
||||||
|
|
||||||
import useLoading from "~/hooks/useLoading";
|
import useLoading from "~/hooks/useLoading";
|
||||||
import { MediaPlayerIcons } from "~/lib/previewHelper";
|
import { MediaPlayerIcons, getPreviewIcon } from "~/lib/previewHelper";
|
||||||
|
import { cn, formatDate } from "~/lib/utils";
|
||||||
|
|
||||||
import { type Schema_File } from "~/types/schema";
|
import { type Schema_File } from "~/types/schema";
|
||||||
|
|
||||||
@@ -37,8 +39,9 @@ import "~/styles/vidstack.css";
|
|||||||
type Props = {
|
type Props = {
|
||||||
file: z.infer<typeof Schema_File>;
|
file: z.infer<typeof Schema_File>;
|
||||||
type: "video" | "audio";
|
type: "video" | "audio";
|
||||||
|
playlist: z.infer<typeof Schema_File>[];
|
||||||
};
|
};
|
||||||
export default function PreviewMedia({ file, type }: Props) {
|
export default function PreviewMedia({ file, type, playlist }: Props) {
|
||||||
const player = useRef<MediaPlayerInstance>(null);
|
const player = useRef<MediaPlayerInstance>(null);
|
||||||
const [canPlay, setCanPlay] = useState<boolean>(false);
|
const [canPlay, setCanPlay] = useState<boolean>(false);
|
||||||
|
|
||||||
@@ -85,7 +88,7 @@ export default function PreviewMedia({ file, type }: Props) {
|
|||||||
seekBackwardButton: null,
|
seekBackwardButton: null,
|
||||||
seekForwardButton: null,
|
seekForwardButton: null,
|
||||||
playButton: (
|
playButton: (
|
||||||
<div className='flex w-full items-center justify-center gap-2 md:w-fit'>
|
<div className='flex w-full items-center justify-center gap-1 md:w-fit'>
|
||||||
<SeekButton
|
<SeekButton
|
||||||
className='vds-button'
|
className='vds-button'
|
||||||
seconds={-10}
|
seconds={-10}
|
||||||
@@ -93,7 +96,7 @@ export default function PreviewMedia({ file, type }: Props) {
|
|||||||
<MediaPlayerIcons.SeekButton.Backward />
|
<MediaPlayerIcons.SeekButton.Backward />
|
||||||
</SeekButton>
|
</SeekButton>
|
||||||
<PlayButton
|
<PlayButton
|
||||||
className='vds-button vds-play-button'
|
className='vds-button vds-play-button aspect-square'
|
||||||
disabled={canPlay === false}
|
disabled={canPlay === false}
|
||||||
>
|
>
|
||||||
{canPlay ? (
|
{canPlay ? (
|
||||||
@@ -144,6 +147,12 @@ export default function PreviewMedia({ file, type }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
|
<PlaylistMenu
|
||||||
|
playlist={playlist}
|
||||||
|
file={file}
|
||||||
|
placement={"bottom end"}
|
||||||
|
/>
|
||||||
|
|
||||||
<Menu.Root className='vds-menu'>
|
<Menu.Root className='vds-menu'>
|
||||||
<Menu.Button
|
<Menu.Button
|
||||||
className='vds-menu-button vds-button'
|
className='vds-menu-button vds-button'
|
||||||
@@ -216,7 +225,7 @@ export default function PreviewMedia({ file, type }: Props) {
|
|||||||
icons={MediaPlayerIcons}
|
icons={MediaPlayerIcons}
|
||||||
colorScheme='default'
|
colorScheme='default'
|
||||||
smallLayoutWhen={smallVideoLayoutQuery}
|
smallLayoutWhen={smallVideoLayoutQuery}
|
||||||
showTooltipDelay={150}
|
showTooltipDelay={200}
|
||||||
slots={{
|
slots={{
|
||||||
currentTime: (
|
currentTime: (
|
||||||
<Time
|
<Time
|
||||||
@@ -230,7 +239,14 @@ export default function PreviewMedia({ file, type }: Props) {
|
|||||||
type='duration'
|
type='duration'
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
beforeSettingsMenu: (
|
||||||
|
<PlaylistMenu
|
||||||
|
playlist={playlist}
|
||||||
|
file={file}
|
||||||
|
/>
|
||||||
|
),
|
||||||
settingsMenu: (
|
settingsMenu: (
|
||||||
|
<>
|
||||||
<Menu.Root className='vds-menu'>
|
<Menu.Root className='vds-menu'>
|
||||||
<Menu.Button
|
<Menu.Button
|
||||||
className='vds-menu-button vds-button'
|
className='vds-menu-button vds-button'
|
||||||
@@ -293,6 +309,7 @@ export default function PreviewMedia({ file, type }: Props) {
|
|||||||
<AudioGain />
|
<AudioGain />
|
||||||
</Menu.Items>
|
</Menu.Items>
|
||||||
</Menu.Root>
|
</Menu.Root>
|
||||||
|
</>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -392,3 +409,87 @@ function AudioGain() {
|
|||||||
</Menu.Root>
|
</Menu.Root>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function PlaylistMenu({
|
||||||
|
playlist,
|
||||||
|
file,
|
||||||
|
placement = "top end",
|
||||||
|
}: {
|
||||||
|
playlist: z.infer<typeof Schema_File>[];
|
||||||
|
file: z.infer<typeof Schema_File>;
|
||||||
|
placement?: Menu.ItemsProps["placement"];
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Menu.Root className='vds-menu'>
|
||||||
|
<Menu.Button
|
||||||
|
className='vds-menu-button vds-button'
|
||||||
|
aria-label='Playlist'
|
||||||
|
>
|
||||||
|
<MediaPlayerIcons.Menu.Chapters />
|
||||||
|
</Menu.Button>
|
||||||
|
<Menu.Items
|
||||||
|
className='vds-menu-items group space-y-1'
|
||||||
|
placement={placement}
|
||||||
|
>
|
||||||
|
{playlist.map((item) => {
|
||||||
|
const isCurrent = `${item.name}#${item.size}` === `${file.name}#${file.size}`;
|
||||||
|
|
||||||
|
const Wrapper = ({ children, className }: React.PropsWithChildren<{ className?: string }>) =>
|
||||||
|
isCurrent ? (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
title={item.name}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Link
|
||||||
|
href={`${item.name}`}
|
||||||
|
className={className}
|
||||||
|
title={item.name}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
key={`playlist-${item.encryptedId}`}
|
||||||
|
className={cn(
|
||||||
|
"flex w-full max-w-96 grid-cols-4 place-items-center gap-2 rounded-lg",
|
||||||
|
isCurrent ? "bg-primary/10" : "hover:bg-primary/5",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{/* Thumbnail */}
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"aspect-video h-16 grow-0 overflow-hidden rounded-lg bg-black",
|
||||||
|
isCurrent && "border border-primary",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{item.mimeType.includes("video") ? (
|
||||||
|
<img
|
||||||
|
src={`/api/thumb/${item.encryptedId}`}
|
||||||
|
alt={`Thumbnail for ${item.name}`}
|
||||||
|
className='aspect-video w-full object-contain'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className={"grid aspect-video w-full place-items-center"}>
|
||||||
|
<Icon
|
||||||
|
name={getPreviewIcon(item.fileExtension ?? "", item.mimeType)}
|
||||||
|
className={"size-6"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"col-span-3 w-full flex-1 p-2"}>
|
||||||
|
<p className={"line-clamp-1 break-all"}>{item.name}</p>
|
||||||
|
<span className={"text-sm text-muted-foreground"}>{formatDate(item.modifiedTime)}</span>
|
||||||
|
</div>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
PreviewUnknown,
|
PreviewUnknown,
|
||||||
} from "~/components/preview";
|
} from "~/components/preview";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "~/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||||
|
|
||||||
import { type getFileType } from "~/lib/previewHelper";
|
import { type getFileType } from "~/lib/previewHelper";
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from "~/lib/utils";
|
||||||
@@ -23,8 +23,6 @@ import { type Schema_File } from "~/types/schema";
|
|||||||
|
|
||||||
import config from "config";
|
import config from "config";
|
||||||
|
|
||||||
import MediaPlaylistLayout from "./MediaPlaylistLayout";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: z.infer<typeof Schema_File>;
|
data: z.infer<typeof Schema_File>;
|
||||||
fileType: "unknown" | ReturnType<typeof getFileType>;
|
fileType: "unknown" | ReturnType<typeof getFileType>;
|
||||||
@@ -32,7 +30,7 @@ type Props = {
|
|||||||
playlist: z.infer<typeof Schema_File>[];
|
playlist: z.infer<typeof Schema_File>[];
|
||||||
paths: string[];
|
paths: string[];
|
||||||
};
|
};
|
||||||
export default function PreviewLayout({ data, paths, fileType, token, playlist }: Props) {
|
export default function PreviewLayout({ data, fileType, token, playlist }: Props) {
|
||||||
const [view, setView] = useState<"markdown" | "raw">("markdown");
|
const [view, setView] = useState<"markdown" | "raw">("markdown");
|
||||||
const PreviewComponent = useMemo(() => {
|
const PreviewComponent = useMemo(() => {
|
||||||
switch (fileType) {
|
switch (fileType) {
|
||||||
@@ -44,6 +42,7 @@ export default function PreviewLayout({ data, paths, fileType, token, playlist }
|
|||||||
<PreviewMedia
|
<PreviewMedia
|
||||||
file={data}
|
file={data}
|
||||||
type={fileType}
|
type={fileType}
|
||||||
|
playlist={playlist}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "code":
|
case "code":
|
||||||
@@ -82,7 +81,7 @@ export default function PreviewLayout({ data, paths, fileType, token, playlist }
|
|||||||
default:
|
default:
|
||||||
return <PreviewUnknown />;
|
return <PreviewUnknown />;
|
||||||
}
|
}
|
||||||
}, [fileType, data, view, token]);
|
}, [fileType, data, view, token, playlist]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -134,14 +133,14 @@ export default function PreviewLayout({ data, paths, fileType, token, playlist }
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
||||||
<CardFooter>
|
{/* <CardFooter>
|
||||||
<MediaPlaylistLayout
|
<MediaPlaylistLayout
|
||||||
type={"inside"}
|
type={"inside"}
|
||||||
paths={paths}
|
paths={paths}
|
||||||
currentItem={data}
|
currentItem={data}
|
||||||
playlist={playlist}
|
playlist={playlist}
|
||||||
/>
|
/>
|
||||||
</CardFooter>
|
</CardFooter> */}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<PreviewInformation
|
<PreviewInformation
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const config: z.input<typeof Schema_Config> = {
|
|||||||
* If possible, please don't change this value
|
* If possible, please don't change this value
|
||||||
* Even if you're creating a PR, just let me change it myself
|
* Even if you're creating a PR, just let me change it myself
|
||||||
*/
|
*/
|
||||||
version: "2.0.4",
|
version: "2.4.2",
|
||||||
/**
|
/**
|
||||||
* Base path of the app, used for generating links
|
* Base path of the app, used for generating links
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import config from "~/config/gIndex.config";
|
|||||||
export const versionExpectMap: Record<"v1" | "v2" | "latest", string[]> = {
|
export const versionExpectMap: Record<"v1" | "v2" | "latest", string[]> = {
|
||||||
v1: ["1.0.0", "1.0.1", "1.0.2", "1.0.3"],
|
v1: ["1.0.0", "1.0.1", "1.0.2", "1.0.3"],
|
||||||
v2: ["2.0.0", "2.0.1", "2.0.2", "2.0.3"],
|
v2: ["2.0.0", "2.0.1", "2.0.2", "2.0.3"],
|
||||||
latest: ["2.0.4"],
|
latest: ["2.0.4", "2.4.0", "2.4.1", "2.4.2"],
|
||||||
};
|
};
|
||||||
export type PickFileResponse =
|
export type PickFileResponse =
|
||||||
| {
|
| {
|
||||||
@@ -166,7 +166,7 @@ export const initialConfiguration: z.input<typeof Schema_App_Configuration> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const configurationTemplate = `import { type z } from "zod";
|
export const configurationTemplate = `import { type z } from "zod";
|
||||||
import { BASE_URL } from "~/constant";
|
import { BASE_URL, IS_DEV } from "~/constant";
|
||||||
|
|
||||||
import { type Schema_Config } from "~/types/schema";
|
import { type Schema_Config } from "~/types/schema";
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ const config: z.input<typeof Schema_Config> = {
|
|||||||
* @default process.env.NEXT_PUBLIC_DOMAIN
|
* @default process.env.NEXT_PUBLIC_DOMAIN
|
||||||
* @fallback process.env.NEXT_PUBLIC_VERCEL_URL
|
* @fallback process.env.NEXT_PUBLIC_VERCEL_URL
|
||||||
*/
|
*/
|
||||||
basePath: \`https://\${BASE_URL}\`,
|
basePath: IS_DEV ? "http://localhost:3000" : \`https://\${BASE_URL}\`,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show deploy guide dropdown on navbar
|
* Show deploy guide dropdown on navbar
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ export const MediaPlayerIcons = {
|
|||||||
Chapters: () => (
|
Chapters: () => (
|
||||||
<Icon
|
<Icon
|
||||||
hideWrapper
|
hideWrapper
|
||||||
name='TableOfContents'
|
name='List'
|
||||||
className='vds-icon size-5'
|
className='vds-icon size-5'
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
+1
-1
@@ -112,7 +112,7 @@ const Schema_Config_API = z
|
|||||||
|
|
||||||
allowDownloadProtectedFile: z.coerce.boolean(),
|
allowDownloadProtectedFile: z.coerce.boolean(),
|
||||||
temporaryTokenDuration: z.coerce.number().positive(),
|
temporaryTokenDuration: z.coerce.number().positive(),
|
||||||
maxFileSize: z.coerce.number().positive(),
|
maxFileSize: z.coerce.number(),
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user