Spaces:
Running
Running
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';
|