feat: add EmojiRain component for dynamic emoji effects and enhance About page with founder section

This commit is contained in:
Pattadon 2024-11-21 15:26:47 +07:00
parent 502f14d161
commit e2d02c2c23
6 changed files with 368 additions and 3 deletions

274
package-lock.json generated
View File

@ -41,6 +41,7 @@
"@tanstack/react-query": "^5.59.0",
"@tanstack/react-query-devtools": "^5.59.0",
"@tanstack/react-table": "^8.20.5",
"@tsparticles/confetti": "^3.6.0",
"b2d-ventures": "file:",
"chart.js": "^4.4.6",
"class-variance-authority": "^0.7.0",
@ -4275,6 +4276,279 @@
}
}
},
"node_modules/@tsparticles/basic": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/basic/-/basic-3.6.0.tgz",
"integrity": "sha512-VWSOTCURUFumvSkxm0ol2ZZ5zCJjwppnHKwt1I6TYRQ2PFUBVJsCpiuEHDWvIAGl6/ZQxgrVBBi+J3+J+edMqQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/matteobruni"
},
{
"type": "github",
"url": "https://github.com/sponsors/tsparticles"
},
{
"type": "buymeacoffee",
"url": "https://www.buymeacoffee.com/matteobruni"
}
],
"dependencies": {
"@tsparticles/engine": "^3.6.0",
"@tsparticles/move-base": "^3.6.0",
"@tsparticles/shape-circle": "^3.6.0",
"@tsparticles/updater-color": "^3.6.0",
"@tsparticles/updater-opacity": "^3.6.0",
"@tsparticles/updater-out-modes": "^3.6.0",
"@tsparticles/updater-size": "^3.6.0"
}
},
"node_modules/@tsparticles/confetti": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/confetti/-/confetti-3.6.0.tgz",
"integrity": "sha512-SE1BBictpt3JevaJcvXR6s/hykJniptYw5dY0DrQS3/iKm77g0LB7nc4HMTzLc6N7Ve1fLQBNyQemm7vt5GzWg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/matteobruni"
},
{
"type": "github",
"url": "https://github.com/sponsors/tsparticles"
},
{
"type": "buymeacoffee",
"url": "https://www.buymeacoffee.com/matteobruni"
}
],
"dependencies": {
"@tsparticles/basic": "^3.6.0",
"@tsparticles/engine": "^3.6.0",
"@tsparticles/plugin-emitters": "^3.6.0",
"@tsparticles/plugin-motion": "^3.6.0",
"@tsparticles/shape-cards": "^3.6.0",
"@tsparticles/shape-emoji": "^3.6.0",
"@tsparticles/shape-heart": "^3.6.0",
"@tsparticles/shape-image": "^3.6.0",
"@tsparticles/shape-polygon": "^3.6.0",
"@tsparticles/shape-square": "^3.6.0",
"@tsparticles/shape-star": "^3.6.0",
"@tsparticles/updater-life": "^3.6.0",
"@tsparticles/updater-roll": "^3.6.0",
"@tsparticles/updater-rotate": "^3.6.0",
"@tsparticles/updater-tilt": "^3.6.0",
"@tsparticles/updater-wobble": "^3.6.0"
}
},
"node_modules/@tsparticles/engine": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/engine/-/engine-3.6.0.tgz",
"integrity": "sha512-iDBD0ZTTtoI5WwZkcjAgMVP2oCK2GkNgO7/Eipsfb8ZWKxtD/niGI14ynVQ31sBzp/weARwTxc4BTpbMeQHCGg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/matteobruni"
},
{
"type": "github",
"url": "https://github.com/sponsors/tsparticles"
},
{
"type": "buymeacoffee",
"url": "https://www.buymeacoffee.com/matteobruni"
}
],
"hasInstallScript": true
},
"node_modules/@tsparticles/move-base": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/move-base/-/move-base-3.6.0.tgz",
"integrity": "sha512-g32LGNcTyNekwTJL0UD9pgTImdysRMxiRii7d+KDdzNMjv/OIiWK7Ar069TVtEtmKnXaiVCUmCX4vcTJzflDKA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/plugin-emitters": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/plugin-emitters/-/plugin-emitters-3.6.0.tgz",
"integrity": "sha512-+nzyAPniZJszozKoImMC88IYObujATL5ZmqJlgrx68eaLcwohUmHttWpaC+olMAHcPWx+bLRROSpbu6LSkiu4A==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/plugin-motion": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/plugin-motion/-/plugin-motion-3.6.0.tgz",
"integrity": "sha512-Df4MmDDM4Rpd8/w9FnAI7Y6TeS0c4S7+wg1q4VXPWrSeLH6EhYAPE8WcoTUYRMi/OHPVt45SWpyyH3b8WIFLKA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-cards": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-cards/-/shape-cards-3.6.0.tgz",
"integrity": "sha512-pw8vBCvpk2FiB4WDVDYHI/nyZA/xVt5ddj2S916KygUIOyxZlHNqc/qs5tUMSCm7H2jk2G+w/Eh50rZXQs6YnA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/matteobruni"
},
{
"type": "github",
"url": "https://github.com/sponsors/tsparticles"
},
{
"type": "buymeacoffee",
"url": "https://www.buymeacoffee.com/matteobruni"
}
],
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-circle": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-circle/-/shape-circle-3.6.0.tgz",
"integrity": "sha512-kOnoKMgK72TD5R179PoblVFX1V7Xy63Bhg8zHEowtZo839SkHygmyBFl1U1o1oz3Ff/5dr1is4qZGJD/6HweQg==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-emoji": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-emoji/-/shape-emoji-3.6.0.tgz",
"integrity": "sha512-i3KtxMzlwR7hLipiWjISiGBMCdY+Nx4k2clZsu1LMHS3okpk7yYkO0JkDUIQ8ZPUXQi7M07h42PkY0oyNuc36Q==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-heart": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-heart/-/shape-heart-3.6.0.tgz",
"integrity": "sha512-KJYpDUWc8RHcS9/JBdc+jU1PpB9/95RM9rB34IPsVGIoTod3cBcz94nU153u6oxT5sMFVKsmeramyH61rRxBfQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/matteobruni"
},
{
"type": "github",
"url": "https://github.com/sponsors/tsparticles"
},
{
"type": "buymeacoffee",
"url": "https://www.buymeacoffee.com/matteobruni"
}
],
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-image": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-image/-/shape-image-3.6.0.tgz",
"integrity": "sha512-m1hW7AFjBsD/SJ3CbiH7QKIted6KOxXaNKXnnkBQpRWKPI9XayYB5NeWBhhxCD4vWynaLpGJT/xiba15ih9COA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-polygon": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-polygon/-/shape-polygon-3.6.0.tgz",
"integrity": "sha512-ubxw2XPY3pAphSR2Aq9lOzq60kG09QY0YxAMkxjFp6/3aeLopm9EondIVOb4LsdTUn12thvCtlxuqpt8cjl3Xg==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-square": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-square/-/shape-square-3.6.0.tgz",
"integrity": "sha512-HSkxmRnlk+N67lm5hgctjLWdaEAAd/XAVXoCD0z6Jtn58Yj/UbmvKqN3n+YXmZGO3dOrKKfJy5mpDJoOo/yHKQ==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/shape-star": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/shape-star/-/shape-star-3.6.0.tgz",
"integrity": "sha512-4UOtrqUgcn8isFbeb58r21HBQubmU84W9R/NwU6rKAB+lmYhmLZMmT5pslRDolYgpSBfugncI2CMPmRFqdKicA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-color": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-color/-/updater-color-3.6.0.tgz",
"integrity": "sha512-P0Ub1vuA8B9CU2ocRuHTM44vFsYA1cqOrdl/YehAeNsIA1N31jUdiRUYDIrQKj+9I+XbL4eyPf/P94eJIMCfMw==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-life": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-life/-/updater-life-3.6.0.tgz",
"integrity": "sha512-srpgYazcd9jH2r3po/Y21ZB+E9fN6N+va9KrLlO52scfA+vh5B8v5/em427O+ZeM2FIJHflkOMfEP3a3fxzpEA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-opacity": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-opacity/-/updater-opacity-3.6.0.tgz",
"integrity": "sha512-qlXfEvYrxy/PQwGKkucu5yHA7GEq6cV4SNAyzON1udbwBu3HKeLjUa0xBEyufpZlwnokg45Vtof0C4WrGSgX2w==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-out-modes": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-out-modes/-/updater-out-modes-3.6.0.tgz",
"integrity": "sha512-ohwKYPw8n4rva+Nm7vXRRA7OUMsSF0xvpXX+rrJ28qUoAjaYntDX/jekPbWiUO1u+0yBdYSqgcKHgO6zUMcYdA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-roll": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-roll/-/updater-roll-3.6.0.tgz",
"integrity": "sha512-1yhF+MjqYLnapt+NyPiQLWu/jWlBbVIsz9tOsRiiygcwkoNZI6CV9S0Wh5Fjtqn62iy+Cw8MflbMHFSzXK6iEQ==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-rotate": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-rotate/-/updater-rotate-3.6.0.tgz",
"integrity": "sha512-E9S2mZ6Qr6p8xyMqo6WEj9Ixqi7W5OYppd16SfR/bjgUkcZSVHabhpVyEoBFbhsnJn/6rFfmE6i+RPpza7OhcA==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-size": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-size/-/updater-size-3.6.0.tgz",
"integrity": "sha512-XzDC6F6FNBv4PoG1SgQ7wMQuAhjzRwwZetTR8ayUaCBk2cjhhruT4YaLmMBpSyrzVjRdvZ+FOyljejUkCT8R3g==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-tilt": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-tilt/-/updater-tilt-3.6.0.tgz",
"integrity": "sha512-LzYy25KjV6xt0Nx/J3mJ+ry5Pr9zWkiOuth2d8khLu08OQSMxY2iApZggb0wnqk6+tUxJ0+49nCfiX6RMjDJ/A==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@tsparticles/updater-wobble": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@tsparticles/updater-wobble/-/updater-wobble-3.6.0.tgz",
"integrity": "sha512-eD/DSuuVfG4jo6LTCJTakgwo5iuqdz/yw9ChhaYr15WCTxNt/2iTfld9gtLKVb/09un+dD5OWV9mN0oiqs/2Ow==",
"dependencies": {
"@tsparticles/engine": "^3.6.0"
}
},
"node_modules/@types/acorn": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",

