diff --git a/frontend/package.json b/frontend/package.json
index ffda4b9..cdd248f 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "homehub-frontend",
"private": true,
- "version": "0.4.7",
+ "version": "0.4.8",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/layout/BottomNav.tsx b/frontend/src/components/layout/BottomNav.tsx
index 1f6fb4b..9440894 100644
--- a/frontend/src/components/layout/BottomNav.tsx
+++ b/frontend/src/components/layout/BottomNav.tsx
@@ -1,4 +1,5 @@
import { NavLink } from 'react-router-dom'
+import { useActionButton } from '../../contexts/ActionButtonContext'
const NAV_ITEMS = [
{ to: '/', icon: 'house', label: 'Accueil' },
@@ -8,12 +9,16 @@ const NAV_ITEMS = [
]
export default function BottomNav() {
+ const { actionButton } = useActionButton()
+
return (
)
}
diff --git a/frontend/src/components/layout/Layout.tsx b/frontend/src/components/layout/Layout.tsx
index 9e808ed..12b1ed7 100644
--- a/frontend/src/components/layout/Layout.tsx
+++ b/frontend/src/components/layout/Layout.tsx
@@ -1,24 +1,27 @@
import { Outlet } from 'react-router-dom'
import BottomNav from './BottomNav'
import SideNav from './SideNav'
+import { ActionButtonProvider } from '../../contexts/ActionButtonContext'
export default function Layout() {
return (
-
- {/* Sidebar — visible uniquement sur laptop (lg et +) */}
-
-
-
+
+
+ {/* Sidebar — visible uniquement sur laptop (lg et +) */}
+
+
+
- {/* Contenu principal */}
-
-
-
+ {/* Contenu principal */}
+
+
+
- {/* Navigation bas — visible uniquement sur mobile */}
-
-
+ {/* Navigation bas — visible uniquement sur mobile */}
+
+
+
-
+
)
}
diff --git a/frontend/src/contexts/ActionButtonContext.tsx b/frontend/src/contexts/ActionButtonContext.tsx
new file mode 100644
index 0000000..dcd5394
--- /dev/null
+++ b/frontend/src/contexts/ActionButtonContext.tsx
@@ -0,0 +1,25 @@
+import { createContext, useContext, useState } from 'react'
+import type { ReactNode } from 'react'
+
+interface ActionButtonContextType {
+ actionButton: ReactNode
+ setActionButton: (node: ReactNode) => void
+}
+
+const ActionButtonContext = createContext
({
+ actionButton: null,
+ setActionButton: () => {},
+})
+
+export function ActionButtonProvider({ children }: { children: ReactNode }) {
+ const [actionButton, setActionButton] = useState(null)
+ return (
+
+ {children}
+
+ )
+}
+
+export function useActionButton() {
+ return useContext(ActionButtonContext)
+}
diff --git a/frontend/src/pages/NotesPage.tsx b/frontend/src/pages/NotesPage.tsx
index 96efdcf..a800163 100644
--- a/frontend/src/pages/NotesPage.tsx
+++ b/frontend/src/pages/NotesPage.tsx
@@ -3,6 +3,7 @@ import type { Note, NoteFilters } from '../api/notes'
import { fetchNotes, createNote, updateNote, deleteNote, addAttachment, deleteAttachment } from '../api/notes'
import Modal from '../components/Modal'
import NoteForm from '../components/notes/NoteForm'
+import { useActionButton } from '../contexts/ActionButtonContext'
const noSelect: React.CSSProperties = { userSelect: 'none' }
@@ -163,6 +164,24 @@ export default function NotesPage() {
const [searchInput, setSearchInput] = useState('')
const searchTimer = useRef | null>(null)
+ const { setActionButton } = useActionButton()
+ useEffect(() => {
+ setActionButton(
+
+ )
+ return () => setActionButton(null)
+ }, [setActionButton])
+
const load = useCallback(async () => {
setLoading(true)
setError(null)
@@ -348,20 +367,6 @@ export default function NotesPage() {
- {/* FAB */}
-
)
}
diff --git a/frontend/src/pages/ShoppingPage.tsx b/frontend/src/pages/ShoppingPage.tsx
index 91e0b69..e375865 100644
--- a/frontend/src/pages/ShoppingPage.tsx
+++ b/frontend/src/pages/ShoppingPage.tsx
@@ -1,5 +1,5 @@
// frontend/src/pages/ShoppingPage.tsx
-import { useState, useEffect, useCallback } from 'react'
+import { useState, useEffect, useCallback, useRef } from 'react'
import { matchesSearch } from '../utils/search'
import type { ShoppingListDetail, ShoppingList, Store, Product, ShoppingItem } from '../api/shopping'
import {
@@ -13,6 +13,7 @@ import ItemRow from '../components/shopping/ItemRow'
import CatalogueModal from '../components/shopping/CatalogueModal'
import BoutiquesModal from '../components/shopping/BoutiquesModal'
import { useWakeLock } from '../hooks/useWakeLock'
+import { useActionButton } from '../contexts/ActionButtonContext'
const inputStyle: React.CSSProperties = {
width: '100%',
@@ -76,6 +77,33 @@ export default function ShoppingPage() {
useWakeLock(currentList !== null)
+ const { setActionButton } = useActionButton()
+ const openAddSheetRef = useRef(openAddSheet)
+ useEffect(() => { openAddSheetRef.current = openAddSheet })
+
+ useEffect(() => {
+ if (!currentList || showAddSheet) {
+ setActionButton(null)
+ return
+ }
+ setActionButton(
+
+ )
+ return () => setActionButton(null)
+ }, [currentList, showAddSheet, setActionButton])
+
const loadData = useCallback(async () => {
setLoading(true)
setError(null)
@@ -526,22 +554,6 @@ export default function ShoppingPage() {
)}
- {/* FAB — masqué quand le sheet est ouvert */}
- {!showAddSheet && (
-
- )}
>
)}
diff --git a/frontend/src/pages/TodosPage.tsx b/frontend/src/pages/TodosPage.tsx
index 26d1c4f..5ed20fa 100644
--- a/frontend/src/pages/TodosPage.tsx
+++ b/frontend/src/pages/TodosPage.tsx
@@ -5,6 +5,7 @@ import { fetchTodos, createTodo, updateTodo, deleteTodo, postponeTodo } from '..
import SwipeableRow from '../components/todos/SwipeableRow'
import TodoForm, { DOMAIN_COLORS } from '../components/todos/TodoForm'
import Modal from '../components/Modal'
+import { useActionButton } from '../contexts/ActionButtonContext'
type EditingTodo = Todo | null
@@ -41,6 +42,24 @@ export default function TodosPage() {
const [editingTodo, setEditingTodo] = useState(null)
const [filters, setFilters] = useState({ status: 'pending' })
+ const { setActionButton } = useActionButton()
+ useEffect(() => {
+ setActionButton(
+
+ )
+ return () => setActionButton(null)
+ }, [setActionButton])
+
const load = useCallback(async () => {
setLoading(true)
setError(null)
@@ -395,27 +414,6 @@ export default function TodosPage() {
)}
- {/* FAB création — mobile : au-dessus de la barre de nav ; laptop : coin bas-droit */}
-
)
}