diff --git a/src/App.jsx b/src/App.jsx index cd63fe6..d85ec92 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -40,7 +40,7 @@ export function App() { * This custom hook takes our token and fetches the data for our list. * Check ./api/firestore.js for its implementation. */ - const data = useShoppingListData(listPath); + const { data, isLoadingListData } = useShoppingListData(listPath); return ( @@ -59,7 +59,14 @@ export function App() { /> } + element={ + + } /> { if (!listPath) return; + setIsLoadingListData(true); // When we get a listPath, we use it to subscribe to real-time updates // from Firestore. @@ -84,12 +86,13 @@ export function useShoppingListData(listPath) { }); // Update our React state with the new data. + setIsLoadingListData(false); setData(nextData); }); }, [listPath]); // Return the data so it can be used by our React components. - return data; + return { data, isLoadingListData }; } /** diff --git a/src/components/Loading.css b/src/components/Loading.css new file mode 100644 index 0000000..fa20fbe --- /dev/null +++ b/src/components/Loading.css @@ -0,0 +1,38 @@ +.loading-block { + padding: 15vh 0 4rem; + display: flex; + justify-content: center; +} + +/** + * Spinner Loading Animation + * Author: Temani Afif + * Source: https://css-tricks.com/single-element-loaders-the-spinner/ + * Notes: + * + * 1. Spinner size. + * 2. Border thickness. + * 3. Spinner color. + */ + +.spinner { + width: 5rem; /* 1 */ + padding: 0.5rem; /* 2 */ + background: var(--color-accent); /* 3 */ + + aspect-ratio: 1; + border-radius: 50%; + --_m: conic-gradient(#0000, #000), linear-gradient(#000 0 0) content-box; + -webkit-mask: var(--_m); + mask: var(--_m); + -webkit-mask-composite: source-out; + mask-composite: subtract; + box-sizing: border-box; + animation: spinner__load 1s linear infinite; +} + +@keyframes spinner__load { + to { + transform: rotate(1turn); + } +} diff --git a/src/components/Loading.jsx b/src/components/Loading.jsx new file mode 100644 index 0000000..06757e0 --- /dev/null +++ b/src/components/Loading.jsx @@ -0,0 +1,11 @@ +import './Loading.css'; + +const Loading = () => { + return ( +
+
+
+ ); +}; + +export default Loading; diff --git a/src/components/index.js b/src/components/index.js index d4e0e97..127fe9a 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -2,3 +2,4 @@ export * from './ListItem'; export * from './SingleList'; export * from './ContainerItems'; export * from './SearchList'; +export * from './Loading'; diff --git a/src/views/List.jsx b/src/views/List.jsx index e6665c0..ece49a4 100644 --- a/src/views/List.jsx +++ b/src/views/List.jsx @@ -4,10 +4,11 @@ import { SearchList } from '../components'; import { useParams, useNavigate } from 'react-router-dom'; import { updateItem, comparePurchaseUrgency } from '../api/firebase'; import { isMoreThanADayAgo } from '../utils'; +import Loading from '../components/Loading'; import './List.css'; import addFirstItem from '../pictures/addFirstItem.png'; -export function List({ data, lists, listPath }) { +export function List({ data, lists, listPath, isLoadingListData }) { const [newList, setNewList] = useState([]); const [sortedList, setSortedList] = useState([]); const { path } = useParams(); @@ -37,6 +38,10 @@ export function List({ data, lists, listPath }) { updateItem(listPath, item, date); }; + if (isLoadingListData) { + return ; + } + return ( <>