Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add visibility control to support Jupyter meta tags #129

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions packages/jupyter/src/output.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import classNames from 'classnames';
import { SafeOutputs } from './safe';
import { JupyterOutputs } from './jupyter';
import { useReadyToExecute } from './providers';
import { useMemo, useRef } from 'react';
import { useMemo, useRef, useState } from 'react';

export const DIRECT_OUTPUT_TYPES = new Set(['stream', 'error']);

Expand Down Expand Up @@ -40,12 +40,14 @@ function JupyterOutput({
identifier,
data,
align,
visibility,
}: {
nodeKey: string;
identifier?: string;
data: MinifiedOutput[];
nodeType?: string;
align?: 'left' | 'center' | 'right';
visibility?: string;
}) {
const ready = useReadyToExecute();
const outputs: MinifiedOutput[] = data;
Expand All @@ -60,20 +62,36 @@ function JupyterOutput({
} else {
component = <JupyterOutputs id={nodeKey} outputs={outputs} />;
}
const [hidden, setHidden] = useState(true);

return (
<figure
id={identifier || undefined}
data-mdast-node-type={nodeType}
data-mdast-node-id={nodeKey}
className={classNames('max-w-full overflow-visible m-0 group not-prose relative', {
'text-left': !align || align === 'left',
'text-center': align === 'center',
'text-right': align === 'right',
})}
>
{component}
</figure>
<div>
<div className={classNames('text-right mb-5', { hidden: visibility !== 'hide' })}>
<label className="relative inline-flex items-center">
<span className="mr-3 text-sm font-medium text-gray-900">
click to {hidden ? 'show' : 'hidden'} output
</span>
<input type="checkbox" defaultValue="" className="sr-only peer" />
<div
className="cursor-pointer w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:right-[22px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-400"
onClick={() => setHidden(!hidden)}
/>
</label>
</div>
<figure
id={identifier || undefined}
data-mdast-node-type={nodeType}
data-mdast-node-id={nodeKey}
className={classNames('max-w-full overflow-auto m-0 group not-prose relative', {
'text-left': !align || align === 'left',
'text-center': align === 'center',
'text-right': align === 'right',
hidden: visibility === 'remove' || (hidden && visibility === 'hide'),
})}
>
{component}
</figure>
</div>
);
}

Expand All @@ -87,6 +105,7 @@ export function Output(node: GenericNode) {
identifier={node.identifier}
align={node.align}
data={node.data}
visibility={node.visibility}
/>
);
}
48 changes: 48 additions & 0 deletions packages/myst-to-react/src/block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import classNames from 'classnames';
import { useState } from 'react';

function BlockInner({
nodeKey,
children,
visibility,
}: {
nodeKey: string;
children: any;
visibility?: string;
}) {
const [hidden, setHidden] = useState(true);
if (visibility) {
return (
<div key={nodeKey} className={classNames({ hidden: visibility === 'remove' })}>
<label
className={classNames('relative inline-flex items-center', {
hidden: visibility === 'show',
})}
>
<input type="checkbox" defaultValue="" className="sr-only peer" />
<div
className="cursor-pointer w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-400"
onClick={() => setHidden(!hidden)}
/>
<span className="ml-3 text-sm font-medium text-gray-900">
click to {hidden ? 'show' : 'hidden'} code cell
</span>
</label>
<div className={classNames({ hidden: hidden && visibility === 'hide' })}>{children}</div>
</div>
);
}
return <div key={nodeKey}>{children}</div>;
}

export function BlockOuter(node: any, children: any) {
return (
<BlockInner nodeKey={node.key} visibility={node.visibility}>
{children}
</BlockInner>
);
}

const BLOCK_RENDERERS = { block: BlockOuter };

export default BLOCK_RENDERERS;
107 changes: 64 additions & 43 deletions packages/myst-to-react/src/code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import light from 'react-syntax-highlighter/dist/cjs/styles/hljs/xcode';
import dark from 'react-syntax-highlighter/dist/cjs/styles/hljs/vs2015';
import classNames from 'classnames';
import { CopyIcon } from './components/CopyIcon';
import { useState } from 'react';

