Contributing Guide
Guidelines for contributing components, CLI tools, fonts, and documentation to Kewti.
Monorepo Architecture
Kewti is structured as a pnpm workspace powered by Turborepo:
| Path | Description |
|---|---|
packages/ui | Core component library source (packages/ui/src/components/). |
packages/cli | Kewti CLI package (npx kewti-cli add ...). |
packages/fonts | Optimized Ge'ez and Amharic web font assets. |
apps/registry | Registry generator and JSON bundle builder for CLI distribution. |
apps/kewti-docs | Documentation site built with Next.js and Fumadocs. |
apps/web | Web app and visual showcase, including hosted API endpoints. |
Setup & Development
1. Clone & Install
git clone https://github.com/coderade1905/kewti.git
cd kewti
pnpm install2. Start Dev Servers
pnpm dev3. Verification Commands
pnpm build: Build all workspace packages and applications.pnpm typecheck: Run TypeScript type checking.pnpm lint: Run ESLint across packages.
Adding New Components
Follow this step-by-step workflow to contribute a new component:
Step 1: Create Component Source
Create your component in packages/ui/src/components/kewti-<name>/component.tsx:
import * as React from "react"
import { cn } from "@/lib/utils"
export interface KewtiExampleProps extends React.HTMLAttributes<HTMLDivElement> {
// Add component props
}
export function KewtiExample({ className, ...props }: KewtiExampleProps) {
return (
<div className={cn("p-4 rounded-lg border", className)} {...props} />
)
}Design & Code Standards:
- Tailwind CSS: Use Tailwind classes with full
dark:mode variant support. - Self-Contained: Ensure component files do not rely on implicit external imports so CLI copy-pasting works cleanly.
Step 2: Register in Registry
Every UI component must be registered in apps/registry/registry-ui.ts so that the registry build script (pnpm --filter registry build) can process it into distribution JSON files (registry.json and registry-combined.json) used by the CLI.
Registry File Location
- File:
apps/registry/registry-ui.ts
Registry Item Schema (RegistryItem)
Each item in the uiRegistry array must adhere to the RegistryItem type:
export type RegistryItem = {
name: string; // Component name (e.g., "kewti-example")
type: "components:ui"; // Registry item type
dependencies?: string[]; // Third-party npm dependencies
registryDependencies?: string[];// Internal registry dependencies
files: string[]; // Relative paths to component source files
};Step-by-Step Registration Guide
-
Add Entry to
uiRegistry: Openapps/registry/registry-ui.tsand add your component configuration touiRegistry:{ name: "kewti-example", type: "components:ui", dependencies: ["lucide-react"], registryDependencies: ["fonts"], files: ["kewti-example/component.tsx"], } -
Configure Property Fields:
name(required): The unique component identifier (e.g.,"kewti-time","kewti-calender"). Must match the component directory name inpackages/ui/src/components/.type(required): Must be set to"components:ui".dependencies(optional): Array of external npm packages required by this component (e.g.,["lucide-react", "kenat"]). When installed via CLI, these are automatically installed in the user's project.registryDependencies(optional): Array of internal Kewti registry items required by this component (e.g.,["fonts"]). The CLI recursively fetches and installs these items prior to installing the component.files(required): Array of relative paths frompackages/ui/src/components/for all source files comprising the component.
Note: The primary entry file for the component should be named
component.tsxin the component root directory. This enables the CLI to automatically generate the barrel export insrc/kewti/ui/index.ts. -
Build Registry Output: Run the registry build script to ensure JSON bundles build without errors:
pnpm --filter registry build
Step 3: Test CLI Fetching
Build the CLI to test component installation:
pnpm --filter cli buildStep 4: Write Documentation
Add an MDX document under apps/kewti-docs/content/docs/components/kewti-<name>.mdx detailing:
- Live
<CodePlayground />preview. - Installation command (
npx kewti-cli add <name>). - Usage examples and props table.
Adding API Data Endpoints
Certain components (like KewtiSelect or KewtiLocationSelector) rely on fetching structured reference data (e.g., Ethiopian banks, universities, or locations). We host these data APIs directly within our Next.js web app under apps/web/app/api/.
To contribute a new data API endpoint:
Step 1: Create the Data Source
Create a structured JSON file (e.g., universities.json) inside the new API route directory apps/web/app/api/<endpoint-name>/.
Step 2: Create the Route Handler
Create a route.ts file in the same directory. It must include CORS headers so that the kewti-docs site, code playgrounds, and external users can fetch the data safely.
Here is a standard example for an API route (apps/web/app/api/universities/route.ts):
import { NextResponse } from "next/server"
import universityData from "./universities.json"
// Helper function to set CORS headers on any response
function setCorsHeaders(response: NextResponse) {
response.headers.set("Access-Control-Allow-Origin", "*")
response.headers.set("Access-Control-Allow-Methods", "GET, OPTIONS")
response.headers.set("Access-Control-Allow-Headers", "Content-Type")
return response
}
export async function GET() {
try {
// Create the response with your JSON data
const response = NextResponse.json(universityData)
// Append CORS headers for cross-origin / cross-port requests
return setCorsHeaders(response)
} catch (error) {
const errorResponse = NextResponse.json(
{ error: "Failed to load data" },
{ status: 500 }
)
return setCorsHeaders(errorResponse)
}
}
// Handle the preflight browser check request
export async function OPTIONS() {
const response = new NextResponse(null, { status: 204 })
return setCorsHeaders(response)
}Adding New Fonts
To contribute an Amharic or Ge'ez web font to Kewti:
Step 1: Add Font Files
Create a directory inside packages/fonts/<Font_Name>/ containing font files (.ttf, .otf, .woff2) and the license:
packages/fonts/Balderasu/
├── Balderasu_Regular.ttf
└── license.txtStep 2: Register Font in Registry
Add an entry to fontsRegistry inside apps/registry/registry-fonts.ts:
{
name: "Balderasu",
title: "Balderasu",
folder: "Balderasu",
license: "SIL Open Font License",
licenseFile: "license.txt",
fontType: "truetype", // "truetype" | "opentype" | "woff2"
files: [
{
file: "Balderasu_Regular.ttf",
variant: "regular",
},
],
}Step 3: Build & Test
- Build registry files:
pnpm --filter registry build - Test CLI font installation:
npx kewti-cli font Balderasu
Submitting Pull Requests
- Keep pull requests scoped to a single feature, component, font, API data endpoint, or fix.
- Always run
pnpm typecheckandpnpm buildbefore opening a pull request. - Follow existing codebase patterns and formatting standards.