akanjs 2.0.0-rc.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base/primitiveRegistry.ts +28 -2
- package/cli/application/application.command.ts +11 -3
- package/cli/application/application.runner.ts +17 -1
- package/cli/guidelines/databaseModule/databaseModule.instruction.md +1 -1
- package/cli/guidelines/modelConstant/modelConstant.instruction.md +5 -5
- package/cli/guidelines/modelDocument/modelDocument.instruction.md +34 -61
- package/cli/guidelines/modelService/modelService.instruction.md +1 -1
- package/cli/index.js +9321 -19222
- package/cli/library/library.runner.ts +14 -13
- package/cli/package/package.runner.ts +31 -6
- package/cli/package/package.script.ts +2 -2
- package/cli/templates/app/page/_index.tsx +200 -79
- package/cli/templates/app/page/_layout.tsx +0 -1
- package/cli/templates/app/public/favicon.ico.template +0 -0
- package/cli/templates/app/public/logo.png.template +0 -0
- package/cli/templates/module/__Model__.Zone.tsx +1 -1
- package/cli/templates/module/__model__.document.ts +1 -1
- package/cli/templates/workspaceRoot/.gitignore.template +1 -11
- package/cli/templates/workspaceRoot/biome.json.template +16 -0
- package/cli/templates/workspaceRoot/package.json.template +1 -5
- package/cli/workspace/workspace.command.ts +7 -9
- package/cli/workspace/workspace.runner.ts +3 -13
- package/cli/workspace/workspace.script.ts +24 -9
- package/client/csrTypes.ts +1 -1
- package/constant/fieldInfo.ts +1 -1
- package/constant/serialize.ts +7 -1
- package/devkit/capacitor.base.config.ts +1 -1
- package/devkit/capacitorApp.ts +5 -1
- package/devkit/commandDecorators/argMeta.ts +28 -14
- package/devkit/commandDecorators/command.ts +41 -15
- package/devkit/commandDecorators/commandBuilder.ts +78 -42
- package/devkit/commandDecorators/helpFormatter.ts +7 -4
- package/devkit/dependencyScanner.ts +121 -15
- package/devkit/executors.ts +35 -23
- package/devkit/frontendBuild/cssCompiler.ts +9 -3
- package/devkit/incrementalBuilder/incrementalBuilder.proc.ts +2 -1
- package/devkit/lint/no-deep-internal-import.grit +25 -0
- package/devkit/lint/no-import-external-library.grit +1 -0
- package/devkit/mobile/mobileTarget.ts +48 -8
- package/devkit/scanInfo.ts +4 -1
- package/devkit/src/capacitorApp.ts +277 -0
- package/devkit/transforms/barrelImportsPlugin.ts +6 -0
- package/fetch/client/fetchClient.ts +1 -0
- package/fetch/client/httpClient.ts +13 -1
- package/package.json +37 -31
- package/server/akanServer.ts +21 -7
- package/server/hmr/clientScript.ts +8 -5
- package/server/resolver/resolver.contract.fixture.ts +1 -1
- package/test/index.ts +14 -0
- package/test/signalTest.preload.ts +10 -0
- package/test/signalTestRuntime.ts +126 -0
- package/test/testServer.ts +130 -25
- package/ui/Constant/Doc.tsx +696 -0
- package/ui/Constant/Mermaid.tsx +149 -0
- package/ui/Constant/index.ts +6 -0
- package/ui/Constant/schemaDoc.ts +324 -0
- package/ui/Field.tsx +0 -1
- package/ui/Portal.tsx +2 -0
- package/ui/System/CSR.tsx +6 -5
- package/ui/System/SSR.tsx +1 -1
- package/ui/System/SelectLanguage.tsx +1 -1
- package/ui/index.ts +1 -0
- package/ui/styles.css +0 -1
- package/webkit/bootCsr.tsx +8 -5
- package/base/test-globals.d.ts +0 -4
- package/cli/templates/app/common/commonLogic.ts +0 -12
- package/cli/templates/app/common/index.ts +0 -10
- package/cli/templates/app/public/favicon.ico +0 -0
- package/cli/templates/app/public/icons/icon-128x128.png +0 -0
- package/cli/templates/app/public/icons/icon-144x144.png +0 -0
- package/cli/templates/app/public/icons/icon-152x152.png +0 -0
- package/cli/templates/app/public/icons/icon-192x192.png +0 -0
- package/cli/templates/app/public/icons/icon-256x256.png +0 -0
- package/cli/templates/app/public/icons/icon-384x384.png +0 -0
- package/cli/templates/app/public/icons/icon-48x48.png +0 -0
- package/cli/templates/app/public/icons/icon-512x512.png +0 -0
- package/cli/templates/app/public/icons/icon-72x72.png +0 -0
- package/cli/templates/app/public/icons/icon-96x96.png +0 -0
- package/cli/templates/app/public/logo.svg +0 -70
- package/cli/templates/app/public/manifest.json.template +0 -67
- package/cli/templates/app/srvkit/backendLogic.ts +0 -12
- package/cli/templates/app/srvkit/index.ts +0 -10
- package/cli/templates/app/ui/UiComponent.ts +0 -16
- package/cli/templates/app/ui/index.ts +0 -10
- package/cli/templates/app/webkit/frontendLogic.ts +0 -12
- package/cli/templates/app/webkit/index.ts +0 -10
- package/cli/templates/module/index.tsx +0 -44
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { parseEnv } from "node:util";
|
|
2
1
|
import { type Lib, LibExecutor, runner, type Workspace } from "akanjs/devkit";
|
|
3
2
|
import { compareVersions } from "compare-versions";
|
|
4
3
|
|
|
@@ -15,11 +14,23 @@ export class LibraryRunner extends runner("library") {
|
|
|
15
14
|
await lib.workspace.unsetTsPaths("lib", lib.name);
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
async
|
|
17
|
+
async #copyInstalledLibrary(workspace: Workspace, libName: string) {
|
|
18
|
+
const installedPackageJson = `node_modules/akanjs/libs/${libName}/package.json`;
|
|
19
|
+
if (!(await workspace.exists(installedPackageJson))) return false;
|
|
20
|
+
await workspace.cp(`node_modules/akanjs/libs/${libName}`, `libs/${libName}`);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async #copyLibraryFromRepository(workspace: Workspace, libName: string) {
|
|
19
25
|
await workspace.mkdir("node_modules/.akan");
|
|
20
26
|
if (await workspace.exists("node_modules/.akan/akanjs")) await workspace.removeDir("node_modules/.akan/akanjs");
|
|
21
|
-
await workspace.exec(`cd node_modules/.akan && git clone
|
|
27
|
+
await workspace.exec(`cd node_modules/.akan && git clone https://github.com/akan-team/akanjs.git`);
|
|
22
28
|
await workspace.cp(`node_modules/.akan/akanjs/libs/${libName}`, `libs/${libName}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async installLibrary(workspace: Workspace, libName: string) {
|
|
32
|
+
const copiedFromInstalledPackage = await this.#copyInstalledLibrary(workspace, libName);
|
|
33
|
+
if (!copiedFromInstalledPackage) await this.#copyLibraryFromRepository(workspace, libName);
|
|
23
34
|
await workspace.cp(`libs/${libName}/env/env.server.example.ts`, `libs/${libName}/env/env.server.testing.ts`);
|
|
24
35
|
await workspace.setTsPaths("lib", libName);
|
|
25
36
|
await workspace.commit(`Add ${libName} library`);
|
|
@@ -53,16 +64,6 @@ export class LibraryRunner extends runner("library") {
|
|
|
53
64
|
await lib.workspace.commit(`Merge ${lib.name} library dependencies`);
|
|
54
65
|
}
|
|
55
66
|
|
|
56
|
-
async #getEnv(lib: Lib, env: Record<string, string> = {}) {
|
|
57
|
-
const rootEnv = parseEnv(await lib.workspace.readFile(".env"));
|
|
58
|
-
return {
|
|
59
|
-
...process.env,
|
|
60
|
-
...rootEnv,
|
|
61
|
-
AKAN_PUBLIC_APP_NAME: lib.name,
|
|
62
|
-
AKAN_WORKSPACE_ROOT: lib.workspace.workspaceRoot,
|
|
63
|
-
...env,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
67
|
async testLibrary(lib: Lib) {
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { Logger } from "akanjs/common";
|
|
2
3
|
import {
|
|
3
4
|
FileSys,
|
|
@@ -10,10 +11,15 @@ import {
|
|
|
10
11
|
import { $ } from "bun";
|
|
11
12
|
|
|
12
13
|
export class PackageRunner extends runner("package") {
|
|
13
|
-
async version(workspace: Workspace) {
|
|
14
|
-
const pkgJson = await FileSys.readJson<PackageJson>(
|
|
14
|
+
async version(workspace: Workspace, { log = true }: { log?: boolean } = {}) {
|
|
15
|
+
const pkgJson = await FileSys.readJson<PackageJson>(
|
|
16
|
+
process.env.USE_AKANJS_PKGS === "true"
|
|
17
|
+
? `${workspace.workspaceRoot}/pkgs/akanjs/package.json`
|
|
18
|
+
: `${path.dirname(Bun.main)}/../package.json`,
|
|
19
|
+
);
|
|
15
20
|
const version = pkgJson.version;
|
|
16
|
-
Logger.rawLog(`${pkgJson.name}@${version}`);
|
|
21
|
+
if (log) Logger.rawLog(`${pkgJson.name}@${version}`);
|
|
22
|
+
return version;
|
|
17
23
|
}
|
|
18
24
|
async createPackage(workspace: Workspace, pkgName: string) {
|
|
19
25
|
await workspace.applyTemplate({ basePath: `pkgs/${pkgName}`, template: "pkgRoot", dict: { pkgName } });
|
|
@@ -30,14 +36,33 @@ export class PackageRunner extends runner("package") {
|
|
|
30
36
|
async buildPackage(pkg: Pkg) {
|
|
31
37
|
await $`rm -rf ${pkg.dist.cwdPath}`;
|
|
32
38
|
await pkg.dist.mkdir(pkg.dist.cwdPath);
|
|
39
|
+
const scanner = await TypeScriptDependencyScanner.from(pkg);
|
|
40
|
+
const { npmDeps, npmDevDeps, missingDeps } = await scanner.getPackageBuildDependencies(pkg.name);
|
|
41
|
+
const packageRuntimeDependencies: Record<string, string[]> = { akanjs: ["daisyui"] };
|
|
42
|
+
const packageRuntimeDevDependencies: Record<string, string[]> = { akanjs: ["@biomejs/biome"] };
|
|
43
|
+
const forcedRuntimeDeps = packageRuntimeDependencies[pkg.name] ?? [];
|
|
44
|
+
const forcedRuntimeDevDeps = packageRuntimeDevDependencies[pkg.name] ?? [];
|
|
45
|
+
const packageRuntimeDeps = [...new Set([...npmDeps, ...forcedRuntimeDeps])];
|
|
46
|
+
const packageRuntimeDevDeps = [...new Set([...npmDevDeps, ...forcedRuntimeDevDeps])];
|
|
47
|
+
const rootPackageJson = await pkg.workspace.getPackageJson();
|
|
48
|
+
const rootDeps = { ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies };
|
|
49
|
+
const missingForcedDeps = forcedRuntimeDeps.filter((dep) => !rootDeps[dep]);
|
|
50
|
+
const missingForcedDevDeps = forcedRuntimeDevDeps.filter((dep) => !rootDeps[dep]);
|
|
51
|
+
const allMissingDeps = [...new Set([...missingDeps, ...missingForcedDeps, ...missingForcedDevDeps])].sort();
|
|
52
|
+
if (allMissingDeps.length > 0)
|
|
53
|
+
throw new Error(`Missing dependency versions in root package.json: ${allMissingDeps.join(", ")}`);
|
|
54
|
+
|
|
55
|
+
await pkg.updatePackageJsonDependencies(packageRuntimeDeps, packageRuntimeDevDeps);
|
|
56
|
+
|
|
33
57
|
const hasBuildFile = await Bun.file(`${pkg.cwdPath}/build.ts`).exists();
|
|
34
58
|
if (hasBuildFile) {
|
|
35
59
|
await pkg.workspace.spawn(process.execPath, [`${pkg.cwdPath}/build.ts`], { env: process.env, stdio: "inherit" });
|
|
36
60
|
} else {
|
|
37
61
|
await $`cp -r ${pkg.cwdPath}/. ${pkg.dist.cwdPath}`;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
await Promise.all([
|
|
63
|
+
pkg.generateDistPackageJson(packageRuntimeDeps, packageRuntimeDevDeps),
|
|
64
|
+
pkg.generateTsconfigJson(),
|
|
65
|
+
]);
|
|
41
66
|
}
|
|
42
67
|
}
|
|
43
68
|
|
|
@@ -3,8 +3,8 @@ import { type Pkg, script, type Workspace } from "akanjs/devkit";
|
|
|
3
3
|
import { PackageRunner } from "./package.runner";
|
|
4
4
|
|
|
5
5
|
export class PackageScript extends script("package", [PackageRunner]) {
|
|
6
|
-
async version(workspace: Workspace) {
|
|
7
|
-
await this.packageRunner.version(workspace);
|
|
6
|
+
async version(workspace: Workspace, { log = true }: { log?: boolean } = {}) {
|
|
7
|
+
return await this.packageRunner.version(workspace, { log });
|
|
8
8
|
}
|
|
9
9
|
async createPackage(workspace: Workspace, pkgName: string) {
|
|
10
10
|
const spinner = workspace.spinning(`Creating package in pkgs/${pkgName}...`);
|
|
@@ -7,9 +7,10 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
|
|
|
7
7
|
return {
|
|
8
8
|
filename: "_index.tsx",
|
|
9
9
|
content: `
|
|
10
|
-
import {
|
|
10
|
+
import { getEnv } from "akanjs/base";
|
|
11
|
+
import { usePage } from "akanjs/client";
|
|
12
|
+
import { Link, System } from "akanjs/ui";
|
|
11
13
|
import {
|
|
12
|
-
FaBolt,
|
|
13
14
|
FaBookOpen,
|
|
14
15
|
FaBoxOpen,
|
|
15
16
|
FaCheckCircle,
|
|
@@ -21,85 +22,88 @@ import {
|
|
|
21
22
|
FaTerminal,
|
|
22
23
|
} from "react-icons/fa";
|
|
23
24
|
|
|
24
|
-
export const head = <title>Akan.js</title>;
|
|
25
|
-
|
|
26
25
|
export default function Page() {
|
|
27
|
-
const appName =
|
|
28
|
-
|
|
29
|
-
const highlights = [
|
|
30
|
-
{
|
|
31
|
-
icon: <FaLayerGroup />,
|
|
32
|
-
title: "One Codebase",
|
|
33
|
-
description: "Design pages, services, server contracts, and deployment surfaces in one Akan workspace.",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
icon: <FaShieldAlt />,
|
|
37
|
-
title: "Type-Safe Flow",
|
|
38
|
-
description: "Keep application contracts close to the business logic they protect.",
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
icon: <FaRocket />,
|
|
42
|
-
title: "Ready To Ship",
|
|
43
|
-
description: "Start locally, build production artifacts, and grow without changing the app shape.",
|
|
44
|
-
},
|
|
45
|
-
];
|
|
46
|
-
|
|
26
|
+
const appName = getEnv().appName;
|
|
27
|
+
const { l } = usePage();
|
|
47
28
|
return (
|
|
48
29
|
<main className="relative min-h-screen overflow-hidden bg-base-100 text-base-content">
|
|
49
|
-
<div className="absolute -
|
|
50
|
-
<div className="absolute -
|
|
30
|
+
<div className="absolute -top-48 -left-48 h-96 w-96 rounded-full bg-primary/25 blur-3xl" />
|
|
31
|
+
<div className="absolute -right-40 -bottom-56 h-112 w-md rounded-full bg-accent/20 blur-3xl" />
|
|
51
32
|
<div className="absolute inset-x-0 top-0 h-px bg-linear-to-r from-transparent via-primary/60 to-transparent" />
|
|
52
33
|
|
|
53
34
|
<section className="relative mx-auto flex min-h-screen w-full max-w-7xl flex-col px-6 py-8 lg:px-8">
|
|
54
35
|
<nav className="flex items-center justify-between">
|
|
55
36
|
<div className="flex items-center gap-3">
|
|
56
|
-
<div className="flex h-11 w-11 items-center justify-center rounded-2xl bg-
|
|
57
|
-
<
|
|
37
|
+
<div className="flex h-11 w-11 items-center justify-center overflow-hidden rounded-2xl bg-base-100 shadow-lg shadow-primary/20">
|
|
38
|
+
<img
|
|
39
|
+
src="/logo.png"
|
|
40
|
+
alt={l.trans({ en: "Akan.js logo", ko: "Akan.js 로고" })}
|
|
41
|
+
className="h-full w-full object-cover"
|
|
42
|
+
/>
|
|
58
43
|
</div>
|
|
59
44
|
<div>
|
|
60
|
-
<p className="text-
|
|
61
|
-
<p className="text-
|
|
45
|
+
<p className="font-semibold text-primary text-sm tracking-[0.25em]">Akan.js</p>
|
|
46
|
+
<p className="text-base-content/60 text-xs">
|
|
47
|
+
{l.trans({ en: "Full-stack TypeScript framework", ko: "풀스택 타입스크립트 프레임워크" })}
|
|
48
|
+
</p>
|
|
62
49
|
</div>
|
|
63
50
|
</div>
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
51
|
+
<div className="flex items-center gap-2">
|
|
52
|
+
<System.ThemeToggle themes={["light", "dark"]} />
|
|
53
|
+
<System.SelectLanguage languages={["en", "ko"]} />
|
|
54
|
+
<Link href="https://akanjs.com" target="_blank">
|
|
55
|
+
<button className="btn btn-sm border-base-content/10 bg-base-content/10 text-base-content hover:border-primary hover:bg-primary hover:text-base-100">
|
|
56
|
+
{l.trans({ en: "Official Site", ko: "공식 사이트" })}
|
|
57
|
+
<FaExternalLinkAlt />
|
|
58
|
+
</button>
|
|
59
|
+
</Link>
|
|
60
|
+
</div>
|
|
70
61
|
</nav>
|
|
71
62
|
|
|
72
63
|
<div className="grid flex-1 items-center gap-10 py-16 lg:grid-cols-[1.04fr_0.96fr] lg:py-10">
|
|
73
64
|
<div>
|
|
74
65
|
<div className="badge mb-6 border-primary/20 bg-primary/10 px-4 py-3 text-primary">
|
|
75
66
|
<FaCheckCircle />
|
|
76
|
-
Your app is running
|
|
67
|
+
{l.trans({ en: "Your app is running", ko: "앱이 실행 중입니다" })}
|
|
77
68
|
</div>
|
|
78
|
-
<h1 className="max-w-4xl
|
|
79
|
-
|
|
69
|
+
<h1 className="max-w-4xl font-black text-5xl text-base-content tracking-tight sm:text-6xl lg:text-7xl">
|
|
70
|
+
{l.trans({
|
|
71
|
+
en: "Akan turns business intent into the whole product.",
|
|
72
|
+
ko: "Akan은 비즈니스 의도를 제품 전체로 바꿉니다.",
|
|
73
|
+
})}
|
|
80
74
|
</h1>
|
|
81
|
-
<p className="mt-6 max-w-2xl text-lg leading-8
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
<p className="mt-6 max-w-2xl text-base-content/70 text-lg leading-8">
|
|
76
|
+
{l.trans({
|
|
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
|
+
ko: "Agents Write. Keep It Minimal. Always Readable. Nice To Review. 더 적은 코드, 더 적은 반복 결정, 더 선명한 출시 경로로 만드세요.",
|
|
79
|
+
})}
|
|
84
80
|
</p>
|
|
85
81
|
|
|
86
82
|
<div className="mt-8 flex flex-wrap gap-3">
|
|
87
|
-
<span className="badge badge-lg border-base-content/10 bg-base-content/10 text-base-content">
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<span className="badge badge-lg border-base-content/10 bg-base-content/10 text-base-content">
|
|
83
|
+
<span className="badge badge-lg border-base-content/10 bg-base-content/10 text-base-content">
|
|
84
|
+
Agent-ready
|
|
85
|
+
</span>
|
|
86
|
+
<span className="badge badge-lg border-base-content/10 bg-base-content/10 text-base-content">
|
|
87
|
+
Minimal code
|
|
88
|
+
</span>
|
|
89
|
+
<span className="badge badge-lg border-base-content/10 bg-base-content/10 text-base-content">
|
|
90
|
+
Readable by default
|
|
91
|
+
</span>
|
|
92
|
+
<span className="badge badge-lg border-base-content/10 bg-base-content/10 text-base-content">
|
|
93
|
+
Review-friendly
|
|
94
|
+
</span>
|
|
91
95
|
</div>
|
|
92
96
|
|
|
93
97
|
<div className="mt-10 flex flex-col gap-3 sm:flex-row">
|
|
94
98
|
<Link href="https://akanjs.com/docs/intro/quickstart" target="_blank">
|
|
95
99
|
<button className="btn border-none bg-primary text-base-100 hover:bg-primary/80">
|
|
96
|
-
Read Quick Start
|
|
100
|
+
{l.trans({ en: "Read Quick Start", ko: "빠른 시작 읽기" })}
|
|
97
101
|
<FaBookOpen />
|
|
98
102
|
</button>
|
|
99
103
|
</Link>
|
|
100
104
|
<Link href="https://akanjs.com/docs/intro/practice" target="_blank">
|
|
101
105
|
<button className="btn border-base-content/10 bg-base-content/10 text-base-content hover:border-base-content/20 hover:bg-base-content/15">
|
|
102
|
-
Learn By Building
|
|
106
|
+
{l.trans({ en: "Learn By Building", ko: "만들면서 배우기" })}
|
|
103
107
|
<FaCodeBranch />
|
|
104
108
|
</button>
|
|
105
109
|
</Link>
|
|
@@ -111,60 +115,177 @@ export default function Page() {
|
|
|
111
115
|
<div className="relative overflow-hidden rounded-4xl border border-base-content/10 bg-base-content/6 p-5 shadow-2xl backdrop-blur">
|
|
112
116
|
<div className="mb-5 flex items-center justify-between rounded-2xl border border-base-content/10 bg-base-100/70 px-4 py-3">
|
|
113
117
|
<div>
|
|
114
|
-
<p className="text-xs uppercase tracking-[0.24em]
|
|
115
|
-
|
|
118
|
+
<p className="text-base-content/40 text-xs uppercase tracking-[0.24em]">
|
|
119
|
+
{l.trans({ en: "Akan Acrostic", ko: "Akan 사행시" })}
|
|
120
|
+
</p>
|
|
121
|
+
<p className="font-semibold text-base-content text-lg">
|
|
122
|
+
{l.trans({ en: "A framework for focused builders", ko: "집중하는 빌더를 위한 프레임워크" })}
|
|
123
|
+
</p>
|
|
116
124
|
</div>
|
|
117
|
-
<div className="rounded-xl bg-primary/10 px-3 py-2
|
|
125
|
+
<div className="rounded-xl bg-primary/10 px-3 py-2 font-medium text-primary text-sm">{appName}</div>
|
|
118
126
|
</div>
|
|
119
127
|
|
|
120
|
-
<div className="
|
|
128
|
+
<div className="grid gap-3">
|
|
129
|
+
<div className="rounded-2xl border border-base-content/10 bg-base-100/80 p-4">
|
|
130
|
+
<div className="flex gap-4">
|
|
131
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-base-100 font-black text-primary text-xl">
|
|
132
|
+
A
|
|
133
|
+
</div>
|
|
134
|
+
<div>
|
|
135
|
+
<p className="font-bold text-base-content">Agents Write</p>
|
|
136
|
+
<p className="mt-1 text-base-content/60 text-sm leading-6">
|
|
137
|
+
{l.trans({
|
|
138
|
+
en: "Business definitions become the source code, so teams and agents can focus on what to build.",
|
|
139
|
+
ko: "비즈니스 정의가 소스 코드가 되므로, 팀과 에이전트는 무엇을 만들지에 집중할 수 있습니다.",
|
|
140
|
+
})}
|
|
141
|
+
</p>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
<div className="rounded-2xl border border-base-content/10 bg-base-100/80 p-4">
|
|
146
|
+
<div className="flex gap-4">
|
|
147
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-base-100 font-black text-primary text-xl">
|
|
148
|
+
K
|
|
149
|
+
</div>
|
|
150
|
+
<div>
|
|
151
|
+
<p className="font-bold text-base-content">Keep It Minimal</p>
|
|
152
|
+
<p className="mt-1 text-base-content/60 text-sm leading-6">
|
|
153
|
+
{l.trans({
|
|
154
|
+
en: "One definition flows into web, app, server, database, and infrastructure without repeated logic.",
|
|
155
|
+
ko: "하나의 정의가 반복 로직 없이 웹, 앱, 서버, 데이터베이스, 인프라로 이어집니다.",
|
|
156
|
+
})}
|
|
157
|
+
</p>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
<div className="rounded-2xl border border-base-content/10 bg-base-100/80 p-4">
|
|
162
|
+
<div className="flex gap-4">
|
|
163
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-base-100 font-black text-primary text-xl">
|
|
164
|
+
A
|
|
165
|
+
</div>
|
|
166
|
+
<div>
|
|
167
|
+
<p className="font-bold text-base-content">Always Readable</p>
|
|
168
|
+
<p className="mt-1 text-base-content/60 text-sm leading-6">
|
|
169
|
+
{l.trans({
|
|
170
|
+
en: "Strict conventions keep the app easy to understand long after the first version ships.",
|
|
171
|
+
ko: "엄격한 컨벤션은 첫 버전 출시 후에도 앱을 쉽게 이해할 수 있게 지켜줍니다.",
|
|
172
|
+
})}
|
|
173
|
+
</p>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
<div className="rounded-2xl border border-base-content/10 bg-base-100/80 p-4">
|
|
178
|
+
<div className="flex gap-4">
|
|
179
|
+
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-base-100 font-black text-primary text-xl">
|
|
180
|
+
N
|
|
181
|
+
</div>
|
|
182
|
+
<div>
|
|
183
|
+
<p className="font-bold text-base-content">Nice To Review</p>
|
|
184
|
+
<p className="mt-1 text-base-content/60 text-sm leading-6">
|
|
185
|
+
{l.trans({
|
|
186
|
+
en: "Focused changes make business intent clear, so reviews stay fast and releases stay calm.",
|
|
187
|
+
ko: "집중된 변경은 비즈니스 의도를 선명하게 만들어 리뷰를 빠르게 하고 배포를 안정적으로 유지합니다.",
|
|
188
|
+
})}
|
|
189
|
+
</p>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div className="mockup-code mt-5 border border-base-content/10 bg-base-100 text-sm shadow-none">
|
|
121
196
|
<pre data-prefix="$">
|
|
122
197
|
<code className="text-primary">bun run akan start {appName}</code>
|
|
123
198
|
</pre>
|
|
124
199
|
<pre data-prefix="✓">
|
|
125
|
-
<code className="text-accent">
|
|
200
|
+
<code className="text-accent">
|
|
201
|
+
{l.trans({ en: "web, app, server, db, and infra ready", ko: "웹, 앱, 서버, DB, 인프라 준비 완료" })}
|
|
202
|
+
</code>
|
|
126
203
|
</pre>
|
|
127
204
|
<pre data-prefix="→">
|
|
128
|
-
<code className="text-base-content/70">
|
|
205
|
+
<code className="text-base-content/70">
|
|
206
|
+
{l.trans({
|
|
207
|
+
en: "edit page/_index.tsx around your business",
|
|
208
|
+
ko: "비즈니스에 맞게 page/_index.tsx를 수정하세요",
|
|
209
|
+
})}
|
|
210
|
+
</code>
|
|
129
211
|
</pre>
|
|
130
212
|
</div>
|
|
131
|
-
|
|
132
|
-
<div className="mt-5 grid gap-3 sm:grid-cols-3">
|
|
133
|
-
{[
|
|
134
|
-
["Pages", "UI routes"],
|
|
135
|
-
["Services", "Typed APIs"],
|
|
136
|
-
["Deploy", "Artifacts"],
|
|
137
|
-
].map(([title, description]) => (
|
|
138
|
-
<div key={title} className="rounded-2xl border border-base-content/10 bg-base-content/4 p-4">
|
|
139
|
-
<p className="text-sm font-semibold text-base-content">{title}</p>
|
|
140
|
-
<p className="mt-1 text-xs text-base-content/60">{description}</p>
|
|
141
|
-
</div>
|
|
142
|
-
))}
|
|
143
|
-
</div>
|
|
144
213
|
</div>
|
|
145
214
|
</div>
|
|
146
215
|
</div>
|
|
147
216
|
|
|
148
|
-
<div className="grid gap-4 pb-8 md:grid-cols-
|
|
149
|
-
|
|
150
|
-
<div
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
217
|
+
<div className="grid gap-4 pb-8 md:grid-cols-2 xl:grid-cols-4">
|
|
218
|
+
<div className="rounded-3xl border border-base-content/10 bg-base-content/4 p-6 backdrop-blur">
|
|
219
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
220
|
+
<FaTerminal />
|
|
221
|
+
</div>
|
|
222
|
+
<h2 className="font-bold text-base-content text-lg">
|
|
223
|
+
{l.trans({ en: "Agentic By Design", ko: "에이전틱 설계" })}
|
|
224
|
+
</h2>
|
|
225
|
+
<p className="mt-2 text-base-content/60 text-sm leading-6">
|
|
226
|
+
{l.trans({
|
|
227
|
+
en: "Describe the business once and let Akan shape the application surfaces around it.",
|
|
228
|
+
ko: "비즈니스를 한 번 설명하면 Akan이 그 주변의 애플리케이션 표면을 구성합니다.",
|
|
229
|
+
})}
|
|
230
|
+
</p>
|
|
231
|
+
</div>
|
|
232
|
+
<div className="rounded-3xl border border-base-content/10 bg-base-content/4 p-6 backdrop-blur">
|
|
233
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
234
|
+
<FaLayerGroup />
|
|
235
|
+
</div>
|
|
236
|
+
<h2 className="font-bold text-base-content text-lg">
|
|
237
|
+
{l.trans({ en: "One Definition", ko: "하나의 정의" })}
|
|
238
|
+
</h2>
|
|
239
|
+
<p className="mt-2 text-base-content/60 text-sm leading-6">
|
|
240
|
+
{l.trans({
|
|
241
|
+
en: "Pages, services, database models, and deployment artifacts stay connected in one workspace.",
|
|
242
|
+
ko: "페이지, 서비스, 데이터베이스 모델, 배포 산출물이 하나의 워크스페이스에서 연결됩니다.",
|
|
243
|
+
})}
|
|
244
|
+
</p>
|
|
245
|
+
</div>
|
|
246
|
+
<div className="rounded-3xl border border-base-content/10 bg-base-content/4 p-6 backdrop-blur">
|
|
247
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
248
|
+
<FaRocket />
|
|
156
249
|
</div>
|
|
157
|
-
|
|
250
|
+
<h2 className="font-bold text-base-content text-lg">
|
|
251
|
+
{l.trans({ en: "Less To Review", ko: "리뷰할 것이 적습니다" })}
|
|
252
|
+
</h2>
|
|
253
|
+
<p className="mt-2 text-base-content/60 text-sm leading-6">
|
|
254
|
+
{l.trans({
|
|
255
|
+
en: "Smaller code surfaces make intent easier to inspect, approve, and ship.",
|
|
256
|
+
ko: "더 작은 코드 표면은 의도를 확인하고 승인하고 배포하기 쉽게 만듭니다.",
|
|
257
|
+
})}
|
|
258
|
+
</p>
|
|
259
|
+
</div>
|
|
260
|
+
<div className="rounded-3xl border border-base-content/10 bg-base-content/4 p-6 backdrop-blur">
|
|
261
|
+
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary text-xl">
|
|
262
|
+
<FaShieldAlt />
|
|
263
|
+
</div>
|
|
264
|
+
<h2 className="font-bold text-base-content text-lg">
|
|
265
|
+
{l.trans({ en: "Type-Safe Growth", ko: "타입 안전한 성장" })}
|
|
266
|
+
</h2>
|
|
267
|
+
<p className="mt-2 text-base-content/60 text-sm leading-6">
|
|
268
|
+
{l.trans({
|
|
269
|
+
en: "Conventions and contracts keep the stack readable as the product expands.",
|
|
270
|
+
ko: "컨벤션과 계약은 제품이 확장되어도 스택을 읽기 쉽게 유지합니다.",
|
|
271
|
+
})}
|
|
272
|
+
</p>
|
|
273
|
+
</div>
|
|
158
274
|
</div>
|
|
159
275
|
|
|
160
|
-
<div className="flex flex-col items-start justify-between gap-4 rounded-3xl border border-base-content/10 bg-base-content/4 p-5 text-
|
|
276
|
+
<div className="flex flex-col items-start justify-between gap-4 rounded-3xl border border-base-content/10 bg-base-content/4 p-5 text-base-content/70 text-sm md:flex-row md:items-center">
|
|
161
277
|
<div className="flex items-center gap-3">
|
|
162
278
|
<FaTerminal className="text-primary" />
|
|
163
|
-
<span>
|
|
279
|
+
<span>
|
|
280
|
+
{l.trans({
|
|
281
|
+
en: "Next: define the business once, then let Akan carry it across every surface.",
|
|
282
|
+
ko: "다음 단계: 비즈니스를 한 번 정의하고, Akan이 모든 표면으로 이어가게 하세요.",
|
|
283
|
+
})}
|
|
284
|
+
</span>
|
|
164
285
|
</div>
|
|
165
286
|
<div className="flex items-center gap-2 text-base-content/40">
|
|
166
287
|
<FaBoxOpen />
|
|
167
|
-
<span>Akan.js template</span>
|
|
288
|
+
<span>{l.trans({ en: "Akan.js template", ko: "Akan.js 템플릿" })}</span>
|
|
168
289
|
</div>
|
|
169
290
|
</div>
|
|
170
291
|
</section>
|
|
@@ -10,7 +10,6 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
|
|
|
10
10
|
content: `
|
|
11
11
|
import "./styles.css";
|
|
12
12
|
import type { LayoutProps } from "akanjs/client";
|
|
13
|
-
import { fetch } from "@${dict.appName}/client";
|
|
14
13
|
${isUsingShared ? "import { Auth } from '@shared/ui';" : ""}
|
|
15
14
|
|
|
16
15
|
export const head = (
|
|
Binary file
|
|
Binary file
|
|
@@ -12,7 +12,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dic
|
|
|
12
12
|
"use client";
|
|
13
13
|
import { Load } from "akanjs/ui";
|
|
14
14
|
import { cnst, ${dict.Model} } from "@${dict.sysName}/client";
|
|
15
|
-
import type { ClientInit, ClientView } from "akanjs/fetch";
|
|
15
|
+
import type { ClientInit, ClientView, SliceMeta } from "akanjs/fetch";
|
|
16
16
|
|
|
17
17
|
interface CardProps {
|
|
18
18
|
className?: string;
|
|
@@ -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 {
|
|
10
|
+
import { by, from, into, type SchemaOf } from "akanjs/document";
|
|
11
11
|
|
|
12
12
|
import * as cnst from "../cnst";
|
|
13
13
|
|
|
@@ -25,10 +25,6 @@ apps/*/scripts
|
|
|
25
25
|
**/*secrets.yaml
|
|
26
26
|
**/kubeconfig.yaml
|
|
27
27
|
**/secrets.*
|
|
28
|
-
**/.idea
|
|
29
|
-
apps/**/src/schema.gql
|
|
30
|
-
.next
|
|
31
|
-
.vite
|
|
32
28
|
dump
|
|
33
29
|
local
|
|
34
30
|
|
|
@@ -50,7 +46,6 @@ DerivedData
|
|
|
50
46
|
*.ipa
|
|
51
47
|
*.xcuserstate
|
|
52
48
|
|
|
53
|
-
# **/android
|
|
54
49
|
build/
|
|
55
50
|
.gradle
|
|
56
51
|
local.properties
|
|
@@ -122,9 +117,4 @@ libs/*/common/index.ts
|
|
|
122
117
|
libs/*/client.ts
|
|
123
118
|
libs/*/server.ts
|
|
124
119
|
libs/*/index.ts
|
|
125
|
-
|
|
126
|
-
# **/postcss.config.js
|
|
127
|
-
# **/playwright.config.ts
|
|
128
|
-
# **/next-env.d.ts
|
|
129
|
-
# **/tsconfig.json
|
|
130
|
-
# **/tsconfig.spec.json
|
|
120
|
+
**/.akan
|
|
@@ -142,6 +142,22 @@
|
|
|
142
142
|
"includes": ["**/*.constant.ts", "**/*.document.ts", "**/*.service.ts", "**/*.store.ts"],
|
|
143
143
|
"plugins": ["./node_modules/akanjs/devkit/lint/no-js-private-class-method.grit"]
|
|
144
144
|
},
|
|
145
|
+
{
|
|
146
|
+
"includes": [
|
|
147
|
+
"**/*.constant.ts",
|
|
148
|
+
"**/*.dictionary.ts",
|
|
149
|
+
"**/*.document.ts",
|
|
150
|
+
"**/*.service.ts",
|
|
151
|
+
"**/*.signal.ts",
|
|
152
|
+
"**/*.store.ts",
|
|
153
|
+
"**/*.Template.tsx",
|
|
154
|
+
"**/*.Unit.tsx",
|
|
155
|
+
"**/*.Util.tsx",
|
|
156
|
+
"**/*.View.tsx",
|
|
157
|
+
"**/*.Zone.tsx"
|
|
158
|
+
],
|
|
159
|
+
"plugins": ["./node_modules/akanjs/devkit/lint/no-deep-internal-import.grit"]
|
|
160
|
+
},
|
|
145
161
|
{
|
|
146
162
|
"includes": [
|
|
147
163
|
"**/page/**/*.ts",
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
"name": "<%= repoName %>",
|
|
3
3
|
"description": "<%= repoName %> workspace",
|
|
4
4
|
"version": "0.0.1",
|
|
5
|
-
"dependencies": {
|
|
6
|
-
"daisyui": "^5.5.20",
|
|
7
|
-
"tailwind-scrollbar": "^4.0.2",
|
|
8
|
-
"tailwindcss-radix": "^4.0.2"
|
|
9
|
-
},
|
|
5
|
+
"dependencies": {},
|
|
10
6
|
"devDependencies": {}
|
|
11
7
|
}
|
|
@@ -5,7 +5,9 @@ import { WorkspaceScript } from "./workspace.script";
|
|
|
5
5
|
export class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({ public: target }) => ({
|
|
6
6
|
createWorkspace: target({ desc: "Create a new Akan.js workspace", runsOnWorkspaceRoot: false })
|
|
7
7
|
.arg("workspaceName", String, { desc: "what is the name of your organization?" })
|
|
8
|
-
.option("app", String, {
|
|
8
|
+
.option("app", String, {
|
|
9
|
+
desc: "what is the codename of your first application? (e.g. myapp)",
|
|
10
|
+
})
|
|
9
11
|
.option("dir", String, {
|
|
10
12
|
desc: "directory of workspace",
|
|
11
13
|
default: process.env.USE_AKANJS_PKGS === "true" ? "local" : ".",
|
|
@@ -20,20 +22,16 @@ export class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({
|
|
|
20
22
|
},
|
|
21
23
|
],
|
|
22
24
|
})
|
|
23
|
-
.option("tag", String, {
|
|
24
|
-
desc: "tag of the update",
|
|
25
|
-
default: "latest",
|
|
26
|
-
enum: ["latest", "dev", "canary", "beta", "rc", "alpha"],
|
|
27
|
-
})
|
|
28
25
|
.option("init", Boolean, {
|
|
29
26
|
desc: "Do you want to initialize the workspace? (Recommended)",
|
|
30
27
|
default: true,
|
|
31
28
|
})
|
|
32
|
-
.exec(async function (workspaceName, app, dir, libs,
|
|
29
|
+
.exec(async function (workspaceName, app, dir, libs, init) {
|
|
30
|
+
const appName = app || "app";
|
|
33
31
|
await this.workspaceScript.createWorkspace(
|
|
34
32
|
workspaceName.toLowerCase().replace(/ /g, "-"),
|
|
35
|
-
|
|
36
|
-
{ dirname: dir, installLibs: libs,
|
|
33
|
+
appName.toLowerCase().replace(/ /g, "-"),
|
|
34
|
+
{ dirname: dir, installLibs: libs, init },
|
|
37
35
|
);
|
|
38
36
|
}),
|
|
39
37
|
lint: target({ desc: "Lint and fix code in a specific app/lib/pkg" })
|