feat: enhance responsive design for glass panel and configurator section

This commit is contained in:
Najjar\NajjarV02 2026-04-17 13:29:44 +04:00
parent 0793a650fb
commit b9444979f2
2 changed files with 164 additions and 14 deletions

View File

@ -200,22 +200,57 @@ html {
@media (max-width: 768px) { @media (max-width: 768px) {
.layout-container { .layout-container {
flex-direction: column !important; flex-direction: column-reverse !important;
height: 100dvh !important;
} }
.glass-panel-responsive { .glass-panel-responsive {
position: fixed !important; order: unset !important;
bottom: 0 !important; position: relative !important;
left: 0 !important; bottom: auto !important;
right: 0 !important; left: auto !important;
right: auto !important;
width: 100% !important; width: 100% !important;
height: 50vh !important; height: 55dvh !important;
border-left: none !important; max-height: 55dvh !important;
border-right: none !important; border-right: none !important;
border-left: none !important;
border-top: 1px solid var(--color-border) !important; border-top: 1px solid var(--color-border) !important;
box-shadow: 0 -4px 40px rgba(0, 0, 0, 0.08) !important; box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.06) !important;
border-radius: 1rem 1rem 0 0 !important; border-radius: 1rem 1rem 0 0 !important;
overflow-y: auto !important;
overflow-x: hidden !important;
z-index: 50; z-index: 50;
padding-bottom: env(safe-area-inset-bottom, 0px) !important;
}
/* Expanded (fullscreen) state overrides */
.glass-panel-responsive.panel-expanded {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100dvh !important;
max-height: 100dvh !important;
border-radius: 0 !important;
border-top: none !important;
box-shadow: none !important;
z-index: 200 !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
padding-bottom: 0 !important;
}
.canvas-area {
height: 45dvh !important;
max-height: 45dvh !important;
min-height: 180px !important;
width: 100% !important;
flex: none !important;
}
#configurator {
height: 100dvh !important;
} }
.mobile-handle { .mobile-handle {
@ -223,6 +258,108 @@ html {
} }
} }
/* Small phones */
@media (max-width: 480px) {
.glass-panel-responsive {
height: 58dvh !important;
max-height: 58dvh !important;
border-radius: 0.75rem 0.75rem 0 0 !important;
}
.canvas-area {
height: 42dvh !important;
max-height: 42dvh !important;
min-height: 160px !important;
}
.glass-panel-responsive header {
padding: 0.75rem 1rem !important;
}
.glass-panel-responsive > div[role="region"] {
padding: 1rem !important;
}
}
/* Very small phones (iPhone SE, etc.) */
@media (max-width: 375px) {
.glass-panel-responsive {
height: 60dvh !important;
max-height: 60dvh !important;
}
.canvas-area {
height: 40dvh !important;
max-height: 40dvh !important;
min-height: 140px !important;
}
}
/* Landscape mobile */
@media (max-height: 500px) and (orientation: landscape) {
.layout-container {
flex-direction: row !important;
}
.glass-panel-responsive {
order: unset !important;
position: relative !important;
width: 320px !important;
min-width: 320px !important;
height: 100% !important;
max-height: 100% !important;
border-radius: 0 !important;
border-top: none !important;
border-left: 1px solid var(--color-border) !important;
overflow-y: auto !important;
}
.canvas-area {
height: 100% !important;
max-height: 100% !important;
width: auto !important;
flex: 1 !important;
}
.mobile-handle {
display: none !important;
}
}
.mobile-handle { .mobile-handle {
display: none; display: none;
} }
/* Hide expand button on desktop */
.panel-expand-btn {
display: none !important;
}
/* Show expand button only on mobile */
@media (max-width: 768px) {
.panel-expand-btn {
display: flex !important;
}
/* Expanded (fullscreen) panel state position handled by React inline styles */
.layout-expanded .canvas-area {
height: 0 !important;
max-height: 0 !important;
min-height: 0 !important;
overflow: hidden !important;
}
}
@media (max-width: 480px) {
.glass-panel-responsive.panel-expanded {
height: 100dvh !important;
max-height: 100dvh !important;
}
}
@media (max-width: 375px) {
.glass-panel-responsive.panel-expanded {
height: 100dvh !important;
max-height: 100dvh !important;
}
}

View File

@ -1,5 +1,6 @@
'use client'; 'use client';
import { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useUrlSync } from '@/hooks/useUrlSync'; import { useUrlSync } from '@/hooks/useUrlSync';
import { RobotCanvas } from '@/components/RobotCanvas'; import { RobotCanvas } from '@/components/RobotCanvas';
@ -10,6 +11,7 @@ import { CheckoutOverlay } from '@/components/CheckoutOverlay';
export function ConfiguratorSection() { export function ConfiguratorSection() {
const { isHydrated } = useUrlSync(); const { isHydrated } = useUrlSync();
const { t } = useTranslation(); const { t } = useTranslation();
const [panelExpanded, setPanelExpanded] = useState(false);
return ( return (
<section <section
@ -23,7 +25,7 @@ export function ConfiguratorSection() {
}} }}
> >
<div <div
className="layout-container" className={`layout-container${panelExpanded ? ' layout-expanded' : ''}`}
style={{ style={{
display: 'flex', display: 'flex',
width: '100%', width: '100%',
@ -32,9 +34,8 @@ export function ConfiguratorSection() {
}} }}
> >
<aside <aside
className="glass-panel-responsive" className={`glass-panel-responsive${panelExpanded ? ' panel-expanded' : ''}`}
style={{ style={{
order: -1,
width: '420px', width: '420px',
height: '100%', height: '100%',
background: 'rgba(255, 255, 255, 0.9)', background: 'rgba(255, 255, 255, 0.9)',
@ -45,28 +46,39 @@ export function ConfiguratorSection() {
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
position: 'relative', position: 'relative',
overflow: 'hidden', overflowX: 'hidden',
overflowY: 'auto',
}} }}
role="complementary" role="complementary"
aria-label={t('panel.title')} aria-label={t('panel.title')}
> >
<div <div
className="mobile-handle" className="mobile-handle"
onClick={() => setPanelExpanded((v) => !v)}
role="button"
tabIndex={0}
aria-label={panelExpanded ? 'Collapse panel' : 'Expand panel'}
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setPanelExpanded((v) => !v); } }}
style={{ style={{
padding: '0.75rem', padding: '0.75rem',
display: 'flex', display: 'flex',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
position: 'relative',
cursor: 'pointer',
userSelect: 'none',
}} }}
aria-hidden="true"
> >
{/* Drag indicator tap to expand/collapse */}
<div <div
style={{ style={{
width: '40px', width: '40px',
height: '4px', height: '4px',
backgroundColor: '#e2e8f0', backgroundColor: '#e2e8f0',
borderRadius: '2px', borderRadius: '2px',
transition: 'width 0.2s, background-color 0.2s',
}} }}
aria-hidden="true"
/> />
</div> </div>
@ -94,7 +106,7 @@ export function ConfiguratorSection() {
style={{ style={{
flex: 1, flex: 1,
padding: '1.5rem', padding: '1.5rem',
overflowY: 'auto', overflowY: 'visible',
position: 'relative', position: 'relative',
zIndex: 1, zIndex: 1,
}} }}
@ -106,6 +118,7 @@ export function ConfiguratorSection() {
</aside> </aside>
<main <main
className="canvas-area"
style={{ style={{
flex: 1, flex: 1,
display: 'flex', display: 'flex',