chore: restructure project into backend and frontend folders
- Move all frontend code to frontend/ directory - Add backend/ with Go project structure (cmd, internal, pkg) - Add docker-compose.yml for orchestration
This commit is contained in:
39
frontend/src/components/ui/Button.tsx
Normal file
39
frontend/src/components/ui/Button.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
|
||||
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: 'primary' | 'secondary' | 'tertiary' | 'ghost';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const Button = ({
|
||||
variant = 'primary',
|
||||
size = 'md',
|
||||
children,
|
||||
className = '',
|
||||
...props
|
||||
}: ButtonProps) => {
|
||||
const baseStyles = 'inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
|
||||
|
||||
const variants = {
|
||||
primary: 'bg-[#1B263B] text-white hover:bg-[#2a3a52] focus:ring-[#1B263B]',
|
||||
secondary: 'bg-[#f0edef] text-[#1b1b1d] hover:bg-[#e4e2e4] focus:ring-[#75777d]',
|
||||
tertiary: 'bg-[#F28C28] text-white hover:bg-[#d97a1f] focus:ring-[#F28C28]',
|
||||
ghost: 'bg-transparent text-[#1b1b1d] hover:bg-[#f5f3f5] focus:ring-[#75777d]',
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
sm: 'px-3 py-1.5 text-sm',
|
||||
md: 'px-4 py-2 text-base',
|
||||
lg: 'px-6 py-3 text-lg',
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
22
frontend/src/components/ui/Card.tsx
Normal file
22
frontend/src/components/ui/Card.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface CardProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg';
|
||||
}
|
||||
|
||||
export const Card = ({ children, className = '', padding = 'md' }: CardProps) => {
|
||||
const paddings = {
|
||||
none: '',
|
||||
sm: 'p-3',
|
||||
md: 'p-4',
|
||||
lg: 'p-6',
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`bg-white rounded-lg shadow-sm border border-[#e4e2e4] ${paddings[padding]} ${className}`}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
25
frontend/src/components/ui/Input.tsx
Normal file
25
frontend/src/components/ui/Input.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { InputHTMLAttributes } from 'react';
|
||||
|
||||
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
||||
label?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const Input = ({ label, error, className = '', ...props }: InputProps) => {
|
||||
return (
|
||||
<div className="w-full">
|
||||
{label && (
|
||||
<label className="block text-sm font-medium text-[#1b1b1d] mb-1">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<input
|
||||
className={`w-full px-3 py-2 bg-[#f5f3f5] border border-[#c5c6cd] rounded-md text-[#1b1b1d] placeholder-[#75777d] focus:outline-none focus:ring-2 focus:ring-[#1B263B] focus:border-transparent transition-colors ${className}`}
|
||||
{...props}
|
||||
/>
|
||||
{error && (
|
||||
<p className="mt-1 text-sm text-red-600">{error}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
44
frontend/src/components/ui/Modal.tsx
Normal file
44
frontend/src/components/ui/Modal.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { X } from 'lucide-react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface ModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
children: ReactNode;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
|
||||
export const Modal = ({ isOpen, onClose, title, children, footer }: ModalProps) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<div
|
||||
className="fixed inset-0 bg-black/30 transition-opacity"
|
||||
onClick={onClose}
|
||||
/>
|
||||
<div className="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all w-full max-w-lg">
|
||||
<div className="flex items-center justify-between border-b border-[#e4e2e4] px-4 py-3">
|
||||
<h3 className="text-lg font-semibold text-[#1b1b1d]">{title}</h3>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="rounded-full p-1 hover:bg-[#f5f3f5] transition-colors"
|
||||
>
|
||||
<X size={20} className="text-[#75777d]" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="px-4 py-4">
|
||||
{children}
|
||||
</div>
|
||||
{footer && (
|
||||
<div className="border-t border-[#e4e2e4] px-4 py-3 flex justify-end gap-2">
|
||||
{footer}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
37
frontend/src/components/ui/Select.tsx
Normal file
37
frontend/src/components/ui/Select.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { SelectHTMLAttributes } from 'react';
|
||||
|
||||
interface SelectOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
||||
label?: string;
|
||||
options: SelectOption[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const Select = ({ label, options, error, className = '', ...props }: SelectProps) => {
|
||||
return (
|
||||
<div className="w-full">
|
||||
{label && (
|
||||
<label className="block text-sm font-medium text-[#1b1b1d] mb-1">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<select
|
||||
className={`w-full px-3 py-2 bg-[#f5f3f5] border border-[#c5c6cd] rounded-md text-[#1b1b1d] focus:outline-none focus:ring-2 focus:ring-[#1B263B] focus:border-transparent transition-colors ${className}`}
|
||||
{...props}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{error && (
|
||||
<p className="mt-1 text-sm text-red-600">{error}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
5
frontend/src/components/ui/index.ts
Normal file
5
frontend/src/components/ui/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export { Button } from './Button';
|
||||
export { Card } from './Card';
|
||||
export { Modal } from './Modal';
|
||||
export { Input } from './Input';
|
||||
export { Select } from './Select';
|
||||
Reference in New Issue
Block a user