@akanjs/cli 2.3.1-rc.3 → 2.3.1-rc.5
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/index.js +9 -2
- package/package.json +2 -2
- package/templates/appSample/common/formatters.ts +32 -0
- package/templates/appSample/common/validators.ts +32 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +47 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.constant.ts +35 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.dictionary.ts +25 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.document.ts +10 -0
- package/templates/appSample/lib/_noti/noti.abstract.ts +38 -0
- package/templates/appSample/lib/_noti/noti.dictionary.ts +23 -0
- package/templates/appSample/lib/_noti/noti.service.ts +27 -0
- package/templates/appSample/lib/_noti/noti.signal.ts +26 -0
- package/templates/appSample/lib/_noti/noti.store.ts +35 -0
- package/templates/appSample/lib/task/Task.Template.tsx +45 -0
- package/templates/appSample/lib/task/Task.Unit.tsx +65 -0
- package/templates/appSample/lib/task/Task.Util.tsx +105 -0
- package/templates/appSample/lib/task/Task.View.tsx +86 -0
- package/templates/appSample/lib/task/Task.Zone.tsx +54 -0
- package/templates/appSample/lib/task/task.abstract.ts +40 -0
- package/templates/appSample/lib/task/task.constant.ts +53 -0
- package/templates/appSample/lib/task/task.dictionary.ts +77 -0
- package/templates/appSample/lib/task/task.document.ts +51 -0
- package/templates/appSample/lib/task/task.service.ts +44 -0
- package/templates/appSample/lib/task/task.signal.ts +54 -0
- package/templates/appSample/lib/task/task.store.ts +42 -0
- package/templates/appSample/page/task/[taskId]/_index.tsx +39 -0
- package/templates/appSample/page/task/[taskId]/edit.tsx +28 -0
- package/templates/appSample/page/task/_index.tsx +34 -0
- package/templates/appSample/page/task/_layout.tsx +24 -0
- package/templates/appSample/page/task/new.tsx +26 -0
- package/templates/appSample/srvkit/AuthGuard.ts +35 -0
- package/templates/appSample/srvkit/SessionInternalArg.ts +32 -0
- package/templates/appSample/ui/GlobalLoading.tsx +30 -0
- package/templates/appSample/ui/QuantityControl.tsx +52 -0
- package/templates/appSample/webkit/useDebounce.ts +41 -0
- package/templates/module/__model__.document.ts +1 -1
- package/templates/workspaceRoot/AGENTS.md.template +470 -16
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
|
+
|
|
3
|
+
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
+
return {
|
|
5
|
+
filename: "AuthGuard.ts",
|
|
6
|
+
content: `import type { Guard, SignalContext } from "akanjs/signal";
|
|
7
|
+
|
|
8
|
+
// ===== AuthGuard.ts =====
|
|
9
|
+
// Convention: srvkit/ folder — server-only helpers, cannot import from client code.
|
|
10
|
+
// Implements the Guard interface from akanjs/signal.
|
|
11
|
+
// Guards are applied at endpoint/slice declaration: { guards: { root: SignedIn } }.
|
|
12
|
+
// Naming: PascalCase .ts, static name property matches the guard identifier.
|
|
13
|
+
// Scanned by akan scan into srvkit/index.ts barrel automatically.
|
|
14
|
+
|
|
15
|
+
export class SignedIn implements Guard {
|
|
16
|
+
static name = "SignedIn";
|
|
17
|
+
|
|
18
|
+
canPass(context: SignalContext): boolean {
|
|
19
|
+
const user = context.getHttpContext<{ user?: { id: string } }>().req.user;
|
|
20
|
+
return !!user;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ---- Expandable additional fields: ----
|
|
25
|
+
// Role-based guard: only allow users with a specific role
|
|
26
|
+
// export class IsAdmin implements Guard {
|
|
27
|
+
// static name = "IsAdmin";
|
|
28
|
+
// canPass(context: SignalContext): boolean {
|
|
29
|
+
// const user = context.getHttpContext<{ user?: { role: string } }>().req.user;
|
|
30
|
+
// return user?.role === "admin";
|
|
31
|
+
// }
|
|
32
|
+
// }
|
|
33
|
+
`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
|
+
|
|
3
|
+
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
+
return {
|
|
5
|
+
filename: "SessionInternalArg.ts",
|
|
6
|
+
content: `import type { InternalArg, SignalContext } from "akanjs/signal";
|
|
7
|
+
|
|
8
|
+
// ===== SessionInternalArg.ts =====
|
|
9
|
+
// Convention: srvkit/ folder — server-only helpers.
|
|
10
|
+
// Implements the InternalArg interface from akanjs/signal.
|
|
11
|
+
// InternalArg is an auto-injected argument for resolveField/endpoint .with() chains.
|
|
12
|
+
// Appended to a query/mutation via: .with(CurrentUserId, { nullable: true }).exec(...)
|
|
13
|
+
// Naming: PascalCase .ts, class name = arg identifier.
|
|
14
|
+
// Scanned by akan scan into srvkit/index.ts barrel automatically.
|
|
15
|
+
|
|
16
|
+
export class CurrentUserId implements InternalArg<string | null> {
|
|
17
|
+
getArg(context: SignalContext): string | null {
|
|
18
|
+
const user = context.getHttpContext<{ user?: { id: string } }>().req.user;
|
|
19
|
+
return user?.id ?? null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ---- Expandable additional fields: ----
|
|
24
|
+
// Inject current session language/locale
|
|
25
|
+
// export class CurrentLocale implements InternalArg<string> {
|
|
26
|
+
// getArg(context: SignalContext): string {
|
|
27
|
+
// return context.getHttpContext<{ locale?: string }>().req.locale ?? "en";
|
|
28
|
+
// }
|
|
29
|
+
// }
|
|
30
|
+
`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
|
+
|
|
3
|
+
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
+
return {
|
|
5
|
+
filename: "GlobalLoading.tsx",
|
|
6
|
+
content: `"use client";
|
|
7
|
+
|
|
8
|
+
import { clsx } from "akanjs/client";
|
|
9
|
+
|
|
10
|
+
// ===== GlobalLoading.tsx =====
|
|
11
|
+
// Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
|
|
12
|
+
// File name = exported component name.
|
|
13
|
+
// Scanned by akan scan into ui/index.ts barrel automatically.
|
|
14
|
+
|
|
15
|
+
interface GlobalLoadingProps {
|
|
16
|
+
className?: string;
|
|
17
|
+
message?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const GlobalLoading = ({ className, message = "Loading..." }: GlobalLoadingProps) => {
|
|
21
|
+
return (
|
|
22
|
+
<div className={clsx("flex flex-col items-center justify-center gap-4 py-32", className)}>
|
|
23
|
+
<span className="loading loading-spinner loading-lg text-primary" />
|
|
24
|
+
<span className="text-base-content/60 text-sm">{message}</span>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
|
+
|
|
3
|
+
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
+
return {
|
|
5
|
+
filename: "QuantityControl.tsx",
|
|
6
|
+
content: `"use client";
|
|
7
|
+
|
|
8
|
+
import { clsx } from "akanjs/client";
|
|
9
|
+
|
|
10
|
+
// ===== QuantityControl.tsx =====
|
|
11
|
+
// Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
|
|
12
|
+
// File name = exported component name.
|
|
13
|
+
// Scanned by akan scan into ui/index.ts barrel automatically.
|
|
14
|
+
|
|
15
|
+
interface QuantityControlProps {
|
|
16
|
+
className?: string;
|
|
17
|
+
value: number;
|
|
18
|
+
onChange: (value: number) => void;
|
|
19
|
+
min?: number;
|
|
20
|
+
max?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const QuantityControl = ({
|
|
24
|
+
className,
|
|
25
|
+
value,
|
|
26
|
+
onChange,
|
|
27
|
+
min = 0,
|
|
28
|
+
max = 99,
|
|
29
|
+
}: QuantityControlProps) => {
|
|
30
|
+
return (
|
|
31
|
+
<div className={clsx("inline-flex items-center gap-1", className)}>
|
|
32
|
+
<button
|
|
33
|
+
className="btn btn-circle btn-outline btn-xs"
|
|
34
|
+
disabled={value <= min}
|
|
35
|
+
onClick={() => onChange(Math.max(min, value - 1))}
|
|
36
|
+
>
|
|
37
|
+
−
|
|
38
|
+
</button>
|
|
39
|
+
<span className="w-8 text-center font-medium tabular-nums">{value}</span>
|
|
40
|
+
<button
|
|
41
|
+
className="btn btn-circle btn-outline btn-xs"
|
|
42
|
+
disabled={value >= max}
|
|
43
|
+
onClick={() => onChange(Math.min(max, value + 1))}
|
|
44
|
+
>
|
|
45
|
+
+
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
|
+
|
|
3
|
+
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
+
return {
|
|
5
|
+
filename: "useDebounce.ts",
|
|
6
|
+
content: `"use client";
|
|
7
|
+
|
|
8
|
+
import { useEffect, useState } from "react";
|
|
9
|
+
|
|
10
|
+
// ===== useDebounce.ts =====
|
|
11
|
+
// Convention: webkit/ folder — browser-only hooks; "use client" directive required.
|
|
12
|
+
// useEffect/useState are React client-side primitives that only work in the browser.
|
|
13
|
+
// Naming: camelCase .ts, file name = primary export name.
|
|
14
|
+
// Scanned by akan scan into webkit/index.ts barrel automatically.
|
|
15
|
+
|
|
16
|
+
export function useDebounce<T>(value: T, delay = 300): T {
|
|
17
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const timer = setTimeout(() => setDebouncedValue(value), delay);
|
|
21
|
+
return () => clearTimeout(timer);
|
|
22
|
+
}, [value, delay]);
|
|
23
|
+
|
|
24
|
+
return debouncedValue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ---- Expandable additional fields: ----
|
|
28
|
+
// useViewportWidth: detect browser window width
|
|
29
|
+
// export function useViewportWidth() {
|
|
30
|
+
// const [width, setWidth] = useState(0);
|
|
31
|
+
// useEffect(() => {
|
|
32
|
+
// const handleResize = () => setWidth(window.innerWidth);
|
|
33
|
+
// handleResize();
|
|
34
|
+
// window.addEventListener("resize", handleResize);
|
|
35
|
+
// return () => window.removeEventListener("resize", handleResize);
|
|
36
|
+
// }, []);
|
|
37
|
+
// return width;
|
|
38
|
+
// }
|
|
39
|
+
`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -7,7 +7,7 @@ interface Dict {
|
|
|
7
7
|
}
|
|
8
8
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
9
|
return `
|
|
10
|
-
import { by, from, into
|
|
10
|
+
import { by, from, into } from "akanjs/document";
|
|
11
11
|
|
|
12
12
|
import * as cnst from "../cnst";
|
|
13
13
|
|