FlotillasGPS - Sistema completo de monitoreo de flotillas GPS

Sistema completo para monitoreo y gestion de flotas de vehiculos con:
- Backend FastAPI con PostgreSQL/TimescaleDB
- Frontend React con TypeScript y TailwindCSS
- App movil React Native con Expo
- Soporte para dispositivos GPS, Meshtastic y celulares
- Video streaming en vivo con MediaMTX
- Geocercas, alertas, viajes y reportes
- Autenticacion JWT y WebSockets en tiempo real

Documentacion completa y guias de usuario incluidas.
This commit is contained in:
FlotillasGPS Developer
2026-01-21 08:18:00 +00:00
commit 51d78bacf4
248 changed files with 50171 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
import { forwardRef, InputHTMLAttributes, ReactNode } from 'react'
import clsx from 'clsx'
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string
error?: string
helperText?: string
leftIcon?: ReactNode
rightIcon?: ReactNode
fullWidth?: boolean
}
const Input = forwardRef<HTMLInputElement, InputProps>(
(
{
className,
label,
error,
helperText,
leftIcon,
rightIcon,
fullWidth = true,
type = 'text',
id,
...props
},
ref
) => {
const inputId = id || label?.toLowerCase().replace(/\s+/g, '-')
return (
<div className={clsx(fullWidth && 'w-full')}>
{label && (
<label
htmlFor={inputId}
className="block text-sm font-medium text-slate-300 mb-1.5"
>
{label}
</label>
)}
<div className="relative">
{leftIcon && (
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-slate-400">
{leftIcon}
</div>
)}
<input
ref={ref}
type={type}
id={inputId}
className={clsx(
'w-full px-4 py-2.5 bg-background-800 border rounded-lg',
'text-white placeholder-slate-500',
'focus:outline-none focus:ring-2 focus:border-transparent',
'transition-all duration-200',
error
? 'border-error-500 focus:ring-error-500'
: 'border-slate-700 focus:ring-accent-500',
leftIcon && 'pl-10',
rightIcon && 'pr-10',
className
)}
{...props}
/>
{rightIcon && (
<div className="absolute inset-y-0 right-0 pr-3 flex items-center text-slate-400">
{rightIcon}
</div>
)}
</div>
{error && <p className="mt-1.5 text-sm text-error-500">{error}</p>}
{helperText && !error && (
<p className="mt-1.5 text-sm text-slate-500">{helperText}</p>
)}
</div>
)
}
)
Input.displayName = 'Input'
export default Input
// Textarea component
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
label?: string
error?: string
helperText?: string
fullWidth?: boolean
}
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
(
{ className, label, error, helperText, fullWidth = true, id, ...props },
ref
) => {
const inputId = id || label?.toLowerCase().replace(/\s+/g, '-')
return (
<div className={clsx(fullWidth && 'w-full')}>
{label && (
<label
htmlFor={inputId}
className="block text-sm font-medium text-slate-300 mb-1.5"
>
{label}
</label>
)}
<textarea
ref={ref}
id={inputId}
className={clsx(
'w-full px-4 py-2.5 bg-background-800 border rounded-lg',
'text-white placeholder-slate-500',
'focus:outline-none focus:ring-2 focus:border-transparent',
'transition-all duration-200 resize-none',
error
? 'border-error-500 focus:ring-error-500'
: 'border-slate-700 focus:ring-accent-500',
className
)}
{...props}
/>
{error && <p className="mt-1.5 text-sm text-error-500">{error}</p>}
{helperText && !error && (
<p className="mt-1.5 text-sm text-slate-500">{helperText}</p>
)}
</div>
)
}
)
Textarea.displayName = 'Textarea'