@windrun-huaiin/third-ui 5.12.3 → 5.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { Translations } from 'fumadocs-ui/i18n';
2
2
  import * as _clerk_types from '@clerk/types';
3
3
  import { z } from 'zod';
4
+ import { MetadataRoute } from 'next';
4
5
 
5
6
  declare const fumaI18nCn: Partial<Translations>;
6
7
 
@@ -4443,4 +4444,35 @@ declare const remarkInstallOptions: {
4443
4444
  };
4444
4445
  };
4445
4446
 
4446
- export { clerkIntl, createCommonDocsSchema, createCommonMetaSchema, createDateSchema, createDescriptionSchema, createIconSchema, createTitleSchema, fumaI18nCn, remarkInstallOptions };
4447
+ /**
4448
+ * Generate robots.txt content
4449
+ * @param baseUrl - The base URL of the website
4450
+ * @returns Robots configuration
4451
+ */
4452
+ declare function generateRobots(baseUrl: string): MetadataRoute.Robots;
4453
+ /**
4454
+ * Generate sitemap.xml content
4455
+ * @param baseUrl - The base URL of the website
4456
+ * @param locales - Supported locales array
4457
+ * @param mdxSourceDir - MDX source directory path
4458
+ * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
4459
+ * @returns Sitemap entries
4460
+ */
4461
+ declare function generateSitemap(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): MetadataRoute.Sitemap;
4462
+ /**
4463
+ * Create robots.txt handler function
4464
+ * @param baseUrl - The base URL of the website
4465
+ * @returns Robots handler function
4466
+ */
4467
+ declare function createRobotsHandler(baseUrl: string): () => MetadataRoute.Robots;
4468
+ /**
4469
+ * Create sitemap.xml handler function
4470
+ * @param baseUrl - The base URL of the website
4471
+ * @param locales - Supported locales array
4472
+ * @param mdxSourceDir - MDX source directory path
4473
+ * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
4474
+ * @returns Sitemap handler function
4475
+ */
4476
+ declare function createSitemapHandler(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): () => MetadataRoute.Sitemap;
4477
+
4478
+ export { clerkIntl, createCommonDocsSchema, createCommonMetaSchema, createDateSchema, createDescriptionSchema, createIconSchema, createRobotsHandler, createSitemapHandler, createTitleSchema, fumaI18nCn, generateRobots, generateSitemap, remarkInstallOptions };
@@ -1,6 +1,7 @@
1
1
  import { Translations } from 'fumadocs-ui/i18n';
2
2
  import * as _clerk_types from '@clerk/types';
3
3
  import { z } from 'zod';
4
+ import { MetadataRoute } from 'next';
4
5
 
5
6
  declare const fumaI18nCn: Partial<Translations>;
6
7
 
@@ -4443,4 +4444,35 @@ declare const remarkInstallOptions: {
4443
4444
  };
4444
4445
  };
4445
4446
 
4446
- export { clerkIntl, createCommonDocsSchema, createCommonMetaSchema, createDateSchema, createDescriptionSchema, createIconSchema, createTitleSchema, fumaI18nCn, remarkInstallOptions };
4447
+ /**
4448
+ * Generate robots.txt content
4449
+ * @param baseUrl - The base URL of the website
4450
+ * @returns Robots configuration
4451
+ */
4452
+ declare function generateRobots(baseUrl: string): MetadataRoute.Robots;
4453
+ /**
4454
+ * Generate sitemap.xml content
4455
+ * @param baseUrl - The base URL of the website
4456
+ * @param locales - Supported locales array
4457
+ * @param mdxSourceDir - MDX source directory path
4458
+ * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
4459
+ * @returns Sitemap entries
4460
+ */
4461
+ declare function generateSitemap(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): MetadataRoute.Sitemap;
4462
+ /**
4463
+ * Create robots.txt handler function
4464
+ * @param baseUrl - The base URL of the website
4465
+ * @returns Robots handler function
4466
+ */
4467
+ declare function createRobotsHandler(baseUrl: string): () => MetadataRoute.Robots;
4468
+ /**
4469
+ * Create sitemap.xml handler function
4470
+ * @param baseUrl - The base URL of the website
4471
+ * @param locales - Supported locales array
4472
+ * @param mdxSourceDir - MDX source directory path
4473
+ * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
4474
+ * @returns Sitemap handler function
4475
+ */
4476
+ declare function createSitemapHandler(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): () => MetadataRoute.Sitemap;
4477
+
4478
+ export { clerkIntl, createCommonDocsSchema, createCommonMetaSchema, createDateSchema, createDescriptionSchema, createIconSchema, createRobotsHandler, createSitemapHandler, createTitleSchema, fumaI18nCn, generateRobots, generateSitemap, remarkInstallOptions };
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
6
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
+ var __getProtoOf = Object.getPrototypeOf;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
9
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
10
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -29,6 +31,14 @@ var __copyProps = (to, from, except, desc) => {
29
31
  }