View File

@ -43,6 +43,7 @@
"@tanstack/react-query": "^5.59.0",
"@tanstack/react-query-devtools": "^5.59.0",
"@tanstack/react-table": "^8.20.5",
"@tsparticles/confetti": "^3.6.0",
"b2d-ventures": "file:",
"chart.js": "^4.4.6",
"class-variance-authority": "^0.7.0",

View File

@ -16,6 +16,7 @@ import { isOwnerOfProject } from "./query";
import { UpdateTab } from "./UpdateTab";
import remarkGfm from "remark-gfm";
import Gallery from "@/components/carousel";
import CountUpComponent from "@/components/countUp";
const PHOTO_MATERIAL_ID = 2;
@ -109,7 +110,9 @@ export default async function ProjectDealPage({ params }: { params: { id: number
<div id="stats" className="flex flex-col w-full mt-4">
<div className="pl-5">
<span>
<h1 className="font-semibold text-xl md:text-4xl mt-8">${totalDealAmount}</h1>
<h1 className="font-semibold text-xl md:text-4xl mt-8">
$<CountUpComponent end={totalDealAmount} duration={0.5} />
</h1>
<p className="text-sm md:text-lg">
{toPercentage(totalDealAmount, projectData?.target_investment)}% raised of $
{projectData?.target_investment} max goal
@ -121,7 +124,9 @@ export default async function ProjectDealPage({ params }: { params: { id: number
</span>
<span>
<h1 className="font-semibold text-4xl md:mt-8">
<p className="text-xl md:text-4xl">{dealList.length}</p>
<p className="text-xl md:text-4xl">
<CountUpComponent end={dealList.length} duration={0.5} />
</p>
</h1>
<p className="text-sm md:text-lg">Investors</p>
</span>
@ -130,7 +135,10 @@ export default async function ProjectDealPage({ params }: { params: { id: number
<h1 className="font-semibold text-xl md:text-4xl mt-8 ml-5"></h1>
{projectData?.investment_deadline ? (
<>
<p className="text-xl md:text-4xl">{Math.floor(hourLeft)} hours</p>
<p className="text-xl md:text-4xl">
<CountUpComponent end={Math.floor(hourLeft)} duration={0.5} />
hours
</p>
<p>Left to invest</p>
</>
) : (

View File

@ -87,6 +87,11 @@ export default function About() {
<h1 className="text-gray-500 text-2xl">top investment platforms and entrepreneurial ecosystems. Since then,</h1>
<h1 className="text-gray-500 text-2xl">we have built a team and a network of the top people from</h1>
<h1 className="text-gray-500 text-2xl">the startup, venture capital, and investment worlds.</h1>
<div className="flex flex-col items-center mt-8">
<Separator className="w-full h-1 bg-primary mb-2"></Separator>
<h2 className="text-3xl font-bold text-center text-primary">Meet the Minds Behind the Innovation.</h2>
</div>
<div className="mt-10">
{founderData.map((profile) => {
return (

View File

@ -7,6 +7,7 @@ import { getTopProjects } from "@/lib/data/projectQuery";
import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
import { Suspense } from "react";
import { ProjectSection } from "@/components/ProjectSection";
import EmojiRain from "@/components/banner";
const ProjectsLoader = () => (
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
@ -30,6 +31,8 @@ export default async function Home() {
<div className="relative mx-auto">
{/* Expanded div */}
<div className="flex flex-row bg-slate-100 dark:bg-gray-800">
<EmojiRain />
<div className="container max-w-screen-xl flex flex-col">
<span className="mx-20 px-10 py-10">
<p className="text-4xl font-bold">Explore the world of ventures</p>

74
src/components/banner.tsx Normal file
View File

@ -0,0 +1,74 @@
"use client";
import { useEffect } from "react";
import { Button } from "./ui/button";
export default function EmojiRain() {
useEffect(() => {
// Dynamically load tsparticles
const loadParticles = async () => {
if (typeof window !== "undefined") {
const { tsParticles } = await import("@tsparticles/engine");
const { loadEmojiShape } = await import("@tsparticles/shape-emoji");
// Load the emoji shape
await loadEmojiShape(tsParticles);
}
};
loadParticles();
}, []);
const startEmojiRain = async () => {
if (typeof window !== "undefined") {
const { tsParticles } = await import("@tsparticles/engine");
try {
await tsParticles.load({
id: "tsparticles",
options: {
fullScreen: {
enable: true,
zIndex: 999,
},
background: {
color: "transparent",
},
particles: {
number: { value: 100 },
move: {
direction: "bottom",
enable: true,
speed: 3,
straight: false,
},
shape: {
type: "emoji",
options: {
emoji: {
value: ["🤑", "🪙", "💰", "💴", "💵", "💶", "💷", "💸", "💳", "💹"],
},
},
},
size: {
value: { min: 10, max: 20 },
},
color: {
value: ["#FFD700", "#FFFFFF"],
},
},
},
});
} catch (error) {
console.error("Particles load error:", error);
}
}
};
return (
<div id="tsparticles-container" className="relative w-full">
<Button onClick={startEmojiRain} className="bg-green-500 text-white p-2 rounded">
Start Emoji Rain 🌧
</Button>
</div>
);
}