mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-04 22:40:29 +03:00
add functionality
This commit is contained in:
parent
96331090c5
commit
bac6763a80
3 changed files with 96 additions and 37 deletions
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue