feat(www): add sitemap and robots.txt (#5)
This commit is contained in:
parent
8925c28333
commit
77d03529cd
5 changed files with 223 additions and 2 deletions
5
apps/www/.gitignore
vendored
5
apps/www/.gitignore
vendored
|
|
@ -25,4 +25,7 @@ yarn-error.log*
|
|||
# others
|
||||
.env*.local
|
||||
.vercel
|
||||
next-env.d.ts
|
||||
next-env.d.ts
|
||||
|
||||
# sitemap
|
||||
/public/sitemap.xml
|
||||
5
apps/www/app/robots.txt
Normal file
5
apps/www/app/robots.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
User-Agent: *
|
||||
Allow: /
|
||||
Disallow: /private/
|
||||
|
||||
Sitemap: https://amical.ai/sitemap.xml
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"build": "pnpm build:sitemap && next build",
|
||||
"build:sitemap": "pnpm exec tsx ./scripts/generate-sitemap.mts",
|
||||
"dev": "next dev --turbo",
|
||||
"start": "next start",
|
||||
"serve": "pnpm dlx serve out -p 3000",
|
||||
|
|
@ -36,9 +37,11 @@
|
|||
"@types/node": "22.15.12",
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"globby": "^14.1.0",
|
||||
"postcss": "^8.5.3",
|
||||
"server": "^1.0.41",
|
||||
"tailwindcss": "^4.1.5",
|
||||
"tsx": "^4.19.4",
|
||||
"tw-animate-css": "^1.2.9",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
|
|
|
|||
129
apps/www/scripts/generate-sitemap.mts
Normal file
129
apps/www/scripts/generate-sitemap.mts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import fs from 'fs';
|
||||
import { globby } from 'globby';
|
||||
import prettier from 'prettier';
|
||||
import path from 'path';
|
||||
|
||||
async function generate() {
|
||||
const prettierConfig = await prettier.resolveConfig('./.prettierrc');
|
||||
|
||||
// Ensure directories exist
|
||||
fs.mkdirSync('public', { recursive: true });
|
||||
fs.mkdirSync('out', { recursive: true });
|
||||
|
||||
// Get static pages
|
||||
const pages = await globby([
|
||||
'app/**/page.tsx',
|
||||
'!app/**/_*/**',
|
||||
'!app/**/api/**',
|
||||
'!app/docs/**', // Exclude docs directory as we'll handle it separately
|
||||
]);
|
||||
|
||||
// Get doc pages from the build output
|
||||
const docPages = await globby(['out/docs/**/*.html'])
|
||||
.then(pages => pages
|
||||
.map(page => page
|
||||
.replace('out', '')
|
||||
.replace('/index.html', '')
|
||||
.replace('.html', '')
|
||||
)
|
||||
.filter(page => !page.includes('/_'))
|
||||
);
|
||||
|
||||
// Get blog pages from the build output
|
||||
const blogPages = await globby(['out/blog/**/*.html'])
|
||||
.then(pages => pages
|
||||
.map(page => page
|
||||
.replace('out', '')
|
||||
.replace('/index.html', '')
|
||||
.replace('.html', '')
|
||||
)
|
||||
.filter(page => !page.includes('/_') && !page.includes('/blog/index'))
|
||||
);
|
||||
|
||||
const baseUrl = 'https://amical.ai';
|
||||
|
||||
const sitemap = `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
${[
|
||||
// Add static pages
|
||||
...pages.map((page) => {
|
||||
const path = page
|
||||
.replace('app', '')
|
||||
.replace('/page.tsx', '')
|
||||
.replace('/(home)', '')
|
||||
.replace(/\[\[\.\.\..*?\]\]/, '');
|
||||
|
||||
// Skip dynamic routes with parameters
|
||||
if (path.includes('[') || path.includes(']')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const route = path === '' ? '' : path;
|
||||
|
||||
return `
|
||||
<url>
|
||||
<loc>${baseUrl}${route}</loc>
|
||||
<lastmod>${new Date().toISOString()}</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
`;
|
||||
}),
|
||||
// Add docs index page
|
||||
`
|
||||
<url>
|
||||
<loc>${baseUrl}/docs</loc>
|
||||
<lastmod>${new Date().toISOString()}</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
`,
|
||||
// Add doc pages
|
||||
...docPages.map((path) => `
|
||||
<url>
|
||||
<loc>${baseUrl}${path}</loc>
|
||||
<lastmod>${new Date().toISOString()}</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
`),
|
||||
// Add blog index page
|
||||
`
|
||||
<url>
|
||||
<loc>${baseUrl}/blog</loc>
|
||||
<lastmod>${new Date().toISOString()}</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
`,
|
||||
// Add blog pages
|
||||
...blogPages.map((path) => `
|
||||
<url>
|
||||
<loc>${baseUrl}${path}</loc>
|
||||
<lastmod>${new Date().toISOString()}</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
`),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('')}
|
||||
</urlset>
|
||||
`;
|
||||
|
||||
const formatted = await prettier.format(sitemap, {
|
||||
...prettierConfig,
|
||||
parser: 'html',
|
||||
});
|
||||
|
||||
fs.writeFileSync('public/sitemap.xml', formatted);
|
||||
fs.writeFileSync('out/sitemap.xml', formatted);
|
||||
|
||||
console.log('✅ Generated sitemap.xml');
|
||||
}
|
||||
|
||||
generate().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
81
pnpm-lock.yaml
generated
81
pnpm-lock.yaml
generated
|
|
@ -93,6 +93,9 @@ importers:
|
|||
'@types/react-dom':
|
||||
specifier: ^19.1.3
|
||||
version: 19.1.3(@types/react@19.1.3)
|
||||
globby:
|
||||
specifier: ^14.1.0
|
||||
version: 14.1.0
|
||||
postcss:
|
||||
specifier: ^8.5.3
|
||||
version: 8.5.3
|
||||
|
|
@ -102,6 +105,9 @@ importers:
|
|||
tailwindcss:
|
||||
specifier: ^4.1.5
|
||||
version: 4.1.5
|
||||
tsx:
|
||||
specifier: ^4.19.4
|
||||
version: 4.19.4
|
||||
tw-animate-css:
|
||||
specifier: ^1.2.9
|
||||
version: 1.2.9
|
||||
|
|
@ -1076,6 +1082,10 @@ packages:
|
|||
'@shikijs/vscode-textmate@10.0.2':
|
||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||
|
||||
'@sindresorhus/merge-streams@2.3.0':
|
||||
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
|
|
@ -2191,6 +2201,11 @@ packages:
|
|||
fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
fumadocs-core@15.3.0:
|
||||
resolution: {integrity: sha512-6+j2qGntJknzQUyes5BQI3U5EE4GCIb1Pi31eAYZ8GLxMP1p1bh8nAyEeW6oZNZmqfstJoVLQNnw+vwuHJJHUw==}
|
||||
peerDependencies:
|
||||
|
|
@ -2268,6 +2283,9 @@ packages:
|
|||
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-tsconfig@4.10.0:
|
||||
resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
|
||||
|
||||
get-uri@6.0.4:
|
||||
resolution: {integrity: sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
|
@ -2302,6 +2320,10 @@ packages:
|
|||
resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
globby@14.1.0:
|
||||
resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
gopd@1.2.0:
|
||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -2431,6 +2453,10 @@ packages:
|
|||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
ignore@7.0.4:
|
||||
resolution: {integrity: sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
image-size@2.0.2:
|
||||
resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==}
|
||||
engines: {node: '>=16.x'}
|
||||
|
|
@ -3297,6 +3323,10 @@ packages:
|
|||
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-type@6.0.0:
|
||||
resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
picocolors@1.0.1:
|
||||
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
|
||||
|
||||
|
|
@ -3553,6 +3583,9 @@ packages:
|
|||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
resolve-pkg-maps@1.0.0:
|
||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||
|
||||
resolve@1.22.10:
|
||||
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -3741,6 +3774,10 @@ packages:
|
|||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
slash@5.1.0:
|
||||
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
smart-buffer@4.2.0:
|
||||
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
|
||||
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
|
||||
|
|
@ -3973,6 +4010,11 @@ packages:
|
|||
resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}
|
||||
engines: {node: '>=0.6.x'}
|
||||
|
||||
tsx@4.19.4:
|
||||
resolution: {integrity: sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
turbo-darwin-64@2.5.3:
|
||||
resolution: {integrity: sha512-YSItEVBUIvAGPUDpAB9etEmSqZI3T6BHrkBkeSErvICXn3dfqXUfeLx35LfptLDEbrzFUdwYFNmt8QXOwe9yaw==}
|
||||
cpu: [x64]
|
||||
|
|
@ -4073,6 +4115,10 @@ packages:
|
|||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
unicorn-magic@0.3.0:
|
||||
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
unified@11.0.5:
|
||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||
|
||||
|
|
@ -5058,6 +5104,8 @@ snapshots:
|
|||
|
||||
'@shikijs/vscode-textmate@10.0.2': {}
|
||||
|
||||
'@sindresorhus/merge-streams@2.3.0': {}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@standard-schema/spec@1.0.0': {}
|
||||
|
|
@ -6463,6 +6511,9 @@ snapshots:
|
|||
|
||||
fs.realpath@1.0.0: {}
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
fumadocs-core@15.3.0(@types/react@19.1.3)(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
'@formatjs/intl-localematcher': 0.6.1
|
||||
|
|
@ -6593,6 +6644,10 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
get-tsconfig@4.10.0:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
get-uri@6.0.4:
|
||||
dependencies:
|
||||
basic-ftp: 5.0.5
|
||||
|
|
@ -6640,6 +6695,15 @@ snapshots:
|
|||
merge2: 1.4.1
|
||||
slash: 3.0.0
|
||||
|
||||
globby@14.1.0:
|
||||
dependencies:
|
||||
'@sindresorhus/merge-streams': 2.3.0
|
||||
fast-glob: 3.3.3
|
||||
ignore: 7.0.4
|
||||
path-type: 6.0.0
|
||||
slash: 5.1.0
|
||||
unicorn-magic: 0.3.0
|
||||
|
||||
gopd@1.2.0: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
|
@ -6830,6 +6894,8 @@ snapshots:
|
|||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
ignore@7.0.4: {}
|
||||
|
||||
image-size@2.0.2: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
|
|
@ -7984,6 +8050,8 @@ snapshots:
|
|||
|
||||
path-type@4.0.0: {}
|
||||
|
||||
path-type@6.0.0: {}
|
||||
|
||||
picocolors@1.0.1: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
|
@ -8337,6 +8405,8 @@ snapshots:
|
|||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
|
||||
resolve@1.22.10:
|
||||
dependencies:
|
||||
is-core-module: 2.16.1
|
||||
|
|
@ -8656,6 +8726,8 @@ snapshots:
|
|||
|
||||
slash@3.0.0: {}
|
||||
|
||||
slash@5.1.0: {}
|
||||
|
||||
smart-buffer@4.2.0: {}
|
||||
|
||||
snake-case@2.1.0:
|
||||
|
|
@ -8900,6 +8972,13 @@ snapshots:
|
|||
|
||||
tsscmp@1.0.6: {}
|
||||
|
||||
tsx@4.19.4:
|
||||
dependencies:
|
||||
esbuild: 0.25.4
|
||||
get-tsconfig: 4.10.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
turbo-darwin-64@2.5.3:
|
||||
optional: true
|
||||
|
||||
|
|
@ -9009,6 +9088,8 @@ snapshots:
|
|||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
unicorn-magic@0.3.0: {}
|
||||
|
||||
unified@11.0.5:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue