@ardly/bunext 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +8 -0
- package/.prettierignore +4 -0
- package/README.md +121 -0
- package/STRUCTURE.md +77 -0
- package/bin/cli.js +67 -0
- package/components.json +21 -0
- package/next.config.ts +22 -0
- package/package.json +59 -0
- package/postcss.config.mjs +8 -0
- package/prettier.config.js +7 -0
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/favicon.svg +1 -0
- package/public/loading-dots.gif +0 -0
- package/public/logo.svg +1 -0
- package/public/ogImage.webp +0 -0
- package/public/site.webmanifest +19 -0
- package/src/actions/placeholder.ts +30 -0
- package/src/actions/sampleAction.ts +39 -0
- package/src/app/(index)/intr/TestCard.tsx +31 -0
- package/src/app/(index)/intr/page.tsx +17 -0
- package/src/app/(index)/page.tsx +156 -0
- package/src/app/(index)/pagetr/page.tsx +37 -0
- package/src/app/error-wrapper.tsx +32 -0
- package/src/app/global-error.tsx +53 -0
- package/src/app/layout.tsx +56 -0
- package/src/app/loading.tsx +11 -0
- package/src/app/not-found.tsx +45 -0
- package/src/app/sitemap.ts +14 -0
- package/src/components/Providers/root-provider.tsx +22 -0
- package/src/components/Providers/theme-provider.tsx +27 -0
- package/src/components/TestComp.tsx +11 -0
- package/src/components/brand.tsx +35 -0
- package/src/components/navigation/footer.tsx +32 -0
- package/src/components/navigation/main-nav.tsx +55 -0
- package/src/components/navigation/mobile-nav.tsx +154 -0
- package/src/components/navigation/site-header.tsx +67 -0
- package/src/components/ui/avatar.tsx +50 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.tsx +79 -0
- package/src/components/ui/command.tsx +153 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/drawer.tsx +118 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/multi-select.tsx +380 -0
- package/src/components/ui/origin/multiselect.tsx +645 -0
- package/src/components/ui/popover.tsx +31 -0
- package/src/components/ui/radio-group.tsx +44 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/themeSelector.tsx +157 -0
- package/src/components/ui/toast.tsx +129 -0
- package/src/components/ui/toaster.tsx +31 -0
- package/src/components/ui/tooltip.tsx +39 -0
- package/src/components/utils/ConditionalLink.tsx +46 -0
- package/src/components/utils/Image.tsx +57 -0
- package/src/components/utils/Img.tsx +104 -0
- package/src/components/utils/Spinner.tsx +29 -0
- package/src/components/utils/TopButton.tsx +67 -0
- package/src/components/utils/TransitionLink.tsx +67 -0
- package/src/components/utils/copy.tsx +98 -0
- package/src/components/utils/featureFlag.tsx +22 -0
- package/src/components/utils/icons.tsx +155 -0
- package/src/components/utils/share-modal.tsx +159 -0
- package/src/hooks/use-intersection.ts +52 -0
- package/src/hooks/use-lazy-load.ts +33 -0
- package/src/hooks/use-meta-color.ts +25 -0
- package/src/hooks/use-toast.ts +191 -0
- package/src/lib/config/featureflags.ts +63 -0
- package/src/lib/config/siteConfig.ts +172 -0
- package/src/lib/config/user.ts +9 -0
- package/src/lib/data/footer-data.ts +85 -0
- package/src/lib/data/nav-data.ts +30 -0
- package/src/lib/data/siteData.ts +52 -0
- package/src/lib/utils/index.ts +190 -0
- package/src/styles/customGlobal.css +141 -0
- package/src/styles/globals.css +72 -0
- package/src/styles/tailwind/base.ts +46 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Bold.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Bold.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Bold.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Bold.woff2 +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Extralight.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Extralight.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Extralight.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Extralight.woff2 +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Light.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Light.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Light.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Light.woff2 +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Medium.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Medium.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Medium.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Medium.woff2 +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Regular.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Regular.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Regular.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Regular.woff2 +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Semibold.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Semibold.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Semibold.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Semibold.woff2 +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Variable.eot +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Variable.ttf +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Variable.woff +0 -0
- package/src/styles/tailwind/fonts/ClashDisplay-Variable.woff2 +0 -0
- package/src/styles/tailwind/fonts/GeistMonoVF.woff +0 -0
- package/src/styles/tailwind/fonts/GeistVF.woff +0 -0
- package/src/styles/tailwind/fonts.ts +51 -0
- package/src/styles/tailwind/tailwindUtils.ts +29 -0
- package/src/types/index.ts +80 -0
- package/tailwind.config.ts +104 -0
- package/tsconfig.json +28 -0
- package/vercel.json +6 -0
package/.eslintrc.json
ADDED
package/.prettierignore
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Bunext
|
|
2
|
+
|
|
3
|
+
A Next.js 15 app with Tailwind CSS template. [Live deployment](https://bunext.ardastroid.com/)
|
|
4
|
+
|
|
5
|
+
## Usage (run locally)
|
|
6
|
+
|
|
7
|
+
> required `bun` or `nodejs` installed and make sure they're up to date
|
|
8
|
+
|
|
9
|
+
Go to the `root` folder where `package.json` exists.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Then
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bun --bun run dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun run dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- Next.js 15 App Directory
|
|
36
|
+
- Tailwind CSS
|
|
37
|
+
- [Shadcn](https://ui.shadcn.com/) components
|
|
38
|
+
- Custom util components like `share modal, multi-select(no library), Img, Icons, etc`
|
|
39
|
+
- CustomFont Optimization using [Next font](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts)
|
|
40
|
+
- Icons using [lucide-react](https://lucide.dev/)
|
|
41
|
+
- Next theme provider (dark and light mode)
|
|
42
|
+
- Url stage management using [nuqs](https://nuqs.47ng.com/)
|
|
43
|
+
- Tailwind css only animations using [tailwindcss-motion](https://docs.rombo.co/tailwind)
|
|
44
|
+
- Feature flags
|
|
45
|
+
- Metadata generator for SEO (including apple-touch-icon)
|
|
46
|
+
- [zod](https://zod.dev/) validation
|
|
47
|
+
- Per Link page transition (without any library)
|
|
48
|
+
- Custom Image components with lazy loading and auto generated placeholder (worsk with or without `next/image`)
|
|
49
|
+
- [Biome](https://biomejs.dev/) for linting and formatting
|
|
50
|
+
- [Fluid Tailwind](https://fluid.tw/) for easier responsive design (disabled by default, to enable go to `tailwind.config.ts` and uncomment the fluid plugin variables, Note: the `min-*` and `max-*` variants don't work while using fluid-tailwind)
|
|
51
|
+
- Utilities like `qrCode gen, string shortner, uniqueCode gen, img placeholder, email validation, hashing etc`
|
|
52
|
+
|
|
53
|
+
## Config
|
|
54
|
+
|
|
55
|
+
- for generating colors use [realtime-colors](https://www.realtimecolors.com/) shadcn template and pase it on `src/styles/globals.css`
|
|
56
|
+
- add fonts on `src/styles/tailwind/fonts.ts`
|
|
57
|
+
- to configure feature flags got to `src/lib/config/featureflags.ts`
|
|
58
|
+
- to configure Metadata got to `src/lib/data/siteData.ts`
|
|
59
|
+
- advance Metadata config in `src/lib/config/siteConfig.ts`
|
|
60
|
+
- for base styles (scrollbar style, selection highlighting etc) go to `src/styles/tailwind/base.ts`
|
|
61
|
+
|
|
62
|
+
## Roadmap
|
|
63
|
+
|
|
64
|
+
- [x] add next themes
|
|
65
|
+
- [x] feature flags
|
|
66
|
+
- [x] add sample responsive nav
|
|
67
|
+
- [ ] add sample footer
|
|
68
|
+
- [ ] add sample server actions
|
|
69
|
+
- [ ] add syntax highlighting for code blocks
|
|
70
|
+
- [ ] add a branch with animation features using motion
|
|
71
|
+
- [ ] add a feature full branch with drizzle orm, analytics, auth
|
|
72
|
+
|
|
73
|
+
### Multi-select sample code
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
'use client'
|
|
77
|
+
import React, { useState } from 'react'
|
|
78
|
+
import { MultiSelect } from '@/components/ui/multi-select'
|
|
79
|
+
|
|
80
|
+
const catsList = [
|
|
81
|
+
{ value: 'persian', label: 'Persian Cat' },
|
|
82
|
+
{ value: 'siamese', label: 'Siamese Cat' },
|
|
83
|
+
{ value: 'maine-coon', label: 'Maine Coon' },
|
|
84
|
+
{ value: 'ragdoll', label: 'Ragdoll' },
|
|
85
|
+
{ value: 'bengal', label: 'Bengal Cat' },
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
function Home() {
|
|
89
|
+
const [selectedCats, setSelectedCats] = useState<string[]>([
|
|
90
|
+
'persian',
|
|
91
|
+
'siamese',
|
|
92
|
+
])
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div className="max-w-xl p-4">
|
|
96
|
+
<h1 className="mb-4 text-2xl font-bold">Multi-Select Component</h1>
|
|
97
|
+
<MultiSelect
|
|
98
|
+
options={catsList}
|
|
99
|
+
onValueChange={setSelectedCats}
|
|
100
|
+
defaultValue={selectedCats}
|
|
101
|
+
placeholder="Select cats"
|
|
102
|
+
variant="inverted"
|
|
103
|
+
animation={2}
|
|
104
|
+
maxCount={3}
|
|
105
|
+
/>
|
|
106
|
+
<div className="mt-4">
|
|
107
|
+
<h2 className="text-xl font-semibold">Selected Cats:</h2>
|
|
108
|
+
<ul className="list-inside list-disc">
|
|
109
|
+
{selectedCats.map((cat) => (
|
|
110
|
+
<li key={cat}>{cat}</li>
|
|
111
|
+
))}
|
|
112
|
+
</ul>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
<!-- ### [Conventions](./CONVENTION.md) -->
|
|
120
|
+
<!-- ## License
|
|
121
|
+
Licensed under the [MIT license](./LICENSE). -->
|
package/STRUCTURE.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
## Bunext Folder Structure
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
├── .env
|
|
5
|
+
├── .env.example
|
|
6
|
+
├── .eslintrc.json
|
|
7
|
+
├── .gitignore
|
|
8
|
+
├── CONVENTION.md
|
|
9
|
+
├── README.md
|
|
10
|
+
├── biome.json
|
|
11
|
+
├── bun.lockb
|
|
12
|
+
├── components.json
|
|
13
|
+
├── next-env.d.ts
|
|
14
|
+
├── next.config.ts
|
|
15
|
+
├── package.json
|
|
16
|
+
├── postcss.config.mjs
|
|
17
|
+
├── tailwind.config.ts
|
|
18
|
+
├── tsconfig.json
|
|
19
|
+
├── public/
|
|
20
|
+
└── src/
|
|
21
|
+
├── actions/
|
|
22
|
+
├── app/
|
|
23
|
+
│ ├── (index)/
|
|
24
|
+
│ │ ├── intr/
|
|
25
|
+
│ │ ├── pagetr/
|
|
26
|
+
│ │ └── page.tsx
|
|
27
|
+
│ ├── layout.tsx
|
|
28
|
+
│ ├── not-found.tsx
|
|
29
|
+
│ └── sitemap.ts
|
|
30
|
+
├── components/
|
|
31
|
+
│ ├── Providers/ # providers for the app
|
|
32
|
+
│ │ ├── root-provider.tsx
|
|
33
|
+
│ │ └── theme-provider.tsx
|
|
34
|
+
│ ├── navigation/ # navigation components
|
|
35
|
+
│ │ ├── footer.tsx
|
|
36
|
+
│ │ ├── main-nav.tsx
|
|
37
|
+
│ │ ├── mobile-nav.tsx
|
|
38
|
+
│ │ └── site-header.tsx
|
|
39
|
+
│ ├── ui/ # shadcn-ui components
|
|
40
|
+
│ ├── utils/ # custom utility components
|
|
41
|
+
│ │ ├── ConditionalLink.tsx
|
|
42
|
+
│ │ ├── Image.tsx
|
|
43
|
+
│ │ ├── Img.tsx
|
|
44
|
+
│ │ ├── Spinner.tsx
|
|
45
|
+
│ │ ├── TopButton.tsx
|
|
46
|
+
│ │ ├── TransitionLink.tsx
|
|
47
|
+
│ │ ├── featureFlag.tsx
|
|
48
|
+
│ │ ├── icons.tsx
|
|
49
|
+
│ │ └── share-modal.tsx
|
|
50
|
+
│ ├── brand.tsx
|
|
51
|
+
│ └── TestComp.tsx
|
|
52
|
+
├── hooks/
|
|
53
|
+
│ ├── use-intersection.ts
|
|
54
|
+
│ ├── use-lazy-load.ts
|
|
55
|
+
│ ├── use-meta-color.ts
|
|
56
|
+
│ └── use-toast.ts
|
|
57
|
+
├── lib/
|
|
58
|
+
│ ├── config/
|
|
59
|
+
│ │ ├── featureflags.ts
|
|
60
|
+
│ │ ├── siteConfig.ts
|
|
61
|
+
│ │ └── user.ts
|
|
62
|
+
│ ├── data/ # data files for core site config & seo
|
|
63
|
+
│ │ ├── footer-data.ts
|
|
64
|
+
│ │ ├── nav-data.ts
|
|
65
|
+
│ │ └── siteData.ts
|
|
66
|
+
│ └── utils.ts # utility functions
|
|
67
|
+
├── styles/
|
|
68
|
+
│ ├── customGlobal.css
|
|
69
|
+
│ ├── globals.css
|
|
70
|
+
│ └── tailwind/
|
|
71
|
+
│ ├── base.ts
|
|
72
|
+
│ ├── fonts.ts
|
|
73
|
+
│ ├── tailwindUtils.ts
|
|
74
|
+
│ └── fonts/
|
|
75
|
+
└── types/
|
|
76
|
+
└── index.ts
|
|
77
|
+
```
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'child_process'
|
|
4
|
+
import readline from 'readline'
|
|
5
|
+
|
|
6
|
+
const runCommand = (command) => {
|
|
7
|
+
try {
|
|
8
|
+
execSync(`${command}`, { stdio: 'inherit' })
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error(`Failed to run command: ${command}`, error)
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
return true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const repoName = process.argv[2]
|
|
17
|
+
const gitCheckout = `git clone --depth 1 https://github.com/DarkidOP/Bunext.git ${repoName}`
|
|
18
|
+
const installDeps = `cd ${repoName} && bun install`
|
|
19
|
+
const removeGit = `rm -rf .git`
|
|
20
|
+
const initGit = `git init && git add . && git commit -m "Initial commit"`
|
|
21
|
+
|
|
22
|
+
const rl = readline.createInterface({
|
|
23
|
+
input: process.stdin,
|
|
24
|
+
output: process.stdout,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
console.log(`Creating project template in ./${repoName}`)
|
|
28
|
+
const checkedOut = runCommand(gitCheckout)
|
|
29
|
+
if (!checkedOut) {
|
|
30
|
+
console.error(
|
|
31
|
+
'Failed to clone template repository "https://github.com/DarkidOP/Bunext.git"'
|
|
32
|
+
)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('Removing Git history...')
|
|
37
|
+
const removedGit = runCommand(removeGit)
|
|
38
|
+
if (!removedGit) {
|
|
39
|
+
console.error('Failed to remove Git history')
|
|
40
|
+
process.exit(1)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log('Installing dependencies...')
|
|
44
|
+
const installedDeps = runCommand(installDeps)
|
|
45
|
+
if (!installedDeps) {
|
|
46
|
+
console.error('Failed to install dependencies')
|
|
47
|
+
process.exit(1)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Add Git initialization prompt
|
|
51
|
+
rl.question(
|
|
52
|
+
'Would you like to initialize a new git repository? (y/n) ',
|
|
53
|
+
(answer) => {
|
|
54
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
55
|
+
console.log('Initializing Git repository...')
|
|
56
|
+
const initializedGit = runCommand(initGit)
|
|
57
|
+
if (!initializedGit) {
|
|
58
|
+
console.error('Failed to initialize Git repository')
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
console.log('Git repository initialized successfully!')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('\nHappy coding! 🎉')
|
|
65
|
+
rl.close()
|
|
66
|
+
}
|
|
67
|
+
)
|
package/components.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "default",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "tailwind.config.ts",
|
|
8
|
+
"css": "src/styles/globals.css",
|
|
9
|
+
"baseColor": "neutral",
|
|
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
|
+
}
|
package/next.config.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { NextConfig } from 'next'
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
/* config options here */
|
|
5
|
+
eslint: {
|
|
6
|
+
ignoreDuringBuilds: false,
|
|
7
|
+
},
|
|
8
|
+
images: {
|
|
9
|
+
remotePatterns: [
|
|
10
|
+
{ protocol: 'https', hostname: 'v0.dev', pathname: '/placeholder.svg' },
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
logging: {
|
|
14
|
+
fetches: {
|
|
15
|
+
fullUrl: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
compiler:
|
|
19
|
+
process.env.NODE_ENV === 'production' ? { removeConsole: true } : {},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default nextConfig
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ardly/bunext",
|
|
3
|
+
"description": "Bunext - A Next.js 15 template with Tailwind CSS, shadcn ui and Bun with some utilities built in",
|
|
4
|
+
"author": "Ard Astroid <ardastroid@gmail.com>",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"bin": "./bin/cli.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "next dev --turbopack",
|
|
9
|
+
"build": "next build",
|
|
10
|
+
"start": "next start",
|
|
11
|
+
"preview": "next build && next start",
|
|
12
|
+
"lint": "next lint",
|
|
13
|
+
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\""
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@radix-ui/react-avatar": "^1.1.2",
|
|
17
|
+
"@radix-ui/react-dialog": "^1.1.4",
|
|
18
|
+
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
|
19
|
+
"@radix-ui/react-label": "^2.1.1",
|
|
20
|
+
"@radix-ui/react-popover": "^1.1.4",
|
|
21
|
+
"@radix-ui/react-radio-group": "^1.2.2",
|
|
22
|
+
"@radix-ui/react-separator": "^1.1.1",
|
|
23
|
+
"@radix-ui/react-slot": "^1.1.1",
|
|
24
|
+
"@radix-ui/react-toast": "^1.2.4",
|
|
25
|
+
"@radix-ui/react-tooltip": "^1.1.6",
|
|
26
|
+
"class-variance-authority": "^0.7.1",
|
|
27
|
+
"clsx": "^2.1.1",
|
|
28
|
+
"cmdk": "1.0.0",
|
|
29
|
+
"lucide-react": "^0.460.0",
|
|
30
|
+
"next": "15.1.1",
|
|
31
|
+
"next-themes": "^0.4.4",
|
|
32
|
+
"nuqs": "^2.2.3",
|
|
33
|
+
"react": "19.0.0",
|
|
34
|
+
"react-dom": "19.0.0",
|
|
35
|
+
"tailwind-merge": "^2.5.5",
|
|
36
|
+
"tailwindcss-animate": "^1.0.7",
|
|
37
|
+
"vaul": "^1.1.2",
|
|
38
|
+
"zod": "^3.24.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.17.10",
|
|
42
|
+
"@types/react": "19.0.1",
|
|
43
|
+
"@types/react-dom": "19.0.2",
|
|
44
|
+
"eslint": "^8.57.1",
|
|
45
|
+
"eslint-config-next": "15.1.1",
|
|
46
|
+
"eslint-config-prettier": "^9.1.0",
|
|
47
|
+
"fluid-tailwind": "^1.0.4",
|
|
48
|
+
"postcss": "^8.4.49",
|
|
49
|
+
"prettier": "^3.4.2",
|
|
50
|
+
"prettier-plugin-tailwindcss": "^0.6.9",
|
|
51
|
+
"tailwindcss": "^3.4.17",
|
|
52
|
+
"tailwindcss-motion": "^1.0.0",
|
|
53
|
+
"typescript": "^5.7.2"
|
|
54
|
+
},
|
|
55
|
+
"overrides": {
|
|
56
|
+
"@types/react": "19.0.1",
|
|
57
|
+
"@types/react-dom": "19.0.2"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 80 80"><defs><style>.cls-1{fill:url(#linear-gradient);}.cls-2,.cls-3,.cls-4{fill:#070707;}.cls-3{opacity:0.14;}.cls-4{opacity:0.3;}.cls-5{fill:#08090a;}.cls-6{fill:#f18a5c;}</style><linearGradient id="linear-gradient" x1="41.94" y1="17.58" x2="38.61" y2="71.97" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f9f1e1"/><stop offset="1" stop-color="#faf8fa"/></linearGradient></defs><path class="cls-1" d="M74.11,34.38C70.67,27,64.91,23,59,19.35h0a89.47,89.47,0,0,1-11.58-9c-.21-.2-.48-.33-.71-.51a.69.69,0,0,0-1,0C44,11.28,42.48,10.91,41,9.25c-.15-.17-.37-.26-.51-.44-.82-1-1.47-.87-2.31.12-1.82,2.13-2,2.16-4.16.68-1.09-.74-1.81-.53-2.63.47a64.85,64.85,0,0,1-10.08,9.63c-2.71,2.15-5.4,4.34-7.94,6.78A38.59,38.59,0,0,0,4.66,38.16a25,25,0,0,0-1.4,17.2h0c1.37,5.8,4.16,10,9,12A70.48,70.48,0,0,0,31.6,71.92a94.32,94.32,0,0,0,30.29-2.31,37.85,37.85,0,0,0,9.37-3.37A9.56,9.56,0,0,0,76.12,60,35.27,35.27,0,0,0,74.11,34.38Z"/><path class="cls-2" d="M39.34,74.87a81.43,81.43,0,0,1-26.26-4.5C5.59,67.83,1.76,61.53.54,52.52S2.14,36.33,7.05,30C11,25,15.72,21.14,20.46,17.36A69,69,0,0,0,30.19,8c1.67-2,2.49-2.13,4.54-.77a1.49,1.49,0,0,0,2.32-.37c2-2.28,2.27-2.25,4.44-.38a3,3,0,0,1,.42.37C43,8.1,44,8.49,45.27,7.22a1.3,1.3,0,0,1,1.5-.12,8.46,8.46,0,0,1,2.62,1.78c3.76,3.69,8,6.39,12.21,9.19,3.88,2.59,7.68,5.32,10.76,9.27,4.47,5.72,6.78,12.62,7.3,20.46a36.52,36.52,0,0,1-2,14.27,10.57,10.57,0,0,1-4.43,5.81c-3.84,2.43-8,3.58-12.19,4.53A105.83,105.83,0,0,1,39.34,74.87ZM59,19.35a89.47,89.47,0,0,1-11.58-9c-.21-.2-.48-.33-.71-.51a.69.69,0,0,0-1,0C44,11.28,42.48,10.91,41,9.25c-.15-.17-.37-.26-.51-.44-.82-1-1.47-.87-2.31.12-1.82,2.13-2,2.16-4.16.68-1.09-.74-1.81-.53-2.63.47a64.85,64.85,0,0,1-10.08,9.63c-2.71,2.15-5.4,4.34-7.94,6.78A38.59,38.59,0,0,0,4.66,38.16a25,25,0,0,0-1.4,17.2c1.37,5.8,4.15,10,9,12A70.48,70.48,0,0,0,31.6,71.92a94.32,94.32,0,0,0,30.29-2.31,37.85,37.85,0,0,0,9.37-3.37A9.56,9.56,0,0,0,76.12,60a35.27,35.27,0,0,0-2-25.64C70.67,27,64.91,23,59,19.35Z"/><path class="cls-3" d="M3.26,55.36c1.18.51,1.76,1.86,2.57,2.84A25.48,25.48,0,0,0,20.9,67.13a66.14,66.14,0,0,0,16.18.94,77.8,77.8,0,0,0,11.21-1.52,82.55,82.55,0,0,0,14.39-4.33,26.23,26.23,0,0,0,3.77-1.84c3-1.74,4.49-4.73,5.26-8.5a45.47,45.47,0,0,0,.77-8.55,22.15,22.15,0,0,0-4.21-13.81c-2.58-3.49-5.66-6.21-8.64-9.1-.3-.3-.64-.52-.64-1.07C64.91,23,70.67,27,74.11,34.38a35.27,35.27,0,0,1,2,25.64,9.56,9.56,0,0,1-4.86,6.22,37.85,37.85,0,0,1-9.37,3.37A94.32,94.32,0,0,1,31.6,71.92a70.48,70.48,0,0,1-19.38-4.61C7.41,65.38,4.63,61.16,3.26,55.36Z"/><path class="cls-4" d="M37.53,13.92a14.62,14.62,0,0,1,1.83,8.89,5.31,5.31,0,0,1-.69,2.11,14,14,0,0,1-8.9,6.35,5.76,5.76,0,0,1,.91-1.86,36.31,36.31,0,0,1,3.86-5.16,8.82,8.82,0,0,0,2.11-5.09A39.25,39.25,0,0,1,37.53,13.92Z"/><path class="cls-4" d="M41.16,33.28a27.11,27.11,0,0,1,.35-7.78,27.36,27.36,0,0,0-.14-9.34c-.1-.66-.13-1.34-.2-2.05,2.29,1.21,4.32,5.16,4.19,8.39A18.11,18.11,0,0,1,41.16,33.28Z"/><path class="cls-4" d="M51,30.28a18.68,18.68,0,0,1-1.75-6A19.33,19.33,0,0,0,47,17.37c-.46-.84-.81-1.77-1.22-2.68,1.63-.33,4.38,1.37,5.51,3.64C53.24,22.24,52.4,26.14,51,30.28Z"/><path class="cls-4" d="M33.66,13.9C34.9,18.62,32.88,23,29.21,24a8.64,8.64,0,0,1-5.92-.35A8.41,8.41,0,0,1,26.54,21a11.64,11.64,0,0,0,6-5.57A11.68,11.68,0,0,1,33.66,13.9Z"/><path class="cls-5" d="M50.14,50.89a4.48,4.48,0,0,1-4.25-4.74,4.34,4.34,0,1,1,8.64.18A4.44,4.44,0,0,1,50.14,50.89Z"/><path class="cls-5" d="M35.11,58C32.28,57.75,30,56,27.9,53.82a1.15,1.15,0,0,1-.07-1.49.76.76,0,0,1,1.22-.2c.57.45,1.09,1,1.66,1.45,3.64,2.94,6.58,2.74,9.94-.66a2.2,2.2,0,0,0,.2-.23c.49-.64,1-1,1.61-.22a1.36,1.36,0,0,1-.33,1.86A11.49,11.49,0,0,1,35.11,58Z"/><path class="cls-5" d="M21.93,42a4.56,4.56,0,0,1,4.12,4.91,4.51,4.51,0,0,1-4.5,4.46,4.61,4.61,0,0,1-4.14-4.76A4.52,4.52,0,0,1,21.93,42Z"/><path class="cls-6" d="M13.72,53.48a2.42,2.42,0,0,1-2.65-2.2,2.47,2.47,0,0,1,2.63-2.05c1.45,0,2.74,1,2.74,2.12S15.22,53.48,13.72,53.48Z"/><path class="cls-6" d="M57.16,53.57c-1.51,0-2.78-1-2.73-2.11s1.27-2,2.7-2,2.73.84,2.74,2S58.73,53.58,57.16,53.57Z"/></svg>
|
|
Binary file
|
package/public/logo.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 192 192"><defs><style>.cls-1{fill:url(#linear-gradient);}.cls-2,.cls-3{fill:#070707;}.cls-2{opacity:0.14;}.cls-3{opacity:0.3;}.cls-4{fill:#08090a;}.cls-5{fill:#f18a5c;}</style><linearGradient id="linear-gradient" x1="100.54" y1="42.93" x2="92.74" y2="170.51" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f9f1e1"/><stop offset="1" stop-color="#faf8fa"/></linearGradient></defs><path class="cls-1" d="M176,82.34c-8.07-17.28-21.58-26.61-35.47-35.26h0c-9.37-6.43-18.67-13-27.16-21.12a15.65,15.65,0,0,0-1.68-1.22,1.63,1.63,0,0,0-2.27,0c-4,3.39-7.61,2.52-11-1.37-.35-.4-.85-.62-1.19-1-1.91-2.37-3.44-2-5.43.29-4.25,5-4.61,5.07-9.75,1.59C79.5,22.5,77.81,23,75.9,25.33,68.78,34,60.68,41.23,52.25,47.92,45.9,53,39.58,58.09,33.63,63.83,25.57,71.59,18.2,80.12,13.1,91.19c-5.93,12.86-6.9,26.33-3.28,40.36h0c3.21,13.59,9.75,23.5,21,28A164.25,164.25,0,0,0,76.3,170.37c23.87,2.35,47.55,0,71-5.4a89.21,89.21,0,0,0,22-7.9c5.53-2.91,9.33-7.5,11.41-14.6C186.88,121.45,184.92,101.44,176,82.34Z"/><path class="cls-2" d="M9.82,131.55c2.76,1.18,4.13,4.36,6,6.65,9.89,11.9,21.81,18.18,35.34,21,12.61,2.59,25.27,2.71,37.94,2.19,8.81-.36,17.58-1.9,26.31-3.56a194.37,194.37,0,0,0,33.75-10.16,59.46,59.46,0,0,0,8.83-4.31c6.93-4.08,10.54-11.1,12.34-19.94a106.48,106.48,0,0,0,1.82-20.06c.14-12.21-3-23.09-9.89-32.39-6.05-8.18-13.26-14.58-20.25-21.35-.72-.69-1.52-1.2-1.51-2.5,13.89,8.65,27.4,18,35.47,35.26,8.91,19.1,10.87,39.11,4.72,60.13-2.08,7.1-5.88,11.69-11.41,14.6a89.21,89.21,0,0,1-22,7.9c-23.49,5.37-47.17,7.75-71,5.41a164.62,164.62,0,0,1-45.48-10.82C19.57,155.05,13,145.14,9.82,131.55Z"/><path class="cls-3" d="M90.21,34.35c3.55,6.71,5.21,13.39,4.29,20.85a12.59,12.59,0,0,1-1.63,4.95C87.72,68.6,80.53,72.72,72,75a13.88,13.88,0,0,1,2.13-4.35,85.47,85.47,0,0,1,9.06-12.11,20.79,20.79,0,0,0,5-11.94A86.45,86.45,0,0,1,90.21,34.35Z"/><path class="cls-3" d="M98.71,79.76a63.7,63.7,0,0,1,.84-18.26c1.4-7.41.77-14.62-.34-21.9-.23-1.55-.31-3.14-.47-4.82,5.38,2.85,10.15,12.1,9.82,19.69C108.15,64.22,104.6,72.31,98.71,79.76Z"/><path class="cls-3" d="M121.7,72.71a43.74,43.74,0,0,1-4.09-14,45.43,45.43,0,0,0-5.21-16.24c-1.08-2-1.9-4.14-2.86-6.29,3.81-.77,10.26,3.22,12.92,8.54C127.05,53.86,125.09,63,121.7,72.71Z"/><path class="cls-3" d="M81.13,34.29C84,45.36,79.3,55.69,70.69,58c-5,1.33-10,1.07-13.89-.83A19.68,19.68,0,0,1,64.43,51a27.38,27.38,0,0,0,14-13.09A30.63,30.63,0,0,1,81.13,34.29Z"/><path class="cls-4" d="M119.78,121.06c-5.62-.07-10.11-5.07-10-11.12S114.6,99,120.13,99.15s10.06,5.17,10,11.21S125.47,121.13,119.78,121.06Z"/><path class="cls-4" d="M84.54,137.83c-6.65-.67-12-4.86-16.93-9.89a2.68,2.68,0,0,1-.15-3.5,1.79,1.79,0,0,1,2.86-.48c1.33,1.06,2.56,2.33,3.88,3.4,8.54,6.91,15.44,6.44,23.32-1.54a5.82,5.82,0,0,0,.46-.53c1.15-1.5,2.45-2.4,3.79-.52,1.2,1.69.35,3.18-.77,4.37A27,27,0,0,1,84.54,137.83Z"/><path class="cls-4" d="M53.61,100.24c5.61.29,10,5.46,9.68,11.51s-5.12,10.79-10.57,10.45-9.8-5.31-9.7-11.15C43.12,104.87,48,100,53.61,100.24Z"/><path class="cls-5" d="M34.35,127.13c-3.5,0-6.33-2.34-6.22-5.15.12-2.65,2.86-4.78,6.19-4.82s6.41,2.29,6.42,5S37.87,127.12,34.35,127.13Z"/><path class="cls-5" d="M136.24,127.36c-3.54,0-6.51-2.33-6.39-5s3-4.63,6.32-4.69c3.67-.06,6.41,2,6.43,4.8S139.93,127.37,136.24,127.36Z"/></svg>
|
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Bunext",
|
|
3
|
+
"short_name": "Bunext",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "/android-chrome-192x192.png",
|
|
7
|
+
"sizes": "192x192",
|
|
8
|
+
"type": "image/png"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"src": "/android-chrome-512x512.png",
|
|
12
|
+
"sizes": "512x512",
|
|
13
|
+
"type": "image/png"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"theme_color": "#fbf0df",
|
|
17
|
+
"background_color": "#2d2b2a",
|
|
18
|
+
"display": "standalone"
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import sharp from 'sharp';
|
|
5
|
+
function bufferToBase64(buffer: Buffer): string {
|
|
6
|
+
return `data:image/png;base64,${buffer.toString('base64')}`;
|
|
7
|
+
}
|
|
8
|
+
async function getFileBufferLocal(src: string) {
|
|
9
|
+
const realsrc = path.join(process.cwd(), 'public', src);
|
|
10
|
+
return fs.readFile(realsrc);
|
|
11
|
+
}
|
|
12
|
+
async function getFileBufferRemote(url: string) {
|
|
13
|
+
const response = await fetch(url);
|
|
14
|
+
return Buffer.from(await response.arrayBuffer());
|
|
15
|
+
}
|
|
16
|
+
function getFileBuffer(src: string) {
|
|
17
|
+
const isRemote = src.startsWith('http');
|
|
18
|
+
return isRemote ? getFileBufferRemote(src) : getFileBufferLocal(src);
|
|
19
|
+
}
|
|
20
|
+
export async function getPlaceholderImage(src: string) {
|
|
21
|
+
try {
|
|
22
|
+
const originalBuffer = await (src.startsWith('http')
|
|
23
|
+
? getFileBuffer(src)
|
|
24
|
+
: getFileBufferLocal(src));
|
|
25
|
+
const resizedBuffer = await sharp(originalBuffer).resize(20).toBuffer();
|
|
26
|
+
return bufferToBase64(resizedBuffer);
|
|
27
|
+
} catch {
|
|
28
|
+
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOsa2yqBwAFCAICLICSyQAAAABJRU5ErkJggg==';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
|
|
3
|
+
import { revalidatePath } from 'next/cache'
|
|
4
|
+
import { redirect } from 'next/navigation'
|
|
5
|
+
|
|
6
|
+
export async function createSampleItem(formData: FormData) {
|
|
7
|
+
try {
|
|
8
|
+
const rawFormData = {
|
|
9
|
+
title: formData.get('title'),
|
|
10
|
+
description: formData.get('description'),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Sample validation
|
|
14
|
+
if (!rawFormData.title || !rawFormData.description) {
|
|
15
|
+
throw new Error('Title and description are required')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Here you would typically:
|
|
19
|
+
// 1. Validate the data
|
|
20
|
+
// 2. Insert into database
|
|
21
|
+
// 3. Handle any errors
|
|
22
|
+
|
|
23
|
+
// Sample success path
|
|
24
|
+
revalidatePath('/items') // Revalidate the items list
|
|
25
|
+
redirect('/items') // Redirect to items page
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Handle errors appropriately
|
|
28
|
+
if (error instanceof Error) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: error.message,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
error: 'Something went wrong',
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { useIntersection } from '@/hooks/use-intersection'
|
|
3
|
+
import { cn } from '@/lib/utils'
|
|
4
|
+
|
|
5
|
+
type TTestCard = {
|
|
6
|
+
className?: string
|
|
7
|
+
index: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function TestCard({ className, index }: TTestCard) {
|
|
11
|
+
const { ref, isInView } = useIntersection({ threshold: 0.2, once: true })
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn(
|
|
16
|
+
'w-full max-w-md rounded-lg bg-muted/45 p-6 shadow-lg transition-opacity duration-500',
|
|
17
|
+
isInView
|
|
18
|
+
? 'motion-scale-in-[0.41] motion-translate-x-in-[2%] motion-translate-y-in-[111%] motion-blur-in-[60px] motion-delay-75'
|
|
19
|
+
: 'opacity-0',
|
|
20
|
+
className
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
<h2 className="mb-4 text-2xl font-semibold">Card {index + 1}</h2>
|
|
24
|
+
<p className="text-muted-foreground">
|
|
25
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
|
|
26
|
+
tempfwfor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
|
27
|
+
veniam.
|
|
28
|
+
</p>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TestCard } from './TestCard'
|
|
2
|
+
|
|
3
|
+
export default function Page() {
|
|
4
|
+
// Simulate a production error
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<main className="container mx-auto">
|
|
8
|
+
<div className="flex flex-col items-center gap-8 py-12">
|
|
9
|
+
<h1 className="text-4xl font-bold">Scroll Intersection Example</h1>
|
|
10
|
+
|
|
11
|
+
{Array.from({ length: 20 }).map((_, i) => (
|
|
12
|
+
<TestCard key={i} index={i} />
|
|
13
|
+
))}
|
|
14
|
+
</div>
|
|
15
|
+
</main>
|
|
16
|
+
)
|
|
17
|
+
}
|