feat: add NSUI components and support preview

- Added Cloudinary as an allowed image domain in next.config.ts for image optimization.
- Included new dependencies: react-use-measure and use-media in package.json for enhanced UI responsiveness.
- Introduced a service worker for caching iframe content to improve performance.
- Added multiple new block components and layouts for enhanced UI features and organization.
- Implemented utility functions and motion primitives for improved animations and effects.
This commit is contained in:
javayhu 2025-03-25 00:40:22 +08:00
parent ef740e23db
commit cc0f17f722
104 changed files with 8345 additions and 40 deletions

View File

@ -7,7 +7,7 @@ import { withContentCollections } from "@content-collections/next";
*/
const nextConfig: NextConfig = {
/* config options here */
// https://nextjs.org/docs/architecture/nextjs-compiler#remove-console
// Remove all console.* calls in production only
compiler: {
@ -27,7 +27,11 @@ const nextConfig: NextConfig = {
{
protocol: "https",
hostname: "randomuser.me",
}
},
{
protocol: 'https',
hostname: 'res.cloudinary.com',
},
],
},
};

View File

@ -84,6 +84,7 @@
"react-hook-form": "^7.54.2",
"react-remove-scroll": "^2.6.3",
"react-resizable-panels": "^2.1.7",
"react-use-measure": "^2.1.7",
"recharts": "^2.15.1",
"rehype-autolink-headings": "^7.1.0",
"rehype-pretty-code": "^0.14.0",
@ -101,6 +102,7 @@
"tw-animate-css": "^1.2.4",
"unist-util-visit": "^5.0.0",
"use-intl": "^3.26.5",
"use-media": "^1.5.0",
"vaul": "^1.1.2",
"zod": "^3.24.2",
"zustand": "^5.0.3"

68
pnpm-lock.yaml generated
View File

@ -230,6 +230,9 @@ importers:
react-resizable-panels:
specifier: ^2.1.7
version: 2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react-use-measure:
specifier: ^2.1.7
version: 2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
recharts:
specifier: ^2.15.1
version: 2.15.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@ -281,6 +284,9 @@ importers:
use-intl:
specifier: ^3.26.5
version: 3.26.5(react@19.0.0)
use-media:
specifier: ^1.5.0
version: 1.5.0(react@19.0.0)
vaul:
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.9))(@types/react@19.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@ -656,28 +662,24 @@ packages:
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@biomejs/cli-linux-arm64@1.9.4':
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@biomejs/cli-linux-x64-musl@1.9.4':
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
libc: [musl]
'@biomejs/cli-linux-x64@1.9.4':
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@biomejs/cli-win32-arm64@1.9.4':
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
@ -1565,79 +1567,67 @@ packages:
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-arm@1.0.5':
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.0.4':
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-x64@1.0.4':
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
cpu: [x64]
os: [linux]
libc: [musl]
'@img/sharp-linux-arm64@0.33.5':
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-arm@0.33.5':
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
libc: [glibc]
'@img/sharp-linux-s390x@0.33.5':
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@img/sharp-linux-x64@0.33.5':
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.33.5':
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@img/sharp-linuxmusl-x64@0.33.5':
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@img/sharp-wasm32@0.33.5':
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
@ -1727,56 +1717,48 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@next/swc-linux-arm64-gnu@15.2.1':
resolution: {integrity: sha512-gXDX5lIboebbjhiMT6kFgu4svQyjoSed6dHyjx5uZsjlvTwOAnZpn13w9XDaIMFFHw7K8CpBK7HfDKw0VZvUXQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@next/swc-linux-arm64-musl@15.1.2':
resolution: {integrity: sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@next/swc-linux-arm64-musl@15.2.1':
resolution: {integrity: sha512-3v0pF/adKZkBWfUffmB/ROa+QcNTrnmYG4/SS+r52HPwAK479XcWoES2I+7F7lcbqc7mTeVXrIvb4h6rR/iDKg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@next/swc-linux-x64-gnu@15.1.2':
resolution: {integrity: sha512-tINV7WmcTUf4oM/eN3Yuu/f8jQ5C6AkueZPKeALs/qfdfX57eNv4Ij7rt0SA6iZ8+fMobVfcFVv664Op0caCCg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@next/swc-linux-x64-gnu@15.2.1':
resolution: {integrity: sha512-RbsVq2iB6KFJRZ2cHrU67jLVLKeuOIhnQB05ygu5fCNgg8oTewxweJE8XlLV+Ii6Y6u4EHwETdUiRNXIAfpBww==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@next/swc-linux-x64-musl@15.1.2':
resolution: {integrity: sha512-jf2IseC4WRsGkzeUw/cK3wci9pxR53GlLAt30+y+B+2qAQxMw6WAC3QrANIKxkcoPU3JFh/10uFfmoMDF9JXKg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@next/swc-linux-x64-musl@15.2.1':
resolution: {integrity: sha512-QHsMLAyAIu6/fWjHmkN/F78EFPKmhQlyX5C8pRIS2RwVA7z+t9cTb0IaYWC3EHLOTjsU7MNQW+n2xGXr11QPpg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@next/swc-win32-arm64-msvc@15.1.2':
resolution: {integrity: sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==}
@ -1845,42 +1827,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@ -2972,28 +2948,24 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.0.14':
resolution: {integrity: sha512-gVkJdnR/L6iIcGYXx64HGJRmlme2FGr/aZH0W6u4A3RgPMAb+6ELRLi+UBiH83RXBm9vwCfkIC/q8T51h8vUJQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.0.14':
resolution: {integrity: sha512-EE+EQ+c6tTpzsg+LGO1uuusjXxYx0Q00JE5ubcIGfsogSKth8n8i2BcS2wYTQe4jXGs+BQs35l78BIPzgwLddw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.0.14':
resolution: {integrity: sha512-KCCOzo+L6XPT0oUp2Jwh233ETRQ/F6cwUnMnR0FvMUCbkDAzHbcyOgpfuAtRa5HD0WbTbH4pVD+S0pn1EhNfbw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@tailwindcss/oxide-win32-arm64-msvc@4.0.14':
resolution: {integrity: sha512-AHObFiFL9lNYcm3tZSPqa/cHGpM5wOrNmM2uOMoKppp+0Hom5uuyRh0QkOp7jftsHZdrZUpmoz0Mp6vhh2XtUg==}
@ -4103,28 +4075,24 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.29.2:
resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.29.2:
resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.29.2:
resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.29.2:
resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==}
@ -4807,6 +4775,15 @@ packages:
react: '>=16.6.0'
react-dom: '>=16.6.0'
react-use-measure@2.1.7:
resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==}
peerDependencies:
react: '>=16.13'
react-dom: '>=16.13'
peerDependenciesMeta:
react-dom:
optional: true
react@19.0.0:
resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
engines: {node: '>=0.10.0'}
@ -5262,6 +5239,11 @@ packages:
peerDependencies:
react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
use-media@1.5.0:
resolution: {integrity: sha512-gEKsAwpqeejjLXllfQLlktok4CX3cpsS0TChDR9VTl3xQ/231jWujjebnJrt+IH50RRO163JPvHVKBj+W+Weqg==}
peerDependencies:
react: '*'
use-sidecar@1.1.3:
resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
engines: {node: '>=10'}
@ -10296,6 +10278,12 @@ snapshots:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
react-use-measure@2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
react: 19.0.0
optionalDependencies:
react-dom: 19.0.0(react@19.0.0)
react@19.0.0: {}
readable-stream@3.6.2:
@ -10891,6 +10879,10 @@ snapshots:
intl-messageformat: 10.7.15
react: 19.0.0
use-media@1.5.0(react@19.0.0):
dependencies:
react: 19.0.0
use-sidecar@1.1.3(@types/react@19.0.9)(react@19.0.0):
dependencies:
detect-node-es: 1.1.0

BIN
public/blocks/card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

BIN
public/blocks/charts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
public/blocks/exercice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

BIN
public/blocks/mail-back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

BIN
public/blocks/mail2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

BIN
public/blocks/music.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

BIN
public/blocks/payments.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

129
public/sw.js Normal file
View File

@ -0,0 +1,129 @@
// Service Worker for caching iframe content
const CACHE_NAME = 'cnblocks-iframe-cache-v1'
// Add iframe URLs to this list to prioritize caching
const URLS_TO_CACHE = [
// Default assets that should be cached
'/favicon.ico',
// Images used in iframes
'/payments.png',
'/payments-light.png',
'/origin-cal.png',
'/origin-cal-dark.png',
'/exercice.png',
'/exercice-dark.png',
'/charts-light.png',
'/charts.png',
'/music-light.png',
'/music.png',
'/mail-back-light.png',
'/mail-upper.png',
'/mail-back.png',
'/card.png',
'/dark-card.webp',
]
// Install event - cache resources
self.addEventListener('install', (event) => {
event.waitUntil(
caches
.open(CACHE_NAME)
.then((cache) => {
console.log('Opened cache')
return cache.addAll(URLS_TO_CACHE)
})
.then(() => self.skipWaiting()) // Activate SW immediately
)
})
// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
const currentCaches = [CACHE_NAME]
event.waitUntil(
caches
.keys()
.then((cacheNames) => {
return cacheNames.filter((cacheName) => !currentCaches.includes(cacheName))
})
.then((cachesToDelete) => {
return Promise.all(
cachesToDelete.map((cacheToDelete) => {
return caches.delete(cacheToDelete)
})
)
})
.then(() => self.clients.claim()) // Take control of clients immediately
)
})
// Fetch event - serve from cache or fetch from network and cache
self.addEventListener('fetch', (event) => {
// Check if this is an iframe request - typically they'll be HTML or have 'preview' in the URL
const isIframeRequest = event.request.url.includes('/preview/') || event.request.url.includes('/examples/')
if (isIframeRequest) {
event.respondWith(
caches.match(event.request, { ignoreSearch: true }).then((response) => {
// Return cached response if found
if (response) {
return response
}
// Clone the request (requests are one-time use)
const fetchRequest = event.request.clone()
return fetch(fetchRequest).then((response) => {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response
}
// Clone the response (responses are one-time use)
const responseToCache = response.clone()
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache)
})
return response
})
})
)
} else {
// For non-iframe requests, use a standard cache-first strategy
event.respondWith(
caches.match(event.request).then((response) => {
if (response) {
return response
}
return fetch(event.request)
})
)
}
})
// Listen for messages from clients (to force cache update, etc)
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting()
}
// Handle cache clearing
if (event.data && event.data.type === 'CLEAR_IFRAME_CACHE') {
const url = event.data.url
if (url) {
// Clear specific URL from cache
caches.open(CACHE_NAME).then((cache) => {
cache.delete(url).then(() => {
console.log(`Cleared cache for: ${url}`)
})
})
} else {
// Clear the entire cache
caches.delete(CACHE_NAME).then(() => {
console.log('Cleared entire iframe cache')
})
}
}
})

View File

@ -0,0 +1,15 @@
import CategoryNavigation from '@/components/nsui/blocks-nav'
import { categories } from '@/components/nsui/blocks'
export default function CategoryLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<>
<CategoryNavigation categories={categories} />
<main>{children}</main>
</>
)
}

View File

@ -0,0 +1,51 @@
import BlockPreview from '@/components/nsui/block-preview'
import { blocks, categories } from '@/components/nsui/blocks'
import { notFound } from 'next/navigation'
interface PageProps {
params: Promise<{ category: string }>
}
export const dynamic = 'force-static'
export const revalidate = 3600
export async function generateStaticParams() {
return categories.map((category) => ({
category: category,
}))
}
export async function generateMetadata({ params }: PageProps) {
const { category } = await params
return {
title: `Shadcn ${category} Blocks`,
}
}
export default async function CategoryPage({ params }: PageProps) {
const { category } = await params
const categoryBlocks = blocks.filter((b) => b.category === category)
if (categoryBlocks.length === 0) {
notFound()
}
return (
<>
<section>
<h1 className="sr-only text-3xl font-bold sm:text-4xl md:text-nowrap">
Shadcn <span className="capitalize">{category}</span> blocks
</h1>
<p className="sr-only text-base md:text-lg">Speed up your workflow with responsive, pre-built UI blocks designed for marketing websites.</p>
<div className="h-6 w-full bg-[repeating-linear-gradient(-45deg,var(--color-border),var(--color-border)_1px,transparent_1px,transparent_6px)] opacity-35"></div>
</section>
{categoryBlocks.map((block, index) => (
<BlockPreview
{...block}
key={index}
/>
))}
</>
)
}

View File

@ -0,0 +1,29 @@
import { Button } from '@/components/ui/button'
import Link from 'next/link'
export default function CallToAction() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-5xl">Start Building</h2>
<p className="mt-4">Libero sapiente aliquam quibusdam aspernatur.</p>
<div className="mt-12 flex flex-wrap justify-center gap-4">
<Button asChild size="lg">
<Link href="/">
<span>Get Started</span>
</Link>
</Button>
<Button asChild size="lg" variant="outline">
<Link href="/">
<span>Book Demo</span>
</Link>
</Button>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,30 @@
import { Button } from '@/components/ui/button'
import { Mail, SendHorizonal } from 'lucide-react'
export default function CallToAction() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-5xl">Start Building</h2>
<p className="mt-4">Libero sapiente aliquam quibusdam aspernatur.</p>
<form action="" className="mx-auto mt-10 max-w-sm lg:mt-12">
<div className="bg-background has-[input:focus]:ring-muted relative grid grid-cols-[1fr_auto] items-center rounded-[calc(var(--radius)+0.75rem)] border pr-3 shadow shadow-zinc-950/5 has-[input:focus]:ring-2">
<Mail className="text-caption pointer-events-none absolute inset-y-0 left-5 my-auto size-5" />
<input placeholder="Your mail address" className="h-14 w-full bg-transparent pl-12 focus:outline-none" type="email" />
<div className="md:pr-1.5 lg:pr-0">
<Button aria-label="submit" className="rounded-(--radius)">
<span className="hidden md:block">Get Started</span>
<SendHorizonal className="relative mx-auto size-5 md:hidden" strokeWidth={2} />
</Button>
</div>
</div>
</form>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,29 @@
import { Button } from '@/components/ui/button'
import Link from 'next/link'
export default function CallToAction() {
return (
<section className="py-16">
<div className="mx-auto max-w-5xl rounded-3xl border px-6 py-12 md:py-20 lg:py-32">
<div className="text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-5xl">Start Building</h2>
<p className="mt-4">Libero sapiente aliquam quibusdam aspernatur.</p>
<div className="mt-12 flex flex-wrap justify-center gap-4">
<Button asChild size="lg">
<Link href="/">
<span>Get Started</span>
</Link>
</Button>
<Button asChild size="lg" variant="outline">
<Link href="/">
<span>Book Demo</span>
</Link>
</Button>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,179 @@
import { Button } from '@/components/ui/button'
import { Cpu, Sparkles } from 'lucide-react'
import Link from 'next/link'
const tableData = [
{
feature: 'Feature 1',
free: true,
pro: true,
startup: true,
},
{
feature: 'Feature 2',
free: true,
pro: true,
startup: true,
},
{
feature: 'Feature 3',
free: false,
pro: true,
startup: true,
},
{
feature: 'Tokens',
free: '',
pro: '20 Users',
startup: 'Unlimited',
},
{
feature: 'Video calls',
free: '',
pro: '12 Weeks',
startup: '56',
},
{
feature: 'Support',
free: '',
pro: 'Secondes',
startup: 'Unlimited',
},
{
feature: 'Security',
free: '',
pro: '20 Users',
startup: 'Unlimited',
},
]
export default function PricingComparator() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="w-full overflow-auto lg:overflow-visible">
<table className="w-[200vw] border-separate border-spacing-x-3 md:w-full dark:[--color-muted:var(--color-zinc-900)]">
<thead className="bg-background sticky top-0">
<tr className="*:py-4 *:text-left *:font-medium">
<th className="lg:w-2/5"></th>
<th className="space-y-3">
<span className="block">Free</span>
<Button asChild variant="outline" size="sm">
<Link href="#">Get Started</Link>
</Button>
</th>
<th className="bg-muted rounded-t-(--radius) space-y-3 px-4">
<span className="block">Pro</span>
<Button asChild size="sm">
<Link href="#">Get Started</Link>
</Button>
</th>
<th className="space-y-3">
<span className="block">Startup</span>
<Button asChild variant="outline" size="sm">
<Link href="#">Get Started</Link>
</Button>
</th>
</tr>
</thead>
<tbody className="text-caption text-sm">
<tr className="*:py-3">
<td className="flex items-center gap-2 font-medium">
<Cpu className="size-4" />
<span>Features</span>
</td>
<td></td>
<td className="bg-muted border-none px-4"></td>
<td></td>
</tr>
{tableData.slice(-4).map((row, index) => (
<tr key={index} className="*:border-b *:py-3">
<td className="text-muted-foreground">{row.feature}</td>
<td>
{row.free === true ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-4">
<path fillRule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clipRule="evenodd" />
</svg>
) : (
row.free
)}
</td>
<td className="bg-muted border-none px-4">
<div className="-mb-3 border-b py-3">
{row.pro === true ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-4">
<path fillRule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clipRule="evenodd" />
</svg>
) : (
row.pro
)}
</div>
</td>
<td>
{row.startup === true ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-4">
<path fillRule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clipRule="evenodd" />
</svg>
) : (
row.startup
)}
</td>
</tr>
))}
<tr className="*:pb-3 *:pt-8">
<td className="flex items-center gap-2 font-medium">
<Sparkles className="size-4" />
<span>AI Models</span>
</td>
<td></td>
<td className="bg-muted border-none px-4"></td>
<td></td>
</tr>
{tableData.map((row, index) => (
<tr key={index} className="*:border-b *:py-3">
<td className="text-muted-foreground">{row.feature}</td>
<td>
{row.free === true ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-4">
<path fillRule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clipRule="evenodd" />
</svg>
) : (
row.free
)}
</td>
<td className="bg-muted border-none px-4">
<div className="-mb-3 border-b py-3">
{row.pro === true ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-4">
<path fillRule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clipRule="evenodd" />
</svg>
) : (
row.pro
)}
</div>
</td>
<td>
{row.startup === true ? (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-4">
<path fillRule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clipRule="evenodd" />
</svg>
) : (
row.startup
)}
</td>
</tr>
))}
<tr className="*:py-6">
<td></td>
<td></td>
<td className="bg-muted rounded-b-(--radius) border-none px-4"></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,78 @@
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Card } from '@/components/ui/card'
export default function ContactSection() {
return (
<section className="py-32">
<div className="mx-auto max-w-3xl px-8 lg:px-0">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Contact Sales</h1>
<p className="mt-4 text-center">We'll help you find the right plan and pricing for your business.</p>
<Card className="mx-auto mt-12 max-w-lg p-8 shadow-md sm:p-16">
<div>
<h2 className="text-xl font-semibold">Let's get you to the right place</h2>
<p className="mt-4 text-sm">Reach out to our sales team! Were eager to learn more about how you plan to use our application.</p>
</div>
<form action="" className="**:[&>label]:block mt-12 space-y-6 *:space-y-3">
<div>
<Label htmlFor="name">Full name</Label>
<Input type="text" id="name" required />
</div>
<div>
<Label htmlFor="email">Work Email</Label>
<Input type="email" id="email" required />
</div>
<div>
<Label htmlFor="country">Country/Region</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select Country/Region" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">DR Congo</SelectItem>
<SelectItem value="2">United States</SelectItem>
<SelectItem value="3">France</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="website">Company Website</Label>
<Input type="url" id="website" />
<span className="text-muted-foreground inline-block text-sm">Must start with 'https'</span>
</div>
<div>
<Label htmlFor="job">Job function</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select Job Function" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">Finance</SelectItem>
<SelectItem value="2">Education</SelectItem>
<SelectItem value="3">Legal</SelectItem>
<SelectItem value="4">More</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="msg">Message</Label>
<Textarea id="msg" rows={3} />
</div>
<Button>Submit</Button>
</form>
</Card>
</div>
</section>
)
}

View File

@ -0,0 +1,105 @@
import { Card } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import Link from 'next/link'
export default function ContactSection() {
return (
<section className="py-32">
<div className="mx-auto max-w-4xl px-4 lg:px-0">
<h1 className="mb-12 text-center text-4xl font-semibold lg:text-5xl">Help us route your inquiry</h1>
<div className="grid divide-y border md:grid-cols-2 md:gap-4 md:divide-x md:divide-y-0">
<div className="flex flex-col justify-between space-y-8 p-6 sm:p-12">
<div>
<h2 className="mb-3 text-lg font-semibold">Collaborate</h2>
<Link href="mailto:hello@tailus.io" className="text-lg text-blue-600 hover:underline dark:text-blue-400">
hello@tailus.io
</Link>
<p className="mt-3 text-sm">+243 000 000 000</p>
</div>
</div>
<div className="flex flex-col justify-between space-y-8 p-6 sm:p-12">
<div>
<h3 className="mb-3 text-lg font-semibold">Press</h3>
<Link href="mailto:press@tailus.io" className="text-lg text-blue-600 hover:underline dark:text-blue-400">
press@tailus.io
</Link>
<p className="mt-3 text-sm">+243 000 000 000</p>
</div>
</div>
</div>
<div className="h-3 border-x bg-[repeating-linear-gradient(-45deg,var(--color-border),var(--color-border)_1px,transparent_1px,transparent_6px)]"></div>
<form action="" className="border px-4 py-12 lg:px-0 lg:py-24">
<Card className="mx-auto max-w-lg p-8 sm:p-16">
<h3 className="text-xl font-semibold">Let's get you to the right place</h3>
<p className="mt-4 text-sm">Reach out to our sales team! Were eager to learn more about how you plan to use our application.</p>
<div className="**:[&>label]:block mt-12 space-y-6 *:space-y-3">
<div>
<Label htmlFor="name" className="space-y-2">
Full name
</Label>
<Input type="text" id="name" required />
</div>
<div>
<Label htmlFor="email" className="space-y-2">
Work Email
</Label>
<Input type="email" id="email" required />
</div>
<div>
<Label htmlFor="country" className="space-y-2">
Country/Region
</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select a country" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">DR Congo</SelectItem>
<SelectItem value="2">United States</SelectItem>
<SelectItem value="3">France</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="website" className="space-y-2">
Company Website
</Label>
<Input type="url" id="website" />
</div>
<div>
<Label htmlFor="job" className="space-y-2">
Job function
</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select a job function" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">Finance</SelectItem>
<SelectItem value="2">Education</SelectItem>
<SelectItem value="3">Legal</SelectItem>
<SelectItem value="4">More</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="msg" className="space-y-2">
Message
</Label>
<Textarea id="msg" rows={3} />
</div>
<Button>Submit</Button>
</div>
</Card>
</form>
</div>
</section>
)
}

View File

