Skip to content

Commit

Permalink
i
Browse files Browse the repository at this point in the history
  • Loading branch information
holtzy committed Nov 5, 2024
1 parent 0611d4a commit 641b3c6
Show file tree
Hide file tree
Showing 19 changed files with 606 additions and 0 deletions.
225 changes: 225 additions & 0 deletions pages/course/tooltip/tooltip-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import React from 'react';
import TitleAndDescription from '@/component/TitleAndDescription';
import { LayoutCourse } from '@/component/LayoutCourse';
import { lessonList } from '@/util/lessonList';
import { CodeSandbox } from '@/component/CodeSandbox';
import Link from 'next/link';
import { Badge } from '@/component/UI/badge';
import { ExerciseAccordion } from '@/component/ExerciseAccordion';
import {
Exercise,
ExerciseDoubleSandbox,
} from '@/component/ExerciseDoubleSandbox';
import { Caption } from '@/component/UI/Caption';
import { Sidenote } from '@/component/SideNote';
import { ScatterplotBasicDemo } from '@/viz/ScatterplotBasic/ScatterplotBasicDemo';
import { ScatterplotClimateCrisisDemo } from '@/viz/ScatterplotClimateCrisis/ScatterplotClimateCrisisDemo';
import { ChartOrSandbox } from '@/component/ChartOrSandbox';
import { TakeHome } from '@/component/TakeHome';
import { CodeBlock } from '@/component/UI/CodeBlock';
import { Graph2 } from '@/viz/exercise/TooltipFirstSolution/Graph';
import { Graph8 } from '@/viz/exercise/TooltipAddContentSolution/Graph';

const previousURL = '/course/tooltip/introduction';
const currentURL = '/course/tooltip/tooltip-component';
const nextURL = '/course/tooltip/display-on-hover';
const seoDescription = '';

export default function Home() {
const currentLesson = lessonList.find((l) => l.link === currentURL);

if (!currentLesson) {
return null;
}

return (
<LayoutCourse
title={currentLesson.name}
seoDescription={seoDescription}
nextTocItem={lessonList.find((l) => l.link === nextURL)}
previousTocItem={lessonList.find((l) => l.link === previousURL)}
>
<TitleAndDescription
title={currentLesson.name}
lessonStatus={currentLesson.status}
readTime={currentLesson.readTime}
selectedLesson={currentLesson}
description={
<>
<p>
Let's see how to create a <code>Tooltip</code> component that can
be re-used in your codebase when a tooltip is required.
</p>
</>
}
/>
<h2>Minimal tooltip example</h2>
<h3>
💾 <code>InteractionData</code>: where the tooltip info is stored.
</h3>
<p>
Our tooltip component is going to expect one property only: an object of
type InteractionData.
</p>
<p>
This object stores everything we need to build a tooltip. At the very
least we need some positions (xPos and yPos) and a title to display
(name here)
</p>
<CodeBlock
code={`
type InteractionData = {
xPos: number;
yPos: number;
name: string;
}
type TooltipProps = {
interactionData: InteractionData | undefined;
};
`.trim()}
/>
<p>
But we could put many other things! A color for the border, some values
to display, a link to an image.. Anything really.
</p>
<h3>🦴 Tooltip component skeleton</h3>
<p>
The Tooltip component uses some props of type TooltipProps, which is
basically just an interactionData object.
</p>
<p>
If this object is undefined (user is not hovering anything), then we do
not return anything;
</p>
<CodeBlock
code={`
// Tooltip.tsx
export const Tooltip = ({ interactionData }: TooltipProps) => {
if (!interactionData) {
return null;
}
... Do something with interactionData otherwise
};
`.trim()}
/>
<h3>🍔 The meat</h3>
<p>
Now, we just need to return something based on the{' '}
<code>interactionData</code> information.
</p>
<p>
Do not forget to use <code>xPos</code> and <code>yPos</code> to put the
tooltip at the right position!
</p>
<CodeBlock
code={`
const { xPos, yPos, name } = interactionData;
return (
<div
style={{
left: xPos,
top: yPos,
}}
>
<b>{name}</b>
</div>
);
`.trim()}
/>

{/* -
-
-
-
-
-
-
-
*/}
<p>
<br />
</p>
<h2>Exercises</h2>
<ExerciseAccordion
localStorageId={currentLesson.link}
exercises={[
{
title: <span>Your first tooltip!</span>,
content: <ExerciseDoubleSandbox exercise={exercices[0]} />,
},
{
title: <span>Pass more information</span>,
content: <ExerciseDoubleSandbox exercise={exercices[1]} />,
},
]}
/>
</LayoutCourse>
);
}

const exercices: Exercise[] = [
{
whyItMatters: (
<>
<p>
Let's start with a very simple tooltip. We'll see how to improve it
later on.
</p>
</>
),
toDo: (
<ul>
<li>The Sandbox has a circle rendered in SVG.</li>
<li>Create an absolute positionned div on top of the SVG area</li>
<li>
Create a <code>Tooltip</code> component in a <code>Tooltip.tsx</code>{' '}
file.
</li>
<li>
In this div, render a small div exactly where the circle is with one
word in it: <code>hello</code>
</li>
</ul>
),
practiceSandbox: 'exercise/TooltipFirstPractice',
solutionSandbox: 'exercise/TooltipFirstSolution',
},
{
whyItMatters: (
<>
<p>
Keep in mind that you can pass absolutely any information to the
tooltip component to display it.
</p>
<p>
Passing styling information like the marker color to make the tooltip
fit the style is a very good practice.
</p>
</>
),
toDo: (
<ul>
<li>
Pass 3 more information to the <code>Tooltip</code> component:{' '}
<code>xValue</code>, <code>yValue</code> and color (use{' '}
<code>green</code>)
</li>
<li>
Use the <code>color</code> to change the tooltip border color
</li>
<li>
Display <code>xValue</code> and <code>yValue</code> in the tooltip
body.
</li>
</ul>
),
practiceSandbox: 'exercise/TooltipAddContentPractice',
solutionSandbox: 'exercise/TooltipAddContentSolution',
},
];
31 changes: 31 additions & 0 deletions viz/exercise/TooltipAddContentPractice/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Tooltip } from './Tooltip';

const width = 500;
const height = 300;

export const Graph = () => {
return (
<div style={{ position: 'relative' }}>
{/* SVG layer */}
<svg width={width} height={height}>
<circle cx={width / 2} cy={height / 2} r={30} fill="red" />
</svg>

{/* Tooltip Layer */}
<div
style={{
position: 'absolute',
width,
height,
top: 0,
left: 0,
pointerEvents: 'none',
}}
>
<Tooltip
interactionData={{ xPos: width / 2, yPos: height / 2, name: 'hello' }}
/>
</div>
</div>
);
};
31 changes: 31 additions & 0 deletions viz/exercise/TooltipAddContentPractice/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import styles from './tooltip.module.css';

type InteractionData = {
xPos: number;
yPos: number;
name: string;
};

type TooltipProps = {
interactionData: InteractionData | undefined;
};

export const Tooltip = ({ interactionData }: TooltipProps) => {
if (!interactionData) {
return null;
}

const { xPos, yPos, name } = interactionData;

return (
<div
className={styles.tooltip}
style={{
left: xPos,
top: yPos,
}}
>
<b className={styles.title}>{name}</b>
</div>
);
};
6 changes: 6 additions & 0 deletions viz/exercise/TooltipAddContentPractice/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// File used to render something in codesandbox only
import ReactDOM from 'react-dom';
import { Graph } from './Graph';

const rootElement = document.getElementById('root');
ReactDOM.render(<Graph />, rootElement);
28 changes: 28 additions & 0 deletions viz/exercise/TooltipAddContentPractice/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "pie-chart-basic",
"version": "1.0.0",
"description": "",
"keywords": [],
"main": "index.js",
"dependencies": {
"react": "17.0.2",
"react-dom": "17.0.2",
"react-scripts": "4.0.0"
},
"devDependencies": {
"@babel/runtime": "7.13.8",
"typescript": "4.1.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
9 changes: 9 additions & 0 deletions viz/exercise/TooltipAddContentPractice/tooltip.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.tooltip {
position: absolute;
background-color: black;
color: white;
border-radius: 4px;
padding: 4px;
max-width: 100px;
font-size: 14px;
}
38 changes: 38 additions & 0 deletions viz/exercise/TooltipAddContentSolution/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Tooltip } from './Tooltip';

const width = 500;
const height = 300;

export const Graph8 = () => {
return (
<div style={{ position: 'relative' }}>
{/* SVG layer */}
<svg width={width} height={height}>
<circle cx={width / 2} cy={height / 2} r={30} fill="red" />
</svg>

{/* Tooltip Layer */}
<div
style={{
position: 'absolute',
width,
height,
top: 0,
left: 0,
pointerEvents: 'none',
}}
>
<Tooltip
interactionData={{
xPos: width / 2,
yPos: height / 2,
name: 'hello',
xValue: width / 2,
yValue: height / 2,
color: 'green',
}}
/>
</div>
</div>
);
};
Loading

0 comments on commit 641b3c6

Please sign in to comment.