add functionality

This commit is contained in:
Gimle Larpes 2025-06-12 23:05:21 +02:00
parent 96331090c5
commit bac6763a80
3 changed files with 96 additions and 37 deletions

View file

@ -162,7 +162,7 @@ export function RenderElement({ attributes, element, children }: RenderElementPr
visibility="Hover" visibility="Hover"
hideTrack hideTrack
> >
<div className={css.CodeBlockInternal}>{children}</div> <div className={css.CodeBlockInternal()}>{children}</div>
</Scroll> </Scroll>
</Text> </Text>
); );

View file

@ -4,6 +4,8 @@ import React, {
ReactEventHandler, ReactEventHandler,
Suspense, Suspense,
lazy, lazy,
useCallback,
useMemo,
useState, useState,
} from 'react'; } from 'react';
import { import {
@ -202,45 +204,103 @@ export const highlightText = (
); );
}); });
export function CodeBlock(children: ChildNode[], opts: HTMLReactParserOptions) { type CodeBlockControlsProps = {
const [copied, setCopied] = useState(false); copied: boolean;
const [collapsed, setCollapsed] = useState(false); onCopy: () => void;
collapsible: boolean;
//HANDLECOPY FUNCTION HERE? collapsed: boolean;
const handleCopyClick = () => { onToggle: () => void;
//const codeText = extractTextFromChildren(children); // IDK HOW THIS SHOULD BE DONE };
//copyToClipboard(codeText);
setCopied(true);
};
function CodeBlockControls({
copied,
onCopy,
collapsible,
collapsed,
onToggle,
}: CodeBlockControlsProps) {
return ( return (
// Probably need a better copy icon // Needs a better copy icon
<> <div className={css.CodeBlockControls}>
<div className={css.CodeBlockControls}> <IconButton
variant="Secondary"
size="300"
radii="300"
onClick={onCopy}
aria-label="Copy Code Block"
>
<Icon src={copied ? Icons.Check : Icons.File} size="50" />
</IconButton>
{collapsible && (
<IconButton <IconButton
variant="Secondary" variant="Secondary"
size="300" size="300"
radii="300" radii="300"
onClick={() => { onClick={onToggle}
handleCopyClick(); aria-expanded={!collapsed}
}} aria-controls="code-block-content"
> aria-label={collapsed ? 'Show Full Code Block' : 'Show Code Block Preview'}
<Icon src={copied ? Icons.Check : Icons.File} size="50" /> style={collapsed ? { visibility: 'visible' } : {}}
</IconButton>
<IconButton
variant="Secondary" // Collapse - how to show icon even when not hovering if collapsed?
size="300" //This should be somewhat persistent - how?
radii="300"
onClick={() => {
setCollapsed(!collapsed);
}}
> >
<Icon src={collapsed ? Icons.ChevronRight : Icons.ChevronBottom} size="50" /> <Icon src={collapsed ? Icons.ChevronRight : Icons.ChevronBottom} size="50" />
</IconButton> </IconButton>
</div> )}
<Scroll direction="Horizontal" variant="Secondary" size="300" visibility="Hover" hideTrack> </div>
<div className={css.CodeBlockInternal({ collapsed })}>{domToReact(children, opts)}</div> );
}
export function CodeBlock(children: ChildNode[], opts: HTMLReactParserOptions) {
const LINE_LIMIT = 14;
const extractTextFromChildren = useCallback((nodes: ChildNode[]): string => {
let text = '';
nodes.forEach((node) => {
if (node.type === 'text') {
text += node.data;
} else if (node instanceof Element && node.children) {
text += extractTextFromChildren(node.children);
}
});
return text;
}, []);
const [copied, setCopied] = useState(false);
const collapsible = useMemo(
() => extractTextFromChildren(children).split('\n').length > LINE_LIMIT,
[children, extractTextFromChildren]
);
const [collapsed, setCollapsed] = useState(collapsible);
const handleCopy = useCallback(() => {
copyToClipboard(extractTextFromChildren(children));
setCopied(true);
}, [children, extractTextFromChildren]);
const toggleCollapse = useCallback(() => {
setCollapsed((prev) => !prev);
}, []);
return (
<>
<CodeBlockControls
copied={copied}
onCopy={handleCopy}
collapsible={collapsible}
collapsed={collapsed}
onToggle={toggleCollapse}
/>
<Scroll
direction={collapsed ? 'Both' : 'Horizontal'}
variant="Secondary"
size="300"
visibility="Hover"
hideTrack
>
<div id="code-block-content" className={css.CodeBlockInternal({ collapsed })}>
{domToReact(children, opts)}
</div>
</Scroll> </Scroll>
</> </>
); );
@ -321,8 +381,7 @@ export const getReactCustomHtmlParser = (
if (name === 'pre') { if (name === 'pre') {
return ( return (
//SHOULD ALL OF THIS BE IN A renderCodeBlock function? not text, but one layr down <Text {...props} as="pre" className={css.CodeBlock}>
<Text {...props} as="pre" className={css.CodeBlock} style={{ position: 'relative' }}>
{CodeBlock(children, opts)} {CodeBlock(children, opts)}
</Text> </Text>
); );

View file

@ -85,6 +85,7 @@ export const CodeBlock = style([
MarginSpaced, MarginSpaced,
{ {
fontStyle: 'normal', fontStyle: 'normal',
position: 'relative',
}, },
]); ]);
export const CodeBlockInternal = recipe({ export const CodeBlockInternal = recipe({
@ -98,8 +99,7 @@ export const CodeBlockInternal = recipe({
variants: { variants: {
collapsed: { collapsed: {
true: { true: {
maxHeight: config.space.S700, // should controls (collapse) be visible when collapsed? - yes, what's the best way to do this? maxHeight: `calc(${config.size.ModalDrawerWidth} - ${config.lineHeight.T400} / 2)`,
overflow: 'hidden', // collapse should also only be visible if the doc has more than 1 line
}, },
}, },
}, },
@ -108,10 +108,10 @@ export const CodeBlockControls = style({
position: 'absolute', position: 'absolute',
top: config.space.S200, top: config.space.S200,
right: config.space.S200, right: config.space.S200,
display: 'none', visibility: 'hidden',
selectors: { selectors: {
[`${CodeBlock}:hover &`]: { [`${CodeBlock}:hover &`]: {
display: 'inline', visibility: 'visible',
}, },
}, },
}); });