Nicolas Cantu d3cae85b3d Update presentation page to dark theme and add language selector
- Update /presentation page to use dark theme (PageHeader, Footer, bg-cyber-darker)
- Add LanguageSelector component to PageHeader for all pages
- Update AuthorPresentationEditor to use dark theme styling
- Update ArticleField and ArticleFormButtons to use dark theme
- Add locale persistence in localStorage
- Update _app.tsx to load saved locale from localStorage
- All pages now support FR/EN language switching
2025-12-27 23:17:50 +01:00

125 lines
2.7 KiB
TypeScript

import React from 'react'
interface ArticleFieldProps {
id: string
label: string
value: string | number
onChange: (value: string | number) => void
required?: boolean
type?: 'text' | 'textarea' | 'number'
rows?: number
placeholder?: string
helpText?: string
min?: number
}
function NumberOrTextInput({
id,
type,
value,
placeholder,
required,
min,
onChange,
className,
}: {
id: string
type: 'text' | 'number'
value: string | number
placeholder?: string
required: boolean
min?: number
className: string
onChange: (value: string | number) => void
}) {
const inputProps = {
id,
type,
value,
className,
required,
...(placeholder ? { placeholder } : {}),
...(typeof min === 'number' ? { min } : {}),
}
return (
<input
{...inputProps}
onChange={(e) => onChange(type === 'number' ? Number(e.target.value) || 0 : e.target.value)}
/>
)
}
function TextAreaInput({
id,
value,
placeholder,
required,
rows,
className,
onChange,
}: {
id: string
value: string | number
placeholder?: string
required: boolean
rows?: number
className: string
onChange: (value: string | number) => void
}) {
const areaProps = {
id,
value,
className,
required,
...(placeholder ? { placeholder } : {}),
...(rows ? { rows } : {}),
}
return (
<textarea
{...areaProps}
onChange={(e) => onChange(e.target.value)}
/>
)
}
export function ArticleField(props: ArticleFieldProps) {
const { id, label, value, onChange, required = false, type = 'text', rows, placeholder, helpText, min } =
props
const inputClass =
'w-full px-3 py-2 bg-cyber-darker border border-neon-cyan/20 rounded-lg text-cyber-accent placeholder-cyber-accent/50 focus:ring-2 focus:ring-neon-cyan/50 focus:border-neon-cyan/50 focus:outline-none transition-colors'
const input =
type === 'textarea' ? (
<TextAreaInput
id={id}
value={value}
required={required}
className={inputClass}
onChange={onChange}
{...(placeholder ? { placeholder } : {})}
{...(rows ? { rows } : {})}
/>
) : (
<NumberOrTextInput
id={id}
type={type}
value={value}
required={required}
className={inputClass}
onChange={onChange}
{...(placeholder ? { placeholder } : {})}
{...(typeof min === 'number' ? { min } : {})}
/>
)
return (
<div>
<label htmlFor={id} className="block text-sm font-medium text-cyber-accent mb-1">
{label} {required && <span className="text-neon-cyan">*</span>}
</label>
{input}
{helpText && <p className="text-xs text-cyber-accent/70 mt-1">{helpText}</p>}
</div>
)
}