MagicUI added (undecided for now)

This commit is contained in:
Fergal Moran
2024-09-18 15:27:18 +01:00
parent a06ac8cbf1
commit 8da0abe325
10 changed files with 202 additions and 69 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -14,7 +14,6 @@
"components": "@/components", "components": "@/components",
"utils": "@/lib/utils", "utils": "@/lib/utils",
"ui": "@/components/ui", "ui": "@/components/ui",
"lib": "@/lib", "magicui": "@/components/magicui"
"hooks": "@/hooks"
} }
} }

View File

@@ -9,6 +9,7 @@
"db:migrate": "drizzle-kit migrate", "db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push", "db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio", "db:studio": "drizzle-kit studio",
"dev:turbo": "NODE_ENV=development next dev -p 3002 --turbo & local-ssl-proxy --config ./ssl-proxy.json",
"dev": "NODE_ENV=development next dev -p 3002 & local-ssl-proxy --config ./ssl-proxy.json", "dev": "NODE_ENV=development next dev -p 3002 & local-ssl-proxy --config ./ssl-proxy.json",
"dev:plain": "next dev", "dev:plain": "next dev",
"lint": "next lint", "lint": "next lint",
@@ -65,6 +66,7 @@
"date-fns": "^4.0.0", "date-fns": "^4.0.0",
"drizzle-orm": "^0.33.0", "drizzle-orm": "^0.33.0",
"embla-carousel-react": "^8.3.0", "embla-carousel-react": "^8.3.0",
"framer-motion": "^11.5.4",
"geist": "^1.3.1", "geist": "^1.3.1",
"http-status-codes": "^2.3.0", "http-status-codes": "^2.3.0",
"input-otp": "^1.2.4", "input-otp": "^1.2.4",

View File

@@ -1,4 +1,3 @@
"use client";
import React from "react"; import React from "react";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";

View File

