@windrun-huaiin/third-ui 11.1.0 → 12.0.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.
- package/dist/clerk/clerk-optional-auth.d.ts +12 -0
- package/dist/clerk/clerk-optional-auth.js +33 -0
- package/dist/clerk/clerk-optional-auth.mjs +31 -0
- package/dist/clerk/clerk-provider-client.d.ts +3 -1
- package/dist/clerk/clerk-provider-client.js +22 -12
- package/dist/clerk/clerk-provider-client.mjs +22 -12
- package/dist/clerk/optional-auth.d.ts +12 -0
- package/dist/clerk/optional-auth.js +47 -0
- package/dist/clerk/optional-auth.mjs +45 -0
- package/dist/clerk/patch/optional-auth.d.ts +11 -0
- package/dist/clerk/patch/optional-auth.js +27 -0
- package/dist/clerk/patch/optional-auth.mjs +25 -0
- package/dist/fuma/base/custom-home-layout.d.ts +9 -1
- package/dist/fuma/base/custom-home-layout.js +2 -2
- package/dist/fuma/base/custom-home-layout.mjs +2 -2
- package/dist/fuma/fuma-page-genarator.d.ts +3 -1
- package/dist/fuma/fuma-page-genarator.js +8 -3
- package/dist/fuma/fuma-page-genarator.mjs +8 -3
- package/dist/lib/seo-util.d.ts +6 -2
- package/dist/lib/seo-util.js +21 -11
- package/dist/lib/seo-util.mjs +21 -11
- package/dist/main/credit/credit-overview-client.js +2 -2
- package/dist/main/credit/credit-overview-client.mjs +2 -2
- package/dist/main/footer-email.js +1 -1
- package/dist/main/footer-email.mjs +1 -1
- package/dist/main/footer.d.ts +6 -2
- package/dist/main/footer.js +3 -2
- package/dist/main/footer.mjs +3 -2
- package/package.json +8 -3
- package/src/clerk/clerk-provider-client.tsx +37 -12
- package/src/clerk/patch/optional-auth.ts +24 -0
- package/src/fuma/base/custom-home-layout.tsx +11 -1
- package/src/fuma/fuma-page-genarator.tsx +19 -4
- package/src/lib/seo-util.ts +27 -13
- package/src/main/credit/credit-overview-client.tsx +4 -4
- package/src/main/footer-email.tsx +1 -1
- package/src/main/footer.tsx +10 -3
package/dist/lib/seo-util.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Generate robots.txt content
|
|
@@ -21,9 +22,11 @@ function generateRobots(baseUrl) {
|
|
|
21
22
|
* @param locales - Supported locales array
|
|
22
23
|
* @param mdxSourceDir - MDX source directory path
|
|
23
24
|
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
25
|
+
* @param localPrefixAsNeeded - Whether localePrefix is set to 'as-needed' (default: true)
|
|
26
|
+
* @param defaultLocale - The default locale for the application (default: 'en')
|
|
24
27
|
* @returns Sitemap entries
|
|
25
28
|
*/
|
|
26
|
-
function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
|
|
29
|
+
function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true, localPrefixAsNeeded = true, defaultLocale = 'en') {
|
|
27
30
|
// 2. handle index.mdx (blog start page) and other slugs
|
|
28
31
|
const blogRoutes = [];
|
|
29
32
|
// 1. read all blog mdx file names with error handling
|
|
@@ -36,8 +39,9 @@ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = tru
|
|
|
36
39
|
for (const locale of locales) {
|
|
37
40
|
for (const f of blogFiles) {
|
|
38
41
|
if (f === 'index.mdx') {
|
|
42
|
+
const localizedPath = getAsNeededLocalizedUrl(locale, '/blog', localPrefixAsNeeded, defaultLocale);
|
|
39
43
|
blogRoutes.push({
|
|
40
|
-
url: `${baseUrl}
|
|
44
|
+
url: `${baseUrl}${localizedPath}`,
|
|
41
45
|
lastModified: new Date(),
|
|
42
46
|
changeFrequency: 'daily',
|
|
43
47
|
priority: 1.0
|
|
@@ -45,8 +49,9 @@ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = tru
|
|
|
45
49
|
}
|
|
46
50
|
else {
|
|
47
51
|
const slug = f.replace(/\.mdx$/, '');
|
|
52
|
+
const localizedPath = getAsNeededLocalizedUrl(locale, `/blog/${slug}`, localPrefixAsNeeded, defaultLocale);
|
|
48
53
|
blogRoutes.push({
|
|
49
|
-
url: `${baseUrl}
|
|
54
|
+
url: `${baseUrl}${localizedPath}`,
|
|
50
55
|
lastModified: new Date(),
|
|
51
56
|
changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',
|
|
52
57
|
priority: 0.8
|
|
@@ -62,12 +67,15 @@ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = tru
|
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
// 3. main page (all language versions)
|
|
65
|
-
const mainRoutes = locales.map(locale =>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
const mainRoutes = locales.map(locale => {
|
|
71
|
+
const localizedPath = getAsNeededLocalizedUrl(locale, '/', localPrefixAsNeeded, defaultLocale);
|
|
72
|
+
return {
|
|
73
|
+
url: `${baseUrl}${localizedPath}`,
|
|
74
|
+
lastModified: new Date(),
|
|
75
|
+
changeFrequency: 'weekly',
|
|
76
|
+
priority: 1.0
|
|
77
|
+
};
|
|
78
|
+
});
|
|
71
79
|
return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
|
|
72
80
|
}
|
|
73
81
|
/**
|
|
@@ -86,12 +94,14 @@ function createRobotsHandler(baseUrl) {
|
|
|
86
94
|
* @param locales - Supported locales array
|
|
87
95
|
* @param mdxSourceDir - MDX source directory path, default is empty
|
|
88
96
|
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
97
|
+
* @param localPrefixAsNeeded - Whether localePrefix is set to 'as-needed' (default: true)
|
|
98
|
+
* @param defaultLocale - The default locale for the application (default: 'en')
|
|
89
99
|
* @returns Sitemap handler function
|
|
90
100
|
*/
|
|
91
|
-
function createSitemapHandler(baseUrl, locales, mdxSourceDir = '', openMdxSEOSiteMap = true) {
|
|
101
|
+
function createSitemapHandler(baseUrl, locales, mdxSourceDir = '', openMdxSEOSiteMap = true, localPrefixAsNeeded = true, defaultLocale = 'en') {
|
|
92
102
|
// force static generation
|
|
93
103
|
const sitemapHandler = function sitemap() {
|
|
94
|
-
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
|
|
104
|
+
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap, localPrefixAsNeeded, defaultLocale);
|
|
95
105
|
};
|
|
96
106
|
// Add static generation directive
|
|
97
107
|
sitemapHandler.dynamic = 'force-static';
|
|
@@ -231,9 +231,9 @@ function CreditOverviewClient({ data, locale, translations, className, expiringS
|
|
|
231
231
|
userToggledRef.current = true;
|
|
232
232
|
setBucketExpanded(true);
|
|
233
233
|
}, []);
|
|
234
|
-
return (jsxRuntime.jsxs("section", { className: utils.cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxRuntime.jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsxRuntime.jsx(server.globalLucideIcons.Gem, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsxRuntime.jsx("span", { className: "text-
|
|
234
|
+
return (jsxRuntime.jsxs("section", { className: utils.cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxRuntime.jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsxRuntime.jsx(server.globalLucideIcons.Gem, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsxRuntime.jsx("span", { className: "text-base sm:text-lg", children: translations.totalLabel })] }), jsxRuntime.jsx("div", { className: "flex justify-center text-3xl font-semibold leading-tight sm:text-4xl", children: formatNumber(locale, data.totalBalance) }), jsxRuntime.jsxs("div", { className: "flex-1 flex-col gap-1", children: [jsxRuntime.jsx("p", { className: "text-xs text-gray-700 dark:text-slate-100 sm:text-sm", children: translations.subscriptionPeriodLabel }), jsxRuntime.jsx("h4", { className: "text-xl font-semibold sm:text-2xl", children: subscription ? subscription.planName : translations.subscriptionInactive })] }), jsxRuntime.jsx("div", { className: "pt-2 sm:pt-0", children: jsxRuntime.jsx(gradientButton.GradientButton, { title: subscription ? translations.subscriptionManage : translations.subscribePay, align: "center", icon: subscription ? jsxRuntime.jsx(server.globalLucideIcons.Settings2, {}) : jsxRuntime.jsx(server.globalLucideIcons.Bell, {}), openInNewTab: false, className: "w-full", onClick: subscription ? handleManageAction : handleSubscribeAction }) })] }), jsxRuntime.jsx("div", { className: "absolute right-3 top-3 sm:right-6 sm:top-6", children: jsxRuntime.jsx(HoverInfo, { label: translations.totalLabel, description: translations.summaryDescription }) })] }), jsxRuntime.jsxs("section", { className: "relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [jsxRuntime.jsx("h3", { className: "text-base text-gray-500 dark:text-slate-100 sm:text-lg", children: translations.bucketsTitle }), hasBuckets ? (jsxRuntime.jsx("button", { type: "button", "aria-expanded": bucketExpanded, "aria-label": bucketExpanded ? translations.hiddenDetail : translations.expandDetail, onClick: toggleBucketExpanded, className: "flex h-7 w-7 items-center justify-center rounded-full border border-transparent bg-white text-purple-600 shadow-[0_6px_20px_rgba(99,102,241,0.25)] transition-colors hover:text-purple-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-500 dark:bg-[#1b1541] dark:text-purple-100 dark:hover:text-purple-50 dark:shadow-[0_6px_22px_rgba(112,86,255,0.35)]", children: bucketExpanded ? (jsxRuntime.jsx(server.globalLucideIcons.ChevronUp, { className: "h-4 w-4" })) : (jsxRuntime.jsx(server.globalLucideIcons.ChevronDown, { className: "h-4 w-4" })) })) : null] }), hasBuckets ? (bucketExpanded ? (jsxRuntime.jsx("ul", { className: "flex flex-col gap-2", children: buckets.map((bucket) => {
|
|
235
235
|
const balanceDisplay = formatNumber(locale, bucket.balance);
|
|
236
|
-
return (jsxRuntime.jsxs("li", { "data-credit-kind": bucket.kind, className: "rounded-2xl border border-slate-200/70 bg-white/85 px-3 py-3 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 sm:px-4", children: [jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm", children: [jsxRuntime.jsx("span", { className: "flex min-w-0 items-center gap-2", children: jsxRuntime.jsx("span", { className: "max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs
|
|
236
|
+
return (jsxRuntime.jsxs("li", { "data-credit-kind": bucket.kind, className: "rounded-2xl border border-slate-200/70 bg-white/85 px-3 py-3 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 sm:px-4", children: [jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm", children: [jsxRuntime.jsx("span", { className: "flex min-w-0 items-center gap-2", children: jsxRuntime.jsx("span", { className: "max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs text-purple-600 shadow-sm dark:bg-purple-500/20 dark:text-purple-100 sm:text-sm", children: bucket.computedLabel }) }), jsxRuntime.jsx("span", { className: "flex min-w-0 justify-end", children: jsxRuntime.jsx("span", { className: "text-right text-base font-semibold leading-tight text-gray-500 dark:text-slate-100 sm:text-lg", title: balanceDisplay, children: balanceDisplay }) })] }), jsxRuntime.jsx("div", { className: "mt-3 flex justify-end gap-2", children: jsxRuntime.jsxs("span", { className: "text-[11px] text-gray-500 dark:text-slate-100 sm:text-xs", children: [translations.expiredAtLabel, ": ", bucket.expiresAt] }) })] }, bucket.kind));
|
|
237
237
|
}) })) : (jsxRuntime.jsx("button", { type: "button", onClick: expandBuckets, className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 hover:text-purple-500", children: translations.expandDetail }))) : (jsxRuntime.jsx("div", { className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform dark:border-slate-800/60 dark:bg-slate-900/60 text-center", children: translations.bucketsEmpty })), jsxRuntime.jsx(gradientButton.GradientButton, { title: translations.onetimeBuy, icon: jsxRuntime.jsx(server.globalLucideIcons.ShoppingCart, {}), align: "center", className: "w-full text-sm sm:text-base", onClick: handleOnetimeAction })] })] }));
|
|
238
238
|
}
|
|
239
239
|
function deriveStatus(expiresAt, thresholdDays = 7) {
|
|
@@ -229,9 +229,9 @@ function CreditOverviewClient({ data, locale, translations, className, expiringS
|
|
|
229
229
|
userToggledRef.current = true;
|
|
230
230
|
setBucketExpanded(true);
|
|
231
231
|
}, []);
|
|
232
|
-
return (jsxs("section", { className: cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsx(globalLucideIcons.Gem, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsx("span", { className: "text-
|
|
232
|
+
return (jsxs("section", { className: cn("flex flex-col gap-2 p-2 shadow-inner rounded-xl bg-white dark:bg-slate-900", className), children: [jsxs("header", { className: "relative rounded-2xl bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 p-4 shadow-inner dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50 sm:p-6", children: [jsxs("div", { className: "flex flex-col gap-2 sm:gap-3", children: [jsxs("div", { className: "flex items-center justify-start rounded-full ", children: [jsx(globalLucideIcons.Gem, { "aria-hidden": true, className: "mr-2 h-6 w-6 sm:h-8 sm:w-8" }), jsx("span", { className: "text-base sm:text-lg", children: translations.totalLabel })] }), jsx("div", { className: "flex justify-center text-3xl font-semibold leading-tight sm:text-4xl", children: formatNumber(locale, data.totalBalance) }), jsxs("div", { className: "flex-1 flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-700 dark:text-slate-100 sm:text-sm", children: translations.subscriptionPeriodLabel }), jsx("h4", { className: "text-xl font-semibold sm:text-2xl", children: subscription ? subscription.planName : translations.subscriptionInactive })] }), jsx("div", { className: "pt-2 sm:pt-0", children: jsx(GradientButton, { title: subscription ? translations.subscriptionManage : translations.subscribePay, align: "center", icon: subscription ? jsx(globalLucideIcons.Settings2, {}) : jsx(globalLucideIcons.Bell, {}), openInNewTab: false, className: "w-full", onClick: subscription ? handleManageAction : handleSubscribeAction }) })] }), jsx("div", { className: "absolute right-3 top-3 sm:right-6 sm:top-6", children: jsx(HoverInfo, { label: translations.totalLabel, description: translations.summaryDescription }) })] }), jsxs("section", { className: "relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5", children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [jsx("h3", { className: "text-base text-gray-500 dark:text-slate-100 sm:text-lg", children: translations.bucketsTitle }), hasBuckets ? (jsx("button", { type: "button", "aria-expanded": bucketExpanded, "aria-label": bucketExpanded ? translations.hiddenDetail : translations.expandDetail, onClick: toggleBucketExpanded, className: "flex h-7 w-7 items-center justify-center rounded-full border border-transparent bg-white text-purple-600 shadow-[0_6px_20px_rgba(99,102,241,0.25)] transition-colors hover:text-purple-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-purple-500 dark:bg-[#1b1541] dark:text-purple-100 dark:hover:text-purple-50 dark:shadow-[0_6px_22px_rgba(112,86,255,0.35)]", children: bucketExpanded ? (jsx(globalLucideIcons.ChevronUp, { className: "h-4 w-4" })) : (jsx(globalLucideIcons.ChevronDown, { className: "h-4 w-4" })) })) : null] }), hasBuckets ? (bucketExpanded ? (jsx("ul", { className: "flex flex-col gap-2", children: buckets.map((bucket) => {
|
|
233
233
|
const balanceDisplay = formatNumber(locale, bucket.balance);
|
|
234
|
-
return (jsxs("li", { "data-credit-kind": bucket.kind, className: "rounded-2xl border border-slate-200/70 bg-white/85 px-3 py-3 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 sm:px-4", children: [jsxs("div", { className: "grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm", children: [jsx("span", { className: "flex min-w-0 items-center gap-2", children: jsx("span", { className: "max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs
|
|
234
|
+
return (jsxs("li", { "data-credit-kind": bucket.kind, className: "rounded-2xl border border-slate-200/70 bg-white/85 px-3 py-3 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 sm:px-4", children: [jsxs("div", { className: "grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm", children: [jsx("span", { className: "flex min-w-0 items-center gap-2", children: jsx("span", { className: "max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs text-purple-600 shadow-sm dark:bg-purple-500/20 dark:text-purple-100 sm:text-sm", children: bucket.computedLabel }) }), jsx("span", { className: "flex min-w-0 justify-end", children: jsx("span", { className: "text-right text-base font-semibold leading-tight text-gray-500 dark:text-slate-100 sm:text-lg", title: balanceDisplay, children: balanceDisplay }) })] }), jsx("div", { className: "mt-3 flex justify-end gap-2", children: jsxs("span", { className: "text-[11px] text-gray-500 dark:text-slate-100 sm:text-xs", children: [translations.expiredAtLabel, ": ", bucket.expiresAt] }) })] }, bucket.kind));
|
|
235
235
|
}) })) : (jsx("button", { type: "button", onClick: expandBuckets, className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform hover:-translate-y-0.5 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60 hover:text-purple-500", children: translations.expandDetail }))) : (jsx("div", { className: "w-full rounded-2xl border border-slate-200/70 bg-white/85 p-6 sm:px-4 text-sm shadow-sm transition-transform dark:border-slate-800/60 dark:bg-slate-900/60 text-center", children: translations.bucketsEmpty })), jsx(GradientButton, { title: translations.onetimeBuy, icon: jsx(globalLucideIcons.ShoppingCart, {}), align: "center", className: "w-full text-sm sm:text-base", onClick: handleOnetimeAction })] })] }));
|
|
236
236
|
}
|
|
237
237
|
function deriveStatus(expiresAt, thresholdDays = 7) {
|
|
@@ -23,7 +23,7 @@ function FooterEmail({ email, clickToCopyText, copiedText, children }) {
|
|
|
23
23
|
// silent fail
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
|
-
return (jsxRuntime.jsxs("div", { className: "relative group", children: [jsxRuntime.jsx("div", { className: "absolute left-2/3
|
|
26
|
+
return (jsxRuntime.jsxs("div", { className: "relative group", children: [jsxRuntime.jsx("div", { className: "absolute right-0 sm:right-auto sm:left-2/3 sm:-translate-x-1/4 bottom-full pb-1 hidden group-hover:block z-10", children: jsxRuntime.jsx("div", { className: "bg-zinc-600 text-white text-xs rounded px-3 py-1 whitespace-nowrap shadow-lg cursor-pointer select-text", onMouseDown: handleCopy, title: displayTitle, children: copied ? displayCopied : email }) }), jsxRuntime.jsx("a", { href: `mailto:${email}`, className: "flex items-center space-x-1 underline cursor-pointer px-2", children: children })] }));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
exports.FooterEmail = FooterEmail;
|
|
@@ -21,7 +21,7 @@ function FooterEmail({ email, clickToCopyText, copiedText, children }) {
|
|
|
21
21
|
// silent fail
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
|
-
return (jsxs("div", { className: "relative group", children: [jsx("div", { className: "absolute left-2/3
|
|
24
|
+
return (jsxs("div", { className: "relative group", children: [jsx("div", { className: "absolute right-0 sm:right-auto sm:left-2/3 sm:-translate-x-1/4 bottom-full pb-1 hidden group-hover:block z-10", children: jsx("div", { className: "bg-zinc-600 text-white text-xs rounded px-3 py-1 whitespace-nowrap shadow-lg cursor-pointer select-text", onMouseDown: handleCopy, title: displayTitle, children: copied ? displayCopied : email }) }), jsx("a", { href: `mailto:${email}`, className: "flex items-center space-x-1 underline cursor-pointer px-2", children: children })] }));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export { FooterEmail };
|
package/dist/main/footer.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
interface FooterProps {
|
|
2
2
|
locale: string;
|
|
3
|
-
|
|
3
|
+
localPrefixAsNeeded?: boolean;
|
|
4
|
+
defaultLocale?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function Footer({ locale, localPrefixAsNeeded, defaultLocale }: FooterProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
7
|
+
export {};
|
package/dist/main/footer.js
CHANGED
|
@@ -7,9 +7,10 @@ var server$1 = require('@windrun-huaiin/base-ui/components/server');
|
|
|
7
7
|
var Link = require('next/link');
|
|
8
8
|
var footerEmail = require('./footer-email.js');
|
|
9
9
|
var tIntl = require('../lib/t-intl.js');
|
|
10
|
+
var lib = require('@windrun-huaiin/lib');
|
|
10
11
|
|
|
11
12
|
function Footer(_a) {
|
|
12
|
-
return tslib_es6.__awaiter(this, arguments, void 0, function* ({ locale }) {
|
|
13
|
+
return tslib_es6.__awaiter(this, arguments, void 0, function* ({ locale, localPrefixAsNeeded = true, defaultLocale = 'en' }) {
|
|
13
14
|
const tFooter = yield server.getTranslations({ locale, namespace: 'footer' });
|
|
14
15
|
const company = tIntl.safeT(tFooter, 'company', '');
|
|
15
16
|
const data = {
|
|
@@ -21,7 +22,7 @@ function Footer(_a) {
|
|
|
21
22
|
clickToCopyText: tIntl.safeT(tFooter, 'clickToCopy', 'Click to copy'),
|
|
22
23
|
copiedText: tIntl.safeT(tFooter, 'copied', 'Copied!'),
|
|
23
24
|
};
|
|
24
|
-
return (jsxRuntime.jsx("div", { className: "mb-10 w-full mx-auto border-t-purple-700/80 border-t", children: jsxRuntime.jsx("footer", { children: jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center px-4 py-8 space-y-3", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-x-2 gap-y-2 text-xs sm:text-sm sm:gap-x-6", children: [jsxRuntime.jsxs(Link, { href:
|
|
25
|
+
return (jsxRuntime.jsx("div", { className: "mb-10 w-full mx-auto border-t-purple-700/80 border-t", children: jsxRuntime.jsx("footer", { children: jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center px-4 py-8 space-y-3", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-x-2 gap-y-2 text-xs sm:text-sm sm:gap-x-6", children: [jsxRuntime.jsxs(Link, { href: lib.getAsNeededLocalizedUrl(locale, "/legal/terms", localPrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsxRuntime.jsx(server$1.globalLucideIcons.ReceiptText, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.terms })] }), jsxRuntime.jsxs(Link, { href: lib.getAsNeededLocalizedUrl(locale, "/legal/privacy", localPrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsxRuntime.jsx(server$1.globalLucideIcons.ShieldUser, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.privacy })] }), jsxRuntime.jsxs(footerEmail.FooterEmail, { email: data.email, clickToCopyText: data.clickToCopyText, copiedText: data.copiedText, children: [jsxRuntime.jsx(server$1.globalLucideIcons.Mail, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.contactUs })] })] }), jsxRuntime.jsx("div", { className: "text-xs sm:text-sm text-center", children: jsxRuntime.jsx("span", { children: data.copyright }) })] }) }) }));
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
|
package/dist/main/footer.mjs
CHANGED
|
@@ -5,9 +5,10 @@ import { globalLucideIcons } from '@windrun-huaiin/base-ui/components/server';
|
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { FooterEmail } from './footer-email.mjs';
|
|
7
7
|
import { safeT } from '../lib/t-intl.mjs';
|
|
8
|
+
import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
8
9
|
|
|
9
10
|
function Footer(_a) {
|
|
10
|
-
return __awaiter(this, arguments, void 0, function* ({ locale }) {
|
|
11
|
+
return __awaiter(this, arguments, void 0, function* ({ locale, localPrefixAsNeeded = true, defaultLocale = 'en' }) {
|
|
11
12
|
const tFooter = yield getTranslations({ locale, namespace: 'footer' });
|
|
12
13
|
const company = safeT(tFooter, 'company', '');
|
|
13
14
|
const data = {
|
|
@@ -19,7 +20,7 @@ function Footer(_a) {
|
|
|
19
20
|
clickToCopyText: safeT(tFooter, 'clickToCopy', 'Click to copy'),
|
|
20
21
|
copiedText: safeT(tFooter, 'copied', 'Copied!'),
|
|
21
22
|
};
|
|
22
|
-
return (jsx("div", { className: "mb-10 w-full mx-auto border-t-purple-700/80 border-t", children: jsx("footer", { children: jsxs("div", { className: "w-full flex flex-col items-center justify-center px-4 py-8 space-y-3", children: [jsxs("div", { className: "flex flex-wrap items-center justify-center gap-x-2 gap-y-2 text-xs sm:text-sm sm:gap-x-6", children: [jsxs(Link, { href:
|
|
23
|
+
return (jsx("div", { className: "mb-10 w-full mx-auto border-t-purple-700/80 border-t", children: jsx("footer", { children: jsxs("div", { className: "w-full flex flex-col items-center justify-center px-4 py-8 space-y-3", children: [jsxs("div", { className: "flex flex-wrap items-center justify-center gap-x-2 gap-y-2 text-xs sm:text-sm sm:gap-x-6", children: [jsxs(Link, { href: getAsNeededLocalizedUrl(locale, "/legal/terms", localPrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsx(globalLucideIcons.ReceiptText, { className: "h-3.5 w-3.5" }), jsx("span", { children: data.terms })] }), jsxs(Link, { href: getAsNeededLocalizedUrl(locale, "/legal/privacy", localPrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsx(globalLucideIcons.ShieldUser, { className: "h-3.5 w-3.5" }), jsx("span", { children: data.privacy })] }), jsxs(FooterEmail, { email: data.email, clickToCopyText: data.clickToCopyText, copiedText: data.copiedText, children: [jsx(globalLucideIcons.Mail, { className: "h-3.5 w-3.5" }), jsx("span", { children: data.contactUs })] })] }), jsx("div", { className: "text-xs sm:text-sm text-center", children: jsx("span", { children: data.copyright }) })] }) }) }));
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.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",
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"import": "./dist/clerk/server.mjs",
|
|
17
17
|
"require": "./dist/clerk/server.js"
|
|
18
18
|
},
|
|
19
|
+
"./clerk/patch/optional-auth": {
|
|
20
|
+
"types": "./dist/clerk/patch/optional-auth.d.ts",
|
|
21
|
+
"import": "./dist/clerk/patch/optional-auth.mjs",
|
|
22
|
+
"require": "./dist/clerk/patch/optional-auth.js"
|
|
23
|
+
},
|
|
19
24
|
"./fingerprint": {
|
|
20
25
|
"types": "./dist/clerk/fingerprint/index.d.ts",
|
|
21
26
|
"import": "./dist/clerk/fingerprint/index.mjs",
|
|
@@ -81,8 +86,8 @@
|
|
|
81
86
|
"react-medium-image-zoom": "^5.2.14",
|
|
82
87
|
"swiper": "^12.0.3",
|
|
83
88
|
"zod": "^4.1.12",
|
|
84
|
-
"@windrun-huaiin/base-ui": "^
|
|
85
|
-
"@windrun-huaiin/lib": "^
|
|
89
|
+
"@windrun-huaiin/base-ui": "^12.0.0",
|
|
90
|
+
"@windrun-huaiin/lib": "^12.0.0"
|
|
86
91
|
},
|
|
87
92
|
"peerDependencies": {
|
|
88
93
|
"clsx": "^2.1.1",
|
|
@@ -7,6 +7,10 @@ import React from 'react';
|
|
|
7
7
|
interface ClerkProviderClientProps {
|
|
8
8
|
children: React.ReactNode;
|
|
9
9
|
locale: string;
|
|
10
|
+
// Whether localePrefix is set to 'as-needed' (default: true)
|
|
11
|
+
localPrefixAsNeeded?: boolean;
|
|
12
|
+
// The default locale used by the host app (default: 'en')
|
|
13
|
+
defaultLocale?: string;
|
|
10
14
|
signInUrl?: string;
|
|
11
15
|
signUpUrl?: string;
|
|
12
16
|
fallbackSignInUrl?: string;
|
|
@@ -17,13 +21,25 @@ interface ClerkProviderClientProps {
|
|
|
17
21
|
export function ClerkProviderClient({
|
|
18
22
|
children,
|
|
19
23
|
locale,
|
|
24
|
+
localPrefixAsNeeded = true,
|
|
25
|
+
defaultLocale = 'en',
|
|
20
26
|
signInUrl,
|
|
21
27
|
signUpUrl,
|
|
22
28
|
fallbackSignInUrl,
|
|
23
29
|
fallbackSignUpUrl,
|
|
24
30
|
waitlistUrl,
|
|
25
31
|
}: ClerkProviderClientProps) {
|
|
26
|
-
const currentLocalization =
|
|
32
|
+
const currentLocalization =
|
|
33
|
+
clerkIntl[locale as keyof typeof clerkIntl] ??
|
|
34
|
+
clerkIntl[defaultLocale as keyof typeof clerkIntl] ??
|
|
35
|
+
clerkIntl.en;
|
|
36
|
+
|
|
37
|
+
// In as-needed mode, skip prefixing for the default locale so /sign-in stays unprefixed.
|
|
38
|
+
const shouldPrefixLocale = localPrefixAsNeeded ? locale !== defaultLocale : true;
|
|
39
|
+
const localeSegment = shouldPrefixLocale && locale ? `/${locale}` : '';
|
|
40
|
+
|
|
41
|
+
const buildUrl = (path?: string) =>
|
|
42
|
+
path ? `${localeSegment}${path}` : undefined;
|
|
27
43
|
|
|
28
44
|
// build the ClerkProvider props, only add when the parameter is not empty
|
|
29
45
|
const clerkProviderProps: Record<string, any> = {
|
|
@@ -31,20 +47,29 @@ export function ClerkProviderClient({
|
|
|
31
47
|
};
|
|
32
48
|
|
|
33
49
|
// Only add URL when the parameter is not empty
|
|
34
|
-
|
|
35
|
-
|
|
50
|
+
const signInWithLocale = buildUrl(signInUrl);
|
|
51
|
+
if (signInWithLocale) {
|
|
52
|
+
clerkProviderProps.signInUrl = signInWithLocale;
|
|
36
53
|
}
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
|
|
55
|
+
const signUpWithLocale = buildUrl(signUpUrl);
|
|
56
|
+
if (signUpWithLocale) {
|
|
57
|
+
clerkProviderProps.signUpUrl = signUpWithLocale;
|
|
39
58
|
}
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
|
|
60
|
+
const signInFallbackWithLocale = buildUrl(fallbackSignInUrl);
|
|
61
|
+
if (signInFallbackWithLocale) {
|
|
62
|
+
clerkProviderProps.signInFallbackRedirectUrl = signInFallbackWithLocale;
|
|
42
63
|
}
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
|
|
65
|
+
const signUpFallbackWithLocale = buildUrl(fallbackSignUpUrl);
|
|
66
|
+
if (signUpFallbackWithLocale) {
|
|
67
|
+
clerkProviderProps.signUpFallbackRedirectUrl = signUpFallbackWithLocale;
|
|
45
68
|
}
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
|
|
70
|
+
const waitlistWithLocale = buildUrl(waitlistUrl);
|
|
71
|
+
if (waitlistWithLocale) {
|
|
72
|
+
clerkProviderProps.waitlistUrl = waitlistWithLocale;
|
|
48
73
|
}
|
|
49
74
|
|
|
50
75
|
// console.log('ClerkProviderClient props:', clerkProviderProps);
|
|
@@ -54,4 +79,4 @@ export function ClerkProviderClient({
|
|
|
54
79
|
{children}
|
|
55
80
|
</ClerkProvider>
|
|
56
81
|
);
|
|
57
|
-
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { auth } from '@clerk/nextjs/server';
|
|
2
|
+
|
|
3
|
+
export type OptionalAuthResult = {
|
|
4
|
+
userId: string | null;
|
|
5
|
+
sessionId: string | null;
|
|
6
|
+
raw: Awaited<ReturnType<typeof auth>> | null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 可选鉴权:在缺少 Clerk 标记或未登录时返回 null,避免 auth() 抛错。
|
|
11
|
+
* 仅供服务端使用,请从 @third-ui/clerk/patch/optional-auth 导入。
|
|
12
|
+
*/
|
|
13
|
+
export async function getOptionalAuth(): Promise<OptionalAuthResult> {
|
|
14
|
+
try {
|
|
15
|
+
const res = await auth();
|
|
16
|
+
return {
|
|
17
|
+
userId: res.userId ?? null,
|
|
18
|
+
sessionId: res.sessionId ?? null,
|
|
19
|
+
raw: res,
|
|
20
|
+
};
|
|
21
|
+
} catch {
|
|
22
|
+
return { userId: null, sessionId: null, raw: null };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -86,6 +86,14 @@ export interface CustomHomeLayoutProps {
|
|
|
86
86
|
* Customize the order of header action items.
|
|
87
87
|
*/
|
|
88
88
|
actionOrders?: HeaderActionOrders;
|
|
89
|
+
/**
|
|
90
|
+
* Whether localePrefix is set to 'as-needed' (default: true)
|
|
91
|
+
*/
|
|
92
|
+
localPrefixAsNeeded?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* The default locale for the application (default: 'en')
|
|
95
|
+
*/
|
|
96
|
+
defaultLocale?: string;
|
|
89
97
|
children?: ReactNode;
|
|
90
98
|
}
|
|
91
99
|
|
|
@@ -112,6 +120,8 @@ export function CustomHomeLayout({
|
|
|
112
120
|
style,
|
|
113
121
|
floatingNav = false,
|
|
114
122
|
actionOrders,
|
|
123
|
+
localPrefixAsNeeded = true,
|
|
124
|
+
defaultLocale = 'en',
|
|
115
125
|
}: CustomHomeLayoutProps) {
|
|
116
126
|
const resolvedBannerHeight = bannerHeight ?? (showBanner ? 3 : 0.5);
|
|
117
127
|
const resolvedPaddingTop =
|
|
@@ -161,7 +171,7 @@ export function CustomHomeLayout({
|
|
|
161
171
|
style={layoutStyle}
|
|
162
172
|
>
|
|
163
173
|
{children}
|
|
164
|
-
{showFooter ? footer ?? <Footer locale={locale} /> : null}
|
|
174
|
+
{showFooter ? footer ?? <Footer locale={locale} localPrefixAsNeeded={localPrefixAsNeeded} defaultLocale={defaultLocale} /> : null}
|
|
165
175
|
{showGoToTop ? goToTop ?? <GoToTop /> : null}
|
|
166
176
|
</HomeLayout>
|
|
167
177
|
</>
|
|
@@ -2,6 +2,7 @@ import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/page
|
|
|
2
2
|
import { ReactNode, ReactElement, cloneElement } from 'react';
|
|
3
3
|
import { TocFooterWrapper } from '@third-ui/fuma/mdx/toc-footer-wrapper';
|
|
4
4
|
import type { LLMCopyButtonProps, LLMCopyButton } from '@third-ui/fuma/mdx/toc-base';
|
|
5
|
+
import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
5
6
|
|
|
6
7
|
interface FumaPageParams {
|
|
7
8
|
/*
|
|
@@ -36,7 +37,7 @@ interface FumaPageParams {
|
|
|
36
37
|
* The fallback page component to use when the page is not found
|
|
37
38
|
*/
|
|
38
39
|
FallbackPage: React.ComponentType<{ siteIcon: ReactNode }>;
|
|
39
|
-
/*
|
|
40
|
+
/*
|
|
40
41
|
* Supported locales for generating alternates metadata, defaults to ['en']
|
|
41
42
|
*/
|
|
42
43
|
supportedLocales?: string[];
|
|
@@ -49,6 +50,16 @@ interface FumaPageParams {
|
|
|
49
50
|
|
|
50
51
|
// default false, for mobile style can cause issue
|
|
51
52
|
showTableOfContentPopover?: boolean;
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* Whether localePrefix is set to 'as-needed' (default: true)
|
|
56
|
+
*/
|
|
57
|
+
localPrefixAsNeeded?: boolean;
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* The default locale for the application (default: 'en')
|
|
61
|
+
*/
|
|
62
|
+
defaultLocale?: string;
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
export function createFumaPage({
|
|
@@ -64,11 +75,14 @@ export function createFumaPage({
|
|
|
64
75
|
showBreadcrumb = true,
|
|
65
76
|
showTableOfContent = true,
|
|
66
77
|
showTableOfContentPopover = false,
|
|
78
|
+
localPrefixAsNeeded = true,
|
|
79
|
+
defaultLocale = 'en',
|
|
67
80
|
}: FumaPageParams) {
|
|
68
81
|
const Page = async function Page({ params }: { params: Promise<{ locale: string; slug?: string[] }> }) {
|
|
69
82
|
const { slug, locale } = await params;
|
|
70
83
|
const page = mdxContentSource.getPage(slug, locale);
|
|
71
84
|
if (!page) {
|
|
85
|
+
console.log('[FumaPage] missing page', { slug, locale, available: mdxContentSource.pageTree?.[locale]?.children?.map((c: any) => c.url) });
|
|
72
86
|
return <FallbackPage siteIcon={siteIcon} />;
|
|
73
87
|
}
|
|
74
88
|
|
|
@@ -129,14 +143,15 @@ export function createFumaPage({
|
|
|
129
143
|
const baseRoute = mdxSourceDir.replace('src/mdx/', '');
|
|
130
144
|
// build the current page path
|
|
131
145
|
const currentPath = slug ? slug.join('/') : '';
|
|
132
|
-
const
|
|
146
|
+
const localizedPath = getAsNeededLocalizedUrl(locale || defaultLocale, `/${baseRoute}${currentPath ? `/${currentPath}` : ''}`, localPrefixAsNeeded, defaultLocale);
|
|
147
|
+
const currentUrl = `${baseUrl}${localizedPath}`;
|
|
133
148
|
|
|
134
149
|
// generate the seo language map
|
|
135
150
|
const seoLanguageMap: Record<string, string> = {};
|
|
136
151
|
|
|
137
|
-
|
|
138
152
|
supportedLocales.forEach(loc => {
|
|
139
|
-
|
|
153
|
+
const seoPath = getAsNeededLocalizedUrl(loc, `/${baseRoute}${currentPath ? `/${currentPath}` : ''}`, localPrefixAsNeeded, defaultLocale);
|
|
154
|
+
seoLanguageMap[loc] = `${baseUrl}${seoPath}`;
|
|
140
155
|
});
|
|
141
156
|
|
|
142
157
|
return {
|
package/src/lib/seo-util.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { MetadataRoute } from 'next';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Generate robots.txt content
|
|
@@ -23,13 +24,17 @@ export function generateRobots(baseUrl: string): MetadataRoute.Robots {
|
|
|
23
24
|
* @param locales - Supported locales array
|
|
24
25
|
* @param mdxSourceDir - MDX source directory path
|
|
25
26
|
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
27
|
+
* @param localPrefixAsNeeded - Whether localePrefix is set to 'as-needed' (default: true)
|
|
28
|
+
* @param defaultLocale - The default locale for the application (default: 'en')
|
|
26
29
|
* @returns Sitemap entries
|
|
27
30
|
*/
|
|
28
31
|
export function generateSitemap(
|
|
29
32
|
baseUrl: string,
|
|
30
33
|
locales: string[],
|
|
31
34
|
mdxSourceDir: string,
|
|
32
|
-
openMdxSEOSiteMap: boolean = true
|
|
35
|
+
openMdxSEOSiteMap: boolean = true,
|
|
36
|
+
localPrefixAsNeeded: boolean = true,
|
|
37
|
+
defaultLocale: string = 'en'
|
|
33
38
|
): MetadataRoute.Sitemap {
|
|
34
39
|
// 2. handle index.mdx (blog start page) and other slugs
|
|
35
40
|
const blogRoutes: MetadataRoute.Sitemap = [];
|
|
@@ -46,16 +51,18 @@ export function generateSitemap(
|
|
|
46
51
|
for (const locale of locales) {
|
|
47
52
|
for (const f of blogFiles) {
|
|
48
53
|
if (f === 'index.mdx') {
|
|
54
|
+
const localizedPath = getAsNeededLocalizedUrl(locale, '/blog', localPrefixAsNeeded, defaultLocale);
|
|
49
55
|
blogRoutes.push({
|
|
50
|
-
url: `${baseUrl}
|
|
56
|
+
url: `${baseUrl}${localizedPath}`,
|
|
51
57
|
lastModified: new Date(),
|
|
52
58
|
changeFrequency: 'daily',
|
|
53
59
|
priority: 1.0
|
|
54
60
|
});
|
|
55
61
|
} else {
|
|
56
62
|
const slug = f.replace(/\.mdx$/, '');
|
|
63
|
+
const localizedPath = getAsNeededLocalizedUrl(locale, `/blog/${slug}`, localPrefixAsNeeded, defaultLocale);
|
|
57
64
|
blogRoutes.push({
|
|
58
|
-
url: `${baseUrl}
|
|
65
|
+
url: `${baseUrl}${localizedPath}`,
|
|
59
66
|
lastModified: new Date(),
|
|
60
67
|
changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',
|
|
61
68
|
priority: 0.8
|
|
@@ -71,12 +78,15 @@ export function generateSitemap(
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
// 3. main page (all language versions)
|
|
74
|
-
const mainRoutes = locales.map(locale =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
const mainRoutes = locales.map(locale => {
|
|
82
|
+
const localizedPath = getAsNeededLocalizedUrl(locale, '/', localPrefixAsNeeded, defaultLocale);
|
|
83
|
+
return {
|
|
84
|
+
url: `${baseUrl}${localizedPath}`,
|
|
85
|
+
lastModified: new Date(),
|
|
86
|
+
changeFrequency: 'weekly' as const,
|
|
87
|
+
priority: 1.0
|
|
88
|
+
};
|
|
89
|
+
});
|
|
80
90
|
|
|
81
91
|
return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
|
|
82
92
|
}
|
|
@@ -98,21 +108,25 @@ export function createRobotsHandler(baseUrl: string) {
|
|
|
98
108
|
* @param locales - Supported locales array
|
|
99
109
|
* @param mdxSourceDir - MDX source directory path, default is empty
|
|
100
110
|
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
111
|
+
* @param localPrefixAsNeeded - Whether localePrefix is set to 'as-needed' (default: true)
|
|
112
|
+
* @param defaultLocale - The default locale for the application (default: 'en')
|
|
101
113
|
* @returns Sitemap handler function
|
|
102
114
|
*/
|
|
103
115
|
export function createSitemapHandler(
|
|
104
116
|
baseUrl: string,
|
|
105
117
|
locales: string[],
|
|
106
118
|
mdxSourceDir: string = '',
|
|
107
|
-
openMdxSEOSiteMap: boolean = true
|
|
119
|
+
openMdxSEOSiteMap: boolean = true,
|
|
120
|
+
localPrefixAsNeeded: boolean = true,
|
|
121
|
+
defaultLocale: string = 'en'
|
|
108
122
|
) {
|
|
109
123
|
// force static generation
|
|
110
124
|
const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {
|
|
111
|
-
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
|
|
125
|
+
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap, localPrefixAsNeeded, defaultLocale);
|
|
112
126
|
};
|
|
113
|
-
|
|
127
|
+
|
|
114
128
|
// Add static generation directive
|
|
115
129
|
(sitemapHandler as any).dynamic = 'force-static';
|
|
116
|
-
|
|
130
|
+
|
|
117
131
|
return sitemapHandler;
|
|
118
132
|
}
|
|
@@ -370,7 +370,7 @@ export function CreditOverviewClient({
|
|
|
370
370
|
<div className="flex flex-col gap-2 sm:gap-3">
|
|
371
371
|
<div className="flex items-center justify-start rounded-full ">
|
|
372
372
|
<icons.Gem aria-hidden className="mr-2 h-6 w-6 sm:h-8 sm:w-8" />
|
|
373
|
-
<span className="text-
|
|
373
|
+
<span className="text-base sm:text-lg">{translations.totalLabel}</span>
|
|
374
374
|
</div>
|
|
375
375
|
<div className="flex justify-center text-3xl font-semibold leading-tight sm:text-4xl">
|
|
376
376
|
{formatNumber(locale, data.totalBalance)}
|
|
@@ -405,7 +405,7 @@ export function CreditOverviewClient({
|
|
|
405
405
|
{/* Credit Details Section */}
|
|
406
406
|
<section className="relative flex flex-col gap-3 rounded-2xl border p-4 shadow-inner sm:gap-2 sm:p-5">
|
|
407
407
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
408
|
-
<h3 className="text-base
|
|
408
|
+
<h3 className="text-base text-gray-500 dark:text-slate-100 sm:text-lg">
|
|
409
409
|
{translations.bucketsTitle}
|
|
410
410
|
</h3>
|
|
411
411
|
{hasBuckets ? (
|
|
@@ -437,7 +437,7 @@ export function CreditOverviewClient({
|
|
|
437
437
|
>
|
|
438
438
|
<div className="grid grid-cols-[1fr_auto] items-center gap-3 text-xs sm:text-sm">
|
|
439
439
|
<span className="flex min-w-0 items-center gap-2">
|
|
440
|
-
<span className="max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs
|
|
440
|
+
<span className="max-w-full truncate rounded-full bg-purple-50 px-2 py-1 text-xs text-purple-600 shadow-sm dark:bg-purple-500/20 dark:text-purple-100 sm:text-sm">
|
|
441
441
|
{bucket.computedLabel}
|
|
442
442
|
</span>
|
|
443
443
|
</span>
|
|
@@ -451,7 +451,7 @@ export function CreditOverviewClient({
|
|
|
451
451
|
</span>
|
|
452
452
|
</div>
|
|
453
453
|
<div className="mt-3 flex justify-end gap-2">
|
|
454
|
-
<span className="text-[11px]
|
|
454
|
+
<span className="text-[11px] text-gray-500 dark:text-slate-100 sm:text-xs">
|
|
455
455
|
{translations.expiredAtLabel}: {bucket.expiresAt}
|
|
456
456
|
</span>
|
|
457
457
|
</div>
|
|
@@ -32,7 +32,7 @@ export function FooterEmail({ email, clickToCopyText, copiedText, children }: Fo
|
|
|
32
32
|
|
|
33
33
|
return (
|
|
34
34
|
<div className="relative group">
|
|
35
|
-
<div className="absolute left-2/3
|
|
35
|
+
<div className="absolute right-0 sm:right-auto sm:left-2/3 sm:-translate-x-1/4 bottom-full pb-1 hidden group-hover:block z-10">
|
|
36
36
|
<div
|
|
37
37
|
className="bg-zinc-600 text-white text-xs rounded px-3 py-1 whitespace-nowrap shadow-lg cursor-pointer select-text"
|
|
38
38
|
onMouseDown={handleCopy}
|