@ -0,0 +1,47 @@
import { Cpu, Lock, Sparkles, Zap } from 'lucide-react'
export default function ContentSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-12">
<div className="mx-auto max-w-xl space-y-6 text-center md:space-y-12">
<h2 className="text-balance text-4xl font-medium lg:text-5xl">The Lyra ecosystem brings together our models, products and platforms.</h2>
<p>Lyra is evolving to be more than just the models. It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<img className="rounded-(--radius) grayscale" src="https://images.unsplash.com/photo-1616587226960-4a03badbe8bf?q=80&w=2940&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="team image" height="" width="" loading="lazy" />
<div className="relative mx-auto grid grid-cols-2 gap-x-3 gap-y-6 sm:gap-8 lg:grid-cols-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Zap className="size-4" />
<h3 className="text-sm font-medium">Faaast</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Cpu className="size-4" />
<h3 className="text-sm font-medium">Powerful</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and businesses.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Lock className="size-4" />
<h3 className="text-sm font-medium">Security</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an helping developers businesses innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Sparkles className="size-4" />
<h3 className="text-sm font-medium">AI Powered</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an helping developers businesses innovate.</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,27 @@
import { Button } from '@/components/ui/button'
import { ChevronRight } from 'lucide-react'
import Link from 'next/link'
export default function ContentSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="grid gap-6 md:grid-cols-2 md:gap-12">
<h2 className="text-4xl font-medium">The Lyra ecosystem brings together our models, products and platforms.</h2>
<div className="space-y-6">
<p>Lyra is evolving to be more than just the models. It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate.</p>
<p>
Tailus UI. <span className="font-bold">It supports an entire ecosystem</span> from products innovate. Sit minus, quod debitis autem quia aspernatur delectus impedit modi, neque non id ad dignissimos? Saepe deleniti perferendis beatae.
</p>
<Button asChild variant="secondary" size="sm" className="gap-1 pr-1.5">
<Link href="#">
<span>Learn More</span>
<ChevronRight className="size-2" />
</Link>
</Button>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,37 @@
import Image from 'next/image'
export default function ContentSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<h2 className="relative z-10 max-w-xl text-4xl font-medium lg:text-5xl">The Lyra ecosystem brings together our models.</h2>
<div className="grid gap-6 sm:grid-cols-2 md:gap-12 lg:gap-24">
<div className="relative mb-6 sm:mb-0">
<div className="bg-linear-to-b aspect-76/59 relative rounded-2xl from-zinc-300 to-transparent p-px dark:from-zinc-700">
<Image src="/blocks/payments.png" className="hidden rounded-[15px] dark:block" alt="payments illustration dark" width={1207} height={929} />
<Image src="/blocks/payments-light.png" className="rounded-[15px] shadow dark:hidden" alt="payments illustration light" width={1207} height={929} />
</div>
</div>
<div className="relative space-y-4">
<p className="text-muted-foreground">
Gemini is evolving to be more than just the models. <span className="text-accent-foreground font-bold">It supports an entire ecosystem</span> from products innovate.
</p>
<p className="text-muted-foreground">It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate</p>
<div className="pt-6">
<blockquote className="border-l-4 pl-4">
<p>Using TailsUI has been like unlocking a secret design superpower. It's the perfect fusion of simplicity and versatility, enabling us to create UIs that are as stunning as they are user-friendly.</p>
<div className="mt-6 space-y-3">
<cite className="block font-medium">John Doe, CEO</cite>
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
</div>
</blockquote>
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,43 @@
import { Cpu, Zap } from 'lucide-react'
import Image from 'next/image'
export default function ContentSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<h2 className="relative z-10 max-w-xl text-4xl font-medium lg:text-5xl">The Lyra ecosystem brings together our models.</h2>
<div className="grid gap-6 sm:grid-cols-2 md:gap-12 lg:gap-24">
<div className="relative space-y-4">
<p className="text-muted-foreground">
Gemini is evolving to be more than just the models. <span className="text-accent-foreground font-bold">It supports an entire ecosystem</span> from products innovate.
</p>
<p className="text-muted-foreground">It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate</p>
<div className="grid grid-cols-2 gap-3 pt-6 sm:gap-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Zap className="size-4" />
<h3 className="text-sm font-medium">Faaast</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Cpu className="size-4" />
<h3 className="text-sm font-medium">Powerful</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and businesses.</p>
</div>
</div>
</div>
<div className="relative mt-6 sm:mt-0">
<div className="bg-linear-to-b aspect-67/34 relative rounded-2xl from-zinc-300 to-transparent p-px dark:from-zinc-700">
<Image src="/blocks/exercice-dark.png" className="hidden rounded-[15px] dark:block" alt="payments illustration dark" width={1206} height={612} />
<Image src="/blocks/exercice.png" className="rounded-[15px] shadow dark:hidden" alt="payments illustration light" width={1206} height={612} />
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,51 @@
import Link from 'next/link'
export default function CommunitySection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="text-center">
<h2 className="text-3xl font-semibold">
Built by the Community <br /> for the Community
</h2>
<p className="mt-6">Harum quae dolore orrupti aut temporibus ariatur.</p>
</div>
<div className="mx-auto mt-12 flex max-w-lg flex-wrap justify-center gap-3">
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/1.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/2.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/3.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/4.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/5.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/6.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/7.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/1.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/8.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/9.jpg" loading="lazy" width={120} height={120} />
</Link>
<Link href="https://github.com/meschacirung" target="_blank" title="Méschac Irung" className="size-16 rounded-full border *:size-full *:rounded-full *:object-cover">
<img alt="John Doe" src="https://randomuser.me/api/portraits/men/10.jpg" loading="lazy" width={120} height={120} />
</Link>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,27 @@
import { Button } from '@/components/ui/button'
import { ChevronRight } from 'lucide-react'
import Link from 'next/link'
export default function ContentSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-12">
<img className="rounded-(--radius) grayscale" src="https://images.unsplash.com/photo-1530099486328-e021101a494a?q=80&w=2747&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="team image" height="" width="" loading="lazy" />
<div className="grid gap-6 md:grid-cols-2 md:gap-12">
<h2 className="text-4xl font-medium">The Lyra ecosystem brings together our models, products and platforms.</h2>
<div className="space-y-6">
<p>Lyra is evolving to be more than just the models. It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate.</p>
<Button asChild variant="secondary" size="sm" className="gap-1 pr-1.5">
<Link href="#">
<span>Learn More</span>
<ChevronRight className="size-2" />
</Link>
</Button>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,44 @@
import { Cpu, Zap } from 'lucide-react'
import Image from 'next/image'
export default function ContentSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<h2 className="relative z-10 max-w-xl text-4xl font-medium lg:text-5xl">The Lyra ecosystem brings together our models.</h2>
<div className="relative">
<div className="relative z-10 space-y-4 md:w-1/2">
<p className="text-body">
Lyra is evolving to be more than just the models. <span className="text-title font-medium">It supports an entire ecosystem</span> from products innovate.
</p>
<p>It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate</p>
<div className="grid grid-cols-2 gap-3 pt-6 sm:gap-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Zap className="size-4" />
<h3 className="text-sm font-medium">Faaast</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Cpu className="size-4" />
<h3 className="text-sm font-medium">Powerful</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and businesses.</p>
</div>
</div>
</div>
<div className="mt-12 h-fit md:absolute md:-inset-y-12 md:inset-x-0 md:mt-0">
<div aria-hidden className="bg-linear-to-l z-1 to-background absolute inset-0 hidden from-transparent to-55% md:block"></div>
<div className="border-border/50 relative rounded-2xl border border-dotted p-2">
<Image src="/blocks/charts.png" className="hidden rounded-[12px] dark:block" alt="payments illustration dark" width={1207} height={929} />
<Image src="/blocks/charts-light.png" className="rounded-[12px] shadow dark:hidden" alt="payments illustration light" width={1207} height={929} />
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,46 @@
export default function FAQs() {
return (
<section className="scroll-py-16 py-16 md:scroll-py-32 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="grid gap-y-12 px-2 lg:[grid-template-columns:1fr_auto]">
<div className="text-center lg:text-left">
<h2 className="mb-4 text-3xl font-semibold md:text-4xl">
Frequently <br className="hidden lg:block" /> Asked <br className="hidden lg:block" />
Questions
</h2>
<p>Accusantium quisquam. Illo, omnis?</p>
</div>
<div className="divide-y divide-dashed sm:mx-auto sm:max-w-lg lg:mx-0">
<div className="pb-6">
<h3 className="font-medium">What is the refund policy?</h3>
<p className="text-muted-foreground mt-4">We offer a 30-day money back guarantee. If you are not satisfied with our product, you can request a refund within 30 days of your purchase.</p>
<ol className="list-outside list-decimal space-y-2 pl-4">
<li className="text-muted-foreground mt-4">To request a refund, please contact our support team with your order number and reason for the refund.</li>
<li className="text-muted-foreground mt-4">Refunds will be processed within 3-5 business days.</li>
<li className="text-muted-foreground mt-4">Please note that refunds are only available for new customers and are limited to one per customer.</li>
</ol>
</div>
<div className="py-6">
<h3 className="font-medium">How do I cancel my subscription?</h3>
<p className="text-muted-foreground mt-4">You can cancel your subscription at any time by logging into your account and clicking on the cancel button.</p>
</div>
<div className="py-6">
<h3 className="font-medium">Can I upgrade my plan?</h3>
<p className="text-muted-foreground my-4">Yes, you can upgrade your plan at any time by logging into your account and selecting the plan you want to upgrade to.</p>
<ul className="list-outside list-disc space-y-2 pl-4">
<li className="text-muted-foreground">You will be charged the difference in price between your current plan and the plan you are upgrading to.</li>
<li className="text-muted-foreground">Your new plan will take effect immediately and you will be billed at the new rate on your next billing cycle.</li>
</ul>
</div>
<div className="py-6">
<h3 className="font-medium">Do you offer phone support?</h3>
<p className="text-muted-foreground mt-4">We do not offer phone support at this time. However, you can contact us via email or live chat for any questions or concerns you may have.</p>
</div>
</div>
</div>
</div>
</section>
)
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,122 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Globe } from 'lucide-react'
import Image from 'next/image'
export default function Features() {
return (
<section className="dark:bg-muted/25 bg-zinc-50 py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto grid gap-2 sm:grid-cols-5">
<Card className="group overflow-hidden shadow-zinc-950/5 sm:col-span-3 sm:rounded-none sm:rounded-tl-xl">
<CardHeader>
<div className="md:p-6">
<p className="font-medium">Advanced tracking system</p>
<p className="text-muted-foreground mt-3 max-w-sm text-sm">Quick AI lives a single hotkey away - ready to quickly appear as a floating window above your other apps..</p>
</div>
</CardHeader>
<div className="relative h-fit pl-6 md:pl-12">
<div className="absolute -inset-6 [background:radial-gradient(75%_95%_at_50%_0%,transparent,var(--color-background)_100%)]"></div>
<div className="bg-background overflow-hidden rounded-tl-lg border-l border-t pl-2 pt-2 dark:bg-zinc-950">
<Image
src="/blocks/mail2.png"
className="hidden dark:block"
alt="payments illustration dark"
width={1207}
height={929}
/>
<Image
src="/blocks/mail2-light.png"
className="shadow dark:hidden"
alt="payments illustration light"
width={1207}
height={929}
/>
</div>
</div>
</Card>
<Card className="group overflow-hidden shadow-zinc-950/5 sm:col-span-2 sm:rounded-none sm:rounded-tr-xl">
<p className="mx-auto my-6 max-w-md text-balance px-6 text-center text-lg font-semibold sm:text-2xl md:p-6">Advanced UX, Instantly locate all your assets.</p>
<CardContent className="mt-auto h-fit">
<div className="relative mb-6 sm:mb-0">
<div className="absolute -inset-6 [background:radial-gradient(50%_75%_at_75%_50%,transparent,var(--color-background)_100%)]"></div>
<div className="aspect-76/59 overflow-hidden rounded-r-lg border">
<Image
src="/blocks/origin-cal-dark.png"
className="hidden dark:block"
alt="payments illustration dark"
width={1207}
height={929}
/>
<Image
src="/blocks/origin-cal.png"
className="shadow dark:hidden"
alt="payments illustration light"
width={1207}
height={929}
/>
</div>
</div>
</CardContent>
</Card>
<Card className="group p-6 shadow-zinc-950/5 sm:col-span-2 sm:rounded-none sm:rounded-bl-xl md:p-12">
<p className="mx-auto mb-12 max-w-md text-balance text-center text-lg font-semibold sm:text-2xl">Advanced UX, Instantly locate all your assets.</p>
<div className="flex justify-center gap-6">
<div className="inset-shadow-sm dark:inset-shadow-white/5 bg-muted/35 relative flex aspect-square size-16 items-center rounded-[7px] border p-3 shadow-lg ring dark:shadow-white/5 dark:ring-black">
<span className="absolute right-2 top-1 block text-sm">fn</span>
<Globe className="mt-auto size-4" />
</div>
<div className="inset-shadow-sm dark:inset-shadow-white/5 bg-muted/35 flex aspect-square size-16 items-center justify-center rounded-[7px] border p-3 shadow-lg ring dark:shadow-white/5 dark:ring-black">
<span>K</span>
</div>
</div>
</Card>
<Card className="group relative shadow-zinc-950/5 sm:col-span-3 sm:rounded-none sm:rounded-br-xl">
<CardHeader className="p-6 md:p-12">
<p className="font-medium">Advanced tracking system</p>
<p className="text-muted-foreground mt-2 max-w-sm text-sm">Quick AI lives a single hotkey away apps..</p>
</CardHeader>
<CardContent className="relative h-fit px-6 pb-6 md:px-12 md:pb-12">
<div className="grid grid-cols-4 gap-2 md:grid-cols-6">
<div className="rounded-(--radius) aspect-square border border-dashed"></div>
<div className="rounded-(--radius) bg-muted/50 flex aspect-square items-center justify-center border p-4">
<img
className="m-auto size-8 invert dark:invert-0"
src="https://oxymor-ns.tailus.io/logos/linear.svg"
alt="Linear logo"
width="32"
height="32"
/>
</div>
<div className="rounded-(--radius) aspect-square border border-dashed"></div>
<div className="rounded-(--radius) bg-muted/50 flex aspect-square items-center justify-center border p-4">
<img
className="m-auto size-8 invert dark:invert-0"
src="https://oxymor-ns.tailus.io/logos/netlify.svg"
alt="Netlify logo"
width="32"
height="32"
/>
</div>
<div className="rounded-(--radius) aspect-square border border-dashed"></div>
<div className="rounded-(--radius) bg-muted/50 flex aspect-square items-center justify-center border p-4">
<img
className="m-auto size-8 invert dark:invert-0"
src="https://oxymor-ns.tailus.io/logos/github.svg"
alt="github logo"
width="32"
height="32"
/>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,43 @@
import { Activity, DraftingCompass, Mail, Zap } from 'lucide-react'
import Image from 'next/image'
export default function FeaturesSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="grid items-center gap-12 md:grid-cols-2 md:gap-12 lg:grid-cols-5 lg:gap-24">
<div className="lg:col-span-2">
<div className="md:pr-6 lg:pr-0">
<h2 className="text-4xl font-semibold lg:text-5xl">Built for Scaling teams</h2>
<p className="mt-6">Orrupti aut temporibus assumenda atque ab, accusamus sit, molestiae veniam laboriosam pariatur.</p>
</div>
<ul className="mt-8 divide-y border-y *:flex *:items-center *:gap-3 *:py-3">
<li>
<Mail className="size-5" />
Email and web support
</li>
<li>
<Zap className="size-5" />
Fast response time
</li>
<li>
<Activity className="size-5" />
Menitoring and analytics
</li>
<li>
<DraftingCompass className="size-5" />
Architectural review
</li>
</ul>
</div>
<div className="border-border/50 relative rounded-3xl border p-3 lg:col-span-3">
<div className="bg-linear-to-b aspect-76/59 relative rounded-2xl from-zinc-300 to-transparent p-px dark:from-zinc-700">
<Image src="/blocks/payments.png" className="hidden rounded-[15px] dark:block" alt="payments illustration dark" width={1207} height={929} />
<Image src="/blocks/payments-light.png" className="rounded-[15px] shadow dark:hidden" alt="payments illustration light" width={1207} height={929} />
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,63 @@
import { Cpu, Fingerprint, Pencil, Settings2, Sparkles, Zap } from 'lucide-react'
export default function Features() {
return (
<section className="py-12 md:py-20">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<div className="relative z-10 mx-auto max-w-xl space-y-6 text-center md:space-y-12">
<h2 className="text-balance text-4xl font-medium lg:text-5xl">The foundation for creative teams management</h2>
<p>Lyra is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="relative mx-auto grid max-w-4xl divide-x divide-y border *:p-12 sm:grid-cols-2 lg:grid-cols-3">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Zap className="size-4" />
<h3 className="text-sm font-medium">Faaast</h3>
</div>
<p className="text-sm">It supports an entire helping developers and innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Cpu className="size-4" />
<h3 className="text-sm font-medium">Powerful</h3>
</div>
<p className="text-sm">It supports an entire helping developers and businesses.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Fingerprint className="size-4" />
<h3 className="text-sm font-medium">Security</h3>
</div>
<p className="text-sm">It supports an helping developers businesses.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Pencil className="size-4" />
<h3 className="text-sm font-medium">Customization</h3>
</div>
<p className="text-sm">It supports helping developers and businesses innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Settings2 className="size-4" />
<h3 className="text-sm font-medium">Control</h3>
</div>
<p className="text-sm">It supports helping developers and businesses innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Sparkles className="size-4" />
<h3 className="text-sm font-medium">Built for AI</h3>
</div>
<p className="text-sm">It supports helping developers and businesses innovate.</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,151 @@
'use client'
import { Logo } from '@/components/logo'
import { Activity, Map as MapIcon, MessageCircle } from 'lucide-react'
import DottedMap from 'dotted-map'
import { Area, AreaChart, CartesianGrid } from 'recharts'
import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
export default function FeaturesSection() {
return (
<section className="px-4 py-16 md:py-32">
<div className="mx-auto grid max-w-5xl border md:grid-cols-2">
<div>
<div className="p-6 sm:p-12">
<span className="text-muted-foreground flex items-center gap-2">
<MapIcon className="size-4" />
Real time location tracking
</span>
<p className="mt-8 text-2xl font-semibold">Advanced tracking system, Instantly locate all your assets.</p>
</div>
<div aria-hidden className="relative">
<div className="absolute inset-0 z-10 m-auto size-fit">
<div className="rounded-(--radius) bg-background z-1 dark:bg-muted relative flex size-fit w-fit items-center gap-2 border px-3 py-1 text-xs font-medium shadow-md shadow-zinc-950/5">
<span className="text-lg">🇨🇩</span> Last connection from DR Congo
</div>
<div className="rounded-(--radius) bg-background absolute inset-2 -bottom-2 mx-auto border px-3 py-4 text-xs font-medium shadow-md shadow-zinc-950/5 dark:bg-zinc-900"></div>
</div>
<div className="relative overflow-hidden">
<div className="bg-radial z-1 to-background absolute inset-0 from-transparent to-75%"></div>
<Map />
</div>
</div>
</div>
<div className="overflow-hidden border-t bg-zinc-50 p-6 sm:p-12 md:border-0 md:border-l dark:bg-transparent">
<div className="relative z-10">
<span className="text-muted-foreground flex items-center gap-2">
<MessageCircle className="size-4" />
Email and web support
</span>
<p className="my-8 text-2xl font-semibold">Reach out via email or web for any assistance you need.</p>
</div>
<div aria-hidden className="flex flex-col gap-8">
<div>
<div className="flex items-center gap-2">
<span className="flex size-5 rounded-full border">
<Logo className="m-auto size-3" />
</span>
<span className="text-muted-foreground text-xs">Sat 22 Feb</span>
</div>
<div className="rounded-(--radius) bg-background mt-1.5 w-3/5 border p-3 text-xs">Hey, I'm having trouble with my account.</div>
</div>
<div>
<div className="rounded-(--radius) mb-1 ml-auto w-3/5 bg-blue-600 p-3 text-xs text-white">Molestiae numquam debitis et ullam distinctio provident nobis repudiandae deleniti necessitatibus.</div>
<span className="text-muted-foreground block text-right text-xs">Now</span>
</div>
</div>
</div>
<div className="col-span-full border-y p-12">
<p className="text-center text-4xl font-semibold lg:text-7xl">99.99% Uptime</p>
</div>
<div className="relative col-span-full">
<div className="absolute z-10 max-w-lg px-6 pr-12 pt-6 md:px-12 md:pt-12">
<span className="text-muted-foreground flex items-center gap-2">
<Activity className="size-4" />
Activity feed
</span>
<p className="my-8 text-2xl font-semibold">
Monitor your application's activity in real-time. <span className="text-muted-foreground"> Instantly identify and resolve issues.</span>
</p>
</div>
<MonitoringChart />
</div>
</div>
</section>
)
}
const map = new DottedMap({ height: 55, grid: 'diagonal' })
const points = map.getPoints()
const svgOptions = {
backgroundColor: 'var(--color-background)',
color: 'currentColor',
radius: 0.15,
}
const Map = () => {
const viewBox = `0 0 120 60`
return (
<svg viewBox={viewBox} style={{ background: svgOptions.backgroundColor }}>
{points.map((point, index) => (
<circle key={index} cx={point.x} cy={point.y} r={svgOptions.radius} fill={svgOptions.color} />
))}
</svg>
)
}
const chartConfig = {
desktop: {
label: 'Desktop',
color: '#2563eb',
},
mobile: {
label: 'Mobile',
color: '#60a5fa',
},
} satisfies ChartConfig
const chartData = [
{ month: 'May', desktop: 56, mobile: 224 },
{ month: 'June', desktop: 56, mobile: 224 },
{ month: 'January', desktop: 126, mobile: 252 },
{ month: 'February', desktop: 205, mobile: 410 },
{ month: 'March', desktop: 200, mobile: 126 },
{ month: 'April', desktop: 400, mobile: 800 },
]
const MonitoringChart = () => {
return (
<ChartContainer className="h-120 aspect-auto md:h-96" config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: 0,
right: 0,
}}>
<defs>
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="var(--color-desktop)" stopOpacity={0.8} />
<stop offset="55%" stopColor="var(--color-desktop)" stopOpacity={0.1} />
</linearGradient>
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="var(--color-mobile)" stopOpacity={0.8} />
<stop offset="55%" stopColor="var(--color-mobile)" stopOpacity={0.1} />
</linearGradient>
</defs>
<CartesianGrid vertical={false} />
<ChartTooltip active cursor={false} content={<ChartTooltipContent className="dark:bg-muted" />} />
<Area strokeWidth={2} dataKey="mobile" type="stepBefore" fill="url(#fillMobile)" fillOpacity={0.1} stroke="var(--color-mobile)" stackId="a" />
<Area strokeWidth={2} dataKey="desktop" type="stepBefore" fill="url(#fillDesktop)" fillOpacity={0.1} stroke="var(--color-desktop)" stackId="a" />
</AreaChart>
</ChartContainer>
)
}

View File

@ -0,0 +1,67 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Settings2, Sparkles, Zap } from 'lucide-react'
import { ReactNode } from 'react'
export default function Features() {
return (
<section className="bg-zinc-50 py-16 md:py-32 dark:bg-transparent">
<div className="@container mx-auto max-w-5xl px-6">
<div className="text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-5xl">Built to cover your needs</h2>
<p className="mt-4">Libero sapiente aliquam quibusdam aspernatur, praesentium iusto repellendus.</p>
</div>
<div className="@min-4xl:max-w-full @min-4xl:grid-cols-3 mx-auto mt-8 grid max-w-sm gap-6 *:text-center md:mt-16">
<Card className="group shadow-zinc-950/5">
<CardHeader className="pb-3">
<CardDecorator>
<Zap className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">Customizable</h3>
</CardHeader>
<CardContent>
<p className="text-sm">Extensive customization options, allowing you to tailor every aspect to meet your specific needs.</p>
</CardContent>
</Card>
<Card className="group shadow-zinc-950/5">
<CardHeader className="pb-3">
<CardDecorator>
<Settings2 className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">You have full control</h3>
</CardHeader>
<CardContent>
<p className="mt-3 text-sm">From design elements to functionality, you have complete control to create a unique and personalized experience.</p>
</CardContent>
</Card>
<Card className="group shadow-zinc-950/5">
<CardHeader className="pb-3">
<CardDecorator>
<Sparkles className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">Powered By AI</h3>
</CardHeader>
<CardContent>
<p className="mt-3 text-sm">Elements to functionality, you have complete control to create a unique experience.</p>
</CardContent>
</Card>
</div>
</div>
</section>
)
}
const CardDecorator = ({ children }: { children: ReactNode }) => (
<div className="relative mx-auto size-36 duration-200 [--color-border:color-mix(in_oklab,var(--color-zinc-950)10%,transparent)] group-hover:[--color-border:color-mix(in_oklab,var(--color-zinc-950)20%,transparent)] dark:[--color-border:color-mix(in_oklab,var(--color-white)15%,transparent)] dark:group-hover:bg-white/5 dark:group-hover:[--color-border:color-mix(in_oklab,var(--color-white)20%,transparent)]">
<div aria-hidden className="absolute inset-0 bg-[linear-gradient(to_right,var(--color-border)_1px,transparent_1px),linear-gradient(to_bottom,var(--color-border)_1px,transparent_1px)] bg-[size:24px_24px]" />
<div aria-hidden className="bg-radial to-background absolute inset-0 from-transparent to-75%" />
<div className="bg-background absolute inset-0 m-auto flex size-12 items-center justify-center border-l border-t">{children}</div>
</div>
)

View File

@ -0,0 +1,58 @@
import { Cpu, Lock, Sparkles, Zap } from 'lucide-react'
import Image from 'next/image'
export default function FeaturesSection() {
return (
<section className="overflow-hidden py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-12">
<div className="relative z-10 max-w-2xl">
<h2 className="text-4xl font-semibold lg:text-5xl">Built for Scaling teams</h2>
<p className="mt-6 text-lg">Empower your team with workflows that adapt to your needs, whether you prefer git synchronization or a AI Agents interface.</p>
</div>
<div className="relative -mx-4 rounded-3xl p-3 md:-mx-12 lg:col-span-3">
<div className="perspective-midrange">
<div className="rotate-x-6 -skew-2">
<div className="aspect-88/36 relative">
<div className="bg-radial-[at_75%_25%] to-background z-1 -inset-17 absolute from-transparent to-75%"></div>
<Image src="/blocks/mail-upper.png" className="absolute inset-0 z-10" alt="payments illustration dark" width={2797} height={1137} />
<Image src="/blocks/mail-back.png" className="hidden dark:block" alt="payments illustration dark" width={2797} height={1137} />
<Image src="/blocks/mail-back-light.png" className="dark:hidden" alt="payments illustration light" width={2797} height={1137} />
</div>
</div>
</div>
</div>
<div className="relative mx-auto grid grid-cols-2 gap-x-3 gap-y-6 sm:gap-8 lg:grid-cols-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Zap className="size-4" />
<h3 className="text-sm font-medium">Faaast</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Cpu className="size-4" />
<h3 className="text-sm font-medium">Powerful</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and businesses.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Lock className="size-4" />
<h3 className="text-sm font-medium">Security</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an helping developers businesses innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Sparkles className="size-4" />
<h3 className="text-sm font-medium">AI Powered</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an helping developers businesses innovate.</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,54 @@
import { Cpu, Lock, Sparkles, Zap } from 'lucide-react'
import Image from 'next/image'
export default function FeaturesSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-12 px-6">
<div className="relative z-10 grid items-center gap-4 md:grid-cols-2 md:gap-12">
<h2 className="text-4xl font-semibold">The Lyra ecosystem brings together our models</h2>
<p className="max-w-sm sm:ml-auto">Empower your team with workflows that adapt to your needs, whether you prefer git synchronization or a AI Agents interface.</p>
</div>
<div className="relative rounded-3xl p-3 md:-mx-8 lg:col-span-3">
<div className="aspect-88/36 relative">
<div className="bg-linear-to-t z-1 from-background absolute inset-0 to-transparent"></div>
<Image src="/blocks/mail-upper.png" className="absolute inset-0 z-10" alt="payments illustration dark" width={2797} height={1137} />
<Image src="/blocks/mail-back.png" className="hidden dark:block" alt="payments illustration dark" width={2797} height={1137} />
<Image src="/blocks/mail-back-light.png" className="dark:hidden" alt="payments illustration light" width={2797} height={1137} />
</div>
</div>
<div className="relative mx-auto grid grid-cols-2 gap-x-3 gap-y-6 sm:gap-8 lg:grid-cols-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Zap className="size-4" />
<h3 className="text-sm font-medium">Faaast</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Cpu className="size-4" />
<h3 className="text-sm font-medium">Powerful</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an entire helping developers and businesses.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Lock className="size-4" />
<h3 className="text-sm font-medium">Security</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an helping developers businesses innovate.</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<Sparkles className="size-4" />
<h3 className="text-sm font-medium">AI Powered</h3>
</div>
<p className="text-muted-foreground text-sm">It supports an helping developers businesses innovate.</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,185 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { cn } from '@/lib/utils'
import { Calendar, LucideIcon, MapIcon } from 'lucide-react'
import Image from 'next/image'
import { ReactNode } from 'react'
export default function Features() {
return (
<section className="bg-zinc-50 py-16 md:py-32 dark:bg-transparent">
<div className="mx-auto max-w-2xl px-6 lg:max-w-5xl">
<div className="mx-auto grid gap-4 lg:grid-cols-2">
<FeatureCard>
<CardHeader className="pb-3">
<CardHeading
icon={MapIcon}
title="Real time location tracking"
description="Advanced tracking system, Instantly locate all your assets."
/>
</CardHeader>
<div className="relative mb-6 border-t border-dashed sm:mb-0">
<div className="absolute inset-0 [background:radial-gradient(125%_125%_at_50%_0%,transparent_40%,var(--color-blue-600),var(--color-white)_100%)]"></div>
<div className="aspect-76/59 p-1 px-6">
<DualModeImage
darksrc="/blocks/payments.png"
lightsrc="/blocks/payments-light.png"
alt="payments illustration"
width={1207}
height={929}
/>
</div>
</div>
</FeatureCard>
<FeatureCard>
<CardHeader className="pb-3">
<CardHeading
icon={Calendar}
title="Advanced Scheduling"
description="Scheduling system, Instantly locate all your assets."
/>
</CardHeader>
<CardContent>
<div className="relative mb-6 sm:mb-0">
<div className="absolute -inset-6 [background:radial-gradient(50%_50%_at_75%_50%,transparent,var(--color-background)_100%)]"></div>
<div className="aspect-76/59 border">
<DualModeImage
darksrc="/blocks/origin-cal-dark.png"
lightsrc="/blocks/origin-cal.png"
alt="calendar illustration"
width={1207}
height={929}
/>
</div>
</div>
</CardContent>
</FeatureCard>
<FeatureCard className="p-6 lg:col-span-2">
<p className="mx-auto my-6 max-w-md text-balance text-center text-2xl font-semibold">Smart scheduling with automated reminders for maintenance.</p>
<div className="flex justify-center gap-6 overflow-hidden">
<CircularUI
label="Inclusion"
circles={[{ pattern: 'border' }, { pattern: 'border' }]}
/>
<CircularUI
label="Inclusion"
circles={[{ pattern: 'none' }, { pattern: 'primary' }]}
/>
<CircularUI
label="Join"
circles={[{ pattern: 'blue' }, { pattern: 'none' }]}
/>
<CircularUI
label="Exclusion"
circles={[{ pattern: 'primary' }, { pattern: 'none' }]}
className="hidden sm:block"
/>
</div>
</FeatureCard>
</div>
</div>
</section>
)
}
interface FeatureCardProps {
children: ReactNode
className?: string
}
const FeatureCard = ({ children, className }: FeatureCardProps) => (
<Card className={cn('group relative rounded-none shadow-zinc-950/5', className)}>
<CardDecorator />
{children}
</Card>
)
const CardDecorator = () => (
<>
<span className="border-primary absolute -left-px -top-px block size-2 border-l-2 border-t-2"></span>
<span className="border-primary absolute -right-px -top-px block size-2 border-r-2 border-t-2"></span>
<span className="border-primary absolute -bottom-px -left-px block size-2 border-b-2 border-l-2"></span>
<span className="border-primary absolute -bottom-px -right-px block size-2 border-b-2 border-r-2"></span>
</>
)
interface CardHeadingProps {
icon: LucideIcon
title: string
description: string
}
const CardHeading = ({ icon: Icon, title, description }: CardHeadingProps) => (
<div className="p-6">
<span className="text-muted-foreground flex items-center gap-2">
<Icon className="size-4" />
{title}
</span>
<p className="mt-8 text-2xl font-semibold">{description}</p>
</div>
)
interface DualModeImageProps {
darkSrc: string
lightSrc: string
alt: string
width: number
height: number
className?: string
}
const DualModeImage = ({ darkSrc, lightSrc, alt, width, height, className }: DualModeImageProps) => (
<>
<Image
src={darkSrc}
className={cn('hidden dark:block', className)}
alt={`${alt} dark`}
width={width}
height={height}
/>
<Image
src={lightSrc}
className={cn('shadow dark:hidden', className)}
alt={`${alt} light`}
width={width}
height={height}
/>
</>
)
interface CircleConfig {
pattern: 'none' | 'border' | 'primary' | 'blue'
}
interface CircularUIProps {
label: string
circles: CircleConfig[]
className?: string
}
const CircularUI = ({ label, circles, className }: CircularUIProps) => (
<div className={className}>
<div className="bg-linear-to-b from-border size-fit rounded-2xl to-transparent p-px">
<div className="bg-linear-to-b from-background to-muted/25 relative flex aspect-square w-fit items-center -space-x-4 rounded-[15px] p-4">
{circles.map((circle, i) => (
<div
key={i}
className={cn('size-7 rounded-full border sm:size-8', {
'border-primary': circle.pattern === 'none',
'border-primary bg-[repeating-linear-gradient(-45deg,var(--color-border),var(--color-border)_1px,transparent_1px,transparent_4px)]': circle.pattern === 'border',
'border-primary bg-background bg-[repeating-linear-gradient(-45deg,var(--color-primary),var(--color-primary)_1px,transparent_1px,transparent_4px)]': circle.pattern === 'primary',
'bg-background z-1 border-blue-500 bg-[repeating-linear-gradient(-45deg,var(--color-blue-500),var(--color-blue-500)_1px,transparent_1px,transparent_4px)]': circle.pattern === 'blue',
})}></div>
))}
</div>
</div>
<span className="text-muted-foreground mt-1.5 block text-center text-sm">{label}</span>
</div>
)

View File

@ -0,0 +1,67 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Settings2, Sparkles, Zap } from 'lucide-react'
import { ReactNode } from 'react'
export default function Features() {
return (
<section className="bg-zinc-50 py-16 md:py-32 dark:bg-transparent">
<div className="@container mx-auto max-w-5xl px-6">
<div className="text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-5xl">Built to cover your needs</h2>
<p className="mt-4">Libero sapiente aliquam quibusdam aspernatur, praesentium iusto repellendus.</p>
</div>
<Card className="@min-4xl:max-w-full @min-4xl:grid-cols-3 @min-4xl:divide-x @min-4xl:divide-y-0 mx-auto mt-8 grid max-w-sm divide-y overflow-hidden shadow-zinc-950/5 *:text-center md:mt-16">
<div className="group shadow-zinc-950/5">
<CardHeader className="pb-3">
<CardDecorator>
<Zap className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">Customizable</h3>
</CardHeader>
<CardContent>
<p className="text-sm">Extensive customization options, allowing you to tailor every aspect to meet your specific needs.</p>
</CardContent>
</div>
<div className="group shadow-zinc-950/5">
<CardHeader className="pb-3">
<CardDecorator>
<Settings2 className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">You have full control</h3>
</CardHeader>
<CardContent>
<p className="mt-3 text-sm">From design elements to functionality, you have complete control to create a unique and personalized experience.</p>
</CardContent>
</div>
<div className="group shadow-zinc-950/5">
<CardHeader className="pb-3">
<CardDecorator>
<Sparkles className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">Powered By AI</h3>
</CardHeader>
<CardContent>
<p className="mt-3 text-sm">Elements to functionality, you have complete control to create a unique experience.</p>
</CardContent>
</div>
</Card>
</div>
</section>
)
}
const CardDecorator = ({ children }: { children: ReactNode }) => (
<div className="relative mx-auto size-36 duration-200 [--color-border:color-mix(in_oklab,var(--color-zinc-950)10%,transparent)] group-hover:[--color-border:color-mix(in_oklab,var(--color-zinc-950)20%,transparent)] dark:[--color-border:color-mix(in_oklab,var(--color-white)15%,transparent)] dark:group-hover:bg-white/5 dark:group-hover:[--color-border:color-mix(in_oklab,var(--color-white)20%,transparent)]">
<div aria-hidden className="absolute inset-0 bg-[linear-gradient(to_right,var(--color-border)_1px,transparent_1px),linear-gradient(to_bottom,var(--color-border)_1px,transparent_1px)] bg-[size:24px_24px]" />
<div aria-hidden className="bg-radial to-background absolute inset-0 from-transparent to-75%" />
<div className="bg-background absolute inset-0 m-auto flex size-12 items-center justify-center border-l border-t">{children}</div>
</div>
)

View File

@ -0,0 +1,116 @@
'use client'
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
import { ChartBarIncreasingIcon, Database, Fingerprint, IdCard } from 'lucide-react'
import Image from 'next/image'
import { useState } from 'react'
import { motion, AnimatePresence } from 'motion/react'
import { BorderBeam } from '@/components/magicui/border-beam'
export default function Features() {
type ImageKey = 'item-1' | 'item-2' | 'item-3' | 'item-4'
const [activeItem, setActiveItem] = useState<ImageKey>('item-1')
const images = {
'item-1': {
image: '/charts.png',
alt: 'Database visualization',
},
'item-2': {
image: '/music.png',
alt: 'Security authentication',
},
'item-3': {
image: '/mail2.png',
alt: 'Identity management',
},
'item-4': {
image: '/payments.png',
alt: 'Analytics dashboard',
},
}
return (
<section className="py-12 md:py-20 lg:py-32">
<div className="bg-linear-to-b absolute inset-0 -z-10 sm:inset-6 sm:rounded-b-3xl dark:block dark:to-[color-mix(in_oklab,var(--color-zinc-900)_75%,var(--color-background))]"></div>
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16 lg:space-y-20 dark:[--color-border:color-mix(in_oklab,var(--color-white)_10%,transparent)]">
<div className="relative z-10 mx-auto max-w-2xl space-y-6 text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-6xl">The foundation for AI</h2>
<p>Lyra is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="grid gap-12 sm:px-12 md:grid-cols-2 lg:gap-20 lg:px-0">
<Accordion
type="single"
value={activeItem}
onValueChange={(value) => setActiveItem(value as ImageKey)}
className="w-full">
<AccordionItem value="item-1">
<AccordionTrigger>
<div className="flex items-center gap-2 text-base">
<Database className="size-4" />
Database Visualization
</div>
</AccordionTrigger>
<AccordionContent>Lyra is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>
<div className="flex items-center gap-2 text-base">
<Fingerprint className="size-4" />
Advanced Authentication
</div>
</AccordionTrigger>
<AccordionContent>Lyra is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger>
<div className="flex items-center gap-2 text-base">
<IdCard className="size-4" />
Identity Management
</div>
</AccordionTrigger>
<AccordionContent>Lyra is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</AccordionContent>
</AccordionItem>
<AccordionItem value="item-4">
<AccordionTrigger>
<div className="flex items-center gap-2 text-base">
<ChartBarIncreasingIcon className="size-4" />
Analytics Dashboard
</div>
</AccordionTrigger>
<AccordionContent>Lyra is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</AccordionContent>
</AccordionItem>
</Accordion>
<div className="bg-background relative flex overflow-hidden rounded-3xl border p-2">
<div className="w-15 absolute inset-0 right-0 ml-auto border-l bg-[repeating-linear-gradient(-45deg,var(--color-border),var(--color-border)_1px,transparent_1px,transparent_8px)]"></div>
<div className="aspect-76/59 bg-background relative w-[calc(3/4*100%+3rem)] rounded-2xl">
<AnimatePresence mode="wait">
<motion.div
key={`${activeItem}-id`}
initial={{ opacity: 0, y: 6, scale: 0.98 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 6, scale: 0.98 }}
transition={{ duration: 0.2 }}
className="size-full overflow-hidden rounded-2xl border bg-zinc-900 shadow-md">
<Image
src={images[activeItem].image}
className="size-full object-cover object-left-top dark:mix-blend-lighten"
alt={images[activeItem].alt}
width={1207}
height={929}
/>
</motion.div>
</AnimatePresence>
</div>
<BorderBeam
duration={6}
size={200}
className="from-transparent via-yellow-700 to-transparent dark:via-white/50"
/>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,67 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Settings2, Sparkles, Zap } from 'lucide-react'
import { ReactNode } from 'react'
export default function Features() {
return (
<section className="py-16 md:py-32">
<div className="@container mx-auto max-w-5xl px-6">
<div className="text-center">
<h2 className="text-balance text-4xl font-semibold lg:text-5xl">Built to cover your needs</h2>
<p className="mt-4">Libero sapiente aliquam quibusdam aspernatur, praesentium iusto repellendus.</p>
</div>
<div className="@min-4xl:max-w-full @min-4xl:grid-cols-3 mx-auto mt-8 grid max-w-sm gap-6 [--color-background:var(--color-muted)] [--color-card:var(--color-muted)] *:text-center md:mt-16 dark:[--color-muted:var(--color-zinc-900)]">
<Card className="group border-0 shadow-none">
<CardHeader className="pb-3">
<CardDecorator>
<Zap className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">Customizable</h3>
</CardHeader>
<CardContent>
<p className="text-sm">Extensive customization options, allowing you to tailor every aspect to meet your specific needs.</p>
</CardContent>
</Card>
<Card className="group border-0 shadow-none">
<CardHeader className="pb-3">
<CardDecorator>
<Settings2 className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">You have full control</h3>
</CardHeader>
<CardContent>
<p className="mt-3 text-sm">From design elements to functionality, you have complete control to create a unique and personalized experience.</p>
</CardContent>
</Card>
<Card className="group border-0 shadow-none">
<CardHeader className="pb-3">
<CardDecorator>
<Sparkles className="size-6" aria-hidden />
</CardDecorator>
<h3 className="mt-6 font-medium">Powered By AI</h3>
</CardHeader>
<CardContent>
<p className="mt-3 text-sm">Elements to functionality, you have complete control to create a unique experience.</p>
</CardContent>
</Card>
</div>
</div>
</section>
)
}
const CardDecorator = ({ children }: { children: ReactNode }) => (
<div className="relative mx-auto size-36 duration-200 [--color-border:color-mix(in_oklab,var(--color-zinc-950)10%,transparent)] group-hover:[--color-border:color-mix(in_oklab,var(--color-zinc-950)20%,transparent)] dark:[--color-border:color-mix(in_oklab,var(--color-white)15%,transparent)] dark:group-hover:bg-white/5 dark:group-hover:[--color-border:color-mix(in_oklab,var(--color-white)20%,transparent)]">
<div aria-hidden className="absolute inset-0 bg-[linear-gradient(to_right,var(--color-border)_1px,transparent_1px),linear-gradient(to_bottom,var(--color-border)_1px,transparent_1px)] bg-[size:24px_24px]" />
<div aria-hidden className="bg-radial to-background absolute inset-0 from-transparent to-75%" />
<div className="dark:bg-background absolute inset-0 m-auto flex size-12 items-center justify-center border-l border-t bg-white">{children}</div>
</div>
)

View File

@ -0,0 +1,133 @@
import React from 'react'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import { Logo } from '@/components/logo'
const enterpriseLinks = [
{ href: '#', label: 'About' },
{ href: '#', label: 'Customers' },
{ href: '#', label: 'Enterprise' },
{ href: '#', label: 'Partners' },
{ href: '#', label: 'Jobs' },
]
const productLinks = [
{ href: '#', label: 'Security' },
{ href: '#', label: 'Customization' },
{ href: '#', label: 'Enterprise' },
{ href: '#', label: 'Partners' },
]
const docsLinks = [
{ href: '#', label: 'Introduction' },
{ href: '#', label: 'Installation' },
{ href: '#', label: 'Utils' },
{ href: '#', label: 'Principles' },
{ href: '#', label: 'Jargon' },
{ href: '#', label: 'Plugin' },
{ href: '#', label: 'Customizer' },
{ href: '#', label: 'Boilerplates' },
]
const communityLinks = [
{ href: '#', label: 'GitHub' },
{ href: '#', label: 'Discord' },
{ href: '#', label: 'Slack' },
{ href: '#', label: 'X / Twitter' },
]
const footerLinks = [
{
name: 'Enterprise',
links: enterpriseLinks,
},
{
name: 'Product',
links: productLinks,
},
{
name: 'Docs',
links: docsLinks,
},
]
export default function Footer() {
return (
<footer className="m-1 rounded-3xl border">
<div className="mx-auto max-w-5xl space-y-16 px-5 py-16">
<div className="flex flex-wrap items-center justify-between gap-4 border-b pb-8">
<Link href="/" aria-label="go home">
<Logo />
</Link>
<div className="flex gap-3">
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Threads" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M19.25 8.505c-1.577-5.867-7-5.5-7-5.5s-7.5-.5-7.5 8.995s7.5 8.996 7.5 8.996s4.458.296 6.5-3.918c.667-1.858.5-5.573-6-5.573c0 0-3 0-3 2.5c0 .976 1 2 2.5 2s3.171-1.027 3.5-3c1-6-4.5-6.5-6-4" color="currentColor"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Instagram" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4zm9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8A1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5a5 5 0 0 1-5 5a5 5 0 0 1-5-5a5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="TikTok" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.6 5.82s.51.5 0 0A4.28 4.28 0 0 1 15.54 3h-3.09v12.4a2.59 2.59 0 0 1-2.59 2.5c-1.42 0-2.6-1.16-2.6-2.6c0-1.72 1.66-3.01 3.37-2.48V9.66c-3.45-.46-6.47 2.22-6.47 5.64c0 3.33 2.76 5.7 5.69 5.7c3.14 0 5.69-2.55 5.69-5.7V9.01a7.35 7.35 0 0 0 4.3 1.38V7.3s-1.88.09-3.24-1.48"></path>
</svg>
</Link>
</div>
</div>
<div className="grid grid-cols-2 gap-6 sm:grid-cols-4">
{footerLinks.map((linksGroup, index) => (
<div key={index}>
<span className="font-medium">{linksGroup.name}</span>
<ul className="mt-4 list-inside space-y-4">
{linksGroup.links.map((link, index) => (
<li key={index}>
<Link href={link.href} className="hover:text-primary text-muted-foreground text-sm duration-150">
{link.label}
</Link>
</li>
))}
</ul>
</div>
))}
<div>
<span className="text-sm font-medium">Community</span>
<ul className="mt-4 list-inside space-y-4">
{communityLinks.map((link, index) => (
<li key={index}>
<Link href={link.href} className="hover:text-primary text-muted-foreground text-sm duration-150">
{link.label}
</Link>
</li>
))}
</ul>
<form className="mt-12 w-full max-w-xs">
<div className="space-y-2.5">
<Label className="block text-sm font-medium" htmlFor="email">
Subscribe to our newsletter
</Label>
<Input className="input variant-mixed sz-md" placeholder="Your email" type="email" id="email" required name="email" />
</div>
<Button type="submit" className="mt-3">
<span>Subscribe</span>
</Button>
</form>
</div>
</div>
<div className="bg-muted mt-16 flex items-center justify-between rounded-md p-4 px-6 py-3">
<span className="text-title">&copy; tailus 2021 - Present</span>
<Link href="#" className="text-muted-foreground hover:text-primary text-sm">
Licence
</Link>
</div>
</div>
</footer>
)
}

View File

@ -0,0 +1,47 @@
import Link from 'next/link'
const links = [
{
title: 'Features',
href: '#',
},
{
title: 'Solution',
href: '#',
},
{
title: 'Customers',
href: '#',
},
{
title: 'Pricing',
href: '#',
},
{
title: 'Help',
href: '#',
},
{
title: 'About',
href: '#',
},
]
export default function FooterSection() {
return (
<footer className="border-b bg-white py-12 dark:bg-transparent">
<div className="mx-auto max-w-5xl px-6">
<div className="flex flex-wrap justify-between gap-6">
<span className="text-muted-foreground order-last block text-center text-sm md:order-first">© {new Date().getFullYear()} Tailus UI, All rights reserved</span>
<div className="order-first flex flex-wrap justify-center gap-6 text-sm md:order-last">
{links.map((link, index) => (
<Link key={index} href={link.href} className="text-muted-foreground hover:text-primary block duration-150">
<span>{link.title}</span>
</Link>
))}
</div>
</div>
</div>
</footer>
)
}

View File

@ -0,0 +1,84 @@
import { Logo } from '@/components/logo'
import Link from 'next/link'
const links = [
{
title: 'Features',
href: '#',
},
{
title: 'Solution',
href: '#',
},
{
title: 'Customers',
href: '#',
},
{
title: 'Pricing',
href: '#',
},
{
title: 'Help',
href: '#',
},
{
title: 'About',
href: '#',
},
]
export default function FooterSection() {
return (
<footer className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<Link href="/" aria-label="go home" className="mx-auto block size-fit">
<Logo />
</Link>
<div className="my-8 flex flex-wrap justify-center gap-6 text-sm">
{links.map((link, index) => (
<Link key={index} href={link.href} className="text-muted-foreground hover:text-primary block duration-150">
<span>{link.title}</span>
</Link>
))}
</div>
<div className="my-8 flex flex-wrap justify-center gap-6 text-sm">
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="X/Twitter" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M10.488 14.651L15.25 21h7l-7.858-10.478L20.93 3h-2.65l-5.117 5.886L8.75 3h-7l7.51 10.015L2.32 21h2.65zM16.25 19L5.75 5h2l10.5 14z"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93zM6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37z"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Facebook" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M22 12c0-5.52-4.48-10-10-10S2 6.48 2 12c0 4.84 3.44 8.87 8 9.8V15H8v-3h2V9.5C10 7.57 11.57 6 13.5 6H16v3h-2c-.55 0-1 .45-1 1v2h3v3h-3v6.95c5.05-.5 9-4.76 9-9.95"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Threads" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M19.25 8.505c-1.577-5.867-7-5.5-7-5.5s-7.5-.5-7.5 8.995s7.5 8.996 7.5 8.996s4.458.296 6.5-3.918c.667-1.858.5-5.573-6-5.573c0 0-3 0-3 2.5c0 .976 1 2 2.5 2s3.171-1.027 3.5-3c1-6-4.5-6.5-6-4" color="currentColor"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Instagram" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4zm9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8A1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5a5 5 0 0 1-5 5a5 5 0 0 1-5-5a5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="TikTok" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.6 5.82s.51.5 0 0A4.28 4.28 0 0 1 15.54 3h-3.09v12.4a2.59 2.59 0 0 1-2.59 2.5c-1.42 0-2.6-1.16-2.6-2.6c0-1.72 1.66-3.01 3.37-2.48V9.66c-3.45-.46-6.47 2.22-6.47 5.64c0 3.33 2.76 5.7 5.69 5.7c3.14 0 5.69-2.55 5.69-5.7V9.01a7.35 7.35 0 0 0 4.3 1.38V7.3s-1.88.09-3.24-1.48"></path>
</svg>
</Link>
</div>
<span className="text-muted-foreground block text-center text-sm"> © {new Date().getFullYear()} Tailus UI, All rights reserved</span>
</div>
</footer>
)
}

View File

@ -0,0 +1,219 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { cn } from '@/lib/utils'
import { ChevronsUpDown } from 'lucide-react'
import Link from 'next/link'
const links = [
{
group: 'Product',
items: [
{
title: 'Features',
href: '#',
},
{
title: 'Solution',
href: '#',
},
{
title: 'Customers',
href: '#',
},
{
title: 'Pricing',
href: '#',
},
{
title: 'Help',
href: '#',
},
{
title: 'About',
href: '#',
},
],
},
{
group: 'Solution',
items: [
{
title: 'Startup',
href: '#',
},
{
title: 'Freelancers',
href: '#',
},
{
title: 'Organizations',
href: '#',
},
{
title: 'Students',
href: '#',
},
{
title: 'Collaboration',
href: '#',
},
{
title: 'Design',
href: '#',
},
{
title: 'Management',
href: '#',
},
],
},
{
group: 'Company',
items: [
{
title: 'About',
href: '#',
},
{
title: 'Careers',
href: '#',
},
{
title: 'Blog',
href: '#',
},
{
title: 'Press',
href: '#',
},
{
title: 'Contact',
href: '#',
},
{
title: 'Help',
href: '#',
},
],
},
{
group: 'Legal',
items: [
{
title: 'Licence',
href: '#',
},
{
title: 'Privacy',
href: '#',
},
{
title: 'Cookies',
href: '#',
},
{
title: 'Security',
href: '#',
},
],
},
]
export default function FooterSection() {
return (
<footer className="border-b bg-white pt-20 dark:bg-transparent">
<div className="mb-8 border-b md:mb-12">
<div className="mx-auto flex max-w-5xl flex-wrap items-end justify-between gap-6 px-6 pb-6">
<Link href="/" aria-label="go home" className="block size-fit">
<Logo />
</Link>
<div className="flex flex-wrap justify-center gap-6 text-sm">
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="X/Twitter" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M10.488 14.651L15.25 21h7l-7.858-10.478L20.93 3h-2.65l-5.117 5.886L8.75 3h-7l7.51 10.015L2.32 21h2.65zM16.25 19L5.75 5h2l10.5 14z"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93zM6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37z"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Facebook" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M22 12c0-5.52-4.48-10-10-10S2 6.48 2 12c0 4.84 3.44 8.87 8 9.8V15H8v-3h2V9.5C10 7.57 11.57 6 13.5 6H16v3h-2c-.55 0-1 .45-1 1v2h3v3h-3v6.95c5.05-.5 9-4.76 9-9.95"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Threads" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M19.25 8.505c-1.577-5.867-7-5.5-7-5.5s-7.5-.5-7.5 8.995s7.5 8.996 7.5 8.996s4.458.296 6.5-3.918c.667-1.858.5-5.573-6-5.573c0 0-3 0-3 2.5c0 .976 1 2 2.5 2s3.171-1.027 3.5-3c1-6-4.5-6.5-6-4" color="currentColor"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Instagram" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4zm9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8A1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5a5 5 0 0 1-5 5a5 5 0 0 1-5-5a5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="TikTok" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.6 5.82s.51.5 0 0A4.28 4.28 0 0 1 15.54 3h-3.09v12.4a2.59 2.59 0 0 1-2.59 2.5c-1.42 0-2.6-1.16-2.6-2.6c0-1.72 1.66-3.01 3.37-2.48V9.66c-3.45-.46-6.47 2.22-6.47 5.64c0 3.33 2.76 5.7 5.69 5.7c3.14 0 5.69-2.55 5.69-5.7V9.01a7.35 7.35 0 0 0 4.3 1.38V7.3s-1.88.09-3.24-1.48"></path>
</svg>
</Link>
</div>
</div>
</div>
<div className="mx-auto max-w-5xl px-6">
<div className="grid gap-12 md:grid-cols-5 md:gap-0 lg:grid-cols-4">
<div className="grid grid-cols-2 gap-6 sm:grid-cols-4 md:col-span-5 md:row-start-1 lg:col-span-3">
{links.map((link, index) => (
<div key={index} className="space-y-4 text-sm">
<span className="block font-medium">{link.group}</span>
{link.items.map((item, index) => (
<Link key={index} href={item.href} className="text-muted-foreground hover:text-primary block duration-150">
<span>{item.title}</span>
</Link>
))}
</div>
))}
</div>
<form className="row-start-1 border-b pb-8 text-sm md:col-span-2 md:border-none lg:col-span-1">
<div className="space-y-4">
<Label htmlFor="mail" className="block font-medium">
Newsletter
</Label>
<div className="flex gap-2">
<Input type="email" id="mail" name="mail" placeholder="Your email" className="h-8 text-sm" />
<Button size="sm">Submit</Button>
</div>
<span className="text-muted-foreground block text-sm">Don't miss any update!</span>
</div>
</form>
</div>
<div className="mt-12 flex flex-wrap items-end justify-between gap-6 border-t py-6">
<small className="text-muted-foreground order-last block text-center text-sm md:order-first">© {new Date().getFullYear()} Tailus UI, All rights reserved</small>
<form action="">
<div className="relative">
<ChevronsUpDown className="pointer-events-none absolute inset-y-0 right-2 my-auto opacity-75" size="0.75rem" />
<select
className={cn(
'border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground shadow-xs flex h-9 w-full min-w-32 appearance-none rounded-md border bg-transparent px-3 py-1 text-base outline-none transition-[color,box-shadow] file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive'
)}
name="language">
<option value="1">English</option>
<option value="2">Espanol</option>
<option value="3">Français</option>
<option value="4">Swahili</option>
<option value="5">Lingala</option>
</select>
</div>
</form>
</div>
</div>
</footer>
)
}

View File

@ -0,0 +1,183 @@
import { Logo } from '@/components/logo'
import Link from 'next/link'
const links = [
{
group: 'Product',
items: [
{
title: 'Features',
href: '#',
},
{
title: 'Solution',
href: '#',
},
{
title: 'Customers',
href: '#',
},
{
title: 'Pricing',
href: '#',
},
{
title: 'Help',
href: '#',
},
{
title: 'About',
href: '#',
},
],
},
{
group: 'Solution',
items: [
{
title: 'Startup',
href: '#',
},
{
title: 'Freelancers',
href: '#',
},
{
title: 'Organizations',
href: '#',
},
{
title: 'Students',
href: '#',
},
{
title: 'Collaboration',
href: '#',
},
{
title: 'Design',
href: '#',
},
{
title: 'Management',
href: '#',
},
],
},
{
group: 'Company',
items: [
{
title: 'About',
href: '#',
},
{
title: 'Careers',
href: '#',
},
{
title: 'Blog',
href: '#',
},
{
title: 'Press',
href: '#',
},
{
title: 'Contact',
href: '#',
},
{
title: 'Help',
href: '#',
},
],
},
{
group: 'Legal',
items: [
{
title: 'Licence',
href: '#',
},
{
title: 'Privacy',
href: '#',
},
{
title: 'Cookies',
href: '#',
},
{
title: 'Security',
href: '#',
},
],
},
]
export default function FooterSection() {
return (
<footer className="border-b bg-white pt-20 dark:bg-transparent">
<div className="mx-auto max-w-5xl px-6">
<div className="grid gap-12 md:grid-cols-5">
<div className="md:col-span-2">
<Link href="/" aria-label="go home" className="block size-fit">
<Logo />
</Link>
</div>
<div className="grid grid-cols-2 gap-6 sm:grid-cols-4 md:col-span-3">
{links.map((link, index) => (
<div key={index} className="space-y-4 text-sm">
<span className="block font-medium">{link.group}</span>
{link.items.map((item, index) => (
<Link key={index} href={item.href} className="text-muted-foreground hover:text-primary block duration-150">
<span>{item.title}</span>
</Link>
))}
</div>
))}
</div>
</div>
<div className="mt-12 flex flex-wrap items-end justify-between gap-6 border-t py-6">
<span className="text-muted-foreground order-last block text-center text-sm md:order-first">© {new Date().getFullYear()} Tailus UI, All rights reserved</span>
<div className="order-first flex flex-wrap justify-center gap-6 text-sm md:order-last">
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="X/Twitter" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M10.488 14.651L15.25 21h7l-7.858-10.478L20.93 3h-2.65l-5.117 5.886L8.75 3h-7l7.51 10.015L2.32 21h2.65zM16.25 19L5.75 5h2l10.5 14z"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93zM6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37z"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Facebook" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M22 12c0-5.52-4.48-10-10-10S2 6.48 2 12c0 4.84 3.44 8.87 8 9.8V15H8v-3h2V9.5C10 7.57 11.57 6 13.5 6H16v3h-2c-.55 0-1 .45-1 1v2h3v3h-3v6.95c5.05-.5 9-4.76 9-9.95"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Threads" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" d="M19.25 8.505c-1.577-5.867-7-5.5-7-5.5s-7.5-.5-7.5 8.995s7.5 8.996 7.5 8.996s4.458.296 6.5-3.918c.667-1.858.5-5.573-6-5.573c0 0-3 0-3 2.5c0 .976 1 2 2.5 2s3.171-1.027 3.5-3c1-6-4.5-6.5-6-4" color="currentColor"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="Instagram" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4zm9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8A1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5a5 5 0 0 1-5 5a5 5 0 0 1-5-5a5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3"></path>
</svg>
</Link>
<Link href="#" target="_blank" rel="noopener noreferrer" aria-label="TikTok" className="text-muted-foreground hover:text-primary block">
<svg className="size-6" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" d="M16.6 5.82s.51.5 0 0A4.28 4.28 0 0 1 15.54 3h-3.09v12.4a2.59 2.59 0 0 1-2.59 2.5c-1.42 0-2.6-1.16-2.6-2.6c0-1.72 1.66-3.01 3.37-2.48V9.66c-3.45-.46-6.47 2.22-6.47 5.64c0 3.33 2.76 5.7 5.69 5.7c3.14 0 5.69-2.55 5.69-5.7V9.01a7.35 7.35 0 0 0 4.3 1.38V7.3s-1.88.09-3.24-1.48"></path>
</svg>
</Link>
</div>
</div>
</div>
</footer>
)
}

View File

@ -0,0 +1,123 @@
'use client'
import React from 'react'
import Link from 'next/link'
import { Logo } from '@/components/logo'
import { ArrowRight, Menu, Rocket, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import Image from 'next/image'
const menuItems = [
{ name: 'Features', href: '#' },
{ name: 'Solution', href: '#' },
{ name: 'Pricing', href: '#' },
{ name: 'About', href: '#' },
]
export default function HeroSection() {
const [menuState, setMenuState] = React.useState(false)
return (
<>
<header>
<nav data-state={menuState && 'active'} className="fixed z-20 w-full border-b border-dashed bg-white backdrop-blur md:relative dark:bg-zinc-950/50 lg:dark:bg-transparent">
<div className="m-auto max-w-5xl px-6">
<div className="flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full justify-between lg:w-auto">
<Link href="/" aria-label="home" className="flex items-center space-x-2">
<Logo />
</Link>
<button onClick={() => setMenuState(!menuState)} aria-label={menuState == true ? 'Close Menu' : 'Open Menu'} className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:pr-4">
<ul className="space-y-6 text-base lg:flex lg:gap-8 lg:space-y-0 lg:text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link href={item.href} className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit lg:border-l lg:pl-6">
<Button asChild variant="outline" size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button asChild size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
<main className="overflow-hidden">
<section>
<div className="relative pt-24">
<div className="mx-auto max-w-7xl px-6">
<div className="max-w-3xl text-center sm:mx-auto lg:mr-auto lg:mt-0 lg:w-4/5">
<Link href="/" className="rounded-(--radius) mx-auto flex w-fit items-center gap-2 border p-1 pr-3">
<span className="bg-muted rounded-[calc(var(--radius)-0.25rem)] px-2 py-1 text-xs">New</span>
<span className="text-sm">Introduction Tailus UI Html</span>
<span className="bg-(--color-border) block h-4 w-px"></span>
<ArrowRight className="size-4" />
</Link>
<h1 className="mt-8 text-balance text-4xl font-semibold md:text-5xl xl:text-6xl xl:[line-height:1.125]">Modern Software testing reimagined</h1>
<p className="mx-auto mt-8 hidden max-w-2xl text-wrap text-lg sm:block">Tailwindcss highly customizable components for building modern websites and applications that look and feel the way you mean it.</p>
<p className="mx-auto mt-6 max-w-2xl text-wrap sm:hidden">Highly customizable components for building modern websites and applications, with your personal spark.</p>
<div className="mt-8">
<Button size="lg" asChild>
<Link href="#">
<Rocket className="relative size-4" />
<span className="text-nowrap">Start Building</span>
</Link>
</Button>
</div>
</div>
</div>
<div className="relative mt-16">
<div aria-hidden className="bg-linear-to-b to-background absolute inset-0 z-10 from-transparent from-35%" />
<div className="relative mx-auto max-w-6xl overflow-hidden px-4">
<Image className="z-2 border-border/25 relative hidden rounded-2xl border dark:block" src="/blocks/music.png" alt="app screen" width={2796} height={2008} />
<Image className="z-2 border-border/25 relative rounded-2xl border dark:hidden" src="/blocks/music-light.png" alt="app screen" width={2796} height={2008} />
</div>
</div>
</div>
</section>
<section className="bg-background relative z-10 pb-16">
<div className="m-auto max-w-5xl px-6">
<h2 className="text-center text-lg font-medium">Your favorite companies are our partners.</h2>
<div className="mx-auto mt-12 flex max-w-4xl flex-wrap items-center justify-center gap-x-12 gap-y-8 sm:gap-x-16 sm:gap-y-12">
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/column.svg" alt="Column Logo" height="16" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/github.svg" alt="GitHub Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/laravel.svg" alt="Laravel Logo" height="16" width="auto" />
<img className="h-7 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/lilly.svg" alt="Lilly Logo" height="28" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg" alt="Lemon Squeezy Logo" height="20" width="auto" />
<img className="h-6 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/openai.svg" alt="OpenAI Logo" height="24" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/tailwindcss.svg" alt="Tailwind CSS Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/vercel.svg" alt="Vercel Logo" height="20" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/zapier.svg" alt="Zapier Logo" height="20" width="auto" />
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,159 @@
import React from 'react'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { HeroHeader } from '@/components/nsui/hero9-header'
import { InfiniteSlider } from '@/components/motion-primitives/infinite-slider'
import { ProgressiveBlur } from '@/components/motion-primitives/progressive-blur'
import { ChevronRight } from 'lucide-react'
export default function HeroSection() {
return (
<>
<HeroHeader />
<main className="overflow-x-hidden">
<section>
<div className="py-24 md:pb-32 lg:pb-36 lg:pt-72">
<div className="relative mx-auto flex max-w-7xl flex-col px-6 lg:block lg:px-12">
<div className="mx-auto max-w-lg text-center lg:ml-0 lg:max-w-full lg:text-left">
<h1 className="mt-8 max-w-2xl text-balance text-5xl md:text-6xl lg:mt-16 xl:text-7xl">Build 10x Faster with NS</h1>
<p className="mt-8 max-w-2xl text-balance text-lg">Highly customizable components for building modern websites and applications you mean it.</p>
<div className="mt-12 flex flex-col items-center justify-center gap-2 sm:flex-row lg:justify-start">
<Button
asChild
size="lg"
className="h-12 rounded-full pl-5 pr-3 text-base">
<Link href="#link">
<span className="text-nowrap">Start Building</span>
<ChevronRight className="ml-1" />
</Link>
</Button>
<Button
key={2}
asChild
size="lg"
variant="ghost"
className="h-12 rounded-full px-5 text-base hover:bg-zinc-950/5 dark:hover:bg-white/5">
<Link href="#link">
<span className="text-nowrap">Request a demo</span>
</Link>
</Button>
</div>
</div>
</div>
<div className="aspect-2/3 absolute inset-1 -z-10 overflow-hidden rounded-3xl border border-black/10 lg:aspect-video lg:rounded-[3rem] dark:border-white/5">
<video
autoPlay
loop
className="size-full -scale-x-100 object-cover opacity-50 invert dark:opacity-35 dark:invert-0 dark:lg:opacity-75"
src="https://res.cloudinary.com/dg4jhba5c/video/upload/v1741605033/dna_ttplyu.mp4"></video>
</div>
</div>
</section>
<section className="bg-background pb-2">
<div className="group relative m-auto max-w-7xl px-6">
<div className="flex flex-col items-center md:flex-row">
<div className="md:max-w-44 md:border-r md:pr-6">
<p className="text-end text-sm">Powering the best teams</p>
</div>
<div className="relative py-6 md:w-[calc(100%-11rem)]">
<InfiniteSlider
speedOnHover={20}
speed={40}
gap={112}>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nvidia.svg"
alt="Nvidia Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/column.svg"
alt="Column Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/github.svg"
alt="GitHub Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nike.svg"
alt="Nike Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg"
alt="Lemon Squeezy Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/laravel.svg"
alt="Laravel Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-7 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lilly.svg"
alt="Lilly Logo"
height="28"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-6 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/openai.svg"
alt="OpenAI Logo"
height="24"
width="auto"
/>
</div>
</InfiniteSlider>
<div className="bg-linear-to-r from-background absolute inset-y-0 left-0 w-20"></div>
<div className="bg-linear-to-l from-background absolute inset-y-0 right-0 w-20"></div>
<ProgressiveBlur
className="pointer-events-none absolute left-0 top-0 h-full w-20"
direction="left"
blurIntensity={1}
/>
<ProgressiveBlur
className="pointer-events-none absolute right-0 top-0 h-full w-20"
direction="right"
blurIntensity={1}
/>
</div>
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,158 @@
import React from 'react'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import Image from 'next/image'
import { HeroHeader } from '@/components/nsui/hero8-header'
import { InfiniteSlider } from '@/components/motion-primitives/infinite-slider'
import { ProgressiveBlur } from '@/components/motion-primitives/progressive-blur'
export default function HeroSection() {
return (
<>
<HeroHeader />
<main className="overflow-x-hidden">
<section>
<div className="pb-24 pt-12 md:pb-32 lg:pb-56 lg:pt-44">
<div className="relative mx-auto flex max-w-6xl flex-col px-6 lg:block">
<div className="mx-auto max-w-lg text-center lg:ml-0 lg:w-1/2 lg:text-left">
<h1 className="mt-8 max-w-2xl text-balance text-5xl font-medium md:text-6xl lg:mt-16 xl:text-7xl">Ship 10x Faster with NS</h1>
<p className="mt-8 max-w-2xl text-pretty text-lg">Highly customizable components for building modern websites and applications that look and feel the way you mean it.</p>
<div className="mt-12 flex flex-col items-center justify-center gap-2 sm:flex-row lg:justify-start">
<Button
asChild
size="lg"
className="px-5 text-base">
<Link href="#link">
<span className="text-nowrap">Start Building</span>
</Link>
</Button>
<Button
key={2}
asChild
size="lg"
variant="ghost"
className="px-5 text-base">
<Link href="#link">
<span className="text-nowrap">Request a demo</span>
</Link>
</Button>
</div>
</div>
<Image
className="-z-10 order-first ml-auto h-56 w-full object-cover invert sm:h-96 lg:absolute lg:inset-0 lg:-right-20 lg:-top-96 lg:order-last lg:h-max lg:w-2/3 lg:object-contain dark:mix-blend-lighten dark:invert-0"
src="https://res.cloudinary.com/dg4jhba5c/image/upload/v1741605150/abstract-bg_wq4f8w.jpg"
alt="Abstract Object"
height="4000"
width="3000"
/>
</div>
</div>
</section>
<section className="bg-background pb-16 md:pb-32">
<div className="group relative m-auto max-w-6xl px-6">
<div className="flex flex-col items-center md:flex-row">
<div className="md:max-w-44 md:border-r md:pr-6">
<p className="text-end text-sm">Powering the best teams</p>
</div>
<div className="relative py-6 md:w-[calc(100%-11rem)]">
<InfiniteSlider
speedOnHover={20}
speed={40}
gap={112}>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nvidia.svg"
alt="Nvidia Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/column.svg"
alt="Column Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/github.svg"
alt="GitHub Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nike.svg"
alt="Nike Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg"
alt="Lemon Squeezy Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/laravel.svg"
alt="Laravel Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-7 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lilly.svg"
alt="Lilly Logo"
height="28"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-6 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/openai.svg"
alt="OpenAI Logo"
height="24"
width="auto"
/>
</div>
</InfiniteSlider>
<div className="bg-linear-to-r from-background absolute inset-y-0 left-0 w-20"></div>
<div className="bg-linear-to-l from-background absolute inset-y-0 right-0 w-20"></div>
<ProgressiveBlur
className="pointer-events-none absolute left-0 top-0 h-full w-20"
direction="left"
blurIntensity={1}
/>
<ProgressiveBlur
className="pointer-events-none absolute right-0 top-0 h-full w-20"
direction="right"
blurIntensity={1}
/>
</div>
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,127 @@
'use client'
import { Logo } from '@/components/logo'
import Link from 'next/link'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Menu, X } from 'lucide-react'
import Image from 'next/image'
const menuItems = [
{ name: 'Features', href: '#' },
{ name: 'Solution', href: '#' },
{ name: 'Pricing', href: '#' },
{ name: 'About', href: '#' },
]
export default function HeroSection() {
const [menuState, setMenuState] = useState(false)
return (
<>
<header>
<nav data-state={menuState && 'active'} className="fixed z-20 w-full border-b border-dashed bg-white backdrop-blur md:relative dark:bg-zinc-950/50 lg:dark:bg-transparent">
<div className="m-auto max-w-5xl px-6">
<div className="flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full justify-between lg:w-auto">
<Link href="/" aria-label="home" className="flex items-center space-x-2">
<Logo />
</Link>
<button onClick={() => setMenuState(!menuState)} aria-label={menuState == true ? 'Close Menu' : 'Open Menu'} className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:pr-4">
<ul className="space-y-6 text-base lg:flex lg:gap-8 lg:space-y-0 lg:text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link href={item.href} className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit lg:border-l lg:pl-6">
<Button asChild variant="outline" size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button asChild size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
<main>
<div aria-hidden className="z-2 absolute inset-0 isolate hidden opacity-50 contain-strict lg:block">
<div className="w-140 h-320 -translate-y-87.5 absolute left-0 top-0 -rotate-45 rounded-full bg-[radial-gradient(68.54%_68.72%_at_55.02%_31.46%,hsla(0,0%,85%,.08)_0,hsla(0,0%,55%,.02)_50%,hsla(0,0%,45%,0)_80%)]" />
<div className="h-320 absolute left-0 top-0 w-60 -rotate-45 rounded-full bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.06)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)] [translate:5%_-50%]" />
<div className="h-320 -translate-y-87.5 absolute left-0 top-0 w-60 -rotate-45 bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.04)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)]" />
</div>
<section className="overflow-hidden bg-white dark:bg-transparent">
<div className="relative mx-auto max-w-5xl px-6 py-28 lg:py-24">
<div className="relative z-10 mx-auto max-w-2xl text-center">
<h1 className="text-balance text-4xl font-semibold md:text-5xl lg:text-6xl">Modern Software testing reimagined</h1>
<p className="mx-auto my-8 max-w-2xl text-xl">Officiis laudantium excepturi ducimus rerum dignissimos, and tempora nam vitae, excepturi ducimus iste provident dolores.</p>
<Button asChild size="lg">
<Link href="#">
<span className="btn-label">Start Building</span>
</Link>
</Button>
</div>
</div>
<div className="mx-auto -mt-16 max-w-7xl">
<div className="perspective-distant -mr-16 pl-16 lg:-mr-56 lg:pl-56">
<div className="[transform:rotateX(20deg);]">
<div className="lg:h-176 relative skew-x-[.36rad]">
<div aria-hidden className="bg-linear-to-b from-background to-background z-1 absolute -inset-16 via-transparent sm:-inset-32" />
<div aria-hidden className="bg-linear-to-r from-background to-background z-1 absolute -inset-16 bg-white/50 via-transparent sm:-inset-32 dark:bg-transparent" />
<div aria-hidden className="absolute -inset-16 bg-[linear-gradient(to_right,var(--color-border)_1px,transparent_1px),linear-gradient(to_bottom,var(--color-border)_1px,transparent_1px)] bg-[size:24px_24px] [--color-border:var(--color-zinc-400)] sm:-inset-32 dark:[--color-border:color-mix(in_oklab,var(--color-white)_20%,transparent)]" />
<div aria-hidden className="from-background z-11 absolute inset-0 bg-gradient-to-l" />
<div aria-hidden className="z-2 absolute inset-0 size-full items-center px-5 py-24 [background:radial-gradient(125%_125%_at_50%_10%,transparent_40%,var(--color-background)_100%)]" />
<div aria-hidden className="z-2 absolute inset-0 size-full items-center px-5 py-24 [background:radial-gradient(125%_125%_at_50%_10%,transparent_40%,var(--color-background)_100%)]" />
<Image className="rounded-(--radius) z-1 relative border dark:hidden" src="/blocks/card.png" alt="tailus ui hero section" width={2880} height={2074} />
<Image className="rounded-(--radius) z-1 relative hidden border dark:block" src="/blocks/dark-card.webp" alt="tailus ui hero section" width={2880} height={2074} />
</div>
</div>
</div>
</div>
</section>
<section className="bg-background relative z-10 py-16">
<div className="m-auto max-w-5xl px-6">
<h2 className="text-center text-lg font-medium">Your favorite companies are our partners.</h2>
<div className="mx-auto mt-20 flex max-w-4xl flex-wrap items-center justify-center gap-x-12 gap-y-8 sm:gap-x-16 sm:gap-y-12">
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/column.svg" alt="Column Logo" height="16" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/github.svg" alt="GitHub Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/laravel.svg" alt="Laravel Logo" height="16" width="auto" />
<img className="h-7 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/lilly.svg" alt="Lilly Logo" height="28" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg" alt="Lemon Squeezy Logo" height="20" width="auto" />
<img className="h-6 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/openai.svg" alt="OpenAI Logo" height="24" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/tailwindcss.svg" alt="Tailwind CSS Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/vercel.svg" alt="Vercel Logo" height="20" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/zapier.svg" alt="Zapier Logo" height="20" width="auto" />
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,286 @@
import React from 'react'
import Link from 'next/link'
import { ArrowRight, ChevronRight } from 'lucide-react'
import { Button } from '@/components/ui/button'
import Image from 'next/image'
import { TextEffect } from '@/components/motion-primitives/text-effect'
import { AnimatedGroup } from '@/components/motion-primitives/animated-group'
import { HeroHeader } from '@/components/nsui/hero5-header'
const transitionVariants = {
item: {
hidden: {
opacity: 0,
filter: 'blur(12px)',
y: 12,
},
visible: {
opacity: 1,
filter: 'blur(0px)',
y: 0,
transition: {
type: 'spring',
bounce: 0.3,
duration: 1.5,
},
},
},
}
export default function HeroSection() {
return (
<>
<HeroHeader />
<main className="overflow-hidden">
<div
aria-hidden
className="absolute inset-0 isolate hidden opacity-65 contain-strict lg:block">
<div className="w-140 h-320 -translate-y-87.5 absolute left-0 top-0 -rotate-45 rounded-full bg-[radial-gradient(68.54%_68.72%_at_55.02%_31.46%,hsla(0,0%,85%,.08)_0,hsla(0,0%,55%,.02)_50%,hsla(0,0%,45%,0)_80%)]" />
<div className="h-320 absolute left-0 top-0 w-60 -rotate-45 rounded-full bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.06)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)] [translate:5%_-50%]" />
<div className="h-320 -translate-y-87.5 absolute left-0 top-0 w-60 -rotate-45 bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.04)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)]" />
</div>
<section>
<div className="relative pt-24 md:pt-36">
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
delayChildren: 1,
},
},
},
item: {
hidden: {
opacity: 0,
y: 20,
},
visible: {
opacity: 1,
y: 0,
transition: {
type: 'spring',
bounce: 0.3,
duration: 2,
},
},
},
}}
className="absolute inset-0 -z-20">
<Image
src="https://res.cloudinary.com/dg4jhba5c/image/upload/v1741605538/night-background_ni3vqb.jpg"
alt="background"
className="absolute inset-x-0 top-56 -z-20 hidden lg:top-32 dark:block"
width="3276"
height="4095"
/>
</AnimatedGroup>
<div className="absolute inset-0 -z-10 size-full [background:radial-gradient(125%_125%_at_50%_100%,transparent_0%,var(--color-background)_75%)]"></div>
<div className="mx-auto max-w-7xl px-6">
<div className="text-center sm:mx-auto lg:mr-auto lg:mt-0">
<AnimatedGroup variants={transitionVariants}>
<Link
href="#link"
className="hover:bg-background dark:hover:border-t-border bg-muted group mx-auto flex w-fit items-center gap-4 rounded-full border p-1 pl-4 shadow-md shadow-zinc-950/5 transition-colors duration-300 dark:border-t-white/5 dark:shadow-zinc-950">
<span className="text-foreground text-sm">Introducing Support for AI Models</span>
<span className="dark:border-background block h-4 w-0.5 border-l bg-white dark:bg-zinc-700"></span>
<div className="bg-background group-hover:bg-muted size-6 overflow-hidden rounded-full duration-500">
<div className="flex w-12 -translate-x-1/2 duration-500 ease-in-out group-hover:translate-x-0">
<span className="flex size-6">
<ArrowRight className="m-auto size-3" />
</span>
<span className="flex size-6">
<ArrowRight className="m-auto size-3" />
</span>
</div>
</div>
</Link>
</AnimatedGroup>
<TextEffect
preset="fade-in-blur"
speedSegment={0.3}
as="h1"
className="mt-8 text-balance text-6xl md:text-7xl lg:mt-16 xl:text-[5.25rem]">
Modern Solutions for Customer Engagement
</TextEffect>
<TextEffect
per="line"
preset="fade-in-blur"
speedSegment={0.3}
delay={0.5}
as="p"
className="mx-auto mt-8 max-w-2xl text-balance text-lg">
Highly customizable components for building modern websites and applications that look and feel the way you mean it.
</TextEffect>
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.75,
},
},
},
...transitionVariants,
}}
className="mt-12 flex flex-col items-center justify-center gap-2 md:flex-row">
<div
key={1}
className="bg-foreground/10 rounded-[calc(var(--radius-xl)+0.125rem)] border p-0.5">
<Button
asChild
size="lg"
className="rounded-xl px-5 text-base">
<Link href="#link">
<span className="text-nowrap">Start Building</span>
</Link>
</Button>
</div>
<Button
key={2}
asChild
size="lg"
variant="ghost"
className="h-10.5 rounded-xl px-5">
<Link href="#link">
<span className="text-nowrap">Request a demo</span>
</Link>
</Button>
</AnimatedGroup>
</div>
</div>
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.75,
},
},
},
...transitionVariants,
}}>
<div className="relative -mr-56 mt-8 overflow-hidden px-2 sm:mr-0 sm:mt-12 md:mt-20">
<div
aria-hidden
className="bg-linear-to-b to-background absolute inset-0 z-10 from-transparent from-35%"
/>
<div className="inset-shadow-2xs ring-background dark:inset-shadow-white/20 bg-background relative mx-auto max-w-6xl overflow-hidden rounded-2xl border p-4 shadow-lg shadow-zinc-950/15 ring-1">
<Image
className="bg-background aspect-15/8 relative hidden rounded-2xl dark:block"
src="/blocks/mail2.png"
alt="app screen"
width="2700"
height="1440"
/>
<Image
className="z-2 border-border/25 aspect-15/8 relative rounded-2xl border dark:hidden"
src="/blocks/mail2-light.png"
alt="app screen"
width="2700"
height="1440"
/>
</div>
</div>
</AnimatedGroup>
</div>
</section>
<section className="bg-background pb-16 pt-16 md:pb-32">
<div className="group relative m-auto max-w-5xl px-6">
<div className="absolute inset-0 z-10 flex scale-95 items-center justify-center opacity-0 duration-500 group-hover:scale-100 group-hover:opacity-100">
<Link
href="/"
className="block text-sm duration-150 hover:opacity-75">
<span> Meet Our Customers</span>
<ChevronRight className="ml-1 inline-block size-3" />
</Link>
</div>
<div className="group-hover:blur-xs mx-auto mt-12 grid max-w-2xl grid-cols-4 gap-x-12 gap-y-8 transition-all duration-500 group-hover:opacity-50 sm:gap-x-16 sm:gap-y-14">
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nvidia.svg"
alt="Nvidia Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/column.svg"
alt="Column Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/github.svg"
alt="GitHub Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nike.svg"
alt="Nike Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg"
alt="Lemon Squeezy Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/laravel.svg"
alt="Laravel Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-7 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lilly.svg"
alt="Lilly Logo"
height="28"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-6 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/openai.svg"
alt="OpenAI Logo"
height="24"
width="auto"
/>
</div>
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,248 @@
'use client'
import React from 'react'
import { Swiper, SwiperSlide } from 'swiper/react'
import { Autoplay, EffectCoverflow } from 'swiper/modules'
import 'swiper/css'
import 'swiper/css/autoplay'
import 'swiper/css/navigation'
import 'swiper/css/pagination'
import 'swiper/css/effect-coverflow'
import Link from 'next/link'
import { Logo } from '@/components/logo'
import { ArrowRight, Menu, Rocket, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
const menuItems = [
{ name: 'Features', href: '#' },
{ name: 'Solution', href: '#' },
{ name: 'Pricing', href: '#' },
{ name: 'About', href: '#' },
]
export default function HeroSection() {
const [menuState, setMenuState] = React.useState(false)
return (
<>
<header>
<nav data-state={menuState && 'active'} className="fixed z-20 w-full border-b border-dashed bg-white backdrop-blur md:relative dark:bg-zinc-950/50 lg:dark:bg-transparent">
<div className="m-auto max-w-5xl px-6">
<div className="flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full justify-between lg:w-auto">
<Link href="/" aria-label="home" className="flex items-center space-x-2">
<Logo />
</Link>
<button onClick={() => setMenuState(!menuState)} aria-label={menuState == true ? 'Close Menu' : 'Open Menu'} className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:pr-4">
<ul className="space-y-6 text-base lg:flex lg:gap-8 lg:space-y-0 lg:text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link href={item.href} className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit lg:border-l lg:pl-6">
<Button asChild variant="outline" size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button asChild size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
<main className="overflow-hidden">
<section className="relative">
<div className="relative py-24 lg:py-28">
<div className="mx-auto max-w-7xl px-6 md:px-12">
<div className="text-center sm:mx-auto sm:w-10/12 lg:mr-auto lg:mt-0 lg:w-4/5">
<Link href="/" className="rounded-(--radius) mx-auto flex w-fit items-center gap-2 border p-1 pr-3">
<span className="bg-muted rounded-[calc(var(--radius)-0.25rem)] px-2 py-1 text-xs">New</span>
<span className="text-sm">Introduction Tailus UI Html</span>
<span className="bg-(--color-border) block h-4 w-px"></span>
<ArrowRight className="size-4" />
</Link>
<h1 className="mt-8 text-4xl font-semibold md:text-5xl xl:text-5xl xl:[line-height:1.125]">
Tame the Wild West <br /> of Frontend Development
</h1>
<p className="mx-auto mt-8 hidden max-w-2xl text-wrap text-lg sm:block">Tailwindcss highly customizable components for building modern websites and applications that look and feel the way you mean it.</p>
<p className="mx-auto mt-6 max-w-2xl text-wrap sm:hidden">Highly customizable components for building modern websites and applications, with your personal spark.</p>
<div className="mt-8">
<Button size="lg" asChild>
<Link href="#">
<Rocket className="relative size-4" />
<span className="text-nowrap">Start Building</span>
</Link>
</Button>
</div>
</div>
<div className="x-auto relative mx-auto mt-8 max-w-lg sm:mt-12">
<div className="absolute inset-0 -top-8 left-1/2 -z-20 h-56 w-full -translate-x-1/2 [background-image:linear-gradient(to_bottom,transparent_98%,theme(colors.gray.200/75%)_98%),linear-gradient(to_right,transparent_94%,_theme(colors.gray.200/75%)_94%)] [background-size:16px_35px] [mask:radial-gradient(black,transparent_95%)] dark:opacity-10"></div>
<div className="absolute inset-x-0 top-12 -z-[1] mx-auto h-1/3 w-2/3 rounded-full bg-blue-300 blur-3xl dark:bg-white/20"></div>
<Swiper slidesPerView={1} pagination={{ clickable: true }} loop autoplay={{ delay: 5000 }} modules={[Autoplay, EffectCoverflow]}>
<SwiperSlide className="px-2">
<div className="bg-background rounded-(--radius) h-44 max-w-lg border p-9">
<div className="mx-auto h-fit w-full">
<NetlifyLogo />
</div>
<p className="mt-6 text-center text-lg font-medium">30% Increase in revenue</p>
</div>
</SwiperSlide>
<SwiperSlide className="px-2">
<div className="bg-background rounded-(--radius) h-44 max-w-lg border p-9">
<div className="mx-auto h-fit w-full">
<AstroLogo />
</div>
<p className="mt-6 text-center text-lg font-medium">45% Increase in revenue</p>
</div>
</SwiperSlide>
<SwiperSlide className="px-2">
<div className="bg-background rounded-(--radius) h-44 max-w-lg border p-9">
<div className="mx-auto h-fit w-full">
<WorkOsLogo />
</div>
<p className="mt-6 text-center text-lg font-medium">60% Increase in revenue</p>
</div>
</SwiperSlide>
</Swiper>
</div>
</div>
</div>
</section>
</main>
</>
)
}
const WorkOsLogo = () => {
return (
<svg className="m-auto h-8" xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 251.8 48">
<g>
<path
fill="currentColor"
className="text-[#29363D] dark:text-white"
d="M73,7.2h7l5,20.6c0.9,3.9,1.1,6.2,1.1,6.2h0.1c0,0,0.3-2.3,1.3-6.2l4.8-20.6h7.9l5.1,20.6 c1,4,1.2,6.2,1.2,6.2h0.1c0,0,0.1-2.2,1-6.2l4.8-20.6h7l-8.8,33.9h-7.7l-5.3-20.5c-1.1-4.5-1.2-6.4-1.2-6.4h-0.1c0,0-0.1,2-1.1,6.4 l-5,20.5h-8C82,41.1,73,7.2,73,7.2z M118.2,28.8c0-7.7,5-12.8,12.6-12.8c7.5,0,12.5,5,12.5,12.8c0,7.8-5,12.8-12.5,12.8 C123.2,41.6,118.2,36.6,118.2,28.8L118.2,28.8z M136.8,28.8c0-5-2.4-7.8-6-7.8c-3.9,0-6.1,3.2-6.1,7.8c0,5.1,2.4,7.9,6.1,7.9 C134.6,36.7,136.8,33.6,136.8,28.8L136.8,28.8z M146.4,16.4h6.2V21h0.1c1.1-2.4,3.6-4.7,8-4.7c0.7,0,1.2,0.1,1.5,0.2v6.2H162 c0,0-0.6-0.2-2.1-0.2c-4.8,0-7.4,2.8-7.4,8.1v10.6h-6.2V16.4z M165.1,7.2h6.2v10.9c0,6.4-0.1,7.6-0.1,7.6h0.1l9.2-9.2h7.7 l-10.8,10.7l12.5,14h-7.3l-9-10.2l-2.3,2.3v7.9H165L165.1,7.2L165.1,7.2z M189.9,24.3c0-10.4,6.5-17.4,16.2-17.4s16.2,7,16.2,17.4 s-6.5,17.4-16.2,17.4C196.4,41.7,189.9,34.7,189.9,24.3z M215.7,24.3c0-7.1-3.8-11.9-9.5-11.9c-5.7,0-9.5,4.8-9.5,11.9 s3.8,11.9,9.5,11.9C211.8,36.2,215.7,31.4,215.7,24.3z M224.7,29.8h7.1c0,4,2.7,6.2,6.9,6.2c3.5,0,5.9-1.8,5.9-4.3 c0-2.8-1.9-3.6-7.7-4.7c-5.4-1.1-11.1-2.9-11.1-9.9c0-5.9,5-10.3,12.7-10.3c8,0,12.9,4.2,12.9,10.5h-7.1c0-3.1-2.4-5-5.8-5 c-3.5,0-5.7,1.7-5.7,4.2c0,2.6,1.5,3.7,6.3,4.6c7,1.5,12.8,2.3,12.8,10.1c0,6.2-5.4,10.3-13.3,10.3 C230.4,41.5,224.7,36.9,224.7,29.8z"></path>
<path fill="#6363F1" d="M0,24c0,1.1,0.3,2.1,0.8,3l9.7,16.8c1,1.7,2.5,3.1,4.4,3.7c3.6,1.2,7.5-0.3,9.4-3.5l2.3-4.1 l-9.2-16l9.8-16.9L29.5,3c0.7-1.2,1.6-2.2,2.7-3H17.2c-2.6,0-5.1,1.4-6.4,3.7L0.8,21C0.3,21.9,0,22.9,0,24z"></path>
<path fill="#6363F1" d="M55.4,24c0-1.1-0.3-2.1-0.8-3l-9.8-17c-1.9-3.3-5.8-4.7-9.4-3.5c-1.9,0.6-3.4,2-4.4,3.7 L28.7,8L38,24l-9.8,16.9L25.9,45c-0.7,1.2-1.6,2.2-2.7,3h15.1c2.6,0,5.1-1.4,6.4-3.7l10-17.3C55.1,26.1,55.4,25.1,55.4,24z"></path>
</g>
</svg>
)
}
const AstroLogo = () => {
return (
<svg className="mx-auto h-12" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 460 160" fill="none">
<path
d="M65.7846 121.175C61.2669 117.045 59.9481 108.368 61.8303 102.082C65.0939 106.045 69.6158 107.301 74.2997 108.009C81.5305 109.103 88.6318 108.694 95.349 105.389C96.1174 105.011 96.8275 104.507 97.6672 103.998C98.2974 105.826 98.4615 107.672 98.2413 109.551C97.706 114.127 95.4288 117.662 91.8069 120.341C90.3586 121.413 88.8261 122.371 87.3303 123.382C82.7349 126.487 81.4917 130.129 83.2184 135.427C83.2594 135.556 83.2961 135.685 83.389 136C81.0427 134.95 79.3289 133.421 78.023 131.411C76.6438 129.289 75.9876 126.942 75.9531 124.403C75.9358 123.167 75.9358 121.92 75.7696 120.702C75.3638 117.732 73.9694 116.402 71.3426 116.325C68.6467 116.247 66.5141 117.913 65.9486 120.538C65.9054 120.739 65.8428 120.938 65.7803 121.172L65.7846 121.175Z"
fill="currentColor"
/>
<path
d="M65.7846 121.175C61.2669 117.045 59.9481 108.368 61.8303 102.082C65.0939 106.045 69.6158 107.301 74.2997 108.009C81.5305 109.103 88.6318 108.694 95.349 105.389C96.1174 105.011 96.8275 104.507 97.6672 103.998C98.2974 105.826 98.4615 107.672 98.2413 109.551C97.706 114.127 95.4288 117.662 91.8069 120.341C90.3586 121.413 88.8261 122.371 87.3303 123.382C82.7349 126.487 81.4917 130.129 83.2184 135.427C83.2594 135.556 83.2961 135.685 83.389 136C81.0427 134.95 79.3289 133.421 78.023 131.411C76.6438 129.289 75.9876 126.942 75.9531 124.403C75.9358 123.167 75.9358 121.92 75.7696 120.702C75.3638 117.732 73.9694 116.402 71.3426 116.325C68.6467 116.247 66.5141 117.913 65.9486 120.538C65.9054 120.739 65.8428 120.938 65.7803 121.172L65.7846 121.175Z"
fill="url(#paint0_linear_1_33)"
/>
<path d="M40 101.034C40 101.034 53.3775 94.5177 66.7924 94.5177L76.9068 63.2155C77.2855 61.7017 78.3911 60.6729 79.6393 60.6729C80.8875 60.6729 81.9932 61.7017 82.3719 63.2155L92.4862 94.5177C108.374 94.5177 119.279 101.034 119.279 101.034C119.279 101.034 96.5558 39.133 96.5114 39.0088C95.8592 37.1787 94.7583 36 93.274 36H66.007C64.5227 36 63.4662 37.1787 62.7696 39.0088C62.7205 39.1307 40 101.034 40 101.034Z" fill="currentColor" />
<path
d="M181.043 81.1227C181.043 86.6079 174.22 89.8838 164.773 89.8838C158.624 89.8838 156.45 88.3601 156.45 85.1604C156.45 81.8083 159.149 80.2085 165.297 80.2085C170.846 80.2085 175.569 80.2846 181.043 80.9703V81.1227ZM181.118 74.3423C177.744 73.5805 172.645 73.1234 166.572 73.1234C148.877 73.1234 140.555 77.3135 140.555 87.065C140.555 97.1975 146.253 101.083 159.449 101.083C170.621 101.083 178.193 98.2641 180.968 91.3313H181.417C181.342 93.0074 181.268 94.6834 181.268 95.9785C181.268 99.5592 181.867 99.8639 184.791 99.8639H198.587C197.837 97.7308 197.388 91.7122 197.388 86.5317C197.388 80.9703 197.612 76.7802 197.612 71.1426C197.612 59.6388 190.715 52.3251 169.121 52.3251C159.824 52.3251 149.477 53.925 141.605 56.2867C142.354 59.4102 143.404 65.7335 143.929 69.8474C150.752 66.6477 160.424 65.2764 167.922 65.2764C178.268 65.2764 181.118 67.6381 181.118 72.4377V74.3423Z"
fill="currentColor"
/>
<path
d="M218.971 84.3224C217.097 84.5509 214.547 84.5509 211.923 84.5509C209.149 84.5509 206.6 84.4748 204.875 84.2462C204.875 84.8557 204.8 85.5413 204.8 86.1508C204.8 95.6738 211.024 101.235 232.917 101.235C253.535 101.235 260.208 95.75 260.208 86.0746C260.208 76.9325 255.785 72.4377 236.216 71.4473C220.995 70.7616 219.646 69.0856 219.646 67.181C219.646 64.9717 221.595 63.8289 231.792 63.8289C242.364 63.8289 245.213 65.2764 245.213 68.3238V69.0094C246.713 68.9332 249.412 68.8571 252.186 68.8571C254.81 68.8571 257.659 68.9332 259.309 69.0856C259.309 68.3999 259.384 67.7905 259.384 67.2572C259.384 56.0581 250.086 52.4013 232.092 52.4013C211.848 52.4013 205.025 57.3533 205.025 67.0286C205.025 75.7136 210.499 81.1227 229.918 81.9607C244.238 82.4178 245.813 84.0177 245.813 86.227C245.813 88.5887 243.489 89.6553 233.442 89.6553C221.895 89.6553 218.971 88.0554 218.971 84.7795V84.3224Z"
fill="currentColor"
/>
<path
d="M284.955 44.1734C279.482 49.2778 269.66 54.3821 264.187 55.7534C264.262 58.5722 264.262 63.7527 264.262 66.5715L269.285 66.6477C269.21 72.0568 269.135 78.6086 269.135 82.9511C269.135 93.0835 274.458 100.702 291.028 100.702C298.001 100.702 302.65 99.9401 308.423 98.7212C307.823 94.9881 307.148 89.2743 306.923 84.9319C303.475 86.0746 299.126 86.6841 294.327 86.6841C287.654 86.6841 284.955 84.8557 284.955 79.599C284.955 75.028 284.955 70.7616 285.03 66.8001C293.578 66.8763 302.125 67.0286 307.148 67.181C307.073 63.2194 307.223 57.5056 307.448 53.6964C300.176 53.8488 292.003 53.925 285.255 53.925C285.33 50.5729 285.405 47.3732 285.48 44.1734H284.955Z"
fill="currentColor"
/>
<path
d="M329.736 64.286C329.811 60.3244 329.886 56.9724 329.961 53.6964H314.89C315.115 60.2483 315.115 66.9525 315.115 76.7802C315.115 86.6079 315.04 93.3883 314.89 99.8639H332.135C331.835 95.2929 331.76 87.5983 331.76 81.0465C331.76 70.6855 335.959 67.7143 345.481 67.7143C349.905 67.7143 353.054 68.2476 355.828 69.238C355.903 65.3526 356.653 57.8104 357.102 54.4583C354.253 53.6203 351.104 53.087 347.28 53.087C339.108 53.0108 333.11 56.3629 330.336 64.3622L329.736 64.286Z"
fill="currentColor"
/>
<path d="M404.808 76.4754C404.808 84.7795 398.81 88.6649 389.363 88.6649C379.991 88.6649 373.993 85.008 373.993 76.4754C373.993 67.9428 380.066 64.7431 389.363 64.7431C398.735 64.7431 404.808 68.1714 404.808 76.4754ZM420.478 76.0945C420.478 59.5626 407.582 52.1728 389.363 52.1728C371.069 52.1728 358.623 59.5626 358.623 76.0945C358.623 92.5503 370.244 101.388 389.288 101.388C408.482 101.388 420.478 92.5503 420.478 76.0945Z" fill="currentColor" />
<defs>
<linearGradient id="paint0_linear_1_33" x1="61.0003" y1="136" x2="104.622" y2="115.39" gradientUnits="userSpaceOnUse">
<stop stopColor="#D83333" />
<stop offset="1" stopColor="#F041FF" />
</linearGradient>
</defs>
</svg>
)
}
const NetlifyLogo = () => {
return (
<>
<svg className="mx-auto h-12 dark:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 209" fill="none">
<g clipPath="url(#clip0_235_8)">
<path d="M117.436 207.036V154.604L118.529 153.51H129.452L130.545 154.604V207.036L129.452 208.13H118.529L117.436 207.036Z" fill="#05BDBA" />
<path d="M117.436 53.5225V1.09339L118.529 0H129.452L130.545 1.09339V53.5225L129.452 54.6159H118.529L117.436 53.5225Z" fill="#05BDBA" />
<path d="M69.9539 169.238H68.4094L60.6869 161.512V159.967L78.7201 141.938L86.8976 141.942L87.9948 143.031V151.209L69.9539 169.238Z" fill="#05BDBA" />
<path d="M69.9462 38.8917H68.4017L60.6792 46.6181V48.1626L78.7124 66.192L86.8899 66.1882L87.9871 65.0986V56.9212L69.9462 38.8917Z" fill="#05BDBA" />
<path d="M1.09339 97.5104H75.3711L76.4645 98.6038V109.526L75.3711 110.62H1.09339L0 109.526V98.6038L1.09339 97.5104Z" fill="#05BDBA" />
<path d="M440.999 97.5104H510.91L512.004 98.6038V109.526L510.91 110.62H436.633L435.539 109.526L439.905 98.6038L440.999 97.5104Z" fill="#05BDBA" />
<path
d="M212.056 108.727L210.963 109.821H177.079L175.986 110.914C175.986 113.101 178.173 119.657 186.916 119.657C190.196 119.657 193.472 118.564 194.566 116.377L195.659 115.284H208.776L209.869 116.377C208.776 122.934 203.313 132.774 186.916 132.774C168.336 132.774 159.589 119.657 159.589 104.357C159.589 89.0576 168.332 75.9408 185.822 75.9408C203.313 75.9408 212.056 89.0576 212.056 104.357V108.731V108.727ZM195.659 97.7971C195.659 96.7037 194.566 89.0538 185.822 89.0538C177.079 89.0538 175.986 96.7037 175.986 97.7971L177.079 98.8905H194.566L195.659 97.7971Z"
fill="#014847"
/>
<path d="M242.66 115.284C242.66 117.47 243.753 118.564 245.94 118.564H255.776L256.87 119.657V130.587L255.776 131.681H245.94C236.103 131.681 227.36 127.307 227.36 115.284V91.2368L226.266 90.1434H218.617L217.523 89.05V78.1199L218.617 77.0265H226.266L227.36 75.9332V66.0965L228.453 65.0031H241.57L242.663 66.0965V75.9332L243.757 77.0265H255.78L256.874 78.1199V89.05L255.78 90.1434H243.757L242.663 91.2368V115.284H242.66Z" fill="#014847" />
<path d="M283.1 131.681H269.983L268.889 130.587V56.2636L269.983 55.1702H283.1L284.193 56.2636V130.587L283.1 131.681Z" fill="#014847" />
<path d="M312.61 68.2871H299.493L298.399 67.1937V56.2636L299.493 55.1702H312.61L313.703 56.2636V67.1937L312.61 68.2871ZM312.61 131.681H299.493L298.399 130.587V78.1237L299.493 77.0304H312.61L313.703 78.1237V130.587L312.61 131.681Z" fill="#014847" />
<path d="M363.98 56.2636V67.1937L362.886 68.2871H353.05C350.863 68.2871 349.769 69.3805 349.769 71.5672V75.9408L350.863 77.0342H361.793L362.886 78.1276V89.0576L361.793 90.151H350.863L349.769 91.2444V130.591L348.676 131.684H335.559L334.466 130.591V91.2444L333.372 90.151H325.723L324.629 89.0576V78.1276L325.723 77.0342H333.372L334.466 75.9408V71.5672C334.466 59.5438 343.209 55.1702 353.046 55.1702H362.882L363.976 56.2636H363.98Z" fill="#014847" />
<path d="M404.42 132.774C400.046 143.704 395.677 150.261 380.373 150.261H374.906L373.813 149.167V138.237L374.906 137.144H380.373C385.836 137.144 386.929 136.05 388.023 132.77V131.677L370.536 89.05V78.1199L371.63 77.0265H381.466L382.56 78.1199L395.677 115.284H396.77L409.887 78.1199L410.98 77.0265H420.817L421.91 78.1199V89.05L404.424 132.77L404.42 132.774Z" fill="#014847" />
<path d="M135.454 131.681L134.361 130.587L134.368 98.9172C134.368 93.4541 132.22 89.2182 125.625 89.0806C122.234 88.9926 118.354 89.0729 114.209 89.2488L113.59 89.8834L113.598 130.587L112.504 131.681H99.3913L98.2979 130.587V77.5388L99.3913 76.4454L128.901 76.1778C143.685 76.1778 149.668 86.3356 149.668 97.8009V130.587L148.575 131.681H135.454Z" fill="#014847" />
</g>
<defs>
<clipPath id="clip0_235_8">
<rect width="512" height="208.126" fill="white" />
</clipPath>
</defs>
</svg>
<svg className="mx-auto hidden h-12 dark:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 209" fill="none">
<g clipPath="url(#clip0_235_26)">
<path d="M117.436 207.036V154.604L118.529 153.51H129.452L130.545 154.604V207.036L129.452 208.13H118.529L117.436 207.036Z" fill="#32E6E2" />
<path d="M117.436 53.5225V1.09339L118.529 0H129.452L130.545 1.09339V53.5225L129.452 54.6159H118.529L117.436 53.5225Z" fill="#32E6E2" />
<path d="M69.9539 169.238H68.4094L60.6869 161.512V159.967L78.7201 141.938L86.8976 141.942L87.9948 143.031V151.209L69.9539 169.238Z" fill="#32E6E2" />
<path d="M69.9462 38.8917H68.4017L60.6792 46.6181V48.1626L78.7124 66.192L86.8899 66.1882L87.9871 65.0986V56.9212L69.9462 38.8917Z" fill="#32E6E2" />
<path d="M1.09339 97.5104H75.3711L76.4645 98.6038V109.526L75.3711 110.62H1.09339L0 109.526V98.6038L1.09339 97.5104Z" fill="#32E6E2" />
<path d="M440.999 97.5104H510.91L512.004 98.6038V109.526L510.91 110.62H436.633L435.539 109.526L439.905 98.6038L440.999 97.5104Z" fill="#32E6E2" />
<path
d="M212.056 108.727L210.963 109.821H177.079L175.986 110.914C175.986 113.101 178.173 119.657 186.916 119.657C190.196 119.657 193.472 118.564 194.566 116.377L195.659 115.284H208.776L209.869 116.377C208.776 122.934 203.313 132.774 186.916 132.774C168.336 132.774 159.589 119.657 159.589 104.357C159.589 89.0576 168.332 75.9408 185.822 75.9408C203.313 75.9408 212.056 89.0576 212.056 104.357V108.731V108.727ZM195.659 97.7971C195.659 96.7037 194.566 89.0538 185.822 89.0538C177.079 89.0538 175.986 96.7037 175.986 97.7971L177.079 98.8905H194.566L195.659 97.7971Z"
fill="white"
/>
<path d="M242.66 115.284C242.66 117.47 243.753 118.564 245.94 118.564H255.776L256.87 119.657V130.587L255.776 131.681H245.94C236.103 131.681 227.36 127.307 227.36 115.284V91.2368L226.266 90.1434H218.617L217.523 89.05V78.1199L218.617 77.0265H226.266L227.36 75.9332V66.0965L228.453 65.0031H241.57L242.663 66.0965V75.9332L243.757 77.0265H255.78L256.874 78.1199V89.05L255.78 90.1434H243.757L242.663 91.2368V115.284H242.66Z" fill="white" />
<path d="M283.1 131.681H269.983L268.889 130.587V56.2636L269.983 55.1702H283.1L284.193 56.2636V130.587L283.1 131.681Z" fill="white" />
<path d="M312.61 68.2871H299.493L298.399 67.1937V56.2636L299.493 55.1702H312.61L313.703 56.2636V67.1937L312.61 68.2871ZM312.61 131.681H299.493L298.399 130.587V78.1237L299.493 77.0304H312.61L313.703 78.1237V130.587L312.61 131.681Z" fill="white" />
<path d="M363.98 56.2636V67.1937L362.886 68.2871H353.05C350.863 68.2871 349.769 69.3805 349.769 71.5672V75.9408L350.863 77.0342H361.793L362.886 78.1276V89.0576L361.793 90.151H350.863L349.769 91.2444V130.591L348.676 131.684H335.559L334.466 130.591V91.2444L333.372 90.151H325.723L324.629 89.0576V78.1276L325.723 77.0342H333.372L334.466 75.9408V71.5672C334.466 59.5438 343.209 55.1702 353.046 55.1702H362.882L363.976 56.2636H363.98Z" fill="white" />
<path d="M404.42 132.774C400.046 143.704 395.677 150.261 380.373 150.261H374.906L373.813 149.167V138.237L374.906 137.144H380.373C385.836 137.144 386.929 136.05 388.023 132.77V131.677L370.536 89.05V78.1199L371.63 77.0265H381.466L382.56 78.1199L395.677 115.284H396.77L409.887 78.1199L410.98 77.0265H420.817L421.91 78.1199V89.05L404.424 132.77L404.42 132.774Z" fill="white" />
<path d="M135.454 131.681L134.361 130.587L134.368 98.9172C134.368 93.4541 132.22 89.2182 125.625 89.0806C122.234 88.9926 118.354 89.0729 114.209 89.2488L113.59 89.8834L113.598 130.587L112.504 131.681H99.3913L98.2979 130.587V77.5388L99.3913 76.4454L128.901 76.1778C143.685 76.1778 149.668 86.3356 149.668 97.8009V130.587L148.575 131.681H135.454Z" fill="white" />
</g>
<defs>
<clipPath id="clip0_235_26">
<rect width="512" height="208.126" fill="white" />
</clipPath>
</defs>
</svg>
</>
)
}

View File

@ -0,0 +1,119 @@
'use client'
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { ArrowRight, Mail, Menu, SendHorizonal, X } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
import { useState } from 'react'
const menuItems = [
{ name: 'Features', href: '#' },
{ name: 'Solution', href: '#' },
{ name: 'Pricing', href: '#' },
{ name: 'About', href: '#' },
]
export default function HeroSection() {
const [menuState, setMenuState] = useState(false)
return (
<>
<header>
<nav data-state={menuState && 'active'} className="fixed z-20 w-full border-b border-dashed bg-white backdrop-blur md:relative dark:bg-zinc-950/50 lg:dark:bg-transparent">
<div className="m-auto max-w-5xl px-6">
<div className="flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full justify-between lg:w-auto">
<Link href="/" aria-label="home" className="flex items-center space-x-2">
<Logo />
</Link>
<button onClick={() => setMenuState(!menuState)} aria-label={menuState == true ? 'Close Menu' : 'Open Menu'} className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:pr-4">
<ul className="space-y-6 text-base lg:flex lg:gap-8 lg:space-y-0 lg:text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link href={item.href} className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit lg:border-l lg:pl-6">
<Button asChild variant="outline" size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button asChild size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
<main>
<section className="overflow-hidden">
<div className="relative mx-auto max-w-5xl px-6 py-28 lg:py-20">
<div className="lg:flex lg:items-center lg:gap-12">
<div className="relative z-10 mx-auto max-w-xl text-center lg:ml-0 lg:w-1/2 lg:text-left">
<Link href="/" className="rounded-(--radius) mx-auto flex w-fit items-center gap-2 border p-1 pr-3 lg:ml-0">
<span className="bg-muted rounded-[calc(var(--radius)-0.25rem)] px-2 py-1 text-xs">New</span>
<span className="text-sm">Introduction Tailus UI Html</span>
<span className="bg-(--color-border) block h-4 w-px"></span>
<ArrowRight className="size-4" />
</Link>
<h1 className="mt-10 text-balance text-4xl font-bold md:text-5xl xl:text-5xl">Production Ready Digital Marketing blocks</h1>
<p className="mt-8">Error totam sit illum. Voluptas doloribus asperiores quaerat aperiam. Quidem harum omnis beatae ipsum soluta!</p>
<div>
<form action="" className="mx-auto my-10 max-w-sm lg:my-12 lg:ml-0 lg:mr-auto">
<div className="bg-background has-[input:focus]:ring-muted relative grid grid-cols-[1fr_auto] items-center rounded-[calc(var(--radius)+0.75rem)] border pr-3 shadow shadow-zinc-950/5 has-[input:focus]:ring-2">
<Mail className="text-caption pointer-events-none absolute inset-y-0 left-5 my-auto size-5" />
<input placeholder="Your mail address" className="h-14 w-full bg-transparent pl-12 focus:outline-none" type="email" />
<div className="md:pr-1.5 lg:pr-0">
<Button aria-label="submit" className="rounded-(--radius)">
<span className="hidden md:block">Get Started</span>
<SendHorizonal className="relative mx-auto size-5 md:hidden" strokeWidth={2} />
</Button>
</div>
</div>
</form>
<ul className="list-inside list-disc space-y-2">
<li>Faster</li>
<li>Modern</li>
<li>100% Customizable</li>
</ul>
</div>
</div>
</div>
<div className="absolute inset-0 -mx-4 rounded-3xl p-3 lg:col-span-3">
<div className="relative">
<div className="bg-radial-[at_65%_25%] to-background z-1 -inset-17 absolute from-transparent to-40%"></div>
<Image className="hidden dark:block" src="/blocks/music.png" alt="app illustration" width={2796} height={2008} />
<Image className="dark:hidden" src="/blocks/music-light.png" alt="app illustration" width={2796} height={2008} />
</div>
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,135 @@
import React from 'react'
import { Mail, SendHorizonal } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { TextEffect } from '@/components/motion-primitives/text-effect'
import { AnimatedGroup } from '@/components/motion-primitives/animated-group'
import { HeroHeader } from '@/components/nsui/hero5-header'
import { LogoCloud } from '@/components/nsui/logo-cloud'
import Image from 'next/image'
const transitionVariants = {
item: {
hidden: {
opacity: 0,
filter: 'blur(12px)',
y: 12,
},
visible: {
opacity: 1,
filter: 'blur(0px)',
y: 0,
transition: {
type: 'spring',
bounce: 0.3,
duration: 1.5,
},
},
},
}
export default function HeroSection() {
return (
<>
<HeroHeader />
<main className="overflow-hidden">
<div
aria-hidden
className="absolute inset-0 isolate z-10 hidden opacity-65 contain-strict lg:block">
<div className="w-140 h-320 -translate-y-87.5 absolute left-0 top-0 -rotate-45 rounded-full bg-[radial-gradient(68.54%_68.72%_at_55.02%_31.46%,hsla(0,0%,85%,.08)_0,hsla(0,0%,55%,.02)_50%,hsla(0,0%,45%,0)_80%)]" />
<div className="h-320 absolute left-0 top-0 w-60 -rotate-45 rounded-full bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.06)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)] [translate:5%_-50%]" />
<div className="h-320 -translate-y-87.5 absolute left-0 top-0 w-60 -rotate-45 bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.04)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)]" />
</div>
<section>
<div className="relative mx-auto max-w-6xl px-6 pt-32 lg:pb-16 lg:pt-48">
<div className="relative z-10 mx-auto max-w-4xl text-center">
<TextEffect
preset="fade-in-blur"
speedSegment={0.3}
as="h1"
className="text-balance text-4xl font-medium sm:text-5xl md:text-6xl">
Your gateway to endless entertainment experiences
</TextEffect>
<TextEffect
per="line"
preset="fade-in-blur"
speedSegment={0.3}
delay={0.5}
as="p"
className="mx-auto mt-12 max-w-2xl text-pretty text-lg">
Tailwindcss highly customizable components for building modern websites and applications that look and feel the way you mean it.
</TextEffect>
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.75,
},
},
},
...transitionVariants,
}}
className="mt-12">
<form
action=""
className="mx-auto max-w-sm">
<div className="bg-background has-[input:focus]:ring-muted relative grid grid-cols-[1fr_auto] items-center rounded-[calc(var(--radius)+0.5rem)] border pr-2 shadow shadow-zinc-950/5 has-[input:focus]:ring-2">
<Mail className="pointer-events-none absolute inset-y-0 left-4 my-auto size-4" />
<input
placeholder="Your mail address"
className="h-12 w-full bg-transparent pl-12 focus:outline-none"
type="email"
/>
<div className="md:pr-1.5 lg:pr-0">
<Button
aria-label="submit"
size="sm"
className="rounded-(--radius)">
<span className="hidden md:block">Get Started</span>
<SendHorizonal
className="relative mx-auto size-5 md:hidden"
strokeWidth={2}
/>
</Button>
</div>
</div>
</form>
</AnimatedGroup>
</div>
<div className="mx-auto md:-mt-20 lg:-mt-40">
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.75,
},
},
},
...transitionVariants,
}}>
<div className="-rotate-30 aspect-3/2 relative mx-auto lg:w-2/3">
<div className="bg-linear-to-b to-background from-background absolute inset-0 via-transparent"></div>
<div className="bg-linear-to-l to-background from-background absolute inset-0 via-transparent"></div>
<Image
src="https://res.cloudinary.com/dg4jhba5c/image/upload/v1741605545/phone-backgroudn_xqgg5g.jpg"
alt="Phone Background"
width="6240"
height="4160"
/>
</div>
</AnimatedGroup>
</div>
</div>
</section>
<LogoCloud />
</main>
</>
)
}

