chore: fmt

This commit is contained in:
Michael Abebe
2026-05-12 16:50:18 +03:00
parent 4540d35215
commit 1c5ee19388
181 changed files with 1492 additions and 1100 deletions

View File

@@ -1,24 +1,29 @@
import { HTMLAttributes } from 'react';
import clsx from 'clsx';
import { HTMLAttributes } from "react";
import clsx from "clsx";
export type BadgeTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
export type BadgeTone = "neutral" | "success" | "warning" | "danger" | "info";
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
tone?: BadgeTone;
}
const toneClasses: Record<BadgeTone, string> = {
neutral: 'bg-gray-100 text-gray-700',
success: 'bg-green-100 text-green-700',
warning: 'bg-amber-100 text-amber-800',
danger: 'bg-red-100 text-red-700',
info: 'bg-sky-100 text-sky-700',
neutral: "bg-gray-100 text-gray-700",
success: "bg-green-100 text-green-700",
warning: "bg-amber-100 text-amber-800",
danger: "bg-red-100 text-red-700",
info: "bg-sky-100 text-sky-700",
};
const Badge = ({ tone = 'neutral', className, children, ...rest }: BadgeProps) => (
const Badge = ({
tone = "neutral",
className,
children,
...rest
}: BadgeProps) => (
<span
className={clsx(
'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium',
"inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
toneClasses[tone],
className,
)}

View File

@@ -1,2 +1,2 @@
export { default } from './Badge';
export type { BadgeProps, BadgeTone } from './Badge';
export { default } from "./Badge";
export type { BadgeProps, BadgeTone } from "./Badge";

View File

@@ -1,8 +1,8 @@
import { ButtonHTMLAttributes, forwardRef } from 'react';
import clsx from 'clsx';
import { ButtonHTMLAttributes, forwardRef } from "react";
import clsx from "clsx";
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
export type ButtonSize = 'sm' | 'md' | 'lg';
export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
export type ButtonSize = "sm" | "md" | "lg";
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
@@ -11,36 +11,47 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
}
const variantClasses: Record<ButtonVariant, string> = {
primary: 'bg-blue-600 text-white hover:bg-blue-700 disabled:bg-blue-300',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200 disabled:bg-gray-50',
ghost: 'bg-transparent text-gray-900 hover:bg-gray-100',
danger: 'bg-red-600 text-white hover:bg-red-700 disabled:bg-red-300',
primary: "bg-blue-600 text-white hover:bg-blue-700 disabled:bg-blue-300",
secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 disabled:bg-gray-50",
ghost: "bg-transparent text-gray-900 hover:bg-gray-100",
danger: "bg-red-600 text-white hover:bg-red-700 disabled:bg-red-300",
};
const sizeClasses: Record<ButtonSize, string> = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-base',
lg: 'px-6 py-3 text-lg',
sm: "px-3 py-1.5 text-sm",
md: "px-4 py-2 text-base",
lg: "px-6 py-3 text-lg",
};
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', size = 'md', isLoading, disabled, className, children, ...rest }, ref) => (
(
{
variant = "primary",
size = "md",
isLoading,
disabled,
className,
children,
...rest
},
ref,
) => (
<button
ref={ref}
disabled={disabled || isLoading}
className={clsx(
'inline-flex items-center justify-center rounded-md font-medium transition-colors disabled:cursor-not-allowed',
"inline-flex items-center justify-center rounded-md font-medium transition-colors disabled:cursor-not-allowed",
variantClasses[variant],
sizeClasses[size],
className,
)}
{...rest}
>
{isLoading ? 'Loading...' : children}
{isLoading ? "Loading..." : children}
</button>
),
);
Button.displayName = 'Button';
Button.displayName = "Button";
export default Button;

View File

@@ -1,2 +1,2 @@
export { default } from './Button';
export type { ButtonProps, ButtonVariant, ButtonSize } from './Button';
export { default } from "./Button";
export type { ButtonProps, ButtonVariant, ButtonSize } from "./Button";

View File

