Skip to content

Commit c6e6748

Browse files
committed
first commit
0 parents  commit c6e6748

34 files changed

+4196
-0
lines changed

.gitignore

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# env files (can opt-in for committing if needed)
34+
.env*
35+
36+
# vercel
37+
.vercel
38+
39+
# typescript
40+
*.tsbuildinfo
41+
next-env.d.ts

README.md

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2+
3+
## Getting Started
4+
5+
First, run the development server:
6+
7+
```bash
8+
npm run dev
9+
# or
10+
yarn dev
11+
# or
12+
pnpm dev
13+
# or
14+
bun dev
15+
```
16+
17+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18+
19+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20+
21+
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22+
23+
## Learn More
24+
25+
To learn more about Next.js, take a look at the following resources:
26+
27+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29+
30+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31+
32+
## Deploy on Vercel
33+
34+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35+
36+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

app/api/verify-password/route.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { cookies } from 'next/headers'
2+
import { NextResponse } from 'next/server'
3+
4+
export async function POST(request: Request) {
5+
const { password } = await request.json()
6+
7+
if (password === process.env.ACCESS_PASSWORD) {
8+
// Set a cookie to remember the valid password
9+
cookies().set('access_token', 'true', {
10+
httpOnly: true,
11+
secure: process.env.NODE_ENV === 'production',
12+
sameSite: 'lax',
13+
maxAge: 60 * 60 * 24, // 24 hours
14+
})
15+
16+
return new NextResponse('OK', { status: 200 })
17+
}
18+
19+
return new NextResponse('Unauthorized', { status: 401 })
20+
}

app/globals.css

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
body {
6+
font-family: Arial, Helvetica, sans-serif;
7+
}
8+
9+
@layer utilities {
10+
.text-balance {
11+
text-wrap: balance;
12+
}
13+
}
14+
15+
@layer base {
16+
:root {
17+
--background: 0 0% 100%;
18+
--foreground: 240 10% 3.9%;
19+
--card: 0 0% 100%;
20+
--card-foreground: 240 10% 3.9%;
21+
--popover: 0 0% 100%;
22+
--popover-foreground: 240 10% 3.9%;
23+
--primary: 240 5.9% 10%;
24+
--primary-foreground: 0 0% 98%;
25+
--secondary: 240 4.8% 95.9%;
26+
--secondary-foreground: 240 5.9% 10%;
27+
--muted: 240 4.8% 95.9%;
28+
--muted-foreground: 240 3.8% 46.1%;
29+
--accent: 240 4.8% 95.9%;
30+
--accent-foreground: 240 5.9% 10%;
31+
--destructive: 0 84.2% 60.2%;
32+
--destructive-foreground: 0 0% 98%;
33+
--border: 240 5.9% 90%;
34+
--input: 240 5.9% 90%;
35+
--ring: 240 10% 3.9%;
36+
--chart-1: 12 76% 61%;
37+
--chart-2: 173 58% 39%;
38+
--chart-3: 197 37% 24%;
39+
--chart-4: 43 74% 66%;
40+
--chart-5: 27 87% 67%;
41+
--radius: 0.5rem;
42+
--sidebar-background: 0 0% 98%;
43+
--sidebar-foreground: 240 5.3% 26.1%;
44+
--sidebar-primary: 240 5.9% 10%;
45+
--sidebar-primary-foreground: 0 0% 98%;
46+
--sidebar-accent: 240 4.8% 95.9%;
47+
--sidebar-accent-foreground: 240 5.9% 10%;
48+
--sidebar-border: 220 13% 91%;
49+
--sidebar-ring: 217.2 91.2% 59.8%;
50+
}
51+
.dark {
52+
--background: 240 10% 3.9%;
53+
--foreground: 0 0% 98%;
54+
--card: 240 10% 3.9%;
55+
--card-foreground: 0 0% 98%;
56+
--popover: 240 10% 3.9%;
57+
--popover-foreground: 0 0% 98%;
58+
--primary: 0 0% 98%;
59+
--primary-foreground: 240 5.9% 10%;
60+
--secondary: 240 3.7% 15.9%;
61+
--secondary-foreground: 0 0% 98%;
62+
--muted: 240 3.7% 15.9%;
63+
--muted-foreground: 240 5% 64.9%;
64+
--accent: 240 3.7% 15.9%;
65+
--accent-foreground: 0 0% 98%;
66+
--destructive: 0 62.8% 30.6%;
67+
--destructive-foreground: 0 0% 98%;
68+
--border: 240 3.7% 15.9%;
69+
--input: 240 3.7% 15.9%;
70+
--ring: 240 4.9% 83.9%;
71+
--chart-1: 220 70% 50%;
72+
--chart-2: 160 60% 45%;
73+
--chart-3: 30 80% 55%;
74+
--chart-4: 280 65% 60%;
75+
--chart-5: 340 75% 55%;
76+
--sidebar-background: 240 5.9% 10%;
77+
--sidebar-foreground: 240 4.8% 95.9%;
78+
--sidebar-primary: 224.3 76.3% 48%;
79+
--sidebar-primary-foreground: 0 0% 100%;
80+
--sidebar-accent: 240 3.7% 15.9%;
81+
--sidebar-accent-foreground: 240 4.8% 95.9%;
82+
--sidebar-border: 240 3.7% 15.9%;
83+
--sidebar-ring: 217.2 91.2% 59.8%;
84+
}
85+
}
86+
87+
@layer base {
88+
* {
89+
@apply border-border;
90+
}
91+
body {
92+
@apply bg-background text-foreground;
93+
}
94+
}

