Remove unused components and models for improved maintainability
- Deleted redundant components (`AddActionButton`, `AlertBox`, `AlertStack`, `BackButton`, `CancelButton`, and `CollapsableArea`) and related files. - Removed unused models (`Book`, `BookSerie`, `BookTables`, `Character`, and `Chapter`) to reduce codebase clutter. - Updated project structure and references to reflect these removals.
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
'use client'
|
||||
import {ChangeEvent, useCallback, useEffect, useMemo} from 'react';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faEye, faFont, faIndent, faPalette, faTextHeight, faTextWidth} from '@fortawesome/free-solid-svg-icons';
|
||||
import {useTranslations} from "next-intl";
|
||||
import React, {ChangeEvent, useCallback, useContext, useEffect, useMemo} from 'react';
|
||||
import {Baseline, CaseSensitive, Eye, Indent, Palette, Type} from 'lucide-react';
|
||||
import {useTranslations} from '@/lib/i18n';
|
||||
import SelectBox from "@/components/form/SelectBox";
|
||||
import Button from "@/components/ui/Button";
|
||||
import {AlertContext, AlertContextProps} from "@/context/AlertContext";
|
||||
|
||||
interface UserEditorSettingsProps {
|
||||
settings: EditorDisplaySettings;
|
||||
@@ -20,11 +21,15 @@ export interface EditorDisplaySettings {
|
||||
focusMode: boolean;
|
||||
}
|
||||
|
||||
const ZOOM_LABELS = ['Très petit', 'Petit', 'Normal', 'Grand', 'Très grand'] as const;
|
||||
const FONT_SIZES = [14, 16, 18, 20, 22] as const;
|
||||
const THEMES = ['clair', 'sombre', 'sépia'] as const;
|
||||
const zoomLabels = ['Très petit', 'Petit', 'Normal', 'Grand', 'Très grand'] as const;
|
||||
const fontSizes = [14, 16, 18, 20, 22] as const;
|
||||
const themes = ['clair', 'sombre', 'sépia'] as const;
|
||||
|
||||
const DEFAULT_SETTINGS: EditorDisplaySettings = {
|
||||
function isValidFontFamily(value: string): value is EditorDisplaySettings['fontFamily'] {
|
||||
return value === 'lora' || value === 'serif' || value === 'sans-serif' || value === 'monospace';
|
||||
}
|
||||
|
||||
const defaultSettings: EditorDisplaySettings = {
|
||||
zoomLevel: 3,
|
||||
indent: 30,
|
||||
lineHeight: 1.5,
|
||||
@@ -34,82 +39,91 @@ const DEFAULT_SETTINGS: EditorDisplaySettings = {
|
||||
focusMode: false
|
||||
};
|
||||
|
||||
export default function UserEditorSettings({settings, onSettingsChange}: UserEditorSettingsProps) {
|
||||
export default function UserEditorSettings({settings, onSettingsChange}: UserEditorSettingsProps): React.JSX.Element {
|
||||
const t = useTranslations();
|
||||
|
||||
const {errorMessage}: AlertContextProps = useContext<AlertContextProps>(AlertContext);
|
||||
|
||||
const handleSettingChange = useCallback(<K extends keyof EditorDisplaySettings>(
|
||||
key: K,
|
||||
value: EditorDisplaySettings[K]
|
||||
) => {
|
||||
): void => {
|
||||
onSettingsChange({...settings, [key]: value});
|
||||
}, [settings, onSettingsChange]);
|
||||
|
||||
const resetToDefaults = useCallback(() => {
|
||||
onSettingsChange(DEFAULT_SETTINGS);
|
||||
const resetToDefaults = useCallback((): void => {
|
||||
onSettingsChange(defaultSettings);
|
||||
}, [onSettingsChange]);
|
||||
|
||||
const zoomOptions = useMemo(() =>
|
||||
ZOOM_LABELS.map((label, index) => ({
|
||||
const zoomOptions = useMemo((): { value: string; label: string }[] =>
|
||||
zoomLabels.map((label: typeof zoomLabels[number], index: number): { value: string; label: string } => ({
|
||||
value: (index + 1).toString(),
|
||||
label: `${t(`userEditorSettings.zoom.${label}`)} (${FONT_SIZES[index]}px)`
|
||||
label: `${t(`userEditorSettings.zoom.${label}`)} (${fontSizes[index]}px)`
|
||||
}))
|
||||
, [t]);
|
||||
|
||||
const themeButtons = useMemo(() =>
|
||||
THEMES.map(theme => ({
|
||||
const themeButtons = useMemo((): { key: typeof themes[number]; isActive: boolean; className: string }[] =>
|
||||
themes.map((theme: typeof themes[number]): {
|
||||
key: typeof themes[number];
|
||||
isActive: boolean;
|
||||
className: string
|
||||
} => ({
|
||||
key: theme,
|
||||
isActive: settings.theme === theme,
|
||||
className: `p-2.5 rounded-xl border capitalize transition-all duration-200 font-medium ${
|
||||
className: `p-2.5 rounded-xl border capitalize transition-colors duration-150 font-medium ${
|
||||
settings.theme === theme
|
||||
? 'bg-primary text-text-primary border-primary shadow-md scale-105'
|
||||
: 'bg-secondary/50 border-secondary/50 text-muted hover:text-text-primary hover:border-secondary hover:bg-secondary hover:scale-102'
|
||||
? 'bg-secondary text-primary border-primary'
|
||||
: 'bg-secondary border-secondary text-muted hover:text-text-primary'
|
||||
}`
|
||||
}))
|
||||
, [settings.theme]);
|
||||
|
||||
|
||||
useEffect((): void => {
|
||||
try {
|
||||
const savedSettings: string | null = localStorage.getItem('userEditorSettings');
|
||||
if (savedSettings) {
|
||||
const parsed = JSON.parse(savedSettings);
|
||||
const parsed: Partial<EditorDisplaySettings> = JSON.parse(savedSettings);
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
onSettingsChange({...DEFAULT_SETTINGS, ...parsed});
|
||||
onSettingsChange({...defaultSettings, ...parsed});
|
||||
}
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
onSettingsChange(DEFAULT_SETTINGS);
|
||||
onSettingsChange(defaultSettings);
|
||||
}
|
||||
}, [onSettingsChange]);
|
||||
|
||||
|
||||
useEffect((): () => void => {
|
||||
const timeoutId = setTimeout((): void => {
|
||||
const timeoutId: ReturnType<typeof setTimeout> = setTimeout((): void => {
|
||||
try {
|
||||
localStorage.setItem('userEditorSettings', JSON.stringify(settings));
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la sauvegarde des settings:', error);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(t('userEditorSettings.saveError'));
|
||||
} else {
|
||||
errorMessage(t('userEditorSettings.unknownError'));
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
|
||||
|
||||
return (): void => clearTimeout(timeoutId);
|
||||
}, [settings]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="p-5 bg-secondary/30 backdrop-blur-sm border-l border-secondary/50 h-full overflow-y-auto shadow-inner">
|
||||
<div className="flex items-center gap-3 mb-8 pb-4 border-b border-secondary/50">
|
||||
<FontAwesomeIcon icon={faEye} className="text-primary w-6 h-6"/>
|
||||
className="p-5 h-full overflow-y-auto">
|
||||
<div className="flex items-center gap-3 mb-8 pb-4 border-b border-secondary">
|
||||
<Eye className="text-primary w-6 h-6" strokeWidth={1.75}/>
|
||||
<h3 className="text-xl font-['ADLaM_Display'] text-text-primary">{t("userEditorSettings.displayPreferences")}</h3>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-2 text-text-primary">
|
||||
<FontAwesomeIcon icon={faTextHeight} className="text-muted w-5 h-5"/>
|
||||
<CaseSensitive className="text-muted w-5 h-5" strokeWidth={1.75}/>
|
||||
{t("userEditorSettings.textSize")}
|
||||
</label>
|
||||
<SelectBox
|
||||
defaultValue={settings.zoomLevel.toString()}
|
||||
onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>) => {
|
||||
onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => {
|
||||
handleSettingChange('zoomLevel', Number(e.target.value))
|
||||
}}
|
||||
data={zoomOptions}
|
||||
@@ -118,7 +132,7 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-2 text-text-primary">
|
||||
<FontAwesomeIcon icon={faIndent} className="text-muted w-5 h-5"/>
|
||||
<Indent className="text-muted w-5 h-5" strokeWidth={1.75}/>
|
||||
{t("userEditorSettings.indent")}
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
@@ -128,7 +142,7 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
max={50}
|
||||
step={5}
|
||||
value={settings.indent}
|
||||
onChange={(e) => handleSettingChange('indent', Number(e.target.value))}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>): void => handleSettingChange('indent', Number(e.target.value))}
|
||||
className="w-full accent-primary"
|
||||
/>
|
||||
<div className="flex justify-between text-sm text-muted">
|
||||
@@ -141,12 +155,12 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-2 text-text-primary">
|
||||
<FontAwesomeIcon icon={faTextWidth} className="text-muted w-5 h-5"/>
|
||||
<Baseline className="text-muted w-5 h-5" strokeWidth={1.75}/>
|
||||
{t("userEditorSettings.lineHeight")}
|
||||
</label>
|
||||
<SelectBox
|
||||
defaultValue={settings.lineHeight.toString()}
|
||||
onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>) => handleSettingChange('lineHeight', Number(e.target.value))}
|
||||
onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => handleSettingChange('lineHeight', Number(e.target.value))}
|
||||
data={[
|
||||
{value: "1.2", label: t("userEditorSettings.lineHeightCompact")},
|
||||
{value: "1.5", label: t("userEditorSettings.lineHeightNormal")},
|
||||
@@ -158,12 +172,17 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-2 text-text-primary">
|
||||
<FontAwesomeIcon icon={faFont} className="text-muted w-5 h-5"/>
|
||||
<Type className="text-muted w-5 h-5" strokeWidth={1.75}/>
|
||||
{t("userEditorSettings.fontFamily")}
|
||||
</label>
|
||||
<SelectBox
|
||||
defaultValue={settings.fontFamily}
|
||||
onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>) => handleSettingChange('fontFamily', e.target.value as EditorDisplaySettings['fontFamily'])}
|
||||
onChangeCallBack={(e: ChangeEvent<HTMLSelectElement>): void => {
|
||||
const fontValue: string = e.target.value;
|
||||
if (isValidFontFamily(fontValue)) {
|
||||
handleSettingChange('fontFamily', fontValue);
|
||||
}
|
||||
}}
|
||||
data={[
|
||||
{value: "lora", label: t("userEditorSettings.fontLora")},
|
||||
{value: "serif", label: t("userEditorSettings.fontSerif")},
|
||||
@@ -175,7 +194,7 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-2 text-text-primary">
|
||||
<FontAwesomeIcon icon={faTextWidth} className="text-muted w-5 h-5"/>
|
||||
<Baseline className="text-muted w-5 h-5" strokeWidth={1.75}/>
|
||||
{t("userEditorSettings.maxWidth")}
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
@@ -185,7 +204,7 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
max={1200}
|
||||
step={50}
|
||||
value={settings.maxWidth}
|
||||
onChange={(e) => handleSettingChange('maxWidth', Number(e.target.value))}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>): void => handleSettingChange('maxWidth', Number(e.target.value))}
|
||||
className="w-full accent-primary"
|
||||
/>
|
||||
<div className="flex justify-between text-sm text-muted">
|
||||
@@ -198,14 +217,18 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-2 text-text-primary">
|
||||
<FontAwesomeIcon icon={faPalette} className="text-muted w-5 h-5"/>
|
||||
<Palette className="text-muted w-5 h-5" strokeWidth={1.75}/>
|
||||
{t("userEditorSettings.theme")}
|
||||
</label>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{themeButtons.map((themeBtn) => (
|
||||
{themeButtons.map((themeBtn: {
|
||||
key: typeof themes[number];
|
||||
isActive: boolean;
|
||||
className: string
|
||||
}) => (
|
||||
<button
|
||||
key={themeBtn.key}
|
||||
onClick={() => handleSettingChange('theme', themeBtn.key)}
|
||||
onClick={(): void => handleSettingChange('theme', themeBtn.key)}
|
||||
className={themeBtn.className}
|
||||
>
|
||||
{t(`userEditorSettings.themeOption.${themeBtn.key}`)}
|
||||
@@ -219,20 +242,17 @@ export default function UserEditorSettings({settings, onSettingsChange}: UserEdi
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.focusMode}
|
||||
onChange={(e) => handleSettingChange('focusMode', e.target.checked)}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>): void => handleSettingChange('focusMode', e.target.checked)}
|
||||
className="w-4 h-4 accent-primary"
|
||||
/>
|
||||
<span className="text-text-primary">{t("userEditorSettings.focusMode")}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="pt-6 border-t border-secondary/50">
|
||||
<button
|
||||
onClick={resetToDefaults}
|
||||
className="w-full py-2.5 bg-secondary/50 border border-secondary/50 rounded-xl text-muted hover:text-text-primary hover:border-secondary hover:bg-secondary transition-all duration-200 hover:scale-105 shadow-sm hover:shadow-md font-medium"
|
||||
>
|
||||
<div className="pt-6 border-t border-secondary">
|
||||
<Button variant="secondary" onClick={resetToDefaults} fullWidth>
|
||||
{t("userEditorSettings.reset")}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user