1import { clsx } from "@akanjs/client";
2import { ModelType } from "@your-app/client";
3
4interface ComponentProps {
5 className?: string;
6 // Feature-specific props
7}
8
9export const Component = ({ className, ...props }: ComponentProps) => {
10 return <div className={clsx("base-classes", className)}>
11 {/* Component content */}
12 </div>;
13};1{apps,libs}/
2└── project-name/
3 └── lib/
4 └── feature-name/
5 ├── FeatureName.Unit.tsx
6 ├── FeatureName.View.tsx
7 ├── FeatureName.Template.tsx
8 ├── FeatureName.Util.tsx
9 ├── FeatureName.Zone.tsx
10 ├── featureName.constant.ts
11 ├── featureName.service.ts
12 ├── featureName.signal.ts
13 ├── featureName.store.ts
14 └── index.ts1export const Card = ({ model, href }) => {
2 return (
3 <Link href={href}
4 className="card bg-base-100 rounded-lg shadow-sm transition-shadow hover:shadow-lg">
5 <div className="card-body p-4">
6 <h3 className="card-title font-medium">{model.title}</h3>
7 <p className="text-base-content/70">{model.description}</p>
8 </div>
9 </Link>
10 );
11};1export const General = ({ model, className }) => {
2 return (
3 <div className={clsx("bg-base-100 rounded-lg p-6 shadow-lg", className)}>
4 <div className="border-base-content mb-6 border-l-4 pl-4 py-2">
5 <h1 className=" text-2xl font-bold">{model.title}</h1>
6 </div>
7 <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
8 {/* Model details */}
9 </div>
10 </div>
11 );
12};1export const General = () => {
2 const form = useModelForm();
3 return (
4 <div className="space-y-4">
5 <div className="form-control w-full">
6 <label className="label">
7 <span className="label-text">Title</span>
8 </label>
9 <input
10 value={form.title ?? ""}
11 onChange={(e) => setTitle(e.target.value)}
12 className="input input-bordered w-full"
13 />
14 </div>
15 {/* Additional form fields */}
16 </div>
17 );
18};1export const Toolbar = ({ model, className }) => {
2 return (
3 <div className={clsx("flex gap-2", className)}>
4 <button className="btn btn-primary btn-sm">Duplicate</button>
5 <button className="btn btn-error btn-sm">Delete</button>
6 </div>
7 );
8};1export const List = ({ init, query, className }) => {
2 return (
3 <Load.Units
4 init={init}
5 query={query}
6 className={clsx("grid grid-cols-1 gap-4 md:grid-cols-2", className)}
7 renderItem={(model) => <Model.Unit.Card model={model} />}
8 renderEmpty={() => <div className="alert alert-info">No items found</div>}
9 />
10 );
11};| Option | Type | Default | Description | Example |
|---|---|---|---|---|
| {Model}.Unit.tsx | Pattern | - | Card/list item components for model display | |
| {Model}.View.tsx | Pattern | - | Detailed view components for single models | |
| {Model}.Template.tsx | Pattern | - | Form/edit components for model manipulation | |
| {Model}.Util.tsx | Pattern | - | Utility components specific to a feature | |
| {Model}.Zone.tsx | Pattern | - | Container components with data loading | |
| {model}.constant.ts | Pattern | - | Types, GraphQL schema, and enums | |
| {model}.service.ts | Pattern | - | Business logic and database operations | |
| {model}.signal.ts | Pattern | - | Client state management and API calls | |
Card/list item components for model display
Detailed view components for single models
Form/edit components for model manipulation
Utility components specific to a feature
Container components with data loading
Types, GraphQL schema, and enums
Business logic and database operations
Client state management and API calls
| utility | Description | Example |
|---|---|---|
| Cookie Management | Handles browser cookie operations | |
| Storage Utilities | Cross-platform storage for web and mobile | |
| Device Capabilities | Access device features like haptic feedback | |
| Routing | Navigation and URL management | |
| CSS Utilities | Class name management and composition | |
Handles browser cookie operations
1setCookie("session", "token123");
2const session = getCookie("session");Cross-platform storage for web and mobile
1await storage.setItem("key", "value");
2const value = await storage.getItem("key");Access device features like haptic feedback
1await device.init();
2device.vibrate("medium");Navigation and URL management
1router.push("/dashboard");
2router.replace("/login", { q: "term" });Class name management and composition
1clsx("base-class", isActive && "active-class", className)1export const ProductCard = ({ product, href }) => {
2 return (
3 <Link href={href} className="card bg-base-100 rounded-lg shadow-sm transition-shadow hover:shadow-lg">
4 <figure className="px-4 pt-4">
5 <img src={product.image?.url} alt={product.name}
6 className="h-48 w-full rounded-lg object-cover" />
7 </figure>
8 <div className="card-body p-4">
9 <h3 className="card-title font-medium">{product.name}</h3>
10 <div className="text-primary">${product.price?.toFixed(2)}</div>
11 <p className="text-base-content/70 text-sm">{product.description}</p>
12 </div>
13 </Link>
14 );
15};1export const ProductView = ({ product, className }) => {
2 return (
3 <div className={clsx("bg-base-100 rounded-lg p-6 shadow-lg", className)}>
4 <div className="flex flex-col gap-6 md:flex-row">
5 <div className="w-full md:w-1/2">
6 <img src={product.image?.url} alt={product.name}
7 className="w-full rounded-lg object-cover" />
8 </div>
9 <div className="w-full md:w-1/2 space-y-4">
10 <h1 className="text-3xl font-bold">{product.name}</h1>
11 <div className="text-primary text-xl font-medium">
12 ${product.price?.toFixed(2)}
13 </div>
14 <p className="whitespace-pre-wrap">{product.description}</p>
15 <div className="flex gap-2">
16 <button className="btn btn-primary">Add to Cart</button>
17 <button className="btn btn-outline">Save for Later</button>
18 </div>
19 </div>
20 </div>
21 </div>
22 );
23};1export const ProductForm = () => {
2 const [form, setForm] = useState({ name: '', price: 0 });
3
4 return (
5 <div className="space-y-6">
6 <div className="form-control w-full">
7 <label className="label">
8 <span className="label-text">Product Name</span>
9 </label>
10 <input
11 value={form.name}
12 onChange={(e) => setForm({...form, name: e.target.value})}
13 className="input input-bordered w-full"
14 />
15 </div>
16
17 <div className="form-control w-full">
18 <label className="label">
19 <span className="label-text">Price</span>
20 </label>
21 <input
22 type="number"
23 value={form.price}
24 onChange={(e) => setForm({...form, price: Number(e.target.value)})}
25 className="input input-bordered w-full"
26 />
27 </div>
28 </div>
29 );
30};