@@ -0,0 +1,79 @@
import { ReactNode } from "react";
import { ArrowRightIcon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
const BentoGrid = ({
children,
className,
}: {
children: ReactNode;
className?: string;
}) => {
return (
<div
className={cn(
"grid w-full auto-rows-[22rem] grid-cols-3 gap-4",
className,
)}
>
{children}
</div>
);
};
const BentoCard = ({
name,
className,
background,
Icon,
description,
href,
cta,
}: {
name: string;
className: string;
background: ReactNode;
Icon: any;
description: string;
href: string;
cta: string;
}) => (
<div
key={name}
className={cn(
"group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl",
// light styles
"bg-white [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]",
// dark styles
"transform-gpu dark:bg-black dark:[border:1px_solid_rgba(255,255,255,.1)] dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset]",
className,
)}
>
<div>{background}</div>
<div className="pointer-events-none z-10 flex transform-gpu flex-col gap-1 p-6 transition-all duration-300 group-hover:-translate-y-10">
<Icon className="h-12 w-12 origin-left transform-gpu text-neutral-700 transition-all duration-300 ease-in-out group-hover:scale-75" />
<h3 className="text-xl font-semibold text-neutral-700 dark:text-neutral-300">
{name}
</h3>
<p className="max-w-lg text-neutral-400">{description}</p>
</div>
<div
className={cn(
"pointer-events-none absolute bottom-0 flex w-full translate-y-10 transform-gpu flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100",
)}
>
<Button variant="ghost" asChild size="sm" className="pointer-events-auto">
<a href={href}>
{cta}
<ArrowRightIcon className="ml-2 h-4 w-4" />
</a>
</Button>
</div>
<div className="pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] group-hover:dark:bg-neutral-800/10" />
</div>
);
export { BentoCard, BentoGrid };

View File

@@ -0,0 +1,39 @@
"use client";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
interface BlurIntProps {
word: string;
className?: string;
variant?: {
hidden: { filter: string; opacity: number };
visible: { filter: string; opacity: number };
};
duration?: number;
}
const BlurIn = ({ word, className, variant, duration = 1 }: BlurIntProps) => {
const defaultVariants = {
hidden: { filter: "blur(10px)", opacity: 0 },
visible: { filter: "blur(0px)", opacity: 1 },
};
const combinedVariants = variant || defaultVariants;
return (
<motion.h1
initial="hidden"
animate="visible"
transition={{ duration }}
variants={combinedVariants}
className={cn(
"font-display text-center text-4xl font-bold tracking-[-0.02em] drop-shadow-sm md:text-7xl md:leading-[5rem]",
className,
)}
>
{word}
</motion.h1>
);
};
export default BlurIn;

View File

@@ -1,29 +1,41 @@
"use client"; import { BellIcon } from "@radix-ui/react-icons";
import { useState } from "react"; import { BentoCard, BentoGrid } from "@/components/magicui/bento-grid";
import { api } from "@/trpc/server";
import { api } from "@/trpc/react"; const createGridCard = (
import Image from "next/image"; key: string,
url: string,
title: string,
description: string,
tags: string[],
) => {
const value = {
Icon: BellIcon,
name: title,
description: description,
href: "/",
cta: "Learn more",
background: <img className="h-128 absolute w-full" src={url} />,
className: "col-span-1 row-start-1 row-end-4",
};
export function TrendingImages() { return <BentoCard key={key} {...value} />;
const [latestImages] = api.image.getTrending.useSuspenseQuery(); };
export async function TrendingImages() {
const latestImages = await api.image.getTrending();
return ( return (
<div className="w-full max-w-xs"> <BentoGrid className="lg:grid-rows-3">
{latestImages ? ( {latestImages.map((image) =>
latestImages.map((image) => ( createGridCard(
<Image image.id,
key={image.id} image.url,
src={image.url} image.title ?? "",
alt={image.title ?? "An image"} image.description ?? "",
width={320} image.tags ?? [],
height={320} ),
/>
// <img src={image.url} key={image.id} />
))
) : (
<p>No images yet.</p>
)} )}
</div> </BentoGrid>
); );
} }

View File

@@ -1,4 +1,4 @@
import { clsx, type ClassValue } from "clsx" import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge" import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {

View File

@@ -1,6 +1,7 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@layer base { @layer base {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
@@ -22,13 +23,14 @@
--border: 240 5.9% 90%; --border: 240 5.9% 90%;
--input: 240 5.9% 90%; --input: 240 5.9% 90%;
--ring: 240 10% 3.9%; --ring: 240 10% 3.9%;
--radius: 0.5rem;
--chart-1: 12 76% 61%; --chart-1: 12 76% 61%;
--chart-2: 173 58% 39%; --chart-2: 173 58% 39%;
--chart-3: 197 37% 24%; --chart-3: 197 37% 24%;
--chart-4: 43 74% 66%; --chart-4: 43 74% 66%;
--chart-5: 27 87% 67%; --chart-5: 27 87% 67%;
--radius: 0.5rem
} }
.dark { .dark {
--background: 240 10% 3.9%; --background: 240 10% 3.9%;
--foreground: 0 0% 98%; --foreground: 0 0% 98%;
@@ -53,9 +55,10 @@
--chart-2: 160 60% 45%; --chart-2: 160 60% 45%;
--chart-3: 30 80% 55%; --chart-3: 30 80% 55%;
--chart-4: 280 65% 60%; --chart-4: 280 65% 60%;
--chart-5: 340 75% 55% --chart-5: 340 75% 55%;
} }
} }
@layer base { @layer base {
* { * {
@apply border-border; @apply border-border;
@@ -63,4 +66,4 @@
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} }

View File

@@ -1,26 +1,29 @@
import { type Config } from "tailwindcss"; import type { Config } from "tailwindcss"
export default { const config = {
darkMode: ["class"], darkMode: ["class"],
content: ["./src/**/*.tsx"], content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
prefix: "",
theme: { theme: {
extend: { container: {
borderRadius: { center: true,
lg: "var(--radius)", padding: "2rem",
md: "calc(var(--radius) - 2px)", screens: {
sm: "calc(var(--radius) - 4px)", "2xl": "1400px",
}, },
},
extend: {
colors: { colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))", background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))", foreground: "hsl(var(--foreground))",
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
primary: { primary: {
DEFAULT: "hsl(var(--primary))", DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))", foreground: "hsl(var(--primary-foreground))",
@@ -29,6 +32,10 @@ export default {
DEFAULT: "hsl(var(--secondary))", DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))", foreground: "hsl(var(--secondary-foreground))",
}, },
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: { muted: {
DEFAULT: "hsl(var(--muted))", DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))", foreground: "hsl(var(--muted-foreground))",
@@ -37,37 +44,28 @@ export default {
DEFAULT: "hsl(var(--accent))", DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))", foreground: "hsl(var(--accent-foreground))",
}, },
destructive: { popover: {
DEFAULT: "hsl(var(--destructive))", DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--destructive-foreground))", foreground: "hsl(var(--popover-foreground))",
}, },
border: "hsl(var(--border))", card: {
input: "hsl(var(--input))", DEFAULT: "hsl(var(--card))",
ring: "hsl(var(--ring))", foreground: "hsl(var(--card-foreground))",
chart: {
"1": "hsl(var(--chart-1))",
"2": "hsl(var(--chart-2))",
"3": "hsl(var(--chart-3))",
"4": "hsl(var(--chart-4))",
"5": "hsl(var(--chart-5))",
}, },
}, },
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: { keyframes: {
"accordion-down": { "accordion-down": {
from: { from: { height: "0" },
height: "0", to: { height: "var(--radix-accordion-content-height)" },
},
to: {
height: "var(--radix-accordion-content-height)",
},
}, },
"accordion-up": { "accordion-up": {
from: { from: { height: "var(--radix-accordion-content-height)" },
height: "var(--radix-accordion-content-height)", to: { height: "0" },
},
to: {
height: "0",
},
}, },
}, },
animation: { animation: {
@@ -77,4 +75,6 @@ export default {
}, },
}, },
plugins: [require("tailwindcss-animate")], plugins: [require("tailwindcss-animate")],
} satisfies Config; } satisfies Config
export default config