The layouts have been extracted to a separate package (@tesseract-design/viewfinder) which can be found in the Modal Pack Registry.master
@@ -1,5 +1,6 @@ | |||||
body { | body { | ||||
margin: 0; | margin: 0; | ||||
/* overflow: overlay; */ | |||||
} | } | ||||
h1 { | h1 { | ||||
@@ -0,0 +1,41 @@ | |||||
import Link from '../Link' | |||||
import styled from 'styled-components' | |||||
const BrandBase = styled(Link)({ | |||||
display: 'block', | |||||
textDecoration: 'none', | |||||
fontSize: '1.5rem', | |||||
fontWeight: 'bold', | |||||
fontStretch: '75%', | |||||
textTransform: 'uppercase', | |||||
width: '2rem', | |||||
textAlign: 'center', | |||||
'@media (min-width: 720px)': { | |||||
width: '8rem', | |||||
textAlign: 'left', | |||||
}, | |||||
}) | |||||
const Hide = styled('span')({ | |||||
display: 'none', | |||||
'@media (min-width: 720px)': { | |||||
display: 'inline', | |||||
}, | |||||
}) | |||||
const Brand = () => { | |||||
return ( | |||||
<BrandBase | |||||
href={{ | |||||
pathname: '/', | |||||
}} | |||||
> | |||||
B | |||||
<Hide> | |||||
rand | |||||
</Hide> | |||||
</BrandBase> | |||||
) | |||||
} | |||||
export default Brand |
@@ -1,6 +1,25 @@ | |||||
import * as React from 'react' | |||||
import NextLink from 'next/link' | import NextLink from 'next/link' | ||||
import {UrlObject} from 'url'; | |||||
const Link = ({ href, as, prefetch, replace, shallow, component: Component = 'a', ...etcProps }) => { | |||||
type Props = { | |||||
href: UrlObject, | |||||
as?: UrlObject, | |||||
prefetch?: boolean, | |||||
replace?: boolean, | |||||
shallow?: boolean, | |||||
component?: React.ElementType, | |||||
} | |||||
const Link: React.FC<Props> = ({ | |||||
href, | |||||
as, | |||||
prefetch, | |||||
replace, | |||||
shallow, | |||||
component: Component = 'a', | |||||
...etcProps | |||||
}) => { | |||||
return ( | return ( | ||||
<NextLink | <NextLink | ||||
href={href} | href={href} | ||||
@@ -1,68 +0,0 @@ | |||||
import * as React from 'react' | |||||
import styled from 'styled-components'; | |||||
import TopBar from '../../widgets/TopBar'; | |||||
import {UrlObject} from 'url'; | |||||
const Main = styled('main')({ | |||||
boxSizing: 'border-box', | |||||
}) | |||||
export const Container = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
margin: '0 auto', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
width: '100%', | |||||
}) | |||||
type Props = { | |||||
query?: string, | |||||
brand?: React.ReactNode, | |||||
onSearch?: React.FormEventHandler, | |||||
searchLabel?: string, | |||||
searchName?: string, | |||||
searchHint?: string, | |||||
linkComponent?: React.ElementType, | |||||
menuLink?: UrlObject, | |||||
userLink?: UrlObject, | |||||
menuLinkLabel?: string, | |||||
userLinkLabel?: string, | |||||
} | |||||
const BasicLayout: React.FC<Props> = ({ | |||||
query, | |||||
children, | |||||
brand, | |||||
onSearch, | |||||
searchLabel, | |||||
searchName, | |||||
searchHint, | |||||
linkComponent, | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | |||||
}) => { | |||||
return ( | |||||
<> | |||||
<TopBar | |||||
query={query} | |||||
brand={brand} | |||||
onSearch={onSearch} | |||||
searchHint={searchHint} | |||||
searchLabel={searchLabel} | |||||
searchName={searchName} | |||||
linkComponent={linkComponent} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
/> | |||||
<Main> | |||||
{children} | |||||
</Main> | |||||
</> | |||||
) | |||||
} | |||||
export default BasicLayout |
@@ -1,149 +0,0 @@ | |||||
import * as React from 'react'; | |||||
import styled, {createGlobalStyle} from 'styled-components'; | |||||
import TopBar from '../../widgets/TopBar'; | |||||
import {UrlObject} from 'url'; | |||||
const DisableScrolling = createGlobalStyle({ | |||||
'body': { | |||||
overflow: 'hidden', | |||||
'@media (min-width: 1080px)': { | |||||
overflow: 'auto', | |||||
}, | |||||
}, | |||||
}) | |||||
const Main = styled('main')({ | |||||
boxSizing: 'border-box', | |||||
'@media (min-width: 1080px)': { | |||||
paddingLeft: 'calc(50% - var(--width-base, 360px) * 0.5)', | |||||
}, | |||||
}) | |||||
const SidebarOverflow = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
overflow: 'auto', | |||||
scrollbarWidth: 'none', | |||||
'::-webkit-scrollbar': { | |||||
display: 'none', | |||||
}, | |||||
}) | |||||
const LeftSidebar = styled('div')({ | |||||
'--width-base': '360px', | |||||
'--size-menu': '4rem', | |||||
boxSizing: 'border-box', | |||||
position: 'fixed', | |||||
top: 0, | |||||
left: '-100%', | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
overflow: 'hidden', | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
width: 'calc(50% - var(--width-base, 360px) * 0.5)', | |||||
left: 0, | |||||
}, | |||||
}) | |||||
const OpenLeftSidebar = styled(LeftSidebar)({ | |||||
left: 0, | |||||
}) | |||||
export const SidebarContainer = styled('div')({ | |||||
margin: '0 auto', | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
'@media (min-width: 1080px)': { | |||||
width: 'var(--width-base, 360px)', | |||||
marginRight: 0, | |||||
}, | |||||
}) | |||||
export const Container = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
width: '100%', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
marginRight: 'auto', | |||||
marginLeft: 'auto', | |||||
'@media (min-width: 1080px)': { | |||||
marginLeft: 0, | |||||
}, | |||||
}) | |||||
type Props = { | |||||
query?: string, | |||||
onSearch?: React.FormEventHandler, | |||||
searchLabel?: string, | |||||
searchName?: string, | |||||
searchHint?: string, | |||||
brand?: React.ReactNode, | |||||
linkComponent?: React.ElementType, | |||||
sidebarMain?: React.ReactChild, | |||||
sidebarMainOpen?: boolean, | |||||
menuLink?: UrlObject, | |||||
userLink?: UrlObject, | |||||
menuLinkLabel?: string, | |||||
userLinkLabel?: string, | |||||
} | |||||
const LeftSidebarLayout: React.FC<Props> = ({ | |||||
query, | |||||
sidebarMain, | |||||
sidebarMainOpen, | |||||
children, | |||||
onSearch, | |||||
searchLabel, | |||||
searchName, | |||||
searchHint, | |||||
brand, | |||||
linkComponent, | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | |||||
}) => { | |||||
const LeftSidebarComponent = sidebarMainOpen ? OpenLeftSidebar : LeftSidebar | |||||
return ( | |||||
<> | |||||
{ | |||||
sidebarMainOpen | |||||
&& ( | |||||
<DisableScrolling /> | |||||
) | |||||
} | |||||
<TopBar | |||||
wide | |||||
query={query} | |||||
withMenu | |||||
onSearch={onSearch} | |||||
searchHint={searchHint} | |||||
searchLabel={searchLabel} | |||||
searchName={searchName} | |||||
brand={brand} | |||||
linkComponent={linkComponent} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
/> | |||||
<LeftSidebarComponent> | |||||
<SidebarOverflow> | |||||
{sidebarMain} | |||||
</SidebarOverflow> | |||||
</LeftSidebarComponent> | |||||
<Main> | |||||
{children} | |||||
</Main> | |||||
</> | |||||
) | |||||
} | |||||
export default LeftSidebarLayout |
@@ -1,532 +0,0 @@ | |||||
import * as React from 'react'; | |||||
import * as T from '@tesseract-design/react-common'; | |||||
import styled, { createGlobalStyle } from 'styled-components'; | |||||
import TopBar from '../../widgets/TopBar'; | |||||
import {UrlObject} from 'url'; | |||||
const DisableScrolling = createGlobalStyle({ | |||||
'body': { | |||||
overflow: 'hidden', | |||||
'@media (min-width: 1080px)': { | |||||
overflow: 'auto', | |||||
}, | |||||
}, | |||||
}) | |||||
const Wrapper = styled('div')({ | |||||
'--width-base': '360px', | |||||
'--size-menu': '4rem', | |||||
'--height-topbar': '4rem', | |||||
}) | |||||
const Main = styled('main')({ | |||||
boxSizing: 'border-box', | |||||
paddingBottom: 'var(--size-menu, 4rem)', | |||||
'@media (min-width: 1080px)': { | |||||
paddingLeft: 'calc(50% - var(--width-base, 360px) * 0.5)', | |||||
paddingBottom: 0, | |||||
}, | |||||
}) | |||||
const LeftSidebar = styled('div')({ | |||||
boxSizing: 'border-box', | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
overflow: 'hidden', | |||||
display: 'contents', | |||||
left: 'calc(var(--width-base, 360px) * -1)', | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
position: 'fixed', | |||||
top: 0, | |||||
left: 0, | |||||
width: 'calc(50% - var(--width-base, 360px) * 0.5)', | |||||
height: '100%', | |||||
display: 'block', | |||||
}, | |||||
}) | |||||
const SidebarMain = styled('div')({ | |||||
scrollbarWidth: 'none', | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
boxSizing: 'border-box', | |||||
position: 'fixed', | |||||
top: 0, | |||||
right: '100%', | |||||
width: '100%', | |||||
height: '100%', | |||||
overflow: 'auto', | |||||
paddingTop: 'inherit', | |||||
paddingBottom: 'var(--size-menu, 4rem)', | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'::-webkit-scrollbar': { | |||||
display: 'none', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
position: 'absolute', | |||||
right: 0, | |||||
width: 'calc(var(--width-base, 360px) - var(--size-menu, 4rem))', | |||||
marginLeft: 'auto', | |||||
paddingBottom: 0, | |||||
}, | |||||
}) | |||||
const OpenSidebarMain = styled(SidebarMain)({ | |||||
right: 0, | |||||
}) | |||||
const SidebarMenu = styled('div')({ | |||||
boxSizing: 'border-box', | |||||
scrollbarWidth: 'none', | |||||
'::-webkit-scrollbar': { | |||||
display: 'none', | |||||
}, | |||||
position: 'fixed', | |||||
bottom: 0, | |||||
left: 0, | |||||
width: '100%', | |||||
height: 'var(--size-menu, 4rem)', | |||||
zIndex: 1, | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
top: 0, | |||||
marginLeft: 'auto', | |||||
position: 'absolute', | |||||
height: '100%', | |||||
paddingTop: 'inherit', | |||||
overflow: 'auto', | |||||
zIndex: 'auto', | |||||
}, | |||||
}) | |||||
const SidebarMenuSize = styled('div')({ | |||||
display: 'flex', | |||||
width: '100%', | |||||
height: '100%', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
margin: '0 auto', | |||||
'@media (min-width: 1080px)': { | |||||
maxWidth: 'none', | |||||
marginRight: 0, | |||||
flexDirection: 'column', | |||||
justifyContent: 'space-between', | |||||
alignItems: 'flex-end', | |||||
}, | |||||
}) | |||||
const SidebarMenuGroup = styled('div')({ | |||||
display: 'contents', | |||||
'@media (min-width: 1080px)': { | |||||
width: '100%', | |||||
display: 'block', | |||||
}, | |||||
}) | |||||
const MoreItems = styled('div')({ | |||||
position: 'fixed', | |||||
top: 0, | |||||
left: '-100%', | |||||
width: '100%', | |||||
height: '100%', | |||||
paddingTop: 'var(--height-topbar, 4rem)', | |||||
paddingBottom: 'var(--size-menu, 4rem)', | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
zIndex: -1, | |||||
boxSizing: 'border-box', | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
display: 'contents', | |||||
}, | |||||
}) | |||||
const OpenMoreItems = styled(MoreItems)({ | |||||
left: 0, | |||||
}) | |||||
const MoreItemsScroll = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
overflow: 'auto', | |||||
'@media (min-width: 1080px)': { | |||||
display: 'contents', | |||||
}, | |||||
}) | |||||
const MorePrimarySidebarMenuGroup = styled(SidebarMenuGroup)({ | |||||
'@media (min-width: 1080px)': { | |||||
flex: 'auto', | |||||
}, | |||||
}) | |||||
const MoreSecondarySidebarMenuGroup = styled(SidebarMenuGroup)({ | |||||
'@media (min-width: 1080px)': { | |||||
order: 4, | |||||
}, | |||||
}) | |||||
const SidebarMenuItem = styled('span')({ | |||||
width: 0, | |||||
flex: 'auto', | |||||
height: 'var(--size-menu, 4rem)', | |||||
'> *': { | |||||
height: '100%', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
width: 'auto !important', | |||||
flex: '0 1 auto', | |||||
'> *': { | |||||
height: 'auto', | |||||
} | |||||
}, | |||||
}) | |||||
const MoreSidebarMenuItem = styled('span')({ | |||||
display: 'block', | |||||
height: 'var(--size-menu, 4rem)', | |||||
'> *': { | |||||
height: '100%', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
width: 'auto !important', | |||||
flex: '0 1 auto', | |||||
}, | |||||
}) | |||||
const MoreToggleSidebarMenuItem = styled(SidebarMenuItem)({ | |||||
'@media (min-width: 1080px)': { | |||||
display: 'none', | |||||
}, | |||||
}) | |||||
const SidebarMenuItemIcon = styled('span')({ | |||||
display: 'block', | |||||
'@media (min-width: 1080px)': { | |||||
width: 'var(--size-menu, 4rem)', | |||||
height: 'var(--size-menu, 4rem)', | |||||
display: 'grid', | |||||
placeContent: 'center', | |||||
}, | |||||
}) | |||||
const MoreSidebarMenuItemIcon = styled('span')({ | |||||
marginRight: '1rem', | |||||
display: 'block', | |||||
'@media (min-width: 1080px)': { | |||||
width: 'var(--size-menu, 4rem)', | |||||
height: 'var(--size-menu, 4rem)', | |||||
display: 'grid', | |||||
placeContent: 'center', | |||||
marginRight: 0, | |||||
}, | |||||
}) | |||||
const SidebarMenuContainer = styled('span')({ | |||||
boxSizing: 'border-box', | |||||
display: 'grid', | |||||
placeContent: 'center', | |||||
width: '100%', | |||||
textAlign: 'center', | |||||
'@media (min-width: 1080px)': { | |||||
display: 'flex', | |||||
justifyContent: 'flex-start', | |||||
alignItems: 'center', | |||||
width: 'var(--width-base, 360px)', | |||||
marginLeft: 'auto', | |||||
paddingRight: '1rem', | |||||
textAlign: 'left', | |||||
boxSizing: 'border-box', | |||||
}, | |||||
}) | |||||
const MoreSidebarMenuContainer = styled('div')({ | |||||
display: 'flex', | |||||
justifyContent: 'flex-start', | |||||
alignItems: 'center', | |||||
width: 'calc(var(--width-base, 360px) * 2)', | |||||
margin: '0 auto', | |||||
padding: '0 1rem', | |||||
textAlign: 'left', | |||||
boxSizing: 'border-box', | |||||
'@media (min-width: 1080px)': { | |||||
marginRight: 0, | |||||
width: 'var(--width-base, 360px)', | |||||
paddingLeft: 0, | |||||
}, | |||||
}) | |||||
export const Container = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
width: '100%', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
marginRight: 'auto', | |||||
marginLeft: 'auto', | |||||
'@media (min-width: 1080px)': { | |||||
marginLeft: 0, | |||||
}, | |||||
}) | |||||
export const SidebarMainContainer = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
width: '100%', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
margin: '0 auto', | |||||
'@media (min-width: 1080px)': { | |||||
maxWidth: 'none', | |||||
}, | |||||
}) | |||||
type MenuItem = { | |||||
id: string, | |||||
label: string, | |||||
url: UrlObject, | |||||
secondary?: boolean, | |||||
icon: React.ReactChild, | |||||
} | |||||
type Props = { | |||||
query?: string, | |||||
onSearch?: React.FormEventHandler, | |||||
searchLabel?: string, | |||||
searchName?: string, | |||||
searchHint?: string, | |||||
brand?: React.ReactNode, | |||||
linkComponent?: React.ElementType, | |||||
sidebarMain?: React.ReactChild, | |||||
sidebarMenuItems?: MenuItem[], | |||||
sidebarMainOpen?: boolean, | |||||
menuLink?: UrlObject, | |||||
userLink?: UrlObject, | |||||
menuLinkLabel?: string, | |||||
userLinkLabel?: string, | |||||
moreItemsOpen?: boolean, | |||||
} | |||||
const LeftSidebarWithMenuLayout: React.FC<Props> = ({ | |||||
query, | |||||
children, | |||||
sidebarMain, | |||||
sidebarMenuItems, | |||||
sidebarMainOpen, | |||||
brand, | |||||
onSearch, | |||||
searchLabel, | |||||
searchName, | |||||
searchHint, | |||||
linkComponent: LinkComponent = 'a', | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | |||||
moreItemsOpen, | |||||
}) => { | |||||
const SidebarMainComponent = sidebarMainOpen ? OpenSidebarMain : SidebarMain | |||||
const MoreItemsComponent = moreItemsOpen ? OpenMoreItems : MoreItems | |||||
const primarySidebarMenuItems = sidebarMenuItems.filter(s => !s.secondary) | |||||
const secondarySidebarMenuItems = sidebarMenuItems.filter(s => s.secondary) | |||||
const visibleSecondarySidebarMenuItems = secondarySidebarMenuItems.slice(0, 1) | |||||
const moreSecondarySidebarMenuItems = secondarySidebarMenuItems.slice(1) | |||||
const visiblePrimarySidebarMenuItems = ( | |||||
visibleSecondarySidebarMenuItems.length === 1 | |||||
? primarySidebarMenuItems.slice(0, 3) | |||||
: primarySidebarMenuItems.slice(0, 4) | |||||
) | |||||
const morePrimarySidebarMenuItems = ( | |||||
visibleSecondarySidebarMenuItems.length === 1 | |||||
? primarySidebarMenuItems.slice(3) | |||||
: primarySidebarMenuItems.slice(4) | |||||
) | |||||
return ( | |||||
<> | |||||
{ | |||||
(sidebarMainOpen || moreItemsOpen) | |||||
&& ( | |||||
<DisableScrolling /> | |||||
) | |||||
} | |||||
<Wrapper> | |||||
<TopBar | |||||
withMenu | |||||
query={query} | |||||
wide | |||||
brand={brand} | |||||
onSearch={onSearch} | |||||
linkComponent={LinkComponent} | |||||
searchHint={searchHint} | |||||
searchLabel={searchLabel} | |||||
searchName={searchName} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
/> | |||||
<LeftSidebar> | |||||
<SidebarMenu> | |||||
<SidebarMenuSize> | |||||
<SidebarMenuGroup> | |||||
{visiblePrimarySidebarMenuItems.map((item) => { | |||||
return ( | |||||
<SidebarMenuItem | |||||
key={item.id} | |||||
> | |||||
<LinkComponent | |||||
href={item.url} | |||||
style={{ | |||||
display: 'flex', | |||||
alignItems: 'center', | |||||
textDecoration: 'none', | |||||
width: '100%', | |||||
}} | |||||
> | |||||
<SidebarMenuContainer> | |||||
<SidebarMenuItemIcon> | |||||
{item.icon} | |||||
</SidebarMenuItemIcon> | |||||
{item.label} | |||||
</SidebarMenuContainer> | |||||
</LinkComponent> | |||||
</SidebarMenuItem> | |||||
) | |||||
})} | |||||
</SidebarMenuGroup> | |||||
<MoreItemsComponent> | |||||
<MoreItemsScroll> | |||||
<MorePrimarySidebarMenuGroup> | |||||
{morePrimarySidebarMenuItems.map((item) => { | |||||
return ( | |||||
<MoreSidebarMenuItem | |||||
key={item.id} | |||||
> | |||||
<LinkComponent | |||||
href={item.url} | |||||
style={{ | |||||
display: 'flex', | |||||
alignItems: 'center', | |||||
textDecoration: 'none', | |||||
width: '100%', | |||||
}} | |||||
> | |||||
<MoreSidebarMenuContainer> | |||||
<MoreSidebarMenuItemIcon> | |||||
{item.icon} | |||||
</MoreSidebarMenuItemIcon> | |||||
{item.label} | |||||
</MoreSidebarMenuContainer> | |||||
</LinkComponent> | |||||
</MoreSidebarMenuItem> | |||||
) | |||||
})} | |||||
</MorePrimarySidebarMenuGroup> | |||||
<MoreSecondarySidebarMenuGroup> | |||||
{moreSecondarySidebarMenuItems.map((item) => { | |||||
return ( | |||||
<MoreSidebarMenuItem | |||||
key={item.id} | |||||
> | |||||
<LinkComponent | |||||
href={item.url} | |||||
style={{ | |||||
display: 'flex', | |||||
alignItems: 'center', | |||||
textDecoration: 'none', | |||||
width: '100%', | |||||
}} | |||||
> | |||||
<MoreSidebarMenuContainer> | |||||
<MoreSidebarMenuItemIcon> | |||||
{item.icon} | |||||
</MoreSidebarMenuItemIcon> | |||||
{item.label} | |||||
</MoreSidebarMenuContainer> | |||||
</LinkComponent> | |||||
</MoreSidebarMenuItem> | |||||
) | |||||
})} | |||||
</MoreSecondarySidebarMenuGroup> | |||||
</MoreItemsScroll> | |||||
</MoreItemsComponent> | |||||
<MoreToggleSidebarMenuItem> | |||||
<SidebarMenuItem> | |||||
<LinkComponent | |||||
href={{ | |||||
query: { | |||||
more: '', | |||||
} | |||||
}} | |||||
style={{ | |||||
display: 'flex', | |||||
alignItems: 'center', | |||||
textDecoration: 'none', | |||||
width: '100%', | |||||
}} | |||||
shallow | |||||
> | |||||
<SidebarMenuContainer> | |||||
<SidebarMenuItemIcon> | |||||
<T.Icon | |||||
name="more-horizontal" | |||||
label="" | |||||
/> | |||||
</SidebarMenuItemIcon> | |||||
More | |||||
</SidebarMenuContainer> | |||||
</LinkComponent> | |||||
</SidebarMenuItem> | |||||
</MoreToggleSidebarMenuItem> | |||||
{ | |||||
visibleSecondarySidebarMenuItems.length > 0 | |||||
&& ( | |||||
<SidebarMenuGroup> | |||||
{visibleSecondarySidebarMenuItems.map((item, i) => ( | |||||
<SidebarMenuItem | |||||
key={item.id} | |||||
> | |||||
<LinkComponent | |||||
href={item.url} | |||||
style={{ | |||||
display: 'flex', | |||||
alignItems: 'center', | |||||
textDecoration: 'none', | |||||
width: '100%', | |||||
}} | |||||
> | |||||
<SidebarMenuContainer> | |||||
<SidebarMenuItemIcon> | |||||
{item.icon} | |||||
</SidebarMenuItemIcon> | |||||
{item.label} | |||||
</SidebarMenuContainer> | |||||
</LinkComponent> | |||||
</SidebarMenuItem> | |||||
))} | |||||
</SidebarMenuGroup> | |||||
) | |||||
} | |||||
</SidebarMenuSize> | |||||
</SidebarMenu> | |||||
<SidebarMainComponent> | |||||
{sidebarMain} | |||||
</SidebarMainComponent> | |||||
</LeftSidebar> | |||||
<Main> | |||||
{children} | |||||
</Main> | |||||
</Wrapper> | |||||
</> | |||||
) | |||||
} | |||||
export default LeftSidebarWithMenuLayout |
@@ -1,116 +0,0 @@ | |||||
import * as React from 'react'; | |||||
import styled from 'styled-components'; | |||||
import TopBar from '../../widgets/TopBar'; | |||||
import {UrlObject} from 'url'; | |||||
const Main = styled('main')({ | |||||
boxSizing: 'border-box', | |||||
'@media (min-width: 1080px)': { | |||||
paddingRight: 'calc(50% - var(--width-base, 360px) * 0.5)', | |||||
}, | |||||
}) | |||||
const RightSidebar = styled('div')({ | |||||
'--width-base': '360px', | |||||
boxSizing: 'border-box', | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
// prevent collapse of margin | |||||
'::after': { | |||||
content: "''", | |||||
display: 'block', | |||||
paddingBottom: 1, | |||||
marginTop: -1, | |||||
boxSizing: 'border-box', | |||||
}, | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
position: 'absolute', | |||||
top: 0, | |||||
right: 0, | |||||
width: 'calc(50% - var(--width-base, 360px) * 0.5)', | |||||
height: '100%', | |||||
}, | |||||
}) | |||||
export const SidebarContainer = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
width: '100%', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
margin: '0 auto', | |||||
'@media (min-width: 1080px)': { | |||||
width: 'var(--width-base, 360px)', | |||||
marginLeft: 0, | |||||
}, | |||||
}) | |||||
export const Container = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
width: '100%', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
margin: '0 auto', | |||||
'@media (min-width: 1080px)': { | |||||
marginRight: 0, | |||||
}, | |||||
}) | |||||
type Props = { | |||||
query?: string, | |||||
onSearch?: React.FormEventHandler, | |||||
searchLabel?: string, | |||||
searchName?: string, | |||||
searchHint?: string, | |||||
brand?: React.ReactNode, | |||||
linkComponent?: React.ElementType, | |||||
sidebarMain?: React.ReactChild, | |||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel?: string, | |||||
userLinkLabel?: string, | |||||
} | |||||
const RightSidebarLayout: React.FC<Props> = ({ | |||||
query, | |||||
sidebarMain, | |||||
children, | |||||
brand, | |||||
linkComponent, | |||||
searchHint, | |||||
searchName, | |||||
searchLabel, | |||||
onSearch, | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | |||||
}) => { | |||||
return ( | |||||
<> | |||||
<TopBar | |||||
query={query} | |||||
wide | |||||
brand={brand} | |||||
linkComponent={linkComponent} | |||||
searchHint={searchHint} | |||||
searchName={searchName} | |||||
searchLabel={searchLabel} | |||||
onSearch={onSearch} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
/> | |||||
<Main> | |||||
{children} | |||||
</Main> | |||||
<RightSidebar> | |||||
{sidebarMain} | |||||
</RightSidebar> | |||||
</> | |||||
) | |||||
} | |||||
export default RightSidebarLayout |
@@ -1,183 +0,0 @@ | |||||
import * as React from 'react' | |||||
import styled from 'styled-components' | |||||
import * as T from '@tesseract-design/react-common' | |||||
import {UrlObject} from 'url'; | |||||
const Base = styled('div')({ | |||||
position: 'fixed', | |||||
top: 0, | |||||
left: 0, | |||||
width: '100%', | |||||
height: 'var(--height-topbar, 4rem)', | |||||
backgroundColor: 'var(--color-bg, white)', | |||||
zIndex: 2, | |||||
'@media (prefers-color-scheme: dark)': { | |||||
backgroundColor: 'var(--color-bg, black)', | |||||
}, | |||||
'~ *': { | |||||
paddingTop: 'var(--height-topbar, 4rem)', | |||||
}, | |||||
'~ main ~ *': { | |||||
paddingTop: 0, | |||||
}, | |||||
'@media (min-width: 1080px)': { | |||||
'~ main ~ *': { | |||||
paddingTop: 'var(--height-topbar, 4rem)', | |||||
}, | |||||
}, | |||||
}) | |||||
const Container = styled('div')({ | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
margin: '0 auto', | |||||
maxWidth: 'calc(var(--width-base, 360px) * 2)', | |||||
width: '100%', | |||||
height: '100%', | |||||
display: 'flex', | |||||
alignItems: 'center', | |||||
}) | |||||
const WideContainer = styled(Container)({ | |||||
'@media (min-width: 1080px)': { | |||||
maxWidth: 'calc(var(--width-base, 360px) * 3)', | |||||
}, | |||||
}) | |||||
const BrandContainer = styled('div')({ | |||||
width: '6rem', | |||||
'@media (min-width: 720px)': { | |||||
width: '8rem', | |||||
}, | |||||
}) | |||||
const SearchContainer = styled('form')({ | |||||
flex: 'auto', | |||||
padding: '0 1rem', | |||||
boxSizing: 'border-box', | |||||
':first-child': { | |||||
paddingLeft: 0, | |||||
}, | |||||
}) | |||||
const UserContainer = styled('div')({ | |||||
textAlign: 'right', | |||||
height: '100%', | |||||
whiteSpace: 'nowrap', | |||||
'@media (min-width: 720px)': { | |||||
minWidth: '8rem', | |||||
}, | |||||
}) | |||||
const MenuUserLinkContainer = styled('span')({ | |||||
'@media (min-width: 1080px)': { | |||||
position: 'absolute', | |||||
left: -999999, | |||||
}, | |||||
}) | |||||
type Props = { | |||||
query?: string, | |||||
onSearch?: React.FormEventHandler, | |||||
searchLabel?: string, | |||||
searchName?: string, | |||||
searchHint?: string, | |||||
wide?: boolean, | |||||
withMenu?: boolean, | |||||
brand?: React.ReactNode, | |||||
linkComponent?: React.ElementType, | |||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel?: string, | |||||
userLinkLabel?: string, | |||||
} | |||||
const TopBar: React.FC<Props> = ({ | |||||
query, | |||||
onSearch, | |||||
searchLabel = 'Search', | |||||
searchName = 'q', | |||||
searchHint = 'e.g. keywords, names…', | |||||
wide, | |||||
withMenu, | |||||
brand, | |||||
linkComponent: LinkComponent = 'a', | |||||
menuLink, | |||||
menuLinkLabel = 'Menu', | |||||
userLink, | |||||
userLinkLabel = 'Guest', | |||||
}) => { | |||||
const ContainerComponent = wide ? WideContainer : Container | |||||
return ( | |||||
<Base> | |||||
<ContainerComponent> | |||||
{ | |||||
Boolean(brand) | |||||
&& ( | |||||
<BrandContainer> | |||||
{brand} | |||||
</BrandContainer> | |||||
) | |||||
} | |||||
<SearchContainer | |||||
onSubmit={onSearch} | |||||
> | |||||
<T.TextInput | |||||
name={searchName} | |||||
label={searchLabel} | |||||
hint={searchHint} | |||||
defaultValue={query} | |||||
border | |||||
alternate | |||||
indicator={ | |||||
<T.Icon | |||||
name="search" | |||||
label="" | |||||
/> | |||||
} | |||||
/> | |||||
</SearchContainer> | |||||
<UserContainer> | |||||
{ | |||||
withMenu | |||||
&& ( | |||||
<MenuUserLinkContainer> | |||||
<LinkComponent | |||||
href={menuLink} | |||||
style={{ | |||||
width: 'var(--height-topbar, 4rem)', | |||||
height: '100%', | |||||
display: 'inline-grid', | |||||
placeContent: 'center', | |||||
}} | |||||
shallow | |||||
> | |||||
<T.Icon | |||||
name="menu" | |||||
label={menuLinkLabel} | |||||
/> | |||||
</LinkComponent> | |||||
</MenuUserLinkContainer> | |||||
) | |||||
} | |||||
<LinkComponent | |||||
href={userLink} | |||||
style={{ | |||||
width: 'var(--height-topbar, 4rem)', | |||||
height: '100%', | |||||
display: 'inline-grid', | |||||
placeContent: 'center', | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="user" | |||||
label={userLinkLabel} | |||||
/> | |||||
</LinkComponent> | |||||
</UserContainer> | |||||
</ContainerComponent> | |||||
</Base> | |||||
) | |||||
} | |||||
export default TopBar |
@@ -1,39 +1,65 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import Basic, { Container } from '../../organisms/layouts/Basic' | |||||
import DummyContent from '../../molecules/DummyContent'; | |||||
import {UrlObject} from 'url'; | |||||
import * as T from '@tesseract-design/react-common' | |||||
import { Basic } from '@tesseract-design/viewfinder' | |||||
import Link from '../../molecules/Link' | |||||
import DummyContent from '../../molecules/DummyContent' | |||||
import Brand from '../../molecules/Brand' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
linkComponent: React.ElementType, | |||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel: string, | |||||
userLinkLabel: string, | userLinkLabel: string, | ||||
searchQueryKey: string, | |||||
searchLabel: string, | |||||
searchHint: string, | |||||
popupQueryKey: string, | |||||
userPopupQueryValue: string, | |||||
} | } | ||||
const BasicLayoutTemplate: React.FC<Props> = ({ | const BasicLayoutTemplate: React.FC<Props> = ({ | ||||
query, | query, | ||||
linkComponent, | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | userLinkLabel, | ||||
searchQueryKey, | |||||
searchLabel, | |||||
searchHint, | |||||
popupQueryKey, | |||||
userPopupQueryValue, | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<Basic | |||||
brand="Brand" | |||||
query={query} | |||||
linkComponent={linkComponent} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
<Basic.Layout | |||||
brand={ | |||||
<Brand /> | |||||
} | |||||
topBarCenter={ | |||||
<form> | |||||
<T.TextInput | |||||
name={searchQueryKey} | |||||
label={searchLabel} | |||||
hint={searchHint} | |||||
defaultValue={query} | |||||
border | |||||
alternate | |||||
/> | |||||
</form> | |||||
} | |||||
userLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[popupQueryKey]: userPopupQueryValue, | |||||
}, | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="user" | |||||
label={userLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
> | > | ||||
<Container> | |||||
<Basic.ContentContainer> | |||||
<DummyContent /> | <DummyContent /> | ||||
</Container> | |||||
</Basic> | |||||
</Basic.ContentContainer> | |||||
</Basic.Layout> | |||||
) | ) | ||||
} | } | ||||
@@ -1,8 +1,9 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import styled from 'styled-components' | import styled from 'styled-components' | ||||
import Basic, { Container } from '../../organisms/layouts/Basic' | |||||
import Link from '../../molecules/Link'; | |||||
import {UrlObject} from 'url'; | |||||
import * as T from '@tesseract-design/react-common' | |||||
import { Basic } from '@tesseract-design/viewfinder' | |||||
import Link from '../../molecules/Link' | |||||
import Brand from '../../molecules/Brand' | |||||
const LinkContainer = styled('nav')({ | const LinkContainer = styled('nav')({ | ||||
margin: '1rem 0', | margin: '1rem 0', | ||||
@@ -62,32 +63,56 @@ const StyledLink = styled(Link)({ | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
linkComponent: React.ElementType, | |||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel: string, | |||||
userLinkLabel: string, | userLinkLabel: string, | ||||
searchQueryKey: string, | |||||
searchLabel: string, | |||||
searchHint: string, | |||||
popupQueryKey: string, | |||||
userPopupQueryValue: string, | |||||
} | } | ||||
const IndexTemplate: React.FC<Props> = ({ | const IndexTemplate: React.FC<Props> = ({ | ||||
query, | query, | ||||
linkComponent, | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | userLinkLabel, | ||||
searchQueryKey, | |||||
searchLabel, | |||||
searchHint, | |||||
popupQueryKey, | |||||
userPopupQueryValue, | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<Basic | |||||
brand="Brand" | |||||
query={query} | |||||
linkComponent={linkComponent} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
<Basic.Layout | |||||
brand={ | |||||
<Brand /> | |||||
} | |||||
topBarCenter={ | |||||
<form> | |||||
<T.TextInput | |||||
name={searchQueryKey} | |||||
label={searchLabel} | |||||
hint={searchHint} | |||||
defaultValue={query} | |||||
border | |||||
alternate | |||||
/> | |||||
</form> | |||||
} | |||||
userLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[popupQueryKey]: userPopupQueryValue, | |||||
}, | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="user" | |||||
label={userLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
> | > | ||||
<Container> | |||||
<Basic.ContentContainer> | |||||
<h1> | <h1> | ||||
Welcome | Welcome | ||||
</h1> | </h1> | ||||
@@ -110,13 +135,13 @@ const IndexTemplate: React.FC<Props> = ({ | |||||
</StyledLink> | </StyledLink> | ||||
<StyledLink | <StyledLink | ||||
href={{ | href={{ | ||||
pathname: '/layouts/right-sidebar' | |||||
pathname: '/layouts/right-sidebar-static' | |||||
}} | }} | ||||
> | > | ||||
Right Sidebar | |||||
Right Sidebar (static) | |||||
<PreviewWrapper> | <PreviewWrapper> | ||||
<Preview | <Preview | ||||
src="/layouts/right-sidebar" | |||||
src="/layouts/right-sidebar-static" | |||||
scrolling="no" | scrolling="no" | ||||
/> | /> | ||||
</PreviewWrapper> | </PreviewWrapper> | ||||
@@ -139,7 +164,7 @@ const IndexTemplate: React.FC<Props> = ({ | |||||
pathname: '/layouts/left-sidebar/with-menu' | pathname: '/layouts/left-sidebar/with-menu' | ||||
}} | }} | ||||
> | > | ||||
Left Sidebar (w/ menu) | |||||
Left Sidebar (with menu) | |||||
<PreviewWrapper> | <PreviewWrapper> | ||||
<Preview | <Preview | ||||
src="/layouts/left-sidebar/with-menu" | src="/layouts/left-sidebar/with-menu" | ||||
@@ -148,8 +173,8 @@ const IndexTemplate: React.FC<Props> = ({ | |||||
</PreviewWrapper> | </PreviewWrapper> | ||||
</StyledLink> | </StyledLink> | ||||
</LinkContainer> | </LinkContainer> | ||||
</Container> | |||||
</Basic> | |||||
</Basic.ContentContainer> | |||||
</Basic.Layout> | |||||
) | ) | ||||
} | } | ||||
@@ -1,47 +1,91 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import LeftSidebarLayout, { SidebarContainer, Container } from '../../organisms/layouts/LeftSidebar'; | |||||
import DummyContent from '../../molecules/DummyContent'; | |||||
import {UrlObject} from 'url'; | |||||
import * as T from '@tesseract-design/react-common' | |||||
import { LeftSidebar } from '@tesseract-design/viewfinder' | |||||
import DummyContent from '../../molecules/DummyContent' | |||||
import Link from '../../molecules/Link' | |||||
import Brand from '../../molecules/Brand' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
linkComponent: React.ElementType, | |||||
sidebarMainOpen: boolean, | sidebarMainOpen: boolean, | ||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel: string, | menuLinkLabel: string, | ||||
userLinkLabel: string, | userLinkLabel: string, | ||||
searchQueryKey: string, | |||||
searchLabel: string, | |||||
searchHint: string, | |||||
popupQueryKey: string, | |||||
userPopupQueryValue: string, | |||||
sidebarQueryKey: string, | |||||
} | } | ||||
const LeftSidebarLayoutTemplate: React.FC<Props> = ({ | const LeftSidebarLayoutTemplate: React.FC<Props> = ({ | ||||
query, | query, | ||||
sidebarMainOpen, | sidebarMainOpen, | ||||
linkComponent, | |||||
menuLinkLabel, | menuLinkLabel, | ||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | userLinkLabel, | ||||
searchQueryKey, | |||||
searchLabel, | |||||
searchHint, | |||||
popupQueryKey, | |||||
userPopupQueryValue, | |||||
sidebarQueryKey, | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<LeftSidebarLayout | |||||
brand="Brand" | |||||
query={query} | |||||
<LeftSidebar.Layout | |||||
brand={ | |||||
<Brand /> | |||||
} | |||||
sidebarMainOpen={sidebarMainOpen} | sidebarMainOpen={sidebarMainOpen} | ||||
linkComponent={linkComponent} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
topBarCenter={ | |||||
<form> | |||||
<T.TextInput | |||||
name={searchQueryKey} | |||||
label={searchLabel} | |||||
hint={searchHint} | |||||
defaultValue={query} | |||||
border | |||||
alternate | |||||
/> | |||||
</form> | |||||
} | |||||
menuLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[sidebarQueryKey]: '', | |||||
}, | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="menu" | |||||
label={menuLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
userLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[popupQueryKey]: userPopupQueryValue, | |||||
}, | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="user" | |||||
label={userLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
sidebarMain={ | sidebarMain={ | ||||
<SidebarContainer> | |||||
<LeftSidebar.SidebarContainer> | |||||
<DummyContent /> | <DummyContent /> | ||||
</SidebarContainer> | |||||
</LeftSidebar.SidebarContainer> | |||||
} | } | ||||
> | > | ||||
<Container> | |||||
<LeftSidebar.ContentContainer> | |||||
<DummyContent /> | <DummyContent /> | ||||
</Container> | |||||
</LeftSidebarLayout> | |||||
</LeftSidebar.ContentContainer> | |||||
</LeftSidebar.Layout> | |||||
) | ) | ||||
} | } | ||||
@@ -1,151 +1,139 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as T from '@tesseract-design/react-common'; | |||||
import LeftSidebarWithMenuLayout, { | |||||
Container, | |||||
SidebarMainContainer, | |||||
} from '../../organisms/layouts/LeftSidebarWithMenu'; | |||||
import DummyContent from '../../molecules/DummyContent'; | |||||
import {UrlObject} from 'url'; | |||||
import * as T from '@tesseract-design/react-common' | |||||
import { LeftSidebarWithMenu } from '@tesseract-design/viewfinder' | |||||
import DummyContent from '../../molecules/DummyContent' | |||||
import Link from '../../molecules/Link' | |||||
import Brand from '../../molecules/Brand' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
linkComponent: React.ElementType, | |||||
sidebarMainOpen: boolean, | sidebarMainOpen: boolean, | ||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel: string, | menuLinkLabel: string, | ||||
userLinkLabel: string, | userLinkLabel: string, | ||||
moreItemsOpen: boolean, | moreItemsOpen: boolean, | ||||
searchQueryKey: string, | |||||
searchLabel: string, | |||||
searchHint: string, | |||||
popupQueryKey: string, | |||||
moreQueryKey: string, | |||||
sidebarQueryKey: string, | |||||
moreLinkLabel: string, | |||||
sidebarMenuItems: LeftSidebarWithMenu.MenuItem[], | |||||
userPopupQueryValue: string, | |||||
} | } | ||||
const LeftSidebarLayoutTemplate: React.FC<Props> = ({ | const LeftSidebarLayoutTemplate: React.FC<Props> = ({ | ||||
query, | query, | ||||
sidebarMainOpen, | sidebarMainOpen, | ||||
linkComponent, | |||||
menuLinkLabel, | menuLinkLabel, | ||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | userLinkLabel, | ||||
moreItemsOpen, | moreItemsOpen, | ||||
searchQueryKey, | |||||
searchLabel, | |||||
searchHint, | |||||
popupQueryKey, | |||||
moreQueryKey, | |||||
sidebarQueryKey, | |||||
moreLinkLabel, | |||||
sidebarMenuItems, | |||||
userPopupQueryValue, | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<LeftSidebarWithMenuLayout | |||||
brand="Brand" | |||||
moreItemsOpen={moreItemsOpen} | |||||
query={query} | |||||
linkComponent={linkComponent} | |||||
sidebarMainOpen={sidebarMainOpen} | |||||
sidebarMain={ | |||||
<SidebarMainContainer> | |||||
<DummyContent /> | |||||
</SidebarMainContainer> | |||||
<LeftSidebarWithMenu.Layout | |||||
brand={ | |||||
<Brand /> | |||||
} | } | ||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
sidebarMenuItems={ | |||||
[ | |||||
{ | |||||
id: '1', | |||||
label: 'P1', | |||||
url: { | |||||
href: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '2', | |||||
label: 'P2', | |||||
url: { | |||||
href: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '3', | |||||
label: 'P3', | |||||
url: { | |||||
href: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '100', | |||||
label: 'P4', | |||||
url: { | |||||
href: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '101', | |||||
label: 'P5', | |||||
url: { | |||||
href: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '4', | |||||
label: 'S1', | |||||
url: { | |||||
href: '/hello', | |||||
topBarCenter={ | |||||
<form> | |||||
<T.TextInput | |||||
name={searchQueryKey} | |||||
label={searchLabel} | |||||
hint={searchHint} | |||||
defaultValue={query} | |||||
border | |||||
alternate | |||||
/> | |||||
</form> | |||||
} | |||||
menuLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[sidebarQueryKey]: '', | |||||
}, | }, | ||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
secondary: true, | |||||
}, | |||||
{ | |||||
id: '5', | |||||
label: 'S2', | |||||
url: { | |||||
href: '/hello', | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="menu" | |||||
label={menuLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
userLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[popupQueryKey]: userPopupQueryValue, | |||||
}, | }, | ||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
secondary: true, | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="user" | |||||
label={userLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
moreLinkMenuItem={{ | |||||
label: moreLinkLabel, | |||||
url: { | |||||
query: { | |||||
[moreQueryKey]: '', | |||||
}, | }, | ||||
] | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="more-horizontal" | |||||
label="" | |||||
/> | |||||
), | |||||
}} | |||||
moreItemsOpen={moreItemsOpen} | |||||
moreLinkComponent={({ url, icon, label, }) => ( | |||||
<Link | |||||
href={url} | |||||
> | |||||
<LeftSidebarWithMenu.MoreSidebarMenuContainer> | |||||
<LeftSidebarWithMenu.MoreSidebarMenuItemIcon> | |||||
{icon} | |||||
</LeftSidebarWithMenu.MoreSidebarMenuItemIcon> | |||||
{label} | |||||
</LeftSidebarWithMenu.MoreSidebarMenuContainer> | |||||
</Link> | |||||
)} | |||||
linkComponent={({ url, icon, label, }) => ( | |||||
<Link | |||||
href={url} | |||||
> | |||||
<LeftSidebarWithMenu.SidebarMenuContainer> | |||||
<LeftSidebarWithMenu.SidebarMenuItemIcon> | |||||
{icon} | |||||
</LeftSidebarWithMenu.SidebarMenuItemIcon> | |||||
{label} | |||||
</LeftSidebarWithMenu.SidebarMenuContainer> | |||||
</Link> | |||||
)} | |||||
sidebarMainOpen={sidebarMainOpen} | |||||
sidebarMain={ | |||||
<LeftSidebarWithMenu.SidebarMainContainer> | |||||
<DummyContent /> | |||||
</LeftSidebarWithMenu.SidebarMainContainer> | |||||
} | } | ||||
sidebarMenuItems={sidebarMenuItems} | |||||
> | > | ||||
<Container> | |||||
<LeftSidebarWithMenu.ContentContainer> | |||||
<DummyContent /> | <DummyContent /> | ||||
</Container> | |||||
</LeftSidebarWithMenuLayout> | |||||
</LeftSidebarWithMenu.ContentContainer> | |||||
</LeftSidebarWithMenu.Layout> | |||||
) | ) | ||||
} | } | ||||
@@ -1,44 +1,70 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import RightSidebarLayout, { SidebarContainer, Container } from '../../organisms/layouts/RightSidebar'; | |||||
import DummyContent from '../../molecules/DummyContent'; | |||||
import {UrlObject} from 'url'; | |||||
import * as T from '@tesseract-design/react-common' | |||||
import { RightSidebarStatic } from '@tesseract-design/viewfinder' | |||||
import DummyContent from '../../molecules/DummyContent' | |||||
import Link from '../../molecules/Link' | |||||
import Brand from '../../molecules/Brand' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
linkComponent: React.ElementType, | |||||
menuLink: UrlObject, | |||||
userLink: UrlObject, | |||||
menuLinkLabel: string, | |||||
userLinkLabel: string, | userLinkLabel: string, | ||||
searchQueryKey: string, | |||||
searchLabel: string, | |||||
searchHint: string, | |||||
popupQueryKey: string, | |||||
userPopupQueryValue: string, | |||||
} | } | ||||
const RightSidebarLayoutTemplate: React.FC<Props> = ({ | const RightSidebarLayoutTemplate: React.FC<Props> = ({ | ||||
query, | query, | ||||
linkComponent, | |||||
menuLinkLabel, | |||||
menuLink, | |||||
userLink, | |||||
userLinkLabel, | userLinkLabel, | ||||
searchQueryKey, | |||||
searchLabel, | |||||
searchHint, | |||||
popupQueryKey, | |||||
userPopupQueryValue, | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<RightSidebarLayout | |||||
brand="Brand" | |||||
query={query} | |||||
linkComponent={linkComponent} | |||||
menuLink={menuLink} | |||||
menuLinkLabel={menuLinkLabel} | |||||
userLink={userLink} | |||||
userLinkLabel={userLinkLabel} | |||||
<RightSidebarStatic.Layout | |||||
brand={ | |||||
<Brand /> | |||||
} | |||||
topBarCenter={ | |||||
<form> | |||||
<T.TextInput | |||||
name={searchQueryKey} | |||||
label={searchLabel} | |||||
hint={searchHint} | |||||
defaultValue={query} | |||||
border | |||||
alternate | |||||
/> | |||||
</form> | |||||
} | |||||
userLink={ | |||||
<Link | |||||
href={{ | |||||
query: { | |||||
[popupQueryKey]: userPopupQueryValue, | |||||
}, | |||||
}} | |||||
> | |||||
<T.Icon | |||||
name="user" | |||||
label={userLinkLabel} | |||||
/> | |||||
</Link> | |||||
} | |||||
sidebarMain={ | sidebarMain={ | ||||
<SidebarContainer> | |||||
<RightSidebarStatic.SidebarContainer> | |||||
<DummyContent /> | <DummyContent /> | ||||
</SidebarContainer> | |||||
</RightSidebarStatic.SidebarContainer> | |||||
} | } | ||||
> | > | ||||
<Container> | |||||
<RightSidebarStatic.ContentContainer> | |||||
<DummyContent /> | <DummyContent /> | ||||
</Container> | |||||
</RightSidebarLayout> | |||||
</RightSidebarStatic.ContentContainer> | |||||
</RightSidebarStatic.Layout> | |||||
) | ) | ||||
} | } | ||||
@@ -1,7 +1,7 @@ | |||||
import Head from 'next/head' | |||||
import Link from '../components/molecules/Link'; | |||||
import Template from '../components/templates/Index'; | |||||
import {GetServerSideProps, NextPage} from 'next'; | |||||
import {GetServerSideProps, NextPage} from 'next' | |||||
import {USER} from '../utilities/popups' | |||||
import {QUERY, POPUP} from '../utilities/queryKeys' | |||||
import Template from '../components/templates/Index' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
@@ -12,22 +12,13 @@ const Page: NextPage<Props> = ({ | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<Template | <Template | ||||
linkComponent={Link} | |||||
query={query} | query={query} | ||||
menuLink={{ | |||||
query: { | |||||
q: query, | |||||
sidebar: '', | |||||
} | |||||
}} | |||||
menuLinkLabel="Menu" | |||||
userLink={{ | |||||
pathname: '/profile', | |||||
query: { | |||||
q: query, | |||||
}, | |||||
}} | |||||
userLinkLabel="User" | userLinkLabel="User" | ||||
searchQueryKey={QUERY} | |||||
searchLabel="Search" | |||||
searchHint="e.g. keywords, names…" | |||||
popupQueryKey={POPUP} | |||||
userPopupQueryValue={USER} | |||||
/> | /> | ||||
) | ) | ||||
} | } | ||||
@@ -35,7 +26,7 @@ const Page: NextPage<Props> = ({ | |||||
export default Page | export default Page | ||||
export const getServerSideProps: GetServerSideProps = async (ctx) => { | export const getServerSideProps: GetServerSideProps = async (ctx) => { | ||||
const { q: query = '', } = ctx.query | |||||
const { [QUERY]: query = '', } = ctx.query | |||||
return { | return { | ||||
props: { | props: { | ||||
query, | query, | ||||
@@ -1,6 +1,7 @@ | |||||
import {GetServerSideProps, NextPage} from 'next' | import {GetServerSideProps, NextPage} from 'next' | ||||
import Template from '../../../components/templates/BasicLayout' | import Template from '../../../components/templates/BasicLayout' | ||||
import Link from '../../../components/molecules/Link'; | |||||
import {USER} from '../../../utilities/popups' | |||||
import {POPUP, QUERY} from '../../../utilities/queryKeys' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
@@ -11,22 +12,13 @@ const Page: NextPage<Props> = ({ | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<Template | <Template | ||||
linkComponent={Link} | |||||
query={query} | query={query} | ||||
menuLink={{ | |||||
query: { | |||||
q: query, | |||||
sidebar: '', | |||||
} | |||||
}} | |||||
menuLinkLabel="Menu" | |||||
userLink={{ | |||||
pathname: '/profile', | |||||
query: { | |||||
q: query, | |||||
}, | |||||
}} | |||||
userLinkLabel="User" | userLinkLabel="User" | ||||
searchQueryKey={QUERY} | |||||
searchLabel="Search" | |||||
searchHint="e.g. keywords, names…" | |||||
popupQueryKey={POPUP} | |||||
userPopupQueryValue={USER} | |||||
/> | /> | ||||
) | ) | ||||
} | } | ||||
@@ -34,7 +26,7 @@ const Page: NextPage<Props> = ({ | |||||
export default Page | export default Page | ||||
export const getServerSideProps: GetServerSideProps = async (ctx) => { | export const getServerSideProps: GetServerSideProps = async (ctx) => { | ||||
const { q: query = '', } = ctx.query | |||||
const { [QUERY]: query = '', } = ctx.query | |||||
return { | return { | ||||
props: { | props: { | ||||
query, | query, | ||||
@@ -1,6 +1,7 @@ | |||||
import {GetServerSideProps, NextPage} from 'next' | import {GetServerSideProps, NextPage} from 'next' | ||||
import Template from '../../../components/templates/LeftSidebarLayout' | import Template from '../../../components/templates/LeftSidebarLayout' | ||||
import Link from '../../../components/molecules/Link'; | |||||
import {POPUP, QUERY, SIDEBAR} from '../../../utilities/queryKeys' | |||||
import {USER} from '../../../utilities/popups' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
@@ -15,21 +16,14 @@ const Page: NextPage<Props> = ({ | |||||
<Template | <Template | ||||
query={query} | query={query} | ||||
sidebarMainOpen={sidebarMainOpen} | sidebarMainOpen={sidebarMainOpen} | ||||
linkComponent={Link} | |||||
menuLink={{ | |||||
query: { | |||||
q: query, | |||||
sidebar: '', | |||||
} | |||||
}} | |||||
menuLinkLabel="Menu" | |||||
userLink={{ | |||||
pathname: '/profile', | |||||
query: { | |||||
q: query, | |||||
}, | |||||
}} | |||||
userLinkLabel="User" | userLinkLabel="User" | ||||
searchQueryKey={QUERY} | |||||
searchLabel="Search" | |||||
searchHint="e.g. keywords, names…" | |||||
popupQueryKey={POPUP} | |||||
userPopupQueryValue={USER} | |||||
menuLinkLabel="Menu" | |||||
sidebarQueryKey={SIDEBAR} | |||||
/> | /> | ||||
) | ) | ||||
} | } | ||||
@@ -37,7 +31,7 @@ const Page: NextPage<Props> = ({ | |||||
export default Page | export default Page | ||||
export const getServerSideProps: GetServerSideProps = async (ctx) => { | export const getServerSideProps: GetServerSideProps = async (ctx) => { | ||||
const { q: query = '', } = ctx.query | |||||
const { [QUERY]: query = '', } = ctx.query | |||||
return { | return { | ||||
props: { | props: { | ||||
query, | query, | ||||
@@ -1,6 +1,9 @@ | |||||
import * as React from 'react' | |||||
import * as T from '@tesseract-design/react-common' | |||||
import {GetServerSideProps, NextPage} from 'next' | import {GetServerSideProps, NextPage} from 'next' | ||||
import Template from '../../../../components/templates/LeftSidebarWithMenuLayout' | import Template from '../../../../components/templates/LeftSidebarWithMenuLayout' | ||||
import Link from '../../../../components/molecules/Link'; | |||||
import {MORE, POPUP, QUERY, SIDEBAR} from '../../../../utilities/queryKeys' | |||||
import {USER} from '../../../../utilities/popups' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
@@ -16,23 +19,113 @@ const Page: NextPage<Props> = ({ | |||||
return ( | return ( | ||||
<Template | <Template | ||||
query={query} | query={query} | ||||
sidebarMainOpen={sidebarMainOpen} | |||||
linkComponent={Link} | |||||
menuLink={{ | |||||
query: { | |||||
q: query, | |||||
sidebar: '', | |||||
} | |||||
}} | |||||
menuLinkLabel="Menu" | |||||
userLink={{ | |||||
pathname: '/profile', | |||||
query: { | |||||
q: query, | |||||
}, | |||||
}} | |||||
moreQueryKey={MORE} | |||||
userLinkLabel="User" | userLinkLabel="User" | ||||
searchQueryKey={QUERY} | |||||
searchLabel="Search" | |||||
searchHint="e.g. keywords, names…" | |||||
popupQueryKey={POPUP} | |||||
userPopupQueryValue={USER} | |||||
menuLinkLabel="Menu" | |||||
sidebarQueryKey={SIDEBAR} | |||||
sidebarMainOpen={sidebarMainOpen} | |||||
moreLinkLabel="More" | |||||
moreItemsOpen={moreItemsOpen} | moreItemsOpen={moreItemsOpen} | ||||
sidebarMenuItems={[ | |||||
{ | |||||
id: '1', | |||||
label: 'P1', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '2', | |||||
label: 'P2', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '3', | |||||
label: 'P3', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '100', | |||||
label: 'P4', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '101', | |||||
label: 'P5', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
}, | |||||
{ | |||||
id: '4', | |||||
label: 'S1', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
secondary: true, | |||||
}, | |||||
{ | |||||
id: '5', | |||||
label: 'S2', | |||||
url: { | |||||
pathname: '/hello', | |||||
}, | |||||
icon: ( | |||||
<T.Icon | |||||
name="square" | |||||
label="" | |||||
/> | |||||
), | |||||
secondary: true, | |||||
}, | |||||
]} | |||||
/> | /> | ||||
) | ) | ||||
} | } | ||||
@@ -1,6 +1,7 @@ | |||||
import {GetServerSideProps, NextPage} from 'next' | import {GetServerSideProps, NextPage} from 'next' | ||||
import Template from '../../../components/templates/RightSidebarLayout' | import Template from '../../../components/templates/RightSidebarLayout' | ||||
import Link from '../../../components/molecules/Link'; | |||||
import {POPUP, QUERY} from '../../../utilities/queryKeys' | |||||
import {USER} from '../../../utilities/popups' | |||||
type Props = { | type Props = { | ||||
query: string, | query: string, | ||||
@@ -11,22 +12,13 @@ const Page: NextPage<Props> = ({ | |||||
}) => { | }) => { | ||||
return ( | return ( | ||||
<Template | <Template | ||||
linkComponent={Link} | |||||
query={query} | query={query} | ||||
menuLink={{ | |||||
query: { | |||||
q: query, | |||||
sidebar: '', | |||||
} | |||||
}} | |||||
menuLinkLabel="Menu" | |||||
userLink={{ | |||||
pathname: '/profile', | |||||
query: { | |||||
q: query, | |||||
}, | |||||
}} | |||||
userLinkLabel="User" | userLinkLabel="User" | ||||
searchQueryKey={QUERY} | |||||
searchLabel="Search" | |||||
searchHint="e.g. keywords, names…" | |||||
popupQueryKey={POPUP} | |||||
userPopupQueryValue={USER} | |||||
/> | /> | ||||
) | ) | ||||
} | } | ||||
@@ -34,7 +26,7 @@ const Page: NextPage<Props> = ({ | |||||
export default Page | export default Page | ||||
export const getServerSideProps: GetServerSideProps = async (ctx) => { | export const getServerSideProps: GetServerSideProps = async (ctx) => { | ||||
const { q: query = '', } = ctx.query | |||||
const { [QUERY]: query = '', } = ctx.query | |||||
return { | return { | ||||
props: { | props: { | ||||
query, | query, |
@@ -0,0 +1 @@ | |||||
export const USER = 'user' |
@@ -0,0 +1,7 @@ | |||||
export const QUERY = 'q' | |||||
export const POPUP = 'popup' | |||||
export const SIDEBAR = 'sidebar' | |||||
export const MORE = 'more' |