1
2import { clsx } from "@akanjs/client";
3import { ModelType } from "@your-app/client";
4
5interface ComponentProps {
6 className?: string;
7 // Feature-specific props
8}
9
10export const Component = ({ className, ...props }: ComponentProps) => {
11 return <div className={clsx("base-classes", className)}>
12 {/* Component content */}
13 </div>;
14};
1
2{apps,libs}/
3└── project-name/
4 └── lib/
5 └── feature-name/
6 ├── FeatureName.Unit.tsx
7 ├── FeatureName.View.tsx
8 ├── FeatureName.Template.tsx
9 ├── FeatureName.Util.tsx
10 ├── FeatureName.Zone.tsx
11 ├── featureName.constant.ts
12 ├── featureName.service.ts
13 ├── featureName.signal.ts
14 ├── featureName.store.ts
15 └── index.ts
1
2export const Card = ({ model, href }) => {
3 return (
4 <Link href={href}
5 className="card bg-base-100 rounded-lg shadow-sm transition-shadow hover:shadow-lg">
6 <div className="card-body p-4">
7 <h3 className="card-title font-medium">{model.title}</h3>
8 <p className="text-base-content/70">{model.description}</p>
9 </div>
10 </Link>
11 );
12};
1
2export const General = ({ model, className }) => {
3 return (
4 <div className={clsx("bg-base-100 rounded-lg p-6 shadow-lg", className)}>
5 <div className="border-base-content mb-6 border-l-4 pl-4 py-2">
6 <h1 className=" text-2xl font-bold">{model.title}</h1>
7 </div>
8 <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
9 {/* Model details */}
10 </div>
11 </div>
12 );
13};
1
2export const General = () => {
3 const form = useModelForm();
4 return (
5 <div className="space-y-4">
6 <div className="form-control w-full">
7 <label className="label">
8 <span className="label-text">Title</span>
9 </label>
10 <input
11 value={form.title ?? ""}
12 onChange={(e) => setTitle(e.target.value)}
13 className="input input-bordered w-full"
14 />
15 </div>
16 {/* Additional form fields */}
17 </div>
18 );
19};
1
2export const Toolbar = ({ model, className }) => {
3 return (
4 <div className={clsx("flex gap-2", className)}>
5 <button className="btn btn-primary btn-sm">Duplicate</button>
6 <button className="btn btn-error btn-sm">Delete</button>
7 </div>
8 );
9};
1
2export const List = ({ init, query, className }) => {
3 return (
4 <Load.Units
5 init={init}
6 query={query}
7 className={clsx("grid grid-cols-1 gap-4 md:grid-cols-2", className)}
8 renderItem={(model) => <Model.Unit.Card model={model} />}
9 renderEmpty={() => <div className="alert alert-info">No items found</div>}
10 />
11 );
12};
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)
1
2export const ProductCard = ({ product, href }) => {
3 return (
4 <Link href={href} className="card bg-base-100 rounded-lg shadow-sm transition-shadow hover:shadow-lg">
5 <figure className="px-4 pt-4">
6 <img src={product.image?.url} alt={product.name}
7 className="h-48 w-full rounded-lg object-cover" />
8 </figure>
9 <div className="card-body p-4">
10 <h3 className="card-title font-medium">{product.name}</h3>
11 <div className="text-primary">${product.price?.toFixed(2)}</div>
12 <p className="text-base-content/70 text-sm">{product.description}</p>
13 </div>
14 </Link>
15 );
16};
1
2export const ProductView = ({ product, className }) => {
3 return (
4 <div className={clsx("bg-base-100 rounded-lg p-6 shadow-lg", className)}>
5 <div className="flex flex-col gap-6 md:flex-row">
6 <div className="w-full md:w-1/2">
7 <img src={product.image?.url} alt={product.name}
8 className="w-full rounded-lg object-cover" />
9 </div>
10 <div className="w-full md:w-1/2 space-y-4">
11 <h1 className="text-3xl font-bold">{product.name}</h1>
12 <div className="text-primary text-xl font-medium">
13 ${product.price?.toFixed(2)}
14 </div>
15 <p className="whitespace-pre-wrap">{product.description}</p>
16 <div className="flex gap-2">
17 <button className="btn btn-primary">Add to Cart</button>
18 <button className="btn btn-outline">Save for Later</button>
19 </div>
20 </div>
21 </div>
22 </div>
23 );
24};
1
2export const ProductForm = () => {
3 const [form, setForm] = useState({ name: '', price: 0 });
4
5 return (
6 <div className="space-y-6">
7 <div className="form-control w-full">
8 <label className="label">
9 <span className="label-text">Product Name</span>
10 </label>
11 <input
12 value={form.name}
13 onChange={(e) => setForm({...form, name: e.target.value})}
14 className="input input-bordered w-full"
15 />
16 </div>
17
18 <div className="form-control w-full">
19 <label className="label">
20 <span className="label-text">Price</span>
21 </label>
22 <input
23 type="number"
24 value={form.price}
25 onChange={(e) => setForm({...form, price: Number(e.target.value)})}
26 className="input input-bordered w-full"
27 />
28 </div>
29 </div>
30 );
31};