*/}
148 |
151 |
152 |
157 |
158 |
159 |
160 |
161 | );
162 | }
163 |
--------------------------------------------------------------------------------
/src/app/animated-list/transactions.ts:
--------------------------------------------------------------------------------
1 | export const transactionsData = [
2 | { title: "Coffee Shop Purchase", cost: 4.75, date: "3 Jan 2025" },
3 | { title: "Grocery Store", cost: 67.32, date: "17 Feb 2025" },
4 | { title: "Gas Station", cost: 45.89, date: "5 Dec 2024" },
5 | { title: "Online Subscription", cost: 9.99, date: "22 Mar 2025" },
6 | { title: "Restaurant Dinner", cost: 34.56, date: "14 Nov 2024" },
7 | { title: "Pharmacy", cost: 12.43, date: "8 Apr 2025" },
8 | { title: "Movie Tickets", cost: 24.5, date: "29 Jan 2025" },
9 | { title: "Clothing Store", cost: 78.25, date: "11 May 2025" },
10 | { title: "Fast Food", cost: 8.75, date: "2 Oct 2024" },
11 | { title: "Hardware Store", cost: 56.78, date: "19 Jun 2025" },
12 | { title: "Book Store", cost: 19.99, date: "7 Sep 2024" },
13 | { title: "Uber Ride", cost: 15.67, date: "25 Feb 2025" },
14 | { title: "Parking Fee", cost: 5.0, date: "13 Jul 2025" },
15 | { title: "Electronics Store", cost: 89.99, date: "30 Dec 2024" },
16 | { title: "Hair Salon", cost: 45.0, date: "16 Mar 2025" },
17 | { title: "Pet Store", cost: 32.45, date: "1 Aug 2024" },
18 | { title: "Office Supplies", cost: 23.56, date: "24 Apr 2025" },
19 | { title: "Gym Membership", cost: 29.99, date: "9 Jan 2025" },
20 | { title: "Convenience Store", cost: 7.85, date: "28 Nov 2024" },
21 | { title: "Car Wash", cost: 12.0, date: "15 May 2025" },
22 | { title: "Bakery", cost: 8.5, date: "3 Oct 2024" },
23 | { title: "Dentist Copay", cost: 25.0, date: "21 Jun 2025" },
24 | { title: "Streaming Service", cost: 14.99, date: "6 Feb 2025" },
25 | { title: "Home Goods", cost: 67.89, date: "27 Jul 2024" },
26 | { title: "Mobile Phone Bill", cost: 85.34, date: "12 Mar 2025" },
27 | { title: "Ice Cream Shop", cost: 6.75, date: "31 Aug 2024" },
28 | { title: "Dry Cleaning", cost: 22.5, date: "18 Apr 2025" },
29 | { title: "Concert Tickets", cost: 75.0, date: "4 Jan 2025" },
30 | { title: "Sporting Goods", cost: 49.99, date: "23 Sep 2024" },
31 | { title: "Florist", cost: 35.0, date: "10 May 2025" },
32 | { title: "Shoe Store", cost: 64.5, date: "26 Dec 2024" },
33 | { title: "Taxi Fare", cost: 18.75, date: "14 Jun 2025" },
34 | { title: "Charity Donation", cost: 10.0, date: "2 Feb 2025" },
35 | { title: "Veterinary Clinic", cost: 95.0, date: "20 Jul 2024" },
36 | { title: "Music Download", cost: 1.29, date: "7 Mar 2025" },
37 | { title: "Pizza Delivery", cost: 22.95, date: "25 Aug 2024" },
38 | { title: "Tool Rental", cost: 38.5, date: "12 Apr 2025" },
39 | { title: "Bike Shop", cost: 52.75, date: "28 Nov 2024" },
40 | { title: "Laundromat", cost: 4.5, date: "15 Jan 2025" },
41 | { title: "Toy Store", cost: 27.99, date: "3 Jun 2025" },
42 | { title: "ATM Withdrawal", cost: 40.0, date: "19 Oct 2024" },
43 | { title: "Eyeglasses", cost: 95.99, date: "8 Feb 2025" },
44 | { title: "Jewelry Store", cost: 78.5, date: "24 Jul 2025" },
45 | { title: "Food Truck", cost: 11.25, date: "11 Mar 2025" },
46 | { title: "Magazine Subscription", cost: 19.95, date: "29 Aug 2024" },
47 | { title: "Craft Store", cost: 43.27, date: "16 Apr 2025" },
48 | { title: "Bowling Alley", cost: 32.0, date: "5 Dec 2024" },
49 | { title: "Art Supplies", cost: 28.75, date: "22 May 2025" },
50 | { title: "Fitness Class", cost: 15.0, date: "9 Jan 2025" },
51 | { title: "Bagel Shop", cost: 5.49, date: "27 Jun 2024" },
52 | { title: "Garden Center", cost: 47.85, date: "13 Feb 2025" },
53 | { title: "Parking Ticket", cost: 35.0, date: "30 Sep 2024" },
54 | { title: "Furniture Store", cost: 99.99, date: "18 Apr 2025" },
55 | { title: "Thrift Shop", cost: 12.75, date: "6 Nov 2024" },
56 | { title: "Smoothie Bar", cost: 7.25, date: "23 Mar 2025" },
57 | { title: "Hotel Booking", cost: 89.0, date: "10 Aug 2024" },
58 | { title: "Tire Shop", cost: 76.5, date: "28 Jan 2025" },
59 | { title: "Museum Admission", cost: 18.0, date: "15 Jun 2025" },
60 | { title: "Bookstore Cafe", cost: 9.5, date: "1 Dec 2024" },
61 | { title: "Fishing Supplies", cost: 42.35, date: "19 Apr 2025" },
62 | { title: "Phone Accessories", cost: 24.99, date: "7 Sep 2024" },
63 | { title: "Yoga Studio", cost: 22.0, date: "24 Feb 2025" },
64 | { title: "Cooking Class", cost: 65.0, date: "11 Jul 2025" },
65 | { title: "Vitamin Shop", cost: 33.45, date: "29 Dec 2024" },
66 | { title: "Sports Event", cost: 55.0, date: "17 Mar 2025" },
67 | { title: "Donut Shop", cost: 6.99, date: "4 Aug 2024" },
68 | { title: "Camera Store", cost: 87.5, date: "22 Jan 2025" },
69 | { title: "Luggage Shop", cost: 79.95, date: "9 Jun 2025" },
70 | { title: "Cake Bakery", cost: 28.5, date: "26 Nov 2024" },
71 | { title: "Spa Treatment", cost: 85.0, date: "14 Apr 2025" },
72 | { title: "Wine Shop", cost: 23.99, date: "2 Sep 2024" },
73 | { title: "Locksmith", cost: 45.0, date: "20 Feb 2025" },
74 | { title: "Pottery Studio", cost: 39.5, date: "8 Jul 2025" },
75 | { title: "Arcade", cost: 15.75, date: "25 Dec 2024" },
76 | { title: "Aquarium Visit", cost: 29.5, date: "13 Mar 2025" },
77 | { title: "Watch Repair", cost: 55.0, date: "30 Aug 2024" },
78 | { title: "Camping Gear", cost: 67.25, date: "18 Jan 2025" },
79 | { title: "Cosmetics Store", cost: 32.99, date: "5 Jun 2025" },
80 | { title: "Cheese Shop", cost: 18.45, date: "23 Oct 2024" },
81 | { title: "Photo Printing", cost: 12.99, date: "10 Apr 2025" },
82 | { title: "Hiking Tour", cost: 45.0, date: "27 Sep 2024" },
83 | { title: "Vinyl Records", cost: 27.5, date: "15 Feb 2025" },
84 | { title: "Candy Store", cost: 8.75, date: "3 Jul 2025" },
85 | { title: "Boat Rental", cost: 75.0, date: "21 Nov 2024" },
86 | { title: "Ski Lift Ticket", cost: 85.0, date: "8 Mar 2025" },
87 | { title: "Tailoring Service", cost: 22.5, date: "26 Aug 2024" },
88 | { title: "Karaoke Bar", cost: 35.0, date: "13 Jan 2025" },
89 | { title: "Plant Nursery", cost: 29.99, date: "2 May 2025" },
90 | { title: "Driving Range", cost: 18.5, date: "19 Oct 2024" },
91 | { title: "Sunglasses Kiosk", cost: 24.95, date: "7 Apr 2025" },
92 | { title: "Escape Room", cost: 32.0, date: "24 Sep 2024" },
93 | { title: "Pottery Barn", cost: 59.5, date: "12 Feb 2025" },
94 | { title: "Candle Shop", cost: 17.25, date: "31 Jul 2025" },
95 | { title: "Surf Shop", cost: 49.99, date: "17 Dec 2024" },
96 | { title: "Gourmet Food Store", cost: 38.75, date: "5 May 2025" },
97 | { title: "Bike Rental", cost: 25.0, date: "22 Oct 2024" },
98 | { title: "Mini Golf", cost: 12.5, date: "9 Mar 2025" },
99 | { title: "Antique Store", cost: 65.0, date: "27 Aug 2024" },
100 | ];
101 |
--------------------------------------------------------------------------------
/src/app/animated-tabs/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { GrainyBackground } from "@/components/grainy-background";
4 | import {
5 | AnimatePresence,
6 | motion,
7 | MotionConfig,
8 | Variants,
9 | type Transition,
10 | } from "framer-motion";
11 | import React, { useRef, useState } from "react";
12 |
13 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
14 |
15 | const Context = React.createContext<{
16 | status: string;
17 | setStatus: React.Dispatch
>;
18 | }>({ status: "", setStatus: () => null });
19 |
20 | const tabs = [
21 | { id: "home", label: "Home" },
22 | { id: "features", label: "Features" },
23 | { id: "about", label: "About" },
24 | { id: "contact", label: "Contact" },
25 | ];
26 |
27 | function InnerContent() {
28 | const [activeTab, setActiveTab] = useState(tabs[0]?.id ?? "");
29 | const previousTabRef = useRef(activeTab);
30 |
31 | const handleTabChange = (tabId: string) => {
32 | previousTabRef.current = activeTab;
33 | setActiveTab(tabId);
34 | };
35 |
36 | const getTabIndex = (id: string) => tabs.findIndex((tab) => tab.id === id);
37 | const previousTabIndex = getTabIndex(previousTabRef.current);
38 | const currentTabIndex = getTabIndex(activeTab);
39 | const indexDifference = Math.abs(currentTabIndex - previousTabIndex);
40 |
41 | const activeTabVariants: Variants = {
42 | transitioning: (indexDifference: number) => ({
43 | filter: `blur(${indexDifference * 2}px)`,
44 | }),
45 | idle: { filter: "blur(0px)" },
46 | };
47 |
48 | return (
49 |
50 | {tabs.map((tab) => (
51 |
handleTabChange(tab.id)}
54 | className="relative px-3 py-1.5 font-mono text-sm font-medium text-[#1f1f1f] outline-2 outline-[#1f1f1f]/50 transition-colors focus-visible:outline"
55 | >
56 |
57 | {activeTab === tab.id && (
58 |
67 | )}
68 |
69 | {tab.label}
70 |
71 | ))}
72 |
73 | );
74 | }
75 |
76 | export default function HomePage() {
77 | const [status, setStatus] = React.useState("idle");
78 |
79 | React.useEffect(() => {
80 | function handleEscape(e: KeyboardEvent) {
81 | if (e.key === "Escape") {
82 | setStatus("idle");
83 | }
84 | }
85 | window.addEventListener("keydown", handleEscape);
86 | return () => window.removeEventListener("keydown", handleEscape);
87 | }, [setStatus]);
88 |
89 | return (
90 |
91 |
92 |
97 |
98 |
99 |
100 |
101 | );
102 | }
103 |
--------------------------------------------------------------------------------
/src/app/audiobooks/all-the-light.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/audiobooks/all-the-light.jpg
--------------------------------------------------------------------------------
/src/app/audiobooks/dune.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/audiobooks/dune.jpg
--------------------------------------------------------------------------------
/src/app/audiobooks/farewell.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/audiobooks/farewell.jpg
--------------------------------------------------------------------------------
/src/app/audiobooks/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | motion,
5 | MotionConfig,
6 | type Transition,
7 | useVelocity,
8 | useMotionValue,
9 | useMotionValueEvent,
10 | useTransform,
11 | useSpring,
12 | } from "framer-motion";
13 | import { Play } from "lucide-react";
14 | import Image from "next/image";
15 | import React from "react";
16 | import imageFarewell from "./farewell.jpg";
17 | import imageDune from "./dune.jpg";
18 | import imageAllTheLight from "./all-the-light.jpg";
19 |
20 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
21 |
22 | const Context = React.createContext<{
23 | status: string;
24 | setStatus: React.Dispatch>;
25 | }>({ status: "", setStatus: () => null });
26 |
27 | function InnerContent() {
28 | const ctx = React.useContext(Context);
29 |
30 | const x = useMotionValue(0);
31 | const xSmooth = useSpring(x, { damping: 10, stiffness: 100 });
32 | const xVelocity = useVelocity(xSmooth);
33 | const rotate = useTransform(
34 | xVelocity,
35 | [-3500, 0, 3500],
36 | ["15deg", "0deg", "-15deg"],
37 | {
38 | clamp: false,
39 | },
40 | );
41 |
42 | useMotionValueEvent(xVelocity, "change", (latestVelocity) => {
43 | console.log("Velocity", latestVelocity);
44 | });
45 |
46 | return (
47 |
48 |
Audiobooks
49 |
61 |
62 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
A Farewell To Arms
77 |
Ernest Hemingway
78 |
79 |
80 |
81 |
84 |
85 | 1h 24m
86 |
87 |
88 |
89 |
90 |
91 |
95 |
100 |
101 |
102 |
103 |
104 |
105 |
Dune
106 |
Frank Herbert
107 |
108 |
109 |
110 |
113 |
114 | 3h 6m
115 |
116 |
117 |
118 |
119 |
120 |
124 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | All the Light We Cannot See
136 |
137 |
Anthony Doerr
138 |
139 |
140 |
141 |
144 |
145 | 3h 51m
146 |
147 |
148 |
149 |
150 |
151 |
152 | );
153 | }
154 |
155 | export default function HomePage() {
156 | const [status, setStatus] = React.useState("idle");
157 |
158 | React.useEffect(() => {
159 | function handleEscape(e: KeyboardEvent) {
160 | if (e.key === "Escape") {
161 | setStatus("idle");
162 | }
163 | }
164 | window.addEventListener("keydown", handleEscape);
165 | return () => window.removeEventListener("keydown", handleEscape);
166 | }, [setStatus]);
167 |
168 | return (
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | );
177 | }
178 |
--------------------------------------------------------------------------------
/src/app/bird/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { AnimatePresence, motion, MotionConfig } from "framer-motion";
4 | import imageBird from "@/assets/bird.jpg";
5 | import Image from "next/image";
6 | import React from "react";
7 | import { X } from "lucide-react";
8 |
9 | export default function HomePage() {
10 | const [open, setOpen] = React.useState(false);
11 | const [closeHovered, setCloseHovered] = React.useState(false);
12 |
13 | const containerVariants = {
14 | hover: (custom: { open: boolean }) => ({
15 | scale: !custom.open ? 1.05 : 1,
16 | }),
17 | };
18 |
19 | const blurVariants = {
20 | hover: (custom: { open: boolean }) => ({
21 | height: !custom.open ? "60%" : "33%",
22 | }),
23 | };
24 |
25 | return (
26 |
27 |
28 |
29 | {open && (
30 |
36 |
41 |
42 | Close
43 |
44 |
45 | setCloseHovered(true)}
47 | onHoverEnd={() => setCloseHovered(false)}
48 | onClick={() => {
49 | setOpen(false);
50 | setCloseHovered(false);
51 | }}
52 | >
53 |
54 |
55 |
56 | )}
57 |
58 |
59 |
setOpen((prevState) => !prevState)}
73 | data-open={open}
74 | className="relative overflow-hidden rounded-[48px] data-[open=false]:shadow-[-16px_-16px_64px_-32px_rgba(56,76,55,1),0_32px_64px_-32px_rgba(53,113,201,0.8),32px_0_64px_-32px_rgba(153,170,4,0.6)]"
75 | >
76 |
81 |
82 |
88 |
89 |
97 |
98 |
99 |
{`Bold New Contemporary\nArt Showcase`}
100 |
101 | See new media evolve
102 |
103 |
104 |
105 |
106 |
107 | );
108 | }
109 |
--------------------------------------------------------------------------------
/src/app/carousel/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | AnimatePresence,
5 | motion,
6 | MotionConfig,
7 | type Transition,
8 | } from "framer-motion";
9 | import Image from "next/image";
10 | import React from "react";
11 | import imageBarn from "@/assets/barn.jpg";
12 | import imageOrlando from "@/assets/orlando.jpg";
13 | import imageSnow from "@/assets/snow-board.jpg";
14 | import imageField from "@/assets/field.jpg";
15 | import { ChevronLeft, ChevronRight } from "lucide-react";
16 | import { cn } from "@/lib/utils";
17 |
18 | const Context = React.createContext<{
19 | index: number;
20 | setIndex: React.Dispatch>;
21 | status: string;
22 | setStatus: React.Dispatch>;
23 | }>({ index: 0, setIndex: () => null, status: "", setStatus: () => null });
24 |
25 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
26 |
27 | const locationData = [
28 | {
29 | title: "Orlando Beach",
30 | city: "Orlando",
31 | state: "FL",
32 | image: imageOrlando,
33 | },
34 | {
35 | title: "Mount Elbert",
36 | city: "Leadville",
37 | state: "CO",
38 | image: imageSnow,
39 | },
40 | {
41 | title: "Mount Rainier",
42 | city: "Paradise",
43 | state: "WA",
44 | image: imageBarn,
45 | },
46 | {
47 | title: "Galt Ranch",
48 | city: "White Sulphur Springs",
49 | state: "MT",
50 | image: imageField,
51 | },
52 | ];
53 |
54 | function NavigationIndicator() {
55 | const ctx = React.useContext(Context);
56 |
57 | return (
58 |
92 | );
93 | }
94 |
95 | function PreviousButton() {
96 | const ctx = React.useContext(Context);
97 |
98 | function handlePreviousClick() {
99 | if (ctx.index <= 0) return;
100 | ctx.setIndex((prev) => prev - 1);
101 | }
102 |
103 | return (
104 | ctx.setStatus("pressing-previous")}
108 | onMouseUp={() => ctx.setStatus("idle")}
109 | onClick={handlePreviousClick}
110 | className="group absolute left-0 top-0 isolate flex h-full w-1/3 items-center pl-8"
111 | >
112 |
113 |
114 |
115 |
116 | );
117 | }
118 |
119 | function NextButton() {
120 | const ctx = React.useContext(Context);
121 |
122 | function handleNextClick() {
123 | if (ctx.index >= 3) return;
124 | ctx.setIndex((prev) => prev + 1);
125 | }
126 |
127 | return (
128 | ctx.setStatus("pressing-next")}
132 | onMouseUp={() => ctx.setStatus("idle")}
133 | onClick={handleNextClick}
134 | className="group absolute right-0 top-0 isolate flex h-full w-1/3 items-center justify-end pr-8"
135 | >
136 |
137 |
138 |
139 |
140 | );
141 | }
142 |
143 | function InnerContent() {
144 | const ctx = React.useContext(Context);
145 | const location = locationData[ctx.index];
146 | const isPressingNext = ctx.status === "pressing-next";
147 | const isPressingPrevious = ctx.status === "pressing-previous";
148 |
149 | return (
150 |
151 |
152 |
177 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
205 |
206 | {location.title}
207 |
208 | {location.city}
209 |
210 | {location.state}
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 | );
221 | }
222 |
223 | export default function HomePage() {
224 | const [index, setIndex] = React.useState(2);
225 | const [status, setStatus] = React.useState("idle");
226 |
227 | React.useEffect(() => {
228 | function handleEscape(e: KeyboardEvent) {
229 | if (e.key === "Escape") {
230 | setStatus("idle");
231 | }
232 | }
233 | window.addEventListener("keydown", handleEscape);
234 | return () => window.removeEventListener("keydown", handleEscape);
235 | }, [setStatus]);
236 |
237 | return (
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 | );
246 | }
247 |
--------------------------------------------------------------------------------
/src/app/checkout/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { AnimatePresence, motion, MotionConfig } from "framer-motion";
4 | import { ShoppingCart } from "lucide-react";
5 | import React from "react";
6 |
7 | export default function AddToCartPage() {
8 | const [hovered, setHovered] = React.useState(false);
9 |
10 | return (
11 |
12 |
13 |
14 |
19 | 3 Items in cart
20 |
21 |
setHovered(true)}
23 | onMouseOut={() => setHovered(false)}
24 | className="relative z-10 flex h-[50px] items-center justify-center rounded-[12px] bg-[#1f1f1f] px-8 font-semibold text-[#fafafa] shadow-[0_1px_1px_1px_rgba(0,0,0,0.08),0_6px_6px_-3px_rgba(0,0,0,0.06)]"
25 | >
26 | Checkout
27 |
28 |
29 |
30 | {!hovered && (
31 |
37 | 3
38 |
39 | )}
40 |
41 |
42 |
43 |
44 |
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/src/app/create-new/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | AnimatePresence,
5 | motion,
6 | MotionConfig,
7 | type Transition,
8 | } from "framer-motion";
9 | import {
10 | BellRing,
11 | ClipboardList,
12 | Flag,
13 | Folder,
14 | Plus,
15 | StickyNote,
16 | Trophy,
17 | X,
18 | } from "lucide-react";
19 | import React from "react";
20 |
21 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
22 |
23 | const Context = React.createContext<{
24 | status: string;
25 | setStatus: React.Dispatch>;
26 | }>({ status: "", setStatus: () => null });
27 |
28 | function InnerContent() {
29 | const ctx = React.useContext(Context);
30 | const isOpen = ctx.status === "open";
31 | const isHovered = ctx.status === "hovered";
32 |
33 | return (
34 |
35 | {isOpen || isHovered ? (
36 |
41 |
42 |
43 | Create New
44 |
45 |
46 |
47 | {isHovered && (
48 |
54 | Close
55 |
56 | )}
57 |
58 |
ctx.setStatus("idle")}
61 | initial={{ opacity: 0, x: -20, y: 10 }}
62 | animate={{ opacity: 1, x: 0, y: 0 }}
63 | exit={{ opacity: 0, x: -20, y: 10 }}
64 | transition={{ ...transition, delay: 0.15 }}
65 | whileTap={{
66 | scale: 0.9,
67 | transition: { ...transition, duration: 0.2 },
68 | }}
69 | onHoverStart={() => ctx.setStatus("hovered")}
70 | onHoverEnd={() => ctx.setStatus("open")}
71 | className="size-6 flex items-center justify-center rounded-full bg-[#b8b6af]"
72 | >
73 |
77 |
78 |
79 |
80 |
90 |
91 |
ctx.setStatus("idle")}
93 | className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-[#fefefe] transition duration-500 ease-in-out hover:bg-[#f6f4f0] hover:duration-200 active:scale-90"
94 | >
95 |
99 |
100 |
ctx.setStatus("idle")}
102 | className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-[#fefefe] transition duration-500 ease-in-out hover:bg-[#f6f4f0] hover:duration-200 active:scale-90"
103 | >
104 |
108 |
109 |
ctx.setStatus("idle")}
111 | className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-[#fefefe] transition duration-500 ease-in-out hover:bg-[#f6f4f0] hover:duration-200 active:scale-90"
112 | >
113 |
117 |
118 |
119 |
120 |
ctx.setStatus("idle")}
122 | className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-[#fefefe] transition duration-500 ease-in-out hover:bg-[#f6f4f0] hover:duration-200 active:scale-90"
123 | >
124 |
128 |
129 |
ctx.setStatus("idle")}
131 | className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-[#fefefe] transition duration-500 ease-in-out hover:bg-[#f6f4f0] hover:duration-200 active:scale-90"
132 | >
133 |
134 |
135 |
Milestone
136 |
137 |
138 |
ctx.setStatus("idle")}
140 | className="size-24 grid cursor-pointer place-items-center rounded-2xl bg-[#fefefe] transition duration-500 ease-in-out hover:bg-[#f6f4f0] hover:duration-200 active:scale-90"
141 | >
142 |
143 |
144 |
Reminder
145 |
146 |
147 |
148 |
149 |
150 | ) : (
151 | ctx.setStatus("open")}
154 | whileTap={{ scale: 0.95 }}
155 | style={{ borderRadius: 22 }}
156 | className="flex items-center gap-1.5 bg-[#fafafa] px-5 py-2.5 tracking-tight text-[#202020] shadow-mixed ring-1 ring-black/[8%] transition-[box-shadow] active:shadow-none"
157 | >
158 |
165 |
166 |
167 |
168 | Create New
169 |
170 |
171 | )}
172 |
173 | );
174 | }
175 |
176 | export default function HomePage() {
177 | const [status, setStatus] = React.useState("idle");
178 |
179 | React.useEffect(() => {
180 | function handleEscape(e: KeyboardEvent) {
181 | if (e.key === "Escape") {
182 | setStatus("idle");
183 | }
184 | }
185 | window.addEventListener("keydown", handleEscape);
186 | return () => window.removeEventListener("keydown", handleEscape);
187 | }, [setStatus]);
188 |
189 | return (
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 | );
198 | }
199 |
--------------------------------------------------------------------------------
/src/app/dynamic-tabs/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { GrainyBackground } from "@/components/grainy-background";
4 | import { cn } from "@/lib/utils";
5 | import {
6 | AnimatePresence,
7 | motion,
8 | MotionConfig,
9 | type Transition,
10 | } from "framer-motion";
11 | import React from "react";
12 |
13 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
14 |
15 | const Context = React.createContext<{
16 | status: string;
17 | setStatus: React.Dispatch>;
18 | bgStatus: string;
19 | setBgStatus: React.Dispatch>;
20 | }>({
21 | status: "",
22 | setStatus: () => null,
23 | bgStatus: "",
24 | setBgStatus: () => null,
25 | });
26 |
27 | function InnerContent() {
28 | const ctx = React.useContext(Context);
29 |
30 | return (
31 |
32 |
ctx.setBgStatus("system")}
34 | animate={
35 | {
36 | // color: ctx.bgStatus === "system" ? "#ffffff" : "#000000",
37 | }
38 | }
39 | className={cn("relative h-12 w-[175px] rounded-full")}
40 | >
41 | {ctx.bgStatus === "system" && (
42 |
47 | )}
48 |
49 | System
50 |
51 |
52 |
53 |
54 |
55 |
56 | {ctx.bgStatus === "system" ? (
57 | ctx.setBgStatus("manual")}
59 | initial={{ opacity: 0, color: "#ffffff" }}
60 | animate={{ opacity: 1, color: "#000000" }}
61 | exit={{ opacity: 0, color: "#ffffff" }}
62 | className={cn("absolute inset-0")}
63 | >
64 |
65 |
72 | Manual
73 |
74 |
75 |
79 | Light
80 |
81 | /
82 |
86 | Dark
87 |
88 |
89 |
90 |
91 | ) : (
92 | <>
93 |
98 |
104 | ctx.setStatus("light")}
107 | className="relative h-full w-full rounded-full text-white"
108 | >
109 | {ctx.status === "light" && (
110 |
115 | )}
116 |
120 | Light
121 |
122 |
123 | ctx.setStatus("dark")}
126 | className="relative h-full w-full rounded-full text-white"
127 | >
128 | {ctx.status === "dark" && (
129 |
134 | )}
135 |
139 | Dark
140 |
141 |
142 |
143 | >
144 | )}
145 |
146 |
147 |
148 |
149 | {ctx.bgStatus === "manual" && (
150 |
157 | Manual
158 |
159 | )}
160 |
161 |
162 |
163 | );
164 | }
165 |
166 | export default function HomePage() {
167 | const [status, setStatus] = React.useState("light");
168 | const [bgStatus, setBgStatus] = React.useState("system");
169 |
170 | React.useEffect(() => {
171 | function handleEscape(e: KeyboardEvent) {
172 | if (e.key === "Escape") {
173 | setStatus("light");
174 | }
175 | }
176 | window.addEventListener("keydown", handleEscape);
177 | return () => window.removeEventListener("keydown", handleEscape);
178 | }, [setStatus]);
179 |
180 | return (
181 |
182 |
183 |
191 |
192 |
193 |
194 |
195 | );
196 | }
197 |
--------------------------------------------------------------------------------
/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/favicon.ico
--------------------------------------------------------------------------------
/src/app/flashlight/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion, MotionConfig, type Transition } from "framer-motion";
4 | import { Flashlight } from "lucide-react";
5 | import React from "react";
6 |
7 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
8 |
9 | const Context = React.createContext<{
10 | status: string;
11 | setStatus: React.Dispatch>;
12 | }>({ status: "", setStatus: () => null });
13 |
14 | function InnerContent() {
15 | const ctx = React.useContext(Context);
16 | const isNarrow = ctx.status === "narrow";
17 |
18 | return (
19 |
20 |
25 |
46 |
68 |
83 |
100 |
101 |
ctx.setStatus("narrow")}
103 | className="size-16 absolute -bottom-20 left-1/2 -translate-x-1/2 bg-white bg-[radial-gradient(circle_at_50%_40%,#f5f1ff_10%,#dcd8ff_40%)] bg-no-repeat [mask:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1mbGFzaGxpZ2h0Ij48cGF0aCBkPSJNMTggNmMwIDItMiAyLTIgNHYxMGEyIDIgMCAwIDEtMiAyaC00YTIgMiAwIDAgMS0yLTJWMTBjMC0yLTItMi0yLTRWMmgxMnoiLz48bGluZSB4MT0iNiIgeDI9IjE4IiB5MT0iNiIgeTI9IjYiLz48bGluZSB4MT0iMTIiIHgyPSIxMiIgeTE9IjEyIiB5Mj0iMTIiLz48L3N2Zz4=)] [maskPosition:center] [maskRepeat:no-repeat] [maskSize:100%_100%]"
104 | />
105 |
106 | );
107 | }
108 |
109 | export default function HomePage() {
110 | const [status, setStatus] = React.useState("idle");
111 |
112 | React.useEffect(() => {
113 | function handleEscape(e: KeyboardEvent) {
114 | if (e.key === "Escape") {
115 | setStatus("idle");
116 | }
117 | }
118 | window.addEventListener("keydown", handleEscape);
119 | return () => window.removeEventListener("keydown", handleEscape);
120 | }, [setStatus]);
121 |
122 | return (
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | );
131 | }
132 |
--------------------------------------------------------------------------------
/src/app/folder/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion, MotionConfig, type Transition } from "framer-motion";
4 | import React from "react";
5 |
6 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
7 |
8 | const Context = React.createContext<{
9 | status: string;
10 | setStatus: React.Dispatch
>;
11 | }>({ status: "", setStatus: () => null });
12 |
13 | function InnerContent() {
14 | const ctx = React.useContext(Context);
15 | const isOpen = ctx.status === "open";
16 |
17 | return (
18 | {
20 | if (isOpen) {
21 | ctx.setStatus("idle");
22 | return;
23 | }
24 | ctx.setStatus("open");
25 | }}
26 | className="relative aspect-[1.3] h-64"
27 | >
28 |
44 |
60 |
80 |
81 |
82 |
98 |
99 |
104 |
109 |
110 |
111 |
112 | );
113 | }
114 |
115 | export default function HomePage() {
116 | const [status, setStatus] = React.useState("idle");
117 |
118 | React.useEffect(() => {
119 | function handleEscape(e: KeyboardEvent) {
120 | if (e.key === "Escape") {
121 | setStatus("idle");
122 | }
123 | }
124 | window.addEventListener("keydown", handleEscape);
125 | return () => window.removeEventListener("keydown", handleEscape);
126 | }, [setStatus]);
127 |
128 | return (
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | );
137 | }
138 |
--------------------------------------------------------------------------------
/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 98%;
8 | --foreground: 240 10% 3.9%;
9 | --card: 0 0% 100%;
10 | --card-foreground: 240 10% 3.9%;
11 | --popover: 0 0% 100%;
12 | --popover-foreground: 240 10% 3.9%;
13 | --primary: 240 5.9% 10%;
14 | --primary-foreground: 0 0% 98%;
15 | --secondary: 240 4.8% 95.9%;
16 | --secondary-foreground: 240 5.9% 10%;
17 | --muted: 240 4.8% 95.9%;
18 | --muted-foreground: 240 3.8% 46.1%;
19 | --accent: 240 4.8% 95.9%;
20 | --accent-foreground: 240 5.9% 10%;
21 | --destructive: 0 84.2% 60.2%;
22 | --destructive-foreground: 0 0% 98%;
23 | --border: 240 5.9% 90%;
24 | --input: 240 5.9% 90%;
25 | --ring: 240 10% 3.9%;
26 | --radius: 0.5rem;
27 | --chart-1: 12 76% 61%;
28 | --chart-2: 173 58% 39%;
29 | --chart-3: 197 37% 24%;
30 | --chart-4: 43 74% 66%;
31 | --chart-5: 27 87% 67%;
32 | --shadow-mixed: 0 1px 1px -0.5px rgba(0, 0, 0, 0.04),
33 | 0 3px 3px -1.5px rgba(0, 0, 0, 0.04), 0 6px 6px -3px rgba(0, 0, 0, 0.04),
34 | 0 12px 12px -6px rgba(0, 0, 0, 0.04),
35 | 0 24px 24px -12px rgba(0, 0, 0, 0.04);
36 | }
37 |
38 | .dark {
39 | --background: 240 10% 3.9%;
40 | --foreground: 0 0% 98%;
41 | --card: 240 10% 3.9%;
42 | --card-foreground: 0 0% 98%;
43 | --popover: 240 10% 3.9%;
44 | --popover-foreground: 0 0% 98%;
45 | --primary: 0 0% 98%;
46 | --primary-foreground: 240 5.9% 10%;
47 | --secondary: 240 3.7% 15.9%;
48 | --secondary-foreground: 0 0% 98%;
49 | --muted: 240 3.7% 15.9%;
50 | --muted-foreground: 240 5% 64.9%;
51 | --accent: 240 3.7% 15.9%;
52 | --accent-foreground: 0 0% 98%;
53 | --destructive: 0 62.8% 30.6%;
54 | --destructive-foreground: 0 0% 98%;
55 | --border: 240 3.7% 15.9%;
56 | --input: 240 3.7% 15.9%;
57 | --ring: 240 4.9% 83.9%;
58 | --chart-1: 220 70% 50%;
59 | --chart-2: 160 60% 45%;
60 | --chart-3: 30 80% 55%;
61 | --chart-4: 280 65% 60%;
62 | --chart-5: 340 75% 55%;
63 | }
64 | }
65 |
66 | @layer base {
67 | * {
68 | @apply border-border;
69 | }
70 |
71 | body {
72 | @apply bg-background text-foreground;
73 | }
74 | }
75 |
76 | @layer utilities {
77 |
78 | /* Hide scrollbar for Chrome, Safari and Opera */
79 | .no-scrollbar::-webkit-scrollbar {
80 | display: none;
81 | }
82 |
83 | /* Hide scrollbar for IE, Edge and Firefox */
84 | .no-scrollbar {
85 | -ms-overflow-style: none;
86 | /* IE and Edge */
87 | scrollbar-width: none;
88 | /* Firefox */
89 | }
90 | }
91 |
92 | [vaul-drawer] {
93 | transition: transform 2.2s cubic-bezier(0.165, 0.84, 0.44, 1);
94 | }
95 |
96 | [vaul-overlay] {
97 | transition: opacity 2.2s cubic-bezier(0.165, 0.84, 0.44, 1);
98 | }
99 |
--------------------------------------------------------------------------------
/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from "next";
2 | import { GeistSans } from "geist/font/sans";
3 | import { GeistMono } from "geist/font/mono";
4 | import { EB_Garamond, Dancing_Script, JetBrains_Mono } from "next/font/google";
5 | import "./globals.css";
6 |
7 | export const metadata: Metadata = {
8 | title: "Lab | Vaun Blu",
9 | };
10 |
11 | const EBGaramond = EB_Garamond({
12 | subsets: ["latin"],
13 | variable: "--font-eb-garamond",
14 | display: "swap",
15 | });
16 |
17 | const Mono = JetBrains_Mono({
18 | subsets: ["latin"],
19 | variable: "--font-mono",
20 | display: "swap",
21 | });
22 |
23 | const DancingScript = Dancing_Script({
24 | subsets: ["latin"],
25 | variable: "--font-dancing-script",
26 | display: "swap",
27 | });
28 |
29 | export default function RootLayout({
30 | children,
31 | }: Readonly<{
32 | children: React.ReactNode;
33 | }>) {
34 | return (
35 |
36 |
39 | {children}
40 |
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/src/app/love-folder/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion, MotionConfig, type Transition } from "framer-motion";
4 | import React from "react";
5 | import Image from "next/image";
6 | import imagePlayfulInca from "@/assets/playful-inca.jpg";
7 | import imageStoicInca from "@/assets/stoic-inca.jpg";
8 |
9 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
10 |
11 | const Context = React.createContext<{
12 | status: string;
13 | setStatus: React.Dispatch>;
14 | }>({ status: "", setStatus: () => null });
15 |
16 | function InnerContent() {
17 | const ctx = React.useContext(Context);
18 | const isOpen = ctx.status === "open";
19 |
20 | return (
21 | {
23 | if (isOpen) {
24 | ctx.setStatus("idle");
25 | return;
26 | }
27 | ctx.setStatus("open");
28 | }}
29 | className="relative h-64 w-[332px]"
30 | >
31 |
47 |
48 |
52 |
53 |
54 |
55 |
68 |
69 |
70 |
83 |
84 |
85 |
86 |
91 |
96 |
97 |
102 |
107 |
108 |
109 |
125 |
126 |
131 |
136 |
137 |
138 |
139 | );
140 | }
141 |
142 | export default function HomePage() {
143 | const [status, setStatus] = React.useState("idle");
144 |
145 | React.useEffect(() => {
146 | function handleEscape(e: KeyboardEvent) {
147 | if (e.key === "Escape") {
148 | setStatus("idle");
149 | }
150 | }
151 | window.addEventListener("keydown", handleEscape);
152 | return () => window.removeEventListener("keydown", handleEscape);
153 | }, [setStatus]);
154 |
155 | return (
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | );
164 | }
165 |
--------------------------------------------------------------------------------
/src/app/love-this/her.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/love-this/her.jpg
--------------------------------------------------------------------------------
/src/app/love-this/interstellar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/love-this/interstellar.jpg
--------------------------------------------------------------------------------
/src/app/love-this/love-this/styles.module.css:
--------------------------------------------------------------------------------
1 | .border .child {
2 | filter: drop-shadow(2.5px 0 0 hsl(var(--background))) drop-shadow(-2.5px 0 0 hsl(var(--background))) drop-shadow(0 2.5px 0 hsl(var(--background))) drop-shadow(0 -2.5px 0 hsl(var(--background)));
3 | }
4 |
5 | .border:hover .child {
6 | filter: drop-shadow(2.5px 0 0 hsl(var(--muted))) drop-shadow(-2.5px 0 0 hsl(var(--muted))) drop-shadow(0 2.5px 0 hsl(var(--muted))) drop-shadow(0 -2.5px 0 hsl(var(--muted)));
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/love-this/murph.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/love-this/murph.jpg
--------------------------------------------------------------------------------
/src/app/love-this/page.tsx:
--------------------------------------------------------------------------------
1 | import { LoveThis } from "./love-this";
2 | import imageInterstellar from "./interstellar.jpg";
3 | import imageHer from "./her.jpg";
4 | import imageMurph from "./murph.jpg";
5 | import imageScarlett from "./scarlett.jpg";
6 | import Image from "next/image";
7 |
8 | export default function Home() {
9 | return (
10 |
11 |
17 |
18 |
19 |
Her
20 |
21 |
26 |
Samantha (Scarlett)
27 |
@scarlettjo
28 |
29 |
December 18, 2013
30 |
31 |
32 |
33 |
34 | Theodore is a lonely man in the final stages of his divorce. When
35 | he's not working as a letter writer, his down time is spent
36 | playing video games and occasionally hanging out with friends. He
37 | decides to purchase the new OS1, which is advertised as the
38 | world's first artificially intelligent operating system,
39 | "It's not just an operating system, it's a
40 | consciousness," the ad states. Theodore quickly finds himself
41 | drawn in with Samantha, the voice behind his OS1.
42 |
43 |
44 | As they start spending time together they grow closer and closer and
45 | eventually find themselves in love. Having fallen in love with his OS,
46 | Theodore finds himself dealing with feelings of both great joy and
47 | doubt. As an OS, Samantha has powerful intelligence that she uses to
48 | help Theodore in ways others hadn't, but how does she help him
49 | deal with his inner conflict of being in love with an OS?
50 |
51 |
52 | A great film about loneliness. Splendid performance of Joaquin
53 | Phoenix. And pure poetry. Admirable poem about isolation, need of
54 | other, social surogate and , off course, freedom. Its basic virtue -
55 | the proposed questions creating perfect atmosphere , becoming inspired
56 | challenges to discover new perspectives.
57 |
58 |
59 |
60 |
61 |
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/src/app/love-this/scarlett.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/love-this/scarlett.jpg
--------------------------------------------------------------------------------
/src/app/magic-button/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { cn } from "@/lib/utils";
4 | import { AnimatePresence, motion, MotionConfig } from "framer-motion";
5 | import { Sparkle } from "lucide-react";
6 | import React from "react";
7 |
8 | export default function HomePage() {
9 | const [loading, setLoading] = React.useState(false);
10 |
11 | React.useEffect(() => {
12 | if (loading) {
13 | const timeout = setTimeout(() => setLoading(false), 2000);
14 | return () => clearTimeout(timeout);
15 | }
16 | }, [loading, setLoading]);
17 |
18 | return (
19 |
20 |
21 |
setLoading(true)}
26 | className={cn(
27 | "flex h-10 w-[145px] items-center justify-center rounded-full bg-gradient-to-b from-[#8D22E1] to-[#F043FF] text-white shadow-[0_-4px_6px_2px_#8D22E1_inset,0_0_0_2px_#AF3DFF_inset,0_5px_11px_0_rgba(114,22,123,0.5)] transition-[box-shadow,opacity,transform] duration-200 active:scale-[0.99] active:shadow-[0_-4px_6px_2px_#8D22E1_inset,0_0_0_2px_#AF3DFF_inset,0_5px_11px_0_rgba(114,22,123,0.2)]",
28 | { "opacity-90": loading },
29 | )}
30 | >
31 |
36 |
37 |
47 |
52 |
53 |
65 |
70 |
71 |
81 |
86 |
87 |
88 |
89 |
95 | {loading ? "Generating" : "Generate"}
96 |
97 |
98 |
99 |
100 |
101 |
102 | );
103 | }
104 |
--------------------------------------------------------------------------------
/src/app/neu/styles.module.css:
--------------------------------------------------------------------------------
1 | .toolbar {
2 | background: linear-gradient(145deg, #2b2b2b, #242424);
3 | box-shadow:
4 | 30px 30px 60px rgba(32, 32, 32, 0.5),
5 | -30px -30px 60px rgba(48, 48, 48, 0.4);
6 | }
7 |
8 | .drop-down {
9 | background: linear-gradient(145deg, #2b2b2b, #242424);
10 | box-shadow:
11 | 30px 30px 60px rgba(32, 32, 32, 0.5),
12 | -30px -30px 60px rgba(48, 48, 48, 0.1);
13 | }
14 |
15 | .drop-down-trigger {
16 | background: linear-gradient(145deg, #3c3c3c, #323232);
17 | border: 2px rgba(0, 0, 0, 0);
18 | border-top-style: solid;
19 | border-left-style: solid;
20 | }
21 |
22 | .drop-down-trigger:hover {
23 | background: linear-gradient(145deg, #3c3c3c, #323232);
24 | }
25 |
26 | .drop-down-trigger[data-open="true"] {
27 | border-color: rgba(76, 76, 76, 0.6);
28 | background: linear-gradient(145deg, #3c3c3c, #323232);
29 | box-shadow:
30 | 12px 12px 28px rgba(45, 45, 45, 0.2),
31 | -12px -12px 28px rgba(67, 67, 67, 0.2);
32 | }
33 |
34 | .drop-down-button {
35 | border: 2px rgba(0, 0, 0, 0);
36 | border-top-style: solid;
37 | border-left-style: solid;
38 | }
39 |
40 | .drop-down-button:hover {
41 | background: rgba(60, 60, 60, 0.8);
42 | }
43 |
44 | .drop-down-button:active {
45 | border-color: rgba(76, 76, 76, 0.6);
46 | background: linear-gradient(145deg, #323232, #3c3c3c);
47 | box-shadow:
48 | 0 12px 12px -6px rgba(0, 0, 0, 0.2),
49 | 12px 12px 28px rgba(45, 45, 45, 0.2),
50 | -12px -12px 28px rgba(67, 67, 67, 0.2);
51 | }
52 |
53 | .button {
54 | border: 2px rgba(0, 0, 0, 0);
55 | border-top-style: solid;
56 | border-left-style: solid;
57 | }
58 |
59 | .button:active,
60 | .button:focus {
61 | border-color: rgba(76, 76, 76, 0.6);
62 | background: linear-gradient(145deg, #323232, #3c3c3c);
63 | box-shadow:
64 | 0 12px 12px -6px rgba(0, 0, 0, 0.2),
65 | 12px 12px 28px rgba(45, 45, 45, 0.2),
66 | -12px -12px 28px rgba(67, 67, 67, 0.2);
67 | }
68 |
--------------------------------------------------------------------------------
/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import { Sidebar } from "../components/sidebar";
5 |
6 | function MainContent() {
7 | return (
8 |
9 |
Welcome to the Lab
10 |
11 | This is the main page of our UI component laboratory.
12 |
13 |
14 | Select an example from the sidebar to explore different UI components
15 | and experiments.
16 |
17 |
18 | );
19 | }
20 |
21 | export default function HomePage() {
22 | return (
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/src/app/phone-glow/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { cn } from "@/lib/utils";
4 | import {
5 | AnimatePresence,
6 | motion,
7 | MotionConfig,
8 | Transition,
9 | } from "framer-motion";
10 | import React from "react";
11 | import Image from "next/image";
12 | import svgPhone from "@/assets/iphone-black.svg";
13 |
14 | const Context = React.createContext<{
15 | status: string;
16 | setStatus: React.Dispatch>;
17 | }>({ status: "", setStatus: () => null });
18 |
19 | const transition: Transition = {
20 | type: "tween",
21 | ease: "easeInOut",
22 | duration: 2,
23 | };
24 |
25 | function InnerContent() {
26 | const ctx = React.useContext(Context);
27 | const isActive = ctx.status === "active";
28 |
29 | return (
30 | ctx.setStatus("active")}
32 | className="relative flex h-full flex-col overflow-hidden rounded-[51px] bg-[#000000] py-20"
33 | >
34 |
47 |
48 |
61 |
62 |
75 |
76 |
89 |
90 | );
91 | }
92 |
93 | export default function HomePage() {
94 | const [status, setStatus] = React.useState("idle");
95 |
96 | React.useEffect(() => {
97 | function handleEscape(e: KeyboardEvent) {
98 | if (e.key === "Escape") {
99 | setStatus("idle");
100 | }
101 | }
102 | window.addEventListener("keydown", handleEscape);
103 | return () => window.removeEventListener("keydown", handleEscape);
104 | }, [setStatus]);
105 |
106 | return (
107 |
108 |
109 |
110 |
115 |
116 |
117 |
118 |
119 |
122 |
123 |
128 |
129 |
130 |
131 |
132 | );
133 | }
134 |
--------------------------------------------------------------------------------
/src/app/popcorn/mesh-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/popcorn/mesh-1.png
--------------------------------------------------------------------------------
/src/app/popcorn/mesh-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/popcorn/mesh-2.png
--------------------------------------------------------------------------------
/src/app/popcorn/mesh-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/popcorn/mesh-3.png
--------------------------------------------------------------------------------
/src/app/shop-claim/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { cn } from "@/lib/utils";
4 | import {
5 | AnimatePresence,
6 | motion,
7 | MotionConfig,
8 | Transition,
9 | useMotionValue,
10 | useTransform,
11 | } from "framer-motion";
12 | import React from "react";
13 | import Image from "next/image";
14 | import svgPhone from "@/assets/iphone-black.svg";
15 | import imageShopDollar from "./shop-dollar.jpg";
16 | import imageShop from "./shop.png";
17 | import imageShopify from "./shopify.png";
18 | import { ArrowRight, CheckIcon } from "lucide-react";
19 |
20 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
21 |
22 | const Context = React.createContext<{
23 | status: string;
24 | setStatus: React.Dispatch>;
25 | }>({ status: "", setStatus: () => null });
26 |
27 | function InnerContent() {
28 | const ctx = React.useContext(Context);
29 | const isClaimed = ctx.status === "claimed";
30 | const x = useMotionValue(0);
31 | const opacity = useTransform(x, [0, 130], [1, 0]);
32 | const bgColor = useTransform(
33 | x,
34 | [0, 160],
35 | ["rgb(204 204 204 / 0.3)", "rgb(159 226 191 / 0.4)"],
36 | );
37 |
38 | React.useEffect(() => {
39 | if (isClaimed) {
40 | const timeout = setTimeout(() => {
41 | x.set(0);
42 | ctx.setStatus("idle");
43 | }, 2500);
44 | return () => clearTimeout(timeout);
45 | }
46 | }, [isClaimed, ctx.setStatus]);
47 |
48 | return (
49 |
50 |
51 |
52 |
53 |
54 |
59 |
60 |
64 |
65 |
66 | Here's $5!
67 |
68 |
69 | You can spend it in your Shop
70 |
71 | app on your favorite brands or products.
72 |
73 |
74 |
75 |
76 |
{
81 | if (info.offset.x >= 196 || info.velocity.x > 500) {
82 | ctx.setStatus("claimed");
83 | } else {
84 | x.set(0);
85 | }
86 | }}
87 | whileTap={{ scale: 1.05 }}
88 | style={{ x }}
89 | className="relative z-10 grid h-full w-20 place-items-center rounded-full bg-white"
90 | >
91 |
92 |
93 |
97 | Claim $5 Shop Cash
98 |
99 |
100 |
101 |
Powered by
102 |
107 |
108 |
109 |
110 |
111 |
112 | {isClaimed && (
113 |
119 |
125 |
126 |
127 |
128 |
134 | You claimed $5 in Shop Cash!
135 |
136 |
137 | )}
138 |
139 |
140 |
141 | {isClaimed && (
142 | <>
143 |
149 |
155 | >
156 | )}
157 |
158 |
159 |
160 | );
161 | }
162 |
163 | export default function HomePage() {
164 | const [status, setStatus] = React.useState("idle");
165 |
166 | React.useEffect(() => {
167 | function handleEscape(e: KeyboardEvent) {
168 | if (e.key === "Escape") {
169 | setStatus("idle");
170 | }
171 | }
172 | window.addEventListener("keydown", handleEscape);
173 | return () => window.removeEventListener("keydown", handleEscape);
174 | }, [setStatus]);
175 |
176 | return (
177 |
178 |
179 |
180 |
185 |
186 |
187 |
188 |
189 |
194 |
195 |
196 |
197 |
198 | );
199 | }
200 |
--------------------------------------------------------------------------------
/src/app/shop-claim/shop-dollar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/shop-claim/shop-dollar.jpg
--------------------------------------------------------------------------------
/src/app/shop-claim/shop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/shop-claim/shop.png
--------------------------------------------------------------------------------
/src/app/shop-claim/shopify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/shop-claim/shopify.png
--------------------------------------------------------------------------------
/src/app/smooth-dropdown/interstellar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/smooth-dropdown/interstellar.jpg
--------------------------------------------------------------------------------
/src/app/smooth-dropdown/murph.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/smooth-dropdown/murph.jpg
--------------------------------------------------------------------------------
/src/app/switch/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { GrainyBackground } from "@/components/grainy-background";
4 | import * as SwitchPrimitive from "@radix-ui/react-switch";
5 | import { motion, MotionConfig, type Transition } from "framer-motion";
6 | import React, { useState } from "react";
7 |
8 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
9 |
10 | const Context = React.createContext<{
11 | status: string;
12 | setStatus: React.Dispatch>;
13 | }>({ status: "", setStatus: () => null });
14 |
15 | function InnerContent() {
16 | const ctx = React.useContext(Context);
17 | const [checked, setChecked] = useState(false);
18 |
19 | return (
20 |
25 |
26 |
40 |
41 |
42 | );
43 | }
44 |
45 | export default function HomePage() {
46 | const [status, setStatus] = React.useState("idle");
47 |
48 | React.useEffect(() => {
49 | function handleEscape(e: KeyboardEvent) {
50 | if (e.key === "Escape") {
51 | setStatus("idle");
52 | }
53 | }
54 | window.addEventListener("keydown", handleEscape);
55 | return () => window.removeEventListener("keydown", handleEscape);
56 | }, [setStatus]);
57 |
58 | return (
59 |
60 |
61 |
66 |
67 |
68 |
69 |
70 | );
71 | }
72 |
--------------------------------------------------------------------------------
/src/app/thunder-airdrop/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion, MotionConfig, Transition, useSpring } from "framer-motion";
4 | import React from "react";
5 | import imageThunderBg from "@/assets/thunder-bg.png";
6 | import imageAzura from "@/assets/azura.png";
7 | import Image from "next/image";
8 |
9 | // NOTE: TOOK 30 MINS
10 |
11 | const transition: Transition = {
12 | type: "spring",
13 | damping: 80,
14 | stiffness: 100,
15 | };
16 |
17 | function SpringNumber(props: { value: number }) {
18 | const ref = React.useRef(null);
19 | const springValue = useSpring(0, {
20 | damping: 80,
21 | stiffness: 100,
22 | });
23 |
24 | React.useEffect(() => {
25 | springValue.set(props.value);
26 | }, [springValue]);
27 |
28 | springValue.on("change", (latest) => {
29 | if (ref.current) {
30 | ref.current.textContent = Intl.NumberFormat("en-US", {
31 | style: "decimal",
32 | minimumSignificantDigits: 1,
33 | }).format(Number(latest.toFixed(0)));
34 | }
35 | });
36 |
37 | return 0 ;
38 | }
39 |
40 | export default function HomePage() {
41 | const [status, setStatus] = React.useState("idle");
42 |
43 | React.useEffect(() => {
44 | function handleEscape(e: KeyboardEvent) {
45 | if (e.key === "Escape") {
46 | setStatus("idle");
47 | }
48 | }
49 | window.addEventListener("keydown", handleEscape);
50 | return () => window.removeEventListener("keydown", handleEscape);
51 | }, [setStatus]);
52 |
53 | return (
54 |
55 |
56 |
57 |
58 |
Airdrop live
59 |
60 | for beta users 0% Fees.
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
76 |
82 |
83 |
84 |
90 | Thunder
91 |
92 |
93 |
98 |
104 |
105 |
106 |
112 | Competition
113 |
114 |
115 |
116 |
117 |
118 | Thunder
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
133 |
134 | {/* Grain SVG */}
135 |
136 |
137 |
143 |
144 |
145 |
146 | );
147 | }
148 |
--------------------------------------------------------------------------------
/src/app/thunder-speed/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { motion, MotionConfig, Transition, useSpring } from "framer-motion";
4 | import React from "react";
5 | import imageThunderBg from "@/assets/thunder-bg.png";
6 | import imageAzura from "@/assets/azura.png";
7 | import Image from "next/image";
8 |
9 | // NOTE: TOOK 90 MINS
10 |
11 | const transition: Transition = {
12 | type: "spring",
13 | damping: 80,
14 | stiffness: 100,
15 | };
16 |
17 | function SpringNumber(props: { value: number }) {
18 | const ref = React.useRef(null);
19 | const springValue = useSpring(0, {
20 | damping: 80,
21 | stiffness: 100,
22 | });
23 |
24 | React.useEffect(() => {
25 | springValue.set(props.value);
26 | }, [springValue]);
27 |
28 | springValue.on("change", (latest) => {
29 | if (ref.current) {
30 | ref.current.textContent = Intl.NumberFormat("en-US", {
31 | style: "decimal",
32 | minimumSignificantDigits: 1,
33 | }).format(Number(latest.toFixed(1)));
34 | }
35 | });
36 |
37 | return 0.0 ;
38 | }
39 |
40 | export default function HomePage() {
41 | const [status, setStatus] = React.useState("idle");
42 |
43 | React.useEffect(() => {
44 | function handleEscape(e: KeyboardEvent) {
45 | if (e.key === "Escape") {
46 | setStatus("idle");
47 | }
48 | }
49 | window.addEventListener("keydown", handleEscape);
50 | return () => window.removeEventListener("keydown", handleEscape);
51 | }, [setStatus]);
52 |
53 | return (
54 |
55 |
56 |
57 |
58 |
Meet Thunder:
59 |
60 | The New, Fastest Way to Trade On-Chain.
61 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 | s
75 |
76 |
81 |
87 | Thunder
88 |
89 |
90 |
91 |
92 |
93 | Thunder
94 |
95 |
96 |
97 |
100 |
101 |
102 |
108 |
109 | s
110 |
111 |
116 |
122 | Competition
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
137 |
138 |
139 |
140 |
141 | {/* Grain SVG */}
142 |
143 |
144 |
150 |
151 |
152 |
153 | );
154 | }
155 |
--------------------------------------------------------------------------------
/src/app/timer/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { GrainyBackground } from "@/components/grainy-background";
4 | import { cn } from "@/lib/utils";
5 | import {
6 | AnimatePresence,
7 | motion,
8 | MotionConfig,
9 | Transition,
10 | } from "framer-motion";
11 | import React, { useEffect, useRef, useState } from "react";
12 | import Image from "next/image";
13 | import svgPhone from "@/assets/iphone-black.svg";
14 | import NumberFlow from "@number-flow/react";
15 | import { Button } from "@/components/ui/button";
16 |
17 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
18 |
19 | const Context = React.createContext<{
20 | status: string;
21 | setStatus: React.Dispatch>;
22 | }>({ status: "", setStatus: () => null });
23 |
24 | function InnerContent() {
25 | const ctx = React.useContext(Context);
26 | const [paused, setPaused] = useState(false);
27 | const [minutesLeft, setMinutesLeft] = useState(43);
28 | let interval = useRef(null);
29 |
30 | useEffect(() => {
31 | interval.current = setInterval(() => {
32 | setMinutesLeft((prev) => prev - 1);
33 | }, 1000);
34 |
35 | return () => {
36 | if (interval.current) {
37 | clearInterval(interval.current);
38 | }
39 | };
40 | }, [setMinutesLeft]);
41 |
42 | function handlePauseToggle() {
43 | console.log(paused);
44 | if (paused) {
45 | interval.current = setInterval(() => {
46 | setMinutesLeft((prev) => prev - 1);
47 | }, 1000);
48 | setPaused(false);
49 | } else {
50 | if (interval.current) {
51 | clearInterval(interval.current);
52 | }
53 | setPaused(true);
54 | }
55 | }
56 |
57 | return (
58 |
59 |
60 |
61 |
62 |
63 |
71 |
72 |
73 |
81 | {paused ? "Start" : "Pause"}
82 |
83 |
89 | Stop
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
Today's activity
98 |
99 |
100 |
101 |
102 |
103 |
Exploration
104 |
Mock out timer design
105 |
106 |
45m
107 |
108 |
109 |
110 |
111 |
112 |
Deep work
113 |
114 | Build page and clip path animation
115 |
116 |
117 |
1h 30m
118 |
119 |
120 |
121 |
122 |
123 |
Deep work
124 |
Record and edit demo
125 |
126 |
30m
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
148 |
149 | );
150 | }
151 |
152 | export default function HomePage() {
153 | const [status, setStatus] = React.useState("idle");
154 |
155 | React.useEffect(() => {
156 | function handleEscape(e: KeyboardEvent) {
157 | if (e.key === "Escape") {
158 | setStatus("idle");
159 | }
160 | }
161 | window.addEventListener("keydown", handleEscape);
162 | return () => window.removeEventListener("keydown", handleEscape);
163 | }, [setStatus]);
164 |
165 | return (
166 |
167 |
168 |
169 |
174 |
175 |
176 |
177 |
178 | {/* */}
179 | {/*
*/}
180 | {/*
*/}
181 |
182 |
187 |
188 |
189 |
190 |
191 | );
192 | }
193 |
--------------------------------------------------------------------------------
/src/app/toast/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { cn } from "@/lib/utils";
4 | import { motion, MotionConfig } from "framer-motion";
5 | import { Check, Loader2, X } from "lucide-react";
6 | import React from "react";
7 |
8 | export default function HomePage() {
9 | const [hovered, setHovered] = React.useState(false);
10 |
11 | return (
12 |
13 |
14 |
15 |
26 |
31 |
37 |
38 |
43 |
44 | Upload Pending
45 |
46 |
47 |
50 |
51 | is being uploaded. Please wait.
52 |
53 |
54 |
55 |
60 |
61 |
62 |
73 |
78 |
79 |
80 |
85 |
86 | Upload Failed
87 |
88 |
89 |
92 |
93 | failed uploading. Please try again.
94 |
95 |
96 |
97 |
102 |
107 |
108 |
109 |
setHovered(true)}
111 | onMouseOut={() => setHovered(false)}
112 | className="relative flex w-[800px] gap-4 rounded-[26px] bg-[#151517] bg-[linear-gradient(45deg,#161618_41.67%,#212123_41.67%,#212123_50%,#161618_50%,#161618_91.67%,#212123_91.67%,#212123_100%)] bg-[size:16.97px_16.97px] p-10 shadow-[0_6px_6px_-3px_rgba(0,0,0,0.1),0_0_0px_2.5px_#161618,0_0_0px_2.5px_rgba(255,255,255,0.15)_inset]"
113 | >
114 |
115 |
116 |
117 |
118 |
119 | Upload Successful
120 |
121 |
122 |
125 |
126 | was uploaded and is ready to use.
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | );
137 | }
138 |
--------------------------------------------------------------------------------
/src/app/todo/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { Checkbox } from "@/components/ui/checkbox";
4 | import {
5 | motion,
6 | MotionConfig,
7 | stagger,
8 | useAnimate,
9 | type Transition,
10 | } from "framer-motion";
11 | import React from "react";
12 |
13 | const transition: Transition = { type: "spring", bounce: 0, duration: 0.4 };
14 |
15 | const Context = React.createContext<{
16 | status: string;
17 | setStatus: React.Dispatch>;
18 | }>({ status: "", setStatus: () => null });
19 |
20 | function InnerContent() {
21 | const [items, setItems] = React.useState([
22 | { id: "1", text: "60 mins practice", checked: true },
23 | { id: "2", text: "Coffee", checked: true },
24 | { id: "3", text: "Work", checked: false },
25 | { id: "4", text: "Walk pupper", checked: true },
26 | { id: "5", text: "Climb", checked: true },
27 | { id: "6", text: "Wind down", checked: true },
28 | ]);
29 |
30 | const [ref, animate] = useAnimate();
31 |
32 | function handleChange(id: string) {
33 | const newItems = items.map((item) => ({
34 | ...item,
35 | checked: item.id === id ? !item.checked : item.checked,
36 | }));
37 |
38 | setItems(newItems);
39 |
40 | if (newItems.every((item) => item.checked)) {
41 | const lastCompletedItemIndex = items.findIndex((item) => !item.checked);
42 | const random = Math.random();
43 |
44 | if (random < 1 / 3) {
45 | // bounce
46 | animate(
47 | '[data-slot="checkbox"]',
48 | {
49 | scale: [1, 1.25, 1],
50 | filter: ["blur(0px)", "blur(1px)", "blur(0px)"],
51 | },
52 | {
53 | duration: 0.4,
54 | delay: stagger(0.1, { from: lastCompletedItemIndex }),
55 | },
56 | );
57 | } else if (random < 2 / 3) {
58 | // shimmy
59 | animate(
60 | '[data-slot="checkbox"]',
61 | {
62 | x: [0, 2, -2, 0],
63 | filter: ["blur(0px)", "blur(1px)", "blur(0px)"],
64 | },
65 | {
66 | duration: 0.4,
67 | delay: stagger(0.1, { from: lastCompletedItemIndex }),
68 | },
69 | );
70 | } else {
71 | // shake
72 | animate(
73 | '[data-slot="checkbox"]',
74 | {
75 | rotate: [0, 12, -12, 0],
76 | filter: ["blur(0px)", "blur(1px)", "blur(0px)"],
77 | },
78 | {
79 | duration: 1,
80 | delay: stagger(0.2, { from: lastCompletedItemIndex }),
81 | },
82 | );
83 | }
84 | }
85 | }
86 |
87 | return (
88 |
89 |
My day
90 |
91 | {items.map((item) => (
92 |
98 |
105 | handleChange(item.id)}
108 | checked={item.checked}
109 | className="rounded-none transition-colors duration-300"
110 | />
111 |
112 | {item.text}
113 |
114 | ))}
115 |
116 |
117 | );
118 | }
119 |
120 | export default function TodoPage() {
121 | const [status, setStatus] = React.useState("idle");
122 |
123 | React.useEffect(() => {
124 | function handleEscape(e: KeyboardEvent) {
125 | if (e.key === "Escape") {
126 | setStatus("idle");
127 | }
128 | }
129 | window.addEventListener("keydown", handleEscape);
130 | return () => window.removeEventListener("keydown", handleEscape);
131 | }, [setStatus]);
132 |
133 | return (
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | );
142 | }
143 |
--------------------------------------------------------------------------------
/src/app/toggle-theme/interstellar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/toggle-theme/interstellar.jpg
--------------------------------------------------------------------------------
/src/app/toggle-theme/murph.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/app/toggle-theme/murph.jpg
--------------------------------------------------------------------------------
/src/app/tooltip-nav/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | AnimatePresence,
5 | motion,
6 | MotionConfig,
7 | Variants,
8 | type Transition,
9 | } from "framer-motion";
10 | import Image from "next/image";
11 | import Link from "next/link";
12 | import React from "react";
13 | import logoX from "@/assets/x.png";
14 | import logoLinkedIn from "@/assets/linkedin.png";
15 | import logoBehance from "@/assets/behance.png";
16 | import logoDribble from "@/assets/dribble.png";
17 |
18 | const transition: Transition = { type: "spring", bounce: 0.4, duration: 0.3 };
19 |
20 | const Context = React.createContext<{
21 | status: string;
22 | setStatus: React.Dispatch>;
23 | }>({ status: "", setStatus: () => null });
24 |
25 | function InnerContent() {
26 | const ctx = React.useContext(Context);
27 |
28 | const icon: Variants = {
29 | hidden: {
30 | opacity: 0,
31 | y: 10,
32 | translateX: "-50%",
33 | filter: "blur(2px)",
34 | rotate: "0deg",
35 | },
36 | show: (custom: { rotateRight: boolean }) => ({
37 | opacity: 1,
38 | y: 0,
39 | filter: "blur(0px)",
40 | rotate: custom?.rotateRight ? "3deg" : "-3deg",
41 | }),
42 | exit: {
43 | opacity: 0,
44 | y: 10,
45 | filter: "blur(2px)",
46 | rotate: "0deg",
47 | transition: { ...transition, duration: 0.5 },
48 | },
49 | };
50 |
51 | return (
52 |
53 |
ctx.setStatus("x")}
56 | onMouseOut={() => ctx.setStatus("idle")}
57 | className="relative transition-colors duration-300 ease-out hover:!text-[#1f1f1f] group-hover:text-black/30"
58 | >
59 |
60 | {ctx.status === "x" && (
61 |
69 |
70 |
71 | )}
72 |
73 |
x
74 |
75 |
ctx.setStatus("behance")}
78 | onMouseOut={() => ctx.setStatus("idle")}
79 | className="relative transition-colors duration-300 ease-out hover:!text-[#1f1f1f] group-hover:text-black/30"
80 | >
81 |
82 | {ctx.status === "behance" && (
83 |
90 |
91 |
92 | )}
93 |
94 |
behance
95 |
96 |
ctx.setStatus("linkedin")}
99 | onMouseOut={() => ctx.setStatus("idle")}
100 | className="relative transition-colors duration-300 ease-out hover:!text-[#1f1f1f] group-hover:text-black/30"
101 | >
102 |
103 | {ctx.status === "linkedin" && (
104 |
112 |
113 |
114 | )}
115 |
116 |
linkedin
117 |
118 |
ctx.setStatus("dribble")}
121 | onMouseOut={() => ctx.setStatus("idle")}
122 | className="relative transition-colors duration-300 ease-out hover:!text-[#1f1f1f] group-hover:text-black/30"
123 | >
124 |
125 | {ctx.status === "dribble" && (
126 |
133 |
134 |
135 | )}
136 |
137 |
dribble
138 |
139 |
140 | );
141 | }
142 |
143 | export default function HomePage() {
144 | const [status, setStatus] = React.useState("idle");
145 |
146 | React.useEffect(() => {
147 | function handleEscape(e: KeyboardEvent) {
148 | if (e.key === "Escape") {
149 | setStatus("idle");
150 | }
151 | }
152 | window.addEventListener("keydown", handleEscape);
153 | return () => window.removeEventListener("keydown", handleEscape);
154 | }, [setStatus]);
155 |
156 | return (
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | );
165 | }
166 |
--------------------------------------------------------------------------------
/src/app/vinyl/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { MotionConfig } from "framer-motion";
4 | import React from "react";
5 |
6 | export default function HomePage() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/src/assets/azura.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/azura.png
--------------------------------------------------------------------------------
/src/assets/barn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/barn.jpg
--------------------------------------------------------------------------------
/src/assets/beach.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/beach.jpg
--------------------------------------------------------------------------------
/src/assets/behance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/behance.png
--------------------------------------------------------------------------------
/src/assets/bird.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/bird.jpg
--------------------------------------------------------------------------------
/src/assets/dribble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/dribble.png
--------------------------------------------------------------------------------
/src/assets/field.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/field.jpg
--------------------------------------------------------------------------------
/src/assets/fish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/fish.jpg
--------------------------------------------------------------------------------
/src/assets/forest-sky.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/forest-sky.jpg
--------------------------------------------------------------------------------
/src/assets/framer-motion.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/huberman.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/huberman.jpg
--------------------------------------------------------------------------------
/src/assets/i-just-need-daniel.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/i-just-need-daniel.webp
--------------------------------------------------------------------------------
/src/assets/i-just-need.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/i-just-need.png
--------------------------------------------------------------------------------
/src/assets/joe-rogan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/joe-rogan.jpg
--------------------------------------------------------------------------------
/src/assets/linkedin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/linkedin.png
--------------------------------------------------------------------------------
/src/assets/monkey.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/monkey.jpg
--------------------------------------------------------------------------------
/src/assets/moral.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/moral.jpg
--------------------------------------------------------------------------------
/src/assets/orlando.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/orlando.jpg
--------------------------------------------------------------------------------
/src/assets/person.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/person.jpg
--------------------------------------------------------------------------------
/src/assets/playful-inca.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/playful-inca.jpg
--------------------------------------------------------------------------------
/src/assets/snow-board.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/snow-board.jpg
--------------------------------------------------------------------------------
/src/assets/stoic-inca.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/stoic-inca.jpg
--------------------------------------------------------------------------------
/src/assets/tailwind.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/tailwind.jpg
--------------------------------------------------------------------------------
/src/assets/thunder-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/thunder-bg.png
--------------------------------------------------------------------------------
/src/assets/tiger.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/tiger.jpg
--------------------------------------------------------------------------------
/src/assets/uncommon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/uncommon.png
--------------------------------------------------------------------------------
/src/assets/vaun-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/vaun-logo.png
--------------------------------------------------------------------------------
/src/assets/x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vaunblu/lab/91249f26e5eb5274426c1426ed903f83fb05d99c/src/assets/x.png
--------------------------------------------------------------------------------
/src/components/grainy-background.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import { cn } from "@/lib/utils";
5 |
6 | interface GrainyBackgroundProps extends React.HTMLAttributes {
7 | baseColor?: string;
8 | grainOpacity?: number;
9 | grainDensity?: number;
10 | grainContrast?: number;
11 | animate?: boolean;
12 | }
13 |
14 | export function GrainyBackground({
15 | baseColor = "#ffffff",
16 | grainOpacity = 0.12,
17 | grainDensity = 0.9,
18 | grainContrast = 0.7,
19 | animate = false,
20 | className,
21 | children,
22 | ...props
23 | }: GrainyBackgroundProps) {
24 | // Generate a unique ID for the filter
25 | const filterId = React.useId();
26 |
27 | return (
28 |
33 | {/* SVG filter definition */}
34 |
35 |
36 |
43 | {animate && (
44 |
51 | )}
52 |
53 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | {/* Grain overlay */}
74 |
82 |
83 | {/* Content */}
84 |
{children}
85 |
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/src/components/icons.tsx:
--------------------------------------------------------------------------------
1 | export function Italic() {
2 | return (
3 |
9 |
14 |
15 | );
16 | }
17 |
18 | export function Underline() {
19 | return (
20 |
26 |
31 |
32 | );
33 | }
34 |
35 | export function Link() {
36 | return (
37 |
43 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/morph.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { AnimatePresence, motion } from "framer-motion";
4 |
5 | export function Morph(props: { children: string | string[]; id?: string }) {
6 | function generateKeys(text: string) {
7 | const charCount: { [key: string]: number } = {};
8 |
9 | return text.split("").map((char) => {
10 | if (!charCount[char]) {
11 | charCount[char] = 0;
12 | }
13 | const key = `${props.id ?? ""}-${char}-${charCount[char]}`;
14 | charCount[char]++;
15 | return { char, key };
16 | });
17 | }
18 |
19 | const textToDisplay = generateKeys(props.children as string);
20 |
21 | return (
22 |
23 | {textToDisplay.map(({ char, key }) => (
24 |
42 | {char === " " ? "\u00A0" : char}
43 |
44 | ))}
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/sidebar.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import Link from "next/link";
4 | import { usePathname } from "next/navigation";
5 | import { Button } from "@/components/ui/button";
6 | import { ScrollArea } from "@/components/ui/scroll-area";
7 |
8 | const examples = [
9 | "timer",
10 | "transaction-drawer",
11 | "switch",
12 | "animated-list",
13 | "animated-tabs",
14 | "toggle-theme",
15 | "smooth-dropdown",
16 | "todo",
17 | "flashlight",
18 | "shop-claim",
19 | "love-folder",
20 | "tooltip-nav",
21 | "audiobooks",
22 | "folder",
23 | "affirmations",
24 | "album",
25 | "bird",
26 | "carousel",
27 | "cd",
28 | "checkout",
29 | "create-new",
30 | "explore",
31 | "happy-cards",
32 | "love-this",
33 | "magic-button",
34 | "neu",
35 | "northern-lights",
36 | "phone-glow",
37 | "podcasts",
38 | "popcorn",
39 | "slingshot",
40 | "thunder-airdrop",
41 | "thunder-speed",
42 | "timer",
43 | "toast",
44 | "ui-course-form",
45 | "vinyl",
46 | ];
47 |
48 | export function Sidebar() {
49 | const pathname = usePathname();
50 |
51 | return (
52 |
53 |
54 |
55 |
56 | Examples
57 |
58 |
59 | {examples.map((example) => (
60 |
66 |
67 | {example.charAt(0).toUpperCase() + example.slice(1)}
68 |
69 |
70 | ))}
71 |
72 |
73 |
74 |
75 | );
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/ui/badge.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { cva, type VariantProps } from "class-variance-authority";
3 |
4 | import { cn } from "@/lib/utils";
5 |
6 | const badgeVariants = cva(
7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
13 | secondary:
14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15 | destructive:
16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
17 | outline: "text-foreground",
18 | },
19 | },
20 | defaultVariants: {
21 | variant: "default",
22 | },
23 | },
24 | );
25 |
26 | export interface BadgeProps
27 | extends React.HTMLAttributes,
28 | VariantProps {}
29 |
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 | return (
32 |
33 | );
34 | }
35 |
36 | export { Badge, badgeVariants };
37 |
--------------------------------------------------------------------------------
/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Slot } from "@radix-ui/react-slot";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default: "bg-primary text-primary-foreground hover:bg-primary/90",
13 | destructive:
14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15 | outline:
16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
17 | secondary:
18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19 | ghost: "hover:bg-accent hover:text-accent-foreground",
20 | link: "text-primary underline-offset-4 hover:underline",
21 | },
22 | size: {
23 | default: "h-10 px-4 py-2",
24 | sm: "h-9 rounded-md px-3",
25 | lg: "h-11 rounded-md px-8",
26 | icon: "h-10 w-10",
27 | },
28 | },
29 | defaultVariants: {
30 | variant: "default",
31 | size: "default",
32 | },
33 | },
34 | );
35 |
36 | export interface ButtonProps
37 | extends React.ButtonHTMLAttributes,
38 | VariantProps {
39 | asChild?: boolean;
40 | }
41 |
42 | const Button = React.forwardRef(
43 | ({ className, variant, size, asChild = false, ...props }, ref) => {
44 | const Comp = asChild ? Slot : "button";
45 | return (
46 |
51 | );
52 | },
53 | );
54 | Button.displayName = "Button";
55 |
56 | export { Button, buttonVariants };
57 |
--------------------------------------------------------------------------------
/src/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
5 | import { Check } from "lucide-react";
6 |
7 | import { cn } from "@/lib/utils";
8 |
9 | const Checkbox = React.forwardRef<
10 | React.ElementRef,
11 | React.ComponentPropsWithoutRef
12 | >(({ className, ...props }, ref) => (
13 |
21 |
24 |
25 |
26 |
27 | ));
28 | Checkbox.displayName = CheckboxPrimitive.Root.displayName;
29 |
30 | export { Checkbox };
31 |
--------------------------------------------------------------------------------
/src/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as DialogPrimitive from "@radix-ui/react-dialog"
5 | import { X } from "lucide-react"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Dialog = DialogPrimitive.Root
10 |
11 | const DialogTrigger = DialogPrimitive.Trigger
12 |
13 | const DialogPortal = DialogPrimitive.Portal
14 |
15 | const DialogClose = DialogPrimitive.Close
16 |
17 | const DialogOverlay = React.forwardRef<
18 | React.ElementRef,
19 | React.ComponentPropsWithoutRef
20 | >(({ className, ...props }, ref) => (
21 |
29 | ))
30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31 |
32 | const DialogContent = React.forwardRef<
33 | React.ElementRef,
34 | React.ComponentPropsWithoutRef
35 | >(({ className, children, ...props }, ref) => (
36 |
37 |
38 |
46 | {children}
47 |
48 |
49 | Close
50 |
51 |
52 |
53 | ))
54 | DialogContent.displayName = DialogPrimitive.Content.displayName
55 |
56 | const DialogHeader = ({
57 | className,
58 | ...props
59 | }: React.HTMLAttributes) => (
60 |
67 | )
68 | DialogHeader.displayName = "DialogHeader"
69 |
70 | const DialogFooter = ({
71 | className,
72 | ...props
73 | }: React.HTMLAttributes) => (
74 |
81 | )
82 | DialogFooter.displayName = "DialogFooter"
83 |
84 | const DialogTitle = React.forwardRef<
85 | React.ElementRef,
86 | React.ComponentPropsWithoutRef
87 | >(({ className, ...props }, ref) => (
88 |
96 | ))
97 | DialogTitle.displayName = DialogPrimitive.Title.displayName
98 |
99 | const DialogDescription = React.forwardRef<
100 | React.ElementRef,
101 | React.ComponentPropsWithoutRef
102 | >(({ className, ...props }, ref) => (
103 |
108 | ))
109 | DialogDescription.displayName = DialogPrimitive.Description.displayName
110 |
111 | export {
112 | Dialog,
113 | DialogPortal,
114 | DialogOverlay,
115 | DialogClose,
116 | DialogTrigger,
117 | DialogContent,
118 | DialogHeader,
119 | DialogFooter,
120 | DialogTitle,
121 | DialogDescription,
122 | }
123 |
--------------------------------------------------------------------------------
/src/components/ui/drawer.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import { Drawer as DrawerPrimitive } from "vaul";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | const Drawer = ({
9 | shouldScaleBackground = true,
10 | ...props
11 | }: React.ComponentProps) => (
12 |
16 | );
17 | Drawer.displayName = "Drawer";
18 |
19 | const DrawerTrigger = DrawerPrimitive.Trigger;
20 |
21 | const DrawerPortal = DrawerPrimitive.Portal;
22 |
23 | const DrawerClose = DrawerPrimitive.Close;
24 |
25 | const DrawerOverlay = React.forwardRef<
26 | React.ElementRef,
27 | React.ComponentPropsWithoutRef
28 | >(({ className, ...props }, ref) => (
29 |
34 | ));
35 | DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
36 |
37 | const DrawerContent = React.forwardRef<
38 | React.ElementRef,
39 | React.ComponentPropsWithoutRef
40 | >(({ className, children, ...props }, ref) => (
41 |
49 | {/*
*/}
50 | {children}
51 |
52 | ));
53 | DrawerContent.displayName = "DrawerContent";
54 |
55 | const DrawerHeader = ({
56 | className,
57 | ...props
58 | }: React.HTMLAttributes) => (
59 |
63 | );
64 | DrawerHeader.displayName = "DrawerHeader";
65 |
66 | const DrawerFooter = ({
67 | className,
68 | ...props
69 | }: React.HTMLAttributes) => (
70 |
74 | );
75 | DrawerFooter.displayName = "DrawerFooter";
76 |
77 | const DrawerTitle = React.forwardRef<
78 | React.ElementRef,
79 | React.ComponentPropsWithoutRef
80 | >(({ className, ...props }, ref) => (
81 |
89 | ));
90 | DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
91 |
92 | const DrawerDescription = React.forwardRef<
93 | React.ElementRef,
94 | React.ComponentPropsWithoutRef
95 | >(({ className, ...props }, ref) => (
96 |
101 | ));
102 | DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
103 |
104 | export {
105 | Drawer,
106 | DrawerPortal,
107 | DrawerOverlay,
108 | DrawerTrigger,
109 | DrawerClose,
110 | DrawerContent,
111 | DrawerHeader,
112 | DrawerFooter,
113 | DrawerTitle,
114 | DrawerDescription,
115 | };
116 |
--------------------------------------------------------------------------------
/src/components/ui/popover.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as PopoverPrimitive from "@radix-ui/react-popover"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Popover = PopoverPrimitive.Root
9 |
10 | const PopoverTrigger = PopoverPrimitive.Trigger
11 |
12 | const PopoverContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
16 |
17 |
27 |
28 | ))
29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName
30 |
31 | export { Popover, PopoverTrigger, PopoverContent }
32 |
--------------------------------------------------------------------------------
/src/components/ui/progress.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as ProgressPrimitive from "@radix-ui/react-progress"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Progress = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, value, ...props }, ref) => (
12 |
20 |
24 |
25 | ))
26 | Progress.displayName = ProgressPrimitive.Root.displayName
27 |
28 | export { Progress }
29 |
--------------------------------------------------------------------------------
/src/components/ui/scroll-area.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const ScrollArea = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, children, ...props }, ref) => (
12 |
17 |
18 | {children}
19 |
20 |
21 |
22 |
23 | ))
24 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
25 |
26 | const ScrollBar = React.forwardRef<
27 | React.ElementRef,
28 | React.ComponentPropsWithoutRef
29 | >(({ className, orientation = "vertical", ...props }, ref) => (
30 |
43 |
44 |
45 | ))
46 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
47 |
48 | export { ScrollArea, ScrollBar }
49 |
--------------------------------------------------------------------------------
/src/components/ui/switch.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as SwitchPrimitives from "@radix-ui/react-switch";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | const Switch = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 |
25 |
26 | ));
27 | Switch.displayName = SwitchPrimitives.Root.displayName;
28 |
29 | export { Switch };
30 |
--------------------------------------------------------------------------------
/src/hooks/use-media-query.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export function useMediaQuery(query: string) {
4 | const [value, setValue] = React.useState(false);
5 |
6 | React.useEffect(() => {
7 | function onChange(event: MediaQueryListEvent) {
8 | setValue(event.matches);
9 | }
10 |
11 | const result = matchMedia(query);
12 | result.addEventListener("change", onChange);
13 | setValue(result.matches);
14 |
15 | return () => result.removeEventListener("change", onChange);
16 | }, [query]);
17 |
18 | return value;
19 | }
20 |
--------------------------------------------------------------------------------
/src/hooks/use-mouse-position.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export function useMousePosition() {
4 | const [mousePosition, setMousePosition] = React.useState({
5 | x: 0,
6 | y: 0,
7 | });
8 |
9 | const updateMousePosition = (ev: MouseEvent) => {
10 | setMousePosition({ x: ev.clientX, y: ev.clientY });
11 | };
12 |
13 | React.useEffect(() => {
14 | window.addEventListener("mousemove", updateMousePosition);
15 | return () => window.removeEventListener("mousemove", updateMousePosition);
16 | }, []);
17 |
18 | return mousePosition;
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 | import defaultTheme from "tailwindcss/defaultTheme";
3 |
4 | const config = {
5 | darkMode: ["class"],
6 | content: [
7 | "./pages/**/*.{ts,tsx}",
8 | "./components/**/*.{ts,tsx}",
9 | "./app/**/*.{ts,tsx}",
10 | "./src/**/*.{ts,tsx}",
11 | ],
12 | prefix: "",
13 | theme: {
14 | container: {
15 | center: true,
16 | padding: "2rem",
17 | screens: {
18 | "2xl": "1400px",
19 | },
20 | },
21 | extend: {
22 | fontFamily: {
23 | sans: ["var(--font-geist-sans)", ...defaultTheme.fontFamily.sans],
24 | serif: ["var(--font-eb-garamond)", ...defaultTheme.fontFamily.serif],
25 | mono: ["var(--font-geist-mono)", ...defaultTheme.fontFamily.mono],
26 | display: [
27 | "var(--font-dancing-script)",
28 | ...defaultTheme.fontFamily.sans,
29 | ],
30 | },
31 | backgroundImage: {
32 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
33 | "border-gradient":
34 | "linear-gradient(to bottom, black var(--progress), transparent var(--progress))",
35 | },
36 | colors: {
37 | border: "hsl(var(--border))",
38 | input: "hsl(var(--input))",
39 | ring: "hsl(var(--ring))",
40 | background: "hsl(var(--background))",
41 | foreground: "hsl(var(--foreground))",
42 | primary: {
43 | DEFAULT: "hsl(var(--primary))",
44 | foreground: "hsl(var(--primary-foreground))",
45 | },
46 | secondary: {
47 | DEFAULT: "hsl(var(--secondary))",
48 | foreground: "hsl(var(--secondary-foreground))",
49 | },
50 | destructive: {
51 | DEFAULT: "hsl(var(--destructive))",
52 | foreground: "hsl(var(--destructive-foreground))",
53 | },
54 | muted: {
55 | DEFAULT: "hsl(var(--muted))",
56 | foreground: "hsl(var(--muted-foreground))",
57 | },
58 | accent: {
59 | DEFAULT: "hsl(var(--accent))",
60 | foreground: "hsl(var(--accent-foreground))",
61 | },
62 | popover: {
63 | DEFAULT: "hsl(var(--popover))",
64 | foreground: "hsl(var(--popover-foreground))",
65 | },
66 | card: {
67 | DEFAULT: "hsl(var(--card))",
68 | foreground: "hsl(var(--card-foreground))",
69 | },
70 | },
71 | boxShadow: {
72 | mixed: "var(--shadow-mixed)",
73 | },
74 | borderRadius: {
75 | lg: "var(--radius)",
76 | md: "calc(var(--radius) - 2px)",
77 | sm: "calc(var(--radius) - 4px)",
78 | },
79 | keyframes: {
80 | "accordion-down": {
81 | from: { height: "0" },
82 | to: { height: "var(--radix-accordion-content-height)" },
83 | },
84 | "accordion-up": {
85 | from: { height: "var(--radix-accordion-content-height)" },
86 | to: { height: "0" },
87 | },
88 | borderTimer: {
89 | "0%": { clipPath: "inset(0 0 0 0)" },
90 | "100%": { clipPath: "inset(0 0 100% 0)" },
91 | },
92 | },
93 | animation: {
94 | "accordion-down": "accordion-down 0.2s ease-out",
95 | "accordion-up": "accordion-up 0.2s ease-out",
96 | "border-timer": "borderTimer var(--duration) linear forwards",
97 | },
98 | },
99 | },
100 | plugins: [require("tailwindcss-animate")],
101 | } satisfies Config;
102 |
103 | export default config;
104 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./src/*"]
22 | }
23 | },
24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25 | "exclude": ["node_modules"]
26 | }
27 |
--------------------------------------------------------------------------------