@maiyunnet/kebab 8.6.5 → 9.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.
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-700:oklch(55.5% .163 48.998);--color-green-100:oklch(96.2% .044 156.743);--color-green-700:oklch(52.7% .154 150.069);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-2xl:42rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.static{position:static}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.table{display:table}.h-10{height:calc(var(--spacing) * 10)}.min-h-screen{min-height:100vh}.w-10{width:calc(var(--spacing) * 10)}.w-28{width:calc(var(--spacing) * 28)}.w-fit{width:fit-content}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-300{border-color:var(--color-slate-300)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-green-100{background-color:var(--color-green-100)}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-white{background-color:var(--color-white)}.p-1{padding:calc(var(--spacing) * 1)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-10{padding-block:calc(var(--spacing) * 10)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-amber-700{color:var(--color-amber-700)}.text-blue-700{color:var(--color-blue-700)}.text-green-700{color:var(--color-green-700)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-800{color:var(--color-slate-800)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.shadow,.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)}.hover\:text-slate-600:hover{color:var(--color-slate-600)}.hover\:text-slate-900:hover{color:var(--color-slate-900)}}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * --- Kebab React BrowserRouter 全页面示例组件 ---
3
+ *
4
+ * node ./source/main build -d ./source/www/example/stc/view
5
+ *
6
+ * 【特性】
7
+ * 本组件演示 _loadReactPage 的 router: 'browser' 模式,实现地址栏与路由联动:
8
+ * - 服务端:框架自动用 StaticRouter 包裹,按当前请求 URL 渲染对应路由
9
+ * - 客户端:框架水合脚本用 BrowserRouter 包裹,Link/NavLink 导航会修改真实地址栏
10
+ * - 直接访问深链接(如 /test/react-router-page/user/42)开箱即用,无需前端 fallback
11
+ *
12
+ * 【要点】
13
+ * 1. 组件本身不包含任何 Router 包裹层,只使用 Routes/Route/Link/NavLink/useParams 等
14
+ * 2. BrowserRouter 的 basename 由框架通过 _routerBase prop 传入
15
+ * 3. 嵌套路由通过 Outlet 渲染子路由内容
16
+ *
17
+ * 【编译方式】
18
+ * tsc watch 会自动编译本文件为同路径的 .js,无需额外命令。
19
+ * 如需打包为 .bundle.js,执行:node ./source/main build
20
+ *
21
+ * 【Tailwind CSS 构建】
22
+ * bundle 模式下不再加载 CDN,需提前构建 CSS 产物。
23
+ * 执行 node ./source/main build 时会自动构建同名 .css,无需单独执行。
24
+ * 框架通过 _urlStc 和 _staticVer 自动拼接正确的带版本号 URL。
25
+ */
26
+ interface IUser {
27
+ 'id': string;
28
+ 'name': string;
29
+ 'email': string;
30
+ }
31
+ interface IProps {
32
+ 'title': string;
33
+ 'serverTime': string;
34
+ 'node': string;
35
+ /** --- 用户列表数据,SSR 时由后端提供,SPA 导航时前端 fetch --- */
36
+ 'users'?: IUser[];
37
+ /** --- 单个用户数据,SSR 时由后端提供,SPA 导航时前端 fetch --- */
38
+ 'user'?: IUser;
39
+ '_urlBase': string;
40
+ '_urlStc': string;
41
+ '_urlFull': string;
42
+ '_staticVer': string;
43
+ /** --- 框架注入:BrowserRouter 的 basename,如 /test/react-router-page --- */
44
+ '_routerBase'?: string;
45
+ /** --- 框架注入:import map JSON 字符串 --- */
46
+ '_importMapJson'?: string;
47
+ /** --- 框架注入:水合脚本 --- */
48
+ '_hydrateScript'?: string;
49
+ /** --- 框架注入:fullProps 序列化 JSON --- */
50
+ '_propsJson'?: string;
51
+ }
52
+ /**
53
+ * --- Kebab React BrowserRouter 全页面演示 ---
54
+ * 框架负责用 StaticRouter(服务端)/ BrowserRouter(客户端)包裹本组件,
55
+ * 组件内部只需使用 Routes/Route/Link 等,无需自行包裹 Router。
56
+ */
57
+ export default function ReactRouterPage({ title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer, _importMapJson, _hydrateScript, _propsJson, }: IProps): import("react/jsx-runtime").JSX.Element;
58
+ export {};
@@ -0,0 +1,142 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * --- Kebab React BrowserRouter 全页面示例组件 ---
4
+ *
5
+ * node ./source/main build -d ./source/www/example/stc/view
6
+ *
7
+ * 【特性】
8
+ * 本组件演示 _loadReactPage 的 router: 'browser' 模式,实现地址栏与路由联动:
9
+ * - 服务端:框架自动用 StaticRouter 包裹,按当前请求 URL 渲染对应路由
10
+ * - 客户端:框架水合脚本用 BrowserRouter 包裹,Link/NavLink 导航会修改真实地址栏
11
+ * - 直接访问深链接(如 /test/react-router-page/user/42)开箱即用,无需前端 fallback
12
+ *
13
+ * 【要点】
14
+ * 1. 组件本身不包含任何 Router 包裹层,只使用 Routes/Route/Link/NavLink/useParams 等
15
+ * 2. BrowserRouter 的 basename 由框架通过 _routerBase prop 传入
16
+ * 3. 嵌套路由通过 Outlet 渲染子路由内容
17
+ *
18
+ * 【编译方式】
19
+ * tsc watch 会自动编译本文件为同路径的 .js,无需额外命令。
20
+ * 如需打包为 .bundle.js,执行:node ./source/main build
21
+ *
22
+ * 【Tailwind CSS 构建】
23
+ * bundle 模式下不再加载 CDN,需提前构建 CSS 产物。
24
+ * 执行 node ./source/main build 时会自动构建同名 .css,无需单独执行。
25
+ * 框架通过 _urlStc 和 _staticVer 自动拼接正确的带版本号 URL。
26
+ */
27
+ import { useState, useEffect } from 'react';
28
+ import { Routes, Route, Link, NavLink, useParams, useNavigate, useLocation, Outlet } from 'react-router-dom';
29
+ // --- 基础控件 ---
30
+ /** --- 卡片容器 --- */
31
+ function Card({ children, className = '' }) {
32
+ return (_jsx("div", { className: `bg-white rounded-xl shadow-sm border border-slate-200 p-6 ${className}`, children: children }));
33
+ }
34
+ /** --- 标签徽章 --- */
35
+ function Badge({ children, variant = 'default' }) {
36
+ const styles = {
37
+ 'default': 'bg-slate-100 text-slate-600',
38
+ 'success': 'bg-green-100 text-green-700',
39
+ 'info': 'bg-blue-100 text-blue-700',
40
+ };
41
+ return (_jsx("span", { className: `inline-flex px-2.5 py-0.5 rounded-md text-xs font-semibold ${styles[variant]}`, children: children }));
42
+ }
43
+ // --- 导航栏 ---
44
+ /** --- 顶部导航栏,NavLink 自动高亮当前路由 --- */
45
+ function NavBar() {
46
+ /** --- NavLink className 回调:激活时高亮 --- */
47
+ const cls = ({ isActive }) => isActive
48
+ ? 'px-3 py-1.5 rounded-lg bg-blue-500 text-white text-sm font-medium transition-colors'
49
+ : 'px-3 py-1.5 rounded-lg text-slate-600 hover:bg-slate-100 text-sm font-medium transition-colors';
50
+ return (_jsxs("nav", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(NavLink, { to: "/", end: true, className: cls, children: "Home" }), _jsx(NavLink, { to: "/about", className: cls, children: "About" }), _jsx(NavLink, { to: "/user", className: cls, children: "Users" })] }));
51
+ }
52
+ // --- 路由页面 ---
53
+ /** --- 首页 --- */
54
+ function PageHome({ serverTime, node }) {
55
+ const location = useLocation();
56
+ const [hydrated, setHydrated] = useState(false);
57
+ useEffect(() => {
58
+ setHydrated(true);
59
+ }, []);
60
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("p", { className: "text-slate-600 text-sm", children: "Home page demonstrating SSR + BrowserRouter integration." }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm", children: [_jsxs("div", { className: "bg-slate-50 rounded-lg p-3", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Server Render Time" }), _jsx("div", { className: "font-mono text-slate-800", children: serverTime })] }), _jsxs("div", { className: "bg-slate-50 rounded-lg p-3", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Node.js Version" }), _jsx("div", { className: "font-mono text-slate-800", children: node })] }), _jsxs("div", { className: "bg-slate-50 rounded-lg p-3", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Current pathname (useLocation)" }), _jsx("div", { className: "font-mono text-slate-800", children: location.pathname })] }), _jsxs("div", { className: "bg-slate-50 rounded-lg p-3", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Hydration Status" }), _jsx("div", { suppressHydrationWarning: true, children: hydrated
61
+ ? _jsx(Badge, { variant: "success", children: "Hydrated" })
62
+ : _jsx(Badge, { children: "SSR" }) })] })] }), _jsxs("div", { className: "flex gap-2 flex-wrap mt-2", children: [_jsx(Link, { to: "/about", className: "inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 hover:bg-blue-600 text-white text-xs font-medium transition-colors", children: "Go to About" }), _jsx(Link, { to: "/user", className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium transition-colors", children: "Go to Users" })] })] }));
63
+ }
64
+ /** --- 关于页 --- */
65
+ function PageAbout() {
66
+ const navigate = useNavigate();
67
+ const location = useLocation();
68
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs("p", { className: "text-slate-600 text-sm", children: ["About page: demonstrates ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "useNavigate()" }), " programmatic navigation."] }), _jsxs("div", { className: "bg-slate-50 rounded-lg p-3 text-sm", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Current pathname" }), _jsx("div", { className: "font-mono text-slate-800", children: location.pathname })] }), _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx("button", { onClick: () => navigate('/'), className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium cursor-pointer transition-colors", children: "Back to Home" }), _jsx("button", { onClick: () => navigate('/user/42'), className: "inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 hover:bg-blue-600 text-white text-xs font-medium cursor-pointer transition-colors", children: "Go to User #42" })] })] }));
69
+ }
70
+ /** --- 用户列表页 --- */
71
+ function PageUsers({ users: initialUsers, urlBase }) {
72
+ const location = useLocation();
73
+ const [users, setUsers] = useState(initialUsers);
74
+ const [loading, setLoading] = useState(false);
75
+ useEffect(() => {
76
+ // --- SSR 已提供数据则跳过 fetch ---
77
+ if (users) {
78
+ return;
79
+ }
80
+ setLoading(true);
81
+ fetch(`${urlBase}test/react-router-page-data?path=/user`)
82
+ .then(r => r.json())
83
+ .then((res) => {
84
+ if (res.result > 0 && res.users) {
85
+ setUsers(res.users);
86
+ }
87
+ setLoading(false);
88
+ })
89
+ .catch(() => setLoading(false));
90
+ }, []);
91
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("p", { className: "text-slate-600 text-sm", children: "User list \u2014 click to view details (with nested /profile route)." }), _jsxs("div", { className: "bg-slate-50 rounded-lg p-3 text-sm", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Current pathname" }), _jsx("div", { className: "font-mono text-slate-800", children: location.pathname })] }), loading && _jsx("p", { className: "text-slate-400 text-sm", children: "Loading..." }), users && (_jsx("ul", { className: "space-y-2", children: users.map(u => (_jsx("li", { className: "flex items-center gap-3", children: _jsxs(Link, { to: `/user/${u.id}`, className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-200 hover:bg-slate-50 text-slate-700 text-xs font-medium transition-colors", children: [u.name, " (id=", u.id, ") \u2014 /user/", u.id] }) }, u.id))) }))] }));
92
+ }
93
+ /**
94
+ * --- 用户详情页(含嵌套路由 Outlet) ---
95
+ * 子路由 /profile 通过 <Outlet /> 渲染在此处
96
+ */
97
+ function PageUserDetail({ user: initialUser, urlBase }) {
98
+ const { id } = useParams();
99
+ const navigate = useNavigate();
100
+ const location = useLocation();
101
+ const [user, setUser] = useState((initialUser?.id === id) ? initialUser : undefined);
102
+ const [loading, setLoading] = useState(false);
103
+ useEffect(() => {
104
+ // --- SSR 数据匹配当前 id 则跳过 fetch ---
105
+ if (user?.id === id) {
106
+ return;
107
+ }
108
+ setLoading(true);
109
+ fetch(`${urlBase}test/react-router-page-data?path=/user/${encodeURIComponent(id ?? '')}`)
110
+ .then(r => r.json())
111
+ .then((res) => {
112
+ if (res.result > 0 && res.user) {
113
+ setUser(res.user);
114
+ }
115
+ setLoading(false);
116
+ })
117
+ .catch(() => setLoading(false));
118
+ }, [id]);
119
+ return (_jsxs("div", { className: "space-y-4", children: [loading && _jsx("p", { className: "text-slate-400 text-sm", children: "Loading..." }), user && (_jsxs("p", { className: "text-slate-700 text-sm font-medium", children: ["User Detail: ", _jsx("code", { className: "bg-slate-100 px-1.5 rounded font-mono", children: user.name }), "\u00A0", _jsxs("span", { className: "text-slate-400 text-xs", children: ["(id=\"", id, "\", email=", user.email, ")"] })] })), _jsxs("div", { className: "bg-slate-50 rounded-lg p-3 text-sm", children: [_jsx("div", { className: "text-slate-500 text-xs mb-1", children: "Current pathname" }), _jsx("div", { className: "font-mono text-slate-800", children: location.pathname })] }), _jsxs("div", { className: "border border-dashed border-slate-300 rounded-lg p-4", children: [_jsxs("p", { className: "text-slate-500 text-xs mb-3", children: ["Nested route ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/user/:id/profile" }), " (rendered via Outlet):"] }), _jsx(Outlet, {}), location.pathname === `/user/${id}` && (_jsx(Link, { to: `/user/${id}/profile`, className: "inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 hover:bg-blue-600 text-white text-xs font-medium transition-colors", children: "View Profile" }))] }), _jsx("button", { onClick: () => navigate('/user'), className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium cursor-pointer transition-colors", children: "Back to Users" })] }));
120
+ }
121
+ /** --- 嵌套子路由:用户 Profile --- */
122
+ function PageUserProfile() {
123
+ const { id } = useParams();
124
+ const location = useLocation();
125
+ return (_jsxs("div", { className: "bg-blue-50 rounded-lg p-3 mb-3 space-y-2 text-sm", children: [_jsx(Badge, { variant: "info", children: "Nested Route Active" }), _jsxs("div", { className: "text-slate-700", children: ["Profile of user ", _jsx("strong", { children: id }), " (rendered via Outlet)"] }), _jsx("div", { className: "font-mono text-slate-500 text-xs", children: location.pathname })] }));
126
+ }
127
+ /** --- 404 兜底页 --- */
128
+ function PageNotFound() {
129
+ const location = useLocation();
130
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-red-600 font-medium", children: "Page Not Found" }), _jsx("div", { className: "text-slate-500 text-xs font-mono", children: location.pathname }), _jsx(Link, { to: "/", className: "inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 text-white text-xs font-medium transition-colors hover:bg-blue-600", children: "Back to Home" })] }));
131
+ }
132
+ // --- 页面主组件 ---
133
+ /**
134
+ * --- Kebab React BrowserRouter 全页面演示 ---
135
+ * 框架负责用 StaticRouter(服务端)/ BrowserRouter(客户端)包裹本组件,
136
+ * 组件内部只需使用 Routes/Route/Link 等,无需自行包裹 Router。
137
+ */
138
+ export default function ReactRouterPage({ title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer, _importMapJson, _hydrateScript, _propsJson, }) {
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" }), _jsx("title", { suppressHydrationWarning: true, children: title }), _importMapJson
140
+ ? _jsx("script", { src: "https://cdn.tailwindcss.com" })
141
+ : _jsx("link", { rel: "stylesheet", href: `${_urlStc}view/react-router-page.css?v=${_staticVer}` }), _importMapJson && (_jsx("script", { type: "importmap", dangerouslySetInnerHTML: { '__html': _importMapJson } }))] }), _jsxs("body", { className: "bg-slate-50 min-h-screen", children: [_jsxs("div", { className: "max-w-2xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-slate-900", children: "Kebab React Router" }), _jsxs("p", { className: "text-slate-500 mt-1 text-sm", children: [_jsx("code", { className: "bg-slate-100 px-1.5 py-0.5 rounded font-mono text-xs", children: "router: 'browser'" }), "\u00A0mode \u2014 URL synced with routes"] })] }), _jsx("a", { href: `${_urlBase}`, className: "text-xs text-slate-400 hover:text-slate-600 transition-colors mt-1", children: "Back to Index" })] }), _jsx("div", { className: "bg-white rounded-xl shadow-sm border border-slate-200 px-4 py-3", children: _jsx(NavBar, {}) }), _jsx("div", { className: "bg-white rounded-xl shadow-sm border border-slate-200 p-6", children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(PageHome, { serverTime: serverTime, node: node }) }), _jsx(Route, { path: "/about", element: _jsx(PageAbout, {}) }), _jsx(Route, { path: "/user", element: _jsx(PageUsers, { users: users, urlBase: _urlBase }) }), _jsx(Route, { path: "/user/:id", element: _jsx(PageUserDetail, { user: user, urlBase: _urlBase }), children: _jsx(Route, { path: "profile", element: _jsx(PageUserProfile, {}) }) }), _jsx(Route, { path: "*", element: _jsx(PageNotFound, {}) })] }) }), _jsxs(Card, { className: "text-xs text-slate-500 space-y-1.5", children: [_jsx("p", { className: "font-semibold text-slate-700 text-sm", children: "How It Works" }), _jsxs("p", { children: ["\u2022 Server: framework wraps with ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "StaticRouter" }), " to SSR the matching route"] }), _jsxs("p", { children: ["\u2022 Client: hydration script wraps with ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "BrowserRouter" }), " for URL-synced navigation"] }), _jsxs("p", { children: ["\u2022 Data: one backend method (", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "_getRouteData" }), ") serves both SSR props and SPA API"] }), _jsxs("p", { children: ["\u2022 Deep links like ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/test/react-router-page/user/42" }), " work out of the box"] })] })] }), _propsJson && (_jsx("script", { id: "__kebab_props__", type: "application/json", suppressHydrationWarning: true, dangerouslySetInnerHTML: { '__html': _propsJson } })), _hydrateScript && (_jsx("script", { type: "module", suppressHydrationWarning: true, dangerouslySetInnerHTML: { '__html': _hydrateScript } }))] })] }));
142
+ }