@@ -1,5 +1,5 @@
import { InputHTMLAttributes, ReactNode, forwardRef } from 'react';
import clsx from 'clsx';
import { InputHTMLAttributes, ReactNode, forwardRef } from "react";
import clsx from "clsx";
export interface FormFieldProps extends InputHTMLAttributes<HTMLInputElement> {
label: string;
@@ -18,21 +18,23 @@ const FormField = forwardRef<HTMLInputElement, FormFieldProps>(
id={fieldId}
aria-invalid={Boolean(error)}
className={clsx(
'rounded-md border px-3 py-2 text-gray-900 outline-none transition focus:ring-2',
"rounded-md border px-3 py-2 text-gray-900 outline-none transition focus:ring-2",
error
? 'border-red-400 focus:border-red-500 focus:ring-red-100'
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-100',
? "border-red-400 focus:border-red-500 focus:ring-red-100"
: "border-gray-300 focus:border-blue-500 focus:ring-blue-100",
className,
)}
{...rest}
/>
{hint && !error ? <span className="text-xs text-gray-500">{hint}</span> : null}
{hint && !error ? (
<span className="text-xs text-gray-500">{hint}</span>
) : null}
{error ? <span className="text-xs text-red-600">{error}</span> : null}
</label>
);
},
);
FormField.displayName = 'FormField';
FormField.displayName = "FormField";
export default FormField;

View File

@@ -1,2 +1,2 @@
export { default as FormField } from './FormField';
export type { FormFieldProps } from './FormField';
export { default as FormField } from "./FormField";
export type { FormFieldProps } from "./FormField";

View File

