diff --git a/.gitignore b/.gitignore
index 3674bb9f..60f03209 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,8 @@ node_modules
out
*.generated.*
/.cache
-/pages/api
-/pages/loaders
-/pages/plugins
+/pages/docs/api
+/pages/docs/loaders
+/pages/docs/plugins
/generated
/pages/about/governance
diff --git a/.prettierignore b/.prettierignore
index f604605e..4f8d655b 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -2,6 +2,8 @@ node_modules
out
*.generated.*
/.cache
-/pages/api
+/pages/docs/api
+/pages/docs/loaders
+/pages/docs/plugins
versions.json
/generated
\ No newline at end of file
diff --git a/.stylelintignore b/.stylelintignore
index f604605e..4f8d655b 100644
--- a/.stylelintignore
+++ b/.stylelintignore
@@ -2,6 +2,8 @@ node_modules
out
*.generated.*
/.cache
-/pages/api
+/pages/docs/api
+/pages/docs/loaders
+/pages/docs/plugins
versions.json
/generated
\ No newline at end of file
diff --git a/components/MetaBar/index.jsx b/components/MetaBar/index.jsx
new file mode 100644
index 00000000..4e621ef3
--- /dev/null
+++ b/components/MetaBar/index.jsx
@@ -0,0 +1,62 @@
+import MetaBar from '@node-core/ui-components/Containers/MetaBar';
+import AvatarGroup from '@node-core/ui-components/Common/AvatarGroup';
+import GitHubIcon from '@node-core/ui-components/Icons/Social/GitHub';
+
+import { editURL } from '#theme/config';
+import sponsors from '#theme/sponsors' with { type: 'json' };
+import SponsorCard from '../Sponsors/Card/index.jsx';
+
+// Active recurring platinum-tier sponsors, ranked by monthly amount. There are
+// only ever a handful, so the MetaBar features them as full expanded cards.
+const platinumSponsors = sponsors.sponsors
+ .filter(sponsor => sponsor.monthly.tier === 'platinum')
+ .sort((a, b) => b.monthly.value - a.monthly.value);
+
+export default ({ metadata, headings = [], readingTime }) => {
+ const editThisPage =
+ metadata.source ?? editURL.replace('{path}', metadata.path);
+ const authors = metadata.authors?.split(',').map(id => ({
+ image: `https://avatars.githubusercontent.com/${id.trim()}`,
+ url: `https://github.com/${id.trim()}`,
+ nickname: id,
+ }));
+
+ return (
+ ,
+ }
+ : {}),
+ Contribute: (
+ <>
+
+ Edit this page
+ >
+ ),
+ ...(platinumSponsors.length
+ ? {
+ [platinumSponsors.length > 1
+ ? 'Featured Sponsors'
+ : 'Featured Sponsor']: (
+
+ {platinumSponsors.map(sponsor => (
+
+ ))}
+
+ ),
+ }
+ : {}),
+ }}
+ />
+ );
+};
diff --git a/components/SideBar.jsx b/components/SideBar.jsx
index b33cd053..725e5e57 100644
--- a/components/SideBar.jsx
+++ b/components/SideBar.jsx
@@ -6,26 +6,28 @@ const redirect = url => (window.location.href = url);
const PrefetchLink = props => ;
-const pathnameFor = path => path.replace(/\/index$/, '') || '/';
+const pathnameFor = path => {
+ const clean = path.replace(/\/index$/, '');
+ if (!clean) return '/';
+ return clean.startsWith('/') ? clean : `/${clean}`;
+};
const groupsFor = path => {
+ if (Array.isArray(sidebar)) return sidebar;
+
const segment = path.split('/').filter(Boolean)[0];
- const matched = sidebar.filter(g => g.groupName.toLowerCase() === segment);
- return matched.length > 0 ? matched : sidebar;
+ return sidebar[segment] ?? [];
};
/**
* Sidebar component for MDX documentation with page navigation.
*/
-export default ({ metadata }) => {
- const path = pathnameFor(metadata.path);
- return (
-
- );
-};
+export default ({ metadata }) => (
+
+);
diff --git a/components/Sponsors/Card/index.jsx b/components/Sponsors/Card/index.jsx
index 4f8782c3..47cb464e 100644
--- a/components/Sponsors/Card/index.jsx
+++ b/components/Sponsors/Card/index.jsx
@@ -19,12 +19,14 @@ const amountLabel = (sponsor, metric) =>
* sponsor: { name: string, slug: string, imageUrl: string|null, url: string, monthly: { value: number, tier: string|null }, allTime: { value: number, tier: string|null }, description?: string },
* size?: 'lg'|'md'|'sm'|'xs',
* metric?: 'monthly'|'allTime',
+ * showAmount?: boolean,
* }} props
*/
export default function SponsorCard({
sponsor,
size = 'md',
metric = 'monthly',
+ showAmount = true,
className,
...props
}) {
@@ -53,7 +55,11 @@ export default function SponsorCard({
{sponsor.description}
)}
- {amountLabel(sponsor, metric)}
+ {showAmount && (
+
+ {amountLabel(sponsor, metric)}
+
+ )}
Visit →
@@ -72,7 +78,7 @@ export default function SponsorCard({
{sponsor.name}
- {size !== 'xs' && (
+ {size !== 'xs' && showAmount && (
{amountLabel(sponsor, metric)}
)}
diff --git a/components/Sponsors/Card/index.module.css b/components/Sponsors/Card/index.module.css
index 41ebebcb..1759c6b3 100644
--- a/components/Sponsors/Card/index.module.css
+++ b/components/Sponsors/Card/index.module.css
@@ -6,7 +6,7 @@
border
border-neutral-200
bg-white
- no-underline
+ no-underline!
transition-colors
duration-150
hover:border-blue-300
@@ -96,6 +96,7 @@
@apply ml-auto
text-xl
leading-none
+ font-normal
text-neutral-300
dark:text-neutral-600;
}
diff --git a/eslint.config.mjs b/eslint.config.mjs
index c79a995e..29ff4016 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -11,6 +11,14 @@ export default [
},
},
{
- ignores: ['node_modules/', 'out/', '.cache/', 'webpack/', 'pages/api'],
+ ignores: [
+ 'node_modules/',
+ 'out/',
+ '.cache/',
+ 'webpack/',
+ 'pages/docs/api',
+ 'pages/docs/loaders',
+ 'pages/docs/plugins',
+ ],
},
];
diff --git a/layouts/Sponsors/index.jsx b/layouts/Sponsors/index.jsx
index 3c07c66d..e1829bd1 100644
--- a/layouts/Sponsors/index.jsx
+++ b/layouts/Sponsors/index.jsx
@@ -4,6 +4,7 @@ import BaseButton from '@node-core/ui-components/Common/BaseButton';
import NavBar from '../../components/NavBar.jsx';
import Footer from '../../components/Footer/index.jsx';
+import SideBar from '../../components/SideBar.jsx';
import SectionHeader from '../../components/SectionHeader/index.jsx';
import SponsorTier from '../../components/Sponsors/Tier/index.jsx';
import BackerWall from '../../components/Sponsors/BackerWall/index.jsx';
@@ -73,54 +74,60 @@ export default function SponsorsLayout({ metadata }) {
<>
-
-
-
-
-
-
- View on Open Collective
-
-
-
-
-
-
- {TIERS.map(tier => (
-
- ))}
+
+
+
+
+
+
+
+
+
+ View on Open Collective
+
+
+
+
+
+
+ {TIERS.map(tier => (
+
+ ))}
+
-
-
+
-
-
>
diff --git a/layouts/Sponsors/index.module.css b/layouts/Sponsors/index.module.css
index 7236c009..77cab0c0 100644
--- a/layouts/Sponsors/index.module.css
+++ b/layouts/Sponsors/index.module.css
@@ -1,7 +1,23 @@
@reference "../../styles/index.css";
+.shell {
+ @apply block
+ w-full
+ min-[896px]:grid
+ min-[896px]:grid-cols-[--spacing(56)_1fr];
+}
+
+.sidebar {
+ @apply min-[896px]:sticky
+ min-[896px]:top-0
+ min-[896px]:grid
+ min-[896px]:h-svh
+ min-[896px]:overflow-y-auto;
+}
+
.page {
- @apply bg-white
+ @apply min-w-0
+ bg-white
text-neutral-900
dark:bg-neutral-950
dark:text-white;
diff --git a/pages/about/branding.md b/pages/about/branding.md
index eda3aca4..a45f6701 100644
--- a/pages/about/branding.md
+++ b/pages/about/branding.md
@@ -1,3 +1,7 @@
+---
+authors: avivkeller
+---
+
# Branding of webpack
Here you can find **webpack** project brand guidelines and assets. Official artwork is maintained in the OpenJS Foundation [artwork repository](https://github.com/openjs-foundation/artwork/tree/main/projects/webpack).
diff --git a/pages/about/index.md b/pages/about/index.md
new file mode 100644
index 00000000..47f68fb7
--- /dev/null
+++ b/pages/about/index.md
@@ -0,0 +1,3 @@
+# About webpack
+
+STUB
diff --git a/pages/docs/index.md b/pages/docs/index.md
new file mode 100644
index 00000000..5568faad
--- /dev/null
+++ b/pages/docs/index.md
@@ -0,0 +1,3 @@
+# Documentation
+
+STUB
diff --git a/pages/site.json b/pages/site.json
index e692df9a..f4052844 100644
--- a/pages/site.json
+++ b/pages/site.json
@@ -13,8 +13,8 @@
"text": "Blog"
},
{
- "link": "/api/v5.x",
- "text": "API"
+ "link": "/docs",
+ "text": "Docs"
},
{
"link": "/about/sponsors",
@@ -26,7 +26,6 @@
"target": "_blank"
}
],
- "sidebar": [],
"footer": {
"socialLinks": [
{
@@ -54,21 +53,17 @@
"text": "Getting Started",
"link": "/guides/getting-started"
},
- {
- "text": "Guides",
- "link": "/guides"
- },
{
"text": "Concepts",
- "link": "/concepts"
+ "link": "/guides/getting-started/concepts"
},
{
- "text": "Configuration",
- "link": "/configuration"
+ "text": "Guides",
+ "link": "/guides"
},
{
"text": "API",
- "link": "/api/v5.x"
+ "link": "/docs/api/v5.x"
}
]
},
@@ -77,11 +72,11 @@
"links": [
{
"text": "Loaders",
- "link": "/loaders"
+ "link": "/docs/loaders"
},
{
"text": "Plugins",
- "link": "/plugins"
+ "link": "/docs/plugins"
},
{
"text": "Awesome webpack",
diff --git a/pages/site.mjs b/pages/site.mjs
index 5da7d15a..74f3a87a 100644
--- a/pages/site.mjs
+++ b/pages/site.mjs
@@ -1,18 +1,40 @@
-import { sidebar as _sidebar } from './site.json' with { type: 'json' };
-import loaders from './loaders/site.json' with { type: 'json' };
-import plugins from './plugins/site.json' with { type: 'json' };
-import contribute from './about/governance/site.json' with { type: 'json' };
+import loaders from './docs/loaders/site.json' with { type: 'json' };
+import plugins from './docs/plugins/site.json' with { type: 'json' };
+import governance from './about/governance/site.json' with { type: 'json' };
+import versions from '../versions.json' with { type: 'json' };
+import { major } from 'semver';
export * from './site.json' with { type: 'json' };
-export const sidebar = [
- ..._sidebar,
- {
- groupName: 'Loaders & Plugins',
- items: [...loaders.sidebar, ...plugins.sidebar],
- },
- {
- groupName: 'About',
- items: contribute.sidebar,
- },
-];
+export const sidebar = {
+ about: [
+ {
+ groupName: 'Get Involved',
+ items: [
+ { link: '/about/branding', label: 'Branding' },
+ { link: '/about/sponsors', label: 'Sponsors' },
+ {
+ link: 'https://github.com/webpack/webpack/blob/main/CONTRIBUTING.md',
+ label: 'Contribute',
+ },
+ ],
+ },
+ ...governance.sidebar,
+ ],
+ docs: [
+ {
+ groupName: 'Main Packages',
+ items: [
+ {
+ label: 'webpack',
+ items: versions.map(v => ({
+ label: `webpack ${v}`,
+ link: `/docs/api/v${major(v)}.x`,
+ })),
+ },
+ ],
+ },
+ ...loaders.sidebar,
+ ...plugins.sidebar,
+ ],
+};
diff --git a/scripts/html/doc-kit.config.mjs b/scripts/html/doc-kit.config.mjs
index 8c63397d..d5494952 100644
--- a/scripts/html/doc-kit.config.mjs
+++ b/scripts/html/doc-kit.config.mjs
@@ -8,7 +8,7 @@ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const VERSION = process.env.VERSION;
const MAJOR_VERSION = VERSION ? `v${major(VERSION)}.x` : undefined;
-const URL_PATH = VERSION ? `/api/${MAJOR_VERSION}` : '/';
+const URL_PATH = VERSION ? `/docs/api/${MAJOR_VERSION}` : '/';
const ORIGIN = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
@@ -29,8 +29,8 @@ export default {
repository: 'webpack/webpack',
version: VERSION,
input: [`${INPUT_DIR}/**/*.md`],
- ignore: VERSION ? [] : ['./pages/api/**/*.md'],
- output: VERSION ? `./out/api/${MAJOR_VERSION}` : './out',
+ ignore: VERSION ? [] : ['./pages/docs/api/**/*.md'],
+ output: VERSION ? `./out/docs/api/${MAJOR_VERSION}` : './out',
baseURL: BASE_URL,
},
threads: 1,
@@ -46,6 +46,8 @@ export default {
useAbsoluteURLs: true,
remoteConfigUrl: null,
title: VERSION ? `Webpack ${MAJOR_VERSION} Documentation` : 'Webpack',
+ editURL:
+ 'https://github.com/webpack/webpack-doc-kit/blob/main/pages/{path}.md',
head: {
meta: [
{
@@ -72,6 +74,7 @@ export default {
'#theme/site': SITE_MODULE,
'#theme/Sidebar': join(ROOT, 'components/SideBar.jsx'),
+ '#theme/Metabar': join(ROOT, 'components/MetaBar/index.jsx'),
'#theme/sponsors': join(ROOT, 'generated/sponsors.json'),
'#theme/Layout': join(ROOT, 'components/Layout.jsx'),
'#theme/Navigation': join(ROOT, 'components/NavBar.jsx'),
diff --git a/scripts/markdown/api.mjs b/scripts/markdown/api.mjs
index c8402e5f..93cf4572 100644
--- a/scripts/markdown/api.mjs
+++ b/scripts/markdown/api.mjs
@@ -12,7 +12,7 @@ const generate = async packageDir => {
const app = await Application.bootstrapWithPlugins({
entryPoints: [join(packageDir, 'types.d.ts')],
- out: join('pages', 'api', `v${major(version)}.x`),
+ out: join('pages', 'docs', 'api', `v${major(version)}.x`),
publicPath: `/api/v${major(version)}.x/`,
plugin: [
diff --git a/scripts/markdown/governance.mjs b/scripts/markdown/governance.mjs
index 76644419..76bbaf38 100644
--- a/scripts/markdown/governance.mjs
+++ b/scripts/markdown/governance.mjs
@@ -10,7 +10,7 @@ const BASE_HEADERS = {
// Maps source filenames in webpack/governance repo to their output slug and sidebar label.
// Insertion order determines sidebar order, this could be changed as per need.
const FILE_MAP = {
- 'README.md': { output: 'index', label: 'Governance Overview' },
+ 'README.md': { output: 'index', label: 'Overview' },
'CHARTER.md': { output: 'charter', label: 'Charter' },
'MEMBER_EXPECTATIONS.md': {
output: 'member-expectations',
@@ -64,7 +64,13 @@ const results = await Promise.all(
return null;
}
- const content = `---\nsource: ${url}\n---\n\n${rewriteLinks(await res.text())}`;
+ let body = rewriteLinks(await res.text());
+
+ // Some governance docs (e.g. MEMBER_EXPECTATIONS.md) have no H1, which the
+ // site derives the page title from — fall back to the sidebar label.
+ if (!/^# /m.test(body)) body = `# ${label}\n\n${body}`;
+
+ const content = `---\nsource: ${url}\n---\n\n${body}`;
await writeFile(join(outputDir, `${output}.md`), content, 'utf8');
console.log(`Fetched: ${source} -> ${output}.md`);
return { output, label };
@@ -76,7 +82,7 @@ const fetched = results.filter(Boolean);
const siteJson = {
sidebar: [
{
- label: 'Governance',
+ groupName: 'Governance',
items: fetched.map(({ output, label }) => ({
link: `/about/governance/${output}`,
label,
diff --git a/scripts/markdown/readmes.mjs b/scripts/markdown/readmes.mjs
index 7be2b47c..54353b09 100644
--- a/scripts/markdown/readmes.mjs
+++ b/scripts/markdown/readmes.mjs
@@ -75,10 +75,10 @@ const processRepos = async (repos, { label, basePath, outputDir }) => {
const siteJson = {
sidebar: [
{
- label,
+ groupName: label,
items: fetched.map(name => ({
link: `${basePath}/${name}`,
- label: name.replace(/-(?:loader|plugin)$/, ''),
+ label: name.replace(/-(?:webpack-)?(?:loader|plugin)$/, ''),
})),
},
],
@@ -102,14 +102,14 @@ await Promise.all(
runLoaders &&
processRepos(loaders, {
label: 'Loaders',
- basePath: '/loaders',
- outputDir: join(root, 'pages/loaders'),
+ basePath: '/docs/loaders',
+ outputDir: join(root, 'pages/docs/loaders'),
}),
runPlugins &&
processRepos(plugins, {
label: 'Plugins',
- basePath: '/plugins',
- outputDir: join(root, 'pages/plugins'),
+ basePath: '/docs/plugins',
+ outputDir: join(root, 'pages/docs/plugins'),
}),
].filter(Boolean)
);