View File

@ -0,0 +1,231 @@
import React from 'react'
import Link from 'next/link'
import { ChevronRight } from 'lucide-react'
import { Button } from '@/components/ui/button'
import Image from 'next/image'
import { TextEffect } from '@/components/motion-primitives/text-effect'
import { AnimatedGroup } from '@/components/motion-primitives/animated-group'
import { HeroHeader } from '@/components/nsui/hero6-header'
const transitionVariants = {
item: {
hidden: {
opacity: 0,
filter: 'blur(12px)',
y: 12,
},
visible: {
opacity: 1,
filter: 'blur(0px)',
y: 0,
transition: {
type: 'spring',
bounce: 0.3,
duration: 1.5,
},
},
},
}
export default function HeroSection() {
return (
<>
<HeroHeader />
<main className="overflow-hidden">
<div
aria-hidden
className="absolute inset-0 isolate hidden contain-strict lg:block">
<div className="w-140 h-320 -translate-y-87.5 absolute left-0 top-0 -rotate-45 rounded-full bg-[radial-gradient(68.54%_68.72%_at_55.02%_31.46%,hsla(0,0%,85%,.08)_0,hsla(0,0%,55%,.02)_50%,hsla(0,0%,45%,0)_80%)]" />
<div className="h-320 absolute left-0 top-0 w-60 -rotate-45 rounded-full bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.06)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)] [translate:5%_-50%]" />
<div className="h-320 -translate-y-87.5 absolute left-0 top-0 w-60 -rotate-45 bg-[radial-gradient(50%_50%_at_50%_50%,hsla(0,0%,85%,.04)_0,hsla(0,0%,45%,.02)_80%,transparent_100%)]" />
</div>
<section>
<div className="relative pt-24">
<div className="absolute inset-0 -z-10 size-full [background:radial-gradient(125%_125%_at_50%_100%,transparent_0%,var(--color-background)_75%)]"></div>
<div className="mx-auto max-w-5xl px-6">
<div className="sm:mx-auto lg:mr-auto lg:mt-0">
<TextEffect
preset="fade-in-blur"
speedSegment={0.3}
as="h1"
className="mt-8 max-w-2xl text-balance text-5xl font-medium md:text-6xl lg:mt-16">
Build and Ship 10x faster with NS
</TextEffect>
<TextEffect
per="line"
preset="fade-in-blur"
speedSegment={0.3}
delay={0.5}
as="p"
className="mt-8 max-w-2xl text-pretty text-lg">
Tailwindcss highly customizable components for building modern websites and applications that look and feel the way you mean it.
</TextEffect>
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.75,
},
},
},
...transitionVariants,
}}
className="mt-12 flex items-center gap-2">
<div
key={1}
className="bg-foreground/10 rounded-[calc(var(--radius-xl)+0.125rem)] border p-0.5">
<Button
asChild
size="lg"
className="rounded-xl px-5 text-base">
<Link href="#link">
<span className="text-nowrap">Start Building</span>
</Link>
</Button>
</div>
<Button
key={2}
asChild
size="lg"
variant="ghost"
className="h-10.5 rounded-xl px-5 text-base">
<Link href="#link">
<span className="text-nowrap">Request a demo</span>
</Link>
</Button>
</AnimatedGroup>
</div>
</div>
<AnimatedGroup
variants={{
container: {
visible: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.75,
},
},
},
...transitionVariants,
}}>
<div className="relative -mr-56 mt-8 overflow-hidden px-2 sm:mr-0 sm:mt-12 md:mt-20">
<div
aria-hidden
className="bg-linear-to-b to-background absolute inset-0 z-10 from-transparent from-35%"
/>
<div className="inset-shadow-2xs ring-background dark:inset-shadow-white/20 bg-background relative mx-auto max-w-5xl overflow-hidden rounded-2xl border p-4 shadow-lg shadow-zinc-950/15 ring-1">
<Image
className="bg-background aspect-15/8 relative hidden rounded-2xl dark:block"
src="/blocks/mail2.png"
alt="app screen"
width="2700"
height="1440"
/>
<Image
className="z-2 border-border/25 aspect-15/8 relative rounded-2xl border dark:hidden"
src="/blocks/mail2-light.png"
alt="app screen"
width="2700"
height="1440"
/>
</div>
</div>
</AnimatedGroup>
</div>
</section>
<section className="bg-background pb-16 pt-16 md:pb-32">
<div className="group relative m-auto max-w-5xl px-6">
<div className="absolute inset-0 z-10 flex scale-95 items-center justify-center opacity-0 duration-500 group-hover:scale-100 group-hover:opacity-100">
<Link
href="/"
className="block text-sm duration-150 hover:opacity-75">
<span> Meet Our Customers</span>
<ChevronRight className="ml-1 inline-block size-3" />
</Link>
</div>
<div className="group-hover:blur-xs mx-auto mt-12 grid max-w-2xl grid-cols-4 gap-x-12 gap-y-8 transition-all duration-500 group-hover:opacity-50 sm:gap-x-16 sm:gap-y-14">
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nvidia.svg"
alt="Nvidia Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/column.svg"
alt="Column Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/github.svg"
alt="GitHub Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nike.svg"
alt="Nike Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg"
alt="Lemon Squeezy Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/laravel.svg"
alt="Laravel Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-7 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lilly.svg"
alt="Lilly Logo"
height="28"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-6 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/openai.svg"
alt="OpenAI Logo"
height="24"
width="auto"
/>
</div>
</div>
</div>
</section>
</main>
</>
)
}

