Skip to content

Commit 5dcaedb

Browse files
committed
draft: add supporters mechanism and new home page
1 parent f33bf00 commit 5dcaedb

31 files changed

Lines changed: 228 additions & 1652 deletions

File tree

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import type { FC } from 'react';
1+
import type { ComponentProps, FC } from 'react';
22

33
import Nodejs from '@/components/Icons/Logos/Nodejs';
44
import type { LogoVariant } from '@/types';
55

66
import style from './index.module.css';
77

8-
type NodejsLogoProps = {
8+
type NodejsLogoProps = ComponentProps<typeof Nodejs> & {
99
variant?: LogoVariant;
1010
};
1111

12-
const NodejsLogo: FC<NodejsLogoProps> = ({ variant = 'default' }) => (
13-
<Nodejs variant={variant} className={style.nodejsLogo} />
12+
const NodejsLogo: FC<NodejsLogoProps> = ({ variant = 'default', ...props }) => (
13+
<Nodejs variant={variant} className={style.nodejsLogo} {...props} />
1414
);
1515

1616
export default NodejsLogo;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Link from 'next/link';
2+
import { cloneElement, type ComponentProps, type FC } from 'react';
3+
4+
import Skeleton from '@/components/Common/Skeleton';
5+
import type { Supporter } from '@/types';
6+
7+
type SupporterIconProps = Supporter & ComponentProps<typeof Skeleton>;
8+
9+
const SupporterIcon: FC<SupporterIconProps> = ({
10+
name,
11+
href,
12+
icon,
13+
loading = false,
14+
}) => (
15+
<Skeleton loading={loading}>
16+
<Link href={href} aria-label={name}>
17+
{cloneElement(icon, {
18+
className: 'h-12 w-12 rounded-lg bg-neutral-100 p-1',
19+
})}
20+
</Link>
21+
</Skeleton>
22+
);
23+
24+
export default SupporterIcon;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use client';
2+
3+
import { useEffect, useRef, useState, type FC } from 'react';
4+
5+
import SupporterIcon from '@/components/Common/Supporters/SupporterIcon';
6+
import { randomSupporterList } from '@/components/Common/Supporters/utils';
7+
import { DEFAULT_SUPPORTERS_LIST } from '@/next.supporters.constants';
8+
import type { Supporter } from '@/types';
9+
10+
type SupporterIconListProps = {
11+
supporters: Array<Supporter>;
12+
maxLength?: number;
13+
};
14+
15+
const SupporterIconList: FC<SupporterIconListProps> = ({
16+
supporters,
17+
maxLength = 4,
18+
}) => {
19+
const initialRenderer = useRef(true);
20+
21+
const [seedList, setSeedList] = useState<Array<Supporter>>(
22+
DEFAULT_SUPPORTERS_LIST
23+
);
24+
25+
useEffect(() => {
26+
// We intentionally render the initial default "mock" list of sponsors
27+
// to have the Skeletons loading, and then we render the actual list
28+
// after an enough amount of time has passed to give a proper sense of Animation
29+
// We do this client-side effect, to ensure that a random-amount of sponsors is renderered
30+
// on every page load. Since our page is natively static, we need to ensure that
31+
// on the client-side we have a random amount of sponsors rendered.
32+
// Although whilst we are deployed on Vercel or other environment that supports ISR
33+
// (Incremental Static Generation) whose would invalidate the cache every 5 minutes
34+
// We want to ensure that this feature is compatible on a full-static environment
35+
const renderSponsorsAnimation = setTimeout(() => {
36+
initialRenderer.current = false;
37+
38+
setSeedList(
39+
randomSupporterList(
40+
supporters,
41+
Math.max(supporters.length, maxLength * 2)
42+
)
43+
);
44+
}, 1000);
45+
46+
return () => clearTimeout(renderSponsorsAnimation);
47+
// We only want this to run once on initial render
48+
// We don't really care if the props change as realistically they shouldn't ever
49+
// eslint-disable-next-line react-hooks/exhaustive-deps
50+
}, []);
51+
52+
return (
53+
<div className="flex flex-row flex-wrap items-center justify-center gap-4">
54+
{seedList.slice(0, maxLength).map((supporter, index) => (
55+
<SupporterIcon
56+
{...supporter}
57+
loading={initialRenderer.current}
58+
key={index}
59+
/>
60+
))}
61+
</div>
62+
);
63+
};
64+
65+
export default SupporterIconList;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { FC } from 'react';
2+
3+
import type { Supporter } from '@/types';
4+
5+
// @TODO: This will be used within the MDX page for Supporters
6+
// to render the Logos of Supporters in the page
7+
const SupporterLogo: FC<Supporter> = () => null;
8+
9+
export default SupporterLogo;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { FC } from 'react';
2+
3+
import type { Supporter } from '@/types';
4+
5+
type SupporterLogoListProps = {
6+
supporters: Array<Supporter>;
7+
};
8+
9+
// @TODO: This will be used within the MDX page for Supporters
10+
// to render the Logos of Supporters in the page
11+
// in a grid format that renders logo biggers based on thresholds
12+
const SupporterLogoList: FC<SupporterLogoListProps> = () => null;
13+
14+
export default SupporterLogoList;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { Supporter } from '@/types';
2+
3+
export const randomSupporterList = (
4+
supporters: Array<Supporter>,
5+
pick: number
6+
) =>
7+
supporters
8+
.sort(() => 0.5 - Math.random())
9+
.slice(0, pick)
10+
.sort((a, b) => b.threshold - a.threshold);

apps/site/components/Containers/Footer/index.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import LinkedIn from '@/components/Icons/Social/LinkedIn';
88
import Mastodon from '@/components/Icons/Social/Mastodon';
99
import Slack from '@/components/Icons/Social/Slack';
1010
import Twitter from '@/components/Icons/Social/Twitter';
11-
import { siteNavigation } from '@/next.json.mjs';
11+
import type { FooterConfig, SocialConfig } from '@/types';
1212

1313
import styles from './index.module.css';
1414

@@ -21,15 +21,20 @@ const footerSocialIcons: Record<string, React.FC<SVGProps<SVGSVGElement>>> = {
2121
bluesky: Bluesky,
2222
};
2323

24-
const Footer: FC = () => {
24+
type FooterProps = {
25+
socialLinks: Array<SocialConfig>;
26+
footerLinks: Array<FooterConfig>;
27+
};
28+
29+
const Footer: FC<FooterProps> = ({ socialLinks, footerLinks }) => {
2530
const t = useTranslations();
2631

27-
const openJSlink = siteNavigation.footerLinks.at(-1)!;
32+
const openJSlink = footerLinks.at(-1)!;
2833

2934
return (
3035
<footer className={styles.footer}>
3136
<div className={styles.sectionPrimary}>
32-
{siteNavigation.footerLinks.slice(0, -1).map(item => (
37+
{footerLinks.slice(0, -1).map(item => (
3338
<NavItem type="footer" href={item.link} key={item.link}>
3439
{t(item.text)}
3540
</NavItem>
@@ -42,7 +47,7 @@ const Footer: FC = () => {
4247
</NavItem>
4348

4449
<div className={styles.social}>
45-
{siteNavigation.socialLinks.map(link => {
50+
{socialLinks.map(link => {
4651
const SocialIcon = footerSocialIcons[link.icon];
4752

4853
return (

apps/site/components/Downloads/DownloadButton/index.module.css

Lines changed: 0 additions & 17 deletions
This file was deleted.

apps/site/components/Downloads/DownloadButton/index.stories.tsx

Lines changed: 0 additions & 30 deletions
This file was deleted.

apps/site/components/Downloads/DownloadButton/index.tsx

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)