@akanjs/cli 0.0.142 → 0.0.144
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/README.md +8 -0
- package/cjs/index.js +2437 -3204
- package/cjs/src/guidelines/___library/sharedUiStructureDescription.en.md +786 -0
- package/cjs/src/guidelines/___library/utilUiStructureDescription.en.md +395 -0
- package/cjs/src/guidelines/___lint/lintRuleDescription.en.md +64 -0
- package/cjs/src/guidelines/___module/moduleStructureDescription.en.md +80 -0
- package/cjs/src/guidelines/componentRule/componentRule.instruction.md +732 -0
- package/cjs/src/guidelines/databaseModule/databaseModule.instruction.md +691 -0
- package/cjs/src/guidelines/enumConstant/enumConstant.instruction.md +232 -0
- package/cjs/src/guidelines/fieldDecorator/fieldDecorator.instruction.md +611 -0
- package/cjs/src/guidelines/framework/framework.instruction.md +1112 -0
- package/cjs/src/guidelines/modelConstant/modelConstant.instruction.md +958 -0
- package/cjs/src/guidelines/modelDictionary/modelDictionary.instruction.md +583 -0
- package/cjs/src/guidelines/modelDocument/modelDocument.instruction.md +683 -0
- package/cjs/src/guidelines/modelService/modelService.instruction.md +935 -0
- package/cjs/src/guidelines/modelSignal/modelSignal.instruction.md +588 -0
- package/cjs/src/guidelines/modelStore/modelStore.instruction.md +591 -0
- package/cjs/src/guidelines/modelTemplate/modelTemplate.instruction.md +577 -0
- package/cjs/src/guidelines/modelUnit/modelUnit.instruction.md +833 -0
- package/cjs/src/guidelines/modelUtil/modelUtil.instruction.md +752 -0
- package/cjs/src/guidelines/modelView/modelView.instruction.md +1005 -0
- package/cjs/src/guidelines/modelZone/modelZone.instruction.md +528 -0
- package/cjs/src/guidelines/scalarConstant/scalarConstant.instruction.md +489 -0
- package/cjs/src/guidelines/scalarDictionary/scalarDictionary.instruction.md +347 -0
- package/cjs/src/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +318 -0
- package/cjs/src/guidelines/utilUiUsage/utilUiUsage.instruction.md +339 -0
- package/cjs/src/templates/module/__model__.dictionary.js +4 -5
- package/esm/index.js +2524 -3286
- package/esm/src/guidelines/___library/sharedUiStructureDescription.en.md +786 -0
- package/esm/src/guidelines/___library/utilUiStructureDescription.en.md +395 -0
- package/esm/src/guidelines/___lint/lintRuleDescription.en.md +64 -0
- package/esm/src/guidelines/___module/moduleStructureDescription.en.md +80 -0
- package/esm/src/guidelines/componentRule/componentRule.instruction.md +732 -0
- package/esm/src/guidelines/databaseModule/databaseModule.instruction.md +691 -0
- package/esm/src/guidelines/enumConstant/enumConstant.instruction.md +232 -0
- package/esm/src/guidelines/fieldDecorator/fieldDecorator.instruction.md +611 -0
- package/esm/src/guidelines/framework/framework.instruction.md +1112 -0
- package/esm/src/guidelines/modelConstant/modelConstant.instruction.md +958 -0
- package/esm/src/guidelines/modelDictionary/modelDictionary.instruction.md +583 -0
- package/esm/src/guidelines/modelDocument/modelDocument.instruction.md +683 -0
- package/esm/src/guidelines/modelService/modelService.instruction.md +935 -0
- package/esm/src/guidelines/modelSignal/modelSignal.instruction.md +588 -0
- package/esm/src/guidelines/modelStore/modelStore.instruction.md +591 -0
- package/esm/src/guidelines/modelTemplate/modelTemplate.instruction.md +577 -0
- package/esm/src/guidelines/modelUnit/modelUnit.instruction.md +833 -0
- package/esm/src/guidelines/modelUtil/modelUtil.instruction.md +752 -0
- package/esm/src/guidelines/modelView/modelView.instruction.md +1005 -0
- package/esm/src/guidelines/modelZone/modelZone.instruction.md +528 -0
- package/esm/src/guidelines/scalarConstant/scalarConstant.instruction.md +489 -0
- package/esm/src/guidelines/scalarDictionary/scalarDictionary.instruction.md +347 -0
- package/esm/src/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +318 -0
- package/esm/src/guidelines/utilUiUsage/utilUiUsage.instruction.md +339 -0
- package/esm/src/templates/module/__model__.dictionary.js +4 -5
- package/package.json +3 -1
- package/src/guideline/guideline.command.d.ts +7 -0
- package/src/guideline/guideline.prompt.d.ts +15 -0
- package/src/guideline/guideline.runner.d.ts +5 -0
- package/src/guideline/guideline.script.d.ts +6 -0
- package/src/guidelines/___library/sharedUiStructureDescription.en.md +786 -0
- package/src/guidelines/___library/utilUiStructureDescription.en.md +395 -0
- package/src/guidelines/___lint/lintRuleDescription.en.md +64 -0
- package/src/guidelines/___module/moduleStructureDescription.en.md +80 -0
- package/src/guidelines/componentRule/componentRule.instruction.md +732 -0
- package/src/guidelines/databaseModule/databaseModule.instruction.md +691 -0
- package/src/guidelines/enumConstant/enumConstant.instruction.md +232 -0
- package/src/guidelines/fieldDecorator/fieldDecorator.instruction.md +611 -0
- package/src/guidelines/framework/framework.instruction.md +1112 -0
- package/src/guidelines/modelConstant/modelConstant.instruction.md +958 -0
- package/src/guidelines/modelDictionary/modelDictionary.instruction.md +583 -0
- package/src/guidelines/modelDocument/modelDocument.instruction.md +683 -0
- package/src/guidelines/modelService/modelService.instruction.md +935 -0
- package/src/guidelines/modelSignal/modelSignal.instruction.md +588 -0
- package/src/guidelines/modelStore/modelStore.instruction.md +591 -0
- package/src/guidelines/modelTemplate/modelTemplate.instruction.md +577 -0
- package/src/guidelines/modelUnit/modelUnit.instruction.md +833 -0
- package/src/guidelines/modelUtil/modelUtil.instruction.md +752 -0
- package/src/guidelines/modelView/modelView.instruction.md +1005 -0
- package/src/guidelines/modelZone/modelZone.instruction.md +528 -0
- package/src/guidelines/scalarConstant/scalarConstant.instruction.md +489 -0
- package/src/guidelines/scalarDictionary/scalarDictionary.instruction.md +347 -0
- package/src/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +318 -0
- package/src/guidelines/utilUiUsage/utilUiUsage.instruction.md +339 -0
- package/src/module/module.command.d.ts +6 -8
- package/src/module/module.prompt.d.ts +2 -15
- package/src/module/module.request.d.ts +22 -18
- package/src/module/module.runner.d.ts +4 -20
- package/src/module/module.script.d.ts +6 -7
- package/src/scalar/scalar.command.d.ts +7 -0
- package/src/scalar/scalar.prompt.d.ts +23 -0
- package/src/scalar/scalar.runner.d.ts +13 -0
- package/src/scalar/scalar.script.d.ts +6 -0
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/forgotpassword/page.js +0 -47
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/page.js +0 -128
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/privacy/page.js +0 -42
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/signin/page.js +0 -50
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/termsofservice/page.js +0 -41
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(public)/unknown/page.js +0 -51
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(user)/layout.js +0 -43
- package/cjs/src/templates/app/app/[lang]/(__appName__)/(user)/self/page.js +0 -60
- package/cjs/src/templates/app/app/[lang]/(__appName__)/layout.js +0 -54
- package/cjs/src/templates/app/app/[lang]/(__appName__)/styles.css.template +0 -19
- package/cjs/src/templates/app/app/[lang]/admin/layout.js +0 -54
- package/cjs/src/templates/app/app/[lang]/admin/page.js +0 -63
- package/cjs/src/templates/app/app/csr.js +0 -34
- package/cjs/src/templates/app/app/index.html.template +0 -13
- package/cjs/src/templates/app/app/layout.js +0 -38
- package/cjs/src/templates/app/capacitor.config.ts.template +0 -8
- package/cjs/src/templates/app/env/env.client.debug.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.develop.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.local.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.main.ts.template +0 -7
- package/cjs/src/templates/app/env/env.client.testing.ts.template +0 -7
- package/cjs/src/templates/app/env/env.server.debug.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.develop.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.local.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.main.ts.template +0 -15
- package/cjs/src/templates/app/env/env.server.testing.ts.template +0 -7
- package/cjs/src/templates/app/lib/setting/Setting.Template.js +0 -57
- package/cjs/src/templates/app/lib/setting/Setting.Unit.js +0 -38
- package/cjs/src/templates/app/lib/setting/Setting.Util.js +0 -34
- package/cjs/src/templates/app/lib/setting/Setting.View.js +0 -51
- package/cjs/src/templates/app/lib/setting/Setting.Zone.js +0 -80
- package/cjs/src/templates/app/lib/setting/index.js +0 -61
- package/cjs/src/templates/app/lib/summary/Summary.Template.js +0 -43
- package/cjs/src/templates/app/lib/summary/Summary.Unit.js +0 -38
- package/cjs/src/templates/app/lib/summary/Summary.Util.js +0 -33
- package/cjs/src/templates/app/lib/summary/Summary.View.js +0 -51
- package/cjs/src/templates/app/lib/summary/Summary.Zone.js +0 -62
- package/cjs/src/templates/app/lib/summary/index.js +0 -67
- package/cjs/src/templates/app/lib/user/User.Template.js +0 -65
- package/cjs/src/templates/app/lib/user/User.Unit.js +0 -38
- package/cjs/src/templates/app/lib/user/User.Util.js +0 -94
- package/cjs/src/templates/app/lib/user/User.View.js +0 -66
- package/cjs/src/templates/app/lib/user/User.Zone.js +0 -74
- package/cjs/src/templates/app/lib/user/index.js +0 -61
- package/cjs/src/templates/app/page.test.ts.template +0 -10
- package/cjs/src/templates/app/playwright.config.ts.template +0 -6
- package/cjs/src/templates/app/postcss.config.js.template +0 -10
- package/cjs/src/templates/app/public/manifest.json.template +0 -67
- package/cjs/src/templates/app/tsconfig.json.template +0 -22
- package/cjs/src/templates/app/tsconfig.spec.json.template +0 -7
- package/cjs/src/templates/app/ui/Footer.js +0 -67
- package/cjs/src/templates/app/ui/MainHeader.js +0 -131
- package/cjs/src/templates/crudPages/[__model__Id]/edit/page.js +0 -73
- package/cjs/src/templates/crudPages/[__model__Id]/page.js +0 -83
- package/cjs/src/templates/crudPages/new/page.js +0 -70
- package/cjs/src/templates/crudPages/page.js +0 -71
- package/cjs/src/templates/libRoot/.gitignore.template +0 -15
- package/cjs/src/templates/libRoot/env/env.server.example.ts.template +0 -7
- package/cjs/src/templates/libRoot/env/env.server.testing.ts.template +0 -7
- package/cjs/src/templates/libRoot/lib/setting/Setting.Template.js +0 -57
- package/cjs/src/templates/libRoot/lib/setting/Setting.Unit.js +0 -38
- package/cjs/src/templates/libRoot/lib/setting/Setting.Util.js +0 -34
- package/cjs/src/templates/libRoot/lib/setting/Setting.View.js +0 -51
- package/cjs/src/templates/libRoot/lib/setting/Setting.Zone.js +0 -80
- package/cjs/src/templates/libRoot/lib/setting/index.js +0 -61
- package/cjs/src/templates/libRoot/lib/summary/Summary.Template.js +0 -43
- package/cjs/src/templates/libRoot/lib/summary/Summary.Unit.js +0 -38
- package/cjs/src/templates/libRoot/lib/summary/Summary.Util.js +0 -33
- package/cjs/src/templates/libRoot/lib/summary/Summary.View.js +0 -51
- package/cjs/src/templates/libRoot/lib/summary/Summary.Zone.js +0 -62
- package/cjs/src/templates/libRoot/lib/summary/index.js +0 -67
- package/cjs/src/templates/libRoot/lib/user/User.Template.js +0 -65
- package/cjs/src/templates/libRoot/lib/user/User.Unit.js +0 -38
- package/cjs/src/templates/libRoot/lib/user/User.Util.js +0 -94
- package/cjs/src/templates/libRoot/lib/user/User.View.js +0 -66
- package/cjs/src/templates/libRoot/lib/user/User.Zone.js +0 -74
- package/cjs/src/templates/libRoot/lib/user/index.js +0 -61
- package/cjs/src/templates/libRoot/package.json.template +0 -4
- package/cjs/src/templates/libRoot/tsconfig.json.template +0 -13
- package/cjs/src/templates/libRoot/tsconfig.spec.json.template +0 -7
- package/cjs/src/templates/localDev/docker-compose.yaml.template +0 -36
- package/cjs/src/templates/module/__Model__.Template.js +0 -54
- package/cjs/src/templates/module/__Model__.Unit.js +0 -42
- package/cjs/src/templates/module/__Model__.Util.js +0 -70
- package/cjs/src/templates/module/__Model__.View.js +0 -48
- package/cjs/src/templates/module/__Model__.Zone.js +0 -83
- package/cjs/src/templates/module/index.js +0 -61
- package/cjs/src/templates/pkgRoot/tsconfig.json.template +0 -15
- package/cjs/src/templates/workspaceRoot/.env.template +0 -20
- package/cjs/src/templates/workspaceRoot/.gitignore.template +0 -118
- package/cjs/src/templates/workspaceRoot/.prettierignore.template +0 -10
- package/cjs/src/templates/workspaceRoot/.prettierrc.json.template +0 -6
- package/cjs/src/templates/workspaceRoot/.swcrc.template +0 -9
- package/cjs/src/templates/workspaceRoot/.vscode/settings.json.template +0 -13
- package/cjs/src/templates/workspaceRoot/README.md.template +0 -37
- package/cjs/src/templates/workspaceRoot/eslint.config.ts.template +0 -3
- package/cjs/src/templates/workspaceRoot/package.json.template +0 -43
- package/cjs/src/templates/workspaceRoot/tsconfig.json.template +0 -29
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/forgotpassword/page.js +0 -27
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/page.js +0 -108
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/privacy/page.js +0 -22
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/signin/page.js +0 -30
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/termsofservice/page.js +0 -21
- package/esm/src/templates/app/app/[lang]/(__appName__)/(public)/unknown/page.js +0 -31
- package/esm/src/templates/app/app/[lang]/(__appName__)/(user)/layout.js +0 -23
- package/esm/src/templates/app/app/[lang]/(__appName__)/(user)/self/page.js +0 -40
- package/esm/src/templates/app/app/[lang]/(__appName__)/layout.js +0 -34
- package/esm/src/templates/app/app/[lang]/(__appName__)/styles.css.template +0 -19
- package/esm/src/templates/app/app/[lang]/admin/layout.js +0 -34
- package/esm/src/templates/app/app/[lang]/admin/page.js +0 -43
- package/esm/src/templates/app/app/csr.js +0 -14
- package/esm/src/templates/app/app/index.html.template +0 -13
- package/esm/src/templates/app/app/layout.js +0 -18
- package/esm/src/templates/app/capacitor.config.ts.template +0 -8
- package/esm/src/templates/app/env/env.client.debug.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.develop.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.local.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.main.ts.template +0 -7
- package/esm/src/templates/app/env/env.client.testing.ts.template +0 -7
- package/esm/src/templates/app/env/env.server.debug.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.develop.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.local.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.main.ts.template +0 -15
- package/esm/src/templates/app/env/env.server.testing.ts.template +0 -7
- package/esm/src/templates/app/lib/setting/Setting.Template.js +0 -37
- package/esm/src/templates/app/lib/setting/Setting.Unit.js +0 -18
- package/esm/src/templates/app/lib/setting/Setting.Util.js +0 -14
- package/esm/src/templates/app/lib/setting/Setting.View.js +0 -31
- package/esm/src/templates/app/lib/setting/Setting.Zone.js +0 -60
- package/esm/src/templates/app/lib/setting/index.js +0 -41
- package/esm/src/templates/app/lib/summary/Summary.Template.js +0 -23
- package/esm/src/templates/app/lib/summary/Summary.Unit.js +0 -18
- package/esm/src/templates/app/lib/summary/Summary.Util.js +0 -13
- package/esm/src/templates/app/lib/summary/Summary.View.js +0 -31
- package/esm/src/templates/app/lib/summary/Summary.Zone.js +0 -42
- package/esm/src/templates/app/lib/summary/index.js +0 -47
- package/esm/src/templates/app/lib/user/User.Template.js +0 -45
- package/esm/src/templates/app/lib/user/User.Unit.js +0 -18
- package/esm/src/templates/app/lib/user/User.Util.js +0 -74
- package/esm/src/templates/app/lib/user/User.View.js +0 -46
- package/esm/src/templates/app/lib/user/User.Zone.js +0 -54
- package/esm/src/templates/app/lib/user/index.js +0 -41
- package/esm/src/templates/app/page.test.ts.template +0 -10
- package/esm/src/templates/app/playwright.config.ts.template +0 -6
- package/esm/src/templates/app/postcss.config.js.template +0 -10
- package/esm/src/templates/app/public/manifest.json.template +0 -67
- package/esm/src/templates/app/tsconfig.json.template +0 -22
- package/esm/src/templates/app/tsconfig.spec.json.template +0 -7
- package/esm/src/templates/app/ui/Footer.js +0 -47
- package/esm/src/templates/app/ui/MainHeader.js +0 -111
- package/esm/src/templates/crudPages/[__model__Id]/edit/page.js +0 -53
- package/esm/src/templates/crudPages/[__model__Id]/page.js +0 -63
- package/esm/src/templates/crudPages/new/page.js +0 -50
- package/esm/src/templates/crudPages/page.js +0 -51
- package/esm/src/templates/libRoot/.gitignore.template +0 -15
- package/esm/src/templates/libRoot/env/env.server.example.ts.template +0 -7
- package/esm/src/templates/libRoot/env/env.server.testing.ts.template +0 -7
- package/esm/src/templates/libRoot/lib/setting/Setting.Template.js +0 -37
- package/esm/src/templates/libRoot/lib/setting/Setting.Unit.js +0 -18
- package/esm/src/templates/libRoot/lib/setting/Setting.Util.js +0 -14
- package/esm/src/templates/libRoot/lib/setting/Setting.View.js +0 -31
- package/esm/src/templates/libRoot/lib/setting/Setting.Zone.js +0 -60
- package/esm/src/templates/libRoot/lib/setting/index.js +0 -41
- package/esm/src/templates/libRoot/lib/summary/Summary.Template.js +0 -23
- package/esm/src/templates/libRoot/lib/summary/Summary.Unit.js +0 -18
- package/esm/src/templates/libRoot/lib/summary/Summary.Util.js +0 -13
- package/esm/src/templates/libRoot/lib/summary/Summary.View.js +0 -31
- package/esm/src/templates/libRoot/lib/summary/Summary.Zone.js +0 -42
- package/esm/src/templates/libRoot/lib/summary/index.js +0 -47
- package/esm/src/templates/libRoot/lib/user/User.Template.js +0 -45
- package/esm/src/templates/libRoot/lib/user/User.Unit.js +0 -18
- package/esm/src/templates/libRoot/lib/user/User.Util.js +0 -74
- package/esm/src/templates/libRoot/lib/user/User.View.js +0 -46
- package/esm/src/templates/libRoot/lib/user/User.Zone.js +0 -54
- package/esm/src/templates/libRoot/lib/user/index.js +0 -41
- package/esm/src/templates/libRoot/package.json.template +0 -4
- package/esm/src/templates/libRoot/tsconfig.json.template +0 -13
- package/esm/src/templates/libRoot/tsconfig.spec.json.template +0 -7
- package/esm/src/templates/localDev/docker-compose.yaml.template +0 -36
- package/esm/src/templates/module/__Model__.Template.js +0 -34
- package/esm/src/templates/module/__Model__.Unit.js +0 -22
- package/esm/src/templates/module/__Model__.Util.js +0 -50
- package/esm/src/templates/module/__Model__.View.js +0 -28
- package/esm/src/templates/module/__Model__.Zone.js +0 -63
- package/esm/src/templates/module/index.js +0 -41
- package/esm/src/templates/pkgRoot/tsconfig.json.template +0 -15
- package/esm/src/templates/workspaceRoot/.env.template +0 -20
- package/esm/src/templates/workspaceRoot/.gitignore.template +0 -118
- package/esm/src/templates/workspaceRoot/.prettierignore.template +0 -10
- package/esm/src/templates/workspaceRoot/.prettierrc.json.template +0 -6
- package/esm/src/templates/workspaceRoot/.swcrc.template +0 -9
- package/esm/src/templates/workspaceRoot/.vscode/settings.json.template +0 -13
- package/esm/src/templates/workspaceRoot/README.md.template +0 -37
- package/esm/src/templates/workspaceRoot/eslint.config.ts.template +0 -3
- package/esm/src/templates/workspaceRoot/package.json.template +0 -43
- package/esm/src/templates/workspaceRoot/tsconfig.json.template +0 -29
- package/src/application/application.prompt.d.ts +0 -2
- package/src/templates/app/app/[lang]/(__appName__)/(public)/forgotpassword/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/privacy/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/signin/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(public)/termsofservice/page.d.ts +0 -10
- package/src/templates/app/app/[lang]/(__appName__)/(public)/unknown/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(user)/layout.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/(user)/self/page.d.ts +0 -9
- package/src/templates/app/app/[lang]/(__appName__)/layout.d.ts +0 -9
- package/src/templates/app/app/[lang]/admin/layout.d.ts +0 -9
- package/src/templates/app/app/[lang]/admin/page.d.ts +0 -9
- package/src/templates/app/app/csr.d.ts +0 -9
- package/src/templates/app/app/layout.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Template.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Unit.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Util.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.View.d.ts +0 -9
- package/src/templates/app/lib/setting/Setting.Zone.d.ts +0 -9
- package/src/templates/app/lib/setting/index.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Template.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Unit.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Util.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.View.d.ts +0 -9
- package/src/templates/app/lib/summary/Summary.Zone.d.ts +0 -9
- package/src/templates/app/lib/summary/index.d.ts +0 -9
- package/src/templates/app/lib/user/User.Template.d.ts +0 -9
- package/src/templates/app/lib/user/User.Unit.d.ts +0 -9
- package/src/templates/app/lib/user/User.Util.d.ts +0 -9
- package/src/templates/app/lib/user/User.View.d.ts +0 -9
- package/src/templates/app/lib/user/User.Zone.d.ts +0 -9
- package/src/templates/app/lib/user/index.d.ts +0 -9
- package/src/templates/app/ui/Footer.d.ts +0 -9
- package/src/templates/app/ui/MainHeader.d.ts +0 -10
- package/src/templates/crudPages/[__model__Id]/edit/page.d.ts +0 -11
- package/src/templates/crudPages/[__model__Id]/page.d.ts +0 -11
- package/src/templates/crudPages/new/page.d.ts +0 -11
- package/src/templates/crudPages/page.d.ts +0 -11
- package/src/templates/libRoot/lib/setting/Setting.Template.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.Unit.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.Util.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.View.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/Setting.Zone.d.ts +0 -9
- package/src/templates/libRoot/lib/setting/index.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Template.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Unit.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Util.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.View.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/Summary.Zone.d.ts +0 -9
- package/src/templates/libRoot/lib/summary/index.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Template.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Unit.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Util.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.View.d.ts +0 -9
- package/src/templates/libRoot/lib/user/User.Zone.d.ts +0 -9
- package/src/templates/libRoot/lib/user/index.d.ts +0 -9
- package/src/templates/module/__Model__.Template.d.ts +0 -11
- package/src/templates/module/__Model__.Unit.d.ts +0 -11
- package/src/templates/module/__Model__.Util.d.ts +0 -11
- package/src/templates/module/__Model__.View.d.ts +0 -11
- package/src/templates/module/__Model__.Zone.d.ts +0 -11
- package/src/templates/module/index.d.ts +0 -11
|
@@ -0,0 +1,833 @@
|
|
|
1
|
+
# Model.Unit.tsx Files in Akan.js - Implementation Guide
|
|
2
|
+
|
|
3
|
+
## Purpose and Role of Model.Unit.tsx Files
|
|
4
|
+
|
|
5
|
+
Model.Unit.tsx files are foundational server components in the Akan.js framework that provide reusable presentation elements for domain models. They serve several critical purposes:
|
|
6
|
+
|
|
7
|
+
1. **Consistent Model Representation**: Create standardized visual representations of domain entities
|
|
8
|
+
2. **UI Building Blocks**: Serve as atomic components for building complex interfaces
|
|
9
|
+
3. **Presentation Layer**: Encapsulate rendering logic for `cnst.LightModel` data objects
|
|
10
|
+
4. **Cross-Component Reuse**: Enable consistent usage across pages, zones, templates, and utilities
|
|
11
|
+
5. **Server-Side Rendering**: Optimize for Next.js server components architecture
|
|
12
|
+
|
|
13
|
+
Key characteristics:
|
|
14
|
+
|
|
15
|
+
- **Server Components**: Do not use client-side hooks (useState, useEffect, etc.)
|
|
16
|
+
- **Model-Focused**: Primarily render `cnst.LightModel` data structures
|
|
17
|
+
- **Presentation-Only**: Contain no business logic, state management, or data fetching
|
|
18
|
+
- **Prop-Configurable**: Accept standardized props for customization
|
|
19
|
+
- **Composable**: Designed to work seamlessly with other Akan.js components
|
|
20
|
+
|
|
21
|
+
## How to Create Model.Unit.tsx Files
|
|
22
|
+
|
|
23
|
+
### 1. File Location and Naming
|
|
24
|
+
|
|
25
|
+
Model Unit files follow strict naming conventions:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
libs/
|
|
29
|
+
your-lib/
|
|
30
|
+
lib/
|
|
31
|
+
feature-name/
|
|
32
|
+
FeatureName.Unit.tsx # PascalCase for file name
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Basic Structure and Exports
|
|
36
|
+
|
|
37
|
+
A typical Model.Unit.tsx file exports multiple component variations:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { clsx } from "clsx";
|
|
41
|
+
import { cnst } from "@your-lib/client";
|
|
42
|
+
import { Image, Link } from "@util/ui";
|
|
43
|
+
|
|
44
|
+
// Compact representation (minimal details)
|
|
45
|
+
export const Abstract = ({
|
|
46
|
+
product,
|
|
47
|
+
className,
|
|
48
|
+
href,
|
|
49
|
+
}: {
|
|
50
|
+
product: cnst.LightProduct;
|
|
51
|
+
className?: string;
|
|
52
|
+
href?: string;
|
|
53
|
+
}) => {
|
|
54
|
+
const Content = (
|
|
55
|
+
<div className={clsx("flex items-center gap-3 rounded border p-2", className)}>
|
|
56
|
+
{product.thumbnail && <Image file={product.thumbnail} className="h-12 w-12 rounded" alt={product.name} />}
|
|
57
|
+
<div>
|
|
58
|
+
<h3 className="font-medium">{product.name}</h3>
|
|
59
|
+
<p className="text-sm text-gray-500">{product.price.toLocaleString()} KRW</p>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return href ? <Link href={href}>{Content}</Link> : Content;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Medium detail representation (card style)
|
|
68
|
+
export const Card = ({ product, className }: { product: cnst.LightProduct; className?: string }) => (
|
|
69
|
+
<div className={clsx("card bg-base-100 shadow-sm", className)}>
|
|
70
|
+
{product.image && (
|
|
71
|
+
<figure>
|
|
72
|
+
<Image file={product.image} className="h-48 w-full object-cover" alt={product.name} />
|
|
73
|
+
</figure>
|
|
74
|
+
)}
|
|
75
|
+
<div className="card-body p-4">
|
|
76
|
+
<h2 className="card-title text-lg">{product.name}</h2>
|
|
77
|
+
<p className="line-clamp-2 text-sm">{product.description}</p>
|
|
78
|
+
<div className="mt-2 flex items-center justify-between">
|
|
79
|
+
<span className="font-bold">{product.price.toLocaleString()} KRW</span>
|
|
80
|
+
<span className={clsx("badge", product.inStock ? "badge-success" : "badge-error")}>
|
|
81
|
+
{product.inStock ? "In Stock" : "Out of Stock"}
|
|
82
|
+
</span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Full detailed representation
|
|
89
|
+
export const Full = ({ product, className }: { product: cnst.LightProduct; className?: string }) => (
|
|
90
|
+
<div className={clsx("overflow-hidden rounded-lg border", className)}>
|
|
91
|
+
{product.image && <Image file={product.image} className="h-64 w-full object-cover" alt={product.name} />}
|
|
92
|
+
<div className="p-4">
|
|
93
|
+
<div className="mb-2 flex justify-between">
|
|
94
|
+
<h2 className="text-xl font-bold">{product.name}</h2>
|
|
95
|
+
<span className="text-lg font-bold">{product.price.toLocaleString()} KRW</span>
|
|
96
|
+
</div>
|
|
97
|
+
<p className="my-3">{product.description}</p>
|
|
98
|
+
<div className="grid grid-cols-2 gap-2 text-sm">
|
|
99
|
+
<div>
|
|
100
|
+
Category: <span className="font-medium">{product.category}</span>
|
|
101
|
+
</div>
|
|
102
|
+
<div>
|
|
103
|
+
SKU: <span className="font-medium">{product.sku}</span>
|
|
104
|
+
</div>
|
|
105
|
+
<div>
|
|
106
|
+
Manufacturer: <span className="font-medium">{product.manufacturer}</span>
|
|
107
|
+
</div>
|
|
108
|
+
<div>
|
|
109
|
+
Stock: <span className="font-medium">{product.stockQuantity}</span>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
{product.tags?.length > 0 && (
|
|
113
|
+
<div className="mt-3 flex flex-wrap gap-1">
|
|
114
|
+
{product.tags.map((tag) => (
|
|
115
|
+
<span key={tag} className="badge badge-outline">
|
|
116
|
+
{tag}
|
|
117
|
+
</span>
|
|
118
|
+
))}
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Additional specialized variations as needed
|
|
126
|
+
export const Row = ({ product, className }: { product: cnst.LightProduct; className?: string }) => (
|
|
127
|
+
<div className={clsx("flex items-center justify-between border-b p-3", className)}>
|
|
128
|
+
<div className="flex items-center gap-3">
|
|
129
|
+
{product.thumbnail && <Image file={product.thumbnail} className="h-10 w-10 rounded" alt={product.name} />}
|
|
130
|
+
<div>
|
|
131
|
+
<h3 className="font-medium">{product.name}</h3>
|
|
132
|
+
<div className="text-xs text-gray-500">SKU: {product.sku}</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
<div className="text-right">
|
|
136
|
+
<div className="font-bold">{product.price.toLocaleString()} KRW</div>
|
|
137
|
+
<div className={clsx("text-xs", product.inStock ? "text-green-600" : "text-red-600")}>
|
|
138
|
+
{product.inStock ? `${product.stockQuantity} in stock` : "Out of stock"}
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 3. Integration with LightModel Types
|
|
146
|
+
|
|
147
|
+
Model Units work with LightModel types defined in constant files:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
// In your constant.ts file
|
|
151
|
+
@Model.Light("LightProduct")
|
|
152
|
+
export class LightProduct extends via(ProductObject, ["name", "price", "sku", "inStock"] as const) {
|
|
153
|
+
get displayPrice() {
|
|
154
|
+
return `${this.price.toLocaleString()} KRW`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// In your Unit.tsx file
|
|
159
|
+
import { cnst } from "@your-lib/client";
|
|
160
|
+
|
|
161
|
+
export const Abstract = ({ product }: { product: cnst.LightProduct }) => (
|
|
162
|
+
<div>
|
|
163
|
+
<h3>{product.name}</h3>
|
|
164
|
+
<p>{product.displayPrice}</p>
|
|
165
|
+
</div>
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 4. Implementation Guidelines
|
|
170
|
+
|
|
171
|
+
1. **Server Component Requirements**:
|
|
172
|
+
|
|
173
|
+
- No client-side hooks (`useState`, `useEffect`, `useRouter`, etc.)
|
|
174
|
+
- No browser-only APIs (`localStorage`, `window`, etc.)
|
|
175
|
+
- No `"use client"` directive in the file
|
|
176
|
+
|
|
177
|
+
2. **Props Design**:
|
|
178
|
+
|
|
179
|
+
- Primary prop should be the model object (e.g., `product`, `user`, `story`)
|
|
180
|
+
- Always include `className` prop for styling customization
|
|
181
|
+
- Include `href` prop when the component might be used for navigation
|
|
182
|
+
- Keep prop interface consistent across export variations
|
|
183
|
+
|
|
184
|
+
3. **Component Variations**:
|
|
185
|
+
|
|
186
|
+
- `Abstract`: Compact representation with minimal information
|
|
187
|
+
- `Card`: Medium-detail representation in a card format
|
|
188
|
+
- `Full`: Complete representation with all relevant details
|
|
189
|
+
- Additional variations as needed (List, Row, Grid, etc.)
|
|
190
|
+
|
|
191
|
+
4. **Accessibility**:
|
|
192
|
+
- Use semantic HTML elements (`<article>`, `<section>`, `<h2>`, etc.)
|
|
193
|
+
- Include appropriate ARIA attributes
|
|
194
|
+
- Ensure proper image alt text
|
|
195
|
+
- Maintain keyboard navigability
|
|
196
|
+
|
|
197
|
+
## How to Use Model.Unit.tsx Files
|
|
198
|
+
|
|
199
|
+
### In Pages
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
// apps/your-app/app/products/page.tsx
|
|
203
|
+
import { Product } from "@shared/client";
|
|
204
|
+
import { getProducts } from "@shared/lib/product/product.service";
|
|
205
|
+
|
|
206
|
+
export default async function ProductsPage() {
|
|
207
|
+
const products = await getProducts();
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
<div className="container mx-auto">
|
|
211
|
+
<h1 className="mb-6 text-2xl font-bold">Products</h1>
|
|
212
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
213
|
+
{products.map((product) => (
|
|
214
|
+
<Product.Unit.Card key={product.id} product={product} href={`/products/${product.id}`} />
|
|
215
|
+
))}
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### In Utils
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
// libs/shared/lib/product/Product.Util.tsx
|
|
226
|
+
"use client";
|
|
227
|
+
import { useState } from "react";
|
|
228
|
+
import { Product } from "@shared/client";
|
|
229
|
+
import { cnst } from "@shared/client";
|
|
230
|
+
|
|
231
|
+
export const ProductSelector = ({
|
|
232
|
+
products,
|
|
233
|
+
onSelect,
|
|
234
|
+
}: {
|
|
235
|
+
products: cnst.LightProduct[];
|
|
236
|
+
onSelect: (product: cnst.LightProduct) => void;
|
|
237
|
+
}) => {
|
|
238
|
+
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
239
|
+
|
|
240
|
+
const handleSelect = (product: cnst.LightProduct) => {
|
|
241
|
+
setSelectedId(product.id);
|
|
242
|
+
onSelect(product);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<div className="space-y-2">
|
|
247
|
+
{products.map((product) => (
|
|
248
|
+
<button key={product.id} onClick={() => handleSelect(product)} className="w-full text-left">
|
|
249
|
+
<Product.Unit.Abstract product={product} className={selectedId === product.id ? "border-primary" : ""} />
|
|
250
|
+
</button>
|
|
251
|
+
))}
|
|
252
|
+
</div>
|
|
253
|
+
);
|
|
254
|
+
};
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### In Templates
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
// libs/shared/lib/product/Product.Template.tsx
|
|
261
|
+
"use client";
|
|
262
|
+
import { useState } from "react";
|
|
263
|
+
import { Product } from "@shared/client";
|
|
264
|
+
import { cnst } from "@shared/client";
|
|
265
|
+
import { sig } from "@shared/client";
|
|
266
|
+
|
|
267
|
+
export const ProductList = ({ initialProducts }: { initialProducts: cnst.LightProduct[] }) => {
|
|
268
|
+
const [products, setProducts] = useState(initialProducts);
|
|
269
|
+
const [loading, setLoading] = useState(false);
|
|
270
|
+
|
|
271
|
+
const loadMore = async () => {
|
|
272
|
+
if (loading) return;
|
|
273
|
+
setLoading(true);
|
|
274
|
+
try {
|
|
275
|
+
const nextPage = await sig.product.getProducts({
|
|
276
|
+
skip: products.length,
|
|
277
|
+
limit: 10,
|
|
278
|
+
});
|
|
279
|
+
setProducts([...products, ...nextPage.products]);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
console.error("Failed to load more products", error);
|
|
282
|
+
} finally {
|
|
283
|
+
setLoading(false);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<div>
|
|
289
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
290
|
+
{products.map((product) => (
|
|
291
|
+
<Product.Unit.Card key={product.id} product={product} />
|
|
292
|
+
))}
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
{products.length >= 10 && (
|
|
296
|
+
<button className="btn btn-outline mx-auto mt-6 block" onClick={loadMore} disabled={loading}>
|
|
297
|
+
{loading ? "Loading..." : "Load More"}
|
|
298
|
+
</button>
|
|
299
|
+
)}
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### In Zones
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
// libs/shared/lib/product/Product.Zone.tsx
|
|
309
|
+
"use client";
|
|
310
|
+
import { useState, useEffect } from "react";
|
|
311
|
+
import { cnst } from "@shared/client";
|
|
312
|
+
import { sig } from "@shared/client";
|
|
313
|
+
import { Product } from "@shared/client";
|
|
314
|
+
import { Zone, Tabs } from "@util/ui";
|
|
315
|
+
|
|
316
|
+
export const ProductManager = () => {
|
|
317
|
+
const [products, setProducts] = useState<cnst.LightProduct[]>([]);
|
|
318
|
+
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
|
319
|
+
|
|
320
|
+
useEffect(() => {
|
|
321
|
+
const loadProducts = async () => {
|
|
322
|
+
const data = await sig.product.getProducts({
|
|
323
|
+
filter: selectedCategory ? { byCategory: selectedCategory } : undefined,
|
|
324
|
+
});
|
|
325
|
+
setProducts(data.products);
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
loadProducts();
|
|
329
|
+
}, [selectedCategory]);
|
|
330
|
+
|
|
331
|
+
return (
|
|
332
|
+
<Zone title="Product Management">
|
|
333
|
+
<Zone.Section title="Categories">
|
|
334
|
+
<Tabs
|
|
335
|
+
tabs={[
|
|
336
|
+
{ key: null, label: "All" },
|
|
337
|
+
{ key: "electronics", label: "Electronics" },
|
|
338
|
+
{ key: "clothing", label: "Clothing" },
|
|
339
|
+
{ key: "food", label: "Food" },
|
|
340
|
+
]}
|
|
341
|
+
activeTab={selectedCategory}
|
|
342
|
+
onChange={(tab) => setSelectedCategory(tab)}
|
|
343
|
+
/>
|
|
344
|
+
</Zone.Section>
|
|
345
|
+
|
|
346
|
+
<Zone.Section title="Products">
|
|
347
|
+
<div className="space-y-2">
|
|
348
|
+
{products.map((product) => (
|
|
349
|
+
<Product.Unit.Row key={product.id} product={product} />
|
|
350
|
+
))}
|
|
351
|
+
</div>
|
|
352
|
+
</Zone.Section>
|
|
353
|
+
</Zone>
|
|
354
|
+
);
|
|
355
|
+
};
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Best Practices
|
|
359
|
+
|
|
360
|
+
### 1. Component Variations and Consistent Exports
|
|
361
|
+
|
|
362
|
+
Define multiple components for different presentation contexts:
|
|
363
|
+
|
|
364
|
+
```tsx
|
|
365
|
+
// User.Unit.tsx - Consistent naming pattern
|
|
366
|
+
export const Abstract = ({ user }) => {}; // Minimal view
|
|
367
|
+
export const Card = ({ user }) => {}; // Card view
|
|
368
|
+
export const Full = ({ user }) => {}; // Complete view
|
|
369
|
+
export const Row = ({ user }) => {}; // Table row view
|
|
370
|
+
export const Avatar = ({ user }) => {}; // Avatar-only view
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### 2. Prop Handling and Styling
|
|
374
|
+
|
|
375
|
+
```tsx
|
|
376
|
+
// Best practice: Accept and forward className
|
|
377
|
+
export const Abstract = ({
|
|
378
|
+
user,
|
|
379
|
+
className,
|
|
380
|
+
...props
|
|
381
|
+
}: {
|
|
382
|
+
user: cnst.LightUser;
|
|
383
|
+
className?: string;
|
|
384
|
+
[key: string]: any;
|
|
385
|
+
}) => (
|
|
386
|
+
<div className={clsx("user-abstract rounded border p-3", className)} {...props}>
|
|
387
|
+
{/* content */}
|
|
388
|
+
</div>
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
// Best practice: Conditional rendering based on available data
|
|
392
|
+
export const Card = ({ user, className }: { user: cnst.LightUser; className?: string }) => (
|
|
393
|
+
<div className={clsx("card", className)}>
|
|
394
|
+
<div className="card-body">
|
|
395
|
+
<h3 className="card-title">{user.name}</h3>
|
|
396
|
+
{user.title && <p className="text-sm text-gray-600">{user.title}</p>}
|
|
397
|
+
{user.bio && <p className="mt-2">{user.bio}</p>}
|
|
398
|
+
{user.tags?.length > 0 && (
|
|
399
|
+
<div className="mt-2 flex gap-1">
|
|
400
|
+
{user.tags.map((tag) => (
|
|
401
|
+
<span key={tag} className="badge">
|
|
402
|
+
{tag}
|
|
403
|
+
</span>
|
|
404
|
+
))}
|
|
405
|
+
</div>
|
|
406
|
+
)}
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
);
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### 3. Image Handling
|
|
413
|
+
|
|
414
|
+
Always use the optimized `Image` component from `@util/ui` with proper attributes:
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
import { Image } from "@util/ui";
|
|
418
|
+
|
|
419
|
+
export const Card = ({ product }: { product: cnst.LightProduct }) => (
|
|
420
|
+
<div className="card">
|
|
421
|
+
{product.image ? (
|
|
422
|
+
<Image
|
|
423
|
+
file={product.image}
|
|
424
|
+
alt={product.name}
|
|
425
|
+
className="h-40 w-full object-cover"
|
|
426
|
+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
427
|
+
/>
|
|
428
|
+
) : (
|
|
429
|
+
<div className="flex h-40 w-full items-center justify-center bg-gray-200">
|
|
430
|
+
<span className="text-gray-400">No image</span>
|
|
431
|
+
</div>
|
|
432
|
+
)}
|
|
433
|
+
{/* Other content */}
|
|
434
|
+
</div>
|
|
435
|
+
);
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### 4. Conditional Rendering and Link Handling
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
export const Abstract = ({ post, href, className }: { post: cnst.LightPost; href?: string; className?: string }) => {
|
|
442
|
+
const Content = (
|
|
443
|
+
<div className={clsx("post-abstract p-3", className)}>
|
|
444
|
+
<h3 className="font-bold">{post.title}</h3>
|
|
445
|
+
<p className="line-clamp-2 text-sm text-gray-600">{post.summary}</p>
|
|
446
|
+
</div>
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
// Conditionally wrap with Link if href is provided
|
|
450
|
+
return href ? (
|
|
451
|
+
<Link href={href} className="block transition hover:bg-gray-50">
|
|
452
|
+
{Content}
|
|
453
|
+
</Link>
|
|
454
|
+
) : (
|
|
455
|
+
Content
|
|
456
|
+
);
|
|
457
|
+
};
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### 5. Responsive Design
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
export const Card = ({ event }: { event: cnst.LightEvent }) => (
|
|
464
|
+
<div className="card">
|
|
465
|
+
<div className="card-body">
|
|
466
|
+
<h3 className="text-lg font-bold md:text-xl">{event.title}</h3>
|
|
467
|
+
<div className="flex flex-col sm:flex-row sm:justify-between">
|
|
468
|
+
<div className="text-sm">{formatDate(event.startDate)}</div>
|
|
469
|
+
<div className="mt-1 text-sm sm:mt-0">{event.location}</div>
|
|
470
|
+
</div>
|
|
471
|
+
<p className="mt-2 line-clamp-3 text-sm md:text-base">{event.description}</p>
|
|
472
|
+
</div>
|
|
473
|
+
</div>
|
|
474
|
+
);
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## Common Component Patterns and Variations
|
|
478
|
+
|
|
479
|
+
### 1. Hierarchical Components
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
// Department.Unit.tsx
|
|
483
|
+
export const Tree = ({ department }: { department: cnst.LightDepartment }) => (
|
|
484
|
+
<div className="rounded border p-3">
|
|
485
|
+
<h3 className="font-bold">{department.name}</h3>
|
|
486
|
+
{department.children?.length > 0 && (
|
|
487
|
+
<div className="mt-2 border-l pl-4">
|
|
488
|
+
{department.children.map((child) => (
|
|
489
|
+
<Tree key={child.id} department={child} />
|
|
490
|
+
))}
|
|
491
|
+
</div>
|
|
492
|
+
)}
|
|
493
|
+
</div>
|
|
494
|
+
);
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### 2. Status-Based Styling
|
|
498
|
+
|
|
499
|
+
```tsx
|
|
500
|
+
// Order.Unit.tsx
|
|
501
|
+
export const Card = ({ order }: { order: cnst.LightOrder }) => (
|
|
502
|
+
<div className="rounded border p-4">
|
|
503
|
+
<div className="flex justify-between">
|
|
504
|
+
<h3 className="font-bold">#{order.orderNumber}</h3>
|
|
505
|
+
<span
|
|
506
|
+
className={clsx(
|
|
507
|
+
"badge",
|
|
508
|
+
order.status === "completed" && "badge-success",
|
|
509
|
+
order.status === "processing" && "badge-info",
|
|
510
|
+
order.status === "cancelled" && "badge-error",
|
|
511
|
+
order.status === "pending" && "badge-warning"
|
|
512
|
+
)}
|
|
513
|
+
>
|
|
514
|
+
{order.status}
|
|
515
|
+
</span>
|
|
516
|
+
</div>
|
|
517
|
+
<div className="mt-2">
|
|
518
|
+
<div>Customer: {order.customerName}</div>
|
|
519
|
+
<div>Items: {order.itemCount}</div>
|
|
520
|
+
<div>Total: {order.totalAmount.toLocaleString()} KRW</div>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
);
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### 3. Detail and Summary Pattern
|
|
527
|
+
|
|
528
|
+
```tsx
|
|
529
|
+
// FAQ.Unit.tsx
|
|
530
|
+
export const Item = ({ faq }: { faq: cnst.LightFAQ }) => (
|
|
531
|
+
<details className="mb-2 overflow-hidden rounded border">
|
|
532
|
+
<summary className="cursor-pointer bg-gray-50 p-3 font-medium hover:bg-gray-100">{faq.question}</summary>
|
|
533
|
+
<div className="mt-2 p-3 pt-0">{faq.answer}</div>
|
|
534
|
+
</details>
|
|
535
|
+
);
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 4. Grid and List Variations
|
|
539
|
+
|
|
540
|
+
```tsx
|
|
541
|
+
// Product.Unit.tsx
|
|
542
|
+
// For grid layouts
|
|
543
|
+
export const Grid = ({ product }: { product: cnst.LightProduct }) => (
|
|
544
|
+
<div className="overflow-hidden rounded border">
|
|
545
|
+
{product.image && <Image file={product.image} className="h-40 w-full object-cover" alt={product.name} />}
|
|
546
|
+
<div className="p-3">
|
|
547
|
+
<h3 className="truncate font-bold">{product.name}</h3>
|
|
548
|
+
<p className="mt-1 font-bold">{product.price.toLocaleString()} KRW</p>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
// For list layouts
|
|
554
|
+
export const List = ({ product }: { product: cnst.LightProduct }) => (
|
|
555
|
+
<div className="flex border-b py-3">
|
|
556
|
+
{product.thumbnail && <Image file={product.thumbnail} className="h-16 w-16 object-cover" alt={product.name} />}
|
|
557
|
+
<div className="ml-3 flex-grow">
|
|
558
|
+
<h3 className="font-medium">{product.name}</h3>
|
|
559
|
+
<p className="line-clamp-1 text-sm text-gray-600">{product.description}</p>
|
|
560
|
+
</div>
|
|
561
|
+
<div className="ml-3 text-right">
|
|
562
|
+
<p className="font-bold">{product.price.toLocaleString()} KRW</p>
|
|
563
|
+
<p className="text-xs text-gray-500">SKU: {product.sku}</p>
|
|
564
|
+
</div>
|
|
565
|
+
</div>
|
|
566
|
+
);
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Performance Optimization
|
|
570
|
+
|
|
571
|
+
### 1. Efficient Rendering with Memoization
|
|
572
|
+
|
|
573
|
+
When using Model.Unit components in lists, consider memoizing them in client components:
|
|
574
|
+
|
|
575
|
+
```tsx
|
|
576
|
+
// In a client component file
|
|
577
|
+
"use client";
|
|
578
|
+
import { memo } from "react";
|
|
579
|
+
import { Product } from "@shared/client";
|
|
580
|
+
|
|
581
|
+
// Create memoized versions to prevent unnecessary re-renders
|
|
582
|
+
const ProductCard = memo(Product.Unit.Card);
|
|
583
|
+
const ProductRow = memo(Product.Unit.Row);
|
|
584
|
+
|
|
585
|
+
export const ProductList = ({ products, view = "grid" }) => {
|
|
586
|
+
return (
|
|
587
|
+
<div className={view === "grid" ? "grid grid-cols-3 gap-4" : "space-y-2"}>
|
|
588
|
+
{products.map((product) =>
|
|
589
|
+
view === "grid" ? (
|
|
590
|
+
<ProductCard key={product.id} product={product} />
|
|
591
|
+
) : (
|
|
592
|
+
<ProductRow key={product.id} product={product} />
|
|
593
|
+
)
|
|
594
|
+
)}
|
|
595
|
+
</div>
|
|
596
|
+
);
|
|
597
|
+
};
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### 2. Virtualization for Long Lists
|
|
601
|
+
|
|
602
|
+
```tsx
|
|
603
|
+
"use client";
|
|
604
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
605
|
+
import { useRef } from "react";
|
|
606
|
+
import { Product } from "@shared/client";
|
|
607
|
+
|
|
608
|
+
export const VirtualProductList = ({ products }) => {
|
|
609
|
+
const parentRef = useRef(null);
|
|
610
|
+
|
|
611
|
+
const virtualizer = useVirtualizer({
|
|
612
|
+
count: products.length,
|
|
613
|
+
getScrollElement: () => parentRef.current,
|
|
614
|
+
estimateSize: () => 80, // Approximate height of each row
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
return (
|
|
618
|
+
<div ref={parentRef} className="h-[600px] overflow-auto">
|
|
619
|
+
<div className="relative w-full" style={{ height: `${virtualizer.getTotalSize()}px` }}>
|
|
620
|
+
{virtualizer.getVirtualItems().map((virtualItem) => (
|
|
621
|
+
<div
|
|
622
|
+
key={virtualItem.key}
|
|
623
|
+
className="absolute top-0 left-0 w-full"
|
|
624
|
+
style={{
|
|
625
|
+
height: `${virtualItem.size}px`,
|
|
626
|
+
transform: `translateY(${virtualItem.start}px)`,
|
|
627
|
+
}}
|
|
628
|
+
>
|
|
629
|
+
<Product.Unit.Row product={products[virtualItem.index]} />
|
|
630
|
+
</div>
|
|
631
|
+
))}
|
|
632
|
+
</div>
|
|
633
|
+
</div>
|
|
634
|
+
);
|
|
635
|
+
};
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### 3. Image Optimization Techniques
|
|
639
|
+
|
|
640
|
+
```tsx
|
|
641
|
+
import { Image } from "@util/ui";
|
|
642
|
+
|
|
643
|
+
export const Card = ({ product }: { product: cnst.LightProduct }) => (
|
|
644
|
+
<div className="card">
|
|
645
|
+
{product.image && (
|
|
646
|
+
<Image
|
|
647
|
+
file={product.image}
|
|
648
|
+
alt={product.name}
|
|
649
|
+
className="h-40 w-full object-cover"
|
|
650
|
+
priority={false}
|
|
651
|
+
loading="lazy"
|
|
652
|
+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
653
|
+
/>
|
|
654
|
+
)}
|
|
655
|
+
{/* Other content */}
|
|
656
|
+
</div>
|
|
657
|
+
);
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### 4. Conditional Loading of Complex Units
|
|
661
|
+
|
|
662
|
+
For complex units with heavy rendering needs:
|
|
663
|
+
|
|
664
|
+
```tsx
|
|
665
|
+
export const Full = ({ product, detailed = false }: { product: cnst.LightProduct; detailed?: boolean }) => (
|
|
666
|
+
<div className="product-full rounded border p-4">
|
|
667
|
+
<h2 className="text-xl font-bold">{product.name}</h2>
|
|
668
|
+
<p className="mt-2">{product.price.toLocaleString()} KRW</p>
|
|
669
|
+
|
|
670
|
+
{/* Only render detailed content when needed */}
|
|
671
|
+
{detailed && (
|
|
672
|
+
<>
|
|
673
|
+
<div className="mt-4 grid grid-cols-2 gap-2">
|
|
674
|
+
<div>SKU: {product.sku}</div>
|
|
675
|
+
<div>Category: {product.category}</div>
|
|
676
|
+
<div>Stock: {product.stockQuantity}</div>
|
|
677
|
+
<div>Weight: {product.weight}kg</div>
|
|
678
|
+
</div>
|
|
679
|
+
|
|
680
|
+
<div className="mt-4">
|
|
681
|
+
<h3 className="font-bold">Specifications</h3>
|
|
682
|
+
<table className="mt-2 w-full border">
|
|
683
|
+
<tbody>
|
|
684
|
+
{product.specifications?.map((spec) => (
|
|
685
|
+
<tr key={spec.key} className="border-b">
|
|
686
|
+
<td className="p-2 font-medium">{spec.key}</td>
|
|
687
|
+
<td className="p-2">{spec.value}</td>
|
|
688
|
+
</tr>
|
|
689
|
+
))}
|
|
690
|
+
</tbody>
|
|
691
|
+
</table>
|
|
692
|
+
</div>
|
|
693
|
+
</>
|
|
694
|
+
)}
|
|
695
|
+
</div>
|
|
696
|
+
);
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
## Troubleshooting Common Issues
|
|
700
|
+
|
|
701
|
+
### 1. Server Component Errors
|
|
702
|
+
|
|
703
|
+
```
|
|
704
|
+
Error: useState is not defined in Model.Unit.tsx
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
**Solution**: Keep Model.Unit.tsx as server components without client-side hooks:
|
|
708
|
+
|
|
709
|
+
```tsx
|
|
710
|
+
// ❌ INCORRECT: Don't use client hooks in Unit components
|
|
711
|
+
export const Card = ({ product }) => {
|
|
712
|
+
const [expanded, setExpanded] = useState(false); // Error: client hook in server component
|
|
713
|
+
return (/* ... */);
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
// ✅ CORRECT: Keep Unit components as pure presentation components
|
|
717
|
+
export const Card = ({ product, expanded = false }) => {
|
|
718
|
+
return (/* Render based on expanded prop */);
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
// If you need interactivity, handle it in a client component that wraps the Unit:
|
|
722
|
+
// In a client component file:
|
|
723
|
+
"use client";
|
|
724
|
+
import { useState } from "react";
|
|
725
|
+
import { Product } from "@shared/client";
|
|
726
|
+
|
|
727
|
+
export const ExpandableProductCard = ({ product }) => {
|
|
728
|
+
const [expanded, setExpanded] = useState(false);
|
|
729
|
+
return (
|
|
730
|
+
<div>
|
|
731
|
+
<Product.Unit.Card product={product} expanded={expanded} />
|
|
732
|
+
<button onClick={() => setExpanded(!expanded)}>
|
|
733
|
+
{expanded ? "Show Less" : "Show More"}
|
|
734
|
+
</button>
|
|
735
|
+
</div>
|
|
736
|
+
);
|
|
737
|
+
};
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
### 2. Image Handling Errors
|
|
741
|
+
|
|
742
|
+
```
|
|
743
|
+
Error: Image component requires "alt" prop
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**Solution**: Always include alt text for images:
|
|
747
|
+
|
|
748
|
+
```tsx
|
|
749
|
+
// ❌ INCORRECT
|
|
750
|
+
<Image file={product.image} className="w-full" />
|
|
751
|
+
|
|
752
|
+
// ✅ CORRECT
|
|
753
|
+
<Image
|
|
754
|
+
file={product.image}
|
|
755
|
+
alt={product.name || "Product image"}
|
|
756
|
+
className="w-full"
|
|
757
|
+
/>
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### 3. Conditional Rendering Issues
|
|
761
|
+
|
|
762
|
+
```
|
|
763
|
+
Error: Cannot read properties of undefined (reading 'url')
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
**Solution**: Always check for existence before accessing nested properties:
|
|
767
|
+
|
|
768
|
+
```tsx
|
|
769
|
+
// ❌ INCORRECT
|
|
770
|
+
<Image file={user.avatar.url} alt={user.name} />;
|
|
771
|
+
|
|
772
|
+
// ✅ CORRECT
|
|
773
|
+
{
|
|
774
|
+
user.avatar?.url && <Image file={user.avatar} alt={user.name} />;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Alternative approach with default/fallback
|
|
778
|
+
{
|
|
779
|
+
user.avatar?.url ? (
|
|
780
|
+
<Image file={user.avatar} alt={user.name} />
|
|
781
|
+
) : (
|
|
782
|
+
<div className="avatar-placeholder">{user.name.charAt(0).toUpperCase()}</div>
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### 4. Type Safety Issues
|
|
788
|
+
|
|
789
|
+
```
|
|
790
|
+
Type error: Property 'description' does not exist on type 'LightProduct'
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
**Solution**: Ensure you're only accessing properties defined in the LightModel:
|
|
794
|
+
|
|
795
|
+
```tsx
|
|
796
|
+
// In constant.ts
|
|
797
|
+
@Model.Light("LightProduct")
|
|
798
|
+
export class LightProduct extends via(ProductObject, ["name", "price", "sku"] as const) {
|
|
799
|
+
// Only these fields are guaranteed to be available
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// ❌ INCORRECT: Accessing properties not in the LightModel
|
|
803
|
+
export const Card = ({ product }: { product: cnst.LightProduct }) => (
|
|
804
|
+
<div>
|
|
805
|
+
<h3>{product.name}</h3>
|
|
806
|
+
<p>{product.description}</p> // Error: description is not in LightProduct
|
|
807
|
+
</div>
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
// ✅ CORRECT: Check for optional properties
|
|
811
|
+
export const Card = ({ product }: { product: cnst.LightProduct }) => (
|
|
812
|
+
<div>
|
|
813
|
+
<h3>{product.name}</h3>
|
|
814
|
+
{/* Use optional chaining for properties that might not exist */}
|
|
815
|
+
{product.description && <p>{product.description}</p>}
|
|
816
|
+
</div>
|
|
817
|
+
);
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
## Conclusion
|
|
821
|
+
|
|
822
|
+
Model.Unit.tsx files are essential building blocks in the Akan.js framework, providing consistent, reusable presentation components for your domain models. By following these guidelines, you'll create well-structured, performant, and maintainable UI components that work seamlessly across your application.
|
|
823
|
+
|
|
824
|
+
Key takeaways:
|
|
825
|
+
|
|
826
|
+
- Create multiple component variations (Abstract, Card, Full, etc.) for different use cases
|
|
827
|
+
- Keep components as server components without client-side hooks
|
|
828
|
+
- Focus on presentation only, leaving business logic to Service files
|
|
829
|
+
- Follow consistent prop patterns with className and href support
|
|
830
|
+
- Optimize for performance with proper image handling and conditional rendering
|
|
831
|
+
- Ensure type safety by respecting LightModel type definitions
|
|
832
|
+
|
|
833
|
+
Well-designed Model.Unit components improve development velocity, maintain UI consistency, and enable seamless component reuse throughout your Akan.js applications.
|