View File

@ -0,0 +1,10 @@
export const dynamic = 'force-static'
export const revalidate = 3600 // Cache for 1 hour
export default function BlockLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return <>{children}</>
}

View File

@ -0,0 +1,80 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import Link from 'next/link'
export default function LoginPage() {
return (
<section className="flex min-h-screen bg-zinc-50 px-4 py-16 md:py-32 dark:bg-transparent">
<form action="" className="bg-card m-auto h-fit w-full max-w-sm rounded-[calc(var(--radius)+.125rem)] border p-0.5 shadow-md dark:[--color-muted:var(--color-zinc-900)]">
<div className="p-8 pb-6">
<div>
<Link href="/" aria-label="go home">
<Logo />
</Link>
<h1 className="mb-1 mt-4 text-xl font-semibold">Sign In to Tailus UI</h1>
<p className="text-sm">Welcome back! Sign in to continue</p>
</div>
<div className="mt-6 grid grid-cols-2 gap-3">
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="0.98em" height="1em" viewBox="0 0 256 262">
<path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"></path>
<path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"></path>
<path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"></path>
<path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"></path>
</svg>
<span>Google</span>
</Button>
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256">
<path fill="#f1511b" d="M121.666 121.666H0V0h121.666z"></path>
<path fill="#80cc28" d="M256 121.666H134.335V0H256z"></path>
<path fill="#00adef" d="M121.663 256.002H0V134.336h121.663z"></path>
<path fill="#fbbc09" d="M256 256.002H134.335V134.336H256z"></path>
</svg>
<span>Microsoft</span>
</Button>
</div>
<hr className="my-4 border-dashed" />
<div className="space-y-6">
<div className="space-y-2">
<Label htmlFor="email" className="block text-sm">
Username
</Label>
<Input type="email" required name="email" id="email" />
</div>
<div className="space-y-0.5">
<div className="flex items-center justify-between">
<Label htmlFor="pwd" className="text-title text-sm">
Password
</Label>
<Button asChild variant="link" size="sm">
<Link href="#" className="link intent-info variant-ghost text-sm">
Forgot your Password ?
</Link>
</Button>
</div>
<Input type="password" required name="pwd" id="pwd" className="input sz-md variant-mixed" />
</div>
<Button className="w-full">Sign In</Button>
</div>
</div>
<div className="bg-muted rounded-(--radius) border p-3">
<p className="text-accent-foreground text-center text-sm">
Don't have an account ?
<Button asChild variant="link" className="px-2">
<Link href="#">Create account</Link>
</Button>
</p>
</div>
</form>
</section>
)
}

