Skip to content

Commit

Permalink
Brand styling for pagination and breadcrumbs
Browse files Browse the repository at this point in the history
  • Loading branch information
risadams committed Jan 6, 2023
1 parent ce8c1e2 commit 0488970
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 2 deletions.
5 changes: 3 additions & 2 deletions docs/src/components/Examples/Plugins/AutoPosition.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ export default function AutoPosition() {
</CodeBlock>

<p>
This select is expected to open on top
<pre className="mb-2">You may need to scroll or adjust your browser window</pre>
This select is expected to open on top.
<br />
<strong className="mb-2 text-red-600">You may need to scroll or adjust your browser window</strong>
</p>
<select id="autoPositionTop">
<option value=""></option>
Expand Down
3 changes: 3 additions & 0 deletions docs/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
--ifm-heading-font-family: "Lexend", sans-serif;
--ifm-font-family-base: "Visby CF", sans-serif;
--ifm-font-family-monospace: "CaskaydiaCove Nerd Font Mono", sans-serif;
--ifm-breadcrumb-color-active: var(--ifm-color-primary-darkest);
--ifm-link-color: var(--ifm-color-primary);
--ifm-link-hover-color: var(--ifm-color-primary-darkest);
}

/* For readability concerns, you should choose a lighter palette in dark mode. */
Expand Down
111 changes: 111 additions & 0 deletions docs/src/theme/DocBreadcrumbs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React from 'react';
import clsx from 'clsx';
import { ThemeClassNames } from '@docusaurus/theme-common';
import {
useSidebarBreadcrumbs,
useHomePageRoute,
} from '@docusaurus/theme-common/internal';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import { translate } from '@docusaurus/Translate';
import IconHome from '@theme/Icon/Home';
import styles from './styles.module.css';
// TODO move to design system folder
function BreadcrumbsItemLink({ children, href, isLast }) {
const className = 'breadcrumbs__link';
if (isLast) {
return (
<span className={className} itemProp="name">
{children}
</span>
);
}
return href ? (
<Link className={className} href={href} itemProp="item">
<span itemProp="name">{children}</span>
</Link>
) : (
// TODO Google search console doesn't like breadcrumb items without href.
// The schema doesn't seem to require `id` for each `item`, although Google
// insist to infer one, even if it's invalid. Removing `itemProp="item
// name"` for now, since I don't know how to properly fix it.
// See https://github.com/facebook/docusaurus/issues/7241
<span className={className}>{children}</span>
);
}
// TODO move to design system folder
function BreadcrumbsItem({ children, active, index, addMicrodata }) {
return (
<li
{...(addMicrodata && {
itemScope: true,
itemProp: 'itemListElement',
itemType: 'https://schema.org/ListItem',
})}
className={clsx('breadcrumbs__item', {
'breadcrumbs__item--active': active,
})}>
{children}
<meta itemProp="position" content={String(index + 1)} />
</li>
);
}
function HomeBreadcrumbItem() {
const homeHref = useBaseUrl('/');
return (
<li className={clsx(
"breadcrumbs__item"
)}>
<Link
aria-label={translate({
id: 'theme.docs.breadcrumbs.home',
message: 'Home page',
description: 'The ARIA label for the home page in the breadcrumbs',
})}
className={clsx('breadcrumbs__link', styles.breadcrumbsItemLink)}
href={homeHref}>
<IconHome className={styles.breadcrumbHomeIcon} />
</Link>
</li>
);
}
export default function DocBreadcrumbs() {
const breadcrumbs = useSidebarBreadcrumbs();
const homePageRoute = useHomePageRoute();
if (!breadcrumbs) {
return null;
}
return (
<nav
className={clsx(
ThemeClassNames.docs.docBreadcrumbs,
'pt-4'
)}
aria-label={translate({
id: 'theme.docs.breadcrumbs.navAriaLabel',
message: 'Breadcrumbs',
description: 'The ARIA label for the breadcrumbs',
})}>
<ul
className="breadcrumbs"
itemScope
itemType="https://schema.org/BreadcrumbList">
{homePageRoute && <HomeBreadcrumbItem />}
{breadcrumbs.map((item, idx) => {
const isLast = idx === breadcrumbs.length - 1;
return (
<BreadcrumbsItem
key={idx}
active={isLast}
index={idx}
addMicrodata={!!item.href}>
<BreadcrumbsItemLink href={item.href} isLast={isLast}>
{item.label}
</BreadcrumbsItemLink>
</BreadcrumbsItem>
);
})}
</ul>
</nav>
);
}
8 changes: 8 additions & 0 deletions docs/src/theme/DocBreadcrumbs/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.breadcrumbHomeIcon {
position: relative;
top: 1px;
vertical-align: top;
height: 1.5rem;
width: 1.6rem;
color: var(--ifm-color-primary);
}
11 changes: 11 additions & 0 deletions docs/src/theme/DocItem/Paginator/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import {useDoc} from '@docusaurus/theme-common/internal';
import DocPaginator from '@theme/DocPaginator';
/**
* This extra component is needed, because <DocPaginator> should remain generic.
* DocPaginator is used in non-docs contexts too: generated-index pages...
*/
export default function DocItemPaginator() {
const {metadata} = useDoc();
return <DocPaginator previous={metadata.previous} next={metadata.next} />;
}
41 changes: 41 additions & 0 deletions docs/src/theme/DocPaginator/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import Translate, { translate } from '@docusaurus/Translate';
import PaginatorNavLink from '@theme/PaginatorNavLink';
export default function DocPaginator(props) {
const { previous, next } = props;
return (
<nav
className="pagination-nav docusaurus-mt-lg"
aria-label={translate({
id: 'theme.docs.paginator.navAriaLabel',
message: 'Docs pages navigation',
description: 'The ARIA label for the docs pagination',
})}>
{previous && (
<PaginatorNavLink
{...previous}
subLabel={
<Translate
id="theme.docs.paginator.previous"
description="The label used to navigate to the previous doc">
Previous
</Translate>
}
/>
)}
{next && (
<PaginatorNavLink
{...next}
subLabel={
<Translate
id="theme.docs.paginator.next"
description="The label used to navigate to the next doc">
Next
</Translate>
}
isNext
/>
)}
</nav>
);
}
1 change: 1 addition & 0 deletions docs/src/theme/Footer/Layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function FooterLayout({ style, links, logo, copyright }) {
className={clsx('footer', {
'footer--dark': style === 'dark'
},
'sm:mt-0 md:mt-4 xl:mt-8',
'overflow-hidden bg-slate-900'
)}>
<div className='relative'>
Expand Down
85 changes: 85 additions & 0 deletions docs/src/theme/PaginatorNavLink/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import { motion, useMotionTemplate, useMotionValue } from 'framer-motion'
import { GridPattern } from '../../components/GridPattern';

export default function PaginatorNavLink(props) {
const { permalink, title, subLabel, isNext } = props;

let mouseX = useMotionValue(0)
let mouseY = useMotionValue(0)

function onMouseMove({ currentTarget, clientX, clientY }) {
let { left, top } = currentTarget.getBoundingClientRect()
mouseX.set(clientX - left)
mouseY.set(clientY - top)
}

let pattern = {
y: 48,
squares: isNext ? [
[-1, 0],
[0, -1],
[-2, -1],
] : [
[2, 0],
[0, 1],
[-1, 0],
],
};

return (
<Link
onMouseMove={onMouseMove}
className={clsx(
'pagination-nav__link',
'group relative',
'bg-zinc-50',
'transition-shadow shadow-lg hover:shadow-lg hover:shadow-zinc-900/5',
'display-inline',
isNext ? 'pagination-nav__link--next' : 'pagination-nav__link--prev',
)}
to={permalink}>
<FeaturePattern {...pattern} mouseX={mouseX} mouseY={mouseY} />
{subLabel && <div className="pagination-nav__sublabel">{subLabel}</div>}
<div className="pagination-nav__label">{title}</div>
</Link>
);
}


function FeaturePattern({ mouseX, mouseY, ...gridProps }) {
let maskImage = useMotionTemplate`radial-gradient(180px at ${mouseX}px ${mouseY}px, white, transparent)`
let style = { maskImage, WebkitMaskImage: maskImage }

return (
<div className="pointer-events-none">
<div className="absolute inset-0 rounded-2xl transition duration-300 [mask-image:linear-gradient(white,transparent)] group-hover:opacity-50">
<GridPattern
width={72}
height={56}
x="50%"
className="absolute inset-x-0 inset-y-[-30%] h-[160%] w-full skew-y-[-18deg] fill-black/[0.02] stroke-black/5"
{...gridProps}
/>
</div>
<motion.div
className="absolute inset-0 rounded-2xl bg-gradient-to-r from-[#d7e6ed] to-[#e0e8f6] opacity-0 transition duration-300 group-hover:opacity-100"
style={style}
/>
<motion.div
className="absolute inset-0 transition duration-300 opacity-0 rounded-2xl mix-blend-overlay group-hover:opacity-100"
style={style}
>
<GridPattern
width={72}
height={56}
x="50%"
className="absolute inset-x-0 inset-y-[-30%] h-[160%] w-full skew-y-[-18deg] fill-black/50 stroke-black/70"
{...gridProps}
/>
</motion.div>
</div>
)
}

0 comments on commit 0488970

Please sign in to comment.