From 2aa8e51b8050498dcec2f2ce6804f67a56971335 Mon Sep 17 00:00:00 2001 From: Anthony GAEREMYNCK <1@anthony.sh> Date: Fri, 31 Jul 2026 14:57:46 +0200 Subject: [PATCH] feat(frontend): add reassurance strip and supported-formats section Part of the Ombrora Convert redesign (Task 3/5). --- frontend/src/components/FormatsGrid.jsx | 19 +++++ frontend/src/components/ReassuranceStrip.jsx | 26 +++++++ frontend/src/data/formats.js | 18 +++++ frontend/src/pages/HomePage.jsx | 76 +++++++++++--------- frontend/src/styles/sections.css | 65 +++++++++++++++++ 5 files changed, 170 insertions(+), 34 deletions(-) create mode 100644 frontend/src/components/FormatsGrid.jsx create mode 100644 frontend/src/components/ReassuranceStrip.jsx create mode 100644 frontend/src/data/formats.js create mode 100644 frontend/src/styles/sections.css diff --git a/frontend/src/components/FormatsGrid.jsx b/frontend/src/components/FormatsGrid.jsx new file mode 100644 index 0000000..f52e017 --- /dev/null +++ b/frontend/src/components/FormatsGrid.jsx @@ -0,0 +1,19 @@ +import { useTranslation } from 'react-i18next'; +import { FORMAT_FAMILIES } from '../data/formats.js'; + +export function FormatsGrid() { + const { t } = useTranslation(); + return ( + + {t('formats.title')} + + {FORMAT_FAMILIES.map(({ key, formats }) => ( + + {t(`formats.${key}`)} + {formats.join(', ').toUpperCase()} + + ))} + + + ); +} diff --git a/frontend/src/components/ReassuranceStrip.jsx b/frontend/src/components/ReassuranceStrip.jsx new file mode 100644 index 0000000..6fccc4d --- /dev/null +++ b/frontend/src/components/ReassuranceStrip.jsx @@ -0,0 +1,26 @@ +import { useTranslation } from 'react-i18next'; +import { Clock, LockKey, CloudArrowUp, HardDrives } from '@phosphor-icons/react'; + +const ITEMS = [ + { key: 'autoDelete', Icon: Clock }, + { key: 'noAccount', Icon: LockKey }, + { key: 'online', Icon: CloudArrowUp }, + { key: 'maxSize', Icon: HardDrives }, +]; + +export function ReassuranceStrip() { + const { t } = useTranslation(); + return ( + + {t('reassurance.title')} + + {ITEMS.map(({ key, Icon }) => ( + + + {t(`reassurance.${key}`)} + + ))} + + + ); +} diff --git a/frontend/src/data/formats.js b/frontend/src/data/formats.js new file mode 100644 index 0000000..747f8b9 --- /dev/null +++ b/frontend/src/data/formats.js @@ -0,0 +1,18 @@ +export const FORMAT_FAMILIES = [ + { + key: 'images', + formats: ['jpg', 'jpeg', 'png', 'webp', 'gif', 'tiff', 'avif', 'heic', 'heif', 'ico'], + }, + { + key: 'documents', + formats: ['docx', 'txt', 'html', 'md', 'pdf', 'csv', 'xlsx'], + }, + { + key: 'fonts', + formats: ['ttf', 'otf', 'woff', 'dfont'], + }, + { + key: 'ebooks', + formats: ['epub', 'fb2', 'lrf', 'mobi', 'pdb', 'rb', 'snb', 'tcr', 'azw3', 'pdf'], + }, +]; diff --git a/frontend/src/pages/HomePage.jsx b/frontend/src/pages/HomePage.jsx index f935dfd..40102c8 100644 --- a/frontend/src/pages/HomePage.jsx +++ b/frontend/src/pages/HomePage.jsx @@ -4,7 +4,10 @@ import { fetchFormats, uploadFiles } from '../api.js'; import { FileCard } from '../FileCard.jsx'; import { Dropzone } from '../components/Dropzone.jsx'; import { FileConfigCard } from '../components/FileConfigCard.jsx'; +import { ReassuranceStrip } from '../components/ReassuranceStrip.jsx'; +import { FormatsGrid } from '../components/FormatsGrid.jsx'; import '../styles/home.css'; +import '../styles/sections.css'; const DEFAULT_QUALITY = { jpg: 80, @@ -79,41 +82,46 @@ export function HomePage() { } return ( - - {t('hero.title')} - {t('hero.subtitle')} - + <> + + {t('hero.title')} + {t('hero.subtitle')} + - {pendingFiles.length > 0 && ( - - - {pendingFiles.map((item, index) => ( - - ))} - - - {t('hero.convert')} - - - )} - - - {submittedJobs.map((job, index) => - job.id ? ( - - ) : ( - - ) + {pendingFiles.length > 0 && ( + + + {pendingFiles.map((item, index) => ( + + ))} + + + {t('hero.convert')} + + )} - - + + + {submittedJobs.map((job, index) => + job.id ? ( + + ) : ( + + ) + )} + + + + + + > ); } diff --git a/frontend/src/styles/sections.css b/frontend/src/styles/sections.css new file mode 100644 index 0000000..b0c346d --- /dev/null +++ b/frontend/src/styles/sections.css @@ -0,0 +1,65 @@ +.reassurance, +.formats-grid-section { + max-width: 960px; + margin: 0 auto; + padding: 2.5rem 1.5rem; + text-align: center; +} + +.reassurance-list { + list-style: none; + padding: 0; + margin: 1.5rem 0 0; + display: grid; + grid-template-columns: 1fr; + gap: 1rem; +} + +.reassurance-list li { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 1rem; + border: 1px solid var(--color-border); + border-radius: 8px; + text-align: left; +} + +.formats-grid { + display: grid; + grid-template-columns: 1fr; + gap: 1rem; + margin-top: 1.5rem; +} + +.formats-family { + padding: 1rem; + border: 1px solid var(--color-border); + border-radius: 8px; + text-align: left; +} + +.formats-family h3 { + margin: 0 0 0.5rem; +} + +.formats-family p { + margin: 0; + opacity: 0.8; + font-size: 0.875rem; +} + +@media (min-width: 768px) { + .reassurance-list { + grid-template-columns: repeat(2, 1fr); + } + .formats-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .formats-grid { + grid-template-columns: repeat(4, 1fr); + } +}
{formats.join(', ').toUpperCase()}
{t('hero.subtitle')}