View File

@ -0,0 +1,59 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import Link from 'next/link'
export default function LoginPage() {
return (
<section className="flex min-h-screen bg-zinc-50 px-4 py-16 md:py-32 dark:bg-transparent">
<form action="" className="max-w-92 m-auto h-fit w-full">
<div className="p-6">
<div>
<Link href="/" aria-label="go home">
<Logo />
</Link>
<h1 className="mb-1 mt-4 text-xl font-semibold">Sign In to Tailus UI</h1>
<p>Welcome back! Sign in to continue</p>
</div>
<div className="mt-6">
<Button type="button" variant="outline" className="w-full">
<svg xmlns="http://www.w3.org/2000/svg" width="0.98em" height="1em" viewBox="0 0 256 262">
<path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"></path>
<path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"></path>
<path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"></path>
<path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"></path>
</svg>
<span>Google</span>
</Button>
</div>
<div className="my-6 grid grid-cols-[1fr_auto_1fr] items-center gap-3">
<hr className="border-dashed" />
<span className="text-muted-foreground text-xs">Or continue With</span>
<hr className="border-dashed" />
</div>
<div className="space-y-6">
<div className="space-y-2">
<Label htmlFor="email" className="block text-sm">
Email
</Label>
<Input type="email" required name="email" id="email" />
</div>
<Button className="w-full">Continue</Button>
</div>
</div>
<p className="text-accent-foreground text-center text-sm">
Don't have an account ?
<Button asChild variant="link" className="px-2">
<Link href="#">Create account</Link>
</Button>
</p>
</form>
</section>
)
}

View File

@ -0,0 +1,84 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import Link from 'next/link'
export default function LoginPage() {
return (
<section className="flex min-h-screen bg-zinc-50 px-4 py-16 md:py-32 dark:bg-transparent">
<form action="" className="bg-muted m-auto h-fit w-full max-w-sm overflow-hidden rounded-[calc(var(--radius)+.125rem)] border shadow-md shadow-zinc-950/5 dark:[--color-muted:var(--color-zinc-900)]">
<div className="bg-card -m-px rounded-[calc(var(--radius)+.125rem)] border p-8 pb-6">
<div className="text-center">
<Link href="/" aria-label="go home" className="mx-auto block w-fit">
<Logo />
</Link>
<h1 className="mb-1 mt-4 text-xl font-semibold">Sign In to Tailus UI</h1>
<p className="text-sm">Welcome back! Sign in to continue</p>
</div>
<div className="mt-6 space-y-6">
<div className="space-y-2">
<Label htmlFor="email" className="block text-sm">
Username
</Label>
<Input type="email" required name="email" id="email" />
</div>
<div className="space-y-0.5">
<div className="flex items-center justify-between">
<Label htmlFor="pwd" className="text-title text-sm">
Password
</Label>
<Button asChild variant="link" size="sm">
<Link href="#" className="link intent-info variant-ghost text-sm">
Forgot your Password ?
</Link>
</Button>
</div>
<Input type="password" required name="pwd" id="pwd" className="input sz-md variant-mixed" />
</div>
<Button className="w-full">Sign In</Button>
</div>
<div className="my-6 grid grid-cols-[1fr_auto_1fr] items-center gap-3">
<hr className="border-dashed" />
<span className="text-muted-foreground text-xs">Or continue With</span>
<hr className="border-dashed" />
</div>
<div className="grid grid-cols-2 gap-3">
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="0.98em" height="1em" viewBox="0 0 256 262">
<path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"></path>
<path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"></path>
<path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"></path>
<path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"></path>
</svg>
<span>Google</span>
</Button>
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256">
<path fill="#f1511b" d="M121.666 121.666H0V0h121.666z"></path>
<path fill="#80cc28" d="M256 121.666H134.335V0H256z"></path>
<path fill="#00adef" d="M121.663 256.002H0V134.336h121.663z"></path>
<path fill="#fbbc09" d="M256 256.002H134.335V134.336H256z"></path>
</svg>
<span>Microsoft</span>
</Button>
</div>
</div>
<div className="p-3">
<p className="text-accent-foreground text-center text-sm">
Don't have an account ?
<Button asChild variant="link" className="px-2">
<Link href="#">Create account</Link>
</Button>
</p>
</div>
</form>
</section>
)
}

