Skip to content

Commit b65f34c

Browse files
bjohansebasbmuenzenmeyerovflowdcanerakdas
authored
chore: partners/sponsors page (#7991)
Co-authored-by: Brian Muenzenmeyer <[email protected]> Co-authored-by: Claudio Wunder <[email protected]> Co-authored-by: Caner Akdas <[email protected]>
1 parent e3e16f2 commit b65f34c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+2838
-1
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@reference "../../../../styles/index.css";
2+
3+
.partnerIcon {
4+
@apply h-9
5+
w-auto
6+
min-w-9
7+
p-2;
8+
9+
svg {
10+
@apply !h-4
11+
!w-auto;
12+
}
13+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import Skeleton from '@node-core/ui-components/Common/Skeleton';
2+
import Tooltip from '@node-core/ui-components/Common/Tooltip';
3+
import type { ComponentProps, FC } from 'react';
4+
import { cloneElement } from 'react';
5+
6+
import Button from '#site/components/Common/Button';
7+
import type { Partners } from '#site/types';
8+
9+
import style from './index.module.css';
10+
11+
type PartnersIconProps = Partners & ComponentProps<typeof Skeleton>;
12+
13+
const PartnersIcon: FC<PartnersIconProps> = ({ name, href, logo, loading }) => (
14+
<Skeleton loading={loading} className="size-9 p-2">
15+
<Tooltip
16+
content={
17+
<div className="p-2 text-neutral-900 dark:text-neutral-200">{name}</div>
18+
}
19+
>
20+
<Button
21+
kind="secondary"
22+
href={`${href}/?utm_source=nodejs-website&utm_medium=Link`}
23+
className={style.partnerIcon}
24+
>
25+
{cloneElement(logo, {
26+
width: '100%',
27+
height: '16px',
28+
})}
29+
</Button>
30+
</Tooltip>
31+
</Skeleton>
32+
);
33+
34+
export default PartnersIcon;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@reference "../../../../styles/index.css";
2+
3+
.partnerIcon {
4+
@apply flex
5+
h-28
6+
max-h-28
7+
w-auto
8+
min-w-12
9+
items-center
10+
justify-center
11+
rounded-lg
12+
p-6
13+
sm:p-10;
14+
15+
svg {
16+
@apply !h-12
17+
!w-auto;
18+
}
19+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Skeleton from '@node-core/ui-components/Common/Skeleton';
2+
import type { ComponentProps, FC } from 'react';
3+
import { cloneElement } from 'react';
4+
5+
import Button from '#site/components/Common/Button';
6+
import type { Partners } from '#site/types';
7+
8+
import style from './index.module.css';
9+
10+
type PartnersLogoProps = Partners & ComponentProps<typeof Skeleton>;
11+
12+
const PartnersLogo: FC<PartnersLogoProps> = ({ href, logo, loading }) => (
13+
<Skeleton loading={loading} className="h-28 w-full p-2">
14+
<Button
15+
kind="secondary"
16+
href={`${href}/?utm_source=nodejs-website&utm_medium=Link`}
17+
className={style.partnerIcon}
18+
>
19+
{cloneElement(logo, {
20+
width: '100%',
21+
height: '16px',
22+
})}
23+
</Button>
24+
</Skeleton>
25+
);
26+
27+
export default PartnersLogo;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@reference "../../../../styles/index.css";
2+
3+
.partnersIconList {
4+
@apply flex
5+
flex-row
6+
flex-wrap
7+
items-center
8+
gap-2;
9+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use client';
2+
3+
import type { FC } from 'react';
4+
5+
import usePartnersList from '#site/hooks/react-client/usePartnersList';
6+
import { ICON_PARTNERS } from '#site/next.partners.constants';
7+
import type { PartnerCategory } from '#site/types';
8+
9+
import PartnerIcon from '../PartnerIcon';
10+
import style from './index.module.css';
11+
12+
type PartnersIconListProps = {
13+
maxLength?: number;
14+
categories?: PartnerCategory;
15+
};
16+
17+
const PartnersIconList: FC<PartnersIconListProps> = ({
18+
maxLength = 6,
19+
categories,
20+
}) => {
21+
const { seedList, initialRenderer } = usePartnersList({
22+
logos: ICON_PARTNERS,
23+
maxLength,
24+
categories,
25+
});
26+
27+
return (
28+
<div className={style.partnersIconList}>
29+
{seedList.map((partner, index) => (
30+
<PartnerIcon
31+
{...partner}
32+
key={index}
33+
loading={initialRenderer.current}
34+
/>
35+
))}
36+
</div>
37+
);
38+
};
39+
40+
export default PartnersIconList;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@reference "../../../../styles/index.css";
2+
3+
.partnersLogoList {
4+
@apply grid
5+
w-full
6+
grid-cols-[repeat(auto-fill,minmax(240px,1fr))]
7+
gap-4;
8+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use client';
2+
3+
import type { FC } from 'react';
4+
5+
import usePartnersList from '#site/hooks/react-client/usePartnersList';
6+
import { LOGO_PARTNERS } from '#site/next.partners.constants';
7+
import type { PartnerCategory } from '#site/types';
8+
9+
import PartnerLogo from '../PartnerLogo';
10+
import style from './index.module.css';
11+
12+
type PartnersLogoListProps = {
13+
maxLength?: number;
14+
categories?: PartnerCategory;
15+
sort?: 'name' | 'weight';
16+
};
17+
18+
const PartnersLogoList: FC<PartnersLogoListProps> = ({
19+
maxLength = 3,
20+
sort = 'weight',
21+
categories,
22+
}) => {
23+
const { seedList, initialRenderer } = usePartnersList({
24+
logos: LOGO_PARTNERS,
25+
maxLength,
26+
sort,
27+
categories,
28+
});
29+
30+
return (
31+
<div className={style.partnersLogoList}>
32+
{seedList.map((partner, index) => (
33+
<PartnerLogo
34+
{...partner}
35+
key={index}
36+
loading={initialRenderer.current}
37+
/>
38+
))}
39+
</div>
40+
);
41+
};
42+
43+
export default PartnersLogoList;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { RandomPartnerListConfig, Partners } from '#site/types';
2+
import { shuffle } from '#site/util/array';
3+
4+
async function randomPartnerList(
5+
partners: Array<Partners>,
6+
config: RandomPartnerListConfig
7+
): Promise<Array<Partners>> {
8+
const { pick = 4, dateSeed = 5, category } = config;
9+
10+
// Generate a deterministic seed based on current time that changes every X minutes
11+
const seed = Math.floor(Date.now() / (dateSeed * 60 * 1000));
12+
13+
// Filter by category if provided
14+
const filtered = category
15+
? partners.filter(p => p.categories.includes(category))
16+
: partners;
17+
18+
const shuffled = await shuffle(filtered, seed);
19+
20+
return shuffled.slice(0, pick ?? filtered.length);
21+
}
22+
23+
export { randomPartnerList };
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use client';
2+
3+
import Avatar from '@node-core/ui-components/Common/AvatarGroup/Avatar';
4+
import type { FC } from 'react';
5+
6+
import type { Supporters } from '#site/types';
7+
8+
type SupportersListProps = {
9+
supporters: Array<Supporters>;
10+
};
11+
12+
const SupportersList: FC<SupportersListProps> = ({ supporters }) => (
13+
<div className="flex max-w-full flex-wrap items-center justify-center gap-1">
14+
{supporters.map(({ name, image }, i) => (
15+
<Avatar nickname={name} image={image} key={`${name}-${i}`} />
16+
))}
17+
</div>
18+
);
19+
20+
export default SupportersList;

0 commit comments

Comments
 (0)