
akan create-application koyoakan start koyo
| 1 | Fruit Ring |
|---|---|
| 2 | Oreo |
| 3 | Strawberry |
| 4 | Mango |
| 5 | Cheese Cube |
| 6 | Corn |
| 7 | Granola |
| 8 | Banana |
| 9 | Fig |
akan create-module icecreamOrder
# then select koyo application
└── apps/ # Application code
└── koyo/ # Individual application
└── lib/ # Domain modules
└── icecreamOrder/ # Icecream order domain module
├── icecreamOrder.constant.ts # Types and schemas
├── icecreamOrder.dictionary.ts # Translations
├── icecreamOrder.document.ts # Document
├── icecreamOrder.service.ts # Business logic
├── icecreamOrder.signal.ts # API endpoints
├── icecreamOrder.store.ts # State management
├── icecreamOrder.Template.tsx # Form UI
├── icecreamOrder.Unit.tsx # Overview UI
├── icecreamOrder.Util.tsx # Utility UI
├── icecreamOrder.View.tsx # Detail view UI
└── icecreamOrder.Zone.tsx # Integration UI1
2// File: apps/koyo/lib/icecreamOrder/icecreamOrder.constant.ts
3import { enumOf, Int } from "@akanjs/base";
4import { via } from "@akanjs/constant";
5
6export class IcecreamOrderStatus extends enumOf("icecreamOrderStatus", [
7 "active",
8 "processing",
9 "served",
10 "finished",
11 "canceled",
12] as const) {}
13
14export class Topping extends enumOf("topping", [
15 "fruitRings",
16 "oreo",
17 "strawberry",
18 "mango",
19 "cheeseCube",
20 "corn",
21 "granola",
22 "banana",
23 "fig",
24] as const) {}
25
26export class IcecreamOrderObject extends via(IcecreamOrderInput, (field) => ({
27 status: field(IcecreamOrderStatus, { default: "active" }),
28})) {}
29
30export class LightIcecreamOrder extends via(
31 IcecreamOrderObject,
32 ["size", "toppings", "status"] as const,
33 (resolve) => ({})
34) {}
35
36export class IcecreamOrder extends via(IcecreamOrderObject, LightIcecreamOrder, (resolve) => ({})) {}
37
38export class IcecreamOrderInsight extends via(IcecreamOrder, (field) => ({})) {}
391
2// File: apps/koyo/lib/icecreamOrder/icecreamOrder.dictionary.ts
3import { modelDictionary } from "@akanjs/dictionary";
4
5import type { IcecreamOrder, IcecreamOrderInsight } from "./icecreamOrder.constant";
6import type { IcecreamOrderFilter } from "./icecreamOrder.document";
7import type { IcecreamOrderEndpoint, IcecreamOrderSlice } from "./icecreamOrder.signal";
8
9export const dictionary = modelDictionary(["en", "ko"])
10 .of((t) =>
11 t(["Icecream Order", "아이스크림 주문"]).desc([
12 "IcecreamOrder is an option that customers can choose when ordering icecream at koyo store.",
13 "아이스크림 주문은 koyo 가게에서 고객이 아이스크림을 주문할 때 커스텀할 수 있는 옵션들을 선택할 수 있습니다.",
14 ])
15 )
16 .model<IcecreamOrder>((t) => ({
17 size: t(["Size", "사이즈"]).desc(["Size of the icecream order", "아이스크림 주문의 사이즈"]),
18 toppings: t(["Toppings", "토핑"]).desc(["Toppings of the icecream order", "아이스크림 주문의 토핑"]),
19 status: t(["Status", "상태"]).desc(["Status of the icecream order", "아이스크림 주문의 상태"]),
20 }))
21 .enum<IcecreamOrderStatus>("icecreamOrderStatus", (t) => ({
22 active: t(["Active", "활성"]).desc(["Active status of the icecream order", "아이스크림 주문의 활성 상태"]),
23 processing: t(["Processing", "처리중"]).desc([
24 "Processing status of the icecream order",
25 "아이스크림 주문의 처리중 상태",
26 ]),
27 served: t(["Served", "서빙완료"]).desc(["Served status of the icecream order", "아이스크림 주문의 서빙완료 상태"]),
28 finished: t(["Finished", "완료"]).desc(["Finished status of the icecream order", "아이스크림 주문의 완료 상태"]),
29 canceled: t(["Canceled", "취소"]).desc(["Canceled status of the icecream order", "아이스크림 주문의 취소 상태"]),
30 }))
31 .enum<Topping>("topping", (t) => ({
32 fruitRings: t(["Fruit Rings", "과일 링"]).desc(["Fruit Rings topping", "과일 링 토핑"]),
33 oreo: t(["Oreo", "오레오"]).desc(["Oreo topping", "오레오 토핑"]),
34 strawberry: t(["Strawberry", "딸기"]).desc(["Strawberry topping", "딸기 토핑"]),
35 mango: t(["Mango", "망고"]).desc(["Mango topping", "망고 토핑"]),
36 cheeseCube: t(["Cheese Cube", "치즈 큐브"]).desc(["Cheese Cube topping", "치즈 큐브 토핑"]),
37 corn: t(["Corn", "옥수수"]).desc(["Corn topping", "옥수수 토핑"]),
38 granola: t(["Granola", "그래놀라"]).desc(["Granola topping", "그래놀라 토핑"]),
39 banana: t(["Banana", "바나나"]).desc(["Banana topping", "바나나 토핑"]),
40 fig: t(["Fig", "피그"]).desc(["Fig topping", "피그 토핑"]),
41 }))
42 .insight<IcecreamOrderInsight>((t) => ({}))
43 .query<IcecreamOrderFilter>((fn) => ({}))
44 .slice<IcecreamOrderSlice>((fn) => ({
45 inPublic: fn(["IcecreamOrder In Public", "IcecreamOrder 공개"]).arg((t) => ({})),
46 }))
47 .endpoint<IcecreamOrderEndpoint>((fn) => ({}))
48 .error({})
49 .translate({});
501
2// File: apps/koyo/lib/icecreamOrder/IcecreamOrder.Template.tsx
3"use client";
4import { cnst, st, usePage } from "@koyo/client";
5import { Layout, Field } from "@akanjs/ui";
6
7interface IcecreamOrderEditProps {
8 className?: string;
9}
10
11export const General = ({ className }: IcecreamOrderEditProps) => {
12 const icecreamOrderForm = st.use.icecreamOrderForm();
13 const { l } = usePage();
14 return (
15 <Layout.Template className={className}>
16 <Field.ToggleSelect
17 label={l("icecreamOrder.size")}
18 items={[50, 100, 200].map((size) => ({ label: `${size}cc`, value: size }))}
19 value={icecreamOrderForm.size}
20 onChange={st.do.setSizeOnIcecreamOrder}
21 />
22 <Field.MultiToggleSelect
23 label={l("icecreamOrder.toppings")}
24 items={cnst.Topping}
25 value={icecreamOrderForm.toppings}
26 onChange={st.do.setToppingsOnIcecreamOrder}
27 />
28 </Layout.Template>
29 );
30};1
2// File: apps/koyo/lib/icecreamOrder/IcecreamOrder.Unit.tsx
3import { clsx, ModelProps } from "@akanjs/client";
4import { cnst, usePage } from "@koyo/client";
5
6export const Card = ({ icecreamOrder }: ModelProps<"icecreamOrder", cnst.LightIcecreamOrder>) => {
7 const { l } = usePage();
8 return (
9 <div className="group flex h-36 w-full overflow-hidden rounded-xl bg-linear-to-br from-pink-100 via-yellow-50 to-pink-200 px-8 py-6 shadow-md transition-all duration-300 hover:shadow-xl">
10 <div className="flex w-full flex-col justify-center">
11 <div className="flex items-center gap-2 text-lg font-semibold text-pink-700">
12 <span className="inline-block rounded bg-pink-200 px-2 py-1 text-xs font-bold tracking-wider uppercase">
13 {l("icecreamOrder.id")}
14 </span>
15 <span className="ml-2 font-mono text-pink-900">{icecreamOrder.id}</span>
16 </div>
17 <div className="mt-4 flex items-center gap-2">
18 <span className="inline-block rounded bg-yellow-200 px-2 py-1 text-xs font-bold tracking-wider text-yellow-800 uppercase">
19 {l("icecreamOrder.status")}
20 </span>
21 <span
22 className={clsx("ml-2 rounded-full px-3 py-1 text-sm font-semibold", {
23 "bg-green-100 text-green-700": icecreamOrder.status === "active",
24 "bg-blue-100 text-blue-700": icecreamOrder.status === "processing",
25 "bg-red-100 text-red-700": icecreamOrder.status === "served",
26 "bg-purple-100 text-purple-700": icecreamOrder.status === "finished",
27 "bg-gray-100 text-gray-700": icecreamOrder.status === "canceled",
28 })}
29 >
30 {l(`icecreamOrderStatus.${icecreamOrder.status}`)}
31 </span>
32 </div>
33 </div>
34 </div>
35 );
36};1
2// File: apps/koyo/app/[lang]/icecreamOrder/page.tsx
3import { Load, Model } from "@akanjs/ui";
4import { cnst, fetch, IcecreamOrder, usePage } from "@koyo/client";
5
6export default function Page() {
7 const { l } = usePage();
8 return (
9 <Load.Page
10 of={Page}
11 loader={async () => {
12 const { icecreamOrderInitInPublic } = await fetch.initIcecreamOrderInPublic();
13 const icecreamOrderForm: Partial<cnst.IcecreamOrderInput> = {};
14 return { icecreamOrderInitInPublic, icecreamOrderForm };
15 }}
16 render={({ icecreamOrderInitInPublic, icecreamOrderForm }) => {
17 return (
18 <div>
19 <div className="flex items-center gap-4 pb-5 text-5xl font-black">
20 {l("icecreamOrder.modelName")}
21 <Model.New
22 className="btn btn-primary"
23 sliceName="icecreamOrderInPublic"
24 renderTitle="name"
25 partial={icecreamOrderForm}
26 >
27 <IcecreamOrder.Template.General />
28 </Model.New>
29 </div>
30 <IcecreamOrder.Zone.Card className="space-y-2" init={icecreamOrderInitInPublic} />
31 </div>
32 );
33 }}
34 />
35 );
36}