feat(shopping): optimisation bottom sheet — icônes haut, tab bar couverte v0.4.5
- Boutons Annuler (fa-xmark, outline err) et Valider (fa-check, ok) déplacés en haut du sheet, pill shape, touch target 48px - Suppression du bouton sticky en bas - zIndex sheet 70 > tab bar 50 : bottom sheet couvre la nav - maxHeight 85dvh → 92dvh pour exploiter l'espace libéré - Poignée de drag supprimée Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "homehub-frontend",
|
"name": "homehub-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.4.4",
|
"version": "0.4.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default function BottomSheet({ onClose, children }: BottomSheetProps) {
|
|||||||
style={{
|
style={{
|
||||||
position: 'fixed', inset: 0,
|
position: 'fixed', inset: 0,
|
||||||
background: 'rgba(0,0,0,0.55)',
|
background: 'rgba(0,0,0,0.55)',
|
||||||
zIndex: 40,
|
zIndex: 60,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
@@ -22,19 +22,16 @@ export default function BottomSheet({ onClose, children }: BottomSheetProps) {
|
|||||||
transform: 'translateX(-50%)',
|
transform: 'translateX(-50%)',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: 600,
|
maxWidth: 600,
|
||||||
maxHeight: '85dvh',
|
maxHeight: '92dvh',
|
||||||
background: 'var(--bg-2)',
|
background: 'var(--bg-2)',
|
||||||
borderRadius: '16px 16px 0 0',
|
borderRadius: '16px 16px 0 0',
|
||||||
boxShadow: '0 -4px 24px rgba(0,0,0,0.4)',
|
boxShadow: '0 -4px 24px rgba(0,0,0,0.4)',
|
||||||
zIndex: 50,
|
zIndex: 70,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', padding: '10px 0 4px', flexShrink: 0 }}>
|
|
||||||
<div style={{ width: 36, height: 4, borderRadius: 2, background: 'var(--bg-5)' }} />
|
|
||||||
</div>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -316,6 +316,8 @@ export default function ShoppingPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const actionCount = selections.filter(sel => !sel.existingItemId || sel.qty !== sel.originalQty).length
|
||||||
|
|
||||||
// Tri : non cochés alpha, cochés alpha (en bas)
|
// Tri : non cochés alpha, cochés alpha (en bas)
|
||||||
const sortedItems = [...(currentList?.items ?? [])].sort((a, b) => {
|
const sortedItems = [...(currentList?.items ?? [])].sort((a, b) => {
|
||||||
if (a.is_checked !== b.is_checked) return a.is_checked ? 1 : -1
|
if (a.is_checked !== b.is_checked) return a.is_checked ? 1 : -1
|
||||||
@@ -569,8 +571,39 @@ export default function ShoppingPage() {
|
|||||||
|
|
||||||
{showAddSheet && (
|
{showAddSheet && (
|
||||||
<BottomSheet onClose={closeAddSheet}>
|
<BottomSheet onClose={closeAddSheet}>
|
||||||
|
{/* Actions annuler / valider */}
|
||||||
|
<div style={{ display: 'flex', gap: 12, padding: '12px 16px', flexShrink: 0 }}>
|
||||||
|
<button
|
||||||
|
onClick={closeAddSheet}
|
||||||
|
aria-label="Annuler"
|
||||||
|
style={{
|
||||||
|
flex: 1, minHeight: 48, borderRadius: 999,
|
||||||
|
border: '1.5px solid var(--err)', background: 'transparent',
|
||||||
|
color: 'var(--err)', fontSize: 20, cursor: 'pointer',
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className="fa-solid fa-xmark" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => void handleConfirmAdd()}
|
||||||
|
disabled={actionCount === 0 || addSaving}
|
||||||
|
aria-label="Valider"
|
||||||
|
style={{
|
||||||
|
flex: 1, minHeight: 48, borderRadius: 999, border: 'none',
|
||||||
|
background: actionCount === 0 ? 'var(--bg-4)' : 'var(--ok)',
|
||||||
|
color: actionCount === 0 ? 'var(--ink-4)' : '#1d2021',
|
||||||
|
fontSize: 20, cursor: actionCount === 0 ? 'default' : 'pointer',
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||||
|
transition: 'background 0.15s',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className={addSaving ? 'fa-solid fa-spinner fa-spin' : 'fa-solid fa-check'} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Recherche */}
|
{/* Recherche */}
|
||||||
<div style={{ padding: '4px 16px 10px', flexShrink: 0 }}>
|
<div style={{ padding: '0 16px 10px', flexShrink: 0 }}>
|
||||||
<input
|
<input
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
placeholder="Rechercher ou saisir un article…"
|
placeholder="Rechercher ou saisir un article…"
|
||||||
@@ -679,28 +712,6 @@ export default function ShoppingPage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bouton confirm sticky */}
|
|
||||||
{(() => {
|
|
||||||
const actionCount = selections.filter(sel => !sel.existingItemId || sel.qty !== sel.originalQty).length
|
|
||||||
return (
|
|
||||||
<div style={{ padding: '12px 16px', borderTop: '1px solid var(--bg-4)', flexShrink: 0 }}>
|
|
||||||
<button
|
|
||||||
onClick={() => void handleConfirmAdd()}
|
|
||||||
disabled={actionCount === 0 || addSaving}
|
|
||||||
style={{
|
|
||||||
width: '100%', padding: '14px', borderRadius: 12, border: 'none',
|
|
||||||
background: actionCount === 0 ? 'var(--bg-4)' : 'var(--accent)',
|
|
||||||
color: actionCount === 0 ? 'var(--ink-4)' : '#1d2021',
|
|
||||||
fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 16,
|
|
||||||
cursor: actionCount === 0 ? 'default' : 'pointer',
|
|
||||||
minHeight: 52, transition: 'background 0.15s',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{addSaving ? 'Enregistrement…' : actionCount === 0 ? 'Aucune modification' : `Confirmer (${actionCount})`}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})()}
|
|
||||||
</BottomSheet>
|
</BottomSheet>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user