diff --git a/src/components/Button.tsx b/src/components/Button.tsx index a83c005..ce98213 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,30 +1,29 @@ 'use client'; -import React, { forwardRef } from 'react'; import { AiOutlineLoading3Quarters as LoadingIcon } from '@react-icons/all-files/ai/AiOutlineLoading3Quarters'; -import clsx from 'clsx'; import { VariantProps, cva } from 'class-variance-authority'; +import clsx from 'clsx'; +import React, { forwardRef } from 'react'; const buttonVariants = cva( 'rounded-md font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 flex items-center justify-center gap-2 cursor-pointer', { variants: { variant: { - default: - 'ring-1 shadow-sm bg-violet-600 hover:bg-violet-700 text-white ring-violet-600', + default: 'shadow-sm bg-violet-600 hover:bg-violet-700 text-white', outline: - 'ring-1 shadow-sm bg-transparent hover:bg-violet-700 text-violet-700 ring-1 ring-violet-600 hover:bg-violet-100 hover:text-white', + 'border border-1 shadow-sm bg-transparent hover:bg-violet-700 text-violet-700 border-violet-600 hover:text-white box-border', destructive: - 'ring-1 shadow-sm bg-red-700 hover:bg-red-600 text-white ring-red-700', + 'border-1 shadow-sm bg-red-700 hover:bg-red-600 text-white border-red-700', destructiveOutline: - 'ring-1 shadow-sm bg-transparent hover:bg-red-700 text-red-700 ring-1 ring-red-700 hover:bg-red-100 hover:text-white', + 'border-1 shadow-sm bg-transparent text-red-700 border-1 border-red-700 hover:bg-red-100 hover:text-white', success: - 'ring-1 shadow-sm bg-[#4ade80] hover:bg-[#3dba6b] text-white ring-[#4ade80] hover:ring-[#3dba6b]', + 'border-1 shadow-sm bg-[#4ade80] hover:bg-[#3dba6b] text-white border-[#4ade80] hover:border-[#3dba6b]', ghost: - 'bg-transparent text-violet-700 ring-1 ring-transparent hover:bg-violet-100 hover:ring-violet-100', + 'bg-transparent text-violet-700 border-1 border-transparent hover:bg-violet-100 hover:border-violet-100', destructiveGhost: - 'bg-transparent text-red-700 ring-1 ring-transparent hover:bg-red-100 hover:ring-red-100', - link: 'ring-0 text-gray-700 text-sm underline hover:text-gray-400 font-light !px-0 !font-normal', + 'bg-transparent text-red-700 border-1 border-transparent hover:bg-red-100 hover:border-red-100', + link: 'border-0 text-gray-700 text-sm underline hover:text-gray-400 !px-0 !font-normal', }, size: { sm: 'py-1 px-4 text-sm', @@ -82,7 +81,7 @@ const Button = forwardRef((props, ref) => { [disabledClass]: disabled, }, { - 'w-full': fullWidth, + 'w-full box-border': fullWidth, }, className )} diff --git a/src/components/auth/LoginForm.tsx b/src/components/auth/LoginForm.tsx index 4551cb6..32b7c5c 100644 --- a/src/components/auth/LoginForm.tsx +++ b/src/components/auth/LoginForm.tsx @@ -1,15 +1,15 @@ 'use client'; import { routes } from '@/core/constants'; +import message from '@/messages/en'; import { EmailProvider, getEmailProvider } from '@/utils/getEmailProvider'; import { CheckCircleIcon } from '@heroicons/react/24/solid'; -import Link from 'next/link'; import { signIn } from 'next-auth/react'; +import Link from 'next/link'; import { useSearchParams } from 'next/navigation'; import { useState } from 'react'; import { useMutation } from 'react-query'; import Button from '../Button'; import { Input } from '../Input'; -import message from '@/messages/en'; const LoginForm = () => { const searchParams = useSearchParams(); @@ -37,7 +37,7 @@ const LoginForm = () => { ); return ( -
+
{isSuccess ? ( <>
diff --git a/src/components/bookmark/BookmarksTeamList.tsx b/src/components/bookmark/BookmarksTeamList.tsx index a102493..aac9f28 100644 --- a/src/components/bookmark/BookmarksTeamList.tsx +++ b/src/components/bookmark/BookmarksTeamList.tsx @@ -1,22 +1,31 @@ 'use client'; +import { TeamLinks } from '@/services/database/link'; +import { Team } from '@prisma/client'; import { BsFillBookmarkFill } from '@react-icons/all-files/bs/BsFillBookmarkFill'; -import NoContent from '../layout/NoContent'; -import { BookmarkItem } from './BookmarkItem'; import Link from 'next/link'; import SearchInput from '../digests/SearchInput'; -import { TeamLinks } from '@/services/database/link'; +import NoContent from '../layout/NoContent'; +import { BookmarkItem } from './BookmarkItem'; +import CreateBookmarkButton from './CreateBookmarkButton'; type Props = { teamLinks: TeamLinks; - teamId: string; - teamSlug: string; + team: Team; }; -export const BookmarksTeamList = ({ teamLinks, teamId, teamSlug }: Props) => { +export const BookmarksTeamList = ({ teamLinks, team }: Props) => { return (
- +
+
+ +
+
+ +
+
+ {teamLinks.length < 1 ? ( } @@ -34,8 +43,8 @@ export const BookmarksTeamList = ({ teamLinks, teamId, teamSlug }: Props) => { > teamLink?.digestBlocks?.length diff --git a/src/components/bookmark/BookmarkButton.tsx b/src/components/bookmark/CreateBookmarkButton.tsx similarity index 55% rename from src/components/bookmark/BookmarkButton.tsx rename to src/components/bookmark/CreateBookmarkButton.tsx index 549fca2..1256fa4 100644 --- a/src/components/bookmark/BookmarkButton.tsx +++ b/src/components/bookmark/CreateBookmarkButton.tsx @@ -1,28 +1,35 @@ +'use client'; + +import { PlusIcon } from '@heroicons/react/24/solid'; import { Team } from '@prisma/client'; -import { FaTelegramPlane } from '@react-icons/all-files/fa/FaTelegramPlane'; -import { BookmarkModal } from './BookmarkModal'; -import { Dialog, DialogContent, DialogTrigger } from '../Dialog'; import { useState } from 'react'; +import Button from '../Button'; +import { Dialog, DialogContent, DialogTrigger } from '../Dialog'; +import { BookmarkModal } from './BookmarkModal'; -type Props = { team: Team }; +interface Props { + team: Team; +} -const BookmarkButton = ({ team }: Props) => { +export default function CreateBookmarkButton({ team }: Props) { const [isDialogOpen, setIsDialogOpen] = useState(false); return ( - + New bookmark + @@ -30,6 +37,4 @@ const BookmarkButton = ({ team }: Props) => { ); -}; - -export default BookmarkButton; +} diff --git a/src/components/bookmark/HeaderCreateBookmarkButton.tsx b/src/components/bookmark/HeaderCreateBookmarkButton.tsx new file mode 100644 index 0000000..b6afd56 --- /dev/null +++ b/src/components/bookmark/HeaderCreateBookmarkButton.tsx @@ -0,0 +1,51 @@ +import { PlusIcon } from '@heroicons/react/24/solid'; +import { Team } from '@prisma/client'; +import { useEffect, useState } from 'react'; +import { Dialog, DialogContent, DialogTrigger } from '../Dialog'; +import { BookmarkModal } from './BookmarkModal'; + +type Props = { team: Team }; + +const HeaderCreateBookmarkButton = ({ team }: Props) => { + const [isDialogOpen, setIsDialogOpen] = useState(false); + + function onKeyDown(event: KeyboardEvent) { + if (event.key === 'b' && event.ctrlKey) { + setIsDialogOpen(true); + } + } + + useEffect(() => { + window.addEventListener('keydown', onKeyDown); + return () => { + window.removeEventListener('keydown', onKeyDown); + }; + }, []); + + return ( + + + + + + setIsDialogOpen(false)} team={team} /> + + + ); +}; + +export default HeaderCreateBookmarkButton; diff --git a/src/components/digests/SearchInput.tsx b/src/components/digests/SearchInput.tsx index 90dea4c..4d5ae25 100644 --- a/src/components/digests/SearchInput.tsx +++ b/src/components/digests/SearchInput.tsx @@ -1,10 +1,10 @@ 'use client'; -import { InputHTMLAttributes, useCallback, useTransition } from 'react'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { AiOutlineLoading3Quarters as LoadingIcon } from '@react-icons/all-files/ai/AiOutlineLoading3Quarters'; -import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import debounce from 'lodash/debounce'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; +import { InputHTMLAttributes, useCallback, useTransition } from 'react'; const SearchInput = ({ className, @@ -30,7 +30,7 @@ const SearchInput = ({ return (
-
+
{isPending ? ( @@ -49,7 +49,7 @@ const SearchInput = ({ type="search" name="search" id="search" - className="block w-full rounded-md border-0 py-1.5 pl-10 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + className="block w-full rounded-md border-0 py-1.5 pl-10 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-violet-600 sm:text-sm sm:leading-6" placeholder="Search bookmarks" onInput={onSearch} defaultValue={searchParams?.get('search') || ''} diff --git a/src/components/layout/NavMenu/NavMenu.tsx b/src/components/layout/NavMenu/NavMenu.tsx index 72884c1..834f4f3 100644 --- a/src/components/layout/NavMenu/NavMenu.tsx +++ b/src/components/layout/NavMenu/NavMenu.tsx @@ -1,21 +1,21 @@ 'use client'; import { routes } from '@/core/constants'; -import { Team } from '@prisma/client'; -import { HiChevronDown } from '@react-icons/all-files/hi/HiChevronDown'; -import * as NavigationMenu from '@radix-ui/react-navigation-menu'; -import { usePathname } from 'next/navigation'; -import BookmarkButton from '../../bookmark/BookmarkButton'; -import { signOut } from 'next-auth/react'; -import Divider from './Divider'; -import Item from './Item'; import { AdjustmentsVerticalIcon, - CheckIcon, - UserIcon, ArrowLeftOnRectangleIcon, + CheckIcon, PlusIcon, + UserIcon, } from '@heroicons/react/24/solid'; +import { Team } from '@prisma/client'; +import * as NavigationMenu from '@radix-ui/react-navigation-menu'; +import { HiChevronDown } from '@react-icons/all-files/hi/HiChevronDown'; +import { signOut } from 'next-auth/react'; +import { usePathname } from 'next/navigation'; +import HeaderCreateBookmarkButton from '../../bookmark/HeaderCreateBookmarkButton'; +import Divider from './Divider'; +import Item from './Item'; type Props = { teams?: Team[]; @@ -36,7 +36,7 @@ export const NavMenu = ({ teams }: Props) => {
{currentTeam && pathName !== '/' && ( <> - + )}
diff --git a/src/components/pages/DigestEditPage.tsx b/src/components/pages/DigestEditPage.tsx index 86fc622..0103a50 100644 --- a/src/components/pages/DigestEditPage.tsx +++ b/src/components/pages/DigestEditPage.tsx @@ -1,16 +1,21 @@ 'use client'; -import { useRouter } from 'next/navigation'; import { routes } from '@/core/constants'; import useCustomToast from '@/hooks/useCustomToast'; import useTransitionRefresh from '@/hooks/useTransitionRefresh'; import api from '@/lib/api'; +import { useRouter } from 'next/navigation'; import useAddAndRemoveBlockOnDigest from '@/hooks/useAddAndRemoveBlockOnDigest'; import { ApiDigestResponseSuccess } from '@/pages/api/teams/[teamId]/digests'; +import { getDigest } from '@/services/database/digest'; +import { TeamLinksData } from '@/services/database/link'; +import { getTeamBySlug } from '@/services/database/team'; import { reorderList } from '@/utils/actionOnList'; import { getRelativeDate } from '@/utils/date'; +import { digestBlockToTemplateBlocks } from '@/utils/template'; import { EyeSlashIcon, RssIcon, TrashIcon } from '@heroicons/react/24/outline'; +import { EyeIcon } from '@heroicons/react/24/solid'; import { DigestBlock, DigestBlockType } from '@prisma/client'; import { BsFillBookmarkFill } from '@react-icons/all-files/bs/BsFillBookmarkFill'; import { AxiosError, AxiosResponse } from 'axios'; @@ -26,22 +31,18 @@ import { useMutation } from 'react-query'; import Button from '../Button'; import { Input, TextArea } from '../Input'; import { DeletePopover } from '../Popover'; -import { BlockListDnd } from '../digests/BlockListDnd'; import BookmarkListDnd from '../bookmark/BookmarkListDnd'; +import CreateBookmarkButton from '../bookmark/CreateBookmarkButton'; +import { BlockListDnd } from '../digests/BlockListDnd'; import SearchInput from '../digests/SearchInput'; +import CreateTemplateModal from '../digests/templates/CreateTemplateModal'; import NoContent from '../layout/NoContent'; import SectionContainer from '../layout/SectionContainer'; import Pagination from '../list/Pagination'; import { Breadcrumb } from '../teams/Breadcrumb'; -import DigestEditVisit from './DigestEditVisit'; -import DigestEditTypefully from './DigestEditTypefully'; import DigestEditSendNewsletter from './DigestEditSendNewsletter'; -import { EyeIcon } from '@heroicons/react/24/solid'; -import CreateTemplateModal from '../digests/templates/CreateTemplateModal'; -import { digestBlockToTemplateBlocks } from '@/utils/template'; -import { TeamLinksData } from '@/services/database/link'; -import { getDigest } from '@/services/database/digest'; -import { getTeamBySlug } from '@/services/database/team'; +import DigestEditTypefully from './DigestEditTypefully'; +import DigestEditVisit from './DigestEditVisit'; type Props = { teamLinksData: TeamLinksData; @@ -285,7 +286,14 @@ export const DigestEditPage = ({
- +
+
+ +
+
+ +
+
{teamLinks && teamLinks.length > 0 ? (
@@ -70,11 +70,7 @@ const Team = ({ subtitle="Start bookmarking links to share them with your team" /> ) : ( - + )}