@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
|
@@ -26,7 +26,7 @@ export default function Page() {
|
|
|
26
26
|
const appName = getEnv().appName;
|
|
27
27
|
const { l } = usePage();
|
|
28
28
|
return (
|
|
29
|
-
<main className="relative min-h-screen overflow-hidden bg-
|
|
29
|
+
<main className="relative min-h-screen overflow-hidden bg-background text-foreground">
|
|
30
30
|
<div className="absolute -top-48 -left-48 h-96 w-96 rounded-full bg-primary/25 blur-3xl" />
|
|
31
31
|
<div className="absolute -right-40 -bottom-56 h-112 w-md rounded-full bg-accent/20 blur-3xl" />
|
|
32
32
|
<div className="absolute inset-x-0 top-0 h-px bg-linear-to-r from-transparent via-primary/60 to-transparent" />
|
|
@@ -34,7 +34,7 @@ export default function Page() {
|
|
|
34
34
|
<section className="relative mx-auto flex min-h-screen w-full max-w-7xl flex-col px-6 py-8 lg:px-8">
|
|
35
35
|
<nav className="flex items-center justify-between">
|
|
36
36
|
<div className="flex items-center gap-3">
|
|
37
|
-
<div className="flex h-11 w-11 items-center justify-center overflow-hidden rounded-2xl bg-
|
|
37
|
+
<div className="flex h-11 w-11 items-center justify-center overflow-hidden rounded-2xl bg-background shadow-lg shadow-primary/20">
|
|
38
38
|
<img
|
|
39
39
|
src="/logo.png"
|
|
40
40
|
alt={l.trans({ en: "Akan.js logo", ko: "Akan.js 로고" })}
|
|
@@ -43,7 +43,7 @@ export default function Page() {
|
|
|
43
43
|
</div>
|
|
44
44
|
<div>
|
|
45
45
|
<p className="font-semibold text-primary text-sm tracking-[0.25em]">Akan.js</p>
|
|
46
|
-
<p className="text-
|
|
46
|
+
<p className="text-foreground/60 text-xs">
|
|
47
47
|
{l.trans({ en: "Full-stack TypeScript framework", ko: "풀스택 타입스크립트 프레임워크" })}
|
|
48
48
|
</p>
|
|
49
49
|
</div>
|
|
@@ -52,7 +52,7 @@ export default function Page() {
|
|
|
52
52
|
<System.ThemeToggle themes={["light", "dark"]} />
|
|
53
53
|
<System.SelectLanguage languages={["en", "ko"]} />
|
|
54
54
|
<Link href="https://akanjs.com" target="_blank">
|
|
55
|
-
<button className="
|
|
55
|
+
<button className="inline-flex items-center gap-2 rounded-field border border-foreground/10 bg-foreground/10 px-3 py-2 text-foreground text-sm transition-colors hover:border-primary hover:bg-primary hover:text-background">
|
|
56
56
|
{l.trans({ en: "Official Site", ko: "공식 사이트" })}
|
|
57
57
|
<FaExternalLinkAlt />
|
|
58
58
|
</button>
|
|
@@ -62,17 +62,17 @@ export default function Page() {
|
|
|
62
62
|
|
|
63
63
|
<div className="grid flex-1 items-center gap-10 py-16 lg:grid-cols-[1.04fr_0.96fr] lg:py-10">
|
|
64
64
|
<div>
|
|
65
|
-
<div className="
|
|
65
|
+
<div className="mb-6 inline-flex items-center gap-1 rounded-full border border-primary/20 bg-primary/10 px-4 py-3 text-primary">
|
|
66
66
|
<FaCheckCircle />
|
|
67
67
|
{l.trans({ en: "Your app is running", ko: "앱이 실행 중입니다" })}
|
|
68
68
|
</div>
|
|
69
|
-
<h1 className="max-w-4xl font-black text-5xl text-
|
|
69
|
+
<h1 className="max-w-4xl font-black text-5xl text-foreground tracking-tight sm:text-6xl lg:text-7xl">
|
|
70
70
|
{l.trans({
|
|
71
71
|
en: "Akan turns business intent into the whole product.",
|
|
72
72
|
ko: "Akan은 비즈니스 의도를 제품 전체로 바꿉니다.",
|
|
73
73
|
})}
|
|
74
74
|
</h1>
|
|
75
|
-
<p className="mt-6 max-w-2xl text-
|
|
75
|
+
<p className="mt-6 max-w-2xl text-foreground/70 text-lg leading-8">
|
|
76
76
|
{l.trans({
|
|
77
77
|
en: "Agents Write. Keep It Minimal. Always Readable. Nice To Review. Build with less code, fewer repeated decisions, and a clearer path from idea to production.",
|
|
78
78
|
ko: "Agents Write. Keep It Minimal. Always Readable. Nice To Review. 더 적은 코드, 더 적은 반복 결정, 더 선명한 출시 경로로 만드세요.",
|
|
@@ -80,29 +80,29 @@ export default function Page() {
|
|
|
80
80
|
</p>
|
|
81
81
|
|
|
82
82
|
<div className="mt-8 flex flex-wrap gap-3">
|
|
83
|
-
<span className="
|
|
83
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-foreground/10 bg-foreground/10 px-4 py-1.5 text-foreground text-sm">
|
|
84
84
|
Agent-ready
|
|
85
85
|
</span>
|
|
86
|
-
<span className="
|
|
86
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-foreground/10 bg-foreground/10 px-4 py-1.5 text-foreground text-sm">
|
|
87
87
|
Minimal code
|
|
88
88
|
</span>
|
|
89
|
-
<span className="
|
|
89
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-foreground/10 bg-foreground/10 px-4 py-1.5 text-foreground text-sm">
|
|
90
90
|
Readable by default
|
|
91
91
|
</span>
|
|
92
|
-
<span className="
|
|
92
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-foreground/10 bg-foreground/10 px-4 py-1.5 text-foreground text-sm">
|
|
93
93
|
Review-friendly
|
|
94
94
|
</span>
|
|
95
95
|
</div>
|
|
96
96
|
|
|
97
97
|
<div className="mt-10 flex flex-col gap-3 sm:flex-row">
|
|
98
98
|
<Link href="https://akanjs.com/docs/intro/quickstart" target="_blank">
|
|
99
|
-
<button className="
|
|
99
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-field bg-primary px-4 py-2 text-background text-sm transition-colors hover:bg-primary/80">
|
|
100
100
|
{l.trans({ en: "Read Quick Start", ko: "빠른 시작 읽기" })}
|
|
101
101
|
<FaBookOpen />
|
|
102
102
|
</button>
|
|
103
103
|
</Link>
|
|
104
104
|
<Link href="https://akanjs.com/docs/intro/practice" target="_blank">
|
|
105
|
-
<button className="
|
|
105
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-field border border-foreground/10 bg-foreground/10 px-4 py-2 text-foreground text-sm transition-colors hover:border-foreground/20 hover:bg-foreground/15">
|
|
106
106
|
{l.trans({ en: "Learn By Building", ko: "만들면서 배우기" })}
|
|
107
107
|
<FaCodeBranch />
|
|
108
108
|
</button>
|
|
@@ -112,13 +112,13 @@ export default function Page() {
|
|
|
112
112
|
|
|
113
113
|
<div className="relative">
|
|
114
114
|
<div className="absolute inset-0 rotate-3 rounded-4xl bg-primary/20 blur-2xl" />
|
|
115
|
-
<div className="relative overflow-hidden rounded-4xl border border-
|
|
116
|
-
<div className="mb-5 flex items-center justify-between rounded-2xl border border-
|
|
115
|
+
<div className="relative overflow-hidden rounded-4xl border border-foreground/10 bg-foreground/6 p-5 shadow-2xl backdrop-blur">
|
|
116
|
+
<div className="mb-5 flex items-center justify-between rounded-2xl border border-foreground/10 bg-background/70 px-4 py-3">
|
|
117
117
|
<div>
|
|
118
|
-
<p className="text-
|
|
118
|
+
<p className="text-foreground/40 text-xs uppercase tracking-[0.24em]">
|
|
119
119
|
{l.trans({ en: "Akan Acrostic", ko: "Akan 사행시" })}
|
|
120
120
|
</p>
|
|
121
|
-
<p className="font-semibold text-
|
|
121
|
+
<p className="font-semibold text-foreground text-lg">
|
|
122
122
|
{l.trans({ en: "A framework for focused builders", ko: "집중하는 빌더를 위한 프레임워크" })}
|
|
123
123
|
</p>
|
|
124
124
|
</div>
|
|
@@ -126,14 +126,14 @@ export default function Page() {
|
|
|
126
126
|
</div>
|
|
127
127
|
|
|
128
128
|
<div className="grid gap-3">
|
|
129
|
-
<div className="rounded-2xl border border-
|
|
129
|
+
<div className="rounded-2xl border border-foreground/10 bg-background/80 p-4">
|
|
130
130
|
<div className="flex gap-4">
|
|
131
|
-
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-
|
|
131
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-background font-black text-primary text-xl">
|
|
132
132
|
A
|
|
133
133
|
</div>
|
|
134
134
|
<div>
|
|
135
|
-
<p className="font-bold text-
|
|
136
|
-
<p className="mt-1 text-
|
|
135
|
+
<p className="font-bold text-foreground">Agents Write</p>
|
|
136
|
+
<p className="mt-1 text-foreground/60 text-sm leading-6">
|
|
137
137
|
{l.trans({
|
|
138
138
|
en: "Business definitions become the source code, so teams and agents can focus on what to build.",
|
|
139
139
|
ko: "비즈니스 정의가 소스 코드가 되므로, 팀과 에이전트는 무엇을 만들지에 집중할 수 있습니다.",
|
|
@@ -142,14 +142,14 @@ export default function Page() {
|
|
|
142
142
|
</div>
|
|
143
143
|
</div>
|
|
144
144
|
</div>
|
|
145
|
-
<div className="rounded-2xl border border-
|
|
145
|
+
<div className="rounded-2xl border border-foreground/10 bg-background/80 p-4">
|
|
146
146
|
<div className="flex gap-4">
|
|
147
|
-
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-
|
|
147
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-background font-black text-primary text-xl">
|
|
148
148
|
K
|
|
149
149
|
</div>
|
|
150
150
|
<div>
|
|
151
|
-
<p className="font-bold text-
|
|
152
|
-
<p className="mt-1 text-
|
|
151
|
+
<p className="font-bold text-foreground">Keep It Minimal</p>
|
|
152
|
+
<p className="mt-1 text-foreground/60 text-sm leading-6">
|
|
153
153
|
{l.trans({
|
|
154
154
|
en: "One definition flows into web, app, server, database, and infrastructure without repeated logic.",
|
|
155
155
|
ko: "하나의 정의가 반복 로직 없이 웹, 앱, 서버, 데이터베이스, 인프라로 이어집니다.",
|
|
@@ -158,14 +158,14 @@ export default function Page() {
|
|
|
158
158
|
</div>
|
|
159
159
|
</div>
|
|
160
160
|
</div>
|
|
161
|
-
<div className="rounded-2xl border border-
|
|
161
|
+
<div className="rounded-2xl border border-foreground/10 bg-background/80 p-4">
|
|
162
162
|
<div className="flex gap-4">
|
|
163
|
-
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-
|
|
163
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-background font-black text-primary text-xl">
|
|
164
164
|
A
|
|
165
165
|
</div>
|
|
166
166
|
<div>
|
|
167
|
-
<p className="font-bold text-
|
|
168
|
-
<p className="mt-1 text-
|
|
167
|
+
<p className="font-bold text-foreground">Always Readable</p>
|
|
168
|
+
<p className="mt-1 text-foreground/60 text-sm leading-6">
|
|
169
169
|
{l.trans({
|
|
170
170
|
en: "Strict conventions keep the app easy to understand long after the first version ships.",
|
|
171
171
|
ko: "엄격한 컨벤션은 첫 버전 출시 후에도 앱을 쉽게 이해할 수 있게 지켜줍니다.",
|
|
@@ -174,14 +174,14 @@ export default function Page() {
|
|
|
174
174
|
</div>
|
|
175
175
|
</div>
|
|
176
176
|
</div>
|
|
177
|
-
<div className="rounded-2xl border border-
|
|
177
|
+
<div className="rounded-2xl border border-foreground/10 bg-background/80 p-4">
|
|
178
178
|
<div className="flex gap-4">
|
|
179
|
-
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-
|
|
179
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-background font-black text-primary text-xl">
|
|
180
180
|
N
|
|
181
181
|
</div>
|
|
182
182
|
<div>
|
|
183
|
-
<p className="font-bold text-
|
|
184
|
-
<p className="mt-1 text-
|
|
183
|
+
<p className="font-bold text-foreground">Nice To Review</p>
|
|
184
|
+
<p className="mt-1 text-foreground/60 text-sm leading-6">
|
|
185
185
|
{l.trans({
|
|
186
186
|
en: "Focused changes make business intent clear, so reviews stay fast and releases stay calm.",
|
|
187
187
|
ko: "집중된 변경은 비즈니스 의도를 선명하게 만들어 리뷰를 빠르게 하고 배포를 안정적으로 유지합니다.",
|
|
@@ -192,17 +192,20 @@ export default function Page() {
|
|
|
192
192
|
</div>
|
|
193
193
|
</div>
|
|
194
194
|
|
|
195
|
-
<div className="
|
|
196
|
-
<pre
|
|
195
|
+
<div className="mt-5 overflow-x-auto rounded-box border border-foreground/10 bg-background py-4 font-mono text-sm">
|
|
196
|
+
<pre className="px-6">
|
|
197
|
+
<span className="select-none text-foreground/40">$ </span>
|
|
197
198
|
<code className="text-primary">bun run akan start {appName}</code>
|
|
198
199
|
</pre>
|
|
199
|
-
<pre
|
|
200
|
+
<pre className="px-6">
|
|
201
|
+
<span className="select-none text-foreground/40">✓ </span>
|
|
200
202
|
<code className="text-accent">
|
|
201
203
|
{l.trans({ en: "web, app, server, db, and infra ready", ko: "웹, 앱, 서버, DB, 인프라 준비 완료" })}
|
|
202
204
|
</code>
|
|
203
205
|
</pre>
|
|
204
|
-
<pre
|
|
205
|
-
<
|
|
206
|
+
<pre className="px-6">
|
|
207
|
+
<span className="select-none text-foreground/40">→ </span>
|
|
208
|
+
<code className="text-foreground/70">
|
|
206
209
|
{l.trans({
|
|
207
210
|
en: "edit page/_index.tsx around your business",
|
|
208
211
|
ko: "비즈니스에 맞게 page/_index.tsx를 수정하세요",
|
|
@@ -215,56 +218,56 @@ export default function Page() {
|
|
|
215
218
|
</div>
|
|
216
219
|
|
|
217
220
|
<div className="grid gap-4 pb-8 md:grid-cols-2 xl:grid-cols-4">
|
|
218
|
-
<div className="rounded-3xl border border-
|
|
221
|
+
<div className="rounded-3xl border border-foreground/10 bg-foreground/4 p-6 backdrop-blur">
|
|
219
222
|
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
220
223
|
<FaTerminal />
|
|
221
224
|
</div>
|
|
222
|
-
<h2 className="font-bold text-
|
|
225
|
+
<h2 className="font-bold text-foreground text-lg">
|
|
223
226
|
{l.trans({ en: "Agentic By Design", ko: "에이전틱 설계" })}
|
|
224
227
|
</h2>
|
|
225
|
-
<p className="mt-2 text-
|
|
228
|
+
<p className="mt-2 text-foreground/60 text-sm leading-6">
|
|
226
229
|
{l.trans({
|
|
227
230
|
en: "Describe the business once and let Akan shape the application surfaces around it.",
|
|
228
231
|
ko: "비즈니스를 한 번 설명하면 Akan이 그 주변의 애플리케이션 표면을 구성합니다.",
|
|
229
232
|
})}
|
|
230
233
|
</p>
|
|
231
234
|
</div>
|
|
232
|
-
<div className="rounded-3xl border border-
|
|
235
|
+
<div className="rounded-3xl border border-foreground/10 bg-foreground/4 p-6 backdrop-blur">
|
|
233
236
|
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
234
237
|
<FaLayerGroup />
|
|
235
238
|
</div>
|
|
236
|
-
<h2 className="font-bold text-
|
|
239
|
+
<h2 className="font-bold text-foreground text-lg">
|
|
237
240
|
{l.trans({ en: "One Definition", ko: "하나의 정의" })}
|
|
238
241
|
</h2>
|
|
239
|
-
<p className="mt-2 text-
|
|
242
|
+
<p className="mt-2 text-foreground/60 text-sm leading-6">
|
|
240
243
|
{l.trans({
|
|
241
244
|
en: "Pages, services, database models, and deployment artifacts stay connected in one workspace.",
|
|
242
245
|
ko: "페이지, 서비스, 데이터베이스 모델, 배포 산출물이 하나의 워크스페이스에서 연결됩니다.",
|
|
243
246
|
})}
|
|
244
247
|
</p>
|
|
245
248
|
</div>
|
|
246
|
-
<div className="rounded-3xl border border-
|
|
249
|
+
<div className="rounded-3xl border border-foreground/10 bg-foreground/4 p-6 backdrop-blur">
|
|
247
250
|
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
248
251
|
<FaRocket />
|
|
249
252
|
</div>
|
|
250
|
-
<h2 className="font-bold text-
|
|
253
|
+
<h2 className="font-bold text-foreground text-lg">
|
|
251
254
|
{l.trans({ en: "Less To Review", ko: "리뷰할 것이 적습니다" })}
|
|
252
255
|
</h2>
|
|
253
|
-
<p className="mt-2 text-
|
|
256
|
+
<p className="mt-2 text-foreground/60 text-sm leading-6">
|
|
254
257
|
{l.trans({
|
|
255
258
|
en: "Smaller code surfaces make intent easier to inspect, approve, and ship.",
|
|
256
259
|
ko: "더 작은 코드 표면은 의도를 확인하고 승인하고 배포하기 쉽게 만듭니다.",
|
|
257
260
|
})}
|
|
258
261
|
</p>
|
|
259
262
|
</div>
|
|
260
|
-
<div className="rounded-3xl border border-
|
|
263
|
+
<div className="rounded-3xl border border-foreground/10 bg-foreground/4 p-6 backdrop-blur">
|
|
261
264
|
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
262
265
|
<FaShieldAlt />
|
|
263
266
|
</div>
|
|
264
|
-
<h2 className="font-bold text-
|
|
267
|
+
<h2 className="font-bold text-foreground text-lg">
|
|
265
268
|
{l.trans({ en: "Type-Safe Growth", ko: "타입 안전한 성장" })}
|
|
266
269
|
</h2>
|
|
267
|
-
<p className="mt-2 text-
|
|
270
|
+
<p className="mt-2 text-foreground/60 text-sm leading-6">
|
|
268
271
|
{l.trans({
|
|
269
272
|
en: "Conventions and contracts keep the stack readable as the product expands.",
|
|
270
273
|
ko: "컨벤션과 계약은 제품이 확장되어도 스택을 읽기 쉽게 유지합니다.",
|
|
@@ -273,7 +276,7 @@ export default function Page() {
|
|
|
273
276
|
</div>
|
|
274
277
|
</div>
|
|
275
278
|
|
|
276
|
-
<div className="flex flex-col items-start justify-between gap-4 rounded-3xl border border-
|
|
279
|
+
<div className="flex flex-col items-start justify-between gap-4 rounded-3xl border border-foreground/10 bg-foreground/4 p-5 text-foreground/70 text-sm md:flex-row md:items-center">
|
|
277
280
|
<div className="flex items-center gap-3">
|
|
278
281
|
<FaTerminal className="text-primary" />
|
|
279
282
|
<span>
|
|
@@ -283,7 +286,7 @@ export default function Page() {
|
|
|
283
286
|
})}
|
|
284
287
|
</span>
|
|
285
288
|
</div>
|
|
286
|
-
<div className="flex items-center gap-2 text-
|
|
289
|
+
<div className="flex items-center gap-2 text-foreground/40">
|
|
287
290
|
<FaBoxOpen />
|
|
288
291
|
<span>{l.trans({ en: "Akan.js template", ko: "Akan.js 템플릿" })}</span>
|
|
289
292
|
</div>
|
|
@@ -1,76 +1,17 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
2
|
@import "akanjs/ui/styles.css";
|
|
3
3
|
|
|
4
|
-
@
|
|
5
|
-
|
|
6
|
-
exclude: properties;
|
|
7
|
-
themes: false;
|
|
8
|
-
}
|
|
4
|
+
/* 테마 시스템(브랜드-중립 기본 팔레트 · @theme inline 매핑 · dark 변형 · 런타임 data-theme 전환)은
|
|
5
|
+
akanjs/ui/styles.css(프레임워크)가 전부 제공한다. 이 앱은 import 만으로 즉시 동작한다.
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
name: "light";
|
|
12
|
-
--color-primary: #c33c32;
|
|
13
|
-
--color-secondary: #2b2e33;
|
|
14
|
-
--color-accent: #e67e22;
|
|
15
|
-
--color-accent-content: #ffffff;
|
|
16
|
-
--color-base-content: #2c3e50;
|
|
17
|
-
--color-base-100: #fafafa;
|
|
18
|
-
--color-base-200: #f5f5f5;
|
|
19
|
-
--color-info: #f1fdff;
|
|
20
|
-
--color-info-content: #2c3e50;
|
|
21
|
-
--color-neutral: #292c32;
|
|
22
|
-
--color-neutral-content: #fafafa;
|
|
23
|
-
--color-success: #2ecc71;
|
|
24
|
-
--color-success-content: #fafafa;
|
|
25
|
-
--color-warning: #f39c12;
|
|
26
|
-
--color-warning-content: #fafafa;
|
|
27
|
-
--color-error: #e74c3c;
|
|
28
|
-
--color-error-content: #fafafa;
|
|
29
|
-
--color-open: #27ae60;
|
|
30
|
-
--color-open-content: #fafafa;
|
|
7
|
+
이 앱만의 브랜드 색을 쓰려면 아래처럼 토큰만 override 하면 된다:
|
|
31
8
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
--depth: 0; /* 1 = subtle 3D depth on components */
|
|
42
|
-
--noise: 0; /* 1 = grain texture on surfaces */
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@plugin "daisyui/theme" {
|
|
46
|
-
name: "dark";
|
|
47
|
-
default: true;
|
|
48
|
-
--color-primary: #ff493b;
|
|
49
|
-
--color-secondary: #2b2e33;
|
|
50
|
-
--color-accent: #d1a23b;
|
|
51
|
-
--color-accent-content: #ffffff;
|
|
52
|
-
--color-base-content: #ffffff;
|
|
53
|
-
--color-base-100: #1a1a1a;
|
|
54
|
-
--color-base-200: #2a2a2a;
|
|
55
|
-
--color-info: #173b78;
|
|
56
|
-
--color-info-content: #ffffff;
|
|
57
|
-
--color-neutral: #3ed13b;
|
|
58
|
-
--color-neutral-content: #ffffff;
|
|
59
|
-
--color-success: #255fc3;
|
|
60
|
-
--color-success-content: #ffffff;
|
|
61
|
-
--color-warning: #ffcc00;
|
|
62
|
-
--color-warning-content: #ffffff;
|
|
63
|
-
--color-error: #f02020;
|
|
64
|
-
--color-error-content: #ffffff;
|
|
65
|
-
--color-open: #10fc00;
|
|
66
|
-
|
|
67
|
-
/* Keep shape & feel consistent with the light theme (usually the same values across modes). */
|
|
68
|
-
--radius-selector: 1rem;
|
|
69
|
-
--radius-field: 0.5rem;
|
|
70
|
-
--radius-box: 1rem;
|
|
71
|
-
--size-selector: 0.25rem;
|
|
72
|
-
--size-field: 0.25rem;
|
|
73
|
-
--border: 1px;
|
|
74
|
-
--depth: 0;
|
|
75
|
-
--noise: 0;
|
|
76
|
-
}
|
|
9
|
+
:root,
|
|
10
|
+
[data-theme="dark"] {
|
|
11
|
+
--primary: #xxxxxx;
|
|
12
|
+
--primary-foreground: #ffffff;
|
|
13
|
+
}
|
|
14
|
+
[data-theme="light"] {
|
|
15
|
+
--primary: #xxxxxx;
|
|
16
|
+
}
|
|
17
|
+
*/
|
|
@@ -5,7 +5,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
5
5
|
filename: "Task.Template.tsx",
|
|
6
6
|
content: `"use client";
|
|
7
7
|
import { st, usePage } from "@apps/${dict.appName}/client";
|
|
8
|
-
import {
|
|
8
|
+
import { cn } from "akanjs/client";
|
|
9
9
|
import { Field, Layout } from "akanjs/ui";
|
|
10
10
|
|
|
11
11
|
// ===== Task.Template.tsx =====
|
|
@@ -25,7 +25,7 @@ export const General = ({ className }: TaskEditProps) => {
|
|
|
25
25
|
const { l } = usePage();
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
|
-
<Layout.Template className={
|
|
28
|
+
<Layout.Template className={cn("flex flex-col gap-4", className)}>
|
|
29
29
|
<Field.Text
|
|
30
30
|
label={l("task.title")}
|
|
31
31
|
desc={l("task.title.desc")}
|
|
@@ -4,8 +4,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "Task.Unit.tsx",
|
|
6
6
|
content: `import { type cnst, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
-
import { type ModelProps,
|
|
8
|
-
import { Layout } from "akanjs/ui";
|
|
7
|
+
import { type ModelProps, cn } from "akanjs/client";
|
|
8
|
+
import { badgeRecipe, Layout } from "akanjs/ui";
|
|
9
9
|
|
|
10
10
|
// ===== Task.Unit.tsx =====
|
|
11
11
|
// Convention: lib/<module>/ — PascalCase .tsx, Unit suffix = card/list-item component.
|
|
@@ -22,25 +22,25 @@ interface CardProps extends ModelProps<"task", cnst.LightTask> {
|
|
|
22
22
|
export const Card = ({ task, className, href }: CardProps) => {
|
|
23
23
|
const { l } = usePage();
|
|
24
24
|
const statusBadge = {
|
|
25
|
-
todo: "
|
|
26
|
-
inProgress: "
|
|
27
|
-
completed: "
|
|
25
|
+
todo: badgeRecipe({ variant: "default" }),
|
|
26
|
+
inProgress: badgeRecipe({ variant: "primary" }),
|
|
27
|
+
completed: badgeRecipe({ variant: "success" }),
|
|
28
28
|
}[task.status];
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
31
|
<Layout.Unit
|
|
32
|
-
className={
|
|
33
|
-
"rounded-lg border border-
|
|
32
|
+
className={cn(
|
|
33
|
+
"rounded-lg border border-foreground/10 bg-background p-4 transition-shadow hover:shadow-md",
|
|
34
34
|
className,
|
|
35
35
|
)}
|
|
36
36
|
href={href}
|
|
37
37
|
>
|
|
38
38
|
<div className="flex items-start justify-between gap-2">
|
|
39
|
-
<span className="font-semibold text-
|
|
40
|
-
<span className={
|
|
39
|
+
<span className="font-semibold text-foreground">{task.title}</span>
|
|
40
|
+
<span className={cn(statusBadge, "shrink-0")}>{l(\`taskStatus.\${task.status}\`)}</span>
|
|
41
41
|
</div>
|
|
42
42
|
{task.due && (
|
|
43
|
-
<div className="mt-2 text-
|
|
43
|
+
<div className="mt-2 text-foreground/60 text-xs">
|
|
44
44
|
{l("task.taskDueLabel")} {task.due.toDate().toLocaleDateString()}
|
|
45
45
|
</div>
|
|
46
46
|
)}
|
|
@@ -52,7 +52,7 @@ export const Card = ({ task, className, href }: CardProps) => {
|
|
|
52
52
|
// Mini: smaller inline display (tag, chip style)
|
|
53
53
|
// export const Mini = ({ task }: MiniProps) => (
|
|
54
54
|
// <span className="inline-flex items-center gap-1 text-sm">
|
|
55
|
-
// <span className={
|
|
55
|
+
// <span className={cn("badge badge-xs", statusBadge)}>{task.status}</span>
|
|
56
56
|
// {task.title}
|
|
57
57
|
// </span>
|
|
58
58
|
// );
|
|
@@ -5,7 +5,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
5
5
|
filename: "Task.Util.tsx",
|
|
6
6
|
content: `"use client";
|
|
7
7
|
import { fetch, st, usePage } from "@apps/${dict.appName}/client";
|
|
8
|
-
import { Model } from "akanjs/ui";
|
|
8
|
+
import { buttonRecipe, Dropdown, Model } from "akanjs/ui";
|
|
9
9
|
|
|
10
10
|
// ===== Task.Util.tsx =====
|
|
11
11
|
// Convention: lib/<module>/ — PascalCase .tsx, Util suffix = action buttons/utility components.
|
|
@@ -20,7 +20,7 @@ interface StartProps {
|
|
|
20
20
|
|
|
21
21
|
export const Start = ({ taskId }: StartProps) => (
|
|
22
22
|
<button
|
|
23
|
-
className="
|
|
23
|
+
className={buttonRecipe({ size: "xs" }, "border-primary/20 bg-primary/10 text-primary hover:bg-primary hover:text-primary-foreground")}
|
|
24
24
|
onClick={() => st.do.startTask(taskId)}
|
|
25
25
|
>
|
|
26
26
|
{usePage().l("task.taskStart")}
|
|
@@ -33,7 +33,7 @@ interface CompleteProps {
|
|
|
33
33
|
|
|
34
34
|
export const Complete = ({ taskId }: CompleteProps) => (
|
|
35
35
|
<button
|
|
36
|
-
className="
|
|
36
|
+
className={buttonRecipe({ size: "xs" }, "border-success/20 bg-success/10 text-success hover:bg-success hover:text-success-foreground")}
|
|
37
37
|
onClick={() => st.do.completeTask(taskId)}
|
|
38
38
|
>
|
|
39
39
|
{usePage().l("task.taskComplete")}
|
|
@@ -46,7 +46,7 @@ interface RemoveProps {
|
|
|
46
46
|
|
|
47
47
|
export const Remove = ({ taskId }: RemoveProps) => (
|
|
48
48
|
<Model.Remove modelId={taskId} slice={fetch.slice.task}>
|
|
49
|
-
<button className="
|
|
49
|
+
<button className={buttonRecipe({ variant: "ghost", size: "xs" }, "text-destructive")}>{usePage().l("task.taskRemove")}</button>
|
|
50
50
|
</Model.Remove>
|
|
51
51
|
);
|
|
52
52
|
|
|
@@ -58,31 +58,30 @@ interface ToolboxProps {
|
|
|
58
58
|
export const Toolbox = ({ taskId, status }: ToolboxProps) => {
|
|
59
59
|
const { l } = usePage();
|
|
60
60
|
return (
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
<Dropdown
|
|
62
|
+
buttonClassName={buttonRecipe({ variant: "ghost", size: "xs" })}
|
|
63
|
+
value={<span>···</span>}
|
|
64
|
+
dropdownClassName="w-40 rounded-box border border-foreground/10 bg-background p-2"
|
|
65
|
+
content={
|
|
66
|
+
<>
|
|
67
|
+
{status === "todo" && (
|
|
68
|
+
<li>
|
|
69
|
+
<button onClick={() => st.do.startTask(taskId)}>{l("task.taskStart")}</button>
|
|
70
|
+
</li>
|
|
71
|
+
)}
|
|
72
|
+
{status === "inProgress" && (
|
|
73
|
+
<li>
|
|
74
|
+
<button onClick={() => st.do.completeTask(taskId)}>{l("task.taskComplete")}</button>
|
|
75
|
+
</li>
|
|
76
|
+
)}
|
|
70
77
|
<li>
|
|
71
|
-
<button onClick={() => st.do.
|
|
78
|
+
<button className="text-destructive" onClick={() => st.do.removeTask(taskId)}>
|
|
79
|
+
{l("task.taskRemove")}
|
|
80
|
+
</button>
|
|
72
81
|
</li>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
<button onClick={() => st.do.completeTask(taskId)}>{l("task.taskComplete")}</button>
|
|
77
|
-
</li>
|
|
78
|
-
)}
|
|
79
|
-
<li>
|
|
80
|
-
<button className="text-error" onClick={() => st.do.removeTask(taskId)}>
|
|
81
|
-
{l("task.taskRemove")}
|
|
82
|
-
</button>
|
|
83
|
-
</li>
|
|
84
|
-
</ul>
|
|
85
|
-
</div>
|
|
82
|
+
</>
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
86
85
|
);
|
|
87
86
|
};
|
|
88
87
|
|
|
@@ -97,7 +96,7 @@ export const Toolbox = ({ taskId, status }: ToolboxProps) => {
|
|
|
97
96
|
// New Task Button: Model.NewWrapper — triggers new Task creation form
|
|
98
97
|
// export const NewTask = () => (
|
|
99
98
|
// <Model.NewWrapper partial={{}}>
|
|
100
|
-
// <button className="
|
|
99
|
+
// <button className={buttonRecipe({ variant: "primary", size: "sm" })}>+ New Task</button>
|
|
101
100
|
// </Model.NewWrapper>
|
|
102
101
|
// );
|
|
103
102
|
`,
|