View File

@ -0,0 +1,22 @@
export default function LogoCloud() {
return (
<section className="bg-background py-16">
<div className="mx-auto max-w-5xl px-6">
<h2 className="text-center text-lg font-medium">Your favorite companies are our partners.</h2>
<div className="mx-auto mt-20 flex max-w-4xl flex-wrap items-center justify-center gap-x-12 gap-y-8 sm:gap-x-16 sm:gap-y-12">
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/column.svg" alt="Column Logo" height="16" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/github.svg" alt="GitHub Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/laravel.svg" alt="Laravel Logo" height="16" width="auto" />
<img className="h-7 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/lilly.svg" alt="Lilly Logo" height="28" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg" alt="Lemon Squeezy Logo" height="20" width="auto" />
<img className="h-6 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/openai.svg" alt="OpenAI Logo" height="24" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/tailwindcss.svg" alt="Tailwind CSS Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/vercel.svg" alt="Vercel Logo" height="20" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/zapier.svg" alt="Zapier Logo" height="20" width="auto" />
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,110 @@
import { InfiniteSlider } from '@/components/motion-primitives/infinite-slider'
import { ProgressiveBlur } from '@/components/motion-primitives/progressive-blur'
export default function LogoCloud() {
return (
<section className="bg-background overflow-hidden py-16">
<div className="group relative m-auto max-w-7xl px-6">
<div className="flex flex-col items-center md:flex-row">
<div className="md:max-w-44 md:border-r md:pr-6">
<p className="text-end text-sm">Powering the best teams</p>
</div>
<div className="relative py-6 md:w-[calc(100%-11rem)]">
<InfiniteSlider
speedOnHover={20}
speed={40}
gap={112}>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nvidia.svg"
alt="Nvidia Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/column.svg"
alt="Column Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/github.svg"
alt="GitHub Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nike.svg"
alt="Nike Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg"
alt="Lemon Squeezy Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/laravel.svg"
alt="Laravel Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-7 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lilly.svg"
alt="Lilly Logo"
height="28"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-6 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/openai.svg"
alt="OpenAI Logo"
height="24"
width="auto"
/>
</div>
</InfiniteSlider>
<div className="bg-linear-to-r from-background absolute inset-y-0 left-0 w-20"></div>
<div className="bg-linear-to-l from-background absolute inset-y-0 right-0 w-20"></div>
<ProgressiveBlur
className="pointer-events-none absolute left-0 top-0 h-full w-20"
direction="left"
blurIntensity={1}
/>
<ProgressiveBlur
className="pointer-events-none absolute right-0 top-0 h-full w-20"
direction="right"
blurIntensity={1}
/>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,96 @@
import { ChevronRight } from 'lucide-react'
import Link from 'next/link'
export default function LogoCloudTwo() {
return (
<section className="bg-background py-16">
<div className="group relative m-auto max-w-5xl px-6">
<div className="absolute inset-0 z-10 flex scale-95 items-center justify-center opacity-0 duration-500 group-hover:scale-100 group-hover:opacity-100">
<Link
href="/"
className="block text-sm duration-150 hover:opacity-75">
<span> Meet Our Customers</span>
<ChevronRight className="ml-1 inline-block size-3" />
</Link>
</div>
<div className="group-hover:blur-xs mx-auto mt-12 grid max-w-2xl grid-cols-4 gap-x-12 gap-y-8 transition-all duration-500 group-hover:opacity-50 sm:gap-x-16 sm:gap-y-14">
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nvidia.svg"
alt="Nvidia Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/column.svg"
alt="Column Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/github.svg"
alt="GitHub Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/nike.svg"
alt="Nike Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-5 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lemonsqueezy.svg"
alt="Lemon Squeezy Logo"
height="20"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-4 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/laravel.svg"
alt="Laravel Logo"
height="16"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-7 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/lilly.svg"
alt="Lilly Logo"
height="28"
width="auto"
/>
</div>
<div className="flex">
<img
className="mx-auto h-6 w-fit dark:invert"
src="https://html.tailus.io/blocks/customers/openai.svg"
alt="OpenAI Logo"
height="24"
width="auto"
/>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,53 @@
import { Button } from '@/components/ui/button'
import { Check } from 'lucide-react'
import Link from 'next/link'
export default function Pricing() {
return (
<div className="relative py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-balance text-3xl font-bold md:text-4xl lg:text-5xl">Start managing your company smarter today</h2>
</div>
<div className="mt-8 md:mt-20">
<div className="bg-card relative rounded-3xl border shadow-2xl shadow-zinc-950/5">
<div className="grid items-center gap-12 divide-y p-12 md:grid-cols-2 md:divide-x md:divide-y-0">
<div className="pb-12 text-center md:pb-0 md:pr-12">
<h3 className="text-2xl font-semibold">Suite Enterprise</h3>
<p className="mt-2 text-lg">For your company of any size</p>
<span className="mb-6 mt-12 inline-block text-6xl font-bold">
<span className="text-4xl">$</span>234
</span>
<div className="flex justify-center">
<Button asChild size="lg">
<Link href="#">Get started</Link>
</Button>
</div>
<p className="text-muted-foreground mt-12 text-sm">Includes : Security, Unlimited Storage, Payment, Search engine, and all features</p>
</div>
<div className="relative">
<ul role="list" className="space-y-4">
{['First premium advantage', 'Second advantage weekly', 'Third advantage donate to project', 'Fourth, access to all components weekly'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
<span>{item}</span>
</li>
))}
</ul>
<p className="text-muted-foreground mt-6 text-sm">Team can be any size, and you can add or switch members as needed. Companies using our platform include:</p>
<div className="mt-12 flex flex-wrap items-center justify-between gap-6">
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/column.svg" alt="Column Logo" height="16" width="auto" />
<img className="h-4 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/github.svg" alt="GitHub Logo" height="16" width="auto" />
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="20" width="auto" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,72 @@
import { Button } from '@/components/ui/button'
import { Check } from 'lucide-react'
import Link from 'next/link'
export default function Pricing() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto max-w-2xl space-y-6 text-center">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Pricing that Scales with You</h1>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="mt-8 grid gap-6 md:mt-20 md:grid-cols-5 md:gap-0">
<div className="rounded-(--radius) flex flex-col justify-between space-y-8 border p-6 md:col-span-2 md:my-2 md:rounded-r-none md:border-r-0 lg:p-10">
<div className="space-y-4">
<div>
<h2 className="font-medium">Free</h2>
<span className="my-3 block text-2xl font-semibold">$0 / mo</span>
<p className="text-muted-foreground text-sm">Per editor</p>
</div>
<Button asChild variant="outline" className="w-full">
<Link href="">Get Started</Link>
</Button>
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Basic Analytics Dashboard', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</div>
</div>
<div className="dark:bg-muted rounded-(--radius) border p-6 shadow-lg shadow-gray-950/5 md:col-span-3 lg:p-10 dark:[--color-muted:var(--color-zinc-900)]">
<div className="grid gap-6 sm:grid-cols-2">
<div className="space-y-4">
<div>
<h2 className="font-medium">Pro</h2>
<span className="my-3 block text-2xl font-semibold">$19 / mo</span>
<p className="text-muted-foreground text-sm">Per editor</p>
</div>
<Button asChild className="w-full">
<Link href="">Get Started</Link>
</Button>
</div>
<div>
<div className="text-sm font-medium">Everything in free plus :</div>
<ul className="mt-4 list-outside space-y-3 text-sm">
{['Everything in Free Plan', '5GB Cloud Storage', 'Email and Chat Support', 'Access to Community Forum', 'Single User Access', 'Access to Basic Templates', 'Mobile App Access', '1 Custom Report Per Month', 'Monthly Product Updates', 'Standard Security Features'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,103 @@
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Check } from 'lucide-react'
export default function Pricing() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="mx-auto max-w-2xl space-y-6 text-center">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Pricing that Scales with You</h1>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="mt-8 grid gap-6 md:mt-20 md:grid-cols-3">
<Card className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Free</CardTitle>
<span className="my-3 block text-2xl font-semibold">$0 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Basic Analytics Dashboard', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
<CardFooter className="mt-auto">
<Button asChild variant="outline" className="w-full">
<Link href="">Get Started</Link>
</Button>
</CardFooter>
</Card>
<Card className="relative">
<span className="bg-linear-to-br/increasing absolute inset-x-0 -top-3 mx-auto flex h-6 w-fit items-center rounded-full from-purple-400 to-amber-300 px-3 py-1 text-xs font-medium text-amber-950 ring-1 ring-inset ring-white/20 ring-offset-1 ring-offset-gray-950/5">Popular</span>
<div className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Pro</CardTitle>
<span className="my-3 block text-2xl font-semibold">$19 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Free Plan', '5GB Cloud Storage', 'Email and Chat Support', 'Access to Community Forum', 'Single User Access', 'Access to Basic Templates', 'Mobile App Access', '1 Custom Report Per Month', 'Monthly Product Updates', 'Standard Security Features'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
<CardFooter>
<Button asChild className="w-full">
<Link href="">Get Started</Link>
</Button>
</CardFooter>
</div>
</Card>
<Card className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Startup</CardTitle>
<span className="my-3 block text-2xl font-semibold">$29 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Pro Plan', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
<CardFooter className="mt-auto">
<Button asChild variant="outline" className="w-full">
<Link href="">Get Started</Link>
</Button>
</CardFooter>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,101 @@
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Check } from 'lucide-react'
export default function Pricing() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="mx-auto max-w-2xl space-y-6 text-center">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Pricing that Scales with You</h1>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="mt-8 grid gap-6 md:mt-20 md:grid-cols-3">
<Card>
<CardHeader>
<CardTitle className="font-medium">Free</CardTitle>
<span className="my-3 block text-2xl font-semibold">$0 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
<Button asChild variant="outline" className="mt-4 w-full">
<Link href="">Get Started</Link>
</Button>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Basic Analytics Dashboard', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
</Card>
<Card className="relative">
<span className="bg-linear-to-br/increasing absolute inset-x-0 -top-3 mx-auto flex h-6 w-fit items-center rounded-full from-purple-400 to-amber-300 px-3 py-1 text-xs font-medium text-amber-950 ring-1 ring-inset ring-white/20 ring-offset-1 ring-offset-gray-950/5">Popular</span>
<CardHeader>
<CardTitle className="font-medium">Pro</CardTitle>
<span className="my-3 block text-2xl font-semibold">$19 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
<Button asChild className="mt-4 w-full">
<Link href="">Get Started</Link>
</Button>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Free Plan', '5GB Cloud Storage', 'Email and Chat Support', 'Access to Community Forum', 'Single User Access', 'Access to Basic Templates', 'Mobile App Access', '1 Custom Report Per Month', 'Monthly Product Updates', 'Standard Security Features'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
</Card>
<Card className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Startup</CardTitle>
<span className="my-3 block text-2xl font-semibold">$29 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
<Button asChild variant="outline" className="mt-4 w-full">
<Link href="">Get Started</Link>
</Button>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Pro Plan', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,103 @@
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Check } from 'lucide-react'
export default function Pricing() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="mx-auto max-w-2xl space-y-6 text-center">
<h1 className="text-center text-4xl font-semibold lg:text-5xl">Pricing that Scales with You</h1>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="mt-8 grid gap-6 [--color-card:var(--color-muted)] *:border-none *:shadow-none md:mt-20 md:grid-cols-3 dark:[--color-muted:var(--color-zinc-900)]">
<Card className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Free</CardTitle>
<span className="my-3 block text-2xl font-semibold">$0 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Basic Analytics Dashboard', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
<CardFooter className="mt-auto">
<Button asChild variant="outline" className="w-full">
<Link href="">Get Started</Link>
</Button>
</CardFooter>
</Card>
<Card className="relative">
<span className="bg-linear-to-br/increasing absolute inset-x-0 -top-3 mx-auto flex h-6 w-fit items-center rounded-full from-purple-400 to-amber-300 px-3 py-1 text-xs font-medium text-amber-950 ring-1 ring-inset ring-white/20 ring-offset-1 ring-offset-gray-950/5">Popular</span>
<div className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Pro</CardTitle>
<span className="my-3 block text-2xl font-semibold">$19 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Free Plan', '5GB Cloud Storage', 'Email and Chat Support', 'Access to Community Forum', 'Single User Access', 'Access to Basic Templates', 'Mobile App Access', '1 Custom Report Per Month', 'Monthly Product Updates', 'Standard Security Features'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
<CardFooter>
<Button asChild className="w-full">
<Link href="">Get Started</Link>
</Button>
</CardFooter>
</div>
</Card>
<Card className="flex flex-col">
<CardHeader>
<CardTitle className="font-medium">Startup</CardTitle>
<span className="my-3 block text-2xl font-semibold">$29 / mo</span>
<CardDescription className="text-sm">Per editor</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<hr className="border-dashed" />
<ul className="list-outside space-y-3 text-sm">
{['Everything in Pro Plan', '5GB Cloud Storage', 'Email and Chat Support'].map((item, index) => (
<li key={index} className="flex items-center gap-2">
<Check className="size-3" />
{item}
</li>
))}
</ul>
</CardContent>
<CardFooter className="mt-auto">
<Button asChild variant="outline" className="w-full">
<Link href="">Get Started</Link>
</Button>
</CardFooter>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,88 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import Link from 'next/link'
export default function LoginPage() {
return (
<section className="flex min-h-screen bg-zinc-50 px-4 py-16 md:py-32 dark:bg-transparent">
<form action="" className="bg-card m-auto h-fit w-full max-w-sm rounded-[calc(var(--radius)+.125rem)] border p-0.5 shadow-md dark:[--color-muted:var(--color-zinc-900)]">
<div className="p-8 pb-6">
<div>
<Link href="/" aria-label="go home">
<Logo />
</Link>
<h1 className="text-title mb-1 mt-4 text-xl font-semibold">Create a Tailus UI Account</h1>
<p className="text-sm">Welcome! Create an account to get started</p>
</div>
<div className="mt-6 grid grid-cols-2 gap-3">
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="0.98em" height="1em" viewBox="0 0 256 262">
<path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"></path>
<path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"></path>
<path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"></path>
<path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"></path>
</svg>
<span>Google</span>
</Button>
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256">
<path fill="#f1511b" d="M121.666 121.666H0V0h121.666z"></path>
<path fill="#80cc28" d="M256 121.666H134.335V0H256z"></path>
<path fill="#00adef" d="M121.663 256.002H0V134.336h121.663z"></path>
<path fill="#fbbc09" d="M256 256.002H134.335V134.336H256z"></path>
</svg>
<span>Microsoft</span>
</Button>
</div>
<hr className="my-4 border-dashed" />
<div className="space-y-5">
<div className="grid grid-cols-2 gap-3">
<div className="space-y-2">
<Label htmlFor="firstname" className="block text-sm">
Firstname
</Label>
<Input type="text" required name="firstname" id="firstname" />
</div>
<div className="space-y-2">
<Label htmlFor="lastname" className="block text-sm">
Lastname
</Label>
<Input type="text" required name="lastname" id="lastname" />
</div>
</div>
<div className="space-y-2">
<Label htmlFor="email" className="block text-sm">
Username
</Label>
<Input type="email" required name="email" id="email" />
</div>
<div className="space-y-2">
<Label htmlFor="pwd" className="text-title text-sm">
Password
</Label>
<Input type="password" required name="pwd" id="pwd" className="input sz-md variant-mixed" />
</div>
<Button className="w-full">Continue</Button>
</div>
</div>
<div className="bg-muted rounded-(--radius) border p-3">
<p className="text-accent-foreground text-center text-sm">
Have an account ?
<Button asChild variant="link" className="px-2">
<Link href="#">Sign In</Link>
</Button>
</p>
</div>
</form>
</section>
)
}

View File

@ -0,0 +1,59 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import Link from 'next/link'
export default function LoginPage() {
return (
<section className="flex min-h-screen bg-zinc-50 px-4 py-16 md:py-32 dark:bg-transparent">
<form action="" className="max-w-92 m-auto h-fit w-full">
<div className="p-6">
<div>
<Link href="/" aria-label="go home">
<Logo />
</Link>
<h1 className="mb-1 mt-4 text-xl font-semibold">Create a Tailus UI Account</h1>
<p>Welcome! Create an account to get started</p>
</div>
<div className="mt-6">
<Button type="button" variant="outline" className="w-full">
<svg xmlns="http://www.w3.org/2000/svg" width="0.98em" height="1em" viewBox="0 0 256 262">
<path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"></path>
<path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"></path>
<path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"></path>
<path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"></path>
</svg>
<span>Google</span>
</Button>
</div>
<div className="my-6 grid grid-cols-[1fr_auto_1fr] items-center gap-3">
<hr className="border-dashed" />
<span className="text-muted-foreground text-xs">Or continue With</span>
<hr className="border-dashed" />
</div>
<div className="space-y-6">
<div className="space-y-2">
<Label htmlFor="email" className="block text-sm">
Email
</Label>
<Input type="email" required name="email" id="email" />
</div>
<Button className="w-full">Continue</Button>
</div>
</div>
<p className="text-accent-foreground text-center text-sm">
Have an account ?
<Button asChild variant="link" className="px-2">
<Link href="#">Sign In</Link>
</Button>
</p>
</form>
</section>
)
}

View File

@ -0,0 +1,99 @@
import { Logo } from '@/components/logo'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import Link from 'next/link'
export default function LoginPage() {
return (
<section className="flex min-h-screen bg-zinc-50 px-4 py-16 md:py-32 dark:bg-transparent">
<form action="" className="bg-muted m-auto h-fit w-full max-w-sm overflow-hidden rounded-[calc(var(--radius)+.125rem)] border shadow-md shadow-zinc-950/5 dark:[--color-muted:var(--color-zinc-900)]">
<div className="bg-card -m-px rounded-[calc(var(--radius)+.125rem)] border p-8 pb-6">
<div className="text-center">
<Link href="/" aria-label="go home" className="mx-auto block w-fit">
<Logo />
</Link>
<h1 className="text-title mb-1 mt-4 text-xl font-semibold">Create a Tailus UI Account</h1>
<p className="text-sm">Welcome! Create an account to get started</p>
</div>
<div className="mt-6 space-y-6">
<div className="grid grid-cols-2 gap-3">
<div className="space-y-2">
<Label htmlFor="firstname" className="block text-sm">
Firstname
</Label>
<Input type="text" required name="firstname" id="firstname" />
</div>
<div className="space-y-2">
<Label htmlFor="lastname" className="block text-sm">
Lastname
</Label>
<Input type="text" required name="lastname" id="lastname" />
</div>
</div>
<div className="space-y-2">
<Label htmlFor="email" className="block text-sm">
Username
</Label>
<Input type="email" required name="email" id="email" />
</div>
<div className="space-y-0.5">
<div className="flex items-center justify-between">
<Label htmlFor="pwd" className="text-title text-sm">
Password
</Label>
<Button asChild variant="link" size="sm">
<Link href="#" className="link intent-info variant-ghost text-sm">
Forgot your Password ?
</Link>
</Button>
</div>
<Input type="password" required name="pwd" id="pwd" className="input sz-md variant-mixed" />
</div>
<Button className="w-full">Sign In</Button>
</div>
<div className="my-6 grid grid-cols-[1fr_auto_1fr] items-center gap-3">
<hr className="border-dashed" />
<span className="text-muted-foreground text-xs">Or continue With</span>
<hr className="border-dashed" />
</div>
<div className="grid grid-cols-2 gap-3">
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="0.98em" height="1em" viewBox="0 0 256 262">
<path fill="#4285f4" d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"></path>
<path fill="#34a853" d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"></path>
<path fill="#fbbc05" d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"></path>
<path fill="#eb4335" d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"></path>
</svg>
<span>Google</span>
</Button>
<Button type="button" variant="outline">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 256 256">
<path fill="#f1511b" d="M121.666 121.666H0V0h121.666z"></path>
<path fill="#80cc28" d="M256 121.666H134.335V0H256z"></path>
<path fill="#00adef" d="M121.663 256.002H0V134.336h121.663z"></path>
<path fill="#fbbc09" d="M256 256.002H134.335V134.336H256z"></path>
</svg>
<span>Microsoft</span>
</Button>
</div>
</div>
<div className="p-3">
<p className="text-accent-foreground text-center text-sm">
Have an account ?
<Button asChild variant="link" className="px-2">
<Link href="#">Sign In</Link>
</Button>
</p>
</div>
</form>
</section>
)
}

View File

@ -0,0 +1,39 @@
export default function StatsSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-12">
<div className="relative z-10 max-w-xl space-y-6">
<h2 className="text-4xl font-medium lg:text-5xl">The Gemini ecosystem brings together our models.</h2>
<p>
Gemini is evolving to be more than just the models. <span className="font-medium">It supports an entire ecosystem</span> from products innovate.
</p>
</div>
<div className="grid gap-6 sm:grid-cols-2 md:gap-12 lg:gap-24">
<div>
<p>It supports an entire ecosystem from products to the APIs and platforms helping developers and businesses innovate</p>
<div className="mb-12 mt-12 grid grid-cols-2 gap-2 md:mb-0">
<div className="space-y-4">
<div className="bg-linear-to-r from-zinc-950 to-zinc-600 bg-clip-text text-5xl font-bold text-transparent dark:from-white dark:to-zinc-800">+1200</div>
<p>Stars on GitHub</p>
</div>
<div className="space-y-4">
<div className="bg-linear-to-r from-zinc-950 to-zinc-600 bg-clip-text text-5xl font-bold text-transparent dark:from-white dark:to-zinc-800">+500</div>
<p>Powered Apps</p>
</div>
</div>
</div>
<div className="relative">
<blockquote className="border-l-4 pl-4">
<p>Using TailsUI has been like unlocking a secret design superpower. It's the perfect fusion of simplicity and versatility, enabling us to create UIs that are as stunning as they are user-friendly.</p>
<div className="mt-6 space-y-3">
<cite className="block font-medium">John Doe, CEO</cite>
<img className="h-5 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
</div>
</blockquote>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,27 @@
export default function StatsSection() {
return (
<section className="py-12 md:py-20">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<div className="relative z-10 mx-auto max-w-xl space-y-6 text-center">
<h2 className="text-4xl font-medium lg:text-5xl">Tailus UI in numbers</h2>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="grid gap-12 divide-y *:text-center md:grid-cols-3 md:gap-2 md:divide-x md:divide-y-0">
<div className="space-y-4">
<div className="text-5xl font-bold">+1200</div>
<p>Stars on GitHub</p>
</div>
<div className="space-y-4">
<div className="text-5xl font-bold">22 Million</div>
<p>Active Users</p>
</div>
<div className="space-y-4">
<div className="text-5xl font-bold">+500</div>
<p>Powered Apps</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,27 @@
export default function StatsSection() {
return (
<section className="py-12 md:py-20">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<div className="relative z-10 mx-auto max-w-xl space-y-6 text-center">
<h2 className="text-4xl font-semibold lg:text-5xl">Tailus UI in numbers</h2>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="grid gap-0.5 *:text-center md:grid-cols-3">
<div className="rounded-(--radius) space-y-4 border py-12">
<div className="text-5xl font-bold">+1200</div>
<p>Stars on GitHub</p>
</div>
<div className="rounded-(--radius) space-y-4 border py-12">
<div className="text-5xl font-bold">56%</div>
<p>Conversion rate</p>
</div>
<div className="rounded-(--radius) space-y-4 border py-12">
<div className="text-5xl font-bold">+500</div>
<p>Powered Apps</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,27 @@
export default function StatsSection() {
return (
<section className="py-12 md:py-20">
<div className="mx-auto max-w-5xl space-y-8 px-6 md:space-y-16">
<div className="relative z-10 mx-auto max-w-xl space-y-6 text-center">
<h2 className="text-4xl font-semibold lg:text-5xl">Tailus UI in numbers</h2>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="grid gap-0.5 *:text-center md:grid-cols-3 dark:[--color-muted:var(--color-zinc-900)]">
<div className="bg-muted rounded-(--radius) space-y-4 py-12">
<div className="text-5xl font-bold">+1200</div>
<p>Stars on GitHub</p>
</div>
<div className="bg-muted rounded-(--radius) space-y-4 py-12">
<div className="text-5xl font-bold">56%</div>
<p>Conversion rate</p>
</div>
<div className="bg-muted rounded-(--radius) space-y-4 py-12">
<div className="text-5xl font-bold">+500</div>
<p>Powered Apps</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,77 @@
const members = [
{
name: 'Méschac Irung',
role: 'Creator',
avatar: 'https://avatars.githubusercontent.com/u/47919550?v=4',
},
{
name: 'Théo Balick',
role: 'Frontend Dev',
avatar: 'https://avatars.githubusercontent.com/u/68236786?v=4',
},
{
name: 'Glodie Lukose',
role: 'Frontend Dev',
avatar: 'https://avatars.githubusercontent.com/u/99137927?v=4',
},
{
name: 'Bernard Ngandu',
role: 'Backend Dev',
avatar: 'https://avatars.githubusercontent.com/u/31113941?v=4',
},
]
export default function TeamSection() {
return (
<section className="py-12 md:py-32">
<div className="mx-auto max-w-3xl px-8 lg:px-0">
<h2 className="mb-8 text-4xl font-bold md:mb-16 lg:text-5xl">Our team</h2>
<div>
<h3 className="mb-6 text-lg font-medium">Leadership</h3>
<div className="grid grid-cols-2 gap-4 border-t py-6 md:grid-cols-4">
{members.map((member, index) => (
<div key={index}>
<div className="bg-background size-20 rounded-full border p-0.5 shadow shadow-zinc-950/5">
<img className="aspect-square rounded-full object-cover" src={member.avatar} alt={member.name} height="460" width="460" loading="lazy" />
</div>
<span className="mt-2 block text-sm">{member.name}</span>
<span className="text-muted-foreground block text-xs">{member.role}</span>
</div>
))}
</div>
</div>
<div className="mt-6">
<h3 className="mb-6 text-lg font-medium">Engineering</h3>
<div data-rounded="full" className="grid grid-cols-2 gap-4 border-t py-6 md:grid-cols-4">
{members.map((member, index) => (
<div key={index}>
<div className="bg-background size-20 rounded-full border p-0.5 shadow shadow-zinc-950/5">
<img className="aspect-square rounded-full object-cover" src={member.avatar} alt={member.name} height="460" width="460" loading="lazy" />
</div>
<span className="mt-2 block text-sm">{member.name}</span>
<span className="text-muted-foreground block text-xs">{member.role}</span>
</div>
))}
</div>
</div>
<div className="mt-6">
<h3 className="mb-6 text-lg font-medium">Marketing</h3>
<div data-rounded="full" className="grid grid-cols-2 gap-4 border-t py-6 md:grid-cols-4">
{members.map((member, index) => (
<div key={index}>
<div className="bg-background size-20 rounded-full border p-0.5 shadow shadow-zinc-950/5">
<img className="aspect-square rounded-full object-cover" src={member.avatar} alt={member.name} height="460" width="460" loading="lazy" />
</div>
<span className="mt-2 block text-sm">{member.name}</span>
<span className="text-muted-foreground block text-xs">{member.role}</span>
</div>
))}
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,80 @@
import Link from 'next/link'
const members = [
{
name: 'Liam Brown',
role: 'Founder - CEO',
avatar: 'https://alt.tailus.io/images/team/member-one.webp',
link: '#',
},
{
name: 'Elijah Jones',
role: 'Co-Founder - CTO',
avatar: 'https://alt.tailus.io/images/team/member-two.webp',
link: '#',
},
{
name: 'Isabella Garcia',
role: 'Sales Manager',
avatar: 'https://alt.tailus.io/images/team/member-three.webp',
link: '#',
},
{
name: 'Henry Lee',
role: 'UX Engeneer',
avatar: 'https://alt.tailus.io/images/team/member-four.webp',
link: '#',
},
{
name: 'Ava Williams',
role: 'Interaction Designer',
avatar: 'https://alt.tailus.io/images/team/member-five.webp',
link: '#',
},
{
name: 'Olivia Miller',
role: 'Visual Designer',
avatar: 'https://alt.tailus.io/images/team/member-six.webp',
link: '#',
},
]
export default function TeamSection() {
return (
<section className="bg-gray-50 py-16 md:py-32 dark:bg-transparent">
<div className="mx-auto max-w-5xl border-t px-6">
<span className="text-caption -ml-6 -mt-3.5 block w-max bg-gray-50 px-6 dark:bg-gray-950">Team</span>
<div className="mt-12 gap-4 sm:grid sm:grid-cols-2 md:mt-24">
<div className="sm:w-2/5">
<h2 className="text-3xl font-bold sm:text-4xl">Our dream team</h2>
</div>
<div className="mt-6 sm:mt-0">
<p>During the working process, we perform regular fitting with the client because he is the only person who can feel whether a new suit fits or not.</p>
</div>
</div>
<div className="mt-12 md:mt-24">
<div className="grid gap-x-6 gap-y-12 sm:grid-cols-2 lg:grid-cols-3">
{members.map((member, index) => (
<div key={index} className="group overflow-hidden">
<img className="h-96 w-full rounded-md object-cover object-top grayscale transition-all duration-500 hover:grayscale-0 group-hover:h-[22.5rem] group-hover:rounded-xl" src={member.avatar} alt="team member" width="826" height="1239" />
<div className="px-2 pt-2 sm:pb-0 sm:pt-4">
<div className="flex justify-between">
<h3 className="text-title text-base font-medium transition-all duration-500 group-hover:tracking-wider">{member.name}</h3>
<span className="text-xs">_0{index + 1}</span>
</div>
<div className="mt-1 flex items-center justify-between">
<span className="text-muted-foreground inline-block translate-y-6 text-sm opacity-0 transition duration-300 group-hover:translate-y-0 group-hover:opacity-100">{member.role}</span>
<Link href={member.link} className="group-hover:text-primary-600 dark:group-hover:text-primary-400 inline-block translate-y-8 text-sm tracking-wide opacity-0 transition-all duration-500 hover:underline group-hover:translate-y-0 group-hover:opacity-100">
{' '}
Linktree
</Link>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,135 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Card, CardContent } from '@/components/ui/card'
type Testimonial = {
name: string
role: string
image: string
quote: string
}
const testimonials: Testimonial[] = [
{
name: 'Jonathan Yombo',
role: 'Software Engineer',
image: 'https://randomuser.me/api/portraits/men/1.jpg',
quote: 'Tailus is really extraordinary and very practical, no need to break your head. A real gold mine.',
},
{
name: 'Yves Kalume',
role: 'GDE - Android',
image: 'https://randomuser.me/api/portraits/men/6.jpg',
quote: 'With no experience in webdesign I just redesigned my entire website in a few minutes with tailwindcss thanks to Tailus.',
},
{
name: 'Yucel Faruksahan',
role: 'Tailkits Creator',
image: 'https://randomuser.me/api/portraits/men/7.jpg',
quote: 'Great work on tailfolio template. This is one of the best personal website that I have seen so far :)',
},
{
name: 'Anonymous author',
role: 'Doing something',
image: 'https://randomuser.me/api/portraits/men/8.jpg',
quote: 'I am really new to Tailwind and I want to give a go to make some page on my own. I searched a lot of hero pages and blocks online. However, most of them are not giving me a clear view or needed some HTML/CSS coding background to make some changes from the original or too expensive to have. I downloaded the one of Tailus template which is very clear to understand at the start and you could modify the codes/blocks to fit perfectly on your purpose of the page.',
},
{
name: 'Shekinah Tshiokufila',
role: 'Senior Software Engineer',
image: 'https://randomuser.me/api/portraits/men/4.jpg',
quote: 'Tailus is redefining the standard of web design, with these blocks it provides an easy and efficient way for those who love beauty but may lack the time to implement it. I can only recommend this incredible wonder.',
},
{
name: 'Oketa Fred',
role: 'Fullstack Developer',
image: 'https://randomuser.me/api/portraits/men/2.jpg',
quote: 'I absolutely love Tailus! The component blocks are beautifully designed and easy to use, which makes creating a great-looking website a breeze.',
},
{
name: 'Zeki',
role: 'Founder of ChatExtend',
image: 'https://randomuser.me/api/portraits/men/5.jpg',
quote: "Using TailsUI has been like unlocking a secret design superpower. It's the perfect fusion of simplicity and versatility, enabling us to create UIs that are as stunning as they are user-friendly.",
},
{
name: 'Joseph Kitheka',
role: 'Fullstack Developer',
image: 'https://randomuser.me/api/portraits/men/9.jpg',
quote: 'Tailus has transformed the way I develop web applications. Their extensive collection of UI components, blocks, and templates has significantly accelerated my workflow. The flexibility to customize every aspect allows me to create unique user experiences. Tailus is a game-changer for modern web development!',
},
{
name: 'Khatab Wedaa',
role: 'MerakiUI Creator',
image: 'https://randomuser.me/api/portraits/men/10.jpg',
quote: "Tailus is an elegant, clean, and responsive tailwind css components it's very helpful to start fast with your project.",
},
{
name: 'Rodrigo Aguilar',
role: 'TailwindAwesome Creator',
image: 'https://randomuser.me/api/portraits/men/11.jpg',
quote: 'I love Tailus ❤️. The component blocks are well-structured, simple to use, and beautifully designed. It makes it really easy to have a good-looking website in no time.',
},
{
name: 'Eric Ampire',
role: 'Mobile Engineer at @BRPNews • @GoogleDevExpert for Android',
image: 'https://randomuser.me/api/portraits/men/12.jpg',
quote: 'Tailus templates are the perfect solution for anyone who wants to create a beautiful and functional website without any web design experience. The templates are easy to use, customizable, and responsive, and the support team is always available to help. I highly recommend Tailus templates to anyone who is looking to create a website.',
},
{
name: 'Roland Tubonge',
role: 'Software Engineer',
image: 'https://randomuser.me/api/portraits/men/13.jpg',
quote: 'Tailus is so well designed that even with a very poor knowledge of web design you can do miracles. Let yourself be seduced!',
},
]
const chunkArray = (array: Testimonial[], chunkSize: number): Testimonial[][] => {
const result: Testimonial[][] = []
for (let i = 0; i < array.length; i += chunkSize) {
result.push(array.slice(i, i + chunkSize))
}
return result
}
const testimonialChunks = chunkArray(testimonials, Math.ceil(testimonials.length / 3))
export default function WallOfLoveSection() {
return (
<section>
<div className="py-16 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center">
<h2 className="text-title text-3xl font-semibold">Loved by the Community</h2>
<p className="text-body mt-6">Harum quae dolore orrupti aut temporibus ariatur.</p>
</div>
<div className="mt-8 grid gap-3 sm:grid-cols-2 md:mt-12 lg:grid-cols-3">
{testimonialChunks.map((chunk, chunkIndex) => (
<div key={chunkIndex} className="space-y-3">
{chunk.map(({ name, role, quote, image }, index) => (
<Card key={index}>
<CardContent className="grid grid-cols-[auto_1fr] gap-3 pt-6">
<Avatar className="size-9">
<AvatarImage alt={name} src={image} loading="lazy" width="120" height="120" />
<AvatarFallback>ST</AvatarFallback>
</Avatar>
<div>
<h3 className="font-medium">{name}</h3>
<span className="text-muted-foreground block text-sm tracking-wide">{role}</span>
<blockquote className="mt-3">
<p className="text-gray-700 dark:text-gray-300">{quote}</p>
</blockquote>
</div>
</CardContent>
</Card>
))}
</div>
))}
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,27 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
export default function TestimonialsSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto max-w-2xl text-center">
<blockquote>
<p className="text-lg font-medium sm:text-xl md:text-3xl">Using TailsUI has been like unlocking a secret design superpower. It's the perfect fusion of simplicity and versatility, enabling us to create UIs that are as stunning as they are user-friendly.</p>
<div className="mt-12 flex items-center justify-center gap-6">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/shekinah.webp" alt="Shekinah Tshiokufila" height="400" width="400" loading="lazy" />
<AvatarFallback>ST</AvatarFallback>
</Avatar>
<div className="space-y-1 border-l pl-6">
<cite className="font-medium">John Doe</cite>
<span className="text-muted-foreground block text-sm">CEO, Nvidia</span>
</div>
</div>
</blockquote>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,94 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
export default function Testimonials() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-6xl space-y-8 px-6 md:space-y-16">
<div className="relative z-10 mx-auto max-w-xl space-y-6 text-center md:space-y-12">
<h2 className="text-4xl font-medium lg:text-5xl">Build by makers, loved by thousand developers</h2>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="grid gap-4 sm:grid-cols-2 md:grid-cols-4 lg:grid-rows-2">
<Card className="grid grid-rows-[auto_1fr] gap-8 sm:col-span-2 sm:p-6 lg:row-span-2">
<CardHeader>
<img className="h-6 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="24" width="auto" />
</CardHeader>
<CardContent>
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p className="text-xl font-medium">Tailus has transformed the way I develop web applications. Their extensive collection of UI components, blocks, and templates has significantly accelerated my workflow. The flexibility to customize every aspect allows me to create unique user experiences. Tailus is a game-changer for modern web development</p>
<div className="grid grid-cols-[auto_1fr] items-center gap-3">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/shekinah.webp" alt="Shekinah Tshiokufila" height="400" width="400" loading="lazy" />
<AvatarFallback>ST</AvatarFallback>
</Avatar>
<div>
<cite className="text-sm font-medium">Shekinah Tshiokufila</cite>
<span className="text-muted-foreground block text-sm">Software Ingineer</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
<Card className="md:col-span-2">
<CardContent className="h-full pt-6">
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p className="text-xl font-medium">Tailus is really extraordinary and very practical, no need to break your head. A real gold mine.</p>
<div className="grid grid-cols-[auto_1fr] items-center gap-3">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/jonathan.webp" alt="Jonathan Yombo" height="400" width="400" loading="lazy" />
<AvatarFallback>JY</AvatarFallback>
</Avatar>
<div>
<cite className="text-sm font-medium">Jonathan Yombo</cite>
<span className="text-muted-foreground block text-sm">Software Ingineer</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
<Card>
<CardContent className="h-full pt-6">
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p>Great work on tailfolio template. This is one of the best personal website that I have seen so far!</p>
<div className="grid items-center gap-3 [grid-template-columns:auto_1fr]">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/yucel.webp" alt="Yucel Faruksahan" height="400" width="400" loading="lazy" />
<AvatarFallback>YF</AvatarFallback>
</Avatar>
<div>
<cite className="text-sm font-medium">Yucel Faruksahan</cite>
<span className="text-muted-foreground block text-sm">Creator, Tailkits</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
<Card className="card variant-mixed">
<CardContent className="h-full pt-6">
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p>Great work on tailfolio template. This is one of the best personal website that I have seen so far!</p>
<div className="grid grid-cols-[auto_1fr] gap-3">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/rodrigo.webp" alt="Rodrigo Aguilar" height="400" width="400" loading="lazy" />
<AvatarFallback>YF</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium">Rodrigo Aguilar</p>
<span className="text-muted-foreground block text-sm">Creator, TailwindAwesome</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,135 @@
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Card, CardContent } from '@/components/ui/card'
type Testimonial = {
name: string
role: string
image: string
quote: string
}
const testimonials: Testimonial[] = [
{
name: 'Jonathan Yombo',
role: 'Software Engineer',
image: 'https://randomuser.me/api/portraits/men/1.jpg',
quote: 'Tailus is really extraordinary and very practical, no need to break your head. A real gold mine.',
},
{
name: 'Yves Kalume',
role: 'GDE - Android',
image: 'https://randomuser.me/api/portraits/men/6.jpg',
quote: 'With no experience in webdesign I just redesigned my entire website in a few minutes with tailwindcss thanks to Tailus.',
},
{
name: 'Yucel Faruksahan',
role: 'Tailkits Creator',
image: 'https://randomuser.me/api/portraits/men/7.jpg',
quote: 'Great work on tailfolio template. This is one of the best personal website that I have seen so far :)',
},
{
name: 'Anonymous author',
role: 'Doing something',
image: 'https://randomuser.me/api/portraits/men/8.jpg',
quote: 'I am really new to Tailwind and I want to give a go to make some page on my own. I searched a lot of hero pages and blocks online. However, most of them are not giving me a clear view or needed some HTML/CSS coding background to make some changes from the original or too expensive to have. I downloaded the one of Tailus template which is very clear to understand at the start and you could modify the codes/blocks to fit perfectly on your purpose of the page.',
},
{
name: 'Shekinah Tshiokufila',
role: 'Senior Software Engineer',
image: 'https://randomuser.me/api/portraits/men/4.jpg',
quote: 'Tailus is redefining the standard of web design, with these blocks it provides an easy and efficient way for those who love beauty but may lack the time to implement it. I can only recommend this incredible wonder.',
},
{
name: 'Oketa Fred',
role: 'Fullstack Developer',
image: 'https://randomuser.me/api/portraits/men/2.jpg',
quote: 'I absolutely love Tailus! The component blocks are beautifully designed and easy to use, which makes creating a great-looking website a breeze.',
},
{
name: 'Zeki',
role: 'Founder of ChatExtend',
image: 'https://randomuser.me/api/portraits/men/5.jpg',
quote: "Using TailsUI has been like unlocking a secret design superpower. It's the perfect fusion of simplicity and versatility, enabling us to create UIs that are as stunning as they are user-friendly.",
},
{
name: 'Joseph Kitheka',
role: 'Fullstack Developer',
image: 'https://randomuser.me/api/portraits/men/9.jpg',
quote: 'Tailus has transformed the way I develop web applications. Their extensive collection of UI components, blocks, and templates has significantly accelerated my workflow. The flexibility to customize every aspect allows me to create unique user experiences. Tailus is a game-changer for modern web development!',
},
{
name: 'Khatab Wedaa',
role: 'MerakiUI Creator',
image: 'https://randomuser.me/api/portraits/men/10.jpg',
quote: "Tailus is an elegant, clean, and responsive tailwind css components it's very helpful to start fast with your project.",
},
{
name: 'Rodrigo Aguilar',
role: 'TailwindAwesome Creator',
image: 'https://randomuser.me/api/portraits/men/11.jpg',
quote: 'I love Tailus ❤️. The component blocks are well-structured, simple to use, and beautifully designed. It makes it really easy to have a good-looking website in no time.',
},
{
name: 'Eric Ampire',
role: 'Mobile Engineer at @BRPNews • @GoogleDevExpert for Android',
image: 'https://randomuser.me/api/portraits/men/12.jpg',
quote: 'Tailus templates are the perfect solution for anyone who wants to create a beautiful and functional website without any web design experience. The templates are easy to use, customizable, and responsive, and the support team is always available to help. I highly recommend Tailus templates to anyone who is looking to create a website.',
},
{
name: 'Roland Tubonge',
role: 'Software Engineer',
image: 'https://randomuser.me/api/portraits/men/13.jpg',
quote: 'Tailus is so well designed that even with a very poor knowledge of web design you can do miracles. Let yourself be seduced!',
},
]
const chunkArray = (array: Testimonial[], chunkSize: number): Testimonial[][] => {
const result: Testimonial[][] = []
for (let i = 0; i < array.length; i += chunkSize) {
result.push(array.slice(i, i + chunkSize))
}
return result
}
const testimonialChunks = chunkArray(testimonials, Math.ceil(testimonials.length / 3))
export default function WallOfLoveSection() {
return (
<section>
<div className="py-16 md:py-32">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center">
<h2 className="text-title text-3xl font-semibold">Loved by the Community</h2>
<p className="text-body mt-6">Harum quae dolore orrupti aut temporibus ariatur.</p>
</div>
<div className="mt-8 grid gap-3 [--color-card:var(--color-muted)] sm:grid-cols-2 md:mt-12 lg:grid-cols-3 dark:[--color-muted:var(--color-zinc-900)]">
{testimonialChunks.map((chunk, chunkIndex) => (
<div key={chunkIndex} className="space-y-3 *:border-none *:shadow-none">
{chunk.map(({ name, role, quote, image }, index) => (
<Card key={index}>
<CardContent className="grid grid-cols-[auto_1fr] gap-3 pt-6">
<Avatar className="size-9">
<AvatarImage alt={name} src={image} loading="lazy" width="120" height="120" />
<AvatarFallback>ST</AvatarFallback>
</Avatar>
<div>
<h3 className="font-medium">{name}</h3>
<span className="text-muted-foreground block text-sm tracking-wide">{role}</span>
<blockquote className="mt-3">
<p className="text-gray-700 dark:text-gray-300">{quote}</p>
</blockquote>
</div>
</CardContent>
</Card>
))}
</div>
))}
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,21 @@
export default function TestimonialsSection() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-5xl px-6">
<div className="mx-auto max-w-2xl">
<blockquote>
<p className="text-lg font-semibold sm:text-xl md:text-3xl">Using TailsUI has been like unlocking a secret design superpower. It's the perfect fusion of simplicity and versatility, enabling us to create UIs that are as stunning as they are user-friendly.</p>
<div className="mt-12 flex items-center gap-6">
<img className="h-7 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nvidia.svg" alt="Nvidia Logo" height="20" width="auto" />
<div className="space-y-1 border-l pl-6">
<cite className="font-medium">John Doe</cite>
<span className="text-muted-foreground block text-sm">CEO, Nvidia</span>
</div>
</div>
</blockquote>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,94 @@
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
export default function Testimonials() {
return (
<section className="py-16 md:py-32">
<div className="mx-auto max-w-6xl space-y-8 px-6 md:space-y-16">
<div className="relative z-10 mx-auto max-w-xl space-y-6 text-center md:space-y-12">
<h2 className="text-4xl font-medium lg:text-5xl">Build by makers, loved by thousand developers</h2>
<p>Gemini is evolving to be more than just the models. It supports an entire to the APIs and platforms helping developers and businesses innovate.</p>
</div>
<div className="grid gap-4 [--color-card:var(--color-muted)] *:border-none *:shadow-none sm:grid-cols-2 md:grid-cols-4 lg:grid-rows-2 dark:[--color-muted:var(--color-zinc-900)]">
<Card className="grid grid-rows-[auto_1fr] gap-8 sm:col-span-2 sm:p-6 lg:row-span-2">
<CardHeader>
<img className="h-6 w-fit dark:invert" src="https://html.tailus.io/blocks/customers/nike.svg" alt="Nike Logo" height="24" width="auto" />
</CardHeader>
<CardContent>
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p className="text-xl font-medium">Tailus has transformed the way I develop web applications. Their extensive collection of UI components, blocks, and templates has significantly accelerated my workflow. The flexibility to customize every aspect allows me to create unique user experiences. Tailus is a game-changer for modern web development</p>
<div className="grid grid-cols-[auto_1fr] items-center gap-3">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/shekinah.webp" alt="Shekinah Tshiokufila" height="400" width="400" loading="lazy" />
<AvatarFallback>ST</AvatarFallback>
</Avatar>
<div>
<cite className="text-sm font-medium">Shekinah Tshiokufila</cite>
<span className="text-muted-foreground block text-sm">Software Ingineer</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
<Card className="md:col-span-2">
<CardContent className="h-full pt-6">
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p className="text-xl font-medium">Tailus is really extraordinary and very practical, no need to break your head. A real gold mine.</p>
<div className="grid grid-cols-[auto_1fr] items-center gap-3">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/jonathan.webp" alt="Jonathan Yombo" height="400" width="400" loading="lazy" />
<AvatarFallback>JY</AvatarFallback>
</Avatar>
<div>
<cite className="text-sm font-medium">Jonathan Yombo</cite>
<span className="text-muted-foreground block text-sm">Software Ingineer</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
<Card>
<CardContent className="h-full pt-6">
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p>Great work on tailfolio template. This is one of the best personal website that I have seen so far!</p>
<div className="grid items-center gap-3 [grid-template-columns:auto_1fr]">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/yucel.webp" alt="Yucel Faruksahan" height="400" width="400" loading="lazy" />
<AvatarFallback>YF</AvatarFallback>
</Avatar>
<div>
<cite className="text-sm font-medium">Yucel Faruksahan</cite>
<span className="text-muted-foreground block text-sm">Creator, Tailkits</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
<Card className="card variant-mixed">
<CardContent className="h-full pt-6">
<blockquote className="grid h-full grid-rows-[1fr_auto] gap-6">
<p>Great work on tailfolio template. This is one of the best personal website that I have seen so far!</p>
<div className="grid grid-cols-[auto_1fr] gap-3">
<Avatar className="size-12">
<AvatarImage src="https://tailus.io/images/reviews/rodrigo.webp" alt="Rodrigo Aguilar" height="400" width="400" loading="lazy" />
<AvatarFallback>YF</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium">Rodrigo Aguilar</p>
<span className="text-muted-foreground block text-sm">Creator, TailwindAwesome</span>
</div>
</div>
</blockquote>
</CardContent>
</Card>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,122 @@
'use client'
import { ReactNode } from 'react'
import { motion, Variants } from 'motion/react'
import React from 'react'
export type PresetType = 'fade' | 'slide' | 'scale' | 'blur' | 'blur-slide' | 'zoom' | 'flip' | 'bounce' | 'rotate' | 'swing'
export type AnimatedGroupProps = {
children: ReactNode
className?: string
variants?: {
container?: Variants
item?: Variants
}
preset?: PresetType
as?: React.ElementType
asChild?: React.ElementType
}
const defaultContainerVariants: Variants = {
visible: {
transition: {
staggerChildren: 0.1,
},
},
}
const defaultItemVariants: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1 },
}
const presetVariants: Record<PresetType, Variants> = {
fade: {},
slide: {
hidden: { y: 20 },
visible: { y: 0 },
},
scale: {
hidden: { scale: 0.8 },
visible: { scale: 1 },
},
blur: {
hidden: { filter: 'blur(4px)' },
visible: { filter: 'blur(0px)' },
},
'blur-slide': {
hidden: { filter: 'blur(4px)', y: 20 },
visible: { filter: 'blur(0px)', y: 0 },
},
zoom: {
hidden: { scale: 0.5 },
visible: {
scale: 1,
transition: { type: 'spring', stiffness: 300, damping: 20 },
},
},
flip: {
hidden: { rotateX: -90 },
visible: {
rotateX: 0,
transition: { type: 'spring', stiffness: 300, damping: 20 },
},
},
bounce: {
hidden: { y: -50 },
visible: {
y: 0,
transition: { type: 'spring', stiffness: 400, damping: 10 },
},
},
rotate: {
hidden: { rotate: -180 },
visible: {
rotate: 0,
transition: { type: 'spring', stiffness: 200, damping: 15 },
},
},
swing: {
hidden: { rotate: -10 },
visible: {
rotate: 0,
transition: { type: 'spring', stiffness: 300, damping: 8 },
},
},
}
const addDefaultVariants = (variants: Variants) => ({
hidden: { ...defaultItemVariants.hidden, ...variants.hidden },
visible: { ...defaultItemVariants.visible, ...variants.visible },
})
function AnimatedGroup({ children, className, variants, preset, as = 'div', asChild = 'div' }: AnimatedGroupProps) {
const selectedVariants = {
item: addDefaultVariants(preset ? presetVariants[preset] : {}),
container: addDefaultVariants(defaultContainerVariants),
}
const containerVariants = variants?.container || selectedVariants.container
const itemVariants = variants?.item || selectedVariants.item
const MotionComponent = motion(as)
const MotionChild = motion(asChild)
return (
<MotionComponent
initial="hidden"
animate="visible"
variants={containerVariants}
className={className}>
{React.Children.map(children, (child, index) => (
<MotionChild
key={index}
variants={itemVariants}>
{child}
</MotionChild>
))}
</MotionComponent>
)
}
export { AnimatedGroup }

View File

@ -0,0 +1,112 @@
'use client';
import { cn } from '@/lib/utils';
import { useMotionValue, animate, motion } from 'motion/react';
import { useState, useEffect } from 'react';
import useMeasure from 'react-use-measure';
export type InfiniteSliderProps = {
children: React.ReactNode;
gap?: number;
speed?: number;
speedOnHover?: number;
direction?: 'horizontal' | 'vertical';
reverse?: boolean;
className?: string;
};
export function InfiniteSlider({
children,
gap = 16,
speed = 100,
speedOnHover,
direction = 'horizontal',
reverse = false,
className,
}: InfiniteSliderProps) {
const [currentSpeed, setCurrentSpeed] = useState(speed);
const [ref, { width, height }] = useMeasure();
const translation = useMotionValue(0);
const [isTransitioning, setIsTransitioning] = useState(false);
const [key, setKey] = useState(0);
useEffect(() => {
let controls;
const size = direction === 'horizontal' ? width : height;
const contentSize = size + gap;
const from = reverse ? -contentSize / 2 : 0;
const to = reverse ? 0 : -contentSize / 2;
const distanceToTravel = Math.abs(to - from);
const duration = distanceToTravel / currentSpeed;
if (isTransitioning) {
const remainingDistance = Math.abs(translation.get() - to);
const transitionDuration = remainingDistance / currentSpeed;
controls = animate(translation, [translation.get(), to], {
ease: 'linear',
duration: transitionDuration,
onComplete: () => {
setIsTransitioning(false);
setKey((prevKey) => prevKey + 1);
},
});
} else {
controls = animate(translation, [from, to], {
ease: 'linear',
duration: duration,
repeat: Infinity,
repeatType: 'loop',
repeatDelay: 0,
onRepeat: () => {
translation.set(from);
},
});
}
return controls?.stop;
}, [
key,
translation,
currentSpeed,
width,
height,
gap,
isTransitioning,
direction,
reverse,
]);
const hoverProps = speedOnHover
? {
onHoverStart: () => {
setIsTransitioning(true);
setCurrentSpeed(speedOnHover);
},
onHoverEnd: () => {
setIsTransitioning(true);
setCurrentSpeed(speed);
},
}
: {};
return (
<div className={cn('overflow-hidden', className)}>
<motion.div
className='flex w-max'
style={{
...(direction === 'horizontal'
? { x: translation }
: { y: translation }),
gap: `${gap}px`,
flexDirection: direction === 'horizontal' ? 'row' : 'column',
}}
ref={ref}
{...hoverProps}
>
{children}
{children}
</motion.div>
</div>
);
}

View File

@ -0,0 +1,62 @@
'use client';
import { cn } from '@/lib/utils';
import { HTMLMotionProps, motion } from 'motion/react';
export const GRADIENT_ANGLES = {
top: 0,
right: 90,
bottom: 180,
left: 270,
};
export type ProgressiveBlurProps = {
direction?: keyof typeof GRADIENT_ANGLES;
blurLayers?: number;
className?: string;
blurIntensity?: number;
} & HTMLMotionProps<'div'>;
export function ProgressiveBlur({
direction = 'bottom',
blurLayers = 8,
className,
blurIntensity = 0.25,
...props
}: ProgressiveBlurProps) {
const layers = Math.max(blurLayers, 2);
const segmentSize = 1 / (blurLayers + 1);
return (
<div className={cn('relative', className)}>
{Array.from({ length: layers }).map((_, index) => {
const angle = GRADIENT_ANGLES[direction];
const gradientStops = [
index * segmentSize,
(index + 1) * segmentSize,
(index + 2) * segmentSize,
(index + 3) * segmentSize,
].map(
(pos, posIndex) =>
`rgba(255, 255, 255, ${posIndex === 1 || posIndex === 2 ? 1 : 0}) ${pos * 100}%`
);
const gradient = `linear-gradient(${angle}deg, ${gradientStops.join(
', '
)})`;
return (
<motion.div
key={index}
className='pointer-events-none absolute inset-0 rounded-[inherit]'
style={{
maskImage: gradient,
WebkitMaskImage: gradient,
backdropFilter: `blur(${index * blurIntensity}px)`,
}}
{...props}
/>
);
})}
</div>
);
}

View File

@ -0,0 +1,237 @@
'use client'
import { cn } from '@/lib/utils'
import { AnimatePresence, motion, TargetAndTransition, Transition, Variant, Variants } from 'motion/react'
import React from 'react'
export type PresetType = 'blur' | 'fade-in-blur' | 'scale' | 'fade' | 'slide'
export type PerType = 'word' | 'char' | 'line'
export type TextEffectProps = {
children: string
per?: PerType
as?: keyof React.JSX.IntrinsicElements
variants?: {
container?: Variants
item?: Variants
}
className?: string
preset?: PresetType
delay?: number
speedReveal?: number
speedSegment?: number
trigger?: boolean
onAnimationComplete?: () => void
onAnimationStart?: () => void
segmentWrapperClassName?: string
containerTransition?: Transition
segmentTransition?: Transition
style?: React.CSSProperties
}
const defaultStaggerTimes: Record<PerType, number> = {
char: 0.03,
word: 0.05,
line: 0.1,
}
const defaultContainerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.05,
},
},
exit: {
transition: { staggerChildren: 0.05, staggerDirection: -1 },
},
}
const defaultItemVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
},
exit: { opacity: 0 },
}
const presetVariants: Record<PresetType, { container: Variants; item: Variants }> = {
blur: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, filter: 'blur(12px)' },
visible: { opacity: 1, filter: 'blur(0px)' },
exit: { opacity: 0, filter: 'blur(12px)' },
},
},
'fade-in-blur': {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, y: 20, filter: 'blur(12px)' },
visible: { opacity: 1, y: 0, filter: 'blur(0px)' },
exit: { opacity: 0, y: 20, filter: 'blur(12px)' },
},
},
scale: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, scale: 0 },
visible: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0 },
},
},
fade: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0 },
visible: { opacity: 1 },
exit: { opacity: 0 },
},
},
slide: {
container: defaultContainerVariants,
item: {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
exit: { opacity: 0, y: 20 },
},
},
}
const AnimationComponent: React.FC<{
segment: string
variants: Variants
per: 'line' | 'word' | 'char'
segmentWrapperClassName?: string
}> = React.memo(({ segment, variants, per, segmentWrapperClassName }) => {
const content =
per === 'line' ? (
<motion.span
variants={variants}
className="block">
{segment}
</motion.span>
) : per === 'word' ? (
<motion.span
aria-hidden="true"
variants={variants}
className="inline-block whitespace-pre">
{segment}
</motion.span>
) : (
<motion.span className="inline-block whitespace-pre">
{segment.split('').map((char, charIndex) => (
<motion.span
key={`char-${charIndex}`}
aria-hidden="true"
variants={variants}
className="inline-block whitespace-pre">
{char}
</motion.span>
))}
</motion.span>
)
if (!segmentWrapperClassName) {
return content
}
const defaultWrapperClassName = per === 'line' ? 'block' : 'inline-block'
return <span className={cn(defaultWrapperClassName, segmentWrapperClassName)}>{content}</span>
})
AnimationComponent.displayName = 'AnimationComponent'
const splitText = (text: string, per: 'line' | 'word' | 'char') => {
if (per === 'line') return text.split('\n')
return text.split(/(\s+)/)
}
const hasTransition = (variant: Variant): variant is TargetAndTransition & { transition?: Transition } => {
return typeof variant === 'object' && variant !== null && 'transition' in variant
}
const createVariantsWithTransition = (baseVariants: Variants, transition?: Transition & { exit?: Transition }): Variants => {
if (!transition) return baseVariants
const { ...mainTransition } = transition
return {
...baseVariants,
visible: {
...baseVariants.visible,
transition: {
...(hasTransition(baseVariants.visible) ? baseVariants.visible.transition : {}),
...mainTransition,
},
},
exit: {
...baseVariants.exit,
transition: {
...(hasTransition(baseVariants.exit) ? baseVariants.exit.transition : {}),
...mainTransition,
staggerDirection: -1,
},
},
}
}
export function TextEffect({ children, per = 'word', as = 'p', variants, className, preset = 'fade', delay = 0, speedReveal = 1, speedSegment = 1, trigger = true, onAnimationComplete, onAnimationStart, segmentWrapperClassName, containerTransition, segmentTransition, style }: TextEffectProps) {
const segments = splitText(children, per)
const MotionTag = motion[as as keyof typeof motion] as typeof motion.div
const baseVariants = preset ? presetVariants[preset] : { container: defaultContainerVariants, item: defaultItemVariants }
const stagger = defaultStaggerTimes[per] / speedReveal
const baseDuration = 0.3 / speedSegment
const customStagger = hasTransition(variants?.container?.visible ?? {}) ? (variants?.container?.visible as TargetAndTransition).transition?.staggerChildren : undefined
const customDelay = hasTransition(variants?.container?.visible ?? {}) ? (variants?.container?.visible as TargetAndTransition).transition?.delayChildren : undefined
const computedVariants = {
container: createVariantsWithTransition(variants?.container || baseVariants.container, {
staggerChildren: customStagger ?? stagger,
delayChildren: customDelay ?? delay,
...containerTransition,
exit: {
staggerChildren: customStagger ?? stagger,
staggerDirection: -1,
},
}),
item: createVariantsWithTransition(variants?.item || baseVariants.item, {
duration: baseDuration,
...segmentTransition,
}),
}
return (
<AnimatePresence mode="popLayout">
{trigger && (
<MotionTag
initial="hidden"
animate="visible"
exit="exit"
variants={computedVariants.container}
className={className}
onAnimationComplete={onAnimationComplete}
onAnimationStart={onAnimationStart}
style={style}>
{per !== 'line' ? <span className="sr-only">{children}</span> : null}
{segments.map((segment, index) => (
<AnimationComponent
key={`${per}-${index}-${segment}`}
segment={segment}
variants={computedVariants.item}
per={per}
segmentWrapperClassName={segmentWrapperClassName}
/>
))}
</MotionTag>
)}
</AnimatePresence>
)
}

View File

@ -0,0 +1,343 @@
'use client'
import type React from 'react'
import { useState, useRef, useEffect } from 'react'
import { Check, Code2, Copy, Eye, Maximize, Terminal } from 'lucide-react'
import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelGroupHandle } from 'react-resizable-panels'
import { Separator } from '@/components/ui/separator'
import * as RadioGroup from '@radix-ui/react-radio-group'
// import { useCopyToClipboard } from '@/hooks/useClipboard'
import { useMedia } from 'use-media'
import { Button } from '../ui/button'
import { cn, titleToNumber } from '@/lib/utils'
// import CodeBlock from './code-block'
import Link from 'next/link'
// import { OpenInV0Button } from './open-in-v0'
import { isUrlCached } from '@/lib/serviceWorker'
import { useMediaQuery } from '@/hooks/use-media-query'
export interface BlockPreviewProps {
code?: string
preview: string
title: string
category: string
previewOnly?: boolean
}
const radioItem = 'rounded-(--radius) duration-200 flex items-center justify-center h-8 px-2.5 gap-2 transition-[color] data-[state=checked]:bg-muted'
const DEFAULTSIZE = 100
const SMSIZE = 30
const MDSIZE = 62
const LGSIZE = 82
const getCacheKey = (src: string) => `iframe-cache-${src}`
export const BlockPreview: React.FC<BlockPreviewProps> = ({ code, preview, title, category, previewOnly }) => {
const [width, setWidth] = useState(DEFAULTSIZE)
const [mode, setMode] = useState<'preview' | 'code'>('preview')
const [iframeHeight, setIframeHeight] = useState(0)
const [shouldLoadIframe, setShouldLoadIframe] = useState(false)
const [cachedHeight, setCachedHeight] = useState<number | null>(null)
const [isIframeCached, setIsIframeCached] = useState(false)
const terminalCode = `pnpm dlx shadcn@canary add https://nsui.irung.me/r/${category}-${titleToNumber(title)}.json`
// const { copied, copy } = useCopyToClipboard({ code: code as string, title, category, eventName: 'block_copy' })
// const { copied: cliCopied, copy: cliCopy } = useCopyToClipboard({ code: terminalCode, title, category, eventName: 'block_cli_copy' })
const ref = useRef<ImperativePanelGroupHandle>(null)
const isLarge = useMedia('(min-width: 1024px)')
const iframeRef = useRef<HTMLIFrameElement>(null)
const observer = useRef<IntersectionObserver | null>(null)
const blockRef = useRef<HTMLDivElement>(null)
useEffect(() => {
observer.current = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
setShouldLoadIframe(true)
observer.current?.disconnect()
}
},
{ threshold: 0.1 }
)
if (blockRef.current) {
observer.current.observe(blockRef.current)
}
return () => {
observer.current?.disconnect()
}
}, [])
useEffect(() => {
const checkCache = async () => {
try {
const isCached = await isUrlCached(preview)
setIsIframeCached(isCached)
if (isCached) {
setShouldLoadIframe(true)
}
} catch (error) {
console.error('Error checking cache status:', error)
}
}
checkCache()
try {
const cacheKey = getCacheKey(preview)
const cached = localStorage.getItem(cacheKey)
if (cached) {
const { height, timestamp } = JSON.parse(cached)
const now = Date.now()
if (now - timestamp < 24 * 60 * 60 * 1000) {
setCachedHeight(height)
setIframeHeight(height)
}
}
} catch (error) {
console.error('Error retrieving cache:', error)
}
}, [preview])
useEffect(() => {
const iframe = iframeRef.current
if (!iframe || !shouldLoadIframe) return
const handleLoad = () => {
try {
const contentHeight = iframe.contentWindow!.document.body.scrollHeight
setIframeHeight(contentHeight)
const cacheKey = getCacheKey(preview)
const cacheValue = JSON.stringify({
height: contentHeight,
timestamp: Date.now(),
})
localStorage.setItem(cacheKey, cacheValue)
} catch (e) {
console.error('Error accessing iframe content:', e)
}
}
iframe.addEventListener('load', handleLoad)
return () => {
iframe.removeEventListener('load', handleLoad)
}
}, [shouldLoadIframe, preview])
useEffect(() => {
if (!blockRef.current || shouldLoadIframe) return
const linkElement = document.createElement('link')
linkElement.rel = 'preload'
linkElement.href = preview
linkElement.as = 'document'
if (!document.head.querySelector(`link[rel="preload"][href="${preview}"]`)) {
document.head.appendChild(linkElement)
}
return () => {
const existingLink = document.head.querySelector(`link[rel="preload"][href="${preview}"]`)
if (existingLink) {
document.head.removeChild(existingLink)
}
}
}, [preview, shouldLoadIframe])
return (
<section className="group mb-16 border-b [--color-border:color-mix(in_oklab,var(--color-zinc-200)_75%,transparent)] dark:[--color-border:color-mix(in_oklab,var(--color-zinc-800)_60%,transparent)]">
<div className="relative border-y">
<div
aria-hidden
className="absolute inset-x-4 -top-14 bottom-0 mx-auto max-w-7xl lg:inset-x-0">
<div className="to-(--color-border) absolute bottom-0 left-0 top-0 w-px bg-gradient-to-b from-transparent to-75%"></div>
<div className="to-(--color-border) absolute bottom-0 right-0 top-0 w-px bg-gradient-to-b from-transparent to-75%"></div>
</div>
<div className="relative z-10 mx-auto flex max-w-7xl justify-between py-1.5 pl-8 pr-6 [--color-border:var(--color-zinc-200)] md:py-2 lg:pl-6 lg:pr-2 dark:[--color-border:var(--color-zinc-800)]">
<div className="-ml-3 flex items-center gap-3">
{code && (
<>
<RadioGroup.Root className="flex gap-0.5">
<RadioGroup.Item
onClick={() => setMode('preview')}
aria-label="Block preview"
value="100"
checked={mode == 'preview'}
className={radioItem}>
<Eye className="size-3.5 sm:opacity-50" />
<span className="hidden text-[13px] sm:block">Preview</span>
</RadioGroup.Item>
<RadioGroup.Item
onClick={() => setMode('code')}
aria-label="Code"
value="0"
checked={mode == 'code'}
className={radioItem}>
<Code2 className="size-3.5 sm:opacity-50" />
<span className="hidden text-[13px] sm:block">Code</span>
</RadioGroup.Item>
</RadioGroup.Root>
<Separator
orientation="vertical"
className="hidden !h-4 lg:block"
/>
</>
)}
{previewOnly && (
<>
{' '}
<span className="ml-2 text-sm capitalize">{title}</span>
<Separator
orientation="vertical"
className="!h-4"
/>{' '}
</>
)}
<Button
asChild
variant="ghost"
size="sm"
className="size-8">
<Link
href={preview}
passHref
target="_blank">
<Maximize className="size-4" />
</Link>
</Button>
<Separator
orientation="vertical"
className="hidden !h-4 lg:block"
/>
<span className="text-muted-foreground hidden text-sm lg:block">{width < MDSIZE ? 'Mobile' : width < LGSIZE ? 'Tablet' : 'Desktop'}</span>{' '}
</div>
<div className="flex items-center gap-2">
{code && (
<>
{/* <Button
onClick={cliCopy}
size="sm"
className="size-8 shadow-none md:w-fit"
variant="outline"
aria-label="copy code">
{cliCopied ? <Check className="size-4" /> : <Terminal className="!size-3.5" />}
<span className="hidden font-mono text-xs md:block">
pnpm dlx shadcn@canary add {category}-{titleToNumber(title)}
</span>
</Button> */}
<Separator
className="!h-4"
orientation="vertical"
/>
{/* <OpenInV0Button
{...{ title, category }}
block={`${category}-${titleToNumber(title)}`}
/> */}
<Separator
className="!h-4"
orientation="vertical"
/>
{/* <Button
onClick={copy}
size="sm"
variant="ghost"
aria-label="copy code"
className="size-8">
{copied ? <Check className="size-4" /> : <Copy className="!size-3.5" />}
</Button> */}
</>
)}
</div>
</div>
</div>
<div className="relative">
<div
aria-hidden
className="absolute inset-x-4 -bottom-14 mx-auto h-14 max-w-7xl lg:inset-x-0">
<div className="from-(--color-border) absolute bottom-0 left-0 top-0 w-px bg-gradient-to-b"></div>
<div className="from-(--color-border) absolute bottom-0 right-0 top-0 w-px bg-gradient-to-b"></div>
</div>
<div className="relative z-10 mx-auto max-w-7xl px-4 lg:border-r lg:px-0">
<div className={cn('bg-white dark:bg-transparent', mode == 'code' && 'hidden')}>
<PanelGroup
direction="horizontal"
tagName="div"
ref={ref}>
<Panel
id={`block-${title}`}
order={1}
onResize={(size) => {
setWidth(Number(size))
}}
defaultSize={DEFAULTSIZE}
minSize={SMSIZE}
className="h-fit border-x">
<div ref={blockRef}>
{shouldLoadIframe ? (
<iframe
key={`${category}-${title}-iframe`}
loading={isIframeCached ? 'eager' : 'lazy'}
allowFullScreen
ref={iframeRef}
title={title}
height={cachedHeight || iframeHeight}
className={cn('h-(--iframe-height) block min-h-56 w-full duration-200 will-change-auto', !cachedHeight && '@starting:opacity-0 @starting:blur-xl', isIframeCached && '!opacity-100 !blur-none')}
src={preview}
id={`block-${title}`}
style={
{
'--iframe-height': `${cachedHeight || iframeHeight}px`,
display: 'block',
} as React.CSSProperties
}
/>
) : (
<div className="flex min-h-56 items-center justify-center">
<div className="border-primary size-6 animate-spin rounded-full border-2 border-t-transparent" />
</div>
)}
</div>
</Panel>
{isLarge && (
<>
<PanelResizeHandle className="relative w-2 before:absolute before:inset-0 before:m-auto before:h-12 before:w-1 before:rounded-full before:bg-zinc-300 before:transition-[height,background] hover:before:h-16 hover:before:bg-zinc-400 focus:before:bg-zinc-400 dark:before:bg-zinc-600 dark:hover:before:bg-zinc-500 dark:focus:before:bg-zinc-400" />
<Panel
id={`code-${title}`}
order={2}
defaultSize={100 - DEFAULTSIZE}
className="-mr-[0.5px] ml-px"></Panel>
</>
)}
</PanelGroup>
</div>
<div className="bg-white dark:bg-transparent">
{/* {mode == 'code' && (
<CodeBlock
code={code as string}
lang="tsx"
maxHeight={iframeHeight}
/>
)} */}
</div>
</div>
</div>
</section>
)
}
export default BlockPreview

