Add foundational components and logic for migration, UI design, and input handling
- Introduced foundational UI components (`Badge`, `LockCard`, `SectionHeader`, `AvatarIcon`, etc.) for flexible layouts and consistent design. - Added migration support with the `MigrationModal` component and backend integration for exporting/importing data between Electron and Tauri. - Extended form components with `TextAreaInput`, `OrderInput`, `ToggleField`, and `ToolbarSelect` for improved input handling. - Updated `ScribeShell` with migration popup logic to prompt users for data migration. - Integrated `AlertStack` for better alert handling and notification management. - Enhanced Rust/Tauri services with migration command implementations. - Added translations and styles for new components.
This commit is contained in:
84
components/form/TextAreaInput.tsx
Normal file
84
components/form/TextAreaInput.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import React, {ChangeEvent, useEffect, useRef} from "react";
|
||||
|
||||
interface TextAreaInputProps {
|
||||
value: string;
|
||||
setValue: (e: ChangeEvent<HTMLTextAreaElement>) => void;
|
||||
placeholder: string;
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
export default function TextAreaInput(
|
||||
{
|
||||
value,
|
||||
setValue,
|
||||
placeholder,
|
||||
maxLength
|
||||
}: TextAreaInputProps) {
|
||||
const progressRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (progressRef.current && maxLength) {
|
||||
progressRef.current.style.width = `${getProgressPercentage()}%`;
|
||||
}
|
||||
});
|
||||
|
||||
function getProgressPercentage(): number {
|
||||
if (!maxLength) return 0;
|
||||
return Math.min((value.length / maxLength) * 100, 100);
|
||||
}
|
||||
|
||||
function getStatusStyles(): { textColor: string; progressColor: string } | Record<string, never> {
|
||||
if (!maxLength) return {};
|
||||
const percentage = getProgressPercentage();
|
||||
|
||||
if (percentage >= 100) return {
|
||||
textColor: 'text-error',
|
||||
progressColor: 'bg-error'
|
||||
};
|
||||
|
||||
if (percentage >= 75) return {
|
||||
textColor: 'text-warning',
|
||||
progressColor: 'bg-warning'
|
||||
};
|
||||
|
||||
return {
|
||||
textColor: 'text-muted',
|
||||
progressColor: 'bg-primary'
|
||||
};
|
||||
}
|
||||
|
||||
const styles = getStatusStyles();
|
||||
|
||||
return (
|
||||
<div className="flex-grow flex-col flex h-full">
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
placeholder={placeholder}
|
||||
rows={3}
|
||||
className={`input-base w-full flex-grow p-3 lg:p-4 resize-none ${
|
||||
maxLength && value.length >= maxLength
|
||||
? 'border-error'
|
||||
: ''
|
||||
} h-full min-h-[200px]`}
|
||||
/>
|
||||
|
||||
{maxLength && (
|
||||
<div className="flex items-center justify-end gap-3 mt-3">
|
||||
{/* Compteur avec effet de croissance */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-24 h-1.5 bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
ref={progressRef}
|
||||
className={`h-full rounded-full transition-all duration-500 ease-out ${styles.progressColor}`}
|
||||
></div>
|
||||
</div>
|
||||
<span className={`text-xs font-medium ${styles.textColor}`}>
|
||||
{value.length}/{maxLength}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user