-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🛫 Add landing page blocks to book theme (#531)
Co-authored-by: Rowan Cockett <[email protected]>
- Loading branch information
Showing
23 changed files
with
578 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@myst-theme/landing-pages': patch | ||
'myst-to-react': patch | ||
--- | ||
|
||
Allow for no-width pilcrows on headings. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module.exports = { | ||
root: true, | ||
extends: ['curvenote'], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# @myst-theme/landing-pages | ||
|
||
[](https://www.npmjs.com/package/@myst-theme/landing-pages) | ||
[](https://github.com/curvenote/curvenote/blob/main/LICENSE) | ||
|
||
A set of landing-page components for MyST |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "@myst-theme/landing-pages", | ||
"version": "0.0.0", | ||
"type": "module", | ||
"exports": "./dist/index.js", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"engines": { | ||
"node": ">=16" | ||
}, | ||
"license": "MIT", | ||
"scripts": { | ||
"clean": "rimraf dist", | ||
"lint": "eslint \"src/**/*.ts*\" \"src/**/*.tsx\" -c ./.eslintrc.cjs", | ||
"lint:format": "prettier --check \"src/**/*.{ts,tsx,md}\"", | ||
"dev": "npm-run-all --parallel \"build:* -- --watch\"", | ||
"build:esm": "tsc", | ||
"build": "npm-run-all -l clean -p build:esm" | ||
}, | ||
"dependencies": { | ||
"@myst-theme/providers": "^0.14.1", | ||
"classnames": "^2.5.1", | ||
"myst-common": "^1.7.9", | ||
"myst-config": "^1.7.9", | ||
"myst-frontmatter": "^1.7.9", | ||
"myst-spec": "^0.0.5", | ||
"myst-spec-ext": "^1.7.9", | ||
"myst-to-react": "^0.14.1", | ||
"unist-util-select": "^4.0.3", | ||
"unist-util-filter": "^4.0.0" | ||
}, | ||
"peerDependencies": { | ||
"@types/react": "^16.8 || ^17.0 || ^18.0", | ||
"@types/react-dom": "^16.8 || ^17.0 || ^18.0", | ||
"react": "^16.8 || ^17.0 || ^18.0", | ||
"react-dom": "^16.8 || ^17.0 || ^18.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { createElement as e } from 'react'; | ||
import type { GenericParent } from 'myst-common'; | ||
import { MyST, HashLink } from 'myst-to-react'; | ||
import classNames from 'classnames'; | ||
|
||
export function BlockHeading({ node, className }: { node: GenericParent; className?: string }) { | ||
const { enumerator, depth, key, identifier, html_id } = node; | ||
const id = html_id || identifier || key; | ||
|
||
return e( | ||
`h${depth}`, | ||
{ | ||
className: classNames(node.class, className, 'group'), | ||
id: id, | ||
}, | ||
<> | ||
{enumerator && <span className="mr-3 select-none">{enumerator}</span>} | ||
<span className="heading-text"> | ||
<MyST ast={node.children} /> | ||
</span> | ||
<HashLink id={id} kind="Section" className="font-normal" hover hideInPopup noWidth /> | ||
</>, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { useMemo } from 'react'; | ||
import type { GenericParent, GenericNode } from 'myst-common'; | ||
import { MyST } from 'myst-to-react'; | ||
|
||
import { select, selectAll, matches } from 'unist-util-select'; | ||
import { filter } from 'unist-util-filter'; | ||
import type { NodeRenderers } from '@myst-theme/providers'; | ||
|
||
import { InvalidBlock } from './InvalidBlock.js'; | ||
import { BlockHeading } from './BlockHeading.js'; | ||
import { splitByHeader } from './utils.js'; | ||
import { LandingBlock, type LandingBlockProps } from './LandingBlock.js'; | ||
|
||
export function CenteredBlock(props: Omit<LandingBlockProps, 'children'>) { | ||
const { node } = props; | ||
const { body, links, subtitle, heading } = useMemo(() => { | ||
const { head, body: rawBody } = splitByHeader(node); | ||
|
||
const linksNode = selectAll('link[class*=button], crossReference[class*=button]', rawBody); | ||
const subtitleNode = select('paragraph', head) as GenericParent | null; | ||
const headingNode = select('heading', head) as GenericParent | null; | ||
const bodyNodes = | ||
filter( | ||
rawBody, | ||
(otherNode: GenericNode) => | ||
!matches('link[class*=button], crossReference[class*=button]', otherNode), | ||
)?.children ?? []; | ||
|
||
return { | ||
body: bodyNodes, | ||
links: linksNode, | ||
subtitle: subtitleNode, | ||
heading: headingNode, | ||
}; | ||
}, [node]); | ||
|
||
if (!body) { | ||
return <InvalidBlock {...props} blockName="centered" />; | ||
} | ||
return ( | ||
<LandingBlock {...props}> | ||
<div className="relative text-center"> | ||
<div className="py-20 sm:py-28"> | ||
{subtitle && ( | ||
<p className="my-0 font-semibold text-indigo-400 uppercase"> | ||
<MyST ast={subtitle.children} /> | ||
</p> | ||
)} | ||
{heading && ( | ||
<BlockHeading | ||
node={heading} | ||
className="mt-2 mb-0 text-5xl font-semibold tracking-tight" | ||
/> | ||
)} | ||
{body && ( | ||
<div className="mt-6"> | ||
<MyST ast={body} /> | ||
</div> | ||
)} | ||
{links && ( | ||
<div className="flex items-center justify-center gap-4 mt-8"> | ||
<MyST ast={links} /> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</LandingBlock> | ||
); | ||
} | ||
|
||
export const CENTERED_RENDERERS: NodeRenderers = { | ||
block: { | ||
'block[kind=centered]': CenteredBlock, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { MyST } from 'myst-to-react'; | ||
import { LandingBlock, type LandingBlockProps } from './LandingBlock.js'; | ||
|
||
export function InvalidBlock(props: Omit<LandingBlockProps, 'children'> & { blockName: string }) { | ||
const { node, blockName } = props; | ||
return ( | ||
<LandingBlock {...props}> | ||
<div className="relative" role="alert"> | ||
<div className="px-4 py-2 font-bold text-white bg-red-500 rounded-t"> | ||
Invalid block <span className="font-mono">{blockName}</span> | ||
</div> | ||
<div className="border border-t-0 border-red-400 rounded-b "> | ||
<div className="px-4 py-3 text-red-700 bg-red-100"> | ||
<p>This '{blockName}' block does not conform to the expected AST structure.</p> | ||
</div> | ||
|
||
<div className="px-4 py-3"> | ||
<MyST ast={node.children} /> | ||
</div> | ||
</div> | ||
</div> | ||
</LandingBlock> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { useMemo } from 'react'; | ||
import type { GenericParent, GenericNode } from 'myst-common'; | ||
import { MyST } from 'myst-to-react'; | ||
|
||
import { select, selectAll, matches } from 'unist-util-select'; | ||
import { filter } from 'unist-util-filter'; | ||
import type { NodeRenderers } from '@myst-theme/providers'; | ||
|
||
import { InvalidBlock } from './InvalidBlock.js'; | ||
import { BlockHeading } from './BlockHeading.js'; | ||
import { splitByHeader } from './utils.js'; | ||
import { LandingBlock, type LandingBlockProps } from './LandingBlock.js'; | ||
|
||
export function JustifiedBlock(props: Omit<LandingBlockProps, 'children'>) { | ||
const { node } = props; | ||
|
||
const { body, links, subtitle, heading } = useMemo(() => { | ||
const { head, body: rawBody } = splitByHeader(node); | ||
|
||
const linksNode = selectAll('link[class*=button], crossReference[class*=button]', rawBody); | ||
const subtitleNode = select('paragraph', head) as GenericParent | null; | ||
const headingNode = select('heading', head) as GenericParent | null; | ||
const bodyNodes = | ||
filter( | ||
rawBody, | ||
(otherNode: GenericNode) => | ||
!matches('link[class*=button], crossReference[class*=button]', otherNode), | ||
)?.children ?? []; | ||
|
||
return { | ||
body: bodyNodes, | ||
links: linksNode, | ||
subtitle: subtitleNode, | ||
heading: headingNode, | ||
}; | ||
}, [node]); | ||
|
||
if (!body) { | ||
return <InvalidBlock {...props} blockName="justified" />; | ||
} | ||
return ( | ||
<LandingBlock {...props}> | ||
<div className="py-20 sm:py-28 lg:px-8"> | ||
{subtitle && ( | ||
<p className="my-0 font-semibold text-indigo-400 uppercase"> | ||
<MyST ast={subtitle.children} /> | ||
</p> | ||
)} | ||
<div className="flex flex-col lg:content-center lg:justify-between lg:flex-row"> | ||
<div className="flex flex-col"> | ||
{heading && ( | ||
<BlockHeading | ||
node={heading} | ||
className="mt-2 mb-0 text-5xl font-semibold tracking-tight" | ||
/> | ||
)} | ||
{body && ( | ||
<div className="mt-6"> | ||
<MyST ast={body} /> | ||
</div> | ||
)} | ||
</div> | ||
<div className="flex flex-col mt-8 lg:mt-0"> | ||
{links && ( | ||
<div className="flex flex-row items-center gap-4"> | ||
<MyST ast={links} /> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
</LandingBlock> | ||
); | ||
} | ||
|
||
export const JUSTIFIED_RENDERERS: NodeRenderers = { | ||
block: { | ||
'block[kind=justified]': JustifiedBlock, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import type { ReactNode } from 'react'; | ||
import type { GenericParent } from 'myst-common'; | ||
|
||
import { useGridSystemProvider } from '@myst-theme/providers'; | ||
import classNames from 'classnames'; | ||
|
||
export type LandingBlockProps = { | ||
node: GenericParent; | ||
className?: string; | ||
children: ReactNode; | ||
}; | ||
|
||
export function LandingBlock({ node, className, children }: LandingBlockProps) { | ||
const grid = useGridSystemProvider(); | ||
const { key } = node; | ||
|
||
const subGrid = node.visibility === 'hide' ? '' : `${grid} subgrid-gap col-page [&>*]:col-page`; | ||
const dataClassName = typeof node.data?.class === 'string' ? node.data?.class : undefined; | ||
// Hide the subgrid if either the dataClass or the className exists and includes `col-` | ||
const noSubGrid = | ||
(dataClassName && dataClassName.includes('col-')) || (className && className.includes('col-')); | ||
|
||
return ( | ||
<div | ||
key={`block-${key}`} | ||
id={key} | ||
className={classNames('relative group/block py-6', className, dataClassName, { | ||
[subGrid]: !noSubGrid, | ||
hidden: node.visibility === 'remove', | ||
})} | ||
> | ||
{children} | ||
</div> | ||
); | ||
} |
Oops, something went wrong.