sync current state

This commit is contained in:
2026-03-01 11:44:23 +01:00
parent e7c5d0c218
commit 217dc4ba5e
66 changed files with 3179 additions and 3885 deletions
+21
View File
@@ -0,0 +1,21 @@
import type React from 'react';
import { cn } from '~/shared/lib/utils';
const variants = {
info: 'bg-cyan-50 text-cyan-800 border border-cyan-200',
warning: 'bg-amber-50 text-amber-800 border border-amber-200',
error: 'bg-red-50 text-red-800 border border-red-200',
success: 'bg-green-50 text-green-800 border border-green-200',
} as const;
interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: keyof typeof variants;
}
export function Alert({ variant = 'info', className, children, ...props }: AlertProps) {
return (
<div className={cn('p-3 rounded text-sm', variants[variant], className)} {...props}>
{children}
</div>
);
}
+36
View File
@@ -0,0 +1,36 @@
import { cn } from '~/shared/lib/utils';
const variants = {
default: 'bg-gray-100 text-gray-600',
keep: 'bg-green-100 text-green-800',
remove: 'bg-red-100 text-red-800',
pending: 'bg-gray-200 text-gray-600',
approved: 'bg-green-100 text-green-800',
skipped: 'bg-gray-200 text-gray-600',
done: 'bg-cyan-100 text-cyan-800',
error: 'bg-red-100 text-red-800',
noop: 'bg-gray-200 text-gray-600',
running: 'bg-amber-100 text-amber-800',
manual: 'bg-orange-100 text-orange-800',
} as const;
interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
variant?: keyof typeof variants;
}
export function Badge({ variant = 'default', className, children, ...props }: BadgeProps) {
return (
<span
className={cn(
'inline-block text-[0.67rem] font-semibold px-[0.45em] py-[0.1em] rounded-full uppercase tracking-[0.03em] whitespace-nowrap',
variants[variant],
className,
)}
{...props}
>
{children}
</span>
);
}
import type React from 'react';
+26
View File
@@ -0,0 +1,26 @@
import type React from 'react';
import { cn } from '~/shared/lib/utils';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'default' | 'sm' | 'xs';
}
export function Button({ variant = 'primary', size = 'default', className, ...props }: ButtonProps) {
return (
<button
className={cn(
'inline-flex items-center justify-center gap-1 rounded font-medium cursor-pointer transition-colors border-0',
variant === 'primary' && 'bg-blue-600 text-white hover:bg-blue-700',
variant === 'secondary' && 'bg-white text-gray-700 border border-gray-300 hover:bg-gray-50',
variant === 'danger' && 'bg-white text-red-600 border border-red-400 hover:bg-red-50',
size === 'default' && 'px-3 py-1.5 text-sm',
size === 'sm' && 'px-2.5 py-1 text-xs',
size === 'xs' && 'px-2 py-0.5 text-xs',
props.disabled && 'opacity-50 cursor-not-allowed',
className,
)}
{...props}
/>
);
}
+16
View File
@@ -0,0 +1,16 @@
import type React from 'react';
import { cn } from '~/shared/lib/utils';
export function Input({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) {
return (
<input
className={cn(
'border border-gray-300 rounded px-2.5 py-1.5 text-sm bg-white w-full',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
'disabled:bg-gray-100 disabled:text-gray-400 disabled:cursor-not-allowed',
className,
)}
{...props}
/>
);
}
+16
View File
@@ -0,0 +1,16 @@
import type React from 'react';
import { cn } from '~/shared/lib/utils';
export function Select({ className, ...props }: React.SelectHTMLAttributes<HTMLSelectElement>) {
return (
<select
className={cn(
'border border-gray-300 rounded px-2 py-1.5 text-sm bg-white',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
'disabled:bg-gray-100 disabled:cursor-not-allowed',
className,
)}
{...props}
/>
);
}
+15
View File
@@ -0,0 +1,15 @@
import type React from 'react';
import { cn } from '~/shared/lib/utils';
export function Textarea({ className, ...props }: React.TextareaHTMLAttributes<HTMLTextAreaElement>) {
return (
<textarea
className={cn(
'border border-gray-300 rounded px-2.5 py-1.5 text-sm bg-white w-full resize-vertical',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
className,
)}
{...props}
/>
);
}