fetch breadcrumbs from api; button disabled support; component fix
This commit is contained in:
1 parent
26c03dfbbf
commit
aefa0ae2d4
9 files changed
+94
-50
No files matched your search
+9
-4
@@ -6,7 +6,7 @@ import { Meta } from 'src/components/Meta'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
import { IBreadcumbsPart, IMeta } from 'src/types'
|
||||
import { IBreadcumbsPart, IMeta, IPage } from 'src/types'
|
||||
|
||||
function array<T>(value: T | T[]) {
|
||||
return Array.isArray(value)
|
||||
@@ -15,9 +15,10 @@ function array<T>(value: T | T[]) {
|
||||
}
|
||||
|
||||
type Props = {
|
||||
page: any
|
||||
title: string
|
||||
content: string
|
||||
breadcrumbs: IBreadcumbsPart[]
|
||||
breadcrumb: IBreadcumbsPart[]
|
||||
meta: IMeta
|
||||
}
|
||||
|
||||
@@ -27,7 +28,7 @@ const Index: NextPage<Props> = props => (
|
||||
contentStyle={{
|
||||
marginTop: 'var(--size-l)'
|
||||
}}
|
||||
breadcrumbs={props.breadcrumbs}
|
||||
breadcrumbs={props.breadcrumb}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
@@ -49,14 +50,17 @@ export const unstable_getStaticProps = async (ctx: any) => {
|
||||
} else {
|
||||
slug = '/' + array(ctx.params.slug).join('/')
|
||||
}
|
||||
const page = await requestGet(createApiUrl(`/api/page?page=${slug}`), null)
|
||||
const page = await requestGet<IPage>(createApiUrl(`/api/page?page=${slug}`), null)
|
||||
if (!page) {
|
||||
throw new Error(`Not found: ${slug}`)
|
||||
}
|
||||
const image = page.preview ? page.preview.artifacts.fb : {}
|
||||
const breadcrumbSize = page.breadcrumb?.length ?? 0
|
||||
const breadcrumb = breadcrumbSize < 2 ? null : page.breadcrumb
|
||||
|
||||
return {
|
||||
props: {
|
||||
page,
|
||||
content: page.data,
|
||||
title: page.title,
|
||||
meta: meta({
|
||||
@@ -65,6 +69,7 @@ export const unstable_getStaticProps = async (ctx: any) => {
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
}),
|
||||
breadcrumb,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Content } from '../Content'
|
||||
import { Block } from '../Block'
|
||||
import { Breadcrumbs } from '../Breadcrumbs'
|
||||
import { IBreadcumbsPart } from 'src/types'
|
||||
import { useRouter } from 'next/router'
|
||||
import { route } from 'next/dist/next-server/server/router'
|
||||
|
||||
const Navigation = dynamic(() => import('../Navigation').then(mod => mod.Navigation), {
|
||||
ssr: false,
|
||||
@@ -21,6 +23,7 @@ export interface IAppProps {
|
||||
}
|
||||
|
||||
export const App: React.FC<IAppProps> = props => {
|
||||
const router = useRouter()
|
||||
const wide = props.wide ?? false
|
||||
const blockStyle = {
|
||||
alignItems: 'center'
|
||||
@@ -36,7 +39,8 @@ export const App: React.FC<IAppProps> = props => {
|
||||
<Block direction={'vertical'} style={blockStyle}>
|
||||
<Content wide={wide}>
|
||||
<Breadcrumbs
|
||||
path={props.breadcrumbs}
|
||||
items={props.breadcrumbs}
|
||||
path={router.asPath}
|
||||
/>
|
||||
</Content>
|
||||
</Block>
|
||||
|
||||
@@ -2,30 +2,41 @@ import './styles.css'
|
||||
|
||||
import { IBreadcumbsPart } from 'src/types'
|
||||
import { Button } from '../Button'
|
||||
import { insertBetween } from 'src/lib/array'
|
||||
|
||||
export type BreadcrumbsProps = {
|
||||
style?: React.CSSProperties
|
||||
path: IBreadcumbsPart[]
|
||||
items: IBreadcumbsPart[]
|
||||
path: string
|
||||
}
|
||||
|
||||
export const Breadcrumbs: React.FC<BreadcrumbsProps> = props => {
|
||||
const items = insertBetween(props.items, () => '/')
|
||||
|
||||
return (
|
||||
<nav className={'breadcrumbs'} style={props.style}>
|
||||
{props.path.map((x, i) => (
|
||||
<li key={x.href}>
|
||||
<Button
|
||||
href={x.href}
|
||||
theme={'ghost'}
|
||||
size={'small'}
|
||||
>
|
||||
{x.name}
|
||||
</Button>
|
||||
{items.map((x, i) => {
|
||||
if (typeof x === 'string') {
|
||||
return (
|
||||
<li key={i}>
|
||||
<span style={{ margin: '0 var(--size-xs)' }}>{x}</span>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
{!(i < props.path.length - 1) ? null : (
|
||||
<span style={{ margin: '0 var(--size-xs)' }}>/</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</nav>
|
||||
return (
|
||||
<li key={x.href}>
|
||||
<Button
|
||||
href={x.href}
|
||||
theme={'ghost'}
|
||||
size={'small'}
|
||||
disabled={x.href === props.path}
|
||||
>
|
||||
{x.name}
|
||||
</Button>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</nav >
|
||||
)
|
||||
}
|
||||
@@ -5,3 +5,9 @@
|
||||
position: relative;
|
||||
right: var(--size-s);
|
||||
}
|
||||
|
||||
.breadcrumbCurrent {
|
||||
color: var(--color-text-second);
|
||||
font-size: var(--font-size-second);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@@ -8,13 +8,18 @@ export type ButtonProps = {
|
||||
href?: string
|
||||
theme?: 'default' | 'ghost'
|
||||
size?: 'default' | 'small'
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({ size='default', theme = 'default', ...props }) => {
|
||||
export const Button: React.FC<ButtonProps> = ({ size = 'default', theme = 'default', disabled = false, ...props }) => {
|
||||
const className = cx('button', theme, size, {
|
||||
disabled
|
||||
})
|
||||
|
||||
if (props.href) {
|
||||
return (
|
||||
<Link href={props.href}>
|
||||
<a className={cx('button', theme, size)} style={props.style}>
|
||||
<a className={className} style={props.style}>
|
||||
{props.children}
|
||||
</a>
|
||||
</Link>
|
||||
@@ -22,7 +27,7 @@ export const Button: React.FC<ButtonProps> = ({ size='default', theme = 'default
|
||||
}
|
||||
|
||||
return (
|
||||
<button className={'button'} style={props.style}>
|
||||
<button className={className} style={props.style}>
|
||||
{props.children}
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
box-shadow: var(--shadow-active);
|
||||
}
|
||||
|
||||
/* MODIFICATORS */
|
||||
|
||||
.button.disabled {
|
||||
pointer-events: none;
|
||||
color: var(--color-text-second);
|
||||
}
|
||||
|
||||
/* THEME */
|
||||
|
||||
.button.ghost {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
export function splitBy(fn) {
|
||||
return items => {
|
||||
return items.reduce((acc, item) => {
|
||||
const key = fn(item)
|
||||
const items = acc.get(key) || []
|
||||
|
||||
return acc.set(key, [...items, item])
|
||||
}, new Map())
|
||||
}
|
||||
}
|
||||
|
||||
export function head(list) {
|
||||
return Array.isArray(list) && list.length
|
||||
? list[0]
|
||||
: null
|
||||
}
|
||||
|
||||
export function last(list) {
|
||||
return Array.isArray(list) && list.length
|
||||
? list[list.length - 1]
|
||||
: null
|
||||
}
|
||||
|
||||
// exports.splitBy = splitBy
|
||||
// exports.head = head
|
||||
// exports.last = last
|
||||
@@ -0,0 +1,22 @@
|
||||
export function splitBy(fn) {
|
||||
return items => {
|
||||
return items.reduce((acc, item) => {
|
||||
const key = fn(item)
|
||||
const items = acc.get(key) || []
|
||||
|
||||
return acc.set(key, [...items, item])
|
||||
}, new Map())
|
||||
}
|
||||
}
|
||||
|
||||
export function insertBetween<T, I = T>(items: T[], fn: (i: number) => I): Array<T | I> {
|
||||
return items.reduce((acc, x, i) => {
|
||||
acc.push(x)
|
||||
|
||||
if (i < items.length - 1) {
|
||||
acc.push(fn(i))
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
@@ -8,6 +8,16 @@ export interface IBreadcumbsPart {
|
||||
href: string
|
||||
}
|
||||
|
||||
export interface IPage {
|
||||
id: string
|
||||
title: string
|
||||
url: string
|
||||
data: string
|
||||
preview: any //IImage
|
||||
tokens: any[]
|
||||
breadcrumb?: IBreadcumbsPart[]
|
||||
}
|
||||
|
||||
export interface IDocument {
|
||||
category: string
|
||||
fileName: string
|
||||
|
||||
Reference in new issue
Block a user