mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix: mobile/responsive issues in FAQ and info pages
- FAQ builder: touch targets 36px → 44px (move up/down/delete buttons) - Filter tabs: add flex-wrap to prevent overflow on narrow screens - Accordion: add ResizeObserver for dynamic content height (images loading, viewport rotation won't clip content anymore) - Accordion: use stable key (index+question) instead of filtered array index — search+toggle no longer opens wrong item
This commit is contained in:
@@ -325,7 +325,7 @@ function FaqBuilder({ items, onChange, locale, localeLabel }: FaqBuilderProps) {
|
||||
type="button"
|
||||
onClick={() => handleMoveUp(index)}
|
||||
disabled={index === 0}
|
||||
className="min-h-[36px] min-w-[36px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
||||
className="min-h-[44px] min-w-[44px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
||||
title={t('admin.infoPages.faq.moveUp')}
|
||||
>
|
||||
<ChevronUpIcon />
|
||||
@@ -334,7 +334,7 @@ function FaqBuilder({ items, onChange, locale, localeLabel }: FaqBuilderProps) {
|
||||
type="button"
|
||||
onClick={() => handleMoveDown(index)}
|
||||
disabled={index >= items.length - 1}
|
||||
className="min-h-[36px] min-w-[36px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
||||
className="min-h-[44px] min-w-[44px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-dark-700 hover:text-dark-200 disabled:cursor-not-allowed disabled:opacity-30"
|
||||
title={t('admin.infoPages.faq.moveDown')}
|
||||
>
|
||||
<ChevronDownIcon />
|
||||
@@ -342,7 +342,7 @@ function FaqBuilder({ items, onChange, locale, localeLabel }: FaqBuilderProps) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemove(index)}
|
||||
className="min-h-[36px] min-w-[36px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-error-500/10 hover:text-error-400"
|
||||
className="min-h-[44px] min-w-[44px] rounded-lg p-2 text-dark-400 transition-colors hover:bg-error-500/10 hover:text-error-400"
|
||||
title={t('admin.infoPages.faq.removeQuestion')}
|
||||
>
|
||||
<TrashSmallIcon />
|
||||
|
||||
@@ -324,7 +324,7 @@ export default function AdminInfoPages() {
|
||||
</div>
|
||||
|
||||
{/* Filter tabs */}
|
||||
<div className="flex gap-1">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{(['all', 'page', 'faq'] as const).map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
|
||||
@@ -216,6 +216,16 @@ function FaqAccordionItem({
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
// Update height when content resizes (images loading, viewport rotation)
|
||||
useEffect(() => {
|
||||
if (!isOpen || !contentRef.current) return;
|
||||
const observer = new ResizeObserver(() => {
|
||||
if (contentRef.current) setHeight(contentRef.current.scrollHeight);
|
||||
});
|
||||
observer.observe(contentRef.current);
|
||||
return () => observer.disconnect();
|
||||
}, [isOpen]);
|
||||
|
||||
const sanitizedAnswer = useMemo(() => sanitizeHtml(item.a), [item.a]);
|
||||
|
||||
return (
|
||||
@@ -246,15 +256,12 @@ function FaqAccordionItem({
|
||||
|
||||
function FaqView({ items }: { items: FaqItem[] }) {
|
||||
const { t } = useTranslation();
|
||||
const [openIndex, setOpenIndex] = useState<number | null>(null);
|
||||
const [openKey, setOpenKey] = useState<string | null>(null);
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const handleToggle = useCallback(
|
||||
(index: number) => {
|
||||
setOpenIndex(openIndex === index ? null : index);
|
||||
},
|
||||
[openIndex],
|
||||
);
|
||||
const handleToggle = useCallback((key: string) => {
|
||||
setOpenKey((prev) => (prev === key ? null : key));
|
||||
}, []);
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
if (!search.trim()) return items;
|
||||
@@ -275,7 +282,7 @@ function FaqView({ items }: { items: FaqItem[] }) {
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
setSearch(e.target.value);
|
||||
setOpenIndex(null);
|
||||
setOpenKey(null);
|
||||
}}
|
||||
placeholder={t('admin.infoPages.faq.searchPlaceholder')}
|
||||
className="input pl-9 text-sm"
|
||||
@@ -290,14 +297,17 @@ function FaqView({ items }: { items: FaqItem[] }) {
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{filteredItems.map((item, index) => (
|
||||
<FaqAccordionItem
|
||||
key={index}
|
||||
item={item}
|
||||
isOpen={openIndex === index}
|
||||
onToggle={() => handleToggle(index)}
|
||||
/>
|
||||
))}
|
||||
{filteredItems.map((item, index) => {
|
||||
const key = `${index}-${item.q.slice(0, 50)}`;
|
||||
return (
|
||||
<FaqAccordionItem
|
||||
key={key}
|
||||
item={item}
|
||||
isOpen={openKey === key}
|
||||
onToggle={() => handleToggle(key)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user