30
32
  return to;
31
33
  };
34
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
35
+ // If the importer is in node compatibility mode or this is not an ESM
36
+ // file that has been converted to a CommonJS file using a Babel-
37
+ // compatible transform (i.e. "__esModule" has not been set), then set
38
+ // "default" to the CommonJS "module.exports" for node compatibility.
39
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
40
+ mod
41
+ ));
32
42
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
43
 
34
44
  // src/lib/server.ts
@@ -40,8 +50,12 @@ __export(server_exports, {
40
50
  createDateSchema: () => createDateSchema,
41
51
  createDescriptionSchema: () => createDescriptionSchema,
42
52
  createIconSchema: () => createIconSchema,
53
+ createRobotsHandler: () => createRobotsHandler,
54
+ createSitemapHandler: () => createSitemapHandler,
43
55
  createTitleSchema: () => createTitleSchema,
44
56
  fumaI18nCn: () => fumaI18nCn,
57
+ generateRobots: () => generateRobots,
58
+ generateSitemap: () => generateSitemap,
45
59
  remarkInstallOptions: () => remarkInstallOptions
46
60
  });
47
61
  module.exports = __toCommonJS(server_exports);
@@ -111,6 +125,63 @@ var remarkInstallOptions = {
111
125
  id: "package-manager"
112
126
  }
113
127
  };
128
+
129
+ // src/lib/seo-util.ts
130
+ var import_fs = __toESM(require("fs"));
131
+ var import_path = __toESM(require("path"));
132
+ function generateRobots(baseUrl) {
133
+ return {
134
+ rules: {
135
+ userAgent: "*",
136
+ allow: "/"
137
+ },
138
+ sitemap: `${baseUrl}/sitemap.xml`
139
+ };
140
+ }
141
+ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
142
+ const blogDir = import_path.default.join(process.cwd(), mdxSourceDir);
143
+ const blogFiles = import_fs.default.readdirSync(blogDir).filter((f) => f.endsWith(".mdx"));
144
+ const blogRoutes = [];
145
+ for (const locale of locales) {
146
+ for (const f of blogFiles) {
147
+ if (f === "index.mdx") {
148
+ blogRoutes.push({
149
+ url: `${baseUrl}/${locale}/blog`,
150
+ lastModified: /* @__PURE__ */ new Date(),
151
+ changeFrequency: "daily",
152
+ priority: 1
153
+ });
154
+ } else {
155
+ const slug = f.replace(/\.mdx$/, "");
156
+ blogRoutes.push({
157
+ url: `${baseUrl}/${locale}/blog/${slug}`,
158
+ lastModified: /* @__PURE__ */ new Date(),
159
+ changeFrequency: f === "ioc.mdx" ? "daily" : "monthly",
160
+ priority: 0.8
161
+ });
162
+ }
163
+ }
164
+ }
165
+ const mainRoutes = locales.map((locale) => ({
166
+ url: `${baseUrl}/${locale}`,
167
+ lastModified: /* @__PURE__ */ new Date(),
168
+ changeFrequency: "weekly",
169
+ priority: 1
170
+ }));
171
+ return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
172
+ }
173
+ function createRobotsHandler(baseUrl) {
174
+ return function robots() {
175
+ return generateRobots(baseUrl);
176
+ };
177
+ }
178
+ function createSitemapHandler(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
179
+ const sitemapHandler = function sitemap() {
180
+ return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
181
+ };
182
+ sitemapHandler.dynamic = "force-static";
183
+ return sitemapHandler;
184
+ }
114
185
  // Annotate the CommonJS export names for ESM import in node:
