[site/components][f]: tooltip with clipped content

This commit is contained in:
olayway 2022-05-18 12:57:53 +02:00
parent 28c087e31d
commit 5589b2244d
6 changed files with 62 additions and 55 deletions

View File

@ -15,7 +15,7 @@ import {
useRole, useRole,
} from '@floating-ui/react-dom-interactions' } from '@floating-ui/react-dom-interactions'
import getAbsolutePath from '../utils/absolutePath' import siteConfig from '../config/siteConfig.js'
import documentExtract from '../utils/documentExtract' import documentExtract from '../utils/documentExtract'
import { Tooltip } from './Tooltip' import { Tooltip } from './Tooltip'
@ -52,7 +52,7 @@ export const Anchor = (props) => {
] ]
}); });
const { getReferenceProps, getFloatingProps } = useInteractions([ const { getReferenceProps, getFloatingProps } = useInteractions([
useHover(context, { delay: { open: 100, close: 0 } }), useHover(context, { delay: 100 }),
useRole(context, { role: 'tooltip' }), useRole(context, { role: 'tooltip' }),
useDismiss(context, { ancestorScroll: true }) useDismiss(context, { ancestorScroll: true })
]); ]);
@ -64,21 +64,17 @@ export const Anchor = (props) => {
}, [showTooltip]) }, [showTooltip])
const fetchPreview = async () => { const fetchPreview = async () => {
console.log("Fetching...")
setPreviewLoaded(false); setPreviewLoaded(false);
const basePath = "http://localhost:3000"; // TODO const path = new URL(props.href, document.baseURI).pathname;
const currentPath = router.asPath; const rawContentPath = [siteConfig.rawContentBaseUrl, path].join("")
const relativePath = props.href.split(".")[0]; // TBD temp remove .md const response = await fetch(rawContentPath);
const absolutePath = getAbsolutePath({ currentPath, basePath, relativePath });
const response = await fetch(absolutePath);
if (response.status !== 200) { if (response.status !== 200) {
// TODO // TODO
console.log(`Looks like there was a problem. Status Code: ${response.status}`) console.log(`Looks like there was a problem. Status Code: ${response.status}`)
return return
} }
const html = await response.text(); const md = await response.text();
const extract = documentExtract(html); const extract = documentExtract(md);
setPreview(extract); setPreview(extract);
setPreviewLoaded(true); setPreviewLoaded(true);
@ -93,24 +89,25 @@ export const Anchor = (props) => {
return <Fragment> return <Fragment>
<a {...props} {...getReferenceProps({ref: reference})} /> <a {...props} {...getReferenceProps({ref: reference})} />
<FloatingPortal> <FloatingPortal>
<Tooltip { showTooltip && previewLoaded &&
{...getFloatingProps({ <Tooltip
ref: floating, {...getFloatingProps({
theme: 'light', ref: floating,
arrowRef, theme: 'light',
arrowX, arrowRef,
arrowY, arrowX,
placement, arrowY,
style: { placement,
position: strategy, style: {
visibility: showTooltip && previewLoaded ? 'visible' : 'hidden', position: strategy,
left: x ?? '', left: x ?? '',
top: y ?? '', top: y ?? '',
}, },
})} })}
> >
{ preview } { preview }
</Tooltip> </Tooltip>
}
</FloatingPortal> </FloatingPortal>
</Fragment>; </Fragment>;
} }

View File

@ -1,18 +1,24 @@
import React from 'react'; import React from 'react';
const tooltipStyles = (theme) => ({ const tooltipBoxStyle = (theme) => ({
height: 'auto', height: 'auto',
maxWidth: '80vw', maxWidth: '60vw',
padding: '1rem 2rem', padding: '1rem',
background: theme === 'light' ? '#fff' : '#000', background: theme === 'light' ? '#fff' : '#000',
color: theme === 'light' ? 'rgb(99, 98, 98)' : '#A8A8A8', color: theme === 'light' ? 'rgb(99, 98, 98)' : '#A8A8A8',
borderRadius: '4px', borderRadius: '4px',
boxShadow: 'rgba(0, 0, 0, 0.55) 0px 0px 16px -3px', boxShadow: 'rgba(0, 0, 0, 0.55) 0px 0px 16px -3px',
fontSize: '0.9em'
}) })
const tooltipArrowStyles = ({ theme, x, y, side }) => ({ const tooltipBodyStyle = () => ({
maxHeight: '3.6rem',
position: 'relative',
lineHeight: '1.2rem',
overflow: 'hidden',
})
const tooltipArrowStyle = ({ theme, x, y, side }) => ({
position: "absolute", position: "absolute",
left: x != null ? `${x}px` : '', left: x != null ? `${x}px` : '',
top: y != null ? `${y}px` : '', top: y != null ? `${y}px` : '',
@ -36,11 +42,13 @@ export const Tooltip = React.forwardRef((props, ref) => {
}[placement.split('-')[0]]; }[placement.split('-')[0]];
return ( return (
<div {...tooltipProps} ref={ref}> <div className="tooltip" {...tooltipProps} ref={ref}>
<div style={ tooltipStyles(theme) }> <div className="tooltip-box" style={ tooltipBoxStyle(theme) }>
{ children } <div className="tooltip-body" style={ tooltipBodyStyle() }>
{ children }
</div>
</div> </div>
<div ref={arrowRef} style={ tooltipArrowStyles({ <div className="tooltip-arrow" ref={arrowRef} style={ tooltipArrowStyle({
theme, theme,
x: arrowX, x: arrowX,
y: arrowY, y: arrowY,

View File

@ -5,6 +5,7 @@ const siteConfig = {
url: "https://web3.lifeitself.us", url: "https://web3.lifeitself.us",
repoRoot: "https://github.com/life-itself/web3", repoRoot: "https://github.com/life-itself/web3",
repoEditPath: "/edit/main/", repoEditPath: "/edit/main/",
rawContentBaseUrl: "https://raw.githubusercontent.com/life-itself/web3/main",
tagline: "", tagline: "",
description: description:
"Introductions to key concepts and ideas in crypto and web3. Plus in-depth evaluation of its potential impact.", "Introductions to key concepts and ideas in crypto and web3. Plus in-depth evaluation of its potential impact.",

View File

@ -27,3 +27,15 @@ body {
.extra-small { .extra-small {
font-size: 0.50rem; font-size: 0.50rem;
} }
/* tooltip fade-out clip */
.tooltip-body::after {
content: "";
text-align: right;
position: absolute;
bottom: 0;
right: 0;
width: 10%;
height: 1.2em;
background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50%);
}

View File

@ -1,9 +0,0 @@
const absolutePath = ({ currentPath, basePath, relativePath }) => {
const absolutePath = currentPath.slice(1).split("/")
absolutePath.pop(); // remove current page name
absolutePath.unshift(basePath);
absolutePath.push(relativePath);
return absolutePath.join("/");
};
export default absolutePath;

View File

@ -1,15 +1,13 @@
import { unified } from 'unified' import { unified } from 'unified'
import rehypeParse from 'rehype-parse' import remarkParse from 'remark-parse'
import find from 'unist-util-find' import find from 'unist-util-find'
import { toString } from 'hast-util-to-string' import { toString } from 'mdast-util-to-string'
// get first paragraph inside article's main tag // get first paragraph
const documentExtract = (htmlString) => { const documentExtract = (md) => {
const hast = unified().use(rehypeParse).parse(htmlString); const mdast = unified().use(remarkParse).parse(md);
const article = find(hast, (node) => node.tagName === "article"); let paragraph = find(mdast, (node) => node.type === "paragraph");
const main = find(article, (node) => node.tagName === "main");
const paragraph = find(main, (node) => node.tagName === "p");
return toString(paragraph); return toString(paragraph);
} }