implement mods functionality and add meta data #3
15 changed files with 370 additions and 202 deletions
7
.env
7
.env
|
@ -1,2 +1,5 @@
|
|||
USERNAME="Svr_admin"
|
||||
PASSWORD="YP6t1kV6rmviuQG"
|
||||
ADMIN_USERNAME=Svr_admin
|
||||
ADMIN_PASSWORD=temppass
|
||||
MONGODB_URI=mongodb+srv://euler:0f61VcV5UWozRWxp@learning-mongo.jcsdeht.mongodb.net/node-tuts
|
||||
UPLOADTHING_SECRET=sk_live_0c456ce4a8366c64660dbf057bf8dd8bbe9db3d4bf7a70766855c04c09ba0aa9
|
||||
UPLOADTHING_APP_ID=6no1s7ob1p
|
||||
|
|
123
app/(auth)/admin/mods/page.tsx
Normal file
123
app/(auth)/admin/mods/page.tsx
Normal file
|
@ -0,0 +1,123 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { useForm, SubmitHandler } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { UploadButton, UploadDropzone } from '@/lib/uploadthing';
|
||||
import { modsSchema } from '@/lib/validations/validation';
|
||||
|
||||
const AdminPage = () => {
|
||||
const form = useForm<z.infer<typeof modsSchema>>({
|
||||
resolver: zodResolver(modsSchema),
|
||||
});
|
||||
|
||||
const onSubmit: SubmitHandler<z.infer<typeof modsSchema>> = async (data) => {
|
||||
const response = await fetch('/api/uploadmods', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
form.reset();
|
||||
console.log('Upload successful');
|
||||
alert('Uploaded');
|
||||
} else {
|
||||
console.error('Upload failed');
|
||||
alert('Upload Failed');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="admin-page" className="wrapper container">
|
||||
<h1 className="text-3xl font-bold py-6">Admin Upload Section</h1>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="fileName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>File Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="version"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Version</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="downloadLink"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Download Link</FormLabel>
|
||||
<UploadButton
|
||||
endpoint="imageUploader"
|
||||
onClientUploadComplete={(res) => {
|
||||
field.onChange(res[0].url);
|
||||
}}
|
||||
onUploadError={(error: Error) => {
|
||||
alert(`ERROR! ${error.message}`);
|
||||
}}
|
||||
/>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="fileSize"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>File Size</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full text-lg rounded-full"
|
||||
size={'lg'}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default AdminPage;
|
|
@ -1,7 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
const AddDownload = () => {
|
||||
return <div>Welcome to downloads</div>;
|
||||
};
|
||||
|
||||
export default AddDownload;
|
|
@ -1,4 +1,9 @@
|
|||
import React from "react";
|
||||
import React from 'react';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Blog - SVRJS',
|
||||
};
|
||||
|
||||
const BlogPage = () => {
|
||||
return <div>BlogPage</div>;
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import Sidebar from '@/components/shared/Sidebar';
|
||||
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Docs - SVRJS',
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
|
|
11
app/(root)/downloads/layout.tsx
Normal file
11
app/(root)/downloads/layout.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Downloads - SVRJS',
|
||||
};
|
||||
|
||||
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <main>{children}</main>;
|
||||
};
|
||||
|
||||
export default ModLayout;
|
|
@ -1,4 +1,9 @@
|
|||
import React from "react";
|
||||
import React from 'react';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Forum - SVRJS',
|
||||
};
|
||||
|
||||
const Forum = () => {
|
||||
return <div>Forum</div>;
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
import Footer from "@/components/shared/Footer";
|
||||
import Navbar from "@/components/shared/Navbar";
|
||||
import Footer from '@/components/shared/Footer';
|
||||
import Navbar from '@/components/shared/Navbar';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Home - SVRJS',
|
||||
};
|
||||
|
||||
export default function PageLayout({
|
||||
children,
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<main className="flex flex-col min-h-screen">
|
||||
<Navbar />
|
||||
<div className="flex-grow flex-1">{children}</div>
|
||||
<Footer />
|
||||
</main>
|
||||
);
|
||||
return (
|
||||
<main className="flex flex-col min-h-screen">
|
||||
<Navbar />
|
||||
<div className="flex-grow flex-1">{children}</div>
|
||||
<Footer />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
'use client';
|
||||
import React, { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
const Login = () => {
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const router = useRouter();
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const res = await fetch('/api/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
router.push('/add-download');
|
||||
} else {
|
||||
alert(res.status);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<label>Username:</label>
|
||||
<input
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUsername(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label>Password:</label>
|
||||
<input
|
||||
type="text"
|
||||
value={password}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPassword(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
11
app/(root)/mods/layout.tsx
Normal file
11
app/(root)/mods/layout.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'MOD - SVRJS',
|
||||
};
|
||||
|
||||
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
return <main>{children}</main>;
|
||||
};
|
||||
|
||||
export default ModLayout;
|
|
@ -1,4 +1,7 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
@ -7,53 +10,61 @@ import {
|
|||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Download } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
} from '@/components/ui/table';
|
||||
import { Download } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
const downloads = [
|
||||
{
|
||||
date: "2024-06-01",
|
||||
fileName: "SVRJS_v1.0.0.zip",
|
||||
version: "1.0.0",
|
||||
fileSize: "15MB",
|
||||
downloadLink: "/downloads/SVRJS_v1.0.0.zip",
|
||||
},
|
||||
{
|
||||
date: "2024-06-10",
|
||||
fileName: "SVRJS_v1.1.0.zip",
|
||||
version: "1.1.0",
|
||||
fileSize: "18MB",
|
||||
downloadLink: "/downloads/SVRJS_v1.1.0.zip",
|
||||
},
|
||||
{
|
||||
date: "2024-06-15",
|
||||
fileName: "SVRJS_v1.2.0.zip",
|
||||
version: "1.2.0",
|
||||
fileSize: "20MB",
|
||||
downloadLink: "/downloads/SVRJS_v1.2.0.zip",
|
||||
},
|
||||
{
|
||||
date: "2024-06-20",
|
||||
fileName: "SVRJS_v1.3.0.zip",
|
||||
version: "1.3.0",
|
||||
fileSize: "22MB",
|
||||
downloadLink: "/downloads/SVRJS_v1.3.0.zip",
|
||||
},
|
||||
];
|
||||
interface Download {
|
||||
_id: string;
|
||||
date: string;
|
||||
fileName: string;
|
||||
version: string;
|
||||
fileSize: string;
|
||||
downloadLink: string;
|
||||
}
|
||||
|
||||
const DownloadPage: React.FC = () => {
|
||||
const [downloads, setDownloads] = useState<Download[]>([]);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const fetchDownloads = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/mods', {
|
||||
method: 'GET',
|
||||
});
|
||||
if (response.ok) {
|
||||
const data: Download[] = await response.json();
|
||||
setDownloads(data);
|
||||
} else {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
} catch (error: any) {
|
||||
setError(error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchDownloads();
|
||||
|
||||
const interval = setInterval(() => {
|
||||
fetchDownloads();
|
||||
}, 10000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const Mods = () => {
|
||||
return (
|
||||
<section
|
||||
id="mods"
|
||||
id="download"
|
||||
className="wrapper container py-24 md:py-28 gap-4 flex flex-col"
|
||||
>
|
||||
<h1 className="text-3xl md:text-5xl font-bold text-black dark:bg-clip-text dark:text-transparent dark:bg-gradient-to-b dark:from-white dark:to-neutral-400">
|
||||
SvrJS Mods
|
||||
Downloads
|
||||
</h1>
|
||||
<p className="text-lg text-muted-foreground text-start mb-4">
|
||||
Get all the latest version of SVRJS Mods and compiled Files here!
|
||||
Get all the latest version of SVRJS download and compiled Files here!
|
||||
</p>
|
||||
{error && <p className="text-red-500">{error}</p>}
|
||||
<Table>
|
||||
<TableCaption>A list of all available downloads.</TableCaption>
|
||||
<TableHeader>
|
||||
|
@ -61,31 +72,34 @@ const Mods = () => {
|
|||
<TableHead className="w-[150px]">Date</TableHead>
|
||||
<TableHead>File Name</TableHead>
|
||||
<TableHead>Version</TableHead>
|
||||
<TableHead>Download Link</TableHead>
|
||||
<TableHead className="text-right">File Size</TableHead>
|
||||
<TableHead>File Size</TableHead>
|
||||
<TableHead className="text-right">Download Link</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{downloads.map((download) => (
|
||||
<TableRow key={download.fileName}>
|
||||
<TableCell className="font-medium">{download.date}</TableCell>
|
||||
<TableCell>{download.fileName}</TableCell>
|
||||
<TableCell>{download.version}</TableCell>
|
||||
<TableCell className="text-left">{download.fileSize}</TableCell>
|
||||
<TableCell className="flex items-center justify-end">
|
||||
<Link href={download.downloadLink}>
|
||||
<Button variant={"ghost"} className="">
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
Download
|
||||
</Button>
|
||||
</Link>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{downloads
|
||||
.slice(0, 10)
|
||||
.reverse()
|
||||
.map((download) => (
|
||||
<TableRow key={download._id}>
|
||||
<TableCell className="font-medium">{download.date}</TableCell>
|
||||
<TableCell>{download.fileName}</TableCell>
|
||||
<TableCell>{download.version}</TableCell>
|
||||
<TableCell className="text-left">{download.fileSize}</TableCell>
|
||||
<TableCell className="flex items-center justify-end">
|
||||
<Link href={download.downloadLink}>
|
||||
<Button variant={'ghost'} className="">
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
Download
|
||||
</Button>
|
||||
</Link>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Mods;
|
||||
export default DownloadPage;
|
||||
|
|
17
app/api/mods/route.ts
Normal file
17
app/api/mods/route.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import clientPromise from '@/lib/db';
|
||||
|
||||
// Handler for GET requests
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const client = await clientPromise;
|
||||
const db = client.db('downloadsDatabase');
|
||||
const downloads = await db.collection('mods').find().toArray();
|
||||
return NextResponse.json(downloads, { status: 200 });
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch mods' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
20
app/api/uploadmods/route.ts
Normal file
20
app/api/uploadmods/route.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { NextResponse } from 'next/server';
|
||||
import clientPromise from '@/lib/db';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const body = await request.json();
|
||||
const { fileName, version, downloadLink, fileSize } = body;
|
||||
|
||||
const client = await clientPromise;
|
||||
const db = client.db('downloadsDatabase');
|
||||
|
||||
const result = await db.collection('mods').insertOne({
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
fileName,
|
||||
version,
|
||||
downloadLink,
|
||||
fileSize,
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, id: result.insertedId });
|
||||
}
|
|
@ -1,53 +1,53 @@
|
|||
import { BadgeAlert, BarChart4, Cog, ShieldCheck } from "lucide-react";
|
||||
import { Download, Home, Settings, User } from "lucide-react";
|
||||
import { BadgeAlert, BarChart4, Cog, ShieldCheck } from 'lucide-react';
|
||||
import { Download, Home, Settings, User } from 'lucide-react';
|
||||
|
||||
export const NAVBAR = {
|
||||
centerLinks: [
|
||||
{
|
||||
href: "/",
|
||||
target: "_self",
|
||||
label: "Home",
|
||||
href: '/',
|
||||
target: '_self',
|
||||
label: 'Home',
|
||||
},
|
||||
{
|
||||
href: "/docs",
|
||||
target: "_self",
|
||||
label: "Docs",
|
||||
href: '/docs',
|
||||
target: '_self',
|
||||
label: 'Docs',
|
||||
},
|
||||
{
|
||||
href: "/forum",
|
||||
target: "_self",
|
||||
label: "Forum",
|
||||
href: '/forum',
|
||||
target: '_self',
|
||||
label: 'Forum',
|
||||
},
|
||||
{
|
||||
href: "/blog",
|
||||
target: "_self",
|
||||
label: "Blog",
|
||||
href: '/blog',
|
||||
target: '_self',
|
||||
label: 'Blog',
|
||||
},
|
||||
],
|
||||
rightLinks: [
|
||||
{
|
||||
label: "Git",
|
||||
target: "_blank",
|
||||
href: "https://git.svrjs.org/",
|
||||
label: 'Git',
|
||||
target: '_blank',
|
||||
href: 'https://git.svrjs.org/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const stats = [
|
||||
{
|
||||
title: "Downloads",
|
||||
title: 'Downloads',
|
||||
count: 69,
|
||||
},
|
||||
{
|
||||
title: "Users",
|
||||
title: 'Users',
|
||||
count: 42,
|
||||
},
|
||||
{
|
||||
title: "Stars",
|
||||
title: 'Stars',
|
||||
count: 6,
|
||||
},
|
||||
{
|
||||
title: "Products",
|
||||
title: 'Products',
|
||||
count: 2,
|
||||
},
|
||||
];
|
||||
|
@ -55,121 +55,121 @@ export const stats = [
|
|||
export const Features = [
|
||||
{
|
||||
icon: <ShieldCheck className="w-10 h-10 text-primary" />,
|
||||
title: "Complete Secured ",
|
||||
title: 'Completely Secured ',
|
||||
description:
|
||||
"lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor",
|
||||
'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor',
|
||||
},
|
||||
{
|
||||
icon: <BadgeAlert className="w-10 h-10 text-primary" />,
|
||||
title: "Best Support",
|
||||
title: 'Best Support',
|
||||
description:
|
||||
"lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor",
|
||||
'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor',
|
||||
},
|
||||
{
|
||||
icon: <BarChart4 className="w-10 h-10 text-primary" />,
|
||||
title: "Most Scalable ",
|
||||
title: 'Most Scalable ',
|
||||
description:
|
||||
"lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor",
|
||||
'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor',
|
||||
},
|
||||
{
|
||||
icon: <Cog className="w-10 h-10 text-primary" />,
|
||||
title: "Fully Configurable ",
|
||||
title: 'Fully Configurable ',
|
||||
description:
|
||||
"lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor",
|
||||
'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor',
|
||||
},
|
||||
];
|
||||
|
||||
export const questions = [
|
||||
{
|
||||
key: "item-1",
|
||||
question: "What is a web server?",
|
||||
key: 'item-1',
|
||||
question: 'What is a web server?',
|
||||
answer:
|
||||
"A web server is computer software that accepts HTTP requests and serves websites. Web servers can also be underlying hardware running web server software.",
|
||||
'A web server is computer software that accepts HTTP requests and serves websites. Web servers can also be underlying hardware running web server software.',
|
||||
},
|
||||
{
|
||||
key: "item-2",
|
||||
question: "What is SVR.JS?",
|
||||
key: 'item-2',
|
||||
question: 'What is SVR.JS?',
|
||||
answer:
|
||||
"SVR.JS is web server software running on Node.JS that can host both static and dynamic content. With additional mods, SVR.JS can be used for different types of dynamic content and can even be used as a forward or reverse proxy. SVR.JS is licensed under a permissive MIT/X11 license",
|
||||
'SVR.JS is web server software running on Node.JS that can host both static and dynamic content. With additional mods, SVR.JS can be used for different types of dynamic content and can even be used as a forward or reverse proxy. SVR.JS is licensed under a permissive MIT/X11 license',
|
||||
},
|
||||
{
|
||||
key: "item-3",
|
||||
question: "How was SVR.JS created?",
|
||||
key: 'item-3',
|
||||
question: 'How was SVR.JS created?',
|
||||
answer:
|
||||
"Someone in 2018 wanted to create a website, but he didnt know about setting up popular web server software like Apache httpd, NGINX, or IIS... So he created his own web server in Node.JS to serve his website! And he saved it in a file called svr.js. Since then, this web server has been gradually turned from a web server intended for one website into a general-purpose web server, which is what SVR.JS is today!",
|
||||
'Someone in 2018 wanted to create a website, but he didnt know about setting up popular web server software like Apache httpd, NGINX, or IIS... So he created his own web server in Node.JS to serve his website! And he saved it in a file called svr.js. Since then, this web server has been gradually turned from a web server intended for one website into a general-purpose web server, which is what SVR.JS is today!',
|
||||
},
|
||||
{
|
||||
key: "item-4",
|
||||
question: "How did SVR.JS get its name?",
|
||||
key: 'item-4',
|
||||
question: 'How did SVR.JS get its name?',
|
||||
answer:
|
||||
"SVR.JS got its name from the original name of the server script: svr.js, one of many generic file names for a server written in JavaScript.",
|
||||
'SVR.JS got its name from the original name of the server script: svr.js, one of many generic file names for a server written in JavaScript.',
|
||||
},
|
||||
{
|
||||
key: "item-5",
|
||||
question: "What is Node.JS?",
|
||||
key: 'item-5',
|
||||
question: 'What is Node.JS?',
|
||||
answer:
|
||||
"Node.JS is an asynchronous event-driven JavaScript runtime built on Chromiums V8 engine. Node.JS is designed to build scalable network applications.",
|
||||
'Node.JS is an asynchronous event-driven JavaScript runtime built on Chromiums V8 engine. Node.JS is designed to build scalable network applications.',
|
||||
},
|
||||
{
|
||||
key: "item-6",
|
||||
question: "How can I use SVR.JS?",
|
||||
key: 'item-6',
|
||||
question: 'How can I use SVR.JS?',
|
||||
answer:
|
||||
"You can read the documents to learn how to use the SVR.JS web server.",
|
||||
'You can read the documents to learn how to use the SVR.JS web server.',
|
||||
},
|
||||
];
|
||||
|
||||
export const FOOTERLINKS = {
|
||||
otherPages: [
|
||||
{ href: "/", label: "Home" },
|
||||
{ href: "/contact", label: "Contact" },
|
||||
{ href: "/blog", label: "Blog" },
|
||||
{ href: "/forum", label: "Forum" },
|
||||
{ href: '/', label: 'Home' },
|
||||
{ href: '/contact', label: 'Contact' },
|
||||
{ href: '/blog', label: 'Blog' },
|
||||
{ href: '/forum', label: 'Forum' },
|
||||
],
|
||||
plans: [
|
||||
{ href: "/docs", label: "Docs" },
|
||||
{ href: "/downloads", label: "Downloads" },
|
||||
{ href: "/tos", label: "Terms of Serivce" },
|
||||
{ href: "/privacy-policy", label: "Privacy Policy" },
|
||||
{ href: '/docs', label: 'Docs' },
|
||||
{ href: '/downloads', label: 'Downloads' },
|
||||
{ href: '/tos', label: 'Terms of Serivce' },
|
||||
{ href: '/privacy-policy', label: 'Privacy Policy' },
|
||||
],
|
||||
social: {
|
||||
supportText: "Support Us on Socials",
|
||||
supportText: 'Support Us on Socials',
|
||||
},
|
||||
footerBottom: {
|
||||
designedBy: {
|
||||
href: "https://abhijee.com",
|
||||
label: "Proxy",
|
||||
href: 'https://abhijee.com',
|
||||
label: 'Proxy',
|
||||
},
|
||||
rightsReserved: {
|
||||
href: "https://cyprostudio.com",
|
||||
label: "SVRJS",
|
||||
href: 'https://cyprostudio.com',
|
||||
label: 'SVRJS',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const AdminLinks = [
|
||||
{
|
||||
name: "Dashboard",
|
||||
url: "/admin",
|
||||
name: 'Dashboard',
|
||||
url: '/admin',
|
||||
icon: Home,
|
||||
},
|
||||
{
|
||||
name: "Downloads",
|
||||
url: "/admin/downloads",
|
||||
name: 'Downloads',
|
||||
url: '/admin/downloads',
|
||||
icon: Download,
|
||||
},
|
||||
{
|
||||
name: "Mods",
|
||||
url: "/admin/mods",
|
||||
name: 'Mods',
|
||||
url: '/admin/mods',
|
||||
icon: User,
|
||||
},
|
||||
{
|
||||
name: "Logs",
|
||||
url: "/admin/changelogs",
|
||||
name: 'Logs',
|
||||
url: '/admin/changelogs',
|
||||
icon: Settings,
|
||||
},
|
||||
{
|
||||
name: "Back Home",
|
||||
url: "/",
|
||||
name: 'Back Home',
|
||||
url: '/',
|
||||
icon: Home,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from "zod";
|
||||
import { z } from 'zod';
|
||||
|
||||
export const downloadSchema = z.object({
|
||||
fileName: z.string().nonempty(),
|
||||
|
@ -6,3 +6,10 @@ export const downloadSchema = z.object({
|
|||
downloadLink: z.string().url().nonempty(),
|
||||
fileSize: z.string().nonempty(),
|
||||
});
|
||||
|
||||
export const modsSchema = z.object({
|
||||
fileName: z.string().nonempty(),
|
||||
version: z.string().nonempty(),
|
||||
downloadLink: z.string().url().nonempty(),
|
||||
fileSize: z.string().nonempty(),
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue