@windrun-huaiin/lib 3.1.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.
@@ -0,0 +1,165 @@
1
+ // Supported languages and their labels
2
+ const ALL_LOCALE_LABELS = {
3
+ en: "English",
4
+ zh: "简体中文",
5
+ ja: "日本語",
6
+ ko: "한국어",
7
+ fr: "Français",
8
+ de: "Deutsch",
9
+ es: "Español",
10
+ it: "Italiano",
11
+ pt: "Português",
12
+ tr: "Türkçe",
13
+ pl: "Polski",
14
+ ru: "Русский",
15
+ ar: "العربية",
16
+ hi: "हिन्दी",
17
+ th: "ไทย",
18
+ vi: "Tiếng Việt",
19
+ } as const;
20
+
21
+ export type SupportedLocale = keyof typeof ALL_LOCALE_LABELS;
22
+
23
+ // Helper function to get language configuration from environment variables
24
+ function getLocaleLabels(locales: string[]) {
25
+ return Object.fromEntries(
26
+ locales.map(locale => [
27
+ locale,
28
+ ALL_LOCALE_LABELS[locale as SupportedLocale] || locale
29
+ ])
30
+ );
31
+ }
32
+
33
+ // Common application configuration creation function
34
+ export function createCommonAppConfig(options?: {
35
+ // Optional: manually specify supported languages, otherwise read from environment variables
36
+ locales?: string[];
37
+ defaultLocale?: string;
38
+ }) {
39
+ // Priority: manual configuration > environment variables > default values
40
+ const locales = options?.locales ??
41
+ process.env.NEXT_PUBLIC_I18N_LOCALES?.split(',').map(s => s.trim()) ??
42
+ ['en', 'zh'];
43
+
44
+ const defaultLocale = options?.defaultLocale ??
45
+ process.env.NEXT_PUBLIC_I18N_DEFAULT_LOCALE ??
46
+ 'en';
47
+
48
+ const storagePrefix = process.env.NEXT_PUBLIC_I18N_STORAGE_PREFIX || 'WINDRUN-HUAIIN';
49
+
50
+ const config = {
51
+ // Basic configuration
52
+ baseUrl: process.env.NEXT_PUBLIC_BASE_URL || '',
53
+ githubBaseUrl: process.env.NEXT_PUBLIC_GITHUB_BASE_URL || '',
54
+ github: process.env.NEXT_PUBLIC_GITHUB || '',
55
+ githubInfoToken: process.env.NEXT_PUBLIC_FUMA_GITHUB_TOKEN || '',
56
+
57
+ // Internationalization configuration
58
+ i18n: {
59
+ locales: locales as readonly string[],
60
+ defaultLocale,
61
+ localeLabels: getLocaleLabels(locales),
62
+ detector: {
63
+ storageKey: process.env.NEXT_PUBLIC_I18N_STORAGE_KEY || 'language-preference-status',
64
+ autoCloseTimeout: parseInt(process.env.NEXT_PUBLIC_I18N_AUTO_CLOSE_TIMEOUT || '10000'),
65
+ expirationDays: parseInt(process.env.NEXT_PUBLIC_I18N_EXPIRATION_DAYS || '30'),
66
+ storagePrefix
67
+ },
68
+ messageRoot: process.env.NEXT_PUBLIC_I18N_MESSAGE_ROOT || 'messages',
69
+ },
70
+
71
+ // Style configuration
72
+ style: {
73
+ icon: {
74
+ uniformColor: process.env.NEXT_PUBLIC_STYLE_ICON_COLOR || "text-purple-500"
75
+ },
76
+ showBanner: process.env.NEXT_PUBLIC_STYLE_SHOW_BANNER === 'true',
77
+ clerkAuthInModal: process.env.NEXT_PUBLIC_STYLE_CLERK_AUTH_IN_MODAL === 'true',
78
+ clerkPageBanner: process.env.NEXT_PUBLIC_STYLE_CLERK_PAGE_BANNER === 'true',
79
+ watermark: {
80
+ enabled: process.env.NEXT_PUBLIC_STYLE_WATERMARK_ENABLED === 'true',
81
+ text: process.env.NEXT_PUBLIC_STYLE_WATERMARK_TEXT || "巽川·怀因"
82
+ },
83
+ cdnBaseUrl: process.env.NEXT_PUBLIC_STYLE_CDN_BASE_URL || "https://raw.githubusercontent.com/caofanCPU/wind-run-1/main/public",
84
+ placeHolder: {
85
+ image: process.env.NEXT_PUBLIC_STYLE_PLACEHOLDER_IMAGE || "/default.webp"
86
+ }
87
+ },
88
+
89
+ // Clerk configuration
90
+ clerk: {
91
+ signInUrl: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL || "/sign-in",
92
+ fallbackSignInUrl: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL || "/",
93
+ signUpUrl: process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL || "/sign-up",
94
+ fallbackSignUpUrl: process.env.NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL || "/",
95
+ waitlistUrl: process.env.NEXT_PUBLIC_CLERK_WAITLIST_URL || "/waitlist",
96
+ debug: process.env.CLERK_DEBUG === 'true',
97
+ },
98
+
99
+ // MDX source file directory configuration
100
+ mdxSourceDir: {
101
+ docs: process.env.NEXT_PUBLIC_MDX_DOCS_DIR || "src/mdx/docs",
102
+ blog: process.env.NEXT_PUBLIC_MDX_BLOG_DIR || "src/mdx/blog",
103
+ legal: process.env.NEXT_PUBLIC_MDX_LEGAL_DIR || "src/mdx/legal"
104
+ },
105
+ };
106
+
107
+ // Convenient constants - avoid deep nested access
108
+ const shortcuts = {
109
+ iconColor: config.style.icon.uniformColor,
110
+ watermark: config.style.watermark,
111
+ showBanner: config.style.showBanner,
112
+ clerkPageBanner: config.style.clerkPageBanner,
113
+ clerkAuthInModal: config.style.clerkAuthInModal,
114
+ placeHolderImage: config.style.placeHolder.image,
115
+ clerk: config.clerk,
116
+ };
117
+
118
+ return {
119
+ ...config,
120
+ shortcuts
121
+ };
122
+ }
123
+
124
+ // Create internationalization helper functions
125
+ export function createI18nHelpers(i18nConfig: ReturnType<typeof createCommonAppConfig>['i18n']) {
126
+ function isSupportedLocale(locale: string): locale is typeof i18nConfig.locales[number] {
127
+ return (i18nConfig.locales as readonly string[]).includes(locale);
128
+ }
129
+
130
+ function getValidLocale(locale: string): typeof i18nConfig.locales[number] {
131
+ return isSupportedLocale(locale) ? locale : i18nConfig.defaultLocale;
132
+ }
133
+
134
+ const generatedLocales = i18nConfig.locales.map((loc) => ({
135
+ name: i18nConfig.localeLabels[loc as keyof typeof i18nConfig.localeLabels] || loc,
136
+ locale: loc,
137
+ }));
138
+
139
+ return {
140
+ isSupportedLocale,
141
+ getValidLocale,
142
+ generatedLocales
143
+ };
144
+ }
145
+
146
+ // Convenient configuration presets
147
+ export const LOCALE_PRESETS = {
148
+ // Only support English
149
+ EN_ONLY: { locales: ['en'] as string[], defaultLocale: 'en' as string },
150
+
151
+ // English and Chinese
152
+ EN_ZH: { locales: ['en', 'zh'] as string[], defaultLocale: 'en' as string },
153
+
154
+ // Main Asian languages
155
+ ASIA: { locales: ['en', 'zh', 'ja', 'ko'] as string[], defaultLocale: 'en' as string },
156
+
157
+ // Main European languages
158
+ EUROPE: { locales: ['en', 'fr', 'de', 'es', 'it'] as string[], defaultLocale: 'en' as string },
159
+
160
+ // Globalization
161
+ GLOBAL: { locales: ['en', 'zh', 'ja', 'ko', 'fr', 'de', 'es', 'it', 'pt', 'ru'] as string[], defaultLocale: 'en' as string },
162
+
163
+ // No internationalization (only default language)
164
+ NONE: { locales: [] as string[], defaultLocale: 'en' as string }
165
+ };
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ // export the utility functions
2
+ export * from './utils';
3
+
4
+ // export the icons
5
+ export * from './limited-lucide-icons';
6
+
7
+ // export the LLM related functions
8
+ export * from './llm-utils';
9
+
10
+ // export the common app config
11
+ export * from './common-app-config';
@@ -0,0 +1,86 @@
1
+ /*
2
+ * This file re-exports selected icons from 'lucide-react'.
3
+ * This is the single place to manage which lucide-react icons are available globally.
4
+ * Editing the list of exports here will automatically update their availability
5
+ * in globalLucideIcons.
6
+ */
7
+ export {
8
+ AlbumIcon,
9
+ AlignHorizontalJustifyEnd,
10
+ ArrowLeft,
11
+ ArrowRight,
12
+ ArrowUp,
13
+ Binary,
14
+ Blocks,
15
+ BookX,
16
+ BringToFront,
17
+ Building2,
18
+ Bug,
19
+ Car,
20
+ Circle,
21
+ CircleAlert,
22
+ CircleSmall,
23
+ Check,
24
+ ChevronDown,
25
+ ChevronLeft,
26
+ ChevronRight,
27
+ ChevronUp,
28
+ Cpu,
29
+ ComponentIcon,
30
+ DatabaseZap,
31
+ Dot,
32
+ Download,
33
+ Eye,
34
+ ExternalLink,
35
+ Facebook,
36
+ FileLock2,
37
+ Fingerprint,
38
+ Gift,
39
+ GitPullRequestArrow,
40
+ Globe,
41
+ GlobeLock,
42
+ GripVertical,
43
+ HandHeart,
44
+ Handshake,
45
+ Highlighter,
46
+ HousePlus,
47
+ Info,
48
+ ImageDown,
49
+ ImageOff,
50
+ ImageUp,
51
+ Keyboard,
52
+ LandPlot,
53
+ Layout,
54
+ LayoutTemplate,
55
+ LibraryIcon,
56
+ Link,
57
+ Loader2,
58
+ LogIn,
59
+ LogOut,
60
+ MoreHorizontal,
61
+ MousePointerClick,
62
+ PanelLeft,
63
+ PanelsTopLeft,
64
+ Pencil,
65
+ Pi,
66
+ Palette,
67
+ ReceiptText,
68
+ Regex,
69
+ Replace,
70
+ Rss,
71
+ Scale,
72
+ Search,
73
+ Share,
74
+ ShieldUser,
75
+ SquareDashedBottomCode,
76
+ SquareTerminal,
77
+ Server,
78
+ SplinePointer,
79
+ Sparkles,
80
+ Star,
81
+ Tablets,
82
+ Terminal,
83
+ Twitter,
84
+ X,
85
+ Zap
86
+ } from 'lucide-react';
@@ -0,0 +1,50 @@
1
+ import { remark } from 'remark';
2
+ import remarkGfm from 'remark-gfm';
3
+ import remarkMdx from 'remark-mdx';
4
+ import remarkFrontmatter from 'remark-frontmatter';
5
+ import { visit } from 'unist-util-visit';
6
+
7
+ function remarkRemoveFrontmatter() {
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ return (tree: any) => {
10
+ visit(tree, 'yaml', (_node, index, parent) => {
11
+ if (parent && typeof index === 'number') {
12
+ parent.children.splice(index, 1);
13
+ }
14
+ });
15
+ };
16
+ }
17
+
18
+ // remark(), parse the MDX file into MDAST
19
+ // remarkPlugins(), parse the MDAST into HAST
20
+ // rehypePlugins(), render the HAST into React components, i.e. HTML code
21
+ const processor = remark()
22
+ // parse the md file header
23
+ .use(remarkFrontmatter, ['yaml'])
24
+ // remove the md file header
25
+ .use(remarkRemoveFrontmatter)
26
+ .use(remarkMdx)
27
+ .use(remarkGfm);
28
+
29
+ export async function getLLMText(mdxContent: string, title?: string, description?: string) {
30
+ if (typeof mdxContent !== 'string') {
31
+ console.error('getLLMText: mdxContent received was not a string. Type:', typeof mdxContent);
32
+ return `# Error\n\nInvalid content received by text processor.`;
33
+ }
34
+
35
+ try {
36
+ const processed = await processor.process(mdxContent);
37
+ const contentWithoutFrontmatter = processed.value as string;
38
+
39
+ const markdownParts = [
40
+ title ? `# ${title}` : null,
41
+ description,
42
+ contentWithoutFrontmatter.trim()
43
+ ];
44
+
45
+ return markdownParts.filter(part => part != null).join('\n\n');
46
+ } catch (processingError) {
47
+ console.error('Error during remark processing in getLLMText:', processingError);
48
+ return `# Error\n\nError processing MDX content.`;
49
+ }
50
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+ import { format, isValid } from 'date-fns';
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs))
7
+ }
8
+
9
+ export function formatTimestamp(timestamp: string, formatter: string) {
10
+ const fail = "";
11
+ if (!timestamp) {
12
+ return fail;
13
+ }
14
+
15
+ // Assume gitTimestamp is a millisecond timestamp string
16
+ const timestampMs = parseInt(timestamp, 10);
17
+ if (isNaN(timestampMs)) {
18
+ return fail;
19
+ }
20
+
21
+ const date = new Date(timestampMs); // or if it is determined to be seconds, use fromUnixTime(timestampSeconds)
22
+
23
+ // Check if the date is valid
24
+ if (!isValid(date)) {
25
+ return fail;
26
+ }
27
+
28
+ // Format the date
29
+ try {
30
+ // 'yyyy-MM-dd HH:mm:ss' is the date-fns formatting pattern
31
+ return format(date, formatter);
32
+ } catch (error) {
33
+ // format may also throw an error due to an invalid date (although isValid should have already caught it)
34
+ console.error("Error formatting date:", error);
35
+ return fail;
36
+ }
37
+ }