@maiyunnet/kebab 9.2.1 → 9.2.3
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 +90 -16
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/text.d.ts +15 -1
- package/lib/text.js +41 -3
- package/lib/undici/response.d.ts +1 -1
- package/package.json +17 -17
- package/www/example/stc/view/react.page.js +2 -10
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.
|
|
1363
|
+
> `const` **VER**: `"9.2.3"` = `'9.2.3'`
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
17466
|
+
Defined in: node\_modules/@types/node/stream.d.ts:80
|
|
17393
17467
|
|
|
17394
17468
|
#### Parameters
|
|
17395
17469
|
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '9.2.
|
|
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
|
|
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(
|
|
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/lib/undici/response.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export declare class Response {
|
|
|
31
31
|
/**
|
|
32
32
|
* --- 获取响应读取流对象 ---
|
|
33
33
|
*/
|
|
34
|
-
getStream(): (import("undici/types/readable").default & undici.Dispatcher.BodyMixin) |
|
|
34
|
+
getStream(): zlib.BrotliDecompress | zlib.Gunzip | zlib.Inflate | (import("undici/types/readable").default & undici.Dispatcher.BodyMixin) | null;
|
|
35
35
|
/**
|
|
36
36
|
* --- 获取原生响应读取流对象 ---
|
|
37
37
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maiyunnet/kebab",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.3",
|
|
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.
|
|
26
|
-
"@aws-sdk/lib-storage": "^3.
|
|
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.
|
|
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.
|
|
35
|
+
"@tailwindcss/cli": "^4.2.4",
|
|
36
36
|
"@types/ssh2": "^1.15.5",
|
|
37
|
-
"@zilliz/milvus2-sdk-node": "^2.6.
|
|
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.
|
|
43
|
-
"esbuild": "^0.
|
|
42
|
+
"ejs": "^5.0.2",
|
|
43
|
+
"esbuild": "^0.28.0",
|
|
44
44
|
"jszip": "^3.10.1",
|
|
45
|
-
"mysql2": "^3.
|
|
45
|
+
"mysql2": "^3.22.2",
|
|
46
46
|
"node-cron": "^4.2.1",
|
|
47
|
-
"openai": "^6.
|
|
47
|
+
"openai": "^6.34.0",
|
|
48
48
|
"pg": "^8.20.0",
|
|
49
|
-
"react": "^19.2.
|
|
50
|
-
"react-dom": "^19.2.
|
|
51
|
-
"react-router-dom": "^7.
|
|
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.
|
|
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.
|
|
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.
|
|
65
|
+
"typedoc": "^0.28.19",
|
|
66
66
|
"typedoc-plugin-markdown": "^4.11.0",
|
|
67
|
-
"typescript": "^
|
|
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"
|