Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ If you want to write something but don't know what, look through [open issues](h

The generator code lives in `scripts/` (pipeline stages) and `plugins/` (TypeDoc processing and the doc-kit theme). Start with the [README](README.md) — it explains the three-stage pipeline (prepare → Markdown → HTML) and what each script does.

The site is built on [@node-core/doc-kit](https://github.com/nodejs/doc-kit). Improvements to the engine itself (Markdown parsing, core rendering) belong upstream; the theme and plugins in this repository customize it for webpack.
The site is built on [doc-kit](https://github.com/nodejs/doc-kit). Improvements to the engine itself (Markdown parsing, core rendering) belong upstream; the theme and plugins in this repository customize it for webpack.

## Local development

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Automated TypeScript API documentation generator for [webpack](https://github.co

1. **TypeDoc** reads webpack's TypeScript type definitions
2. Custom plugins process the output (namespace merging, type mapping, themed rendering)
3. **@node-core/doc-kit** converts Markdown to HTML
3. **doc-kit** converts Markdown to HTML
4. GitHub Actions deploys the result to GitHub Pages

### Webpack Versions
Expand Down
2 changes: 1 addition & 1 deletion components/Blog/Byline/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function Byline({ authors, date, size = 'sm', className }) {

return (
<div className={classNames(styles.byline, styles[size], className)}>
{CLIENT && authors.length > 0 && (
{authors.length > 0 && (
<span className={styles.avatars}>
{authors.length === 1 ? (
<Avatar {...toAvatar(authors[0])} size={avatarSize} />
Expand Down
19 changes: 16 additions & 3 deletions components/HomePage/HomeSponsorSection/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import {
TIERS as BASE_TIERS,
bucketSponsors,
OC_URL,
} from '../../../layouts/Sponsors/index.jsx';
} from '../../Sponsors/tiers.mjs';

// TODO(avivkeller): Give these components proper exports
import withIsland from '../../../node_modules/@doc-kit/generator-react/src/html/ui/islands/withIsland.jsx';

const SPONSORS_URL = '/about/sponsors';

Expand Down Expand Up @@ -43,7 +46,12 @@ function SeeMore({ count, href, className }) {
);
}

export default () => {
/**
* Sponsor teaser for the home page. Server-rendered with empty data — which renders
* nothing at all — so it has to be an island: the section only ever appears once
* {@link useSponsors} has run in the browser.
*/
function HomeSponsorSection() {
const data = useSponsors();
const buckets = useMemo(
() => bucketSponsors(data.sponsors, METRIC),
Expand Down Expand Up @@ -123,4 +131,9 @@ export default () => {
</div>
</section>
);
};
}

export default withIsland(HomeSponsorSection, {
name: 'HomeSponsorSection',
on: { idle: true },
});
4 changes: 3 additions & 1 deletion components/Layout.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import DefaultLayout from '@node-core/doc-kit/src/generators/web/ui/components/Layout/index.jsx';
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/react';
import HomeLayout from '../layouts/Home/index.jsx';
Expand All @@ -8,6 +7,9 @@ import PostLayout from '../layouts/Post/index.jsx';
import PageNotFoundLayout from '../layouts/PageNotFound/index.jsx';
import '../styles/index.css';

// TODO(avivkeller): Give these components proper exports
import DefaultLayout from '../node_modules/@doc-kit/generator-react/src/html/ui/components/Layout/index.jsx';

const LAYOUTS = {
home: HomeLayout,
sponsors: SponsorsLayout,
Expand Down
2 changes: 1 addition & 1 deletion components/MetaBar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default ({ metadata, headings = [], readingTime }) => {
headings={{ items: headings }}
items={{
'Reading Time': readingTime,
...(CLIENT && authors?.length
...(authors?.length
? {
Authors: <AvatarGroup avatars={authors} as="a" limit={5} />,
}
Expand Down
6 changes: 4 additions & 2 deletions components/NavBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import NavBar from '@node-core/ui-components/Containers/NavBar';
import styles from '@node-core/ui-components/Containers/NavBar/index.module.css';
import GitHubIcon from '@node-core/ui-components/Icons/Social/GitHub';

import SearchBox from '@node-core/doc-kit/src/generators/web/ui/components/SearchBox';
import { useTheme } from '@node-core/doc-kit/src/generators/web/ui/hooks/useTheme.mjs';
import { navbar } from '#theme/site';
import { baseURL } from '#theme/config';
import { toPublicLink } from '../utils/helpers/urls.mjs';
import Logo from '#theme/Logo';

// TODO(avivkeller): Give these components proper exports
import SearchBox from '../node_modules/@doc-kit/generator-react/src/html/ui/components/SearchBox';
import { useTheme } from '../node_modules/@doc-kit/generator-react/src/html/ui/hooks/useTheme.mjs';

const versionBase = new URL(baseURL).pathname;

/**
Expand Down
61 changes: 34 additions & 27 deletions components/Sponsors/BackerWall/index.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useMemo } from 'react';

import Avatar from '@node-core/ui-components/Common/AvatarGroup/Avatar';
import classNames from 'classnames';

Expand All @@ -24,31 +26,36 @@ const shuffle = arr => [...arr].sort(() => Math.random() - 0.5);
* limit?: number,
* }} props
*/
export default ({ backers, limit = 100, showLink = true, ...props }) => (
<div {...props}>
<div className={classNames(styles.wall)}>
{CLIENT &&
shuffle(backers)
.slice(0, limit)
.map(backer => (
<Avatar
image={backer.imageUrl}
name={backer.name}
nickname={backer.slug}
fallback={initialsOf(backer.name)}
url={`${OC_BASE}/${backer.slug}`}
/>
))}
export default ({ backers, limit = 100, showLink = true, ...props }) => {
const shown = useMemo(
() => shuffle(backers).slice(0, limit),
[backers, limit]
);

return (
<div {...props}>
<div className={classNames(styles.wall)}>
{shown.map(backer => (
<Avatar
key={backer.slug}
image={backer.imageUrl}
name={backer.name}
nickname={backer.slug}
fallback={initialsOf(backer.name)}
url={`${OC_BASE}/${backer.slug}`}
/>
))}
</div>
{showLink && (
<a
href={`${OC_BASE}/webpack/contributors`}
target="_blank"
rel="noreferrer noopener"
className={styles.link}
>
See all backers on Open Collective &rarr;
</a>
)}
</div>
{showLink && (
<a
href={`${OC_BASE}/webpack/contributors`}
target="_blank"
rel="noreferrer noopener"
className={styles.link}
>
See all backers on Open Collective &rarr;
</a>
)}
</div>
);
);
};
12 changes: 2 additions & 10 deletions components/Sponsors/Card/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,7 @@ export default function SponsorCard({
{...linkProps}
className={classNames(styles.card, styles.lg, className)}
>
{CLIENT && (
<Avatar
name={sponsor.name}
image={sponsor.imageUrl}
size={'medium'}
/>
)}
<Avatar name={sponsor.name} image={sponsor.imageUrl} size={'medium'} />
<span className={styles.name}>{sponsor.name}</span>
{sponsor.description && (
<p className={styles.description}>{sponsor.description}</p>
Expand All @@ -72,9 +66,7 @@ export default function SponsorCard({
className={classNames(styles.card, styles[size], className)}
>
<div>
{CLIENT && (
<Avatar name={sponsor.name} image={sponsor.imageUrl} size={'small'} />
)}
<Avatar name={sponsor.name} image={sponsor.imageUrl} size={'small'} />
</div>
<span className={styles.body}>
<span className={styles.name}>{sponsor.name}</span>
Expand Down
44 changes: 44 additions & 0 deletions components/Sponsors/tiers.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export const OC_URL = 'https://opencollective.com/webpack';

export const TIERS = [
{
tier: 'platinum',
label: 'Platinum',
price: { monthly: '$2,500+ / month', allTime: '$50,000+ all-time' },
cardSize: 'lg',
},
{
tier: 'gold',
label: 'Gold',
price: { monthly: '$500 / month', allTime: '$10,000+ all-time' },
cardSize: 'md',
},
{
tier: 'silver',
label: 'Silver',
price: { monthly: '$100 / month', allTime: '$2,000+ all-time' },
cardSize: 'sm',
},
{
tier: 'bronze',
label: 'Bronze',
price: { monthly: '$10 / month', allTime: '$200+ all-time' },
cardSize: 'xs',
},
];

export const sortByMetric = (list, metric) =>
[...list].sort((a, b) => b[metric].value - a[metric].value);

/**
* Group sponsors into tier buckets
*/
export const bucketSponsors = (sponsors, metric) => {
const buckets = { platinum: [], gold: [], silver: [], bronze: [] };
for (const sponsor of sortByMetric(sponsors, metric)) {
const tier = sponsor[metric].tier;
if (!tier) continue;
buckets[tier].push(sponsor);
}
return buckets;
};
3 changes: 1 addition & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export default [
files: ['**/*.jsx'],
languageOptions: {
parserOptions: { ecmaFeatures: { jsx: true } },
// SERVER/CLIENT are compile-time defines from doc-kit, not real globals.
globals: { ...globals.browser, SERVER: 'readonly', CLIENT: 'readonly' },
globals: globals.browser,
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion layouts/Post/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import styles from './index.module.css';
* walking the listing order (newest-first, so "previous" is the newer post).
*
* @param {{
* metadata: import('@node-core/doc-kit/src/generators/web/ui/types').SerializedMetadata
* metadata: import('@doc-kit/generator-react/html/ui/types').SerializedMetadata
* & { authors?: string[], date?: string, category?: string },
* headings: Array<object>,
* readingTime: string,
Expand Down
85 changes: 85 additions & 0 deletions layouts/Sponsors/Board.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { useState } from 'react';

import BaseButton from '@node-core/ui-components/Common/BaseButton';

import SectionHeader from '../../components/SectionHeader/index.jsx';
import SponsorTier from '../../components/Sponsors/Tier/index.jsx';
import BackerWall from '../../components/Sponsors/BackerWall/index.jsx';
import SortToggle from '../../components/Sponsors/SortToggle/index.jsx';
import {
OC_URL,
TIERS,
bucketSponsors,
} from '../../components/Sponsors/tiers.mjs';
import useSponsors from '../../hooks/useSponsors.mjs';

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

// TODO(avivkeller): Give these components proper exports
import withIsland from '../../node_modules/@doc-kit/generator-react/src/html/ui/islands/withIsland.jsx';

/**
* Everything on the Sponsors page
*/
function SponsorBoard() {
const [metric, setMetric] = useState('monthly');
const data = useSponsors();

const buckets = bucketSponsors(data.sponsors, metric);

return (
<>
<section className={styles.sponsorsSection}>
<div className={styles.container}>
<SectionHeader
eyebrow="Our sponsors"
title="The organizations supporting webpack"
/>
<div className={styles.actions}>
<BaseButton
href={OC_URL}
target="_blank"
rel="noreferrer noopener"
kind="primary"
>
View on Open Collective
</BaseButton>
</div>
<div className={styles.toolbar}>
<SortToggle value={metric} onChange={setMetric} />
</div>
<div className={styles.tiers}>
{TIERS.map(tier => (
<SponsorTier
key={tier.tier}
tier={tier.tier}
label={tier.label}
price={tier.price[metric]}
cardSize={tier.cardSize}
sponsors={buckets[tier.tier]}
metric={metric}
/>
))}
</div>
</div>
</section>

<section className={styles.backersSection}>
<div className={styles.container}>
<SectionHeader
eyebrow="Our backers"
title="And the people who chip in"
/>
<div className={styles.backersBody}>
<BackerWall backers={data.backers} />
</div>
</div>
</section>
</>
);
}

export default withIsland(SponsorBoard, {
name: 'SponsorBoard',
on: { idle: true },
});
Loading
Loading