115
186
  0 && (module.exports = {
116
187
  clerkIntl,
@@ -119,8 +190,12 @@ var remarkInstallOptions = {
119
190
  createDateSchema,
120
191
  createDescriptionSchema,
121
192
  createIconSchema,
193
+ createRobotsHandler,
194
+ createSitemapHandler,
122
195
  createTitleSchema,
123
196
  fumaI18nCn,
197
+ generateRobots,
198
+ generateSitemap,
124
199
  remarkInstallOptions
125
200
  });
126
201
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/server.ts","../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts"],"sourcesContent":["// This is a server component!\n\nexport * from './fuma-search-util';\nexport * from './clerk-intl';\nexport * from './fuma-schema-check-util';","import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,aAAoC;AAAA,EAC/C,QAAQ;AAAA;AAEV;;;ACLA,2BAA2B;AAK3B,IAAM,WAAiC,mBAClC;AAGE,IAAM,YAAY;AAAA,EACvB,IAAI;AAAA,EACJ,IAAI;AACN;;;ACZA,iBAAkB;AAClB,oBAA8C;AAIvC,IAAM,oBAAoB,MAC/B,aAAE,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,oBAAoB;AACtB,CAAC,EACA,KAAK,EACL,IAAI,GAAG,EAAE,SAAS,sDAAsD,CAAC;AAGrE,IAAM,0BAA0B,MACrC,aAAE;AAAA,EACA,CAAC,QAAa;AACZ,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,IAAI,KAAK,MAAM,MAAM,QAAQ,OAAO,SAAY,IAAI,KAAK;AAAA,IAClE;AACA,WAAO,QAAQ,OAAO,SAAY;AAAA,EACpC;AAAA,EACA,aAAE,OAAO,EAAE,SAAS;AACtB;AAGK,IAAM,mBAAmB,MAC9B,aAAE;AAAA,EACA,CAAC,QAAc,QAAQ,MAAM,QAAQ,OAAO,SAAY;AAAA,EACxD,aAAE,OAAO,EAAE,SAAS;AACtB;AAGK,IAAM,mBAAmB,MAC9B,aAAE;AAAA,EAAW,CAAC,QAAa;AACzB,QAAI,eAAe,MAAM;AAEvB,YAAM,OAAO,IAAI,YAAY;AAC7B,YAAM,SAAS,IAAI,SAAS,IAAI,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAC7D,YAAM,MAAM,IAAI,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACpD,aAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA,IAChC;AACA,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,IAAI,KAAK;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AAAA,EACA,aAAE,OAAO,EACN,MAAM,uBAAuB,0DAA0D,EACvF,OAAO,CAAC,QAAa,CAAC,MAAM,IAAI,KAAK,GAAG,EAAE,QAAQ,CAAC,GAAG,eAAe;AACxE;AAGK,IAAM,yBAAyB,MAAM,gCAAkB,OAAO;AAAA,EACnE,OAAO,kBAAkB;AAAA,EACzB,aAAa,wBAAwB;AAAA,EACrC,MAAM,iBAAiB;AAAA,EACvB,MAAM,iBAAiB;AAAA,EACvB,QAAQ,aAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,aAAE,MAAM,aAAE,OAAO,CAAC,EAAE,SAAS;AACzC,CAAC;AAGM,IAAM,yBAAyB,MAAM,yBAAW,OAAO;AAAA,EAC5D,aAAa,aAAE,OAAO,EAAE,SAAS;AACnC,CAAC;AAEM,IAAM,uBAAuB;AAAA,EAClC,SAAS;AAAA,IACP,IAAI;AAAA,EACN;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/server.ts","../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts","../../src/lib/seo-util.ts"],"sourcesContent":["// This is a server component!\n\nexport * from './fuma-search-util';\nexport * from './clerk-intl';\nexport * from './fuma-schema-check-util';\nexport * from './seo-util';","import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};","import type { MetadataRoute } from 'next';\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * Generate robots.txt content\n * @param baseUrl - The base URL of the website\n * @returns Robots configuration\n */\nexport function generateRobots(baseUrl: string): MetadataRoute.Robots {\n return {\n rules: {\n userAgent: \"*\",\n allow: \"/\",\n },\n sitemap: `${baseUrl}/sitemap.xml`,\n };\n}\n\n/**\n * Generate sitemap.xml content\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap entries\n */\nexport function generateSitemap(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n): MetadataRoute.Sitemap {\n // 1. read all blog mdx file names\n const blogDir = path.join(process.cwd(), mdxSourceDir);\n const blogFiles = fs.readdirSync(blogDir).filter(f => f.endsWith('.mdx'));\n\n // 2. handle index.mdx (blog start page) and other slugs\n const blogRoutes: MetadataRoute.Sitemap = [];\n\n for (const locale of locales) {\n for (const f of blogFiles) {\n if (f === 'index.mdx') {\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog`,\n lastModified: new Date(),\n changeFrequency: 'daily',\n priority: 1.0\n });\n } else {\n const slug = f.replace(/\\.mdx$/, '');\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog/${slug}`,\n lastModified: new Date(),\n changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',\n priority: 0.8\n });\n }\n }\n }\n\n // 3. main page (all language versions)\n const mainRoutes = locales.map(locale => ({\n url: `${baseUrl}/${locale}`,\n lastModified: new Date(),\n changeFrequency: 'weekly' as const,\n priority: 1.0\n }));\n\n return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];\n}\n\n/**\n * Create robots.txt handler function\n * @param baseUrl - The base URL of the website\n * @returns Robots handler function\n */\nexport function createRobotsHandler(baseUrl: string) {\n return function robots(): MetadataRoute.Robots {\n return generateRobots(baseUrl);\n };\n}\n\n/**\n * Create sitemap.xml handler function\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap handler function\n */\nexport function createSitemapHandler(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n) {\n // force static generation\n const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {\n return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);\n };\n \n // Add static generation directive\n (sitemapHandler as any).dynamic = 'force-static';\n \n return sitemapHandler;\n}"],"mappings":"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","names":["path","fs"]}
@@ -80,6 +80,63 @@ var remarkInstallOptions = {
80
80
  id: "package-manager"
81
81
  }
82
82
  };
