Spaces:
Sleeping
Sleeping
Merge remote-tracking branch 'upstream/feat/login'
Browse files- src/app/(auth)/layout.tsx +0 -2
- src/app/(auth)/sign-in/page.tsx +0 -1
- src/app/(auth)/sign-up/page.tsx +14 -0
- src/app/layout.tsx +3 -3
- src/app/page.tsx +6 -50
- src/components/Navbar.tsx +1 -0
- src/components/Sponsors.tsx +0 -115
- src/components/atoms/Badge/index.tsx +0 -1
- src/components/atoms/Button/index.tsx +1 -1
- src/components/atoms/Card/index.tsx +0 -1
- src/components/atoms/Input/index.tsx +0 -1
- src/components/atoms/index.ts +1 -1
- src/components/homepage/AnnouncementBanner.tsx +0 -1
- src/components/homepage/CustomizationSection.tsx +0 -1
- src/components/homepage/FeatureSection.tsx +0 -1
- src/utils/AppConfig.ts +1 -1
- src/utils/Helpers.ts +2 -0
src/app/(auth)/layout.tsx
CHANGED
|
@@ -1,5 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
-
|
| 3 |
import { ClerkProvider } from '@clerk/nextjs';
|
| 4 |
import { setRequestLocale } from 'next-intl/server';
|
| 5 |
|
|
|
|
|
|
|
|
|
|
| 1 |
import { ClerkProvider } from '@clerk/nextjs';
|
| 2 |
import { setRequestLocale } from 'next-intl/server';
|
| 3 |
|
src/app/(auth)/sign-in/page.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import { SignIn } from '@clerk/nextjs';
|
| 3 |
|
| 4 |
type ISignInPageProps = {
|
|
|
|
|
|
|
| 1 |
import { SignIn } from '@clerk/nextjs';
|
| 2 |
|
| 3 |
type ISignInPageProps = {
|
src/app/(auth)/sign-up/page.tsx
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { SignUp } from '@clerk/nextjs';
|
| 2 |
+
|
| 3 |
+
type ISignUpPageProps = {
|
| 4 |
+
params: Promise<{ locale: string }>;
|
| 5 |
+
};
|
| 6 |
+
|
| 7 |
+
export default async function SignUpPage(_props: ISignUpPageProps) {
|
| 8 |
+
return (
|
| 9 |
+
<SignUp
|
| 10 |
+
path="/sign-up"
|
| 11 |
+
signInUrl="/sign-in"
|
| 12 |
+
/>
|
| 13 |
+
);
|
| 14 |
+
};
|
src/app/layout.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import type { Metadata } from 'next';
|
| 3 |
import { Navbar } from '@/components/Navbar';
|
|
|
|
| 4 |
import { Inter, Outfit } from 'next/font/google';
|
| 5 |
import '../styles/global.css';
|
| 6 |
|
|
@@ -16,7 +16,7 @@ const outfit = Outfit({
|
|
| 16 |
});
|
| 17 |
|
| 18 |
export const metadata: Metadata = {
|
| 19 |
-
title: '
|
| 20 |
description: 'A clone of Jan.ai built with Next.js and Tailwind CSS',
|
| 21 |
};
|
| 22 |
|
|
@@ -27,7 +27,7 @@ export default function RootLayout({
|
|
| 27 |
}) {
|
| 28 |
return (
|
| 29 |
<html lang="en" suppressHydrationWarning>
|
| 30 |
-
<body className={`${inter.variable} ${outfit.variable} font-sans antialiased`}>
|
| 31 |
<Navbar />
|
| 32 |
{children}
|
| 33 |
</body>
|
|
|
|
|
|
|
| 1 |
import type { Metadata } from 'next';
|
| 2 |
import { Navbar } from '@/components/Navbar';
|
| 3 |
+
import { isDevMode } from '@/utils/Helpers';
|
| 4 |
import { Inter, Outfit } from 'next/font/google';
|
| 5 |
import '../styles/global.css';
|
| 6 |
|
|
|
|
| 16 |
});
|
| 17 |
|
| 18 |
export const metadata: Metadata = {
|
| 19 |
+
title: 'X-App',
|
| 20 |
description: 'A clone of Jan.ai built with Next.js and Tailwind CSS',
|
| 21 |
};
|
| 22 |
|
|
|
|
| 27 |
}) {
|
| 28 |
return (
|
| 29 |
<html lang="en" suppressHydrationWarning>
|
| 30 |
+
<body className={`${inter.variable} ${outfit.variable} font-sans antialiased`} suppressHydrationWarning={isDevMode}>
|
| 31 |
<Navbar />
|
| 32 |
{children}
|
| 33 |
</body>
|
src/app/page.tsx
CHANGED
|
@@ -1,58 +1,14 @@
|
|
| 1 |
-
|
| 2 |
-
import {
|
| 3 |
-
import {
|
| 4 |
-
import Image from 'next/image';
|
| 5 |
|
| 6 |
export default function Home() {
|
| 7 |
return (
|
| 8 |
<main className="flex min-h-screen flex-col">
|
| 9 |
<div className="flex-1 space-y-16 pb-8 pt-20 md:pb-12 md:pt-24 lg:py-32">
|
| 10 |
-
<
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
{' '}
|
| 14 |
-
<span className="mx-1">+</span>
|
| 15 |
-
{' '}
|
| 16 |
-
v0.5.14 is now live on GitHub. Check it out!
|
| 17 |
-
</Badge>
|
| 18 |
-
|
| 19 |
-
<span className="text-4xl">❝</span>
|
| 20 |
-
|
| 21 |
-
<h1 className="font-heading text-3xl sm:text-5xl md:text-6xl lg:text-7xl">
|
| 22 |
-
Chat with AI
|
| 23 |
-
<br />
|
| 24 |
-
without privacy concerns
|
| 25 |
-
</h1>
|
| 26 |
-
|
| 27 |
-
<p className="max-w-2xl leading-normal text-muted-foreground sm:text-xl sm:leading-8">
|
| 28 |
-
Jan is an open source ChatGPT-alternative that runs 100% offline.
|
| 29 |
-
</p>
|
| 30 |
-
|
| 31 |
-
<div className="space-y-4">
|
| 32 |
-
<Button className="h-11 px-8" size="lg">
|
| 33 |
-
<Download className="mr-2 size-4" />
|
| 34 |
-
Download for Windows
|
| 35 |
-
<ChevronDown className="ml-2 size-4" />
|
| 36 |
-
</Button>
|
| 37 |
-
<p className="text-xs text-muted-foreground">
|
| 38 |
-
<span className="font-semibold text-yellow-500">2.5M+</span>
|
| 39 |
-
{' '}
|
| 40 |
-
downloads | Free & Open Source
|
| 41 |
-
</p>
|
| 42 |
-
</div>
|
| 43 |
-
</div>
|
| 44 |
-
|
| 45 |
-
<div className="container">
|
| 46 |
-
<div className="relative mx-auto aspect-video max-w-5xl overflow-hidden rounded-xl border bg-background shadow-xl">
|
| 47 |
-
<Image
|
| 48 |
-
src="https://sjc.microlink.io/-ax0tIqUfnMYpO1Y6sFNuRcGN_Oe6cQwpzrnQR5q5pzkpfA29UGKZ228lDnpeQCpNANORBcNBmQgFoOtLn18vw.jpeg"
|
| 49 |
-
alt="Jan AI Interface"
|
| 50 |
-
fill
|
| 51 |
-
className="object-cover"
|
| 52 |
-
priority
|
| 53 |
-
/>
|
| 54 |
-
</div>
|
| 55 |
-
</div>
|
| 56 |
</div>
|
| 57 |
</main>
|
| 58 |
);
|
|
|
|
| 1 |
+
import { AnnouncementBanner } from '@/components/homepage/AnnouncementBanner';
|
| 2 |
+
import { CustomizationSection } from '@/components/homepage/CustomizationSection';
|
| 3 |
+
import { FeaturesSection } from '@/components/homepage/FeatureSection';
|
|
|
|
| 4 |
|
| 5 |
export default function Home() {
|
| 6 |
return (
|
| 7 |
<main className="flex min-h-screen flex-col">
|
| 8 |
<div className="flex-1 space-y-16 pb-8 pt-20 md:pb-12 md:pt-24 lg:py-32">
|
| 9 |
+
<AnnouncementBanner />
|
| 10 |
+
<FeaturesSection />
|
| 11 |
+
<CustomizationSection />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
</div>
|
| 13 |
</main>
|
| 14 |
);
|
src/components/Navbar.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import { Button, Input } from '@/components/atoms';
|
| 2 |
import { Search, Settings } from 'lucide-react';
|
| 3 |
import Link from 'next/link';
|
|
|
|
| 1 |
+
'use client';
|
| 2 |
import { Button, Input } from '@/components/atoms';
|
| 3 |
import { Search, Settings } from 'lucide-react';
|
| 4 |
import Link from 'next/link';
|
src/components/Sponsors.tsx
DELETED
|
@@ -1,115 +0,0 @@
|
|
| 1 |
-
/* eslint-disable react-dom/no-unsafe-target-blank */
|
| 2 |
-
import Image from 'next/image';
|
| 3 |
-
|
| 4 |
-
export const Sponsors = () => (
|
| 5 |
-
<table className="border-collapse">
|
| 6 |
-
<tbody>
|
| 7 |
-
<tr className="h-56">
|
| 8 |
-
<td className="border-2 border-gray-300 p-3">
|
| 9 |
-
<a
|
| 10 |
-
href="https://clerk.com?utm_source=github&utm_medium=sponsorship&utm_campaign=nextjs-boilerplate"
|
| 11 |
-
target="_blank"
|
| 12 |
-
rel="noopener"
|
| 13 |
-
>
|
| 14 |
-
<Image
|
| 15 |
-
src="/assets/images/clerk-logo-dark.png"
|
| 16 |
-
alt="Clerk – Authentication & User Management for Next.js"
|
| 17 |
-
width={260}
|
| 18 |
-
height={224}
|
| 19 |
-
/>
|
| 20 |
-
</a>
|
| 21 |
-
</td>
|
| 22 |
-
<td className="border-2 border-gray-300 p-3">
|
| 23 |
-
<a href="https://l.crowdin.com/next-js" target="_blank" rel="noopener">
|
| 24 |
-
<Image
|
| 25 |
-
src="/assets/images/crowdin-dark.png"
|
| 26 |
-
alt="Crowdin"
|
| 27 |
-
width={260}
|
| 28 |
-
height={224}
|
| 29 |
-
/>
|
| 30 |
-
</a>
|
| 31 |
-
</td>
|
| 32 |
-
<td className="border-2 border-gray-300 p-3">
|
| 33 |
-
<a
|
| 34 |
-
href="https://sentry.io/for/nextjs/?utm_source=github&utm_medium=paid-community&utm_campaign=general-fy25q1-nextjs&utm_content=github-banner-nextjsboilerplate-logo"
|
| 35 |
-
target="_blank"
|
| 36 |
-
rel="noopener"
|
| 37 |
-
>
|
| 38 |
-
<Image
|
| 39 |
-
src="/assets/images/sentry-dark.png"
|
| 40 |
-
alt="Sentry"
|
| 41 |
-
width={260}
|
| 42 |
-
height={224}
|
| 43 |
-
/>
|
| 44 |
-
</a>
|
| 45 |
-
</td>
|
| 46 |
-
</tr>
|
| 47 |
-
<tr className="h-56">
|
| 48 |
-
<td className="border-2 border-gray-300 p-3">
|
| 49 |
-
<a href="https://launch.arcjet.com/Q6eLbRE">
|
| 50 |
-
<Image
|
| 51 |
-
src="/assets/images/arcjet-light.svg"
|
| 52 |
-
alt="Arcjet"
|
| 53 |
-
width={260}
|
| 54 |
-
height={224}
|
| 55 |
-
/>
|
| 56 |
-
</a>
|
| 57 |
-
</td>
|
| 58 |
-
<td className="border-2 border-gray-300 p-3">
|
| 59 |
-
<a
|
| 60 |
-
href="https://posthog.com/?utm_source=github&utm_medium=sponsorship&utm_campaign=next-js-boilerplate"
|
| 61 |
-
target="_blank"
|
| 62 |
-
rel="noopener"
|
| 63 |
-
>
|
| 64 |
-
<Image
|
| 65 |
-
src="https://posthog.com/brand/posthog-logo.svg"
|
| 66 |
-
alt="PostHog"
|
| 67 |
-
width={260}
|
| 68 |
-
height={224}
|
| 69 |
-
/>
|
| 70 |
-
</a>
|
| 71 |
-
</td>
|
| 72 |
-
<td className="border-2 border-gray-300 p-3">
|
| 73 |
-
<a
|
| 74 |
-
href="https://betterstack.com/?utm_source=github&utm_medium=sponsorship&utm_campaign=next-js-boilerplate"
|
| 75 |
-
target="_blank"
|
| 76 |
-
rel="noopener"
|
| 77 |
-
>
|
| 78 |
-
<Image
|
| 79 |
-
src="/assets/images/better-stack-dark.png"
|
| 80 |
-
alt="Better Stack"
|
| 81 |
-
width={260}
|
| 82 |
-
height={224}
|
| 83 |
-
/>
|
| 84 |
-
</a>
|
| 85 |
-
</td>
|
| 86 |
-
</tr>
|
| 87 |
-
<tr className="h-56">
|
| 88 |
-
<td className="border-2 border-gray-300 p-3">
|
| 89 |
-
<a
|
| 90 |
-
href="https://www.checklyhq.com/?utm_source=github&utm_medium=sponsorship&utm_campaign=next-js-boilerplate"
|
| 91 |
-
target="_blank"
|
| 92 |
-
rel="noopener"
|
| 93 |
-
>
|
| 94 |
-
<Image
|
| 95 |
-
src="/assets/images/checkly-logo-light.png"
|
| 96 |
-
alt="Checkly"
|
| 97 |
-
width={260}
|
| 98 |
-
height={224}
|
| 99 |
-
/>
|
| 100 |
-
</a>
|
| 101 |
-
</td>
|
| 102 |
-
<td className="border-2 border-gray-300 p-3">
|
| 103 |
-
<a href="https://nextjs-boilerplate.com/pro-saas-starter-kit">
|
| 104 |
-
<Image
|
| 105 |
-
src="/assets/images/nextjs-boilerplate-saas.png"
|
| 106 |
-
alt="Next.js SaaS Boilerplate"
|
| 107 |
-
width={260}
|
| 108 |
-
height={224}
|
| 109 |
-
/>
|
| 110 |
-
</a>
|
| 111 |
-
</td>
|
| 112 |
-
</tr>
|
| 113 |
-
</tbody>
|
| 114 |
-
</table>
|
| 115 |
-
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/atoms/Badge/index.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import type * as React from 'react';
|
| 3 |
import { cn } from '@/utils/Helpers';
|
| 4 |
import { cva, type VariantProps } from 'class-variance-authority';
|
|
|
|
|
|
|
| 1 |
import type * as React from 'react';
|
| 2 |
import { cn } from '@/utils/Helpers';
|
| 3 |
import { cva, type VariantProps } from 'class-variance-authority';
|
src/components/atoms/Button/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
/* eslint
|
| 2 |
import { cn } from '@/utils/Helpers';
|
| 3 |
import { cva, type VariantProps } from 'class-variance-authority';
|
| 4 |
import { type ButtonHTMLAttributes, type FC, memo, type PropsWithChildren, type Ref } from 'react';
|
|
|
|
| 1 |
+
/* eslint-disable react-refresh/only-export-components */
|
| 2 |
import { cn } from '@/utils/Helpers';
|
| 3 |
import { cva, type VariantProps } from 'class-variance-authority';
|
| 4 |
import { type ButtonHTMLAttributes, type FC, memo, type PropsWithChildren, type Ref } from 'react';
|
src/components/atoms/Card/index.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import { cn } from '@/utils/Helpers';
|
| 3 |
import * as React from 'react';
|
| 4 |
|
|
|
|
|
|
|
| 1 |
import { cn } from '@/utils/Helpers';
|
| 2 |
import * as React from 'react';
|
| 3 |
|
src/components/atoms/Input/index.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import { cn } from '@/utils/Helpers';
|
| 3 |
import { type FC, type InputHTMLAttributes, memo, type Ref } from 'react';
|
| 4 |
|
|
|
|
|
|
|
| 1 |
import { cn } from '@/utils/Helpers';
|
| 2 |
import { type FC, type InputHTMLAttributes, memo, type Ref } from 'react';
|
| 3 |
|
src/components/atoms/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
export { Badge } from './Badge';
|
| 2 |
export { Button } from './Button';
|
| 3 |
-
export
|
| 4 |
export { Input } from './Input';
|
|
|
|
| 1 |
export { Badge } from './Badge';
|
| 2 |
export { Button } from './Button';
|
| 3 |
+
export * from './Card';
|
| 4 |
export { Input } from './Input';
|
src/components/homepage/AnnouncementBanner.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import { Badge, Button } from '@/components/atoms';
|
| 3 |
import { ChevronDown, Download } from 'lucide-react';
|
| 4 |
import Image from 'next/image';
|
|
|
|
|
|
|
| 1 |
import { Badge, Button } from '@/components/atoms';
|
| 2 |
import { ChevronDown, Download } from 'lucide-react';
|
| 3 |
import Image from 'next/image';
|
src/components/homepage/CustomizationSection.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import { Badge, Card } from '@/components/atoms';
|
| 3 |
import Image from 'next/image';
|
| 4 |
|
|
|
|
|
|
|
| 1 |
import { Badge, Card } from '@/components/atoms';
|
| 2 |
import Image from 'next/image';
|
| 3 |
|
src/components/homepage/FeatureSection.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
/* eslint import/newline-after-import: "off" */
|
| 2 |
import { Badge } from '@/components/atoms';
|
| 3 |
import { Cloud, FileText, Grid, MessageCircle, Server } from 'lucide-react';
|
| 4 |
import Image from 'next/image';
|
|
|
|
|
|
|
| 1 |
import { Badge } from '@/components/atoms';
|
| 2 |
import { Cloud, FileText, Grid, MessageCircle, Server } from 'lucide-react';
|
| 3 |
import Image from 'next/image';
|
src/utils/AppConfig.ts
CHANGED
|
@@ -5,7 +5,7 @@ const localePrefix: LocalePrefixMode = 'as-needed';
|
|
| 5 |
// FIXME: Update this configuration file based on your project information
|
| 6 |
export const AppConfig = {
|
| 7 |
name: 'Nextjs Starter',
|
| 8 |
-
locales: ['en', 'fr'],
|
| 9 |
defaultLocale: 'en',
|
| 10 |
localePrefix,
|
| 11 |
};
|
|
|
|
| 5 |
// FIXME: Update this configuration file based on your project information
|
| 6 |
export const AppConfig = {
|
| 7 |
name: 'Nextjs Starter',
|
| 8 |
+
locales: ['en', 'fr', 'vi'],
|
| 9 |
defaultLocale: 'en',
|
| 10 |
localePrefix,
|
| 11 |
};
|
src/utils/Helpers.ts
CHANGED
|
@@ -32,3 +32,5 @@ export const getI18nPath = (url: string, locale: string) => {
|
|
| 32 |
export function cn(...inputs: ClassValue[]) {
|
| 33 |
return twMerge(clsx(inputs));
|
| 34 |
}
|
|
|
|
|
|
|
|
|
| 32 |
export function cn(...inputs: ClassValue[]) {
|
| 33 |
return twMerge(clsx(inputs));
|
| 34 |
}
|
| 35 |
+
|
| 36 |
+
export const isDevMode = process.env.NODE_ENV !== 'production';
|