Move pinned searches to under the bar

This commit is contained in:
Jackson Harper
2024-02-08 19:03:22 +08:00
parent 11463ba6f7
commit 29a4e7311e
12 changed files with 156 additions and 85 deletions

View File

@ -195,11 +195,11 @@ export const Button = styled('button', {
py: '5px',
font: '$inter',
fontSize: '12px',
fontWeight: '700',
fontWeight: '500',
whiteSpace: 'nowrap',
color: '$thLibraryMenuPrimary',
border: '1px solid $thLeftMenuBackground',
backgroundColor: '$thLeftMenuBackground',
bg: '$thBackgroundActive',
'&:hover': {
bg: '$thBackgroundActive',
border: '1px solid $thBackgroundActive',
@ -210,12 +210,12 @@ export const Button = styled('button', {
borderRadius: '15px',
px: '12px',
py: '5px',
bg: 'transparent',
font: '$inter',
fontSize: '12px',
fontWeight: 'medium',
fontWeight: '500',
whiteSpace: 'nowrap',
border: '1px solid $thBackground4',
backgroundColor: '$thBackground4',
'&:hover': {
bg: '$thBackgroundActive',
border: '1px solid $thBackgroundActive',

View File

@ -45,7 +45,7 @@ export const TitleStyle = {
fontSize: '16px',
fontWeight: '700',
maxLines: 2,
lineHeight: 1.25,
lineHeight: 1.5,
fontFamily: '$display',
overflow: 'hidden',
textOverflow: 'ellipsis',

View File

@ -56,7 +56,7 @@ const TriggerButton = (props: TriggerButtonProps): JSX.Element => {
height: '32px',
padding: '5px',
'&:hover': {
bg: '#6A6968',
bg: '$thLibraryMenuFooterHover',
opacity: '0.7px',
},
}}

View File

@ -2,10 +2,9 @@ import { Book } from 'phosphor-react'
import { VStack } from '../../elements/LayoutPrimitives'
import { StyledText } from '../../elements/StyledText'
import { theme } from '../../tokens/stitches.config'
import { useGetHeaderHeight } from './HeaderSpacer'
import { DEFAULT_HEADER_HEIGHT } from './HeaderSpacer'
export function EmptyHighlights(): JSX.Element {
const headerHeight = useGetHeaderHeight()
return (
<VStack
alignment="center"
@ -13,7 +12,7 @@ export function EmptyHighlights(): JSX.Element {
css={{
color: '$grayTextContrast',
textAlign: 'center',
marginTop: headerHeight,
marginTop: DEFAULT_HEADER_HEIGHT,
}}
>
<Book size={44} color={theme.colors.grayTextContrast.toString()} />

View File

@ -2,32 +2,32 @@ import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { PinnedSearch } from '../../../pages/settings/pinned-searches'
import { Box } from '../../elements/LayoutPrimitives'
export const DEFAULT_HEADER_HEIGHT = '98px'
export const DEFAULT_HEADER_HEIGHT = '85px'
export const useGetHeaderHeight = () => {
const [hidePinnedSearches] = usePersistedState({
key: '--library-hide-pinned-searches',
initialValue: false,
isSessionStorage: false,
})
const [pinnedSearches] = usePersistedState<PinnedSearch[] | null>({
key: `--library-pinned-searches`,
initialValue: [],
isSessionStorage: false,
})
// export const useGetHeaderHeight = () => {
// const [hidePinnedSearches] = usePersistedState({
// key: '--library-hide-pinned-searches',
// initialValue: false,
// isSessionStorage: false,
// })
// const [pinnedSearches] = usePersistedState<PinnedSearch[] | null>({
// key: `--library-pinned-searches`,
// initialValue: [],
// isSessionStorage: false,
// })
if (hidePinnedSearches || !pinnedSearches?.length) {
return '98px'
}
return '100px'
}
// if (hidePinnedSearches || !pinnedSearches?.length) {
// return '90px'
// }
// return '90px'
// }
export function HeaderSpacer(): JSX.Element {
const headerHeight = useGetHeaderHeight()
// const headerHeight = useGetHeaderHeight()
return (
<Box
css={{
height: headerHeight,
height: DEFAULT_HEADER_HEIGHT,
bg: '$grayBase',
'@mdDown': {
height: DEFAULT_HEADER_HEIGHT,

View File

@ -20,7 +20,7 @@ import {
import { LibraryHighlightGridCard } from '../../patterns/LibraryCards/LibraryHighlightGridCard'
import { NotebookContent } from '../article/Notebook'
import { EmptyHighlights } from './EmptyHighlights'
import { DEFAULT_HEADER_HEIGHT, useGetHeaderHeight } from './HeaderSpacer'
import { DEFAULT_HEADER_HEIGHT } from './HeaderSpacer'
import { highlightsAsMarkdown } from './HighlightItem'
type HighlightItemsLayoutProps = {
@ -33,7 +33,7 @@ type HighlightItemsLayoutProps = {
export function HighlightItemsLayout(
props: HighlightItemsLayoutProps
): JSX.Element {
const headerHeight = useGetHeaderHeight()
// const headerHeight = useGetHeaderHeight()
const [currentItem, setCurrentItem] = useState<LibraryItem | undefined>(
undefined
)
@ -106,7 +106,7 @@ export function HighlightItemsLayout(
<Box
css={{
width: '100%',
height: `calc(100vh - ${headerHeight})`,
height: `calc(100vh - ${DEFAULT_HEADER_HEIGHT})`,
'@mdDown': {
height: DEFAULT_HEADER_HEIGHT,
},

View File

@ -31,13 +31,17 @@ import { StyledText } from '../../elements/StyledText'
import { ConfirmationModal } from '../../patterns/ConfirmationModal'
import { LinkedItemCardAction } from '../../patterns/LibraryCards/CardTypes'
import { LinkedItemCard } from '../../patterns/LibraryCards/LinkedItemCard'
import { Box, HStack, VStack } from './../../elements/LayoutPrimitives'
import { Box, HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { AddLinkModal } from './AddLinkModal'
import { EditLibraryItemModal } from './EditItemModals'
import { EmptyLibrary } from './EmptyLibrary'
import { HighlightItemsLayout } from './HighlightsLayout'
import { LibraryFilterMenu } from './LibraryFilterMenu'
import { LibraryHeader, MultiSelectMode } from './LibraryHeader'
import {
LibraryHeader,
MultiSelectMode,
headerControlWidths,
} from './LibraryHeader'
import { UploadModal } from '../UploadModal'
import { BulkAction } from '../../../lib/networking/mutations/bulkActionMutation'
import { bulkActionMutation } from '../../../lib/networking/mutations/bulkActionMutation'
@ -53,6 +57,8 @@ import { articleQuery } from '../../../lib/networking/queries/useGetArticleQuery
import { searchQuery } from '../../../lib/networking/queries/search'
import { MoreOptionsIcon } from '../../elements/images/MoreOptionsIcon'
import { theme } from '../../tokens/stitches.config'
import { PinnedSearch } from '../../../pages/settings/pinned-searches'
import { PinnedButtons } from './PinnedButtons'
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
export type LibraryMode = 'reads' | 'highlights'
@ -1036,6 +1042,14 @@ function LibraryItemsLayout(props: LibraryItemsLayoutProps): JSX.Element {
setShowUnsubscribeConfirmation(false)
}
const [pinnedSearches, setPinnedSearches] = usePersistedState<
PinnedSearch[] | null
>({
key: `--library-pinned-searches`,
initialValue: [],
isSessionStorage: false,
})
return (
<>
<VStack
@ -1048,6 +1062,28 @@ function LibraryItemsLayout(props: LibraryItemsLayoutProps): JSX.Element {
>
<Toaster />
<SpanBox
css={{
alignSelf: 'flex-start',
'-ms-overflow-style': 'none',
scrollbarWidth: 'none',
'::-webkit-scrollbar': {
display: 'none',
},
'@lgDown': {
display: 'none',
},
}}
>
<PinnedButtons
multiSelectMode={props.multiSelectMode}
layout={props.layout}
items={pinnedSearches ?? []}
searchTerm={props.searchTerm}
applySearchQuery={props.applySearchQuery}
/>
</SpanBox>
{props.isValidating && props.items.length == 0 && <TopBarProgress />}
<div
onDragEnter={(event) => {

View File

@ -620,8 +620,6 @@ const Footer = (props: LibraryFilterMenuProps): JSX.Element => {
position: 'fixed',
bottom: '0%',
alignItems: 'center',
paddingX: '5px',
paddingY: '5px',
backgroundColor: '$thBackground2',
width: LIBRARY_LEFT_MENU_WIDTH,
@ -639,7 +637,7 @@ const Footer = (props: LibraryFilterMenuProps): JSX.Element => {
<SpanBox
css={{
marginLeft: 'auto',
marginRight: '5px',
marginRight: '15px',
}}
>
<SplitButton

View File

@ -14,13 +14,8 @@ import {
X,
} from 'phosphor-react'
import { LayoutType } from './HomeFeedContainer'
import { PrimaryDropdown } from '../PrimaryDropdown'
import { OmnivoreSmallLogo } from '../../elements/images/OmnivoreNameLogo'
import {
DEFAULT_HEADER_HEIGHT,
HeaderSpacer,
useGetHeaderHeight,
} from './HeaderSpacer'
import { DEFAULT_HEADER_HEIGHT, HeaderSpacer } from './HeaderSpacer'
import { LIBRARY_LEFT_MENU_WIDTH } from '../../templates/homeFeed/LibraryFilterMenu'
import { CardCheckbox } from '../../patterns/LibraryCards/LibraryCardStyles'
import { Dropdown, DropdownOption } from '../../elements/DropdownElements'
@ -62,7 +57,7 @@ type LibraryHeaderProps = {
performMultiSelectAction: (action: BulkAction, labelIds?: string[]) => void
}
const controlWidths = (
export const headerControlWidths = (
layout: LayoutType,
multiSelectMode: MultiSelectMode
) => {
@ -87,8 +82,14 @@ export function LibraryHeader(props: LibraryHeaderProps): JSX.Element {
const [small, setSmall] = useState(false)
useEffect(() => {
const handleScroll = () => {
setSmall(window.scrollY > 40)
}
if (typeof window !== 'undefined') {
window.addEventListener('scroll', () => setSmall(window.scrollY > 40))
window.addEventListener('scroll', handleScroll)
}
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
@ -144,7 +145,7 @@ function LargeHeaderLayout(props: LibraryHeaderProps): JSX.Element {
css={{
gap: '10px',
height: '100%',
...controlWidths(props.layout, props.multiSelectMode),
...headerControlWidths(props.layout, props.multiSelectMode),
}}
>
{props.multiSelectMode !== 'off' ? (

View File

@ -8,11 +8,16 @@ import { MoreOptionsIcon } from '../../elements/images/MoreOptionsIcon'
import { PinnedSearch } from '../../../pages/settings/pinned-searches'
import { useRouter } from 'next/router'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { LayoutType } from './HomeFeedContainer'
import { MultiSelectMode } from './LibraryHeader'
type PinnedButtonsProps = {
items: PinnedSearch[]
searchTerm: string | undefined
applySearchQuery: (searchQuery: string) => void
multiSelectMode: MultiSelectMode
layout: LayoutType
}
export const PinnedButtons = (props: PinnedButtonsProps): JSX.Element => {
@ -22,53 +27,82 @@ export const PinnedButtons = (props: PinnedButtonsProps): JSX.Element => {
initialValue: false,
isSessionStorage: false,
})
const [opacity, setOpacity] = useState(1.0)
useEffect(() => {
const handleScroll = () => {
const scrollTop = window.scrollY
const opacityValue = 1 - scrollTop / 15
setOpacity(opacityValue >= 0 ? opacityValue : 0)
}
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [])
if (hidePinnedSearches || !props.items.length) {
return <></>
}
return (
<HStack
alignment="center"
distribution="start"
css={{
width: '100%',
maxWidth: '100%',
pt: '10px',
pb: '0px',
gap: '10px',
bg: 'transparent',
overflowX: 'scroll',
}}
>
{props.items.map((item) => {
const style =
item.search == props.searchTerm ? 'ctaPill' : 'ctaPillUnselected'
return (
<Button
key={item.search}
style={style}
onClick={(event) => {
props.applySearchQuery(item.search)
event.preventDefault()
}}
>
{item.name}
</Button>
)
})}
<HStack alignment="center" distribution="start" css={{ maxWidth: '100%' }}>
<HStack
alignment="center"
distribution="start"
css={{
gap: '10px',
bg: 'transparent',
overflowX: 'scroll',
opacity: opacity,
'@lgDown': {
display: 'none',
},
'@media (min-width: 930px)': {
px: '0px',
maxWidth: '600px',
},
'@media (min-width: 1280px)': {
maxWidth: '950px',
},
'@media (min-width: 1600px)': {
maxWidth: '1260px',
},
}}
>
{props.items.map((item) => {
const style =
item.search == props.searchTerm ? 'ctaPill' : 'ctaPillUnselected'
return (
<Button
key={item.search}
style={style}
onClick={(event) => {
props.applySearchQuery(item.search)
event.preventDefault()
}}
>
{item.name}
</Button>
)
})}
</HStack>
<Dropdown
triggerElement={
<SpanBox
css={{
ml: '10px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '50%',
width: '24px',
height: '24px',
width: '30px',
height: '30px',
border: '1px solid $thBackground4',
backgroundColor: '$thBackground4',
'&:hover': {
bg: '$grayBgHover',
border: '1px solid $grayBgHover',

View File

@ -3,7 +3,10 @@ import { Button } from '../../elements/Button'
import { PrimaryDropdown } from '../PrimaryDropdown'
import { LogoBox } from '../../elements/LogoBox'
import { ReactNode } from 'react'
import { useGetHeaderHeight } from '../homeFeed/HeaderSpacer'
import {
DEFAULT_HEADER_HEIGHT,
useGetHeaderHeight,
} from '../homeFeed/HeaderSpacer'
import { theme } from '../../tokens/stitches.config'
import { ReaderSettingsIcon } from '../../elements/icons/ReaderSettingsIcon'
import { CircleUtilityMenuIcon } from '../../elements/icons/CircleUtilityMenuIcon'
@ -16,7 +19,6 @@ type ReaderHeaderProps = {
}
export function ReaderHeader(props: ReaderHeaderProps): JSX.Element {
const headerHeight = useGetHeaderHeight()
return (
<>
<VStack
@ -29,7 +31,7 @@ export function ReaderHeader(props: ReaderHeaderProps): JSX.Element {
pt: '0px',
position: 'fixed',
width: '100%',
height: headerHeight,
height: DEFAULT_HEADER_HEIGHT,
display: props.alwaysDisplayToolbar ? 'flex' : 'transparent',
pointerEvents: props.alwaysDisplayToolbar ? 'unset' : 'none',
borderBottom: '1px solid transparent',

View File

@ -145,7 +145,7 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
omnivoreYellow: 'rgb(255, 234, 159)',
omnivoreLightGray: 'rgb(125, 125, 125)',
omnivoreCtaYellow: 'rgb(255, 210, 52)',
searchActiveOutline: '#866D15',
searchActiveOutline: 'rgb(255, 210, 52)',
// Reader Colors
readerBg: 'white',
@ -183,6 +183,8 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
thLibraryMenuUnselected: '#898989',
thLibrarySelectionColor: '#FFEA9F',
thLibraryNavigationMenuFooter: '#EFEADE',
thLibraryMenuFooterHover: '#FFFFFF',
thHeaderIconRing: '#D9D9D9',
thHeaderIconInner: '#898989',
@ -303,6 +305,9 @@ const darkThemeSpec = {
thLibraryMenuUnselected: '#898989',
thLibrarySelectionColor: '#3D3D3D',
thLibraryNavigationMenuFooter: '#3D3D3D',
thLibraryMenuFooterHover: '#6A6968',
searchActiveOutline: '#866D15',
thHeaderIconRing: '#3D3D3D',
thHeaderIconInner: '#D9D9D9',
@ -334,10 +339,6 @@ const darkThemeSpec = {
highlight_underline_alpha: '0.5',
highlight_background_alpha: '0.35',
},
shadows: {
cardBoxShadow:
'0px 0px 9px -2px rgba(5, 5, 5, 0.16), 0px 7px 12px rgba(0, 0, 0, 0.13)',
},
}
// This is used by iOS