akanjs 2.4.2-rc.2 → 3.0.0-alpha.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/base/baseEnv.ts +0 -6
- package/client/cn.ts +52 -0
- package/client/csrTypes.ts +2 -2
- package/client/frameConfig.ts +2 -2
- package/client/index.ts +1 -0
- package/client/types.ts +0 -4
- package/common/fileUpload.ts +1 -1
- package/common/index.ts +1 -0
- package/common/isThenable.ts +12 -0
- package/constant/purify.ts +9 -10
- package/fetch/client/fetchClient.ts +1 -1
- package/fetch/client/httpClient.ts +9 -5
- package/fetch/fetchType/sliceFetch.type.ts +1 -1
- package/package.json +4 -7
- package/server/akanApp.ts +2 -0
- package/server/systemPageDocument.tsx +12 -12
- package/signal/endpointInfo.ts +2 -1
- package/signal/slice.ts +1 -1
- package/signal/sliceInfo.ts +2 -1
- package/store/action.ts +18 -2
- package/store/baseSt.ts +2 -2
- package/store/state.ts +9 -1
- package/store/storeInstance.ts +2 -0
- package/test/sampleOf.ts +3 -3
- package/test/signalTestRuntime.ts +0 -2
- package/types/base/baseEnv.d.ts +0 -2
- package/types/client/cn.d.ts +12 -0
- package/types/client/index.d.ts +1 -0
- package/types/client/types.d.ts +0 -3
- package/types/common/fileUpload.d.ts +1 -1
- package/types/common/index.d.ts +1 -0
- package/types/common/isThenable.d.ts +9 -0
- package/types/constant/purify.d.ts +3 -2
- package/types/fetch/fetchType/sliceFetch.type.d.ts +1 -1
- package/types/signal/endpointInfo.d.ts +2 -2
- package/types/signal/slice.d.ts +1 -1
- package/types/signal/sliceInfo.d.ts +2 -2
- package/types/store/action.d.ts +1 -1
- package/types/store/state.d.ts +4 -2
- package/types/test/sampleOf.d.ts +2 -2
- package/types/ui/Badge.d.ts +6 -0
- package/types/ui/Button.d.ts +26 -6
- package/types/ui/Load/Units.d.ts +3 -1
- package/types/ui/RecentTime.d.ts +1 -1
- package/types/ui/Signal/Collapse.d.ts +12 -0
- package/types/ui/Signal/style.d.ts +5 -6
- package/types/ui/Switch.d.ts +14 -0
- package/types/ui/Tooltip.d.ts +11 -0
- package/types/ui/UiOverride/Provider.d.ts +6 -5
- package/types/ui/UiOverride/context.d.ts +22 -1
- package/types/ui/UiOverride/index.d.ts +2 -1
- package/types/ui/UiOverride/override.d.ts +7 -6
- package/types/ui/UiOverride/useUiRecipe.d.ts +8 -0
- package/types/ui/index.d.ts +5 -1
- package/types/ui/recipe/badgeRecipe.d.ts +13 -0
- package/types/ui/recipe/buttonRecipe.d.ts +15 -0
- package/types/ui/recipe/factory.d.ts +24 -0
- package/types/ui/recipe/index.d.ts +18 -0
- package/types/ui/recipe/inputRecipe.d.ts +13 -0
- package/types/ui/recipe.d.ts +1 -0
- package/ui/Badge.tsx +17 -0
- package/ui/BottomSheet.tsx +8 -10
- package/ui/Button.tsx +158 -48
- package/ui/Clipboard.tsx +3 -3
- package/ui/Constant/Doc.tsx +108 -65
- package/ui/Constant/Mermaid.tsx +9 -9
- package/ui/Data/CardList.tsx +3 -3
- package/ui/Data/Dashboard.tsx +22 -13
- package/ui/Data/Insight.tsx +6 -6
- package/ui/Data/Item.tsx +49 -34
- package/ui/Data/ListContainer.tsx +11 -7
- package/ui/Data/Pagination.tsx +2 -2
- package/ui/DatePicker.tsx +5 -5
- package/ui/Dialog/Content.tsx +2 -2
- package/ui/Dialog/Modal.tsx +12 -8
- package/ui/Dialog/Provider.tsx +2 -2
- package/ui/DragAction.tsx +2 -2
- package/ui/DraggableList.tsx +10 -5
- package/ui/Dropdown.tsx +33 -26
- package/ui/Empty.tsx +5 -5
- package/ui/Field.tsx +82 -70
- package/ui/Image.tsx +2 -2
- package/ui/Input.tsx +62 -60
- package/ui/Layout/BottomInset.tsx +2 -2
- package/ui/Layout/BottomTab.tsx +5 -5
- package/ui/Layout/Header.tsx +3 -3
- package/ui/Layout/LeftSider.tsx +6 -5
- package/ui/Layout/Navbar.tsx +2 -12
- package/ui/Layout/RightSider.tsx +10 -8
- package/ui/Layout/Sider.tsx +5 -4
- package/ui/Layout/Template.tsx +2 -2
- package/ui/Layout/TopInset.tsx +2 -2
- package/ui/Layout/Unit.tsx +2 -2
- package/ui/Layout/View.tsx +2 -2
- package/ui/Layout/Zone.tsx +2 -2
- package/ui/Link/Back.tsx +2 -2
- package/ui/Link/Close.tsx +2 -2
- package/ui/Link/CsrLink.tsx +6 -4
- package/ui/Link/Lang.tsx +2 -2
- package/ui/Link/SsrLink.tsx +6 -5
- package/ui/Load/Page.tsx +1 -1
- package/ui/Load/Pagination.tsx +2 -2
- package/ui/Load/Units.tsx +19 -4
- package/ui/Load/View.tsx +2 -2
- package/ui/Loading/Area.tsx +4 -2
- package/ui/Loading/Button.tsx +2 -2
- package/ui/Loading/Input.tsx +2 -2
- package/ui/Loading/ProgressBar.tsx +2 -2
- package/ui/Loading/Skeleton.tsx +6 -6
- package/ui/Loading/Spin.tsx +2 -2
- package/ui/Menu.tsx +29 -27
- package/ui/Model/Edit.tsx +3 -3
- package/ui/Model/EditModal.tsx +5 -5
- package/ui/Model/EditWrapper.tsx +2 -2
- package/ui/Model/New.tsx +3 -3
- package/ui/Model/NewWrapper_Client.tsx +2 -2
- package/ui/Model/Remove.tsx +5 -4
- package/ui/Model/RemoveWrapper.tsx +2 -2
- package/ui/Model/SureToRemove.tsx +7 -6
- package/ui/Model/View.tsx +2 -2
- package/ui/Model/ViewEditModal.tsx +20 -21
- package/ui/Model/ViewWrapper.tsx +2 -2
- package/ui/More.tsx +2 -2
- package/ui/ObjectId.tsx +9 -3
- package/ui/Pagination.tsx +14 -11
- package/ui/Popconfirm.tsx +20 -11
- package/ui/Radio.tsx +4 -4
- package/ui/RecentTime.tsx +30 -83
- package/ui/Refresh.tsx +1 -1
- package/ui/ScreenNavigator.tsx +2 -2
- package/ui/Select.tsx +21 -23
- package/ui/Signal/Arg.tsx +21 -18
- package/ui/Signal/Collapse.tsx +29 -0
- package/ui/Signal/Doc.tsx +27 -22
- package/ui/Signal/Listener.tsx +3 -3
- package/ui/Signal/Message.tsx +31 -17
- package/ui/Signal/Object.tsx +13 -8
- package/ui/Signal/PubSub.tsx +26 -16
- package/ui/Signal/Request.tsx +3 -2
- package/ui/Signal/Response.tsx +5 -4
- package/ui/Signal/RestApi.tsx +27 -17
- package/ui/Signal/style.ts +16 -16
- package/ui/Switch.tsx +62 -0
- package/ui/System/CSR.tsx +40 -35
- package/ui/System/Client.tsx +2 -2
- package/ui/System/DevModeToggle.tsx +10 -12
- package/ui/System/Messages.tsx +14 -16
- package/ui/System/Reconnect.tsx +7 -7
- package/ui/System/SSR.tsx +25 -21
- package/ui/System/SelectLanguage.tsx +24 -28
- package/ui/System/ThemeToggle.tsx +38 -45
- package/ui/Tab/Menu.tsx +20 -18
- package/ui/Tab/Panel.tsx +3 -3
- package/ui/Tab/Provider.tsx +2 -2
- package/ui/Table.tsx +11 -8
- package/ui/ToggleSelect.tsx +14 -18
- package/ui/Tooltip.tsx +55 -0
- package/ui/UiOverride/Provider.tsx +10 -6
- package/ui/UiOverride/context.ts +22 -2
- package/ui/UiOverride/index.ts +8 -1
- package/ui/UiOverride/override.ts +7 -6
- package/ui/UiOverride/useUiRecipe.ts +15 -0
- package/ui/Unauthorized.tsx +5 -5
- package/ui/index.ts +16 -0
- package/ui/recipe/badgeRecipe.ts +23 -0
- package/ui/recipe/buttonRecipe.ts +32 -0
- package/ui/recipe/factory.ts +32 -0
- package/ui/recipe/index.ts +18 -0
- package/ui/recipe/inputRecipe.ts +13 -0
- package/ui/styles.css +150 -21
package/ui/Link/SsrLink.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { getEnv } from "akanjs/base";
|
|
4
|
-
import {
|
|
4
|
+
import { cn, getPathInfo, router, usePage, usePathCtx } from "akanjs/client";
|
|
5
5
|
import { Logger } from "akanjs/common";
|
|
6
6
|
import type { SsrLinkProps } from "./types";
|
|
7
7
|
|
|
@@ -28,16 +28,17 @@ export default function SsrLink({
|
|
|
28
28
|
const path = internalPathInfo.path;
|
|
29
29
|
if (href.startsWith("#")) {
|
|
30
30
|
return (
|
|
31
|
-
<a className={
|
|
31
|
+
<a className={cn(className, currentPath === path && (activeClassName ?? ""))} href={href}>
|
|
32
32
|
{children}
|
|
33
33
|
</a>
|
|
34
34
|
);
|
|
35
35
|
}
|
|
36
36
|
return (
|
|
37
37
|
<a
|
|
38
|
-
className={
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
className={cn(
|
|
39
|
+
className,
|
|
40
|
+
(activeExact ? currentPath === path : currentPath.startsWith(path)) && (activeClassName ?? ""),
|
|
41
|
+
)}
|
|
41
42
|
href={isExternal ? href : href.startsWith("#") ? href : requestHref}
|
|
42
43
|
|
|
43
44
|
{...props}
|
package/ui/Load/Page.tsx
CHANGED
package/ui/Load/Pagination.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { capitalize, lowerlize } from "akanjs/common";
|
|
4
4
|
import type { BaseInsight } from "akanjs/constant";
|
|
5
5
|
import type { ClientInit, ServerInit } from "akanjs/fetch";
|
|
@@ -64,7 +64,7 @@ function Render<RefName extends string, Light>({ className, init, scrollToTop }:
|
|
|
64
64
|
if (!loaded.current) loaded.current = true;
|
|
65
65
|
|
|
66
66
|
return (
|
|
67
|
-
<div className={
|
|
67
|
+
<div className={cn("mt-4 flex flex-wrap justify-center", className)}>
|
|
68
68
|
{insight.count > limit && (
|
|
69
69
|
<Pagn
|
|
70
70
|
currentPage={page}
|
package/ui/Load/Units.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { DataList } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "akanjs/client";
|
|
4
4
|
import { capitalize, isQueryEqual, lowerlize } from "akanjs/common";
|
|
5
5
|
import type { BaseInsight } from "akanjs/constant";
|
|
6
6
|
import { ConstantRegistry } from "akanjs/constant";
|
|
@@ -28,6 +28,8 @@ interface DefaultProps<L extends { id: string }> {
|
|
|
28
28
|
renderList?: (list: DataList<L>) => ReactNode;
|
|
29
29
|
reverse?: boolean;
|
|
30
30
|
pagination?: boolean;
|
|
31
|
+
/** Max age in ms of the cached slice data before the client refetches on mount; `0` always refetches. */
|
|
32
|
+
staleTime?: number;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
interface UnitsProps<RefName extends string, Light extends { id: string }> extends DefaultProps<Light> {
|
|
@@ -60,6 +62,7 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
60
62
|
sort = (a, b) => 1,
|
|
61
63
|
reverse,
|
|
62
64
|
pagination,
|
|
65
|
+
staleTime,
|
|
63
66
|
}: RenderProps<RefName, Light>) {
|
|
64
67
|
const loaded = useRef(false);
|
|
65
68
|
const storeUse = st.use as { [key: string]: () => unknown };
|
|
@@ -75,6 +78,7 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
75
78
|
modelInsight: `${modelName}Insight`,
|
|
76
79
|
modelInitList: `${modelName}InitList`,
|
|
77
80
|
modelInitAt: `${modelName}InitAt`,
|
|
81
|
+
modelStaleAt: `${modelName}StaleAt`,
|
|
78
82
|
modelObjList: `${modelName}ObjList`,
|
|
79
83
|
modelObjInsight: `${modelName}ObjInsight`,
|
|
80
84
|
pageOfModel: `pageOf${ModelName}`,
|
|
@@ -84,12 +88,14 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
84
88
|
sortOfModel: `sortOf${ModelName}`,
|
|
85
89
|
setPageOfModel: `setPageOf${ModelName}`,
|
|
86
90
|
addPageOfModel: `addPageOf${ModelName}`,
|
|
91
|
+
refreshModel: `refresh${ModelName}`,
|
|
87
92
|
};
|
|
88
93
|
const namesOfSlice = {
|
|
89
94
|
modelList: sliceName.replace(names.model, names.modelList),
|
|
90
95
|
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
91
96
|
modelInitList: sliceName.replace(names.model, names.modelInitList),
|
|
92
97
|
modelInitAt: sliceName.replace(names.model, names.modelInitAt),
|
|
98
|
+
modelStaleAt: sliceName.replace(names.model, names.modelStaleAt),
|
|
93
99
|
modelInsight: sliceName.replace(names.model, names.modelInsight),
|
|
94
100
|
pageOfModel: sliceName.replace(names.model, names.pageOfModel),
|
|
95
101
|
lastPageOfModel: sliceName.replace(names.model, names.lastPageOfModel),
|
|
@@ -98,6 +104,7 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
98
104
|
sortOfModel: sliceName.replace(names.model, names.sortOfModel),
|
|
99
105
|
setPageOfModel: sliceName.replace(names.model, names.setPageOfModel),
|
|
100
106
|
addPageOfModel: sliceName.replace(names.model, names.addPageOfModel),
|
|
107
|
+
refreshModel: sliceName.replace(names.model, names.refreshModel),
|
|
101
108
|
};
|
|
102
109
|
const modelList = storeUse[namesOfSlice.modelList]() as DataList<Light>;
|
|
103
110
|
const modelListLoading = storeUse[namesOfSlice.modelListLoading]() as string | boolean;
|
|
@@ -106,6 +113,7 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
106
113
|
const initModelObjInsight = (init as any)[names.modelObjInsight] as BaseInsight;
|
|
107
114
|
const initLimitOfModel = (init as any)[names.limitOfModel] as number;
|
|
108
115
|
const initPageOfModel = (init as any)[names.pageOfModel] as number;
|
|
116
|
+
const modelStaleAt = storeUse[namesOfSlice.modelStaleAt]() as Date;
|
|
109
117
|
|
|
110
118
|
const useCache =
|
|
111
119
|
!modelListLoading &&
|
|
@@ -143,6 +151,13 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
143
151
|
loaded.current = true;
|
|
144
152
|
}, []);
|
|
145
153
|
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
const staleThreshold = Math.max(modelStaleAt.getTime(), staleTime === undefined ? 0 : Date.now() - staleTime);
|
|
156
|
+
if (storeGet<Date>()[namesOfSlice.modelInitAt].getTime() >= staleThreshold) return;
|
|
157
|
+
if (storeGet<boolean>()[namesOfSlice.modelListLoading]) return;
|
|
158
|
+
void storeDo[namesOfSlice.refreshModel]({ invalidate: true });
|
|
159
|
+
}, [modelStaleAt]);
|
|
160
|
+
|
|
146
161
|
const modelInsight = storeUse[namesOfSlice.modelInsight]() as BaseInsight;
|
|
147
162
|
const limitOfModel = storeUse[namesOfSlice.limitOfModel]() as number;
|
|
148
163
|
const pageOfModel = storeUse[namesOfSlice.pageOfModel]() as number;
|
|
@@ -175,9 +190,7 @@ function Render<RefName extends string, Light extends { id: string }>({
|
|
|
175
190
|
{modelDataList.length || renderEmpty === false ? (
|
|
176
191
|
<ContainerWrapper
|
|
177
192
|
containerRef={containerRef}
|
|
178
|
-
className={
|
|
179
|
-
"grid-cols-1 md:grid-cols-1 lg:grid-cols-1": modelDataList.length === 0,
|
|
180
|
-
})}
|
|
193
|
+
className={cn(className, modelDataList.length === 0 && "grid-cols-1 md:grid-cols-1 lg:grid-cols-1")}
|
|
181
194
|
noDiv={noDiv}
|
|
182
195
|
pagination={pagination}
|
|
183
196
|
moreProps={moreProps}
|
|
@@ -237,6 +250,7 @@ export default function Units<RefName extends string, Light extends { id: string
|
|
|
237
250
|
reverse,
|
|
238
251
|
style,
|
|
239
252
|
pagination = true,
|
|
253
|
+
staleTime,
|
|
240
254
|
}: UnitsProps<RefName, Light>) {
|
|
241
255
|
const props: UnitsProps<RefName, Light> = {
|
|
242
256
|
containerRef,
|
|
@@ -254,6 +268,7 @@ export default function Units<RefName extends string, Light extends { id: string
|
|
|
254
268
|
sort,
|
|
255
269
|
reverse,
|
|
256
270
|
pagination,
|
|
271
|
+
staleTime,
|
|
257
272
|
};
|
|
258
273
|
|
|
259
274
|
const { fulfilled, value: promiseInit } = useFetch(init);
|
package/ui/Load/View.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { ConstantRegistry } from "akanjs/constant";
|
|
4
4
|
import type { ClientView, ServerView } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
@@ -76,7 +76,7 @@ function Render<T extends string, Full extends { id: string }>({
|
|
|
76
76
|
return noDiv && renderModel ? (
|
|
77
77
|
<>{renderView(renderModel)}</>
|
|
78
78
|
) : renderModel ? (
|
|
79
|
-
<div className={
|
|
79
|
+
<div className={cn("w-full", className)}>{renderView(renderModel)}</div>
|
|
80
80
|
) : null;
|
|
81
81
|
}
|
|
82
82
|
|
package/ui/Loading/Area.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { AiOutlineLoading } from "react-icons/ai";
|
|
2
|
+
|
|
1
3
|
export const Area = () => {
|
|
2
4
|
return (
|
|
3
|
-
<div className="absolute inset-0 flex size-full items-center justify-center bg-
|
|
5
|
+
<div className="absolute inset-0 flex size-full items-center justify-center bg-border/30">
|
|
4
6
|
<div className="text-center">
|
|
5
|
-
<
|
|
7
|
+
<AiOutlineLoading className="mx-auto animate-spin text-primary/60 text-sm" />
|
|
6
8
|
<div className="z-10 text-sm">Loading</div>
|
|
7
9
|
</div>
|
|
8
10
|
</div>
|
package/ui/Loading/Button.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn } from "akanjs/client";
|
|
2
2
|
import type { CSSProperties } from "react";
|
|
3
3
|
|
|
4
4
|
export interface LoadingProps {
|
|
@@ -10,7 +10,7 @@ export const Button = ({ className = "", active, style }: LoadingProps) => {
|
|
|
10
10
|
const activeClassName = active ? "animate-pulse" : "";
|
|
11
11
|
return (
|
|
12
12
|
<div
|
|
13
|
-
className={
|
|
13
|
+
className={cn("inline-block h-8 w-16 rounded-md bg-muted align-bottom", activeClassName, className)}
|
|
14
14
|
style={style}
|
|
15
15
|
/>
|
|
16
16
|
);
|
package/ui/Loading/Input.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn } from "akanjs/client";
|
|
2
2
|
import type { CSSProperties } from "react";
|
|
3
3
|
|
|
4
4
|
export interface LoadingProps {
|
|
@@ -10,7 +10,7 @@ export const Input = ({ className = "", active, style }: LoadingProps) => {
|
|
|
10
10
|
const activeClassName = active ? "animate-pulse" : "";
|
|
11
11
|
return (
|
|
12
12
|
<div
|
|
13
|
-
className={
|
|
13
|
+
className={cn("inline-block h-8 w-44 rounded-md bg-muted align-bottom", activeClassName, className)}
|
|
14
14
|
style={style}
|
|
15
15
|
/>
|
|
16
16
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { animated } from "akanjs/ui";
|
|
4
4
|
import { useSpring } from "react-spring";
|
|
5
5
|
|
|
@@ -10,5 +10,5 @@ export interface ProgressBarProps {
|
|
|
10
10
|
}
|
|
11
11
|
export const ProgressBar = ({ className, value, max }: ProgressBarProps) => {
|
|
12
12
|
const progress = useSpring({ value: 0, to: { value: value } });
|
|
13
|
-
return <animated.progress className={
|
|
13
|
+
return <animated.progress className={cn("progress w-full", className)} value={progress.value} max={max} />;
|
|
14
14
|
};
|
package/ui/Loading/Skeleton.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn } from "akanjs/client";
|
|
2
2
|
import type { CSSProperties } from "react";
|
|
3
3
|
|
|
4
4
|
export interface SkeletonProps {
|
|
@@ -10,12 +10,12 @@ export interface SkeletonProps {
|
|
|
10
10
|
export const Skeleton = ({ className = "", active, style }: SkeletonProps) => {
|
|
11
11
|
const activeClassName = active ? "animate-pulse" : "";
|
|
12
12
|
return (
|
|
13
|
-
<div className={
|
|
13
|
+
<div className={cn("w-full", activeClassName, className)} style={style}>
|
|
14
14
|
<div className="flex flex-col justify-start space-y-3">
|
|
15
|
-
<div className="h-4 w-2/5 rounded-md bg-
|
|
16
|
-
<div className="h-4 w-full rounded-md bg-
|
|
17
|
-
<div className="h-4 w-full rounded-md bg-
|
|
18
|
-
<div className="h-4 w-3/5 rounded-md bg-
|
|
15
|
+
<div className="h-4 w-2/5 rounded-md bg-muted"></div>
|
|
16
|
+
<div className="h-4 w-full rounded-md bg-muted"></div>
|
|
17
|
+
<div className="h-4 w-full rounded-md bg-muted"></div>
|
|
18
|
+
<div className="h-4 w-3/5 rounded-md bg-muted"></div>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
);
|
package/ui/Loading/Spin.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn } from "akanjs/client";
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
import { AiOutlineLoading } from "react-icons/ai";
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ export interface SpinProps {
|
|
|
9
9
|
}
|
|
10
10
|
export const Spin = ({ indicator, isCenter, className }: SpinProps) => {
|
|
11
11
|
return (
|
|
12
|
-
<div className={
|
|
12
|
+
<div className={cn("inline-block py-1", className)}>
|
|
13
13
|
<div className={isCenter ? "absolute inset-0 flex size-full flex-none items-center justify-center" : ""}>
|
|
14
14
|
{indicator ? (
|
|
15
15
|
<div className="[&>svg]:animate-spin">{indicator}</div>
|
package/ui/Menu.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { st } from "akanjs/store";
|
|
4
4
|
import { type ReactNode, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
5
5
|
import { AiFillCaretDown, AiOutlineEllipsis } from "react-icons/ai";
|
|
6
|
+
import { buttonRecipe } from "./Button";
|
|
6
7
|
|
|
7
8
|
import { createOverridable } from "./UiOverride";
|
|
8
9
|
|
|
@@ -49,7 +50,7 @@ export const DefaultMenu = ({
|
|
|
49
50
|
}: MenuProps) => {
|
|
50
51
|
const [expandedKey, setExpandedKey] = useState<string>();
|
|
51
52
|
const [currentKey, setCurrentKey] = useState<string | null>(defaultSelectedKeys?.[0] ?? null);
|
|
52
|
-
const modeClassName = mode === "horizontal" ? "
|
|
53
|
+
const modeClassName = mode === "horizontal" ? "flex-row " : "bg-muted";
|
|
53
54
|
const menuRef = useRef<HTMLDivElement | null>(null);
|
|
54
55
|
const LiRefs = useRef<HTMLLIElement[]>([]);
|
|
55
56
|
const overflowLiRef = useRef<HTMLLIElement | null>(null);
|
|
@@ -58,20 +59,16 @@ export const DefaultMenu = ({
|
|
|
58
59
|
|
|
59
60
|
const subMenuClassName =
|
|
60
61
|
mode === "horizontal"
|
|
61
|
-
? `fixed
|
|
62
|
+
? `fixed bottom-0 flex translate-y-[98%] flex-col rounded-xs border-0 bg-background shadow-lg hover:bg-background`
|
|
62
63
|
: "flex flex-col gap-0 p-0 bg-primary/10 hover:bg-primary/10 overflow-hidden";
|
|
63
64
|
|
|
64
65
|
const subMenuItemClassName =
|
|
65
66
|
mode === "inline"
|
|
66
|
-
? "
|
|
67
|
-
:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
? "bg-primary text-primary-focus"
|
|
72
|
-
: activeStyle === "bordered"
|
|
73
|
-
? " border-b-2 border-white"
|
|
74
|
-
: activeStyle;
|
|
67
|
+
? buttonRecipe({ variant: "ghost" }, "m-0 h-full w-full px-2 font-normal text-primary hover:bg-primary/20")
|
|
68
|
+
: buttonRecipe(
|
|
69
|
+
{ variant: "ghost" },
|
|
70
|
+
"w-full whitespace-nowrap text-center font-normal text-primary duration-300",
|
|
71
|
+
);
|
|
75
72
|
|
|
76
73
|
const [overflowMenuItems, setOverflowMenuItems] = useState<MenuItem[]>([]);
|
|
77
74
|
|
|
@@ -125,10 +122,10 @@ export const DefaultMenu = ({
|
|
|
125
122
|
<div
|
|
126
123
|
ref={menuRef}
|
|
127
124
|
id="menu"
|
|
128
|
-
className={
|
|
125
|
+
className={cn(mode === "horizontal" ? "w-full shrink overflow-hidden" : "w-fit", className)}
|
|
129
126
|
>
|
|
130
127
|
<ul
|
|
131
|
-
className={
|
|
128
|
+
className={cn("flex size-full flex-col flex-nowrap overflow-y-auto p-0", modeClassName, ulClassName)}
|
|
132
129
|
style={{ ...style }}
|
|
133
130
|
onMouseOver={onMouseOver}
|
|
134
131
|
onMouseLeave={onMouseLeave}
|
|
@@ -145,10 +142,13 @@ export const DefaultMenu = ({
|
|
|
145
142
|
}}
|
|
146
143
|
id={item.key}
|
|
147
144
|
key={item.key}
|
|
148
|
-
className={
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
className={cn(
|
|
146
|
+
"relative m-0 duration-200 hover:opacity-70",
|
|
147
|
+
overflowClassName,
|
|
148
|
+
liClassName,
|
|
149
|
+
activeStyle === "active" && checkIsActive(item.key) && "bg-border",
|
|
150
|
+
activeStyle === "bordered" && checkIsActive(item.key) && "border-background border-b-2",
|
|
151
|
+
)}
|
|
152
152
|
onClick={() => {
|
|
153
153
|
if (!isOverflowItem) handleOnClick(item);
|
|
154
154
|
}}
|
|
@@ -161,12 +161,12 @@ export const DefaultMenu = ({
|
|
|
161
161
|
}}
|
|
162
162
|
>
|
|
163
163
|
<div className="flex h-full justify-between rounded-none">
|
|
164
|
-
<div className={
|
|
164
|
+
<div className={cn("flex items-center gap-1", labelClassName?.(checkIsActive(item.key)))}>
|
|
165
165
|
{item.icon}
|
|
166
166
|
|
|
167
|
-
{!inlineCollapsed && <div className="whitespace-nowrap text-
|
|
167
|
+
{!inlineCollapsed && <div className="whitespace-nowrap text-foreground">{item.label}</div>}
|
|
168
168
|
{/* <div
|
|
169
|
-
className={
|
|
169
|
+
className={cn(
|
|
170
170
|
"whitespace-nowrap truncate ",
|
|
171
171
|
mode === "horizontal" && !isOverflowItem && item.children
|
|
172
172
|
? "flex justify-start animate-menuOpen"
|
|
@@ -178,7 +178,7 @@ export const DefaultMenu = ({
|
|
|
178
178
|
</div>
|
|
179
179
|
{item.children && mode === "inline" && (
|
|
180
180
|
<AiFillCaretDown
|
|
181
|
-
className={
|
|
181
|
+
className={cn(
|
|
182
182
|
"text-xs transition-transform duration-400",
|
|
183
183
|
expandedKey === item.key ? "rotate-180" : "",
|
|
184
184
|
)}
|
|
@@ -234,12 +234,12 @@ const OverflowMenu = ({ overflowItems, onClick }: OverflowMenuProps) => {
|
|
|
234
234
|
<AiOutlineEllipsis />
|
|
235
235
|
</div>
|
|
236
236
|
{isOpen && (
|
|
237
|
-
<div className="fixed -bottom-0 flex translate-y-[98%] flex-col rounded-xs border-0 bg-
|
|
237
|
+
<div className="fixed -bottom-0 flex translate-y-[98%] flex-col rounded-xs border-0 bg-background p-2 shadow-lg hover:bg-background">
|
|
238
238
|
{overflowItems.map((item) => (
|
|
239
239
|
<div
|
|
240
240
|
key={item.key}
|
|
241
241
|
onClick={() => onClick?.(item)}
|
|
242
|
-
className="
|
|
242
|
+
className={buttonRecipe({ variant: "ghost" }, "relative whitespace-nowrap font-normal text-primary")}
|
|
243
243
|
onMouseEnter={() => {
|
|
244
244
|
if (item.children && expandedKey !== item.key) setExpandedKey(item.key);
|
|
245
245
|
}}
|
|
@@ -249,7 +249,7 @@ const OverflowMenu = ({ overflowItems, onClick }: OverflowMenuProps) => {
|
|
|
249
249
|
>
|
|
250
250
|
{item.label}
|
|
251
251
|
{item.children && expandedKey === item.key && (
|
|
252
|
-
<div className="absolute top-0 left-0 -translate-x-full bg-
|
|
252
|
+
<div className="absolute top-0 left-0 -translate-x-full bg-background p-4 drop-shadow-sm">
|
|
253
253
|
{item.children.map((child) => (
|
|
254
254
|
<div
|
|
255
255
|
onClick={(e) => {
|
|
@@ -258,8 +258,10 @@ const OverflowMenu = ({ overflowItems, onClick }: OverflowMenuProps) => {
|
|
|
258
258
|
setExpandedKey(undefined);
|
|
259
259
|
}}
|
|
260
260
|
key={child.key}
|
|
261
|
-
className=
|
|
262
|
-
|
|
261
|
+
className={buttonRecipe(
|
|
262
|
+
{ variant: "ghost" },
|
|
263
|
+
"flex items-center justify-center text-center font-normal text-primary",
|
|
264
|
+
)}
|
|
263
265
|
>
|
|
264
266
|
{child.label}
|
|
265
267
|
</div>
|
package/ui/Model/Edit.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn, usePage } from "akanjs/client";
|
|
2
2
|
import type { SliceMeta } from "akanjs/fetch";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { AiOutlineEdit } from "react-icons/ai";
|
|
@@ -29,9 +29,9 @@ export default function Edit({
|
|
|
29
29
|
}: EditProps) {
|
|
30
30
|
const { l } = usePage();
|
|
31
31
|
return (
|
|
32
|
-
<div className={
|
|
32
|
+
<div className={cn("inline", wrapperClassName)}>
|
|
33
33
|
<EditWrapper
|
|
34
|
-
className={
|
|
34
|
+
className={cn("flex w-full items-center justify-center gap-2", className)}
|
|
35
35
|
slice={slice}
|
|
36
36
|
modelId={modelId}
|
|
37
37
|
modal={modal}
|
package/ui/Model/EditModal.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, isRscNavigationFromCache, router, usePage } from "akanjs/client";
|
|
3
3
|
import { capitalize, deepObjectify, lowerlize } from "akanjs/common";
|
|
4
4
|
import { ConstantRegistry, immerify } from "akanjs/constant";
|
|
5
5
|
import type { ClientEdit, ServerEdit, SliceMeta } from "akanjs/fetch";
|
|
@@ -74,15 +74,15 @@ const EditModel = <Full,>({
|
|
|
74
74
|
: ({ children, className }: { children?: any; className?: string }) => {
|
|
75
75
|
const modelFormLoading = storeUse[names.modelFormLoading]();
|
|
76
76
|
return (
|
|
77
|
-
<div className={
|
|
77
|
+
<div className={cn("", className)}>
|
|
78
78
|
{children}
|
|
79
|
-
{modelFormLoading ? <div className="absolute inset-0 animate-pulse bg-
|
|
79
|
+
{modelFormLoading ? <div className="absolute inset-0 animate-pulse bg-background/50" /> : null}
|
|
80
80
|
</div>
|
|
81
81
|
);
|
|
82
82
|
};
|
|
83
83
|
}, []);
|
|
84
84
|
|
|
85
|
-
return <LoadingWrapper className={
|
|
85
|
+
return <LoadingWrapper className={cn("w-full", className)}>{children}</LoadingWrapper>;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
interface EditModalProps<Full extends { id: string }> extends EditModelProps<Full> {
|
|
@@ -256,7 +256,7 @@ export default function EditModal<Full extends { id: string }>({
|
|
|
256
256
|
};
|
|
257
257
|
return (
|
|
258
258
|
<Button
|
|
259
|
-
className={
|
|
259
|
+
className={cn("mt-4 w-full gap-2 rounded-2xl", submitClassName)}
|
|
260
260
|
disabled={modelSubmit.disabled || !!disabled}
|
|
261
261
|
onClick={async (e, { onError }) => {
|
|
262
262
|
await handleSubmit({ onError });
|
package/ui/Model/EditWrapper.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { SliceMeta } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
@@ -32,7 +32,7 @@ export default function EditWrapper({
|
|
|
32
32
|
const storeDo = st.do as unknown as { [key: string]: (...args: any[]) => Promise<void> };
|
|
33
33
|
return (
|
|
34
34
|
<div
|
|
35
|
-
className={
|
|
35
|
+
className={cn("cursor-pointer", className)}
|
|
36
36
|
onClick={(e) => {
|
|
37
37
|
if (disabled) return;
|
|
38
38
|
e.stopPropagation();
|
package/ui/Model/New.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn, usePage } from "akanjs/client";
|
|
2
2
|
import type { SliceMeta } from "akanjs/fetch";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { AiOutlinePlus } from "react-icons/ai";
|
|
@@ -29,9 +29,9 @@ export default function New({
|
|
|
29
29
|
}: NewProps) {
|
|
30
30
|
const { l } = usePage();
|
|
31
31
|
return (
|
|
32
|
-
<div className={
|
|
32
|
+
<div className={cn("inline", wrapperClassName)}>
|
|
33
33
|
<NewWrapper
|
|
34
|
-
className={
|
|
34
|
+
className={cn("flex w-full items-center justify-center gap-2", className)}
|
|
35
35
|
slice={slice}
|
|
36
36
|
modal={modal}
|
|
37
37
|
partial={partial}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import type { GetStateObject } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "akanjs/client";
|
|
4
4
|
import { capitalize } from "akanjs/common";
|
|
5
5
|
import { ConstantRegistry } from "akanjs/constant";
|
|
6
6
|
import type { SliceMeta } from "akanjs/fetch";
|
|
@@ -39,7 +39,7 @@ export const NewWrapper_Client = <Full,>({
|
|
|
39
39
|
const disabled = modelModal === "edit";
|
|
40
40
|
return (
|
|
41
41
|
<div
|
|
42
|
-
className={
|
|
42
|
+
className={cn(!disabled && "cursor-pointer", disabled && "pointer-events-none", className)}
|
|
43
43
|
onClick={(e) => {
|
|
44
44
|
e.stopPropagation();
|
|
45
45
|
if (disabled) return;
|
package/ui/Model/Remove.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, msg, router, usePage } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { SliceMeta } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
@@ -32,7 +32,7 @@ export default function Remove({ className, name, modelId, slice, modal, redirec
|
|
|
32
32
|
return (
|
|
33
33
|
<>
|
|
34
34
|
<div
|
|
35
|
-
className={
|
|
35
|
+
className={cn("cursor-pointer", className)}
|
|
36
36
|
onClick={(e) => {
|
|
37
37
|
e.stopPropagation();
|
|
38
38
|
setModalOpen(true);
|
|
@@ -46,13 +46,14 @@ export default function Remove({ className, name, modelId, slice, modal, redirec
|
|
|
46
46
|
setModalOpen(false);
|
|
47
47
|
}}
|
|
48
48
|
title={
|
|
49
|
-
<div className="font-bold text-
|
|
49
|
+
<div className="font-bold text-destructive text-lg">
|
|
50
50
|
{l("base.removeModel", { model: l(`${modelName}.modelName` as "base.new") })}
|
|
51
51
|
</div>
|
|
52
52
|
}
|
|
53
53
|
action={
|
|
54
54
|
<Button
|
|
55
|
-
|
|
55
|
+
variant="warning"
|
|
56
|
+
className="w-full"
|
|
56
57
|
onClick={async (e, { onError }) => {
|
|
57
58
|
await storeDo[names.removeModel](modelId, { onError, modal });
|
|
58
59
|
msg.success("base.removeSuccess", { data: { model: l(`${modelName}.modelName` as "base.new") } });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, usePage } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { SliceMeta } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
@@ -32,7 +32,7 @@ export default function RemoveWrapper({ children, slice, name, modelId, classNam
|
|
|
32
32
|
void storeDo[names.removeModel](modelId, { modal });
|
|
33
33
|
}}
|
|
34
34
|
>
|
|
35
|
-
<div className={
|
|
35
|
+
<div className={cn("cursor-pointer", className)}>{children}</div>
|
|
36
36
|
</Popconfirm>
|
|
37
37
|
);
|
|
38
38
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cn, msg, router, usePage } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { SliceMeta } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
6
6
|
import { useMemo, useState } from "react";
|
|
7
7
|
import { AiOutlineDelete } from "react-icons/ai";
|
|
8
8
|
|
|
9
|
+
import { buttonRecipe } from "../Button";
|
|
9
10
|
import { Modal } from "../Modal";
|
|
10
11
|
|
|
11
12
|
interface SureToRemoveProps {
|
|
@@ -46,8 +47,8 @@ export default function SureToRemove({
|
|
|
46
47
|
}}
|
|
47
48
|
>
|
|
48
49
|
<div
|
|
49
|
-
className={
|
|
50
|
-
"flex size-full cursor-pointer flex-nowrap items-center justify-center gap-2 whitespace-nowrap text-
|
|
50
|
+
className={cn(
|
|
51
|
+
"flex size-full cursor-pointer flex-nowrap items-center justify-center gap-2 whitespace-nowrap text-destructive",
|
|
51
52
|
className,
|
|
52
53
|
)}
|
|
53
54
|
>
|
|
@@ -59,14 +60,14 @@ export default function SureToRemove({
|
|
|
59
60
|
setModalOpen(false);
|
|
60
61
|
}}
|
|
61
62
|
title={
|
|
62
|
-
<div className="font-bold text-
|
|
63
|
+
<div className="font-bold text-destructive text-lg">
|
|
63
64
|
{l("base.removeModel", { model: l(`${modelName}.modelName` as "base.new") })}
|
|
64
65
|
</div>
|
|
65
66
|
}
|
|
66
|
-
bodyClassName="border-
|
|
67
|
+
bodyClassName="border-destructive"
|
|
67
68
|
action={
|
|
68
69
|
<button
|
|
69
|
-
className="
|
|
70
|
+
className={buttonRecipe({ variant: "destructive" }, "w-full")}
|
|
70
71
|
disabled={typeNameToRemove && repeatName !== name}
|
|
71
72
|
onClick={async () => {
|
|
72
73
|
await storeDo[names.removeModel](modelId);
|
package/ui/Model/View.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { type ReactNode, useMemo } from "react";
|
|
3
|
-
import { AiOutlineMeh } from "react-icons/ai";
|
|
3
|
+
import { AiOutlineLoading, AiOutlineMeh } from "react-icons/ai";
|
|
4
4
|
|
|
5
5
|
interface ViewProps<Full extends { id: string }> {
|
|
6
6
|
className?: string;
|
|
@@ -41,7 +41,7 @@ export default function View<Full extends { id: string }>({
|
|
|
41
41
|
: (loading ??
|
|
42
42
|
(() => (
|
|
43
43
|
<div className="flex size-full flex-col items-center justify-center gap-3 pt-6 pb-3">
|
|
44
|
-
<
|
|
44
|
+
<AiOutlineLoading className="animate-spin text-2xl text-primary/60" />
|
|
45
45
|
Loading
|
|
46
46
|
</div>
|
|
47
47
|
)))
|