From 8b732602a5b5d91f1eb7d7a4c05ce02368d3ea70 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 7 Feb 2024 12:53:04 +0800 Subject: [PATCH 01/22] Start work on navigation updates for the library --- packages/web/components/elements/Avatar.tsx | 2 +- .../components/elements/AvatarDropdown.tsx | 2 +- .../components/templates/PrimaryDropdown.tsx | 658 +++++++++--------- .../templates/homeFeed/HeaderSpacer.tsx | 4 +- .../templates/homeFeed/LibraryFilterMenu.tsx | 53 +- .../templates/homeFeed/LibraryHeader.tsx | 82 +-- .../web/components/tokens/stitches.config.ts | 4 +- yarn.lock | 152 +++- 8 files changed, 584 insertions(+), 373 deletions(-) diff --git a/packages/web/components/elements/Avatar.tsx b/packages/web/components/elements/Avatar.tsx index 447dbb4b2..34656f5d5 100644 --- a/packages/web/components/elements/Avatar.tsx +++ b/packages/web/components/elements/Avatar.tsx @@ -40,7 +40,7 @@ const StyledFallback = styled(Fallback, { justifyContent: 'center', fontSize: '15px', fontWeight: 600, - fontFamily: 'Inter', + fontFamily: '$inter', color: '$avatarFont', backgroundColor: '$avatarBg', }) diff --git a/packages/web/components/elements/AvatarDropdown.tsx b/packages/web/components/elements/AvatarDropdown.tsx index ec24d0a1f..c021afa11 100644 --- a/packages/web/components/elements/AvatarDropdown.tsx +++ b/packages/web/components/elements/AvatarDropdown.tsx @@ -8,7 +8,7 @@ type AvatarDropdownProps = { export function AvatarDropdown(props: AvatarDropdownProps): JSX.Element { return ( - + ) } diff --git a/packages/web/components/templates/PrimaryDropdown.tsx b/packages/web/components/templates/PrimaryDropdown.tsx index 7a01cb2cd..5cbcf576b 100644 --- a/packages/web/components/templates/PrimaryDropdown.tsx +++ b/packages/web/components/templates/PrimaryDropdown.tsx @@ -6,347 +6,377 @@ import { currentTheme, updateTheme } from '../../lib/themeUpdater' import { Avatar } from '../elements/Avatar' import { AvatarDropdown } from '../elements/AvatarDropdown' import { - Dropdown, - DropdownOption, - DropdownSeparator, + Dropdown, + DropdownOption, + DropdownSeparator, } from '../elements/DropdownElements' import GridLayoutIcon from '../elements/images/GridLayoutIcon' import ListLayoutIcon from '../elements/images/ListLayoutIcon' -import { Box, HStack, VStack } from '../elements/LayoutPrimitives' +import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives' import { StyledText } from '../elements/StyledText' import { styled, theme, ThemeId } from '../tokens/stitches.config' import { LayoutType } from './homeFeed/HomeFeedContainer' +import { DropdownMenu } from '@radix-ui/react-dropdown-menu' type PrimaryDropdownProps = { - children?: ReactNode - showThemeSection: boolean + children?: ReactNode + showThemeSection: boolean - layout?: LayoutType - updateLayout?: (layout: LayoutType) => void + layout?: LayoutType + updateLayout?: (layout: LayoutType) => void - showAddLinkModal?: () => void + showAddLinkModal?: () => void } export type HeaderDropdownAction = - | 'navigate-to-install' - | 'navigate-to-feeds' - | 'navigate-to-emails' - | 'navigate-to-labels' - | 'navigate-to-rules' - | 'navigate-to-profile' - | 'navigate-to-subscriptions' - | 'navigate-to-api' - | 'navigate-to-integrations' - | 'navigate-to-saved-searches' - | 'increaseFontSize' - | 'decreaseFontSize' - | 'logout' + | 'navigate-to-install' + | 'navigate-to-feeds' + | 'navigate-to-emails' + | 'navigate-to-labels' + | 'navigate-to-rules' + | 'navigate-to-profile' + | 'navigate-to-subscriptions' + | 'navigate-to-api' + | 'navigate-to-integrations' + | 'navigate-to-saved-searches' + | 'increaseFontSize' + | 'decreaseFontSize' + | 'logout' + +type TriggerButtonProps = { + name: string +} + +const TriggerButton = (props: TriggerButtonProps): JSX.Element => { + return ( + + + + + {props.name} + + + ) +} export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element { - const { viewerData } = useGetViewerQuery() - const router = useRouter() + const { viewerData } = useGetViewerQuery() + const router = useRouter() - const headerDropdownActionHandler = useCallback( - (action: HeaderDropdownAction) => { - switch (action) { - case 'navigate-to-install': - router.push('/settings/installation') - break - case 'navigate-to-feeds': - router.push('/settings/feeds') - break - case 'navigate-to-emails': - router.push('/settings/emails') - break - case 'navigate-to-labels': - router.push('/settings/labels') - break - case 'navigate-to-rules': - router.push('/settings/rules') - break - case 'navigate-to-subscriptions': - router.push('/settings/subscriptions') - break - case 'navigate-to-api': - router.push('/settings/api') - break - case 'navigate-to-integrations': - router.push('/settings/integrations') - break - case 'navigate-to-saved-searches': - router.push('/settings/saved-searches') - break - case 'logout': - document.dispatchEvent(new Event('logout')) - break - default: - break - } - }, - [router] - ) + const headerDropdownActionHandler = useCallback( + (action: HeaderDropdownAction) => { + switch (action) { + case 'navigate-to-install': + router.push('/settings/installation') + break + case 'navigate-to-feeds': + router.push('/settings/feeds') + break + case 'navigate-to-emails': + router.push('/settings/emails') + break + case 'navigate-to-labels': + router.push('/settings/labels') + break + case 'navigate-to-rules': + router.push('/settings/rules') + break + case 'navigate-to-subscriptions': + router.push('/settings/subscriptions') + break + case 'navigate-to-api': + router.push('/settings/api') + break + case 'navigate-to-integrations': + router.push('/settings/integrations') + break + case 'navigate-to-saved-searches': + router.push('/settings/saved-searches') + break + case 'logout': + document.dispatchEvent(new Event('logout')) + break + default: + break + } + }, + [router] + ) - if (!viewerData?.me) { - return <> - } + if (!viewerData?.me) { + return <> + } - return ( - - ) - } - css={{ width: '240px' }} + return ( + + } + css={{ width: '240px' }} + > + { + router.push('/settings/account') + event.preventDefault() + }} + > + + - + { - router.push('/settings/account') - event.preventDefault() + > + {viewerData.me.name} + + - - - {viewerData.me && ( - <> - - {viewerData.me.name} - - - {`@${viewerData.me.profile.username}`} - - - )} - - - - {props.showThemeSection && } - headerDropdownActionHandler('navigate-to-install')} - title="Install" - /> - headerDropdownActionHandler('navigate-to-feeds')} - title="Feeds" - /> - headerDropdownActionHandler('navigate-to-emails')} - title="Emails" - /> - headerDropdownActionHandler('navigate-to-labels')} - title="Labels" - /> - headerDropdownActionHandler('navigate-to-rules')} - title="Rules" - /> - {props.showAddLinkModal && ( - <> - + > + {`@${viewerData.me.profile.username}`} + + + )} + + + + {props.showThemeSection && } + headerDropdownActionHandler('navigate-to-install')} + title="Install" + /> + headerDropdownActionHandler('navigate-to-feeds')} + title="Feeds" + /> + headerDropdownActionHandler('navigate-to-emails')} + title="Emails" + /> + headerDropdownActionHandler('navigate-to-labels')} + title="Labels" + /> + headerDropdownActionHandler('navigate-to-rules')} + title="Rules" + /> + + headerDropdownActionHandler('navigate-to-api')} + title="API Keys" + /> + + headerDropdownActionHandler('navigate-to-integrations') + } + title="Integrations" + /> + - props.showAddLinkModal && props.showAddLinkModal()} - title="Add Link" - /> - - )} - headerDropdownActionHandler('navigate-to-api')} - title="API Keys" - /> - headerDropdownActionHandler('navigate-to-integrations')} - title="Integrations" - /> - window.open('https://docs.omnivore.app', '_blank')} - title="Documentation" - /> - window.Intercom('show')} - title="Feedback" - /> - - headerDropdownActionHandler('logout')} - title="Logout" - /> - - ) + window.open('https://docs.omnivore.app', '_blank')} + title="Documentation" + /> + window.Intercom('show')} + title="Feedback" + /> + + headerDropdownActionHandler('logout')} + title="Logout" + /> + + ) } export const StyledToggleButton = styled('button', { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - color: '$thTextContrast2', - backgroundColor: 'transparent', - border: 'none', - cursor: 'pointer', - width: '70px', - height: '100%', - borderRadius: '5px', - fontSize: '12px', - fontFamily: '$inter', - gap: '5px', - m: '2px', - '&:hover': { - opacity: 0.8, - }, - '&[data-state="on"]': { - bg: '$thBackground', - }, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: '$thTextContrast2', + backgroundColor: 'transparent', + border: 'none', + cursor: 'pointer', + width: '70px', + height: '100%', + borderRadius: '5px', + fontSize: '12px', + fontFamily: '$inter', + gap: '5px', + m: '2px', + '&:hover': { + opacity: 0.8, + }, + '&[data-state="on"]': { + bg: '$thBackground', + }, }) function ThemeSection(props: PrimaryDropdownProps): JSX.Element { - return ( - <> - - - - Mode - - - { - updateTheme(ThemeId.Light) - }} - > - Light - - - { - updateTheme(ThemeId.Dark) - }} - > - Dark - - - - - {props.layout && ( - - - Layout - - - { - props.updateLayout && props.updateLayout('LIST_LAYOUT') - }} - > - - - { - props.updateLayout && props.updateLayout('GRID_LAYOUT') - }} - > - - - - - )} - - - - ) + return ( + <> + + + + Mode + + + { + updateTheme(ThemeId.Light) + }} + > + Light + + + { + updateTheme(ThemeId.Dark) + }} + > + Dark + + + + + {props.layout && ( + + + Layout + + + { + props.updateLayout && props.updateLayout('LIST_LAYOUT') + }} + > + + + { + props.updateLayout && props.updateLayout('GRID_LAYOUT') + }} + > + + + + + )} + + + + ) } diff --git a/packages/web/components/templates/homeFeed/HeaderSpacer.tsx b/packages/web/components/templates/homeFeed/HeaderSpacer.tsx index 998878190..48342e68b 100644 --- a/packages/web/components/templates/homeFeed/HeaderSpacer.tsx +++ b/packages/web/components/templates/homeFeed/HeaderSpacer.tsx @@ -2,7 +2,7 @@ import { usePersistedState } from '../../../lib/hooks/usePersistedState' import { PinnedSearch } from '../../../pages/settings/pinned-searches' import { Box } from '../../elements/LayoutPrimitives' -export const DEFAULT_HEADER_HEIGHT = '70px' +export const DEFAULT_HEADER_HEIGHT = '98px' export const useGetHeaderHeight = () => { const [hidePinnedSearches] = usePersistedState({ @@ -17,7 +17,7 @@ export const useGetHeaderHeight = () => { }) if (hidePinnedSearches || !pinnedSearches?.length) { - return '70px' + return '98px' } return '100px' } diff --git a/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx b/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx index 0c9000ea2..dad163a9e 100644 --- a/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx +++ b/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx @@ -19,8 +19,11 @@ import { SavedSearch } from '../../../lib/networking/fragments/savedSearchFragme import { ToggleCaretDownIcon } from '../../elements/icons/ToggleCaretDownIcon' import Link from 'next/link' import { ToggleCaretRightIcon } from '../../elements/icons/ToggleCaretRightIcon' +import { SplitButton } from '../../elements/SplitButton' +import { AvatarDropdown } from '../../elements/AvatarDropdown' +import { PrimaryDropdown } from '../PrimaryDropdown' -export const LIBRARY_LEFT_MENU_WIDTH = '233px' +export const LIBRARY_LEFT_MENU_WIDTH = '275px' type LibraryFilterMenuProps = { setShowAddLinkModal: (show: boolean) => void @@ -119,6 +122,7 @@ export function LibraryFilterMenu(props: LibraryFilterMenuProps): JSX.Element { +