From 1f86f4a77e8de90d54f454b9229530c133ddca35 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Tue, 1 Jul 2025 19:24:01 +0200 Subject: [PATCH 1/5] vibecode a new homepage structure --- app/home/comments-section.tsx | 40 +++++++++++++++ app/home/donations-section.tsx | 89 ++++++++++++++++++++++++++++++++++ app/home/loading.tsx | 29 +++++++++++ app/home/page.tsx | 84 ++++++++++++++++++++++++++++++++ app/home/projects-section.tsx | 30 ++++++++++++ db/home-cached.ts | 72 +++++++++++++++++++++++++++ 6 files changed, 344 insertions(+) create mode 100644 app/home/comments-section.tsx create mode 100644 app/home/donations-section.tsx create mode 100644 app/home/loading.tsx create mode 100644 app/home/page.tsx create mode 100644 app/home/projects-section.tsx create mode 100644 db/home-cached.ts diff --git a/app/home/comments-section.tsx b/app/home/comments-section.tsx new file mode 100644 index 00000000..e2664607 --- /dev/null +++ b/app/home/comments-section.tsx @@ -0,0 +1,40 @@ +'use client' + +import { Col } from '@/components/layout/col' +import { Comment } from '@/components/comment' +import { FullComment } from '@/db/comment' + +export function CommentsSection({ + comments, + userId, +}: { + comments: FullComment[] + userId?: string +}) { + return ( +
+
+

Recent Comments

+ + View all → + +
+ + {comments.map((comment) => ( + + ))} + +
+ ) +} diff --git a/app/home/donations-section.tsx b/app/home/donations-section.tsx new file mode 100644 index 00000000..938831df --- /dev/null +++ b/app/home/donations-section.tsx @@ -0,0 +1,89 @@ +import { Col } from '@/components/layout/col' +import { Card } from '@/components/layout/card' +import { Row } from '@/components/layout/row' +import { Tag } from '@/components/tags' +import { UserAvatarAndBadge } from '@/components/user-link' +import { FullTxn } from '@/db/txn' +import { FullBid } from '@/db/bid' +import { formatDistanceToNow } from 'date-fns' +import Link from 'next/link' + +export function DonationsSection({ + donations, + bids, +}: { + donations: FullTxn[] + bids: FullBid[] +}) { + // Combine and sort donations and bids by date + const combinedItems = [ + ...donations.map((txn) => ({ + type: 'donation' as const, + item: txn, + })), + ...bids.map((bid) => ({ type: 'bid' as const, item: bid })), + ].sort((a, b) => { + return ( + new Date(b.item.created_at).getTime() - + new Date(a.item.created_at).getTime() + ) + }) + + return ( +
+
+

Recent Activity

+ + View all → + +
+ + + {combinedItems.map(({ type, item }) => ( + + + + + + + + + ))} + +
+ ) +} + +function DonationItem(props: { + type: 'donation' | 'bid' + item: FullTxn | FullBid +}) { + const { type, item } = props + return ( +
+ + {item.profiles && } + + +
+ + ${Math.round(item.amount)} + +
+
+ + + {formatDistanceToNow(new Date(item.created_at), { + addSuffix: true, + })} + + +
+ ) +} diff --git a/app/home/loading.tsx b/app/home/loading.tsx new file mode 100644 index 00000000..36a12b72 --- /dev/null +++ b/app/home/loading.tsx @@ -0,0 +1,29 @@ +import { Col } from '@/components/layout/col' + +export default function HomeLoading() { + return ( + +
+
+
+
+ + {[...Array(3)].map((_, i) => ( +
+
+
+
+
+
+
+
+ {[...Array(3)].map((_, j) => ( +
+ ))} +
+
+
+ ))} + + ) +} diff --git a/app/home/page.tsx b/app/home/page.tsx new file mode 100644 index 00000000..8c1dffbe --- /dev/null +++ b/app/home/page.tsx @@ -0,0 +1,84 @@ +import { Suspense } from 'react' +import { Metadata } from 'next' +import { createServerSupabaseClient } from '@/db/supabase-server' +import { getUser } from '@/db/profile' +import { Col } from '@/components/layout/col' +import { ProjectsSection } from './projects-section' +import { CommentsSection } from './comments-section' +import { DonationsSection } from './donations-section' +import { + getCachedHotProjects, + getCachedRecentComments, + getCachedRecentDonations, + getCachedRecentBids, + getCachedCauses, +} from '@/db/home-cached' + +export const metadata: Metadata = { + title: 'Home - Manifund', + description: 'Discover and support impactful projects on Manifund', +} + +export default async function HomePage() { + const supabase = await createServerSupabaseClient() + const user = await getUser(supabase) + + return ( + + {/* Use Suspense boundaries for progressive loading */} + }> + + + + }> + + + + }> + + + + ) +} + +// Async components for each section +async function AsyncProjectsSection() { + const [projects, causesList] = await Promise.all([ + getCachedHotProjects(), + getCachedCauses(), + ]) + + return +} + +async function AsyncCommentsSection({ userId }: { userId?: string }) { + const comments = await getCachedRecentComments() + return +} + +async function AsyncDonationsSection() { + const [donations, bids] = await Promise.all([ + getCachedRecentDonations(), + getCachedRecentBids(), + ]) + + return +} + +function SectionSkeleton({ title }: { title: string }) { + return ( +
+
+

