Skip to content
Open
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
83 changes: 83 additions & 0 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ const webpack = require('webpack');
const {getDocusaurusConfig} = require('@vis.gl/docusaurus-website');
const {resolve} = require('path');

const SITE_URL = 'https://visgl.github.io/react-map-gl';

const sharedDocPatterns = [
'README.md',
'whats-new.md',
'upgrade-guide.md',
'contributing.md',
'get-started/**'
];
const mapboxApiPatterns = ['api-reference/mapbox/**'];
const maplibreApiPatterns = ['api-reference/maplibre/**'];
const mapboxDocPatterns = [...sharedDocPatterns, ...mapboxApiPatterns];
const maplibreDocPatterns = [...sharedDocPatterns, ...maplibreApiPatterns];

const config = getDocusaurusConfig({
projectName: 'react-map-gl',
tagline: 'React components for Mapbox GL JS and Maplibre GL JS',
Expand Down Expand Up @@ -39,6 +53,75 @@ const config = getDocusaurusConfig({
'./src/styles.css',
'./src/mapbox-gl.css',
'./src/maplibre-gl.css'
],

plugins: [
[
'docusaurus-plugin-llms',
{
docsDir: [{path: '../docs', routeBasePath: 'docs', label: 'Docs'}],
generateLLMsTxt: false,
generateLLMsFullTxt: false,
generateMarkdownFiles: false,
excludeImports: true,
removeDuplicateHeadings: true,
title: 'react-map-gl',
description: 'React components for Mapbox GL JS and MapLibre GL JS',
customLLMFiles: [
{
filename: 'llms.txt',
fullContent: false,
title: 'react-map-gl',
description: 'React components for Mapbox GL JS and MapLibre GL JS',
includePatterns: sharedDocPatterns,
orderPatterns: sharedDocPatterns,
includeUnmatchedLast: false,
rootContent: `Choose the documentation bundle for your base map library:

- [Mapbox GL JS index](${SITE_URL}/llms-mapbox.txt) (full content: [llms-mapbox-full.txt](${SITE_URL}/llms-mapbox-full.txt))
- [MapLibre GL JS index](${SITE_URL}/llms-maplibre.txt) (full content: [llms-maplibre-full.txt](${SITE_URL}/llms-maplibre-full.txt))

Only load one stack's files — API reference pages are parallel but not interchangeable.`
},
{
filename: 'llms-mapbox.txt',
fullContent: false,
title: 'react-map-gl (Mapbox GL JS)',
description: 'Docs for react-map-gl with Mapbox GL JS',
includePatterns: mapboxDocPatterns,
orderPatterns: mapboxDocPatterns,
includeUnmatchedLast: false
},
{
filename: 'llms-mapbox-full.txt',
fullContent: true,
title: 'react-map-gl (Mapbox GL JS) — full',
description: 'Docs for react-map-gl with Mapbox GL JS',
includePatterns: mapboxDocPatterns,
orderPatterns: mapboxDocPatterns,
includeUnmatchedLast: false
},
{
filename: 'llms-maplibre.txt',
fullContent: false,
title: 'react-map-gl (MapLibre GL JS)',
description: 'Docs for react-map-gl with MapLibre GL JS',
includePatterns: maplibreDocPatterns,
orderPatterns: maplibreDocPatterns,
includeUnmatchedLast: false
},
{
filename: 'llms-maplibre-full.txt',
fullContent: true,
title: 'react-map-gl (MapLibre GL JS) — full',
description: 'Docs for react-map-gl with MapLibre GL JS',
includePatterns: maplibreDocPatterns,
orderPatterns: maplibreDocPatterns,
includeUnmatchedLast: false
}
]
}
]
]
});

Expand Down
7 changes: 5 additions & 2 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Website for vis.gl project",
"scripts": {
"start": "docusaurus start",
"build": "docusaurus build",
"build": "docusaurus build && node scripts/append-examples-to-llms.js",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-heading-ids": "ocular-doc-headers ../docs",
Expand All @@ -22,9 +22,9 @@
"@mapbox/mapbox-gl-draw": "^1.3.0",
"@mapbox/mapbox-gl-geocoder": "^4.7.4",
"@maplibre/maplibre-gl-geocoder": "^1.5.0",
"@vis.gl/docusaurus-website": "1.0.0-alpha.23",
"@turf/area": "^6.5.0",
"@turf/bbox": "^6.5.0",
"@vis.gl/docusaurus-website": "1.0.0-alpha.23",
"d3-array": "^3.1.1",
"d3-scale": "^4.0.2",
"immutable": "^4.0.0",
Expand All @@ -40,5 +40,8 @@
"volta": {
"node": "18.20.5",
"yarn": "1.22.22"
},
"devDependencies": {
"docusaurus-plugin-llms": "^0.4.0"
}
}
177 changes: 177 additions & 0 deletions website/scripts/append-examples-to-llms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
const fs = require('fs');
const path = require('path');

const SITE_URL = 'https://visgl.github.io/react-map-gl';
const BUILD_DIR = path.join(__dirname, '../build');
const REPO_ROOT = path.join(__dirname, '../..');
const EXAMPLES_TOC = path.join(__dirname, '../src/examples/table-of-contents.json');

function getExampleIdsByStack(toc) {
const stacks = {mapbox: [], maplibre: []};

for (const entry of toc) {
if (entry.type !== 'category') {
continue;
}
const label = entry.label.toLowerCase();
if (label === 'mapbox') {
stacks.mapbox = entry.items;
} else if (label === 'maplibre') {
stacks.maplibre = entry.items;
}
}

return stacks;
}

function readTitle(exampleId) {
const mdxPath = path.join(__dirname, '../src/examples', `${exampleId}.mdx`);
if (fs.existsSync(mdxPath)) {
const firstLine = fs.readFileSync(mdxPath, 'utf8').split('\n')[0];
const match = firstLine.match(/^#\s+(.+)$/);
if (match) {
return match[1].trim();
}
}

const readmePath = path.join(REPO_ROOT, 'examples', exampleId, 'README.md');
if (fs.existsSync(readmePath)) {
const firstLine = fs.readFileSync(readmePath, 'utf8').split('\n')[0];
const match = firstLine.match(/^#\s+Example:\s*(.+)$/);
if (match) {
return match[1].trim();
}
}

const slug = exampleId.split('/').pop();
return slug
.split('-')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}

function readBlurb(exampleId) {
const readmePath = path.join(REPO_ROOT, 'examples', exampleId, 'README.md');
if (!fs.existsSync(readmePath)) {
return null;
}

const content = fs.readFileSync(readmePath, 'utf8');
const showcaseMatch = content.match(/This example showcases how to ([^\n.]+(?:\.[^\n.]+)*)\./i);
if (showcaseMatch) {
return showcaseMatch[1].trim().replace(/\.$/, '');
}

return null;
}

function readReadmeIntro(exampleId) {
const readmePath = path.join(REPO_ROOT, 'examples', exampleId, 'README.md');
if (!fs.existsSync(readmePath)) {
return null;
}

const lines = fs.readFileSync(readmePath, 'utf8').split('\n');
const intro = [];

for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
if (line.startsWith('## Usage')) {
break;
}
if (line) {
intro.push(line);
}
}

return intro.join('\n').trim() || null;
}

function buildExampleLinks(exampleIds) {
return exampleIds.map(exampleId => {
const title = readTitle(exampleId);
const blurb = readBlurb(exampleId);
const url = `${SITE_URL}/examples/${exampleId}`;
const description = blurb ? `: ${blurb}` : '';
return `- [${title}](${url})${description}`;
});
}

function buildExampleSections(exampleIds) {
const sections = [];

for (const exampleId of exampleIds) {
const title = readTitle(exampleId);
const url = `${SITE_URL}/examples/${exampleId}`;
const intro = readReadmeIntro(exampleId);
const blurb = readBlurb(exampleId);

sections.push(`### ${title}\n\n[View example](${url})`);
if (intro) {
sections.push(`\n${intro}`);
} else if (blurb) {
sections.push(`\nThis example showcases how to ${blurb}.`);
}
sections.push('');
}

return sections.join('\n');
}

function appendSection(filePath, section) {
if (!fs.existsSync(filePath)) {
console.warn(`Skipping ${path.basename(filePath)} — file not found`);
return;
}

const content = fs.readFileSync(filePath, 'utf8').trimEnd();
fs.writeFileSync(filePath, `${content}\n\n${section}\n`);
}

function fixDocUrls(content) {
return content
.replace(
/https:\/\/visgl\.github\.io\/docs\/\.\.\/docs\/README\.md/g,
`${SITE_URL}/docs`
)
.replace(
/https:\/\/visgl\.github\.io\/react-map-gl\/docs\/get-started\/get-started\.md/g,
`${SITE_URL}/docs/get-started.md`
);
}

function fixUrlsInLlmsFiles() {
const llmsFiles = fs
.readdirSync(BUILD_DIR)
.filter(name => name.startsWith('llms') && name.endsWith('.txt'))
.map(name => path.join(BUILD_DIR, name));

for (const filePath of llmsFiles) {
const fixed = fixDocUrls(fs.readFileSync(filePath, 'utf8'));
fs.writeFileSync(filePath, fixed);
}
}

function main() {
const toc = JSON.parse(fs.readFileSync(EXAMPLES_TOC, 'utf8'));
const stacks = getExampleIdsByStack(toc);

for (const [stack, exampleIds] of Object.entries(stacks)) {
if (exampleIds.length === 0) {
continue;
}

const linksSection = `## Examples\n\n${buildExampleLinks(exampleIds).join('\n')}`;
appendSection(path.join(BUILD_DIR, `llms-${stack}.txt`), linksSection);

const fullSection = `## Examples\n\n${buildExampleSections(exampleIds)}`;
appendSection(path.join(BUILD_DIR, `llms-${stack}-full.txt`), fullSection);

console.log(`Appended ${exampleIds.length} ${stack} examples to llms-${stack}.txt`);
}

fixUrlsInLlmsFiles();
console.log('Fixed doc URLs in generated llms files');
}

main();
28 changes: 28 additions & 0 deletions website/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3483,6 +3483,13 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"

brace-expansion@^2.0.2:
version "2.1.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8"
integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==
dependencies:
balanced-match "^1.0.0"

braces@^3.0.3, braces@~3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
Expand Down Expand Up @@ -4438,6 +4445,15 @@ dns-packet@^5.2.2:
dependencies:
"@leichtgewicht/ip-codec" "^2.0.1"

docusaurus-plugin-llms@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/docusaurus-plugin-llms/-/docusaurus-plugin-llms-0.4.0.tgz#020f00d83459c7feb71c7b6e61774d864336d8ae"
integrity sha512-jYlj2HJ5+gu7oJZuJ83Hk8KlB65YlZZ/7UpHXiL7Qr+qpNBkVocmt2Molc6F3HNr5RqcfhWD/98CvgyNztg/ow==
dependencies:
gray-matter "^4.0.3"
minimatch "^9.0.3"
yaml "^2.8.1"

dom-converter@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
Expand Down Expand Up @@ -7192,6 +7208,13 @@ minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1:
dependencies:
brace-expansion "^1.1.7"

minimatch@^9.0.3:
version "9.0.9"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e"
integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==
dependencies:
brace-expansion "^2.0.2"

minimist-options@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
Expand Down Expand Up @@ -10205,6 +10228,11 @@ yaml@^1.7.2:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==

yaml@^2.8.1:
version "2.9.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.9.0.tgz#78274afd93598a1dfdd6130df6a566defcbf9aa4"
integrity sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==

yargs-parser@^20.2.3:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
Expand Down