View File

@ -0,0 +1,28 @@
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { cn } from '@/lib/utils'
const BlocksNav = ({ categories }: { categories: string[] }) => {
const pathname = usePathname()
return (
<div className="dark:border-border/50 relative z-50 border-b">
<div className="mx-auto max-w-7xl">
<nav className="flex items-center lg:-mx-3">
<ul className="relative -mb-px flex h-11 snap-x snap-proximity scroll-px-6 items-center gap-6 overflow-x-auto overflow-y-hidden px-6 lg:scroll-px-2 lg:gap-5">
{categories.map((category) => (
<li key={category} className={cn('flex h-full snap-start items-center border-b border-b-transparent', pathname === `/nsui/${category}` && 'border-primary')}>
<Link href={`/nsui/${category}`} prefetch={true} className={cn(pathname === `/nsui/${category}` && 'text-foreground!', 'hover:bg-muted dark:text-muted-foreground hover:text-foreground flex h-7 w-fit items-center text-nowrap rounded-full px-1 text-sm text-zinc-700 lg:-mx-2 lg:px-3')}>
<span className="block w-max text-nowrap capitalize">{category}</span>
</Link>
</li>
))}
</ul>
</nav>
</div>
</div>
)
}
export default BlocksNav

View File

@ -0,0 +1,491 @@
import fs from 'fs'
import path from 'path'
export interface Block {
slug: string
title: string
category: string
preview: string
// code: string
}
// function loadCode(filePath: string): string {
// const fullPath = path.join(process.cwd(), filePath)
// return fs.readFileSync(fullPath, 'utf-8')
// }
export const blocks: Block[] = [
{
slug: 'hero-section',
title: 'one',
category: 'hero-section',
preview: '/preview/hero-section/one',
// code: loadCode('app/preview/hero-section/one/page.tsx'),
},
{
slug: 'hero-section',
title: 'two',
category: 'hero-section',
preview: '/preview/hero-section/two',
// code: loadCode('app/preview/hero-section/two/page.tsx'),
},
{
slug: 'hero-section',
title: 'three',
category: 'hero-section',
preview: '/preview/hero-section/three',
// code: loadCode('app/preview/hero-section/three/page.tsx'),
},
{
slug: 'hero-section',
title: 'four',
category: 'hero-section',
preview: '/preview/hero-section/four',
// code: loadCode('app/preview/hero-section/four/page.tsx'),
},
{
slug: 'hero-section',
title: 'five',
category: 'hero-section',
preview: '/preview/hero-section/five',
// code: loadCode('app/preview/hero-section/five/page.tsx'),
},
{
slug: 'hero-section',
title: 'six',
category: 'hero-section',
preview: '/preview/hero-section/six',
// code: loadCode('app/preview/hero-section/six/page.tsx'),
},
{
slug: 'hero-section',
title: 'seven',
category: 'hero-section',
preview: '/preview/hero-section/seven',
// code: loadCode('app/preview/hero-section/seven/page.tsx'),
},
{
slug: 'hero-section',
title: 'eight',
category: 'hero-section',
preview: '/preview/hero-section/eight',
// code: loadCode('app/preview/hero-section/eight/page.tsx'),
},
{
slug: 'hero-section',
title: 'nine',
category: 'hero-section',
preview: '/preview/hero-section/nine',
// code: loadCode('app/preview/hero-section/nine/page.tsx'),
},
{
slug: 'logo-cloud',
title: 'one',
category: 'logo-cloud',
preview: '/preview/logo-cloud/one',
// code: loadCode('app/preview/logo-cloud/one/page.tsx'),
},
{
slug: 'logo-cloud',
title: 'two',
category: 'logo-cloud',
preview: '/preview/logo-cloud/two',
// code: loadCode('app/preview/logo-cloud/two/page.tsx'),
},
{
slug: 'logo-cloud',
title: 'three',
category: 'logo-cloud',
preview: '/preview/logo-cloud/three',
// code: loadCode('app/preview/logo-cloud/three/page.tsx'),
},
{
slug: 'features',
title: 'one',
category: 'features',
preview: '/preview/features/one',
// code: loadCode('app/preview/features/one/page.tsx'),
},
{
slug: 'features',
title: 'two',
category: 'features',
preview: '/preview/features/two',
// code: loadCode('app/preview/features/two/page.tsx'),
},
{
slug: 'features',
title: 'three',
category: 'features',
preview: '/preview/features/three',
// code: loadCode('app/preview/features/three/page.tsx'),
},
{
slug: 'features',
title: 'four',
category: 'features',
preview: '/preview/features/four',
// code: loadCode('app/preview/features/four/page.tsx'),
},
{
slug: 'features',
title: 'five',
category: 'features',
preview: '/preview/features/five',
// code: loadCode('app/preview/features/five/page.tsx'),
},
{
slug: 'features',
title: 'six',
category: 'features',
preview: '/preview/features/six',
// code: loadCode('app/preview/features/six/page.tsx'),
},
{
slug: 'features',
title: 'seven',
category: 'features',
preview: '/preview/features/seven',
// code: loadCode('app/preview/features/seven/page.tsx'),
},
{
slug: 'features',
title: 'eight',
category: 'features',
preview: '/preview/features/eight',
// code: loadCode('app/preview/features/eight/page.tsx'),
},
{
slug: 'features',
title: 'nine',
category: 'features',
preview: '/preview/features/nine',
// code: loadCode('app/preview/features/nine/page.tsx'),
},
{
slug: 'features',
title: 'ten',
category: 'features',
preview: '/preview/features/ten',
// code: loadCode('app/preview/features/ten/page.tsx'),
},
{
slug: 'features',
title: 'eleven',
category: 'features',
preview: '/preview/features/eleven',
// code: loadCode('app/preview/features/eleven/page.tsx'),
},
{
slug: 'features',
title: 'twelve',
category: 'features',
preview: '/preview/features/twelve',
// code: loadCode('app/preview/features/twelve/page.tsx'),
},
{
slug: 'content',
title: 'one',
category: 'content',
preview: '/preview/content/one',
// code: loadCode('app/preview/content/one/page.tsx'),
},
{
slug: 'content',
title: 'seven',
category: 'content',
preview: '/preview/content/seven',
// code: loadCode('app/preview/content/seven/page.tsx'),
},
{
slug: 'content',
title: 'two',
category: 'content',
preview: '/preview/content/two',
// code: loadCode('app/preview/content/two/page.tsx'),
},
{
slug: 'content',
title: 'three',
category: 'content',
preview: '/preview/content/three',
// code: loadCode('app/preview/content/three/page.tsx'),
},
{
slug: 'content',
title: 'four',
category: 'content',
preview: '/preview/content/four',
// code: loadCode('app/preview/content/four/page.tsx'),
},
{
slug: 'content',
title: 'five',
category: 'content',
preview: '/preview/content/five',
// code: loadCode('app/preview/content/five/page.tsx'),
},
{
slug: 'content',
title: 'six',
category: 'content',
preview: '/preview/content/six',
// code: loadCode('app/preview/content/six/page.tsx'),
},
{
slug: 'stats',
title: 'one',
category: 'stats',
preview: '/preview/stats/one',
// code: loadCode('app/preview/stats/one/page.tsx'),
},
{
slug: 'stats',
title: 'two',
category: 'stats',
preview: '/preview/stats/two',
// code: loadCode('app/preview/stats/two/page.tsx'),
},
{
slug: 'stats',
title: 'three',
category: 'stats',
preview: '/preview/stats/three',
// code: loadCode('app/preview/stats/three/page.tsx'),
},
{
slug: 'stats',
title: 'four',
category: 'stats',
preview: '/preview/stats/four',
// code: loadCode('app/preview/stats/four/page.tsx'),
},
{
slug: 'team',
title: 'one',
category: 'team',
preview: '/preview/team/one',
// code: loadCode('app/preview/team/one/page.tsx'),
},
{
slug: 'team',
title: 'two',
category: 'team',
preview: '/preview/team/two',
// code: loadCode('app/preview/team/two/page.tsx'),
},
{
slug: 'testimonials',
title: 'one',
category: 'testimonials',
preview: '/preview/testimonials/one',
// code: loadCode('app/preview/testimonials/one/page.tsx'),
},
{
slug: 'testimonials',
title: 'two',
category: 'testimonials',
preview: '/preview/testimonials/two',
// code: loadCode('app/preview/testimonials/two/page.tsx'),
},
{
slug: 'testimonials',
title: 'three',
category: 'testimonials',
preview: '/preview/testimonials/three',
// code: loadCode('app/preview/testimonials/three/page.tsx'),
},
{
slug: 'testimonials',
title: 'four',
category: 'testimonials',
preview: '/preview/testimonials/four',
// code: loadCode('app/preview/testimonials/four/page.tsx'),
},
{
slug: 'testimonials',
title: 'five',
category: 'testimonials',
preview: '/preview/testimonials/five',
// code: loadCode('app/preview/testimonials/five/page.tsx'),
},
{
slug: 'testimonials',
title: 'six',
category: 'testimonials',
preview: '/preview/testimonials/six',
// code: loadCode('app/preview/testimonials/six/page.tsx'),
},
{
slug: 'call-to-action',
title: 'one',
category: 'call-to-action',
preview: '/preview/call-to-action/one',
// code: loadCode('app/preview/call-to-action/one/page.tsx'),
},
{
slug: 'call-to-action',
title: 'two',
category: 'call-to-action',
preview: '/preview/call-to-action/two',
// code: loadCode('app/preview/call-to-action/two/page.tsx'),
},
{
slug: 'call-to-action',
title: 'three',
category: 'call-to-action',
preview: '/preview/call-to-action/three',
// code: loadCode('app/preview/call-to-action/three/page.tsx'),
},
{
slug: 'footer',
title: 'one',
category: 'footer',
preview: '/preview/footer/one',
// code: loadCode('app/preview/footer/one/page.tsx'),
},
{
slug: 'footer',
title: 'two',
category: 'footer',
preview: '/preview/footer/two',
// code: loadCode('app/preview/footer/two/page.tsx'),
},
{
slug: 'footer',
title: 'three',
category: 'footer',
preview: '/preview/footer/three',
// code: loadCode('app/preview/footer/three/page.tsx'),
},
{
slug: 'footer',
title: 'four',
category: 'footer',
preview: '/preview/footer/four',
// code: loadCode('app/preview/footer/four/page.tsx'),
},
{
slug: 'footer',
title: 'five',
category: 'footer',
preview: '/preview/footer/five',
// code: loadCode('app/preview/footer/five/page.tsx'),
},
{
slug: 'pricing',
title: 'one',
category: 'pricing',
preview: '/preview/pricing/one',
// code: loadCode('app/preview/pricing/one/page.tsx'),
},
{
slug: 'pricing',
title: 'two',
category: 'pricing',
preview: '/preview/pricing/two',
// code: loadCode('app/preview/pricing/two/page.tsx'),
},
{
slug: 'pricing',
title: 'three',
category: 'pricing',
preview: '/preview/pricing/three',
// code: loadCode('app/preview/pricing/three/page.tsx'),
},
{
slug: 'pricing',
title: 'four',
category: 'pricing',
preview: '/preview/pricing/four',
// code: loadCode('app/preview/pricing/four/page.tsx'),
},
{
slug: 'pricing',
title: 'five',
category: 'pricing',
preview: '/preview/pricing/five',
// code: loadCode('app/preview/pricing/five/page.tsx'),
},
{
slug: 'comparator',
title: 'one',
category: 'comparator',
preview: '/preview/comparator/one',
// code: loadCode('app/preview/comparator/one/page.tsx'),
},
{
slug: 'faqs',
title: 'one',
category: 'faqs',
preview: '/preview/faqs/one',
// code: loadCode('app/preview/faqs/one/page.tsx'),
},
{
slug: 'login',
title: 'one',
category: 'login',
preview: '/preview/login/one',
// code: loadCode('app/preview/login/one/page.tsx'),
},
{
slug: 'login',
title: 'two',
category: 'login',
preview: '/preview/login/two',
// code: loadCode('app/preview/login/two/page.tsx'),
},
{
slug: 'login',
title: 'three',
category: 'login',
preview: '/preview/login/three',
// code: loadCode('app/preview/login/three/page.tsx'),
},
{
slug: 'sign-up',
title: 'one',
category: 'sign-up',
preview: '/preview/sign-up/one',
// code: loadCode('app/preview/sign-up/one/page.tsx'),
},
{
slug: 'sign-up',
title: 'two',
category: 'sign-up',
preview: '/preview/sign-up/two',
// code: loadCode('app/preview/sign-up/two/page.tsx'),
},
{
slug: 'sign-up',
title: 'three',
category: 'sign-up',
preview: '/preview/sign-up/three',
// code: loadCode('app/preview/sign-up/three/page.tsx'),
},
{
slug: 'contact',
title: 'one',
category: 'contact',
preview: '/preview/contact/one',
// code: loadCode('app/preview/contact/one/page.tsx'),
},
{
slug: 'contact',
title: 'two',
category: 'contact',
preview: '/preview/contact/two',
// code: loadCode('app/preview/contact/two/page.tsx'),
}
]
export const categories = [...new Set(blocks.map((b) => b.category))]

