diff --git a/README.md b/README.md index 4c24c29..b494722 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ bun create better-t-stack@latest pnpm create better-t-stack@latest ``` +## Sponsors + +

+Sponsors +

+ + ## Features - **Zero-config setup** with interactive CLI wizard @@ -61,12 +68,6 @@ bun dev:web Just fork the repository and submit a pull request! -## Sponsors - -

-Sponsors -

- ## Star History diff --git a/apps/cli/README.md b/apps/cli/README.md index aa1fa82..f4668ff 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -21,6 +21,12 @@ pnpm create better-t-stack@latest Follow the prompts to configure your project or use the `--yes` flag for defaults. +## Sponsors + +

+Sponsors +

+ ## Features | Category | Options | @@ -211,9 +217,3 @@ my-better-t-app/ ``` After project creation, you'll receive detailed instructions for next steps and additional setup requirements. - -## Sponsors - -

-Sponsors -

diff --git a/apps/web/public/icon/x.svg b/apps/web/public/icon/x.svg new file mode 100644 index 0000000..9145996 --- /dev/null +++ b/apps/web/public/icon/x.svg @@ -0,0 +1 @@ + diff --git a/apps/web/src/app/(home)/_components/sponsors-section.tsx b/apps/web/src/app/(home)/_components/sponsors-section.tsx index 5173bbc..180abdd 100644 --- a/apps/web/src/app/(home)/_components/sponsors-section.tsx +++ b/apps/web/src/app/(home)/_components/sponsors-section.tsx @@ -4,9 +4,11 @@ import { Github, Globe, Heart, + Star, Terminal, } from "lucide-react"; import Image from "next/image"; +// import Link from "next/link"; import { useEffect, useState } from "react"; import type { Sponsor } from "@/lib/types"; @@ -48,13 +50,22 @@ export default function SponsorsSection() { ); } + const aAmount = getAmount(a); + const bAmount = getAmount(b); + + if (aAmount !== bAmount) { + return bAmount - aAmount; + } + const aIsMonthly = !a.isOneTime; const bIsMonthly = !b.isOneTime; if (aIsMonthly && !bIsMonthly) return -1; if (!aIsMonthly && bIsMonthly) return 1; - return getAmount(b) - getAmount(a); + return ( + new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() + ); }); setSponsors(sortedSponsors); @@ -66,6 +77,34 @@ export default function SponsorsSection() { }); }, []); + const SPECIAL_SPONSOR_THRESHOLD = 100; + + const getSponsorAmount = (sponsor: Sponsor) => { + if (sponsor.monthlyDollars === -1) { + if (sponsor.tierName) { + const match = sponsor.tierName.match(/\$(\d+(?:\.\d+)?)/); + return match ? Number.parseFloat(match[1]) : 0; + } + return 0; + } + + if (!sponsor.isOneTime && sponsor.monthlyDollars > 0) { + return sponsor.monthlyDollars; + } + + if (sponsor.isOneTime && sponsor.tierName) { + const match = sponsor.tierName.match(/\$(\d+(?:\.\d+)?)/); + return match ? Number.parseFloat(match[1]) : 0; + } + + return 0; + }; + + const isSpecialSponsor = (sponsor: Sponsor) => { + const amount = getSponsorAmount(sponsor); + return amount >= SPECIAL_SPONSOR_THRESHOLD; + }; + const currentSponsors = sponsors.filter( (sponsor) => sponsor.monthlyDollars !== -1, ); @@ -73,6 +112,11 @@ export default function SponsorsSection() { (sponsor) => sponsor.monthlyDollars === -1, ); + const specialSponsors = currentSponsors.filter(isSpecialSponsor); + const regularSponsors = currentSponsors.filter( + (sponsor) => !isSpecialSponsor(sponsor), + ); + return (
@@ -133,19 +177,103 @@ export default function SponsorsSection() {
) : (
- {currentSponsors.length > 0 && ( + {specialSponsors.length > 0 && (
- {/*
- - - ACTIVE_SPONSORS.SH - - - ({currentSponsors.length}) - -
*/}
- {currentSponsors.map((entry, index) => { + {specialSponsors.map((entry, index) => { + const since = new Date(entry.createdAt).toLocaleDateString( + undefined, + { year: "numeric", month: "short" }, + ); + const sponsorUrl = + entry.sponsor.websiteUrl || + entry.sponsor.linkUrl || + `https://github.com/${entry.sponsor.login}`; + + return ( +
+
+
+ +
+ SPECIAL + + SINCE {since.toUpperCase()} +
+
+
+
+
+ ); + })} +
+
+ )} + {regularSponsors.length > 0 && ( +
+
+ {regularSponsors.map((entry, index) => { const since = new Date(entry.createdAt).toLocaleDateString( undefined, { year: "numeric", month: "short" }, @@ -160,16 +288,12 @@ export default function SponsorsSection() {
- - {entry.isOneTime ? "ONE-TIME" : "MONTHLY"} - - SINCE {since.toUpperCase()}
-
+
-
+

{entry.sponsor.name || entry.sponsor.login} @@ -267,6 +391,12 @@ export default function SponsorsSection() { undefined, { year: "numeric", month: "short" }, ); + const wasSpecial = isSpecialSponsor(entry); + const sponsorUrl = + entry.sponsor.websiteUrl || + entry.sponsor.linkUrl || + `https://github.com/${entry.sponsor.login}`; + return (
- - ◆ - + {wasSpecial ? ( + + ) : ( + + ◆ + + )}
- PAST - + {wasSpecial && SPECIAL} + {wasSpecial && } SINCE {since.toUpperCase()}
-
+
{entry.sponsor.name
-
+

{entry.sponsor.name || entry.sponsor.login} @@ -323,20 +460,14 @@ export default function SponsorsSection() { {(entry.sponsor.websiteUrl || entry.sponsor.linkUrl) && ( - {( - entry.sponsor.websiteUrl || - entry.sponsor.linkUrl - ) + {sponsorUrl ?.replace(/^https?:\/\//, "") ?.replace(/\/$/, "")} diff --git a/apps/web/src/app/(home)/_components/testimonials.tsx b/apps/web/src/app/(home)/_components/testimonials.tsx index 7170933..049b95f 100644 --- a/apps/web/src/app/(home)/_components/testimonials.tsx +++ b/apps/web/src/app/(home)/_components/testimonials.tsx @@ -13,19 +13,25 @@ const TWEET_IDS = [ "1931029815047455149", "1933149770639614324", "1937599252173128103", + "1947357370302304559", "1930511724702285885", + "1945591420657532994", "1945204056063913989", "1912836377365905496", + "1947973299805561005", "1907817662215757853", "1933216760896934060", "1942558041704182158", + "1947636576118304881", "1937383786637094958", "1931709370003583004", "1929147326955704662", + "1948050877454938549", "1904228496144269699", "1930257410259616057", "1937258706279817570", "1917815700980391964", + "1947812547551498466", "1928317790588403953", "1917640304758514093", "1907831059275735353", @@ -74,8 +80,8 @@ const TWEET_IDS = [ ]; export const components: TwitterComponents = { - AvatarImg: (props) => , - MediaImg: (props) => , + AvatarImg: (props) => {props.alt}, + MediaImg: (props) => {props.alt}, }; export default function Testimonials() { diff --git a/apps/web/src/app/layout.config.tsx b/apps/web/src/app/layout.config.tsx index 5fa86f4..08b06b0 100644 --- a/apps/web/src/app/layout.config.tsx +++ b/apps/web/src/app/layout.config.tsx @@ -2,6 +2,7 @@ import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; import Image from "next/image"; import discordLogo from "@/public/icon/discord.svg"; import npmLogo from "@/public/icon/npm.svg"; +import xLogo from "@/public/icon/x.svg"; import mainLogo from "@/public/logo.svg"; export const logo = ( @@ -20,7 +21,6 @@ export const baseOptions: BaseLayoutProps = { title: ( <> {logo} - Better T Stack @@ -60,6 +60,17 @@ export const baseOptions: BaseLayoutProps = { external: true, secondary: true, }, + { + text: "X", + icon: ( + x + ), + label: "X", + type: "icon", + url: "https://x.com/amanvarshney01", + external: true, + secondary: true, + }, { text: "Discord", icon: ( diff --git a/apps/web/src/lib/types.ts b/apps/web/src/lib/types.ts index 11ea19f..8ec5a55 100644 --- a/apps/web/src/lib/types.ts +++ b/apps/web/src/lib/types.ts @@ -38,6 +38,7 @@ export interface Sponsor { avatarUrl: string; websiteUrl?: string; linkUrl: string; + customLogoUrl: string; type: string; }; isOneTime: boolean;