{title}

+
+
+
+
+ {[...Array(3)].map((_, i) => ( +
+ ))} +
+
+
+ ) +} diff --git a/app/home/projects-section.tsx b/app/home/projects-section.tsx new file mode 100644 index 00000000..90c4faa3 --- /dev/null +++ b/app/home/projects-section.tsx @@ -0,0 +1,30 @@ +import { Col } from '@/components/layout/col' +import { ProjectsDisplay } from '@/components/projects-display' +import { FullProject } from '@/db/project' +import { SimpleCause } from '@/db/cause' + +export function ProjectsSection({ + projects, + causesList, +}: { + projects: FullProject[] + causesList: SimpleCause[] +}) { + return ( +
+ + +
+ ) +} diff --git a/db/home-cached.ts b/db/home-cached.ts new file mode 100644 index 00000000..dcedaa20 --- /dev/null +++ b/db/home-cached.ts @@ -0,0 +1,72 @@ +import { unstable_cache } from 'next/cache' +import { createPublicSupabaseClient } from './supabase-server' +import { getHotProjects } from './project-hot' +import { getRecentFullComments } from './comment' +import { getRecentFullTxns } from './txn' +import { getRecentFullBids } from './bid' +import { listSimpleCauses } from './cause' + +// Cache hot projects for 1 hour +export const getCachedHotProjects = unstable_cache( + async () => { + const supabase = createPublicSupabaseClient() + return await getHotProjects(supabase, 16) + }, + ['home-hot-projects'], + { + revalidate: 3600, // 1 hour + tags: ['home-hot-projects'], + } +) + +// Cache recent comments for 5 minutes +export const getCachedRecentComments = unstable_cache( + async () => { + const supabase = createPublicSupabaseClient() + return await getRecentFullComments(supabase, 10, 0) + }, + ['home-recent-comments'], + { + revalidate: 300, // 5 minutes + tags: ['home-recent-comments'], + } +) + +// Cache recent donations for 5 minutes +export const getCachedRecentDonations = unstable_cache( + async () => { + const supabase = createPublicSupabaseClient() + return await getRecentFullTxns(supabase, 10, 0) + }, + ['home-recent-donations'], + { + revalidate: 300, // 5 minutes + tags: ['home-recent-donations'], + } +) + +// Cache recent bids for 5 minutes +export const getCachedRecentBids = unstable_cache( + async () => { + const supabase = createPublicSupabaseClient() + return await getRecentFullBids(supabase, 10, 0) + }, + ['home-recent-bids'], + { + revalidate: 300, // 5 minutes + tags: ['home-recent-bids'], + } +) + +// Cache causes list for 1 hour +export const getCachedCauses = unstable_cache( + async () => { + const supabase = createPublicSupabaseClient() + return await listSimpleCauses(supabase) + }, + ['home-causes'], + { + revalidate: 3600, // 1 hour + tags: ['home-causes'], + } +) From 1189812babda27f2fbffb5d8bac0f008f4822ace Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Tue, 1 Jul 2025 19:34:23 +0200 Subject: [PATCH 2/5] Use masonic masonry for projects --- bun.lock | 27 +++++++++++++++++++++++++++ components/project-group.tsx | 24 +++++++++++++++--------- package.json | 1 + 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/bun.lock b/bun.lock index 6c13328d..a42717b9 100644 --- a/bun.lock +++ b/bun.lock @@ -44,6 +44,7 @@ "es-toolkit": "^1.39.3", "eslint": "^8.40.0", "eslint-config-next": "^14.0.4", + "masonic": "^4.1.0", "next": "14.2.5", "node-html-markdown": "^1.3.0", "openai": "^5.0.1", @@ -166,6 +167,14 @@ "@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], + "@essentials/memoize-one": ["@essentials/memoize-one@1.1.0", "", {}, "sha512-HMkuIkKNe0EWSUpZhlaq9+5Yp47YhrMhxLMnXTRnEyE5N4xKLspAvMGjUFdi794VnEF1EcOZFS8rdROeujrgag=="], + + "@essentials/one-key-map": ["@essentials/one-key-map@1.2.0", "", {}, "sha512-C2H7zHVcsoipDv4VKY5uUcv5ilsK+uEgEj+WeOdN5oz/Qj1/OZIzCdle90gDzj0xnGQrmZ9qDujwD7AkBb5k9A=="], + + "@essentials/raf": ["@essentials/raf@1.2.0", "", {}, "sha512-AWJvpprE2o7ATMb7HBYMVUVmPJBCt2wZp2rY7d+rAcNSMvzLbDepy9KFeqqrPZh+s9aIpbw1LgmuAW7kuRFgrQ=="], + + "@essentials/request-timeout": ["@essentials/request-timeout@1.3.0", "", { "dependencies": { "@essentials/raf": "^1.2.0" } }, "sha512-lKZPhKScNFnR1MBnk4+sxshk46fpvdN+Uh1LlKWFO5g1ocuz4EcknNIL7tm/rsCAs/+xMWiBTwbDUvm+pDNlXw=="], + "@faker-js/faker": ["@faker-js/faker@8.0.2", "", {}, "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A=="], "@floating-ui/core": ["@floating-ui/core@1.7.1", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw=="], @@ -268,6 +277,20 @@ "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + "@react-hook/debounce": ["@react-hook/debounce@3.0.0", "", { "dependencies": { "@react-hook/latest": "^1.0.2" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag=="], + + "@react-hook/event": ["@react-hook/event@1.2.6", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q=="], + + "@react-hook/latest": ["@react-hook/latest@1.0.3", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg=="], + + "@react-hook/passive-layout-effect": ["@react-hook/passive-layout-effect@1.2.1", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg=="], + + "@react-hook/throttle": ["@react-hook/throttle@2.2.0", "", { "dependencies": { "@react-hook/latest": "^1.0.2" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg=="], + + "@react-hook/window-scroll": ["@react-hook/window-scroll@1.3.0", "", { "dependencies": { "@react-hook/event": "^1.2.1", "@react-hook/throttle": "^2.2.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-LdYnCL22pFI+LTs85Fi2OQHSKWkzIuHFgv8lA+wwuaPxLOEhWR5bzJ21iygUH9X4meeLVRZKEbfpYi3OWWD4GQ=="], + + "@react-hook/window-size": ["@react-hook/window-size@3.1.1", "", { "dependencies": { "@react-hook/debounce": "^3.0.0", "@react-hook/event": "^1.2.1", "@react-hook/throttle": "^2.2.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g=="], + "@remirror/core-constants": ["@remirror/core-constants@3.0.0", "", {}, "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg=="], "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], @@ -1248,6 +1271,8 @@ "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], + "masonic": ["masonic@4.1.0", "", { "dependencies": { "@essentials/memoize-one": "^1.1.0", "@essentials/one-key-map": "^1.2.0", "@essentials/request-timeout": "^1.3.0", "@react-hook/event": "^1.2.6", "@react-hook/latest": "^1.0.3", "@react-hook/passive-layout-effect": "^1.2.1", "@react-hook/throttle": "^2.2.0", "@react-hook/window-scroll": "^1.3.0", "@react-hook/window-size": "^3.1.1", "raf-schd": "^4.0.3", "trie-memoize": "^1.2.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-3RNbAG5qLve7qNtGp1UM/u7vI39jO73ZFHDBAg3xl8AVh7A6Ikx7I7mBeC0NY0h1r1jJn2Wqeol1QMa09MQbyQ=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "md5-file": ["md5-file@5.0.0", "", { "bin": { "md5-file": "cli.js" } }, "sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw=="], @@ -1788,6 +1813,8 @@ "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "trie-memoize": ["trie-memoize@1.2.0", "", {}, "sha512-hEDLVEP1FCgaRtt0oZDJdz2lK9uK7WlB7ASswt9U9cqruSNueVigtRGxI97hevKlViqhAcRgNgzuY/m8FCCMcg=="], + "ts-gems": ["ts-gems@3.11.3", "", {}, "sha512-zEAkPUvP9L7f6SmzXq3mtKnRr6nbWt2vMdGl2NO0b1stHFFtKcmNxZKLHyv5889gOp3InI4ki2WaZAtz85OJBg=="], "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], diff --git a/components/project-group.tsx b/components/project-group.tsx index bac70c5c..80670be6 100644 --- a/components/project-group.tsx +++ b/components/project-group.tsx @@ -1,6 +1,7 @@ 'use client' import { FullProject } from '@/db/project' import { ProjectCard } from '@/components/project-card' +import { Masonry } from 'masonic' export function ProjectGroup(props: { projects: FullProject[] @@ -8,14 +9,19 @@ export function ProjectGroup(props: { }) { const { projects, prices } = props return ( -
- {projects.map((project) => ( - - ))} -
+ ( +
+ +
+ )} + /> ) } diff --git a/package.json b/package.json index dd365497..754251a0 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "es-toolkit": "^1.39.3", "eslint": "^8.40.0", "eslint-config-next": "^14.0.4", + "masonic": "^4.1.0", "next": "14.2.5", "node-html-markdown": "^1.3.0", "openai": "^5.0.1", From 4e9167f749df3d5bf46d8ea4431fb565ccb7a94c Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Tue, 1 Jul 2025 19:39:57 +0200 Subject: [PATCH 3/5] Replace with react-plock --- bun.lock | 30 +++--------------------------- components/project-group.tsx | 22 +++++++++++----------- package.json | 2 +- 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index a42717b9..3caab1d4 100644 --- a/bun.lock +++ b/bun.lock @@ -44,7 +44,6 @@ "es-toolkit": "^1.39.3", "eslint": "^8.40.0", "eslint-config-next": "^14.0.4", - "masonic": "^4.1.0", "next": "14.2.5", "node-html-markdown": "^1.3.0", "openai": "^5.0.1", @@ -56,6 +55,7 @@ "react-dom": "^19.0.0", "react-hot-toast": "^2.4.1", "react-icons": "^4.10.1", + "react-plock": "^3.5.1", "react-uuid": "^2.0.0", "recharts": "^2.8.0", "server-only": "^0.0.1", @@ -167,14 +167,6 @@ "@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], - "@essentials/memoize-one": ["@essentials/memoize-one@1.1.0", "", {}, "sha512-HMkuIkKNe0EWSUpZhlaq9+5Yp47YhrMhxLMnXTRnEyE5N4xKLspAvMGjUFdi794VnEF1EcOZFS8rdROeujrgag=="], - - "@essentials/one-key-map": ["@essentials/one-key-map@1.2.0", "", {}, "sha512-C2H7zHVcsoipDv4VKY5uUcv5ilsK+uEgEj+WeOdN5oz/Qj1/OZIzCdle90gDzj0xnGQrmZ9qDujwD7AkBb5k9A=="], - - "@essentials/raf": ["@essentials/raf@1.2.0", "", {}, "sha512-AWJvpprE2o7ATMb7HBYMVUVmPJBCt2wZp2rY7d+rAcNSMvzLbDepy9KFeqqrPZh+s9aIpbw1LgmuAW7kuRFgrQ=="], - - "@essentials/request-timeout": ["@essentials/request-timeout@1.3.0", "", { "dependencies": { "@essentials/raf": "^1.2.0" } }, "sha512-lKZPhKScNFnR1MBnk4+sxshk46fpvdN+Uh1LlKWFO5g1ocuz4EcknNIL7tm/rsCAs/+xMWiBTwbDUvm+pDNlXw=="], - "@faker-js/faker": ["@faker-js/faker@8.0.2", "", {}, "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A=="], "@floating-ui/core": ["@floating-ui/core@1.7.1", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw=="], @@ -277,20 +269,6 @@ "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], - "@react-hook/debounce": ["@react-hook/debounce@3.0.0", "", { "dependencies": { "@react-hook/latest": "^1.0.2" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag=="], - - "@react-hook/event": ["@react-hook/event@1.2.6", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q=="], - - "@react-hook/latest": ["@react-hook/latest@1.0.3", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg=="], - - "@react-hook/passive-layout-effect": ["@react-hook/passive-layout-effect@1.2.1", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg=="], - - "@react-hook/throttle": ["@react-hook/throttle@2.2.0", "", { "dependencies": { "@react-hook/latest": "^1.0.2" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg=="], - - "@react-hook/window-scroll": ["@react-hook/window-scroll@1.3.0", "", { "dependencies": { "@react-hook/event": "^1.2.1", "@react-hook/throttle": "^2.2.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-LdYnCL22pFI+LTs85Fi2OQHSKWkzIuHFgv8lA+wwuaPxLOEhWR5bzJ21iygUH9X4meeLVRZKEbfpYi3OWWD4GQ=="], - - "@react-hook/window-size": ["@react-hook/window-size@3.1.1", "", { "dependencies": { "@react-hook/debounce": "^3.0.0", "@react-hook/event": "^1.2.1", "@react-hook/throttle": "^2.2.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g=="], - "@remirror/core-constants": ["@remirror/core-constants@3.0.0", "", {}, "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg=="], "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], @@ -1271,8 +1249,6 @@ "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], - "masonic": ["masonic@4.1.0", "", { "dependencies": { "@essentials/memoize-one": "^1.1.0", "@essentials/one-key-map": "^1.2.0", "@essentials/request-timeout": "^1.3.0", "@react-hook/event": "^1.2.6", "@react-hook/latest": "^1.0.3", "@react-hook/passive-layout-effect": "^1.2.1", "@react-hook/throttle": "^2.2.0", "@react-hook/window-scroll": "^1.3.0", "@react-hook/window-size": "^3.1.1", "raf-schd": "^4.0.3", "trie-memoize": "^1.2.0" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-3RNbAG5qLve7qNtGp1UM/u7vI39jO73ZFHDBAg3xl8AVh7A6Ikx7I7mBeC0NY0h1r1jJn2Wqeol1QMa09MQbyQ=="], - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "md5-file": ["md5-file@5.0.0", "", { "bin": { "md5-file": "cli.js" } }, "sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw=="], @@ -1597,6 +1573,8 @@ "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + "react-plock": ["react-plock@3.5.1", "", { "peerDependencies": { "react": "^18.2.0 || ^19.0.0" } }, "sha512-uJqiSaib+/EwhNyKB4cb9YdNAlS0tXhr5I35exEbcdTbPM0EaMiSPdzhlH4lmjBCkNwMPs7Xi23PZo7EQ04ndQ=="], + "react-redux": ["react-redux@7.2.9", "", { "dependencies": { "@babel/runtime": "^7.15.4", "@types/react-redux": "^7.1.20", "hoist-non-react-statics": "^3.3.2", "loose-envify": "^1.4.0", "prop-types": "^15.7.2", "react-is": "^17.0.2" }, "peerDependencies": { "react": "^16.8.3 || ^17 || ^18" } }, "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ=="], "react-resize-detector": ["react-resize-detector@7.1.2", "", { "dependencies": { "lodash": "^4.17.21" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw=="], @@ -1813,8 +1791,6 @@ "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "trie-memoize": ["trie-memoize@1.2.0", "", {}, "sha512-hEDLVEP1FCgaRtt0oZDJdz2lK9uK7WlB7ASswt9U9cqruSNueVigtRGxI97hevKlViqhAcRgNgzuY/m8FCCMcg=="], - "ts-gems": ["ts-gems@3.11.3", "", {}, "sha512-zEAkPUvP9L7f6SmzXq3mtKnRr6nbWt2vMdGl2NO0b1stHFFtKcmNxZKLHyv5889gOp3InI4ki2WaZAtz85OJBg=="], "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], diff --git a/components/project-group.tsx b/components/project-group.tsx index 80670be6..64559df6 100644 --- a/components/project-group.tsx +++ b/components/project-group.tsx @@ -1,7 +1,7 @@ 'use client' import { FullProject } from '@/db/project' import { ProjectCard } from '@/components/project-card' -import { Masonry } from 'masonic' +import { Masonry } from 'react-plock' export function ProjectGroup(props: { projects: FullProject[] @@ -11,16 +11,16 @@ export function ProjectGroup(props: { return ( ( -
- -
+ config={{ + columns: 2, + gap: 16, + }} + render={(item, idx) => ( + )} /> ) diff --git a/package.json b/package.json index 754251a0..ada13d70 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "es-toolkit": "^1.39.3", "eslint": "^8.40.0", "eslint-config-next": "^14.0.4", - "masonic": "^4.1.0", "next": "14.2.5", "node-html-markdown": "^1.3.0", "openai": "^5.0.1", @@ -71,6 +70,7 @@ "react-dom": "^19.0.0", "react-hot-toast": "^2.4.1", "react-icons": "^4.10.1", + "react-plock": "^3.5.1", "react-uuid": "^2.0.0", "recharts": "^2.8.0", "server-only": "^0.0.1", From 82bd47a7a412d69dcb868d845c222c188bf19c4d Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Tue, 1 Jul 2025 22:42:28 +0200 Subject: [PATCH 4/5] Fix columns --- components/project-group.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/project-group.tsx b/components/project-group.tsx index 64559df6..dbf01f22 100644 --- a/components/project-group.tsx +++ b/components/project-group.tsx @@ -12,8 +12,9 @@ export function ProjectGroup(props: { ( Date: Tue, 1 Jul 2025 22:42:39 +0200 Subject: [PATCH 5/5] New header --- app/home/comments-section.tsx | 15 +++++++++++---- app/home/donations-section.tsx | 11 ++--------- app/home/projects-section.tsx | 11 ++--------- components/home-header.tsx | 28 ++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 components/home-header.tsx diff --git a/app/home/comments-section.tsx b/app/home/comments-section.tsx index e2664607..c9ed235f 100644 --- a/app/home/comments-section.tsx +++ b/app/home/comments-section.tsx @@ -3,6 +3,7 @@ import { Col } from '@/components/layout/col' import { Comment } from '@/components/comment' import { FullComment } from '@/db/comment' +import { Row } from '@/components/layout/row' export function CommentsSection({ comments, @@ -13,15 +14,21 @@ export function CommentsSection({ }) { return (
-
-

Recent Comments

+
+
+

+ Comments +

+
+
+ View all → -
+ {comments.map((comment) => ( -
-

Recent Activity

- - View all → - -
+ {combinedItems.map(({ type, item }) => ( diff --git a/app/home/projects-section.tsx b/app/home/projects-section.tsx index 90c4faa3..0d3a4e01 100644 --- a/app/home/projects-section.tsx +++ b/app/home/projects-section.tsx @@ -1,7 +1,7 @@ -import { Col } from '@/components/layout/col' import { ProjectsDisplay } from '@/components/projects-display' import { FullProject } from '@/db/project' import { SimpleCause } from '@/db/cause' +import { HomeHeader } from '@/components/home-header' export function ProjectsSection({ projects, @@ -12,14 +12,7 @@ export function ProjectsSection({ }) { return (
- + +
+
+

+ {title} +

+
+
+ + + View all → + + + + ) +}