mirror of
https://github.com/remvze/moodist.git
synced 2025-12-17 17:04:15 +00:00
feat: add toolbar and portal
This commit is contained in:
parent
6dfa998ffe
commit
ede480186c
12 changed files with 98 additions and 49 deletions
|
|
@ -9,9 +9,8 @@ import { Container } from '@/components/container';
|
|||
import { StoreConsumer } from '@/components/store-consumer';
|
||||
import { Buttons } from '@/components/buttons';
|
||||
import { Categories } from '@/components/categories';
|
||||
import { ScrollToTop } from '@/components/scroll-to-top';
|
||||
import { SharedModal } from '@/components/modals/shared';
|
||||
import { Menu } from '@/components/menu/menu';
|
||||
import { Toolbar } from '@/components/toolbar';
|
||||
import { SnackbarProvider } from '@/contexts/snackbar';
|
||||
|
||||
import { sounds } from '@/data/sounds';
|
||||
|
|
@ -77,8 +76,7 @@ export function App() {
|
|||
<Categories categories={allCategories} />
|
||||
</Container>
|
||||
|
||||
<ScrollToTop />
|
||||
<Menu />
|
||||
<Toolbar />
|
||||
<SharedModal />
|
||||
</StoreConsumer>
|
||||
</SnackbarProvider>
|
||||
|
|
|
|||
|
|
@ -6,4 +6,8 @@
|
|||
&.tight {
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
&.wide {
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,24 @@ interface ContainerProps {
|
|||
children: React.ReactNode;
|
||||
className?: string;
|
||||
tight?: boolean;
|
||||
wide?: boolean;
|
||||
}
|
||||
|
||||
export function Container({ children, className, tight }: ContainerProps) {
|
||||
export function Container({
|
||||
children,
|
||||
className,
|
||||
tight,
|
||||
wide,
|
||||
}: ContainerProps) {
|
||||
return (
|
||||
<div className={cn(styles.container, className, tight && styles.tight)}>
|
||||
<div
|
||||
className={cn(
|
||||
styles.container,
|
||||
className,
|
||||
tight && styles.tight,
|
||||
wide && styles.wide,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,4 @@
|
|||
.wrapper {
|
||||
position: fixed;
|
||||
right: calc(50vw - 400px);
|
||||
bottom: 20px;
|
||||
z-index: 15;
|
||||
|
||||
@media (width <= 850px) {
|
||||
right: 5vw;
|
||||
}
|
||||
|
||||
& .menuButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { useEffect } from 'react';
|
|||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { IoClose } from 'react-icons/io5/index';
|
||||
|
||||
import { Portal } from '@/components/portal';
|
||||
|
||||
import { fade, mix, slideY } from '@/lib/motion';
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ export function Modal({
|
|||
}, [show, lockBody]);
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<AnimatePresence>
|
||||
{show && (
|
||||
<>
|
||||
|
|
@ -66,5 +69,6 @@ export function Modal({
|
|||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</Portal>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
1
src/components/portal/index.ts
Normal file
1
src/components/portal/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { Portal } from './portal';
|
||||
14
src/components/portal/portal.tsx
Normal file
14
src/components/portal/portal.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
interface PortalProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Portal({ children }: PortalProps) {
|
||||
const [isClientSide, setIsClientSide] = useState(false);
|
||||
|
||||
useEffect(() => setIsClientSide(true), []);
|
||||
|
||||
return isClientSide ? createPortal(children, document.body) : null;
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
.button {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: calc(50vw - 400px);
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -16,10 +12,6 @@
|
|||
border-radius: 50%;
|
||||
transition: 0.2s;
|
||||
|
||||
@media (width <= 850px) {
|
||||
left: 5vw;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-neutral-200);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export function ScrollToTop() {
|
|||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isVisible && (
|
||||
{isVisible ? (
|
||||
<motion.button
|
||||
animate="show"
|
||||
aria-label="Scroll to top"
|
||||
|
|
@ -43,6 +43,8 @@ export function ScrollToTop() {
|
|||
>
|
||||
<BiUpArrowAlt />
|
||||
</motion.button>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
|
|
|
|||
1
src/components/toolbar/index.ts
Normal file
1
src/components/toolbar/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { Toolbar } from './toolbar';
|
||||
13
src/components/toolbar/toolbar.module.css
Normal file
13
src/components/toolbar/toolbar.module.css
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.wrapper {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
z-index: 15;
|
||||
width: 100%;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
16
src/components/toolbar/toolbar.tsx
Normal file
16
src/components/toolbar/toolbar.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { Container } from '@/components/container';
|
||||
import { Menu } from '@/components/menu';
|
||||
import { ScrollToTop } from '@/components/scroll-to-top';
|
||||
|
||||
import styles from './toolbar.module.css';
|
||||
|
||||
export function Toolbar() {
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Container className={styles.container} wide>
|
||||
<ScrollToTop />
|
||||
<Menu />
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue