feat: add dropdown for links and collection header

This commit is contained in:
Sonny
2024-05-13 00:04:01 +02:00
committed by Sonny
parent 0f1dc9b69c
commit 2f0e1dd375
13 changed files with 204 additions and 131 deletions

View File

@@ -1,34 +1,28 @@
import PATHS from '#constants/paths';
import styled from '@emotion/styled';
import QuickResourceAction from '~/components/dashboard/quick_action/quick_action';
import useActiveCollection from '~/hooks/use_active_collection';
import { BsThreeDotsVertical } from 'react-icons/bs';
import { HiOutlinePencil } from 'react-icons/hi2';
import { IoIosAddCircleOutline } from 'react-icons/io';
import { IoTrashOutline } from 'react-icons/io5';
import Dropdown from '~/components/common/dropdown/dropdown';
import { DropdownItemLink } from '~/components/common/dropdown/dropdown_item';
const CollectionControlsStyle = styled.span({
display: 'flex',
gap: '0.5em',
alignItems: 'center',
});
const DeleteItem = styled(DropdownItemLink)(({ theme }) => ({
color: theme.colors.lightRed,
}));
export default function CollectionControls() {
const { activeCollection } = useActiveCollection();
return (
activeCollection && (
<CollectionControlsStyle>
<QuickResourceAction
resource="link"
action="create"
collectionId={activeCollection.id}
/>
<QuickResourceAction
resource="collection"
action="edit"
resourceId={activeCollection.id}
/>
<QuickResourceAction
resource="collection"
action="remove"
resourceId={activeCollection.id}
/>
</CollectionControlsStyle>
)
);
}
const CollectionControls = () => (
<Dropdown label={<BsThreeDotsVertical />}>
<DropdownItemLink href={PATHS.LINK.CREATE}>
<IoIosAddCircleOutline /> Add
</DropdownItemLink>
<DropdownItemLink href={PATHS.COLLECTION.EDIT}>
<HiOutlinePencil /> Edit
</DropdownItemLink>
<DeleteItem href={PATHS.COLLECTION.REMOVE}>
<IoTrashOutline /> Delete
</DeleteItem>
</Dropdown>
);
export default CollectionControls;

View File

@@ -0,0 +1,98 @@
import PATHS from '#constants/paths';
import type Link from '#models/link';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useCallback } from 'react';
import { AiFillStar, AiOutlineStar } from 'react-icons/ai';
import { BsThreeDotsVertical } from 'react-icons/bs';
import { HiOutlinePencil } from 'react-icons/hi2';
import { IoTrashOutline } from 'react-icons/io5';
import Dropdown from '~/components/common/dropdown/dropdown';
import {
DropdownItemButton,
DropdownItemLink,
} from '~/components/common/dropdown/dropdown_item';
import useCollections from '~/hooks/use_collections';
import { appendCollectionId } from '~/lib/navigation';
import { makeRequest } from '~/lib/request';
const StartItem = styled(DropdownItemButton)(({ theme }) => ({
color: theme.colors.yellow,
}));
const DeleteItem = styled(DropdownItemLink)(({ theme }) => ({
color: theme.colors.lightRed,
}));
export default function LinkControls({ link }: { link: Link }) {
const theme = useTheme();
const { collections, setCollections } = useCollections();
const toggleFavorite = useCallback(
(linkId: Link['id']) => {
let linkIndex = 0;
const collectionIndex = collections.findIndex(({ links }) => {
const lIndex = links.findIndex((l) => l.id === linkId);
if (lIndex !== -1) {
linkIndex = lIndex;
}
return lIndex !== -1;
});
const collectionLink = collections[collectionIndex].links[linkIndex];
const collectionsCopy = [...collections];
collectionsCopy[collectionIndex].links[linkIndex] = {
...collectionLink,
favorite: !collectionLink.favorite,
};
setCollections(collectionsCopy);
},
[collections, setCollections]
);
const onFavorite = () => {
makeRequest({
url: `${PATHS.API.LINK}/${link.id}`,
method: 'PUT',
body: {
name: link.name,
url: link.url,
favorite: !link.favorite,
collectionId: link.collectionId,
},
})
.then(() => toggleFavorite(link.id))
.catch(console.error);
};
console.log(link.favorite, link.favorite ? 'oui' : 'non');
return (
<Dropdown
label={<BsThreeDotsVertical />}
css={{ backgroundColor: theme.colors.secondary }}
>
<StartItem onClick={onFavorite}>
{!link.favorite ? (
<>
<AiFillStar /> Add to favorites
</>
) : (
<>
<AiOutlineStar /> Remove from favorites
</>
)}
</StartItem>
<DropdownItemLink
href={appendCollectionId(PATHS.LINK.EDIT, link.collectionId)}
>
<HiOutlinePencil /> Edit
</DropdownItemLink>
<DeleteItem
href={appendCollectionId(PATHS.LINK.REMOVE, link.collectionId)}
>
<IoTrashOutline /> Delete
</DeleteItem>
</Dropdown>
);
}

View File

@@ -1,14 +1,9 @@
import PATHS from '#constants/paths';
import type Link from '#models/link';
import styled from '@emotion/styled';
import { useCallback } from 'react';
import { AiFillStar } from 'react-icons/ai';
import ExternalLink from '~/components/common/external_link';
import LinkFavicon from '~/components/dashboard/link/link_favicon';
import QuickResourceAction from '~/components/dashboard/quick_action/quick_action';
import QuickLinkFavorite from '~/components/dashboard/quick_action/quick_favorite_link';
import useCollections from '~/hooks/use_collections';
import { makeRequest } from '~/lib/request';
import LinkControls from '~/components/dashboard/link_list/link_controls';
const LinkWrapper = styled.li(({ theme }) => ({
userSelect: 'none',
@@ -20,16 +15,21 @@ const LinkWrapper = styled.li(({ theme }) => ({
padding: '0.75em 1em',
border: `1px solid ${theme.colors.lightGrey}`,
borderRadius: theme.border.radius,
outline: '3px solid transparent',
'&:hover': {
outlineWidth: '1px',
outlineStyle: 'solid',
},
}));
const LinkHeader = styled.div(({ theme }) => ({
display: 'flex',
gap: '1em',
alignItems: 'center',
'& > a': {
height: '100%',
maxWidth: 'calc(100% - 125px)', // TODO: fix this, it is ugly af :(
maxWidth: 'calc(100% - 75px)', // TODO: fix this, it is ugly af :(
textDecoration: 'none',
display: 'flex',
flex: 1,
@@ -49,22 +49,6 @@ const LinkName = styled.div({
overflow: 'hidden',
});
const LinkControls = styled.div({
display: 'none',
alignItems: 'center',
justifyContent: 'center',
gap: '10px',
'& svg': {
height: '20px',
width: '20px',
},
'&:hover *': {
transform: 'scale(1.3)',
},
});
const LinkDescription = styled.div(({ theme }) => ({
marginTop: '0.5em',
color: theme.colors.font,
@@ -97,46 +81,6 @@ export default function LinkItem({
showUserControls: boolean;
}) {
const { id, name, url, description, favorite } = link;
const { collections, setCollections } = useCollections();
const toggleFavorite = useCallback(
(linkId: Link['id']) => {
let linkIndex = 0;
const collectionIndex = collections.findIndex(({ links }) => {
const lIndex = links.findIndex((l) => l.id === linkId);
if (lIndex !== -1) {
linkIndex = lIndex;
}
return lIndex !== -1;
});
const collectionLink = collections[collectionIndex].links[linkIndex];
const collectionsCopy = [...collections];
collectionsCopy[collectionIndex].links[linkIndex] = {
...collectionLink,
favorite: !collectionLink.favorite,
};
setCollections(collectionsCopy);
},
[collections, setCollections]
);
const onFavorite = () => {
makeRequest({
url: `${PATHS.API.LINK}/${link.id}`,
method: 'PUT',
body: {
name,
url,
favorite: !favorite,
collectionId: link.collectionId,
},
})
.then(() => toggleFavorite(link.id))
.catch(console.error);
};
return (
<LinkWrapper key={id}>
<LinkHeader>
@@ -147,21 +91,7 @@ export default function LinkItem({
</LinkName>
<LinkItemURL url={url} />
</ExternalLink>
{showUserControls && (
<LinkControls>
<QuickLinkFavorite onClick={onFavorite} isFavorite={favorite} />
<QuickResourceAction
resource="link"
action="edit"
resourceId={id}
/>
<QuickResourceAction
resource="link"
action="remove"
resourceId={id}
/>
</LinkControls>
)}
{showUserControls && <LinkControls link={link} />}
</LinkHeader>
{description && <LinkDescription>{description}</LinkDescription>}
</LinkWrapper>

View File

@@ -19,8 +19,9 @@ const LinksWrapper = styled.div({
});
const CollectionHeaderWrapper = styled.h2(({ theme }) => ({
fontWeight: 400,
color: theme.colors.primary,
fontWeight: 500,
paddingInline: '1em',
display: 'flex',
gap: '0.4em',
alignItems: 'center',