@maiyunnet/kebab 9.2.1 → 9.2.2

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/doc/kebab-rag.md CHANGED
@@ -1360,7 +1360,7 @@ index/variables/VER.md
1360
1360
 
1361
1361
  # Variable: VER
1362
1362
 
1363
- > `const` **VER**: `"9.2.1"` = `'9.2.1'`
1363
+ > `const` **VER**: `"9.2.2"` = `'9.2.2'`
1364
1364
 
1365
1365
  Defined in: [index.ts:10](https://github.com/maiyunnet/kebab/blob/master/index.ts#L10)
1366
1366
 
@@ -10514,7 +10514,7 @@ Defined in: [lib/net/formdata.ts:37](https://github.com/maiyunnet/kebab/blob/mas
10514
10514
 
10515
10515
  > **new FormData**(`options?`): `FormData`
10516
10516
 
10517
- Defined in: node\_modules/@types/node/stream.d.ts:99
10517
+ Defined in: node\_modules/@types/node/stream.d.ts:80
10518
10518
 
10519
10519
  #### Parameters
10520
10520
 
@@ -15691,6 +15691,72 @@ lib/ssh/shell/index.md
15691
15691
 
15692
15692
  - [Connection](classes/Connection.md)
15693
15693
 
15694
+ lib/text/functions/getFileExt.md
15695
+ ---
15696
+
15697
+ [**Documents for @maiyunnet/kebab**](../../../index.md)
15698
+
15699
+ ***
15700
+
15701
+ [Documents for @maiyunnet/kebab](../../../index.md) / [lib/text](../index.md) / getFileExt
15702
+
15703
+ # Function: getFileExt()
15704
+
15705
+ > **getFileExt**(`path`): `string`
15706
+
15707
+ Defined in: [lib/text.ts:527](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L527)
15708
+
15709
+ 获取文件后缀
15710
+
15711
+ ## Parameters
15712
+
15713
+ ### path
15714
+
15715
+ `string`
15716
+
15717
+ 文件路径
15718
+
15719
+ ## Returns
15720
+
15721
+ `string`
15722
+
15723
+ lib/text/functions/getFileNameExt.md
15724
+ ---
15725
+
15726
+ [**Documents for @maiyunnet/kebab**](../../../index.md)
15727
+
15728
+ ***
15729
+
15730
+ [Documents for @maiyunnet/kebab](../../../index.md) / [lib/text](../index.md) / getFileNameExt
15731
+
15732
+ # Function: getFileNameExt()
15733
+
15734
+ > **getFileNameExt**(`path`): `object`
15735
+
15736
+ Defined in: [lib/text.ts:540](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L540)
15737
+
15738
+ 获取文件名和后缀
15739
+
15740
+ ## Parameters
15741
+
15742
+ ### path
15743
+
15744
+ `string`
15745
+
15746
+ 文件路径
15747
+
15748
+ ## Returns
15749
+
15750
+ `object`
15751
+
15752
+ ### ext
15753
+
15754
+ > **ext**: `string`
15755
+
15756
+ ### name
15757
+
15758
+ > **name**: `string`
15759
+
15694
15760
  lib/text/functions/getFilename.md
15695
15761
  ---
15696
15762
 
@@ -15702,9 +15768,9 @@ lib/text/functions/getFilename.md
15702
15768
 
15703
15769
  # Function: getFilename()
15704
15770
 
15705
- > **getFilename**(`path`): `string`
15771
+ > **getFilename**(`path`, `ext?`): `string`
15706
15772
 
15707
- Defined in: [lib/text.ts:506](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L506)
15773
+ Defined in: [lib/text.ts:507](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L507)
15708
15774
 
15709
15775
  获取文件名
15710
15776
 
@@ -15716,6 +15782,12 @@ Defined in: [lib/text.ts:506](https://github.com/maiyunnet/kebab/blob/master/lib
15716
15782
 
15717
15783
  文件路径
15718
15784
 
15785
+ ### ext?
15786
+
15787
+ `boolean` = `true`
15788
+
15789
+ 是否包含后缀,默认包含
15790
+
15719
15791
  ## Returns
15720
15792
 
15721
15793
  `string`
@@ -15762,7 +15834,7 @@ lib/text/functions/int2str.md
15762
15834
 
15763
15835
  > **int2str**(`int`, `digits?`, `decimal?`): `string`
15764
15836
 
15765
- Defined in: [lib/text.ts:697](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L697)
15837
+ Defined in: [lib/text.ts:740](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L740)
15766
15838
 
15767
15839
  为解决精度问题,将整数转换为小数字符串
15768
15840
  以下几个示例都是当 digits 为 3、decimal 为 2 时
@@ -15895,7 +15967,7 @@ lib/text/functions/isFalsy.md
15895
15967
 
15896
15968
  > **isFalsy**(`val`): `val is TFalsy`
15897
15969
 
15898
- Defined in: [lib/text.ts:648](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L648)
15970
+ Defined in: [lib/text.ts:691](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L691)
15899
15971
 
15900
15972
  判断一个值是否是虚假的(为 null/undefined/空字符串/false/0)
15901
15973
 
@@ -16065,7 +16137,7 @@ lib/text/functions/isTruthy.md
16065
16137
 
16066
16138
  > **isTruthy**\<`T`\>(`val`): `val is Exclude<T, TFalsy>`
16067
16139
 
16068
- Defined in: [lib/text.ts:656](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L656)
16140
+ Defined in: [lib/text.ts:699](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L699)
16069
16141
 
16070
16142
  判断一个值是否是真实的(不为 null/undefined/空字符串/false/0)
16071
16143
 
@@ -16100,7 +16172,7 @@ lib/text/functions/logicalOr.md
16100
16172
 
16101
16173
  > **logicalOr**\<`T`, `T2`\>(`v1`, `v2`): `T` *extends* [`TFalsy`](../type-aliases/TFalsy.md) ? `T2` : `T`
16102
16174
 
16103
- Defined in: [lib/text.ts:665](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L665)
16175
+ Defined in: [lib/text.ts:708](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L708)
16104
16176
 
16105
16177
  类似 || 运算符的效果
16106
16178
 
@@ -16285,7 +16357,7 @@ lib/text/functions/parseJson.md
16285
16357
 
16286
16358
  > **parseJson**\<`T`\>(`str`): `false` \| `T`
16287
16359
 
16288
- Defined in: [lib/text.ts:559](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L559)
16360
+ Defined in: [lib/text.ts:602](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L602)
16289
16361
 
16290
16362
  将字符串解析为对象,返回 false 代表解析失败,支持 BigInt
16291
16363
 
@@ -16484,7 +16556,7 @@ lib/text/functions/str2int.md
16484
16556
 
16485
16557
  > **str2int**(`str`, `digits?`): `number`
16486
16558
 
16487
- Defined in: [lib/text.ts:679](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L679)
16559
+ Defined in: [lib/text.ts:722](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L722)
16488
16560
 
16489
16561
  为解决精度问题,将字符串数字转换为整数显示
16490
16562
  以下几个示例都是当 digits 为 2 时
@@ -16524,7 +16596,7 @@ lib/text/functions/stringifyBuffer.md
16524
16596
 
16525
16597
  > **stringifyBuffer**(`buf`): `string`
16526
16598
 
16527
- Defined in: [lib/text.ts:602](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L602)
16599
+ Defined in: [lib/text.ts:645](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L645)
16528
16600
 
16529
16601
  输出文本格式的 buffer
16530
16602
 
@@ -16553,7 +16625,7 @@ lib/text/functions/stringifyJson.md
16553
16625
 
16554
16626
  > **stringifyJson**(`obj`, `space?`): `string`
16555
16627
 
16556
- Defined in: [lib/text.ts:589](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L589)
16628
+ Defined in: [lib/text.ts:632](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L632)
16557
16629
 
16558
16630
  将对象转换为 json 字符串,返回 false 代表解析失败,支持 BigInt
16559
16631
 
@@ -16588,7 +16660,7 @@ lib/text/functions/stringifyResult.md
16588
16660
 
16589
16661
  > **stringifyResult**(`rtn`): `string`
16590
16662
 
16591
- Defined in: [lib/text.ts:519](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L519)
16663
+ Defined in: [lib/text.ts:562](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L562)
16592
16664
 
16593
16665
  将普通的返回 JSON 对象序列化为字符串
16594
16666
 
@@ -16617,7 +16689,7 @@ lib/text/functions/trimJson.md
16617
16689
 
16618
16690
  > **trimJson**(`json`): `any`
16619
16691
 
16620
- Defined in: [lib/text.ts:610](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L610)
16692
+ Defined in: [lib/text.ts:653](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L653)
16621
16693
 
16622
16694
  递归删除 json 中的字符串首尾空格,会返回一个新的对象
16623
16695
 
@@ -16724,7 +16796,9 @@ lib/text/index.md
16724
16796
 
16725
16797
  ## Functions
16726
16798
 
16799
+ - [getFileExt](functions/getFileExt.md)
16727
16800
  - [getFilename](functions/getFilename.md)
16801
+ - [getFileNameExt](functions/getFileNameExt.md)
16728
16802
  - [htmlescape](functions/htmlescape.md)
16729
16803
  - [int2str](functions/int2str.md)
16730
16804
  - [isAscii](functions/isAscii.md)
@@ -16815,7 +16889,7 @@ lib/text/type-aliases/TFalsy.md
16815
16889
 
16816
16890
  > **TFalsy** = `false` \| `""` \| `0` \| `null` \| `undefined` \| *typeof* `NaN`
16817
16891
 
16818
- Defined in: [lib/text.ts:642](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L642)
16892
+ Defined in: [lib/text.ts:685](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L685)
16819
16893
 
16820
16894
  虚假值类型
16821
16895
 
@@ -17389,7 +17463,7 @@ Defined in: [lib/undici/formdata.ts:37](https://github.com/maiyunnet/kebab/blob/
17389
17463
 
17390
17464
  > **new FormData**(`options?`): `FormData`
17391
17465
 
17392
- Defined in: node\_modules/@types/node/stream.d.ts:99
17466
+ Defined in: node\_modules/@types/node/stream.d.ts:80
17393
17467
 
17394
17468
  #### Parameters
17395
17469
 
package/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
6
  */
7
7
  /** --- 当前系统版本号 --- */
8
- export declare const VER = "9.2.1";
8
+ export declare const VER = "9.2.2";
9
9
  /** --- 框架根目录,以 / 结尾 --- */
10
10
  export declare const ROOT_PATH: string;
11
11
  /** --- 框架的 LIB,以 / 结尾 --- */
package/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
7
  */
8
8
  /** --- 当前系统版本号 --- */
9
- export const VER = '9.2.1';
9
+ export const VER = '9.2.2';
10
10
  // --- 服务端用的路径 ---
11
11
  const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
12
12
  /** --- /xxx/xxx --- */
package/lib/text.d.ts CHANGED
@@ -136,8 +136,22 @@ export declare function isRealPath(path: string): boolean;
136
136
  /**
137
137
  * --- 获取文件名 ---
138
138
  * @param path 文件路径
139
+ * @param ext 是否包含后缀,默认包含
139
140
  */
140
- export declare function getFilename(path: string): string;
141
+ export declare function getFilename(path: string, ext?: boolean): string;
142
+ /**
143
+ * --- 获取文件后缀 ---
144
+ * @param path 文件路径
145
+ */
146
+ export declare function getFileExt(path: string): string;
147
+ /**
148
+ * --- 获取文件名和后缀 ---
149
+ * @param path 文件路径
150
+ */
151
+ export declare function getFileNameExt(path: string): {
152
+ name: string;
153
+ ext: string;
154
+ };
141
155
  /**
142
156
  * --- 将普通的返回 JSON 对象序列化为字符串 ---
143
157
  * @param rtn 返回 JSON 对象
package/lib/text.js CHANGED
@@ -439,14 +439,52 @@ export function isRealPath(path) {
439
439
  /**
440
440
  * --- 获取文件名 ---
441
441
  * @param path 文件路径
442
+ * @param ext 是否包含后缀,默认包含
442
443
  */
443
- export function getFilename(path) {
444
+ export function getFilename(path, ext = true) {
444
445
  path = path.replace(/\\/g, '/');
445
446
  const lio = path.lastIndexOf('/');
446
- if (lio === -1) {
447
+ if (lio !== -1) {
448
+ path = path.slice(lio + 1);
449
+ }
450
+ if (ext) {
451
+ return path;
452
+ }
453
+ const dot = path.lastIndexOf('.');
454
+ if (dot === -1) {
447
455
  return path;
448
456
  }
449
- return path.slice(lio + 1);
457
+ return path.slice(0, dot);
458
+ }
459
+ /**
460
+ * --- 获取文件后缀 ---
461
+ * @param path 文件路径
462
+ */
463
+ export function getFileExt(path) {
464
+ const filename = getFilename(path);
465
+ const dot = filename.lastIndexOf('.');
466
+ if (dot === -1) {
467
+ return '';
468
+ }
469
+ return filename.slice(dot + 1).toLowerCase();
470
+ }
471
+ /**
472
+ * --- 获取文件名和后缀 ---
473
+ * @param path 文件路径
474
+ */
475
+ export function getFileNameExt(path) {
476
+ const filename = getFilename(path);
477
+ const dot = filename.lastIndexOf('.');
478
+ if (dot === -1) {
479
+ return {
480
+ 'name': filename,
481
+ 'ext': ''
482
+ };
483
+ }
484
+ return {
485
+ 'name': filename.slice(0, dot),
486
+ 'ext': filename.slice(dot + 1).toLowerCase()
487
+ };
450
488
  }
451
489
  /**
452
490
  * --- 将普通的返回 JSON 对象序列化为字符串 ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maiyunnet/kebab",
3
- "version": "9.2.1",
3
+ "version": "9.2.2",
4
4
  "description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -22,48 +22,48 @@
22
22
  "#kebab/*": "./*"
23
23
  },
24
24
  "dependencies": {
25
- "@aws-sdk/client-s3": "^3.1014.0",
26
- "@aws-sdk/lib-storage": "^3.1014.0",
25
+ "@aws-sdk/client-s3": "^3.1034.0",
26
+ "@aws-sdk/lib-storage": "^3.1034.0",
27
27
  "@litert/http-client": "^1.1.2",
28
28
  "@litert/mime": "^0.1.3",
29
- "@litert/redis": "^3.2.0",
29
+ "@litert/redis": "^3.2.1",
30
30
  "@litert/websocket": "^0.2.8",
31
31
  "@radix-ui/react-checkbox": "^1.3.3",
32
32
  "@radix-ui/react-label": "^2.1.8",
33
33
  "@radix-ui/react-slot": "^1.2.4",
34
34
  "@radix-ui/react-switch": "^1.2.6",
35
- "@tailwindcss/cli": "^4.2.2",
35
+ "@tailwindcss/cli": "^4.2.4",
36
36
  "@types/ssh2": "^1.15.5",
37
- "@zilliz/milvus2-sdk-node": "^2.6.11",
37
+ "@zilliz/milvus2-sdk-node": "^2.6.13",
38
38
  "ajv": "^8.18.0",
39
39
  "ajv-formats": "^3.0.1",
40
40
  "class-variance-authority": "^0.7.1",
41
41
  "clsx": "^2.1.1",
42
- "ejs": "^5.0.1",
43
- "esbuild": "^0.27.4",
42
+ "ejs": "^5.0.2",
43
+ "esbuild": "^0.28.0",
44
44
  "jszip": "^3.10.1",
45
- "mysql2": "^3.20.0",
45
+ "mysql2": "^3.22.2",
46
46
  "node-cron": "^4.2.1",
47
- "openai": "^6.32.0",
47
+ "openai": "^6.34.0",
48
48
  "pg": "^8.20.0",
49
- "react": "^19.2.4",
50
- "react-dom": "^19.2.4",
51
- "react-router-dom": "^7.13.1",
49
+ "react": "^19.2.5",
50
+ "react-dom": "^19.2.5",
51
+ "react-router-dom": "^7.14.2",
52
52
  "ssh2": "^1.17.0",
53
53
  "svg-captcha": "^1.4.0",
54
54
  "tailwind-merge": "^3.5.0",
55
- "tencentcloud-sdk-nodejs": "^4.1.199",
55
+ "tencentcloud-sdk-nodejs": "^4.1.219",
56
56
  "undici": "^8.1.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@litert/eslint-plugin-rules": "^0.3.1",
60
60
  "@types/ejs": "^3.1.5",
61
- "@types/node": "^25.5.0",
61
+ "@types/node": "^25.6.0",
62
62
  "@types/pg": "^8.20.0",
63
63
  "@types/react": "^19.2.14",
64
64
  "@types/react-dom": "^19.2.3",
65
- "typedoc": "^0.28.17",
65
+ "typedoc": "^0.28.19",
66
66
  "typedoc-plugin-markdown": "^4.11.0",
67
- "typescript": "^5.9.3"
67
+ "typescript": "^6.0.3"
68
68
  }
69
69
  }
@@ -136,9 +136,7 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
136
136
  setIsFetching(false);
137
137
  });
138
138
  }
139
- return (
140
- // --- 组件渲染完整 HTML 文档,无需外部 EJS 模板 ---
141
- _jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), _jsx("title", { children: title }), _jsx("link", { href: `${_urlStc}view/react.page.css?v=${_staticVer}`, rel: "stylesheet" })] }), _jsx("body", { className: "bg-slate-50 min-h-screen font-sans", children: _jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex gap-2 mb-2", children: [_jsx(Badge, { children: "SSR \u00B7 Kebab" }), _jsx(Badge, { variant: hydrated ? 'success' : 'warn', children: hydrated ? 'Hydrated ✓' : 'Rendering...' })] }), _jsx("h1", { className: "text-2xl font-bold text-slate-900", children: title }), _jsxs("p", { className: "text-slate-500 text-sm mt-1", children: [serverTime, " \u00B7 ", node] })] }), _jsx("div", { className: "flex gap-1 bg-slate-100 p-1 rounded-lg w-fit", children: ['overview', 'routing', 'fetch', 'shadcn'].map(t => (_jsx("button", { onClick: () => setTab(t), className: [
139
+ return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), _jsx("title", { children: title }), _jsx("link", { href: `${_urlStc}view/react.page.css?v=${_staticVer}`, rel: "stylesheet" })] }), _jsx("body", { className: "bg-slate-50 min-h-screen font-sans", children: _jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex gap-2 mb-2", children: [_jsx(Badge, { children: "SSR \u00B7 Kebab" }), _jsx(Badge, { variant: hydrated ? 'success' : 'warn', children: hydrated ? 'Hydrated ✓' : 'Rendering...' })] }), _jsx("h1", { className: "text-2xl font-bold text-slate-900", children: title }), _jsxs("p", { className: "text-slate-500 text-sm mt-1", children: [serverTime, " \u00B7 ", node] })] }), _jsx("div", { className: "flex gap-1 bg-slate-100 p-1 rounded-lg w-fit", children: ['overview', 'routing', 'fetch', 'shadcn'].map(t => (_jsx("button", { onClick: () => setTab(t), className: [
142
140
  'px-4 py-2 rounded-md text-sm font-medium transition-colors cursor-pointer',
143
141
  tab === t ? 'bg-white shadow text-slate-900' : 'text-slate-500 hover:text-slate-900',
144
142
  ].join(' '), children: t.charAt(0).toUpperCase() + t.slice(1) }, t))) }), tab === 'overview' && (_jsxs("div", { className: "space-y-4", children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "Counter\uFF08useState + hydration\uFF09" }), _jsx("p", { className: "text-slate-500 text-xs mb-4", children: "SSR renders with initial value 0; props are serialized as inline JSON. After hydration the state becomes interactive \u2014 click the buttons to test:" }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("button", { onClick: () => setCount(c => c - 1), className: "w-10 h-10 rounded-lg border border-slate-300 hover:bg-slate-50 font-bold text-slate-700 text-xl cursor-pointer", children: "\u2212" }), _jsx("span", { className: "text-3xl font-bold text-slate-900 w-10 text-center tabular-nums", children: count }), _jsx("button", { onClick: () => setCount(c => c + 1), className: "w-10 h-10 rounded-lg bg-blue-500 hover:bg-blue-600 text-white font-bold text-xl cursor-pointer", children: "+" })] })] }), _jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-3", children: "Server Props (from Ctr method)" }), _jsxs("p", { className: "text-slate-500 text-xs mb-3", children: ["Passed via", ' ', _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "_loadReactPage(path, props)" }), ". The framework auto-injects constants like _urlBase and serializes all props as inline JSON, reused directly during client hydration \u2014 no extra request needed."] }), _jsx("div", { className: "space-y-2", children: [
@@ -155,13 +153,7 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
155
153
  checkbox.tsx # shadcn Checkbox
156
154
  switch.tsx # shadcn Switch
157
155
  view/
158
- react-page.tsx # Page component (import + compose)` }), _jsxs("p", { className: "text-slate-500 text-xs mt-3", children: ["Mirrors the shadcn/ui ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "components/ui/" }), " convention. In dev mode, the framework auto-scans imports \u2014 no manual import map configuration needed."] })] })] })), tab === 'routing' && (
159
- /*
160
- MemoryRouter:路由状态保存在内存中,服务端 SSR 和客户端水合均可运行,
161
- 无需服务端配置 catch-all 路由,适合在页面内嵌入独立的路由演示。
162
- 若要整页接管 URL,改用 BrowserRouter(需服务端对所有子路径返回同一页面)。
163
- */
164
- _jsxs(MemoryRouter, { children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "React Router Demo" }), _jsxs("p", { className: "text-slate-500 text-xs mb-4", children: ["Uses ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "MemoryRouter" }), ' ', "to demonstrate route navigation, dynamic params (useParams), and programmatic navigation (useNavigate). Works on both server SSR and client hydration with no extra server configuration."] }), _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(RouterHome, {}) }), _jsx(Route, { path: "/about", element: _jsx(RouterAbout, {}) }), _jsx(Route, { path: "/user/:id", element: _jsx(RouterUser, {}) })] })] }), _jsxs(Card, { className: "mt-4", children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-2", children: "Full-Page BrowserRouter Setup" }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "To let React Router manage the real URL (e.g. /app, /app/about), replace MemoryRouter with BrowserRouter and route all sub-paths to the same Ctr method on the server:" }), _jsx("pre", { className: "bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700", children: `// 1. route.json: 将所有子路径路由到同一 Ctr 方法
156
+ react-page.tsx # Page component (import + compose)` }), _jsxs("p", { className: "text-slate-500 text-xs mt-3", children: ["Mirrors the shadcn/ui ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "components/ui/" }), " convention. In dev mode, the framework auto-scans imports \u2014 no manual import map configuration needed."] })] })] })), tab === 'routing' && (_jsxs(MemoryRouter, { children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "React Router Demo" }), _jsxs("p", { className: "text-slate-500 text-xs mb-4", children: ["Uses ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "MemoryRouter" }), ' ', "to demonstrate route navigation, dynamic params (useParams), and programmatic navigation (useNavigate). Works on both server SSR and client hydration with no extra server configuration."] }), _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(RouterHome, {}) }), _jsx(Route, { path: "/about", element: _jsx(RouterAbout, {}) }), _jsx(Route, { path: "/user/:id", element: _jsx(RouterUser, {}) })] })] }), _jsxs(Card, { className: "mt-4", children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-2", children: "Full-Page BrowserRouter Setup" }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "To let React Router manage the real URL (e.g. /app, /app/about), replace MemoryRouter with BrowserRouter and route all sub-paths to the same Ctr method on the server:" }), _jsx("pre", { className: "bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700", children: `// 1. route.json: 将所有子路径路由到同一 Ctr 方法
165
157
  {
166
158
  "app": "ctr/app@reactPage",
167
159
  "app\\/.*": "ctr/app@reactPage"