@@ -1,5 +1,5 @@
import { ReactNode } from 'react';
import Sidebar, { SidebarItem } from './Sidebar';
import { ReactNode } from "react";
import Sidebar, { SidebarItem } from "./Sidebar";
export interface DashboardLayoutProps {
title?: string;

View File

@@ -1,5 +1,5 @@
import { ReactNode } from 'react';
import clsx from 'clsx';
import { ReactNode } from "react";
import clsx from "clsx";
export interface SidebarItem {
label: string;
@@ -16,7 +16,11 @@ export interface SidebarProps {
const Sidebar = ({ title, items, activeHref, onNavigate }: SidebarProps) => (
<aside className="flex w-60 flex-col gap-1 border-r border-gray-200 bg-white px-3 py-4">
{title ? <div className="px-2 pb-3 text-sm font-semibold text-gray-700">{title}</div> : null}
{title ? (
<div className="px-2 pb-3 text-sm font-semibold text-gray-700">
{title}
</div>
) : null}
<nav className="flex flex-col gap-0.5">
{items.map((item) => (
<a
@@ -29,13 +33,15 @@ const Sidebar = ({ title, items, activeHref, onNavigate }: SidebarProps) => (
}
}}
className={clsx(
'flex items-center gap-2 rounded-md px-2 py-2 text-sm transition-colors',
"flex items-center gap-2 rounded-md px-2 py-2 text-sm transition-colors",
activeHref === item.href
? 'bg-blue-50 text-blue-700'
: 'text-gray-700 hover:bg-gray-100',
? "bg-blue-50 text-blue-700"
: "text-gray-700 hover:bg-gray-100",
)}
>
{item.icon ? <span className="text-gray-500">{item.icon}</span> : null}
{item.icon ? (
<span className="text-gray-500">{item.icon}</span>
) : null}
<span>{item.label}</span>
</a>
))}

View File

@@ -1,4 +1,4 @@
export { default as Sidebar } from './Sidebar';
export { default as DashboardLayout } from './DashboardLayout';
export type { SidebarProps, SidebarItem } from './Sidebar';
export type { DashboardLayoutProps } from './DashboardLayout';
export { default as Sidebar } from "./Sidebar";
export { default as DashboardLayout } from "./DashboardLayout";
export type { SidebarProps, SidebarItem } from "./Sidebar";
export type { DashboardLayoutProps } from "./DashboardLayout";

View File

@@ -1,4 +1,4 @@
import { ReactNode, useEffect } from 'react';
import { ReactNode, useEffect } from "react";
export interface ModalProps {
open: boolean;
@@ -12,10 +12,10 @@ const Modal = ({ open, title, onClose, children, footer }: ModalProps) => {
useEffect(() => {
if (!open) return;
const onKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') onClose();
if (event.key === "Escape") onClose();
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [open, onClose]);
if (!open) return null;
@@ -38,7 +38,9 @@ const Modal = ({ open, title, onClose, children, footer }: ModalProps) => {
) : null}
<div className="px-4 py-4 text-sm text-gray-700">{children}</div>
{footer ? (
<div className="flex justify-end gap-2 border-t border-gray-200 px-4 py-3">{footer}</div>
<div className="flex justify-end gap-2 border-t border-gray-200 px-4 py-3">
{footer}
</div>
) : null}
</div>
</div>

View File

@@ -1,2 +1,2 @@
export { default } from './Modal';
export type { ModalProps } from './Modal';
export { default } from "./Modal";
export type { ModalProps } from "./Modal";

View File

@@ -1,4 +1,4 @@
import { ReactNode } from 'react';
import { ReactNode } from "react";
export interface TableColumn<T> {
key: string;
@@ -14,7 +14,12 @@ export interface TableProps<T> {
emptyMessage?: string;
}
function Table<T>({ columns, data, rowKey, emptyMessage = 'No data' }: TableProps<T>) {
function Table<T>({
columns,
data,
rowKey,
emptyMessage = "No data",
}: TableProps<T>) {
return (
<div className="overflow-x-auto rounded-md border border-gray-200">
<table className="min-w-full divide-y divide-gray-200 text-sm">
@@ -34,7 +39,10 @@ function Table<T>({ columns, data, rowKey, emptyMessage = 'No data' }: TableProp
<tbody className="divide-y divide-gray-100 bg-white">
{data.length === 0 ? (
<tr>
<td colSpan={columns.length} className="px-4 py-6 text-center text-gray-500">
<td
colSpan={columns.length}
className="px-4 py-6 text-center text-gray-500"
>
{emptyMessage}
</td>
</tr>
@@ -45,7 +53,9 @@ function Table<T>({ columns, data, rowKey, emptyMessage = 'No data' }: TableProp
<td key={column.key} className="px-4 py-2 text-gray-900">
{column.render
? column.render(row)
: ((row as unknown as Record<string, ReactNode>)[column.key] ?? '-')}
: ((row as unknown as Record<string, ReactNode>)[
column.key
] ?? "-")}
</td>
))}
</tr>

View File

@@ -1,2 +1,2 @@
export { default } from './Table';
export type { TableProps, TableColumn } from './Table';
export { default } from "./Table";
export type { TableProps, TableColumn } from "./Table";

View File

@@ -1,26 +1,27 @@
export { default as Button } from './components/Button';
export type { ButtonProps, ButtonVariant, ButtonSize } from './components/Button';
export { default as Button } from "./components/Button";
export type {
ButtonProps,
ButtonVariant,
ButtonSize,
} from "./components/Button";
export { default as Table } from './components/Table';
export type { TableProps, TableColumn } from './components/Table';
export { default as Table } from "./components/Table";
export type { TableProps, TableColumn } from "./components/Table";
export { FormField } from './components/Form';
export type { FormFieldProps } from './components/Form';
export { FormField } from "./components/Form";
export type { FormFieldProps } from "./components/Form";
export { default as Modal } from './components/Modal';
export type { ModalProps } from './components/Modal';
export { default as Modal } from "./components/Modal";
export type { ModalProps } from "./components/Modal";
export { default as Badge } from './components/Badge';
export type { BadgeProps, BadgeTone } from './components/Badge';
export { default as Badge } from "./components/Badge";
export type { BadgeProps, BadgeTone } from "./components/Badge";
export {
Sidebar,
DashboardLayout,
} from './components/Layout';
export { Sidebar, DashboardLayout } from "./components/Layout";
export type {
SidebarProps,
SidebarItem,
DashboardLayoutProps,
} from './components/Layout';
} from "./components/Layout";
export * from './theme';
export * from "./theme";

View File

@@ -1,24 +1,24 @@
export const colors = {
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
900: '#1e3a8a',
50: "#eff6ff",
100: "#dbeafe",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
900: "#1e3a8a",
},
neutral: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
400: '#9ca3af',
600: '#4b5563',
900: '#111827',
50: "#f9fafb",
100: "#f3f4f6",
200: "#e5e7eb",
400: "#9ca3af",
600: "#4b5563",
900: "#111827",
},
success: '#16a34a',
warning: '#f59e0b',
danger: '#dc2626',
info: '#0ea5e9',
success: "#16a34a",
warning: "#f59e0b",
danger: "#dc2626",
info: "#0ea5e9",
} as const;
export type Colors = typeof colors;

View File

@@ -1,2 +1,2 @@
export * from './colors';
export * from './typography';
export * from "./colors";
export * from "./typography";

View File

@@ -4,13 +4,13 @@ export const typography = {
mono: '"Fira Code", "Menlo", monospace',
},
fontSize: {
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
'2xl': '1.5rem',
'3xl': '1.875rem',
xs: "0.75rem",
sm: "0.875rem",
base: "1rem",
lg: "1.125rem",
xl: "1.25rem",
"2xl": "1.5rem",
"3xl": "1.875rem",
},
fontWeight: {
regular: 400,