type Props = {
value: string;
Expand All @@ -20,6 +21,7 @@ type Props = {
background?: boolean;
border?: boolean;
className?: string;
visibility?: string;
};

function normalizeLanguage(lang?: string): string | undefined {
Expand All @@ -46,53 +48,71 @@ export function CodeBlock(props: Props) {
shadow,
background,
border,
visibility,
} = props;
const [hidden, setHidden] = useState(true);
const highlightLines = new Set(emphasizeLines);
return (
<div
id={identifier}
className={classNames('relative group not-prose overflow-auto', className, {
'shadow hover:shadow-md dark:shadow-2xl dark:shadow-neutral-900 my-5 text-sm': shadow,
'bg-stone-200/10': background,
'border border-l-4 border-l-blue-400 border-gray-200 dark:border-l-blue-400 dark:border-gray-800':
border,
})}
>
{filename && <div className="leading-3 mt-1 p-1">{filename}</div>}
<SyntaxHighlighter
language={normalizeLanguage(lang)}
startingLineNumber={startingLineNumber}
showLineNumbers={showLineNumbers}
style={isLight ? { ...light, hljs: { ...light.hljs, background: 'transparent' } } : dark}
wrapLines
lineNumberContainerStyle={{
// This stops page content shifts
display: 'inline-block',
float: 'left',
minWidth: '1.25em',
paddingRight: '1em',
textAlign: 'right',
userSelect: 'none',
borderLeft: '4px solid transparent',
}}
lineProps={(line) => {
if (typeof line === 'boolean') return {};
return highlightLines.has(line)
? ({
'data-line-number': `${line}`,
'data-highlight': 'true',
} as any)
: ({ 'data-line-number': `${line}` } as any);
}}
customStyle={{ padding: '0.8rem' }}
<div>
<div className={classNames('text-right', { hidden: visibility !== 'hide' })}>
<label className="relative inline-flex items-center">
<span className="mr-3 text-sm font-medium text-gray-900">
click to {hidden ? 'show' : 'hidden'} input
</span>
<input type="checkbox" defaultValue="" className="sr-only peer" />
<div
className="cursor-pointer w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:right-[22px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-400"
onClick={() => setHidden(!hidden)}
/>
</label>
</div>

<div
id={identifier}
className={classNames('relative group not-prose overflow-auto', className, {
'shadow hover:shadow-md dark:shadow-2xl dark:shadow-neutral-900 my-5 text-sm': shadow,
'bg-stone-200/10': background,
'border border-l-4 border-l-blue-400 border-gray-200 dark:border-l-blue-400 dark:border-gray-800':
border,
hidden: visibility === 'remove' || (hidden && visibility === 'hide'),
})}
>
{value}
</SyntaxHighlighter>
{showCopy && (
<div className="absolute hidden top-1 right-1 group-hover:block">
<CopyIcon text={value} />
</div>
)}
{filename && <div className="leading-3 mt-1 p-1">{filename}</div>}
<SyntaxHighlighter
language={normalizeLanguage(lang)}
startingLineNumber={startingLineNumber}
showLineNumbers={showLineNumbers}
style={isLight ? { ...light, hljs: { ...light.hljs, background: 'transparent' } } : dark}
wrapLines
lineNumberContainerStyle={{
// This stops page content shifts
display: 'inline-block',
float: 'left',
minWidth: '1.25em',
paddingRight: '1em',
textAlign: 'right',
userSelect: 'none',
borderLeft: '4px solid transparent',
}}
lineProps={(line) => {
if (typeof line === 'boolean') return {};
return highlightLines.has(line)
? ({
'data-line-number': `${line}`,
'data-highlight': 'true',
} as any)
: ({ 'data-line-number': `${line}` } as any);
}}
customStyle={{ padding: '0.8rem' }}
>
{value}
</SyntaxHighlighter>
{showCopy && (
<div className="absolute hidden top-1 right-1 group-hover:block">
<CopyIcon text={value} />
</div>
)}
</div>
</div>
);
}
Expand All @@ -113,6 +133,7 @@ const code: NodeRenderer<Code & { executable: boolean }> = (node) => {
shadow
border={node.executable}
background={!node.executable}
visibility={node.visibility}
/>
);
};
Expand Down
2 changes: 2 additions & 0 deletions packages/myst-to-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import INLINE_EXPRESSION_RENDERERS from './inlineExpression';
import PROOF_RENDERERS from './proof';
import EXERCISE_RENDERERS from './exercise';
import UNKNOWN_MYST_RENDERERS from './unknown';
import BLOCK_RENDERERS from './block';

export { CopyIcon } from './components/CopyIcon';
export { CodeBlock } from './code';
Expand Down Expand Up @@ -51,6 +52,7 @@ export const DEFAULT_RENDERERS: Record<string, NodeRenderer> = {
...EXT_RENDERERS,
...PROOF_RENDERERS,
...EXERCISE_RENDERERS,
...BLOCK_RENDERERS,
};

export function useParse(
Expand Down