app/layout.tsx

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import type { Metadata } from 'next'
2+
import { Geist, Geist_Mono } from 'next/font/google'
3+
4+
const geistSans = Geist({
5+
subsets: ['latin'],
6+
variable: '--font-sans',
7+
})
8+
const geistMono = Geist_Mono({
9+
subsets: ['latin'],
10+
variable: '--font-mono',
11+
})
12+
13+
export const metadata: Metadata = {
14+
title: 'TechArt Email Cosole',
15+
description: 'Send email using @xyehr.cn',
16+
}
17+
18+
export default function RootLayout({
19+
children,
20+
}: Readonly<{
21+
children: React.ReactNode
22+
}>) {
23+
return (
24+
<html lang="en">
25+
<body
26+
className={`${geistSans.variable} ${geistMono.variable} font-sans antialiased`}
27+
>
28+
{children}
29+
</body>
30+
</html>
31+
)
32+
}
33+
34+
35+
36+
import './globals.css'

app/page.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { EmailForm } from '@/components/email-form'
2+
3+
export default function Page() {
4+
return (
5+
<div className="flex min-h-svh items-center justify-center p-4">
6+
<EmailForm />
7+
</div>
8+
)
9+
}

app/password/page.tsx

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { useRouter } from 'next/navigation'
5+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
6+
import { Input } from '@/components/ui/input'
7+
import { Button } from '@/components/ui/button'
8+
import { Label } from '@/components/ui/label'
9+
10+
export default function PasswordPage() {
11+
const [error, setError] = useState('')
12+
const [loading, setLoading] = useState(false)
13+
const router = useRouter()
14+
15+
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
16+
event.preventDefault()
17+
setLoading(true)
18+
setError('')
19+
20+
const formData = new FormData(event.currentTarget)
21+
const password = formData.get('password')
22+
23+
try {
24+
const response = await fetch('/api/verify-password', {
25+
method: 'POST',
26+
body: JSON.stringify({ password }),
27+
headers: {
28+
'Content-Type': 'application/json',
29+
},
30+
})
31+
32+
if (response.ok) {
33+
router.refresh()
34+
router.push('/')
35+
} else {
36+
setError('Invalid password')
37+
}
38+
} catch (err) {
39+
setError('An error occurred. Please try again.')
40+
} finally {
41+
setLoading(false)
42+
}
43+
}
44+
45+
return (
46+
<div className="flex min-h-svh items-center justify-center p-4">
47+
<Card className="w-full max-w-sm">
48+
<CardHeader>
49+
<CardTitle>Password Required</CardTitle>
50+
<CardDescription>
51+
Please enter the password to access this page
52+
</CardDescription>
53+
</CardHeader>
54+
<form onSubmit={handleSubmit}>
55+
<CardContent>
56+
<div className="grid gap-4">
57+
<div className="grid gap-2">
58+
<Label htmlFor="password">Password</Label>
59+
<Input
60+
id="password"
61+
name="password"
62+
type="password"
63+
autoComplete="current-password"
64+
required
65+
/>
66+
</div>
67+
{error && <p className="text-sm text-destructive">{error}</p>}
68+
</div>
69+
</CardContent>
70+
<CardFooter>
71+
<Button type="submit" className="w-full" disabled={loading}>
72+
{loading ? 'Verifying...' : 'Submit'}
73+
</Button>
74+
</CardFooter>
75+
</form>
76+
</Card>
77+
</div>
78+
)
79+
}

bun.lockb

83.3 KB
Binary file not shown.

components.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.ts",
8+
"css": "app/globals.css",
9+
"baseColor": "zinc",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}

0 commit comments

Comments
 (0)