83
+
84
+ // src/lib/seo-util.ts
85
+ import fs from "fs";
86
+ import path from "path";
87
+ function generateRobots(baseUrl) {
88
+ return {
89
+ rules: {
90
+ userAgent: "*",
91
+ allow: "/"
92
+ },
93
+ sitemap: `${baseUrl}/sitemap.xml`
94
+ };
95
+ }
96
+ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
97
+ const blogDir = path.join(process.cwd(), mdxSourceDir);
98
+ const blogFiles = fs.readdirSync(blogDir).filter((f) => f.endsWith(".mdx"));
99
+ const blogRoutes = [];
100
+ for (const locale of locales) {
101
+ for (const f of blogFiles) {
102
+ if (f === "index.mdx") {
103
+ blogRoutes.push({
104
+ url: `${baseUrl}/${locale}/blog`,
105
+ lastModified: /* @__PURE__ */ new Date(),
106
+ changeFrequency: "daily",
107
+ priority: 1
108
+ });
109
+ } else {
110
+ const slug = f.replace(/\.mdx$/, "");
111
+ blogRoutes.push({
112
+ url: `${baseUrl}/${locale}/blog/${slug}`,
113
+ lastModified: /* @__PURE__ */ new Date(),
114
+ changeFrequency: f === "ioc.mdx" ? "daily" : "monthly",
115
+ priority: 0.8
116
+ });
117
+ }
118
+ }
119
+ }
120
+ const mainRoutes = locales.map((locale) => ({
121
+ url: `${baseUrl}/${locale}`,
122
+ lastModified: /* @__PURE__ */ new Date(),
123
+ changeFrequency: "weekly",
124
+ priority: 1
125
+ }));
126
+ return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
127
+ }
128
+ function createRobotsHandler(baseUrl) {
129
+ return function robots() {
130
+ return generateRobots(baseUrl);
131
+ };
132
+ }
133
+ function createSitemapHandler(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
134
+ const sitemapHandler = function sitemap() {
135
+ return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
136
+ };
137
+ sitemapHandler.dynamic = "force-static";
138
+ return sitemapHandler;
139
+ }
83
140
  export {
84
141
  clerkIntl,
85
142
  createCommonDocsSchema,
@@ -87,8 +144,12 @@ export {
87
144
  createDateSchema,
88
145
  createDescriptionSchema,
89
146
  createIconSchema,
147
+ createRobotsHandler,
148
+ createSitemapHandler,
90
149
  createTitleSchema,
91
150
  fumaI18nCn,
151
+ generateRobots,
152
+ generateSitemap,
92
153
  remarkInstallOptions
93
154
  };
94
155
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts"],"sourcesContent":["import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};"],"mappings":";;;;;;;;;;;;;;;;;;AAEO,IAAM,aAAoC;AAAA,EAC/C,QAAQ;AAAA;AAEV;;;ACLA,SAAS,MAAM,YAAY;AAK3B,IAAM,WAAiC,mBAClC;AAGE,IAAM,YAAY;AAAA,EACvB,IAAI;AAAA,EACJ,IAAI;AACN;;;ACZA,SAAS,SAAS;AAClB,SAAS,mBAAmB,kBAAkB;AAIvC,IAAM,oBAAoB,MAC/B,EAAE,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,oBAAoB;AACtB,CAAC,EACA,KAAK,EACL,IAAI,GAAG,EAAE,SAAS,sDAAsD,CAAC;AAGrE,IAAM,0BAA0B,MACrC,EAAE;AAAA,EACA,CAAC,QAAa;AACZ,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,IAAI,KAAK,MAAM,MAAM,QAAQ,OAAO,SAAY,IAAI,KAAK;AAAA,IAClE;AACA,WAAO,QAAQ,OAAO,SAAY;AAAA,EACpC;AAAA,EACA,EAAE,OAAO,EAAE,SAAS;AACtB;AAGK,IAAM,mBAAmB,MAC9B,EAAE;AAAA,EACA,CAAC,QAAc,QAAQ,MAAM,QAAQ,OAAO,SAAY;AAAA,EACxD,EAAE,OAAO,EAAE,SAAS;AACtB;AAGK,IAAM,mBAAmB,MAC9B,EAAE;AAAA,EAAW,CAAC,QAAa;AACzB,QAAI,eAAe,MAAM;AAEvB,YAAM,OAAO,IAAI,YAAY;AAC7B,YAAM,SAAS,IAAI,SAAS,IAAI,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAC7D,YAAM,MAAM,IAAI,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACpD,aAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA,IAChC;AACA,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,IAAI,KAAK;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AAAA,EACA,EAAE,OAAO,EACN,MAAM,uBAAuB,0DAA0D,EACvF,OAAO,CAAC,QAAa,CAAC,MAAM,IAAI,KAAK,GAAG,EAAE,QAAQ,CAAC,GAAG,eAAe;AACxE;AAGK,IAAM,yBAAyB,MAAM,kBAAkB,OAAO;AAAA,EACnE,OAAO,kBAAkB;AAAA,EACzB,aAAa,wBAAwB;AAAA,EACrC,MAAM,iBAAiB;AAAA,EACvB,MAAM,iBAAiB;AAAA,EACvB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AACzC,CAAC;AAGM,IAAM,yBAAyB,MAAM,WAAW,OAAO;AAAA,EAC5D,aAAa,EAAE,OAAO,EAAE,SAAS;AACnC,CAAC;AAEM,IAAM,uBAAuB;AAAA,EAClC,SAAS;AAAA,IACP,IAAI;AAAA,EACN;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts","../../src/lib/seo-util.ts"],"sourcesContent":["import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};","import type { MetadataRoute } from 'next';\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * Generate robots.txt content\n * @param baseUrl - The base URL of the website\n * @returns Robots configuration\n */\nexport function generateRobots(baseUrl: string): MetadataRoute.Robots {\n return {\n rules: {\n userAgent: \"*\",\n allow: \"/\",\n },\n sitemap: `${baseUrl}/sitemap.xml`,\n };\n}\n\n/**\n * Generate sitemap.xml content\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap entries\n */\nexport function generateSitemap(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n): MetadataRoute.Sitemap {\n // 1. read all blog mdx file names\n const blogDir = path.join(process.cwd(), mdxSourceDir);\n const blogFiles = fs.readdirSync(blogDir).filter(f => f.endsWith('.mdx'));\n\n // 2. handle index.mdx (blog start page) and other slugs\n const blogRoutes: MetadataRoute.Sitemap = [];\n\n for (const locale of locales) {\n for (const f of blogFiles) {\n if (f === 'index.mdx') {\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog`,\n lastModified: new Date(),\n changeFrequency: 'daily',\n priority: 1.0\n });\n } else {\n const slug = f.replace(/\\.mdx$/, '');\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog/${slug}`,\n lastModified: new Date(),\n changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',\n priority: 0.8\n });\n }\n }\n }\n\n // 3. main page (all language versions)\n const mainRoutes = locales.map(locale => ({\n url: `${baseUrl}/${locale}`,\n lastModified: new Date(),\n changeFrequency: 'weekly' as const,\n priority: 1.0\n }));\n\n return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];\n}\n\n/**\n * Create robots.txt handler function\n * @param baseUrl - The base URL of the website\n * @returns Robots handler function\n */\nexport function createRobotsHandler(baseUrl: string) {\n return function robots(): MetadataRoute.Robots {\n return generateRobots(baseUrl);\n };\n}\n\n/**\n * Create sitemap.xml handler function\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap handler function\n */\nexport function createSitemapHandler(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n) {\n // force static generation\n const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {\n return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);\n };\n \n // Add static generation directive\n (sitemapHandler as any).dynamic = 'force-static';\n \n return sitemapHandler;\n}"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "5.12.3",
3
+ "version": "5.13.0",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -35,7 +35,11 @@ interface FumaPageParams {
35
35
  /*
36
36
  * The fallback page component to use when the page is not found
37
37
  */
38
- FallbackPage: React.ComponentType<{ siteIcon: ReactNode }>;
38
+ FallbackPage: React.ComponentType<{ siteIcon: ReactNode }>;
39
+ /*
40
+ * Supported locales for generating alternates metadata, defaults to ['en']
41
+ */
42
+ supportedLocales?: string[];
39
43
  }
40
44
 
41
45
  export function createFumaPage({
@@ -47,6 +51,7 @@ export function createFumaPage({
47
51
  copyButtonComponent,
48
52
  siteIcon,
49
53
  FallbackPage,
54
+ supportedLocales = ['en'],
50
55
  }: FumaPageParams) {
51
56
  const Page = async function Page({ params }: { params: Promise<{ locale: string; slug?: string[] }> }) {
52
57
  const { slug, locale } = await params;
@@ -92,17 +97,39 @@ export function createFumaPage({
92
97
  }
93
98
 
94
99
  async function generateMetadata(props: { params: Promise<{ slug?: string[]; locale?: string }> }) {
95
- const params = await props.params;
96
- const page = mdxContentSource.getPage(params.slug, params.locale);
100
+ const { slug, locale } = await props.params;
101
+ const page = mdxContentSource.getPage(slug, locale);
97
102
  if (!page) {
98
103
  return {
99
104
  title: '404 - Page Not Found',
100
105
  description: 'This page could not be found.',
101
106
  };
102
107
  }
108
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL!;
109
+ const baseRoute = mdxSourceDir.replace('src/mdx/', '');
110
+ // build the current page path
111
+ const currentPath = slug ? slug.join('/') : '';
112
+ const currentUrl = `${baseUrl}/${locale}/${baseRoute}${currentPath ? `/${currentPath}` : ''}`;
113
+
114
+ // generate the seo language map
115
+ const seoLanguageMap: Record<string, string> = {};
116
+
117
+ console.log('supportedLocales', supportedLocales);
118
+
119
+ supportedLocales.forEach(loc => {
120
+ seoLanguageMap[loc] = `${baseUrl}/${loc}/${baseRoute}${currentPath ? `/${currentPath}` : ''}`;
121
+ });
122
+
123
+ console.log('seoLanguageMap', seoLanguageMap);
124
+
103
125
  return {
126
+ metadataBase: new URL(baseUrl),
104
127
  title: page.data.title,
105
128
  description: page.data.description,
129
+ alternates: {
130
+ canonical: currentUrl,
131
+ languages: seoLanguageMap
132
+ },
106
133
  };
107
134
  }
108
135
 
@@ -0,0 +1,107 @@
1
+ import type { MetadataRoute } from 'next';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ /**
6
+ * Generate robots.txt content
7
+ * @param baseUrl - The base URL of the website
8
+ * @returns Robots configuration
9
+ */
10
+ export function generateRobots(baseUrl: string): MetadataRoute.Robots {
11
+ return {
12
+ rules: {
13
+ userAgent: "*",
14
+ allow: "/",
15
+ },
16
+ sitemap: `${baseUrl}/sitemap.xml`,
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Generate sitemap.xml content
22
+ * @param baseUrl - The base URL of the website
23
+ * @param locales - Supported locales array
24
+ * @param mdxSourceDir - MDX source directory path
25
+ * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
26
+ * @returns Sitemap entries
27
+ */
28
+ export function generateSitemap(
29
+ baseUrl: string,
30
+ locales: string[],
31
+ mdxSourceDir: string,
32
+ openMdxSEOSiteMap: boolean = true
33
+ ): MetadataRoute.Sitemap {
34
+ // 1. read all blog mdx file names
35
+ const blogDir = path.join(process.cwd(), mdxSourceDir);
36
+ const blogFiles = fs.readdirSync(blogDir).filter(f => f.endsWith('.mdx'));
37
+
38
+ // 2. handle index.mdx (blog start page) and other slugs
39
+ const blogRoutes: MetadataRoute.Sitemap = [];
40
+
41
+ for (const locale of locales) {
42
+ for (const f of blogFiles) {
43
+ if (f === 'index.mdx') {
44
+ blogRoutes.push({
45
+ url: `${baseUrl}/${locale}/blog`,
46
+ lastModified: new Date(),
47
+ changeFrequency: 'daily',
48
+ priority: 1.0
49
+ });
50
+ } else {
51
+ const slug = f.replace(/\.mdx$/, '');
52
+ blogRoutes.push({
53
+ url: `${baseUrl}/${locale}/blog/${slug}`,
54
+ lastModified: new Date(),
55
+ changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',
56
+ priority: 0.8
57
+ });
58
+ }
59
+ }
60
+ }
61
+
62
+ // 3. main page (all language versions)
63
+ const mainRoutes = locales.map(locale => ({
64
+ url: `${baseUrl}/${locale}`,
65
+ lastModified: new Date(),
66
+ changeFrequency: 'weekly' as const,
67
+ priority: 1.0
68
+ }));
69
+
70
+ return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
71
+ }
72
+
73
+ /**
74
+ * Create robots.txt handler function
75
+ * @param baseUrl - The base URL of the website
76
+ * @returns Robots handler function
77
+ */
78
+ export function createRobotsHandler(baseUrl: string) {
79
+ return function robots(): MetadataRoute.Robots {
80
+ return generateRobots(baseUrl);
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Create sitemap.xml handler function
86
+ * @param baseUrl - The base URL of the website
87
+ * @param locales - Supported locales array
88
+ * @param mdxSourceDir - MDX source directory path
89
+ * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
90
+ * @returns Sitemap handler function
91
+ */
92
+ export function createSitemapHandler(
93
+ baseUrl: string,
94
+ locales: string[],
95
+ mdxSourceDir: string,
96
+ openMdxSEOSiteMap: boolean = true
97
+ ) {
98
+ // force static generation
99
+ const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {
100
+ return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
101
+ };
102
+
103
+ // Add static generation directive
104
+ (sitemapHandler as any).dynamic = 'force-static';
105
+
106
+ return sitemapHandler;
107
+ }
package/src/lib/server.ts CHANGED
@@ -2,4 +2,5 @@
2
2
 
3
3
  export * from './fuma-search-util';
4
4
  export * from './clerk-intl';
5
- export * from './fuma-schema-check-util';
5
+ export * from './fuma-schema-check-util';
6
+ export * from './seo-util';