@akanjs/cli 2.4.2-rc.3 → 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/.build-stamp +1 -1
- package/{abstractCompactor-ghh1q9an.js → abstractCompactor-rk6twzvj.js} +4 -4
- package/{agent.command-de4r6vk8.js → agent.command-jfz8yfwy.js} +8 -7
- package/{application.command-nfsfm96y.js → application.command-3smsv7mq.js} +5 -5
- package/{applicationBuildRunner-554a2vnk.js → applicationBuildRunner-aq7mb3z6.js} +2 -1
- package/buildBatch.proc.js +7 -6
- package/{capacitorApp-yg9b4ajz.js → capacitorApp-q3mpmkkz.js} +3 -3
- package/{cloud.command-1qf95x67.js → cloud.command-rk4e9vrt.js} +10 -10
- package/{context.command-hhjyjtp7.js → context.command-ygzyb0xb.js} +16 -15
- package/{guideline.command-vj956kfr.js → guideline.command-1m1ctar3.js} +10 -10
- package/guidelines/componentRule/componentRule.instruction.md +2 -2
- package/guidelines/cssRule/cssRule.generate.json +1 -1
- package/guidelines/cssRule/cssRule.instruction.md +57 -34
- package/guidelines/framework/framework.instruction.md +1 -1
- package/guidelines/recipeRule/recipeRule.generate.json +31 -0
- package/guidelines/recipeRule/recipeRule.instruction.md +72 -0
- package/incrementalBuilder.proc.js +5 -5
- package/{index-v9jqrdd1.js → index-4yp06pn1.js} +100 -2
- package/{index-pfnh87f9.js → index-4zgs8g1w.js} +1 -1
- package/{index-7ppn9v4n.js → index-b978vs2e.js} +3 -3
- package/{index-s9s0n5fz.js → index-cn24dcqn.js} +2 -2
- package/{index-h971erkm.js → index-csqk9z5j.js} +3 -3
- package/{index-z36qzgzp.js → index-e3qskyt2.js} +3 -4
- package/{index-fbv96xaw.js → index-ev6rjw9n.js} +11 -11
- package/{index-h6eav7zx.js → index-f4gqk0dd.js} +6 -6
- package/{index-z5v766nx.js → index-fmgbwsr5.js} +6 -6
- package/{index-y1e79mz3.js → index-h0bngh79.js} +13 -13
- package/{index-dgeaqwmw.js → index-hjzr8ja1.js} +1 -1
- package/{index-d0h48d2f.js → index-jk9q6pse.js} +1 -1
- package/{index-xwfg9bam.js → index-jtm86byd.js} +120 -4
- package/{index-h5cvg9z9.js → index-ktprgc5g.js} +4 -4
- package/{index-zn9rh7sh.js → index-n0z3f2xg.js} +73 -24
- package/{index-7k9sj7j5.js → index-pyt2b4nw.js} +212 -0
- package/{index-acwxfncv.js → index-r4w8cry5.js} +4 -4
- package/{index-zfp1gz9f.js → index-sggm9qkv.js} +1 -1
- package/{index-04as43rp.js → index-vhv3xnjz.js} +16 -15
- package/index-xjd3rqzj.js +129 -0
- package/{index-xftstr5s.js → index-xwgm94zr.js} +1 -1
- package/index-xys926f2.js +136 -0
- package/index.js +19 -19
- package/{library.command-68ah07a3.js → library.command-pwfx8dx2.js} +4 -4
- package/{localRegistry.command-84dz000g.js → localRegistry.command-bxhqmd1d.js} +9 -9
- package/{module.command-t68xhamx.js → module.command-0t3ewata.js} +8 -8
- package/{package.command-00ncttab.js → package.command-7hmkxvpa.js} +4 -4
- package/package.json +2 -3
- package/{page.command-1096s18n.js → page.command-st6r4s0q.js} +4 -4
- package/{primitive.command-02eqpx6t.js → primitive.command-1qkxpzsn.js} +9 -9
- package/{quality.command-r9cageqb.js → quality.command-hy5vt1bh.js} +3 -3
- package/recipeScanner-tghkzrrt.js +12 -0
- package/{repair.command-7dynpnf1.js → repair.command-nakkq2zp.js} +7 -6
- package/{scalar.command-3kxy3fkh.js → scalar.command-fjq272gs.js} +7 -7
- package/templates/app/page/_index.tsx +55 -52
- package/templates/app/page/styles.css.template +12 -71
- package/templates/appSample/lib/task/Task.Template.tsx +2 -2
- package/templates/appSample/lib/task/Task.Unit.tsx +11 -11
- package/templates/appSample/lib/task/Task.Util.tsx +27 -28
- package/templates/appSample/lib/task/Task.View.tsx +22 -19
- package/templates/appSample/lib/task/Task.Zone.tsx +3 -3
- package/templates/appSample/page/task/[taskId]/_index.tsx +3 -3
- package/templates/appSample/page/task/[taskId]/edit.tsx +5 -5
- package/templates/appSample/page/task/_index.tsx +4 -4
- package/templates/appSample/page/task/_layout.tsx +1 -1
- package/templates/appSample/page/task/new.tsx +5 -5
- package/templates/appSample/ui/GlobalLoading.tsx +4 -4
- package/templates/appSample/ui/QuantityControl.tsx +5 -4
- package/templates/crudPages/[__model__Id]/page.tsx +1 -1
- package/templates/crudPages/page.tsx +1 -1
- package/templates/crudSinglePage/page.tsx +1 -1
- package/templates/module/__Model__.Template.tsx +2 -1
- package/templates/module/__Model__.Unit.tsx +2 -1
- package/templates/module/__Model__.Util.tsx +2 -1
- package/templates/module/__Model__.View.tsx +4 -3
- package/templates/module/__Model__.Zone.tsx +2 -1
- package/templates/workspaceRoot/AGENTS.md.template +11 -13
- package/templates/workspaceRoot/biome.json.template +1 -1
- package/{workflow.command-yy0d9gk3.js → workflow.command-jswbgk90.js} +15 -14
- package/{workspace.command-stv9g4a0.js → workspace.command-p9r9nckg.js} +87 -27
- package/{applicationReleasePackager-pjbxc793.js → applicationReleasePackager-yrrhbkv3.js} +3 -3
- package/{index-nsj2ftxj.js → index-3pgtw35d.js} +3 -3
|
@@ -4,7 +4,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "Task.View.tsx",
|
|
6
6
|
content: `import { type cnst, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
-
import {
|
|
7
|
+
import { cn } from "akanjs/client";
|
|
8
|
+
import { badgeRecipe } from "akanjs/ui";
|
|
8
9
|
|
|
9
10
|
// ===== Task.View.tsx =====
|
|
10
11
|
// Convention: lib/<module>/ — PascalCase .tsx, View suffix = detail display component.
|
|
@@ -20,25 +21,25 @@ interface GeneralProps {
|
|
|
20
21
|
export const General = ({ className, task }: GeneralProps) => {
|
|
21
22
|
const { l } = usePage();
|
|
22
23
|
const statusColor = {
|
|
23
|
-
todo: "text-
|
|
24
|
+
todo: "text-foreground/50",
|
|
24
25
|
inProgress: "text-primary",
|
|
25
26
|
completed: "text-success",
|
|
26
27
|
}[task.status];
|
|
27
28
|
|
|
28
29
|
return (
|
|
29
|
-
<div className={
|
|
30
|
+
<div className={cn("flex w-full flex-col gap-4", className)}>
|
|
30
31
|
<div>
|
|
31
|
-
<h1 className="font-bold text-2xl text-
|
|
32
|
-
<div className={
|
|
32
|
+
<h1 className="font-bold text-2xl text-foreground">{task.title}</h1>
|
|
33
|
+
<div className={cn("mt-1 font-medium text-sm", statusColor)}>{l(\`taskStatus.\${task.status}\`)}</div>
|
|
33
34
|
</div>
|
|
34
35
|
|
|
35
36
|
{task.content && (
|
|
36
|
-
<div className="rounded-lg border border-
|
|
37
|
-
<p className="whitespace-pre-wrap text-
|
|
37
|
+
<div className="rounded-lg border border-foreground/10 bg-background p-4">
|
|
38
|
+
<p className="whitespace-pre-wrap text-foreground/80 text-sm">{task.content}</p>
|
|
38
39
|
</div>
|
|
39
40
|
)}
|
|
40
41
|
|
|
41
|
-
<div className="flex items-center gap-4 text-
|
|
42
|
+
<div className="flex items-center gap-4 text-foreground/60 text-sm">
|
|
42
43
|
<div>
|
|
43
44
|
<span className="font-medium">{l("task.taskDueLabel")} </span>
|
|
44
45
|
{task.due ? task.due.toDate().toLocaleDateString() : l("task.taskNoDue")}
|
|
@@ -46,23 +47,25 @@ export const General = ({ className, task }: GeneralProps) => {
|
|
|
46
47
|
</div>
|
|
47
48
|
|
|
48
49
|
{task.workHistory && task.workHistory.length > 0 && (
|
|
49
|
-
<div className="mt-2 border-
|
|
50
|
-
<h3 className="mb-3 font-semibold text-
|
|
50
|
+
<div className="mt-2 border-foreground/10 border-t pt-4">
|
|
51
|
+
<h3 className="mb-3 font-semibold text-foreground text-sm">{l("task.taskWorkHistoryTitle")}</h3>
|
|
51
52
|
<ul className="space-y-2">
|
|
52
53
|
{task.workHistory.map((entry, i) => (
|
|
53
54
|
<li key={i} className="flex items-start gap-3 text-sm">
|
|
54
55
|
<span
|
|
55
|
-
className={
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
className={cn(
|
|
57
|
+
badgeRecipe({
|
|
58
|
+
variant:
|
|
59
|
+
entry.action === "started" ? "primary" : entry.action === "completed" ? "success" : "default",
|
|
60
|
+
}),
|
|
61
|
+
"mt-0.5 shrink-0",
|
|
62
|
+
)}
|
|
60
63
|
>
|
|
61
64
|
{l(\`workHistoryAction.\${entry.action}\`)}
|
|
62
65
|
</span>
|
|
63
66
|
<div>
|
|
64
|
-
<span className="text-
|
|
65
|
-
{entry.note && <span className="ml-2 text-
|
|
67
|
+
<span className="text-foreground/60">{entry.at.toDate().toLocaleString()}</span>
|
|
68
|
+
{entry.note && <span className="ml-2 text-foreground/50">{entry.note}</span>}
|
|
66
69
|
</div>
|
|
67
70
|
</li>
|
|
68
71
|
))}
|
|
@@ -76,9 +79,9 @@ export const General = ({ className, task }: GeneralProps) => {
|
|
|
76
79
|
// ---- Expandable additional fields: ----
|
|
77
80
|
// Compact: for narrow spaces like sidebars or modals
|
|
78
81
|
// export const Compact = ({ className, task }: CompactProps) => (
|
|
79
|
-
// <div className={
|
|
82
|
+
// <div className={cn("text-sm", className)}>
|
|
80
83
|
// <span className="font-medium">{task.title}</span>
|
|
81
|
-
// {task.due && <span className="text-
|
|
84
|
+
// {task.due && <span className="text-foreground/50 ml-2">Due: {new Date(task.due).toLocaleDateString()}</span>}
|
|
82
85
|
// </div>
|
|
83
86
|
// );
|
|
84
87
|
`,
|
|
@@ -6,7 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
6
6
|
content: `"use client";
|
|
7
7
|
import { type cnst, Task, usePage } from "@apps/${dict.appName}/client";
|
|
8
8
|
import type { ClientInit, ClientView } from "akanjs/fetch";
|
|
9
|
-
import { Link, Load } from "akanjs/ui";
|
|
9
|
+
import { Link, Load, buttonRecipe } from "akanjs/ui";
|
|
10
10
|
|
|
11
11
|
// ===== Task.Zone.tsx =====
|
|
12
12
|
// Convention: lib/<module>/ — PascalCase .tsx, Zone suffix = composition layer between pages and UI.
|
|
@@ -28,9 +28,9 @@ export const Card = ({ className, init }: CardProps) => {
|
|
|
28
28
|
init={init}
|
|
29
29
|
renderEmpty={() => (
|
|
30
30
|
<div className="flex flex-col items-center gap-4 py-16 text-center">
|
|
31
|
-
<div className="text-
|
|
31
|
+
<div className="text-foreground/40 text-lg">{l("task.taskNoTasks")}</div>
|
|
32
32
|
<Link href="/task/new">
|
|
33
|
-
<button className="
|
|
33
|
+
<button className={buttonRecipe({ variant: "primary", size: "sm" })}>{l("task.taskCreateFirst")}</button>
|
|
34
34
|
</Link>
|
|
35
35
|
</div>
|
|
36
36
|
)}
|
|
@@ -6,7 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
6
6
|
content: `
|
|
7
7
|
import { fetch, usePage } from "@apps/${dict.appName}/client";
|
|
8
8
|
import { Task } from "@apps/${dict.appName}/lib/task";
|
|
9
|
-
import { Link } from "akanjs/ui";
|
|
9
|
+
import { Link, buttonRecipe } from "akanjs/ui";
|
|
10
10
|
|
|
11
11
|
// ===== page/task/[taskId]/_index.tsx =====
|
|
12
12
|
// Convention: Akan.js file-based routing with dynamic segments.
|
|
@@ -22,10 +22,10 @@ export default async function Page({ params: { taskId } }: PageProps) {
|
|
|
22
22
|
return (
|
|
23
23
|
<main className="mx-auto max-w-4xl px-6 py-8">
|
|
24
24
|
<div className="mb-6 flex items-center justify-between">
|
|
25
|
-
<a href="/task" className="
|
|
25
|
+
<a href="/task" className={buttonRecipe({ variant: "ghost", size: "sm" })}>
|
|
26
26
|
{l("task.taskBackToTasks")}
|
|
27
27
|
</a>
|
|
28
|
-
<Link href={\`/task/\${taskId}/edit\`} className="
|
|
28
|
+
<Link href={\`/task/\${taskId}/edit\`} className={buttonRecipe({ variant: "primary", size: "sm" })}>
|
|
29
29
|
{l("task.taskEdit")}
|
|
30
30
|
</Link>
|
|
31
31
|
</div>
|
|
@@ -4,7 +4,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "edit.tsx",
|
|
6
6
|
content: `import { fetch, Task } from "@apps/${dict.appName}/client";
|
|
7
|
-
import { Load, Link } from "akanjs/ui";
|
|
7
|
+
import { Load, Link, buttonRecipe } from "akanjs/ui";
|
|
8
8
|
|
|
9
9
|
// ===== page/task/[taskId]/edit.tsx =====
|
|
10
10
|
// Convention: Server-side edit form page using Load.Edit from akanjs/ui.
|
|
@@ -21,15 +21,15 @@ export default async function Page({ params: { taskId } }: PageProps) {
|
|
|
21
21
|
return (
|
|
22
22
|
<main className="mx-auto max-w-2xl px-6 py-8">
|
|
23
23
|
<div className="mb-6">
|
|
24
|
-
<Link href={\`/task/\${taskId}\`} className="
|
|
24
|
+
<Link href={\`/task/\${taskId}\`} className={buttonRecipe({ variant: "ghost", size: "sm" })}>
|
|
25
25
|
← Back to Task
|
|
26
26
|
</Link>
|
|
27
27
|
</div>
|
|
28
28
|
<div className="mb-6">
|
|
29
|
-
<h1 className="font-extrabold text-3xl text-
|
|
30
|
-
<p className="mt-1 text-
|
|
29
|
+
<h1 className="font-extrabold text-3xl text-foreground">Edit Task</h1>
|
|
30
|
+
<p className="mt-1 text-foreground/60 text-sm">Update the task details</p>
|
|
31
31
|
</div>
|
|
32
|
-
<div className="rounded-xl border border-
|
|
32
|
+
<div className="rounded-xl border border-foreground/10 bg-background p-6 shadow-sm">
|
|
33
33
|
<Load.Edit slice={fetch.slice.taskInPublic} edit={taskEdit} type="form" onSubmit={\`/task/\${taskId}\`}>
|
|
34
34
|
<Task.Template.General />
|
|
35
35
|
</Load.Edit>
|
|
@@ -4,7 +4,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "_index.tsx",
|
|
6
6
|
content: `import { fetch, Task, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
-
import { Link } from "akanjs/ui";
|
|
7
|
+
import { Link, buttonRecipe } from "akanjs/ui";
|
|
8
8
|
|
|
9
9
|
// ===== page/task/_index.tsx =====
|
|
10
10
|
// Convention: Akan.js file-based routing — _index.tsx is the index page for /task.
|
|
@@ -18,10 +18,10 @@ export default async function Page() {
|
|
|
18
18
|
<main className="mx-auto max-w-4xl px-6 py-8">
|
|
19
19
|
<div className="mb-6 flex items-center justify-between">
|
|
20
20
|
<div>
|
|
21
|
-
<h1 className="font-extrabold text-3xl text-
|
|
22
|
-
<p className="mt-1 text-
|
|
21
|
+
<h1 className="font-extrabold text-3xl text-foreground">{l("task.modelName")}</h1>
|
|
22
|
+
<p className="mt-1 text-foreground/60 text-sm">{l("task.modelDesc")}</p>
|
|
23
23
|
</div>
|
|
24
|
-
<Link href="/task/new" className="
|
|
24
|
+
<Link href="/task/new" className={buttonRecipe({ variant: "primary", size: "sm" })}>
|
|
25
25
|
{l("task.taskNew")}
|
|
26
26
|
</Link>
|
|
27
27
|
</div>
|
|
@@ -4,7 +4,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "new.tsx",
|
|
6
6
|
content: `import { type cnst, fetch, Task, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
-
import { Load, Link } from "akanjs/ui";
|
|
7
|
+
import { Load, Link, buttonRecipe } from "akanjs/ui";
|
|
8
8
|
|
|
9
9
|
// ===== page/task/new.tsx =====
|
|
10
10
|
// Convention: Server-side form page using Load.Edit from akanjs/ui.
|
|
@@ -19,15 +19,15 @@ export default async function Page() {
|
|
|
19
19
|
return (
|
|
20
20
|
<main className="mx-auto max-w-2xl px-6 py-8">
|
|
21
21
|
<div className="mb-6">
|
|
22
|
-
<Link href="/task" className="
|
|
22
|
+
<Link href="/task" className={buttonRecipe({ variant: "ghost", size: "sm" })}>
|
|
23
23
|
← Tasks
|
|
24
24
|
</Link>
|
|
25
25
|
</div>
|
|
26
26
|
<div className="mb-6">
|
|
27
|
-
<h1 className="font-extrabold text-3xl text-
|
|
28
|
-
<p className="mt-1 text-
|
|
27
|
+
<h1 className="font-extrabold text-3xl text-foreground">New Task</h1>
|
|
28
|
+
<p className="mt-1 text-foreground/60 text-sm">Create a new task with title and description</p>
|
|
29
29
|
</div>
|
|
30
|
-
<div className="rounded-xl border border-
|
|
30
|
+
<div className="rounded-xl border border-foreground/10 bg-background p-6 shadow-sm">
|
|
31
31
|
<Load.Edit slice={fetch.slice.taskInPublic} edit={taskForm} type="form" onCancel="back" onSubmit="/task">
|
|
32
32
|
<Task.Template.General />
|
|
33
33
|
</Load.Edit>
|
|
@@ -5,7 +5,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
5
5
|
filename: "GlobalLoading.tsx",
|
|
6
6
|
content: `"use client";
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { cn } from "akanjs/client";
|
|
9
9
|
|
|
10
10
|
// ===== GlobalLoading.tsx =====
|
|
11
11
|
// Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
|
|
@@ -19,9 +19,9 @@ interface GlobalLoadingProps {
|
|
|
19
19
|
|
|
20
20
|
export const GlobalLoading = ({ className, message = "Loading..." }: GlobalLoadingProps) => {
|
|
21
21
|
return (
|
|
22
|
-
<div className={
|
|
23
|
-
<span className="
|
|
24
|
-
<span className="text-
|
|
22
|
+
<div className={cn("flex flex-col items-center justify-center gap-4 py-32", className)}>
|
|
23
|
+
<span className="inline-block size-8 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
|
24
|
+
<span className="text-foreground/60 text-sm">{message}</span>
|
|
25
25
|
</div>
|
|
26
26
|
);
|
|
27
27
|
};
|
|
@@ -5,7 +5,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
5
5
|
filename: "QuantityControl.tsx",
|
|
6
6
|
content: `"use client";
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { cn } from "akanjs/client";
|
|
9
|
+
import { buttonRecipe } from "akanjs/ui";
|
|
9
10
|
|
|
10
11
|
// ===== QuantityControl.tsx =====
|
|
11
12
|
// Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
|
|
@@ -28,9 +29,9 @@ export const QuantityControl = ({
|
|
|
28
29
|
max = 99,
|
|
29
30
|
}: QuantityControlProps) => {
|
|
30
31
|
return (
|
|
31
|
-
<div className={
|
|
32
|
+
<div className={cn("inline-flex items-center gap-1", className)}>
|
|
32
33
|
<button
|
|
33
|
-
className="
|
|
34
|
+
className={buttonRecipe({ variant: "outline", size: "icon" }, "size-6 rounded-full")}
|
|
34
35
|
disabled={value <= min}
|
|
35
36
|
onClick={() => onChange(Math.max(min, value - 1))}
|
|
36
37
|
>
|
|
@@ -38,7 +39,7 @@ export const QuantityControl = ({
|
|
|
38
39
|
</button>
|
|
39
40
|
<span className="w-8 text-center font-medium tabular-nums">{value}</span>
|
|
40
41
|
<button
|
|
41
|
-
className="
|
|
42
|
+
className={buttonRecipe({ variant: "outline", size: "icon" }, "size-6 rounded-full")}
|
|
42
43
|
disabled={value >= max}
|
|
43
44
|
onClick={() => onChange(Math.min(max, value + 1))}
|
|
44
45
|
>
|
|
@@ -38,7 +38,7 @@ export default async function Page({ params }: PageProps) {
|
|
|
38
38
|
<div className="flex gap-4 font-bold text-lg items-center">
|
|
39
39
|
<${dict.Model}.Zone.View view={${dict.model}View} />
|
|
40
40
|
<Link href={\`/${dict.model}/\${${dict.model}.id}/edit\`}>
|
|
41
|
-
<button className="
|
|
41
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-field bg-primary px-4 py-2 font-medium text-primary-foreground text-sm transition-colors hover:bg-primary/90">
|
|
42
42
|
{l("base.updateModel", { model: l("${dict.model}.modelName") })}
|
|
43
43
|
</button>
|
|
44
44
|
</Link>
|
|
@@ -23,7 +23,7 @@ export default async function Page() {
|
|
|
23
23
|
<div className="animate-fadeIn px-4 pt-4 flex gap-4 items-center">
|
|
24
24
|
<div className="font-bold text-lg md:text-4xl">${dict.Model}s</div>
|
|
25
25
|
<Link href={\`/${dict.model}/new\`}>
|
|
26
|
-
<button className="
|
|
26
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-field bg-primary px-4 py-2 font-medium text-primary-foreground text-sm transition-colors hover:bg-primary/90">+ {l("base.createModel", { model: l("${dict.model}.modelName") })}</button>
|
|
27
27
|
</Link>
|
|
28
28
|
</div>
|
|
29
29
|
<div>{l("${dict.model}.modelDesc")}</div>
|
|
@@ -20,7 +20,7 @@ export default async function Page() {
|
|
|
20
20
|
<>
|
|
21
21
|
<div className="animate-fadeIn flex items-center gap-4 px-4 pt-4">
|
|
22
22
|
<div className="text-lg font-bold md:text-4xl">{l("${dict.model}.modelName")}</div>
|
|
23
|
-
<Model.New className="
|
|
23
|
+
<Model.New className="inline-flex items-center gap-2 rounded-field px-3 py-1.5 text-sm transition-colors hover:bg-muted" slice={fetch.slice["${dict.model}InPublic"]} renderTitle="id">
|
|
24
24
|
<${dict.Model}.Template.General />
|
|
25
25
|
</Model.New>
|
|
26
26
|
</div>
|
|
@@ -4,6 +4,7 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
sysName: string;
|
|
7
|
+
sysType: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
@@ -11,7 +12,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
|
|
|
11
12
|
content: `
|
|
12
13
|
"use client";
|
|
13
14
|
import { Field, Layout } from "akanjs/ui";
|
|
14
|
-
import { st, usePage } from "@${
|
|
15
|
+
import { st, usePage } from "@${dict.sysType}s/${dict.sysName}/client";
|
|
15
16
|
|
|
16
17
|
interface GeneralProps {
|
|
17
18
|
className?: string;
|
|
@@ -4,13 +4,14 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
sysName: string;
|
|
7
|
+
sysType: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: `${dict.Model}.Unit.tsx`,
|
|
11
12
|
content: `
|
|
12
13
|
import type { ModelProps } from "akanjs/client";
|
|
13
|
-
import { cnst, usePage } from "@${
|
|
14
|
+
import { cnst, usePage } from "@${dict.sysType}s/${dict.sysName}/client";
|
|
14
15
|
import { Link } from "akanjs/ui";
|
|
15
16
|
|
|
16
17
|
export const Card = ({ ${dict.model}, href }: ModelProps<"${dict.model}", cnst.Light${dict.Model}>) => {
|
|
@@ -4,6 +4,7 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
sysName: string;
|
|
7
|
+
sysType: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
@@ -11,7 +12,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
|
|
|
11
12
|
content: `
|
|
12
13
|
"use client";
|
|
13
14
|
import { Model } from "akanjs/ui";
|
|
14
|
-
import { fetch, usePage } from "@${
|
|
15
|
+
import { fetch, usePage } from "@${dict.sysType}s/${dict.sysName}/client";
|
|
15
16
|
import { BiTrash } from "react-icons/bi";
|
|
16
17
|
|
|
17
18
|
interface RemoveProps {
|
|
@@ -4,13 +4,14 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
sysName: string;
|
|
7
|
+
sysType: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: `${dict.Model}.View.tsx`,
|
|
11
12
|
content: `
|
|
12
|
-
import {
|
|
13
|
-
import { cnst, usePage } from "@${
|
|
13
|
+
import { cn } from "akanjs/client";
|
|
14
|
+
import { cnst, usePage } from "@${dict.sysType}s/${dict.sysName}/client";
|
|
14
15
|
|
|
15
16
|
interface GeneralProps {
|
|
16
17
|
className?: string;
|
|
@@ -19,7 +20,7 @@ interface GeneralProps {
|
|
|
19
20
|
export const General = ({ className, ${dict.model} }: GeneralProps) => {
|
|
20
21
|
const { l } = usePage();
|
|
21
22
|
return (
|
|
22
|
-
<div className={
|
|
23
|
+
<div className={cn("w-full", className)}>
|
|
23
24
|
<div>{l("${dict.model}.name")}: {${dict.model}.name}</div>
|
|
24
25
|
</div>
|
|
25
26
|
);
|
|
@@ -4,6 +4,7 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
sysName: string;
|
|
7
|
+
sysType: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
@@ -13,7 +14,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
|
|
|
13
14
|
import { Load } from "akanjs/ui";
|
|
14
15
|
// Alias the domain namespace so the Card/View exports below never collide with the model name
|
|
15
16
|
// (a model literally named "card" or "view" would otherwise shadow this import).
|
|
16
|
-
import { type cnst, ${dict.Model} as ${dict.Model}Domain } from "@${
|
|
17
|
+
import { type cnst, ${dict.Model} as ${dict.Model}Domain } from "@${dict.sysType}s/${dict.sysName}/client";
|
|
17
18
|
import type { ClientInit, ClientView, SliceMeta } from "akanjs/fetch";
|
|
18
19
|
|
|
19
20
|
interface CardProps {
|
|
@@ -239,7 +239,7 @@ final fallback when no CLI command covers the change.
|
|
|
239
239
|
| Add a pure workflow / integration (e.g., Payment, Email) | `lib/_<service>/` → service, signal, store, dictionary, abstract | `akan sync <name>` |
|
|
240
240
|
| Add a reusable value type (e.g., Address, WorkHistory) | `lib/__scalar/<type>/` → constant, dictionary, abstract | `akan sync <name>` |
|
|
241
241
|
| Create a new URL-visitable page | `page/` → `_index.tsx`, `_layout.tsx`, `[param]/_index.tsx` | Rebuild (akan start auto-detects) |
|
|
242
|
-
| Change the app color theme / design tokens | `apps/<app>/page/styles.css` →
|
|
242
|
+
| Change the app color theme / design tokens | `apps/<app>/page/styles.css` → override the semantic token values under `:root, [data-theme="dark"]` and `[data-theme="light"]` (`--primary`, `--background`, `--foreground`, …) | akan start hot-reloads |
|
|
243
243
|
| Add a form or reusable UI component | `ui/` → PascalCase `.tsx` with `"use client"` if needed | `akan sync <name>` |
|
|
244
244
|
| Add a React hook or browser helper | `webkit/` → camelCase `.ts` with `"use client"` | `akan sync <name>` |
|
|
245
245
|
| Add a server-only guard, middleware, or adaptor | `srvkit/` → PascalCase `.ts` | `akan sync <name>` |
|
|
@@ -439,11 +439,9 @@ const form = st.use.taskForm();
|
|
|
439
439
|
|
|
440
440
|
// 4. apps/<app>/lib/<model>/<Model>.Unit.tsx
|
|
441
441
|
// Display the new field in card/list views
|
|
442
|
-
<
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
"badge-ghost": task.priority === "low",
|
|
446
|
-
})}>{task.priority}</span>
|
|
442
|
+
<Badge variant={task.priority === "high" ? "error" : task.priority === "medium" ? "warning" : "default"}>
|
|
443
|
+
{task.priority}
|
|
444
|
+
</Badge>
|
|
447
445
|
|
|
448
446
|
// 5. Regenerate barrels
|
|
449
447
|
// akan sync <name>
|
|
@@ -632,7 +630,7 @@ async startTask(taskId: string) {
|
|
|
632
630
|
|
|
633
631
|
// 6. <Model>.Util.tsx — Reusable button component
|
|
634
632
|
export const Start = ({ taskId }: { taskId: string }) => (
|
|
635
|
-
<button className=
|
|
633
|
+
<button className={buttonRecipe({ variant: "primary", size: "xs" })} onClick={() => st.do.startTask(taskId)}>
|
|
636
634
|
Start
|
|
637
635
|
</button>
|
|
638
636
|
);
|
|
@@ -694,13 +692,13 @@ export class TaskInsight extends via(Task, (field) => ({
|
|
|
694
692
|
// 3. <Model>.View.tsx — Display component consuming an Insight model
|
|
695
693
|
export const Stats = ({ taskInsight }: { taskInsight: cnst.TaskInsight }) => (
|
|
696
694
|
<div className="grid grid-cols-2 gap-4">
|
|
697
|
-
<div className="
|
|
698
|
-
<div className="
|
|
699
|
-
<div className="
|
|
695
|
+
<div className="rounded-lg border border-border bg-card p-4">
|
|
696
|
+
<div className="text-muted-foreground text-sm">{l("task.totalCount")}</div>
|
|
697
|
+
<div className="font-bold text-2xl text-primary">{taskInsight.totalCount}</div>
|
|
700
698
|
</div>
|
|
701
|
-
<div className="
|
|
702
|
-
<div className="
|
|
703
|
-
<div className="
|
|
699
|
+
<div className="rounded-lg border border-border bg-card p-4">
|
|
700
|
+
<div className="text-muted-foreground text-sm">{l("task.completedCount")}</div>
|
|
701
|
+
<div className="font-bold text-2xl text-success">{taskInsight.completedCount}</div>
|
|
704
702
|
</div>
|
|
705
703
|
</div>
|
|
706
704
|
);
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
WorkflowRunner
|
|
4
|
-
} from "./index-
|
|
5
|
-
import {
|
|
6
|
-
ScalarScript
|
|
7
|
-
} from "./index-z5v766nx.js";
|
|
4
|
+
} from "./index-csqk9z5j.js";
|
|
8
5
|
import {
|
|
9
6
|
PrimitiveScript
|
|
10
|
-
} from "./index-
|
|
7
|
+
} from "./index-r4w8cry5.js";
|
|
11
8
|
import {
|
|
12
9
|
ModuleScript
|
|
13
|
-
} from "./index-
|
|
14
|
-
import"./index-
|
|
10
|
+
} from "./index-vhv3xnjz.js";
|
|
11
|
+
import"./index-hjzr8ja1.js";
|
|
12
|
+
import {
|
|
13
|
+
ScalarScript
|
|
14
|
+
} from "./index-fmgbwsr5.js";
|
|
15
15
|
import"./index-ss469dec.js";
|
|
16
|
-
import"./index-
|
|
16
|
+
import"./index-3pgtw35d.js";
|
|
17
|
+
import"./index-4yp06pn1.js";
|
|
17
18
|
import {
|
|
18
19
|
createWorkflowStepRegistry
|
|
19
|
-
} from "./index-
|
|
20
|
-
import"./index-
|
|
21
|
-
import"./index-nsj2ftxj.js";
|
|
20
|
+
} from "./index-4zgs8g1w.js";
|
|
21
|
+
import"./index-xwgm94zr.js";
|
|
22
22
|
import {
|
|
23
23
|
Workspace,
|
|
24
24
|
command,
|
|
25
25
|
script
|
|
26
|
-
} from "./index-
|
|
27
|
-
import"./index-
|
|
28
|
-
import"./index-67546d0j.js";
|
|
26
|
+
} from "./index-jk9q6pse.js";
|
|
27
|
+
import"./index-jtm86byd.js";
|
|
29
28
|
import"./index-6pz1j0zj.js";
|
|
29
|
+
import"./index-xys926f2.js";
|
|
30
|
+
import"./index-67546d0j.js";
|
|
30
31
|
import"./index-r24hmh0q.js";
|
|
31
32
|
|
|
32
33
|
// pkgs/@akanjs/cli/workflow/workflow.script.ts
|