feat: features

This commit is contained in:
Kinfe123
2024-09-09 01:18:05 +03:00
parent 19c9587e15
commit 46cee0d320
10 changed files with 455 additions and 11 deletions

View File

@@ -1,9 +1,9 @@
import Link from "next/link";
import {} from "better-auth/client";
import Section from "@/components/landing/section";
import Hero from "@/components/landing/hero";
import { Separator } from "@/components/ui/separator";
import { FeaturesSectionDemo } from "@/components/blocks/features-section-demo-3";
import Features from "@/components/features";
export default function HomePage() {
return (
<main>
@@ -15,6 +15,7 @@ export default function HomePage() {
id="hero"
>
<Hero />
<Features />
</Section>
</main>
);

View File

@@ -0,0 +1,44 @@
import { cn } from "@/lib/utils";
import { techStackIcons } from "./techstack-icons";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
type TechStackIconType = {
[key: string]: {
name: string;
icon: any;
};
};
export const TechStackDisplay = ({
skills,
className,
}: {
skills: string[];
className?: string;
}) => {
return (
<div className={cn("flex gap-7 flex-wrap mt-3 items-center max-w-4xl", className)}>
{skills.map((icon) => {
return (
<TooltipProvider key={icon} >
<Tooltip>
<TooltipTrigger asChild>
<span className="transform duration-300 hover:rotate-12 transition-transform">
{techStackIcons[icon].icon}
</span>
</TooltipTrigger>
<TooltipContent className="text-white/80 bg-gradient-to-tr from-black/80 via-black to-black/90 z-1">
{techStackIcons[icon].name}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
})}
</div>
);
};

View File

@@ -0,0 +1,225 @@
"use client";
import {
CheckIcon,
Globe2Icon,
PlugIcon,
PlugZap2Icon,
Plus,
RabbitIcon,
ShieldCheckIcon,
Webhook,
XIcon,
} from "lucide-react";
import {
LockClosedIcon,
} from "@radix-ui/react-icons";
import Link from "next/link";
import { Button } from "./ui/button";
import React, { useState } from "react";
import { TechStackDisplay } from "./display-techstack";
import { Ripple } from "./ripple";
export default function Features() {
return (
<div className="max-w-[1300px] font-geist relative my-32 mx-auto md:border-[1.2px] rounded-none md:w-full xl:w-4/5 2xl:w-3/5">
<Plus className="absolute top-[-17px] left-[-17px] text-black/20 dark:text-white/30 w-8 h-8" />
<div className="grid grid-cols-1 md:grid-cols-3 grid-rows-10 md:grid-rows-4 w-full">
<div className="relative items-start justify-start border-l-[1.2px] transform-gpu flex flex-col p-10 overflow-clip">
<Plus className="absolute bottom-[-17px] left-[-17px] text-black/20 dark:text-white/30 w-8 h-8" />
<div className="flex gap-2 items-center my-1">
<PlugZap2Icon className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Framework Agnostic </p>
</div>
<div className="mt-2">
<div className="max-w-full">
<div className="flex gap-3 ">
<p className="text-2xl tracking-tighter font-normal max-w-lg">
Supports popular <strong>frameworks</strong>
</p>
</div>
</div>
<p className="text-left text-sm mt-2 text-muted-foreground">
Supports your favorite frontend, backend and meta frameworks, including React, Vue, Svelte, Solid, Next.js, Nuxt.js, Hono, and more{" "}
<a
className="text-gray-50"
href=".docs"
target="_blank"
>
Learn more
</a>
</p>
</div>
</div>
<div className="relative items-start justify-start border-l-[1.2px] transform-gpu flex flex-col p-10">
<Plus className="absolute bottom-[-17px] left-[-17px] text-black/20 dark:text-white/30 w-8 h-8" />
<div className="flex gap-2 items-center my-1">
<LockClosedIcon className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Authentication</p>
</div>
<div className="mt-2">
<div className="max-w-full">
<div className="flex gap-3 ">
<p className="text-2xl tracking-tighter font-normal max-w-lg">
Email & Password <strong>Authentication</strong>
</p>
</div>
</div>
<p className="text-left text-sm mt-2 text-muted-foreground">
Builtin support for email and password authentication, with secure password hashing and account management features{" "}
<a
className="text-gray-50"
href="/docs"
target="_blank"
>
Learn more
</a>
</p>
</div>
</div>
<div className="relative items-start justify-start md:border-l-[0.2px] flex flex-col p-10">
<Plus className="absolute bottom-[-17px] left-[-17px] text-black/20 dark:text-white/30 w-8 h-8" />
<div className="flex gap-2 items-center my-1">
<Webhook className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Social Sign-on</p>
</div>
<div className="mt-2">
<div className="max-w-full">
<div className="flex gap-3 ">
<p className="text-2xl tracking-tighter font-normal max-w-lg">
Support multiple <strong>providers.</strong>
</p>
</div>
</div>
<p className="text-left text-sm mt-2 text-muted-foreground">
Allow users to sign in with their accounts, including Github, Google, Discord, Twitter, and more.{" "}
<a
className="text-gray-50"
href="#"
target="_blank"
>
Learn more
</a>
</p>
</div>
</div>
<div className="items-start justify-start border-l-[1.2px] border-t-[1.2px] flex flex-col p-10 ">
<div className="flex gap-2 items-center my-1">
<ShieldCheckIcon className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Two Factor</p>
</div>
<div className="mt-2">
<div className="max-w-full">
<div className="flex gap-3 ">
<p className="text-2xl tracking-tighter font-normal max-w-lg">
2FA right out of <strong>the box.</strong>
</p>
</div>
</div>
<p className="text-left text-sm mt-2 text-muted-foreground">
Supports your favorite frontend, backend and meta frameworks, including React, Vue, Svelte, Solid, Next.js, Nuxt.js, Hono, and more,
{" "}
<a
className="text-gray-50"
href="/docs"
target="_blank"
>
Learn more
</a>
</p>
</div>
</div>
<div className="items-start justify-staart border-l-[1.2px] border-t-[1.2px] flex flex-col p-10 ">
<div className="flex gap-2 items-center my-1">
<RabbitIcon className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Organization & Access Control </p>
</div>
<div className="mt-2">
<div className="max-w-full">
<div className="flex gap-3 ">
<p className="text-2xl tracking-tighter font-normal max-w-lg">
Gain and manage <strong>access.</strong>
</p>
</div>
</div>
<p className="text-left text-sm mt-2 text-muted-foreground">
Manage users and their access to resources within your application.{" "}
<a
className="text-gray-50"
href="/docs"
target="_blank"
>
Learn more
</a>
</p>
</div>
</div>
<div className="items-start justify-start border-l-[1.2px] border-t-[1.2px] transform-gpu relative flex flex-col p-10 ">
<Plus className="absolute bottom-[-15px] right-[-15px] text-black/20 dark:text-white/40 w-8 h-8" />
<div className="flex gap-2 items-center my-1">
<PlugIcon className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Plugin Ecosystem </p>
</div>
<div className="max-w-full">
<div className="flex gap-3 ">
<p className="text-2xl tracking-tighter font-normal max-w-lg">
Pluggable with <strong>custom.</strong>
</p>
</div>
</div>
<div className="mt-2">
<p className="text-left text-sm mt-2 text-muted-foreground">
Enhance your application with our official plugins and those created by the community.{" "}
<a
className="text-gray-50"
href="/docs"
target="_blank"
>
Learn more
</a>
</p>
</div>
</div>
<div className="relative md:grid md:col-span-3 grid-cols-2 row-span-2 border-t-[1.2px] md:border-b-[1.2px] dark:border-b-0 h-full overflow-visible py-20 ">
<div className="p-16 pt-10 md:px-10 h-full md:absolute top-0 left-0 w-full">
<div className="flex flex-col gap-3 justify-center h-full items-center w-full">
<div className="flex gap-2 items-center">
<Globe2Icon className="w-4 h-4" />
<p className="text-gray-600 dark:text-gray-400">Start in a minute</p>
</div>
<p className="text-4xl md:text-4xl mt-4 tracking-tighter font-normal max-w-md mx-auto text-center">
Start in a minute and. <strong>accelerate with 10x speed </strong>
</p>
<div className="flex mt-[10px] z-20">
<TechStackDisplay
skills={[
"nextJs",
"nuxt",
"svelteKit",
"solidStart",
"react",
"hono",
]}
/>
</div>
<Link href="/docs" className="z-50">
<Button className="mt-4 rounded-lg p-5 ml-auto">
Start now!
</Button>
</Link>
<Ripple />
</div>
</div>
<Plus className="absolute bottom-[-15px] left-[-15px] text-black/20 dark:text-black/20 dark:text-white/40 w-8 h-8" />
<Plus className="absolute bottom-[-15px] right-[-15px] text-black/20 dark:text-black/20 dark:text-white/40 w-8 h-8" />
<Plus className="absolute top-[-15px] left-[-15px] text-black/20 dark:text-black/20 dark:text-white/40 w-8 h-8" />
</div>
</div>
</div>
);
}

View File

@@ -1,6 +1,7 @@
export const Icons = {
nextJS: () => (
nextJS: ({className}: {className?:string}) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
@@ -12,8 +13,9 @@ export const Icons = {
></path>
</svg>
),
nuxt: () => (
nuxt: ({className}: {className?:string}) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
@@ -25,8 +27,9 @@ export const Icons = {
></path>
</svg>
),
svelteKit: () => (
svelteKit: ({className}: {className?:string}) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
@@ -38,8 +41,9 @@ export const Icons = {
></path>
</svg>
),
solidStart: () => (
solidStart: ({className}: {className?:string}) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
@@ -51,8 +55,9 @@ export const Icons = {
></path>
</svg>
),
react: () => (
react: ({className}: {className?:string}) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
@@ -66,8 +71,9 @@ export const Icons = {
></path>
</svg>
),
hono: () => (
hono: ({className}: {className?:string}) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"

View File

@@ -0,0 +1,46 @@
import React, { CSSProperties } from "react";
interface RippleProps {
mainCircleSize?: number;
mainCircleOpacity?: number;
numCircles?: number;
}
export const Ripple = React.memo(function Ripple({
mainCircleSize = 180,
mainCircleOpacity = 0.20,
numCircles = 10,
}: RippleProps) {
return (
<div className="absolute opacity-65 w-full inset-0 flex items-center justify-center bg-white/5 [mask-image:linear-gradient(to_bottom,white,transparent)] dark:[box-shadow:0_-20px_80px_-20px_#8686f01f_inset]">
{Array.from({ length: numCircles }, (_, i) => {
const size = mainCircleSize + i * 70;
const opacity = mainCircleOpacity - i * 0.03;
const animationDelay = `${i * 0.06}s`;
const borderStyle = i === numCircles - 1 ? "dashed" : "solid";
const borderOpacity = 5 + i * 5;
return (
<div
key={i}
className={`absolute animate-ripple rounded-full bg-foreground/25 shadow-xl border [--i:${i}]`}
style={
{
width: `${size}px`,
height: `${size}px`,
opacity,
animationDelay,
borderStyle,
borderWidth: "1px",
borderColor: `hsl(var(--foreground), ${borderOpacity / 100})`,
top: "50%",
left: "50%",
transform: "translate(-50%, -50%) scale(1)",
} as CSSProperties
}
/>
);
})}
</div>
);
});

View File

@@ -0,0 +1,36 @@
import {Icons} from './icons'
type TechStackIconType = {
[key: string]: {
name: string;
icon: any;
};
};
export const techStackIcons: TechStackIconType = {
nextJs: {
name: "Nextjs",
icon: <Icons.nextJS className="w-10 h-10" />,
},
nuxt: {
name: "Nuxt",
icon: <Icons.nuxt className="w-10 h-10" />,
},
svelteKit: {
name: "Svelte Kit",
icon: <Icons.svelteKit className="w-10 h-10" />,
},
solidStart: {
name: "Solid Start",
icon: <Icons.solidStart className="w-10 h-10" />,
},
react: {
name: "Reaact",
icon: <Icons.react className="w-10 h-10" />,
},
hono: {
name: "Hono",
icon: <Icons.hono className="w-10 h-10" />,
},
};

View File

View File

@@ -41,7 +41,7 @@
"@tsparticles/engine": "^3.5.0",
"@tsparticles/react": "^3.0.0",
"@tsparticles/slim": "^3.5.0",
"better-auth": "^0.0.8-beta.6",
"better-auth": "workspace:*",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "1.0.0",

View File

@@ -102,6 +102,14 @@ export default {
},
},
keyframes: {
ripple: {
"0% , 100%": {
transform: "translate(-50% , -50%) scale(1)",
},
"50%": {
transform: "translate(-50% , -50%) scale(0.9)",
},
},
"accordion-down": {
from: {
height: "0",
@@ -122,6 +130,7 @@ export default {
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
ripple: "ripple var(--duration,2s) ease calc(var(--i, 0)*.2s) infinite",
},
},
},

83
pnpm-lock.yaml generated
View File

@@ -109,7 +109,7 @@ importers:
version: 0.6.0
better-auth:
specifier: ^0.0.8-beta.6
version: link:../../packages/better-auth
version: 0.0.8-beta.25(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.1(typescript@5.5.4))
oslo:
specifier: ^1.2.1
version: 1.2.1
@@ -589,7 +589,7 @@ importers:
specifier: ^3.5.0
version: 3.5.0
better-auth:
specifier: ^0.0.8-beta.6
specifier: workspace:*
version: link:../packages/better-auth
class-variance-authority:
specifier: ^0.7.0
@@ -2735,7 +2735,7 @@ packages:
'@expo/bunyan@4.0.1':
resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==}
engines: {node: '>=0.10.0'}
engines: {'0': node >=0.10.0}
'@expo/cli@0.18.29':
resolution: {integrity: sha512-X810C48Ss+67RdZU39YEO1khNYo1RmjouRV+vVe0QhMoTe8R6OA3t+XYEdwaNbJ5p/DJN7szfHfNmX2glpC7xg==}
@@ -5415,6 +5415,10 @@ packages:
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
argon2@0.31.2:
resolution: {integrity: sha512-QSnJ8By5Mth60IEte45w9Y7v6bWcQw3YhRtJKKN8oNCxnTLDiv/AXXkDPf2srTMfxFVn3QJdVv2nhXESsUa+Yg==}
engines: {node: '>=14.0.0'}
argon2@0.41.1:
resolution: {integrity: sha512-dqCW8kJXke8Ik+McUcMDltrbuAWETPyU6iq+4AhxqKphWi7pChB/Zgd/Tp/o8xRLbg8ksMj46F/vph9wnxpTzQ==}
engines: {node: '>=16.17.0'}
@@ -5580,6 +5584,10 @@ packages:
resolution: {integrity: sha512-PR1bR6zbgNRkSHZAPQQEqaHpHMyASXwBU2IbDY60gDWJO72d3wBSCiOKQcSGJRxJ55O9jitHVMHqHcAtC0++0A==}
hasBin: true
better-auth@0.0.8-beta.25:
resolution: {integrity: sha512-UPXF+77OG7FkpQCqCO3qA8wWja3VptKsLkS0k8EEFyL3WwVncpJfysJg2BqSMUjxAkHoGZnSCq6tuFMMxTLzlA==}
hasBin: true
better-call@0.1.0:
resolution: {integrity: sha512-CfLBgWyReKx2fXJb0OkNV0/ot8BMO+HDRKJRCidIGuCBkk07d7NzVZR4BnnOy02Jiuh4x3l5oupKQGXw78fqSA==}
peerDependencies:
@@ -5590,6 +5598,11 @@ packages:
peerDependencies:
typescript: ^5.6.0-beta
better-call@0.2.0:
resolution: {integrity: sha512-a2NFJP2BBnUzyaHHwDldUBc4mr3V0czleV4t0Di9e2zewzFVNdCY1m5ZugbIhzY1b5xoUN8R1yMhyZFDuZh2aA==}
peerDependencies:
typescript: ^5.6.0-beta
better-opn@3.0.2:
resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
engines: {node: '>=12.0.0'}
@@ -17815,6 +17828,15 @@ snapshots:
arg@5.0.2: {}
argon2@0.31.2:
dependencies:
'@mapbox/node-pre-gyp': 1.0.11
'@phc/format': 1.0.0
node-addon-api: 7.1.1
transitivePeerDependencies:
- encoding
- supports-color
argon2@0.41.1:
dependencies:
'@phc/format': 1.0.0
@@ -18085,6 +18107,53 @@ snapshots:
- typescript
- vue
better-auth@0.0.8-beta.25(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.1(typescript@5.5.4)):
dependencies:
'@better-fetch/fetch': 1.1.4
'@better-fetch/logger': 1.1.3
'@chronark/access-policies': 0.0.2
'@nanostores/query': 0.3.4(nanostores@0.11.2)
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@18.3.1)
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.1(typescript@5.5.4))
'@noble/ciphers': 0.6.0
'@noble/hashes': 1.4.0
'@paralleldrive/cuid2': 2.2.2
'@simplewebauthn/browser': 10.0.0
'@simplewebauthn/server': 10.0.1
arctic: 2.0.0-next.5
argon2: 0.31.2
better-call: 0.2.0(typescript@5.5.4)
better-sqlite3: 11.1.2
chalk: 5.3.0
commander: 12.1.0
consola: 3.2.3
defu: 6.1.4
dotenv: 16.4.5
jiti: 1.21.6
jose: 5.7.0
kysely: 0.27.4
mysql2: 3.11.0
nanostores: 0.11.2
oauth4webapi: 2.12.0
ora: 8.0.1
oslo: 1.2.1
pg: 8.12.0
prompts: 2.4.2
tiny-glob: 0.2.9
ts-morph: 23.0.0
zod: 3.23.8
transitivePeerDependencies:
- '@nanostores/logger'
- '@vue/devtools-api'
- encoding
- pg-native
- react
- solid-js
- supports-color
- typescript
- vue
better-call@0.1.0(typescript@5.5.4):
dependencies:
'@better-fetch/fetch': 1.1.4
@@ -18107,6 +18176,14 @@ snapshots:
set-cookie-parser: 2.7.0
typescript: 5.6.0-beta
better-call@0.2.0(typescript@5.5.4):
dependencies:
'@better-fetch/fetch': 1.1.4
'@types/set-cookie-parser': 2.4.10
rou3: 0.5.1
set-cookie-parser: 2.7.0
typescript: 5.5.4
better-opn@3.0.2:
dependencies:
open: 8.4.2