Move pinned searches to under the bar
This commit is contained in:
@ -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',
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -56,7 +56,7 @@ const TriggerButton = (props: TriggerButtonProps): JSX.Element => {
|
||||
height: '32px',
|
||||
padding: '5px',
|
||||
'&:hover': {
|
||||
bg: '#6A6968',
|
||||
bg: '$thLibraryMenuFooterHover',
|
||||
opacity: '0.7px',
|
||||
},
|
||||
}}
|
||||
|
||||
@ -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()} />
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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' ? (
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user