View File

@ -0,0 +1,112 @@
'use client'
import Link from 'next/link'
import { Logo } from '../logo'
import { Menu, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import React from 'react'
import { cn } from '@/lib/utils'
const menuItems = [
{ name: 'Features', href: '#link' },
{ name: 'Solution', href: '#link' },
{ name: 'Pricing', href: '#link' },
{ name: 'About', href: '#link' },
]
export const HeroHeader = () => {
const [menuState, setMenuState] = React.useState(false)
const [isScrolled, setIsScrolled] = React.useState(false)
React.useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50)
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])
return (
<header>
<nav
data-state={menuState && 'active'}
className="fixed z-20 w-full px-2">
<div className={cn('mx-auto mt-2 max-w-6xl px-6 transition-all duration-300 lg:px-12', isScrolled && 'bg-background/50 max-w-4xl rounded-2xl border backdrop-blur-lg lg:px-5')}>
<div className="relative flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full justify-between lg:w-auto">
<Link
href="/"
aria-label="home"
className="flex items-center space-x-2">
<Logo />
</Link>
<button
onClick={() => setMenuState(!menuState)}
aria-label={menuState == true ? 'Close Menu' : 'Open Menu'}
className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
</div>
<div className="absolute inset-0 m-auto hidden size-fit lg:block">
<ul className="flex gap-8 text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link
href={item.href}
className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:hidden">
<ul className="space-y-6 text-base">
{menuItems.map((item, index) => (
<li key={index}>
<Link
href={item.href}
className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit">
<Button
asChild
variant="outline"
size="sm"
className={cn(isScrolled && 'lg:hidden')}>
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button
asChild
size="sm"
className={cn(isScrolled && 'lg:hidden')}>
<Link href="#">
<span>Sign Up</span>
</Link>
</Button>
<Button
asChild
size="sm"
className={cn(isScrolled ? 'lg:inline-flex' : 'hidden')}>
<Link href="#">
<span>Get Started</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
)
}

View File

@ -0,0 +1,105 @@
'use client'
import Link from 'next/link'
import { Logo } from '../logo'
import { Menu, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import React from 'react'
import { useScroll } from 'motion/react'
import { cn } from '@/lib/utils'
const menuItems = [
{ name: 'Features', href: '#link' },
{ name: 'Solution', href: '#link' },
{ name: 'Pricing', href: '#link' },
{ name: 'About', href: '#link' },
]
export const HeroHeader = () => {
const [menuState, setMenuState] = React.useState(false)
const [scrolled, setScrolled] = React.useState(false)
const { scrollYProgress } = useScroll()
React.useEffect(() => {
const unsubscribe = scrollYProgress.on('change', (latest) => {
setScrolled(latest > 0.05)
})
return () => unsubscribe()
}, [scrollYProgress])
return (
<header>
<nav
data-state={menuState && 'active'}
className={cn('fixed z-20 w-full border-b transition-colors duration-150', scrolled && 'bg-background/50 backdrop-blur-3xl')}>
<div className="mx-auto max-w-5xl px-6 transition-all duration-300">
<div className="relative flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full items-center justify-between gap-12 lg:w-auto">
<Link
href="/"
aria-label="home"
className="flex items-center space-x-2">
<Logo />
</Link>
<button
onClick={() => setMenuState(!menuState)}
aria-label={menuState == true ? 'Close Menu' : 'Open Menu'}
className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
<div className="hidden lg:block">
<ul className="flex gap-8 text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link
href={item.href}
className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:hidden">
<ul className="space-y-6 text-base">
{menuItems.map((item, index) => (
<li key={index}>
<Link
href={item.href}
className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit">
<Button
asChild
variant="outline"
size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button
asChild
size="sm">
<Link href="#">
<span>Sign Up</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
)
}

View File

@ -0,0 +1,92 @@
'use client'
import Link from 'next/link'
import { Logo } from '../logo'
import { Menu, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import React from 'react'
const menuItems = [
{ name: 'Features', href: '#link' },
{ name: 'Solution', href: '#link' },
{ name: 'Pricing', href: '#link' },
{ name: 'About', href: '#link' },
]
export const HeroHeader = () => {
const [menuState, setMenuState] = React.useState(false)
return (
<header>
<nav
data-state={menuState && 'active'}
className="bg-background/50 fixed z-20 w-full border-b backdrop-blur-3xl">
<div className="mx-auto max-w-6xl px-6 transition-all duration-300">
<div className="relative flex flex-wrap items-center justify-between gap-6 py-3 lg:gap-0 lg:py-4">
<div className="flex w-full items-center justify-between gap-12 lg:w-auto">
<Link
href="/"
aria-label="home"
className="flex items-center space-x-2">
<Logo />
</Link>
<button
onClick={() => setMenuState(!menuState)}
aria-label={menuState == true ? 'Close Menu' : 'Open Menu'}
className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-6 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-6 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
<div className="hidden lg:block">
<ul className="flex gap-8 text-sm">
{menuItems.map((item, index) => (
<li key={index}>
<Link
href={item.href}
className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
</div>
<div className="bg-background in-data-[state=active]:block lg:in-data-[state=active]:flex mb-6 hidden w-full flex-wrap items-center justify-end space-y-8 rounded-3xl border p-6 shadow-2xl shadow-zinc-300/20 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:hidden">
<ul className="space-y-6 text-base">
{menuItems.map((item, index) => (
<li key={index}>
<Link
href={item.href}
className="text-muted-foreground hover:text-accent-foreground block duration-150">
<span>{item.name}</span>
</Link>
</li>
))}
</ul>
</div>
<div className="flex w-full flex-col space-y-3 sm:flex-row sm:gap-3 sm:space-y-0 md:w-fit">
<Button
asChild
variant="outline"
size="sm">
<Link href="#">
<span>Login</span>
</Link>
</Button>
<Button
asChild
size="sm">
<Link href="#">
<span>Sign Up</span>
</Link>
</Button>
</div>
</div>
</div>
</div>
</nav>
</header>
)
}

Some files were not shown because too many files have changed in this diff Show More