Merge pull request #1031 from omnivore-app/1017

Menu Component Start
This commit is contained in:
Jackson Harper
2022-08-12 12:28:34 +08:00
committed by GitHub
21 changed files with 839 additions and 4 deletions

View File

@ -20,7 +20,7 @@ export const Button = styled('button', {
},
ctaDarkYellow: {
border: 0,
fontSize: '16px',
fontSize: '14px',
fontWeight: 500,
fontStyle: 'normal',
fontFamily: 'Inter',
@ -28,7 +28,7 @@ export const Button = styled('button', {
cursor: 'pointer',
color: '$omnivoreGray',
bg: '$omnivoreCtaYellow',
p: '10px 12px',
p: '10px 13px',
},
ctaOutlineYellow: {
boxSizing: 'border-box',

View File

@ -15,6 +15,7 @@ export function ProgressBar(props: ProgressBarProps): JSX.Element {
width: '100%',
borderRadius: '$1',
overflow: 'hidden',
backgroundColor: props.backgroundColor,
}}
>
<Box

View File

@ -152,6 +152,15 @@ const textVariants = {
fontWeight: '500',
lineHeight: 'unset',
},
libraryHeader: {
pt: '0px',
m: '0px',
fontSize: 24,
fontFamily: 'inter',
lineHeight: 'unset',
fontWeight: 'medium',
color: '$textSubtle',
},
error: {
color: '$error',
fontSize: '$2',

View File

@ -0,0 +1,21 @@
type LibraryGridLayoutIconProps = {
color: string
}
export function LibraryGridLayoutIcon(props: LibraryGridLayoutIconProps): JSX.Element {
return (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_3573_89627)">
<path d="M9.5 -0.00299072H1.5C0.671573 -0.00299072 0 0.668582 0 1.49701V9.49701C0 10.3254 0.671573 10.997 1.5 10.997H9.5C10.3284 10.997 11 10.3254 11 9.49701V1.49701C11 0.668582 10.3284 -0.00299072 9.5 -0.00299072Z" fill={props.color} />
<path d="M22.5 -0.00299072H14.5C13.6716 -0.00299072 13 0.668582 13 1.49701V9.49701C13 10.3254 13.6716 10.997 14.5 10.997H22.5C23.3284 10.997 24 10.3254 24 9.49701V1.49701C24 0.668582 23.3284 -0.00299072 22.5 -0.00299072Z" fill={props.color} />
<path d="M9.5 12.997H1.5C0.671573 12.997 0 13.6686 0 14.497V22.497C0 23.3254 0.671573 23.997 1.5 23.997H9.5C10.3284 23.997 11 23.3254 11 22.497V14.497C11 13.6686 10.3284 12.997 9.5 12.997Z" fill={props.color} />
<path d="M22.5 12.997H14.5C13.6716 12.997 13 13.6686 13 14.497V22.497C13 23.3254 13.6716 23.997 14.5 23.997H22.5C23.3284 23.997 24 23.3254 24 22.497V14.497C24 13.6686 23.3284 12.997 22.5 12.997Z" fill={props.color} />
</g>
<defs>
<clipPath id="clip0_3573_89627">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>
)
}

View File

@ -0,0 +1,13 @@
type LibraryListLayoutIconProps = {
color: string
}
export function LibraryListLayoutIcon(props: LibraryListLayoutIconProps): JSX.Element {
return (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5 0.747009H1.5C0.671573 0.747009 0 1.41858 0 2.24701V4.74701C0 5.57544 0.671573 6.24701 1.5 6.24701H22.5C23.3284 6.24701 24 5.57544 24 4.74701V2.24701C24 1.41858 23.3284 0.747009 22.5 0.747009Z" fill={props.color} />
<path d="M22.5 9.24701H1.5C0.671573 9.24701 0 9.91858 0 10.747V13.247C0 14.0754 0.671573 14.747 1.5 14.747H22.5C23.3284 14.747 24 14.0754 24 13.247V10.747C24 9.91858 23.3284 9.24701 22.5 9.24701Z" fill={props.color} />
<path d="M22.5 17.747H1.5C0.671573 17.747 0 18.4186 0 19.247V21.747C0 22.5754 0.671573 23.247 1.5 23.247H22.5C23.3284 23.247 24 22.5754 24 21.747V19.247C24 18.4186 23.3284 17.747 22.5 17.747Z" fill={props.color} />
</svg>
)
}

View File

@ -46,7 +46,7 @@ export function GridLinkedItemCard(props: LinkedItemCardProps): JSX.Element {
<ProgressBar
fillPercentage={props.item.readingProgressPercent}
fillColor={theme.colors.highlight.toString()}
backgroundColor={theme.colors.grayTextContrast.toString()}
backgroundColor="transparent"
borderRadius={
props.item.readingProgressPercent === 100 ? '0' : '0px 8px 8px 0px'
}

View File

@ -0,0 +1,178 @@
import { Box, VStack, HStack, SpanBox } from '../../elements/LayoutPrimitives'
import { CoverImage } from '../../elements/CoverImage'
import { StyledText } from '../../elements/StyledText'
import { authoredByText } from '../ArticleSubtitle'
import { MoreOptionsIcon } from '../../elements/images/MoreOptionsIcon'
import { theme } from '../../tokens/stitches.config'
import { CardMenu } from '../CardMenu'
import { LabelChip } from '../../elements/LabelChip'
import { ProgressBar } from '../../elements/ProgressBar'
import type { LinkedItemCardProps } from './CardTypes'
export function LibraryGridCard(props: LinkedItemCardProps): JSX.Element {
return (
<VStack
css={{
p: '12px',
height: '100%',
width: '100%',
maxWidth: '100%',
borderRadius: '8px',
cursor: 'pointer',
wordBreak: 'break-word',
overflow: 'clip',
border: '1px solid $border',
position: 'relative',
}}
alignment="start"
distribution="start"
onClick={() => {
props.handleAction('showDetail')
}}
>
{props.item.image && (
<CoverImage
src={props.item.image}
alt="Link Preview Image"
width="100%"
height={160}
css={{ borderRadius: '8px' }}
onError={(e) => {
;(e.target as HTMLElement).style.display = 'none'
}}
/>
)}
<VStack
distribution="start"
alignment="start"
css={{
px: '0px',
width: '100%',
pl: '$1',
}}
>
<HStack
alignment="start"
distribution="between"
css={{
width: '100%',
p: '0px',
mr: '-12px',
mt: '15px',
display: 'grid',
gridTemplateColumns: '1fr 24px',
gridTemplateRows: '1fr',
}}
>
<CardTitle title={props.item.title} />
{/* <Box
css={{ alignSelf: 'end', alignItems: 'start', height: '100%' }}
onClick={(e) => {
// This is here to prevent menu click events from bubbling
// up and causing us to "click" on the link item.
e.stopPropagation()
}}
>
<CardMenu
item={props.item}
viewer={props.viewer}
triggerElement={
<MoreOptionsIcon
size={24}
strokeColor={theme.colors.grayTextContrast.toString()}
orientation="horizontal"
/>
}
actionHandler={props.handleAction}
/>
</Box> */}
</HStack>
{/* <HStack alignment="start" distribution="between">
<StyledText style="caption" css={{ my: '0', mt: '-$2' }}>
{props.item.author && (
<SpanBox css={{ mr: '8px' }}>
{authoredByText(props.item.author)}
</SpanBox>
)}
<SpanBox css={{ textDecorationLine: 'underline' }}>
{props.originText}
</SpanBox>
</StyledText>
</HStack> */}
</VStack>
<HStack
alignment="start"
distribution="between"
css={{
width: '100%',
pt: '$2',
px: '$1',
pr: '12px',
mt: '7px',
flexGrow: '1',
}}
>
<StyledText
css={{
m: 0,
py: '0px',
mr: '$2',
fontStyle: 'normal',
fontWeight: '400',
fontSize: '14px',
lineHeight: '125%',
color: '$grayTextContrast',
flexGrow: '4',
overflow: 'hidden',
display: '-webkit-box',
WebkitLineClamp: 5,
WebkitBoxOrient: 'vertical',
}}
data-testid="listDesc"
>
{props.item.description}
</StyledText>
</HStack>
<Box css={{ display: 'block', py: '12px' }}>
{props.item.labels?.map(({ name, color }, index) => (
<LabelChip key={index} text={name || ''} color={color} />
))}
</Box>
<ProgressBar
fillPercentage={props.item.readingProgressPercent}
fillColor={theme.colors.highlight.toString()}
backgroundColor={theme.colors.lightBorder.toString()}
borderRadius={
props.item.readingProgressPercent === 100 ? '0' : '0px 8px 8px 0px'
}
/>
</VStack>
)
}
type CardTitleProps = {
title: string
}
function CardTitle(props: CardTitleProps): JSX.Element {
return (
<StyledText
style="listTitle"
data-testid="listTitle"
css={{
mt: '0',
mb: '0',
fontSize: '18px',
textAlign: 'left',
lineHeight: '1.25',
// whiteSpace: 'nowrap',
// textOverflow: 'ellipsis',
width: '100%',
// overflow: 'hidden',
}}
>
{props.title}
</StyledText>
)
}

View File

@ -0,0 +1,174 @@
import Link from 'next/link'
import React, { useEffect, useState } from 'react'
import { useGetLabelsQuery } from '../../lib/networking/queries/useGetLabelsQuery'
import { useGetSubscriptionsQuery } from '../../lib/networking/queries/useGetSubscriptionsQuery'
import { ProSidebar, Menu, MenuItem, SubMenu } from 'react-pro-sidebar'
import { Tag } from 'phosphor-react'
// styles
const proSideBarStyles = {
display: 'inline-block',
}
// Types
type MenuItems = {
label: string
query: string
active?: boolean
icon: string | JSX.Element | null
href: string
}
type DynamicMenuItems = {
labels?: MenuItems[]
subscriptions?: MenuItems[]
}
// Functions
const calculateTodayMenuItem = () => {
const timeZoneHourDiff = -new Date().getTimezoneOffset() / 60
const hrefStr = `?q=in%3Ainbox+saved%3A${
new Date(new Date().getTime() - 24 * 3600000).toISOString().split('T')[0]
}Z%${timeZoneHourDiff}B2..*`
return hrefStr
}
const createDynamicMenuItems = (
labels: Array<any>,
subscriptions: Array<any>
) => {
const labelsList: Array<MenuItems> = []
const subscriptionsList: Array<MenuItems> = []
// Create labels list
if (labels.length) {
labels.map((l) =>
labelsList.push({
label: l.name,
query: `label:"${l.name}"`,
icon: <Tag size={18} weight="light" />,
href: `?q=label:"${l.name}"`,
})
)
}
// create subscriptions list
if (subscriptions.length) {
subscriptions.map((s) =>
subscriptionsList.push({
label: s.name,
query: `subscription:"${s.subscription}"`,
icon: 'subscription',
href: `?q=subscription:"${s.subscription}"`,
})
)
}
return { labels: [...labelsList], subscriptions: [...subscriptionsList] }
}
// Component
export const Menubar = () => {
const { labels } = useGetLabelsQuery()
const { subscriptions } = useGetSubscriptionsQuery()
const [menuList, setMenuList] = useState<Array<MenuItems>>([])
const [dynamicMenuItems, setDynamicMenuItems] = useState<DynamicMenuItems>({})
useEffect(() => {
if (labels || subscriptions) {
setDynamicMenuItems(createDynamicMenuItems(labels, subscriptions))
}
setMenuList([
{
label: 'Home',
query: 'in:inbox',
icon: null,
href: '/home',
active: true,
},
{
label: 'Today',
query: 'in:inbox-label:Newsletter',
icon: null,
href: calculateTodayMenuItem(),
},
{
label: 'Read Later',
query: 'in:inbox-label:Newsletter',
icon: null,
href: `?q=in:inbox+-label:Newsletter`,
},
{
label: 'HighLights',
query: 'type:highlights',
icon: null,
href: `?q=type:highlights`,
},
{
label: 'Newsletters',
query: 'in:inbox label:Newsletter',
icon: null,
href: `?q=in:inbox+label:Newsletter`,
},
])
},[labels, subscriptions])
return (
<ProSidebar style={proSideBarStyles} breakPoint={'sm'}>
<Menu>
{menuList.length > 0 &&
menuList.map((item) => {
return (
<MenuItem
key={item.label}
icon={item.icon}
active={item.active ?? false}
>
<Link passHref href={item.href}>
{item.label}
</Link>
</MenuItem>
)
})}
{dynamicMenuItems.labels &&
<SubMenu
key="labels-list"
title="Labels"
>
{dynamicMenuItems.labels.map((item: MenuItems) => {
return (<MenuItem
key={item.label}
icon={item.icon}
active={item.active ?? false}
>
<Link passHref href={item.href}>
{item.label}
</Link>
</MenuItem>)
})}
</SubMenu>
}
{dynamicMenuItems.subscriptions &&
<SubMenu
key="subscriptions-list"
title="Subscriptions"
>
{dynamicMenuItems.subscriptions.map((item: MenuItems) => {
return (
<MenuItem
key={item.label}
icon={item.icon}
active={item.active ?? false}
>
<Link passHref href={item.href}>
{item.label}
</Link>
</MenuItem>
)
})}
</SubMenu>
}
</Menu>
</ProSidebar>
)
}

View File

@ -0,0 +1,62 @@
import { SpanBox, VStack } from '../../elements/LayoutPrimitives'
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
import { styled } from '../../tokens/stitches.config'
import { Root, Image, Fallback } from '@radix-ui/react-avatar'
type AvatarProps = {
viewer?: UserBasicData
}
export function LibraryAvatar(props: AvatarProps): JSX.Element {
return (
<VStack alignment="center" distribution="start" css={{ pl: '8px', pt: '20px', width: '100%', height: '100%' }}>
<VStack css={{ height: '100%' }}>
<StyledAvatar
css={{
width: '40px',
height: '40px',
borderRadius: '6px',
}}
>
{props.viewer?.profile.pictureUrl
? <StyledImage src={props.viewer.profile.pictureUrl} />
: <StyledFallback>{props.viewer?.name.charAt(0) ?? ''}</StyledFallback>
}
</StyledAvatar>
</VStack>
{/* This spacer is to help align with items in the search box */}
<SpanBox css={{ marginTop: 'auto', height: '10px', width: '100%' }} />
</VStack>
)
}
const StyledAvatar = styled(Root, {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
verticalAlign: 'middle',
overflow: 'hidden',
userSelect: 'none',
})
const StyledImage = styled(Image, {
width: '100%',
height: '100%',
objectFit: 'cover',
'&:hover': {
opacity: '48%',
},
})
const StyledFallback = styled(Fallback, {
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '20px',
backgroundColor: '$omnivoreCtaYellow',
color: '#595959',
})

View File

@ -0,0 +1,35 @@
import { Box, HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { LibraryMenu } from './LibraryMenu'
import { LibraryAvatar } from './LibraryAvatar'
import { LibrarySearchBar } from './LibrarySearchBar'
import { LibraryList } from './LibraryList'
import { LibraryHeadline } from './LibraryHeadline'
export function LibraryContainer(): JSX.Element {
useGetUserPreferences()
const { viewerData } = useGetViewerQuery()
return (
<>
<VStack alignment="start" distribution="start" css={{ width: '100vw', height: '100vh', overflow: 'hidden', bg: '$libraryBackground' }}>
<HStack alignment="start" distribution="start" css={{ width: '100%' }}>
<LibrarySearchBar />
<SpanBox css={{ marginLeft: 'auto', width: '130px', height: '100%' }}>
<LibraryAvatar viewer={viewerData?.me} />
</SpanBox>
</HStack>
<HStack alignment="start" distribution="start" css={{ width: '100%', height: '100%' }}>
<LibraryMenu />
<VStack alignment="start" distribution="start" css={{ width: '100%', height: '100%', mr: '20px' }}>
<LibraryHeadline />
<LibraryList />
</VStack>
</HStack>
</VStack>
</>
)
}

View File

@ -0,0 +1,23 @@
import { HStack } from '../../elements/LayoutPrimitives'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { StyledText } from '../../elements/StyledText'
import { theme } from '../../tokens/stitches.config'
import { LibraryListLayoutIcon } from '../../elements/images/LibraryListLayoutIcon'
import { LibraryGridLayoutIcon } from '../../elements/images/LibraryGridLayoutIcon'
import { Button } from '../../elements/Button'
export function LibraryHeadline(): JSX.Element {
useGetUserPreferences()
return (
<HStack alignment="center" distribution="start" css={{ pt: '4px', pb: '8px', width: '100%', pr: '15px' }}>
<StyledText style="libraryHeader">Home</StyledText>
<HStack alignment="center" distribution="start" css={{ marginLeft: 'auto', gap: '16px' }}>
<Button style="ctaDarkYellow">Add Link</Button>
<LibraryListLayoutIcon color="#D6D6D6" />
<LibraryGridLayoutIcon color={theme.colors.omnivoreCtaYellow.toString()} />
</HStack>
</HStack>
)
}

View File

@ -0,0 +1,114 @@
import { Box } from '../../elements/LayoutPrimitives'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { useMemo, useState } from 'react'
import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { LinkedItemCardAction } from '../../patterns/LibraryCards/CardTypes'
import { LibraryGridCard } from '../../patterns/LibraryCards/LibraryGridCard'
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
export function LibraryList(): JSX.Element {
useGetUserPreferences()
const [layout, setLayout] = useState<LayoutType>('GRID_LAYOUT')
const { viewerData } = useGetViewerQuery()
const defaultQuery = {
limit: 50,
sortDescending: true,
searchQuery: undefined,
}
const { itemsPages, size, setSize, isValidating, performActionOnItem } =
useGetLibraryItemsQuery(defaultQuery)
const libraryItems = useMemo(() => {
const items =
itemsPages?.flatMap((ad) => {
return ad.search.edges
}) || []
return items
}, [itemsPages, performActionOnItem])
return (
<Box css={{ overflowY: 'scroll' }}>
{/* // {!isValidating && items.length == 0 ? (
// <EmptyLibrary
// onAddLinkClicked={() => {
// }}
// />
// ) : ( */}
<Box
css={{
display: 'grid',
gridGap: layout == 'LIST_LAYOUT' ? '0' : '16px',
width: '100%',
gridAutoRows: 'auto',
borderRadius: '8px',
marginBottom: '0px',
paddingRight: '14px',
paddingTop: '0px',
marginTop: layout == 'LIST_LAYOUT' ? '21px' : '0',
paddingBottom: layout == 'LIST_LAYOUT' ? '0px' : '21px',
'@smDown': {
border: 'unset',
width: layout == 'LIST_LAYOUT' ? '100vw' : undefined,
margin: layout == 'LIST_LAYOUT' ? '16px -16px' : undefined,
borderRadius: layout == 'LIST_LAYOUT' ? 0 : undefined,
},
'@lg': {
gridTemplateColumns:
layout == 'LIST_LAYOUT' ? 'none' : '1fr 1fr',
},
'@xl': {
gridTemplateColumns:
layout == 'LIST_LAYOUT' ? 'none' : 'repeat(3, 1fr)',
},
}}
>
{libraryItems.map((linkedItem) => (
<Box
className="linkedItemCard"
data-testid="linkedItemCard"
id={linkedItem.node.id}
tabIndex={0}
key={linkedItem.node.id}
css={{
width: '100%',
'&> div': {
bg: '$libraryBackground',
},
'&:focus': {
'> div': {
bg: '$grayBgActive',
},
},
'&:hover': {
'> div': {
bg: '$grayBgActive',
},
},
}}
>
{viewerData?.me && (
<LibraryGridCard
layout={layout}
item={linkedItem.node}
viewer={viewerData.me}
handleAction={(action: LinkedItemCardAction) => {
console.log('card clicked')
}}
/>
)}
</Box>
))}
</Box>
{/* Extra padding at bottom to give space for scrolling */}
<Box css={{ width: '100%', height: '200px' }} />
</Box>
)
}

View File

@ -0,0 +1,14 @@
import { VStack } from '../../elements/LayoutPrimitives'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { Menubar } from '../Menu'
export function LibraryMenu(): JSX.Element {
useGetUserPreferences()
return (
<VStack alignment="start" distribution="start" css={{ width: '286px', pl: '16px', height: '100%' }}>
<Menubar />
</VStack>
)
}

View File

@ -0,0 +1,97 @@
import { Box, HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useRouter } from 'next/router'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { useState } from 'react'
import { FormInput } from '../../elements/FormElements'
import { Button } from '../../elements/Button'
import { X } from 'phosphor-react'
import { theme } from '../../tokens/stitches.config'
export function LibrarySearchBar(): JSX.Element {
useGetUserPreferences()
const router = useRouter()
const [searchTerm, setSearchTerm] = useState('')
const { viewerData } = useGetViewerQuery()
return (
<>
<VStack alignment="start" distribution="start" css={{ pl: '32px', pt: '20px', width: '100%', height: '110px' }}>
<HStack alignment="start" distribution="start" css={{ width: '100%' }}>
<form
style={{ width: '100%' }}
onSubmit={(event) => {
event.preventDefault()
// props.applySearchQuery(searchTerm || '')
// inputRef.current?.blur()
}}
>
<FormInput
css={{
width: '100%',
height: '80px',
fontFamily: 'Inter',
fontSize: '24px',
}}
type="text"
value={searchTerm}
placeholder="Search"
// onFocus={(event) => {
// event.target.select()
// setFocused(true)
// }}
// onBlur={() => {
// setFocused(false)
// }}
// onChange={(event) => {
// setSearchTerm(event.target.value)
// }}
/>
</form>
{searchTerm && (
<HStack alignment="center" distribution="start" css={{ height: '100%' }}>
<Button
style="plainIcon"
onClick={(event) => {
// event.preventDefault()
// setSearchTerm('')
// props.applySearchQuery('')
// inputRef.current?.blur()
}}
css={{
display: 'flex',
flexDirection: 'row',
mr: '16px',
height: '100%',
alignItems: 'center',
}}
>
<X
width={24}
height={24}
color={theme.colors.grayTextContrast.toString()}
/>
</Button>
<Button
style="ctaDarkYellow"
onClick={(event) => {
// event.preventDefault()
// setSearchTerm('')
// props.applySearchQuery('')
// inputRef.current?.blur()
}}
>
Search
</Button>
</HStack>
)}
</HStack>
<SpanBox css={{ width: '100%', height: '1px', bg: '$grayBorder' }} />
</VStack>
</>
)
}

View File

@ -112,6 +112,7 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
grayBg: '#FFFFFF',
grayBgActive: '#e6e6e6',
grayBorder: '#F0F0F0',
lightBorder: '#F0F0F0',
grayTextContrast: '#3A3939',
graySolid: '#9C9B9A',
textDefault: 'rgba(255, 255, 255, 0.8)',
@ -155,6 +156,12 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
labelButtonsBg: '#F5F5F4',
tooltipIcons: '#FDFAEC',
textSubtle: '#605F5D',
libraryActive: '#F8F8F8',
libraryBackground: '#FFFFFF',
border: '#F0F0F0',
//utility
textNonEssential: 'rgba(10, 8, 6, 0.4)',
overlay: 'rgba(63, 62, 60, 0.2)',
@ -207,6 +214,11 @@ const darkThemeSpec = {
avatarBg: '#000000',
avatarFont: 'rgba(255, 255, 255, 0.8)',
textSubtle: '#AAAAAA',
libraryActive: '#3B3938',
libraryBackground: '#252525',
border: '#323232',
//utility
utilityTextSubtle: 'rgba(255, 255, 255, 0.65)',
textNonEssential: 'rgba(10, 8, 6, 0.4)',

View File

@ -43,6 +43,7 @@
"react-colorful": "^5.5.1",
"react-dom": "^17.0.2",
"react-hot-toast": "^2.1.1",
"react-pro-sidebar": "^0.7.1",
"react-super-responsive-table": "^5.2.1",
"react-topbar-progress-indicator": "^4.1.1",
"react-twitter-widgets": "^1.10.0",

View File

@ -1,5 +1,8 @@
import '../styles/globals.css'
import '../styles/articleInnerStyling.css'
import 'react-pro-sidebar/dist/css/styles.css'
import '../styles/menu.css'
import type { AppProps } from 'next/app'
import { IdProvider } from '@radix-ui/react-id'
import { NextRouter, useRouter } from 'next/router'

View File

@ -0,0 +1,5 @@
import { LibraryContainer } from '../components/templates/library/LibraryContainer'
export default function Library(): JSX.Element {
return <LibraryContainer />
}

View File

@ -0,0 +1,16 @@
import { ComponentStory, ComponentMeta } from '@storybook/react'
//import { updateThemeLocally } from '../lib/themeUpdater'
//import { ThemeId } from '../components/tokens/stitches.config'
import { Menubar } from '../components/templates/Menu'
export default {
title: 'Components/Menu',
component: Menubar,
} as ComponentMeta<typeof Menubar>
const Template: ComponentStory<typeof Menubar> = () => (
<Menubar/>
)
export const MenuStory = Template.bind({})

View File

@ -0,0 +1,30 @@
/* Menu Override styles */
.pro-sidebar > .pro-sidebar-inner, .pro-sidebar .pro-menu a {
background-color: var(--colors-libraryBackground);
color: var(--colors-utilityTextDefault);
}
.pro-sidebar .pro-menu > ul > .pro-sub-menu > .pro-inner-list-item {
color: var(--colors-utilityTextDefault);
background-color: var(--colors-libraryBackground);
}
.pro-sidebar .pro-menu a:hover {
color: var(--colors-utilityTextDefault);
}
.pro-sidebar .pro-menu .pro-menu-item > .pro-inner-item {
padding: 8px 20px 3px 20px;
}
/* .pro-sidebar .pro-menu .active > .pro-inner-item {
background-color: #F8F8F8;
border-radius: 8px;
} */
.pro-sidebar .pro-menu .pro-menu-item > .pro-inner-item > .pro-icon-wrapper {
width: 20px;
min-width: 0;
height: 25px;
}

View File

@ -4531,7 +4531,7 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@popperjs/core@^2.5.4", "@popperjs/core@^2.6.0":
"@popperjs/core@^2.4.0", "@popperjs/core@^2.5.4", "@popperjs/core@^2.6.0":
version "2.11.5"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
@ -10641,6 +10641,11 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
classnames@^2.2.6:
version "2.3.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
clean-css@^4.2.3:
version "4.2.4"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178"
@ -21134,6 +21139,16 @@ react-popper@^2.2.4:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-pro-sidebar@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/react-pro-sidebar/-/react-pro-sidebar-0.7.1.tgz#0b5edca0809ff6a23bda188c5db370f880690ee7"
integrity sha512-Iy1X8ce4t5Vqz4CsyzjwokGUE3/IObgmYzS0ins7/2eWKle0SMUPaWdgMKFIVjtVrMr5vmjPbRicq8FxnVaf8A==
dependencies:
"@popperjs/core" "^2.4.0"
classnames "^2.2.6"
react-slidedown "^2.4.5"
resize-observer-polyfill "^1.5.1"
react-refresh@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
@ -21183,6 +21198,13 @@ react-sizeme@^3.0.1:
shallowequal "^1.1.0"
throttle-debounce "^3.0.1"
react-slidedown@^2.4.5:
version "2.4.7"
resolved "https://registry.yarnpkg.com/react-slidedown/-/react-slidedown-2.4.7.tgz#c09e72bba8aac25018fd644ece041da771854589"
integrity sha512-HGDfrqo70r1WVE0DwrySPdCT27/2wcZaJYh5kOnmuPSCtjDDJrNkDdn4Ep/cma2VVfwupeAGhbc2pbrGThU6VQ==
dependencies:
tslib "^2.0.0"
react-style-singleton@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
@ -21763,6 +21785,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"