mirror of
https://github.com/remvze/moodist.git
synced 2025-12-17 08:54:13 +00:00
feat: basic structure for share link
This commit is contained in:
parent
35e32152b1
commit
ef81f198ba
9 changed files with 131 additions and 71 deletions
9
src/components/menu/items/share.tsx
Normal file
9
src/components/menu/items/share.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Item } from '../item';
|
||||||
|
|
||||||
|
interface ShareProps {
|
||||||
|
open: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Share({ open }: ShareProps) {
|
||||||
|
return <Item onClick={open}>Share Sounds</Item>;
|
||||||
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { Share } from './share';
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import { useState } from 'react';
|
|
||||||
import { createPortal } from 'react-dom';
|
|
||||||
import { IoCopyOutline } from 'react-icons/io5/index';
|
|
||||||
|
|
||||||
import { Modal } from '@/components/modal';
|
|
||||||
|
|
||||||
import { Item } from '../../item';
|
|
||||||
|
|
||||||
import styles from './share.module.css';
|
|
||||||
|
|
||||||
export function Share() {
|
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Item onClick={() => setIsModalOpen(true)}>Share Sounds</Item>
|
|
||||||
|
|
||||||
{createPortal(
|
|
||||||
<Modal show={isModalOpen} onClose={() => setIsModalOpen(false)}>
|
|
||||||
<h1 className={styles.heading}>Share your sound selection!</h1>
|
|
||||||
<p className={styles.desc}>
|
|
||||||
Copy and send the following link to the person you want to share
|
|
||||||
your selection with.
|
|
||||||
</p>
|
|
||||||
<div className={styles.inputWrapper}>
|
|
||||||
<input type="text" onFocus={e => e.stopPropagation()} />
|
|
||||||
<button>
|
|
||||||
<IoCopyOutline />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Modal>,
|
|
||||||
document.body,
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from '@floating-ui/react';
|
} from '@floating-ui/react';
|
||||||
|
|
||||||
import { ShuffleItem, ShareItem } from './items';
|
import { ShuffleItem, ShareItem } from './items';
|
||||||
|
import { ShareLinkModal } from '@/components/modals/share-link';
|
||||||
|
|
||||||
import { slideY, fade, mix } from '@/lib/motion';
|
import { slideY, fade, mix } from '@/lib/motion';
|
||||||
|
|
||||||
|
|
@ -23,6 +24,8 @@ import styles from './menu.module.css';
|
||||||
export function Menu() {
|
export function Menu() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const [showShareLink, setShowShareLink] = useState(false);
|
||||||
|
|
||||||
const variants = mix(slideY(-20), fade());
|
const variants = mix(slideY(-20), fade());
|
||||||
|
|
||||||
const { context, floatingStyles, refs } = useFloating({
|
const { context, floatingStyles, refs } = useFloating({
|
||||||
|
|
@ -44,39 +47,46 @@ export function Menu() {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<>
|
||||||
<button
|
<div className={styles.wrapper}>
|
||||||
aria-label="Menu"
|
<button
|
||||||
className={styles.menuButton}
|
aria-label="Menu"
|
||||||
ref={refs.setReference}
|
className={styles.menuButton}
|
||||||
onClick={() => setIsOpen(prev => !prev)}
|
ref={refs.setReference}
|
||||||
{...getReferenceProps()}
|
onClick={() => setIsOpen(prev => !prev)}
|
||||||
>
|
{...getReferenceProps()}
|
||||||
{isOpen ? <IoClose /> : <IoMenu />}
|
>
|
||||||
</button>
|
{isOpen ? <IoClose /> : <IoMenu />}
|
||||||
|
</button>
|
||||||
|
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<FloatingFocusManager context={context}>
|
<FloatingFocusManager context={context} modal={false}>
|
||||||
<div
|
<div
|
||||||
ref={refs.setFloating}
|
ref={refs.setFloating}
|
||||||
style={floatingStyles}
|
style={floatingStyles}
|
||||||
{...getFloatingProps()}
|
{...getFloatingProps()}
|
||||||
>
|
|
||||||
<motion.div
|
|
||||||
animate="show"
|
|
||||||
className={styles.menu}
|
|
||||||
exit="hidden"
|
|
||||||
initial="hidden"
|
|
||||||
variants={variants}
|
|
||||||
>
|
>
|
||||||
<ShareItem />
|
<motion.div
|
||||||
<ShuffleItem />
|
animate="show"
|
||||||
</motion.div>
|
className={styles.menu}
|
||||||
</div>
|
exit="hidden"
|
||||||
</FloatingFocusManager>
|
initial="hidden"
|
||||||
)}
|
variants={variants}
|
||||||
</AnimatePresence>
|
>
|
||||||
</div>
|
<ShareItem open={() => setShowShareLink(true)} />
|
||||||
|
<ShuffleItem />
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</FloatingFocusManager>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ShareLinkModal
|
||||||
|
show={showShareLink}
|
||||||
|
onClose={() => setShowShareLink(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
padding: 50px 0;
|
padding: 50px 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
pointer-events: none;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
& .content {
|
& .content {
|
||||||
|
|
@ -22,8 +23,27 @@
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
padding-top: 40px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
pointer-events: fill;
|
||||||
background-color: var(--color-neutral-100);
|
background-color: var(--color-neutral-100);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
||||||
|
& .close {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--color-foreground-subtle);
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
|
import { IoClose } from 'react-icons/io5/index';
|
||||||
|
|
||||||
import styles from './modal.module.css';
|
import styles from './modal.module.css';
|
||||||
|
|
||||||
|
|
@ -19,7 +20,13 @@ export function Modal({ children, onClose, show }: ModalProps) {
|
||||||
onKeyDown={onClose}
|
onKeyDown={onClose}
|
||||||
/>
|
/>
|
||||||
<div className={styles.modal}>
|
<div className={styles.modal}>
|
||||||
<div className={styles.content}>{children}</div>
|
<div className={styles.content}>
|
||||||
|
<button className={styles.close} onClick={onClose}>
|
||||||
|
<IoClose />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
1
src/components/modals/share-link/index.ts
Normal file
1
src/components/modals/share-link/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { ShareLinkModal } from './share-link';
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 45px;
|
height: 45px;
|
||||||
|
padding: 4px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
background-color: var(--color-neutral-50);
|
background-color: var(--color-neutral-50);
|
||||||
border: 1px solid var(--color-neutral-200);
|
border: 1px solid var(--color-neutral-200);
|
||||||
|
|
@ -23,9 +24,30 @@
|
||||||
& input {
|
& input {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: red;
|
padding: 0 10px;
|
||||||
|
font-size: var(--font-sm);
|
||||||
|
color: var(--color-foreground);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
color: var(--color-foreground);
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--color-neutral-100);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
transition: 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-neutral-200);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
28
src/components/modals/share-link/share-link.tsx
Normal file
28
src/components/modals/share-link/share-link.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { IoCopyOutline } from 'react-icons/io5/index';
|
||||||
|
|
||||||
|
import { Modal } from '@/components/modal';
|
||||||
|
|
||||||
|
import styles from './share-link.module.css';
|
||||||
|
|
||||||
|
interface ShareLinkModalProps {
|
||||||
|
onClose: () => void;
|
||||||
|
show: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ShareLinkModal({ onClose, show }: ShareLinkModalProps) {
|
||||||
|
return (
|
||||||
|
<Modal show={show} onClose={onClose}>
|
||||||
|
<h1 className={styles.heading}>Share your sound selection!</h1>
|
||||||
|
<p className={styles.desc}>
|
||||||
|
Copy and send the following link to the person you want to share your
|
||||||
|
selection with.
|
||||||
|
</p>
|
||||||
|
<div className={styles.inputWrapper}>
|
||||||
|
<input type="text" value="https://moodist.app/?share=test" />
|
||||||
|
<button>
|
||||||
|
<IoCopyOutline />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue