Redo everything
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
42638cbdb5
commit
c1b8ae469f
|
@ -1,21 +1,79 @@
|
||||||
.timebox {
|
.wrapper {
|
||||||
margin: 0;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timebox:hover {
|
.line {
|
||||||
background-color: blueviolet;
|
position: absolute;
|
||||||
|
width: 5px;
|
||||||
|
background-color: var(--secondary-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeboxHover {
|
.timelineSections {
|
||||||
background-color: blue;
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textbox {
|
.timelineSection {
|
||||||
background-color: maroon;
|
width: 100%;
|
||||||
|
height: inherit;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
margin: 0px;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--secondary-accent);
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeHover {
|
||||||
|
color: var(--secondary-accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
margin-left: 2px;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 30px;
|
||||||
|
background-color: var(--secondary-accent);
|
||||||
|
box-shadow: 0px 0px 30px var(--secondary-accent);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerCircle {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: var(--label);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
position: absolute;
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--label);
|
||||||
|
background-color: var(--card-background);
|
||||||
|
position: relative;
|
||||||
|
height: fit-content;
|
||||||
|
word-wrap: break-word;
|
||||||
|
border-radius: 10px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textboxText {
|
.textHover {
|
||||||
overflow-y: scroll;
|
border: 2px solid var(--secondary-accent-light);
|
||||||
word-break: break-all;
|
box-shadow: 0px 0px 20px var(--secondary-accent);
|
||||||
}
|
}
|
|
@ -1,11 +1,3 @@
|
||||||
import {
|
|
||||||
Connector,
|
|
||||||
CircleSubject,
|
|
||||||
Annotation,
|
|
||||||
HtmlLabel,
|
|
||||||
} from "@visx/annotation";
|
|
||||||
import { Group } from "@visx/group";
|
|
||||||
import { LinePath } from "@visx/shape";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import styles from "./Timeline.module.css";
|
import styles from "./Timeline.module.css";
|
||||||
|
@ -21,24 +13,14 @@ interface TimelineProps {
|
||||||
width: number;
|
width: number;
|
||||||
/** Height of the entire timeline, in pixels. */
|
/** Height of the entire timeline, in pixels. */
|
||||||
height: number;
|
height: number;
|
||||||
/** Padding top and bottom, in pixels. */
|
|
||||||
padding: number;
|
|
||||||
/** Location of timeline width-wise, in pixels. Default is width / 2. */
|
|
||||||
timelinePosition?: number;
|
|
||||||
/** Distance between consecutive nodes on timeline, in pixels. Default is evenly spaced. padding is not calculated if user specifies this value. */
|
|
||||||
nodeGap?: number;
|
|
||||||
/** Whether the time is transformed to uppercase */
|
/** Whether the time is transformed to uppercase */
|
||||||
isTimeUppercase?: boolean;
|
isTimeUppercase?: boolean;
|
||||||
/** Offset between the line and the time label, in pixels (negative for left offset, positive for right offset). */
|
|
||||||
timeXOffset?: number;
|
|
||||||
/** Width of time label, in pixels. */
|
/** Width of time label, in pixels. */
|
||||||
timeWidth?: number;
|
timeWidth?: number;
|
||||||
/** Offset between the line and the text label, in pixels (negative for left offset, positive for right offset). */
|
|
||||||
textXOffset?: number;
|
|
||||||
/** Width of text label, in pixels. */
|
/** Width of text label, in pixels. */
|
||||||
textWidth?: number;
|
textWidth?: number;
|
||||||
/** Height of text label, in pixels. */
|
/** Distance between labels to middle line, in pixels. */
|
||||||
textHeight?: number;
|
labelsOffset?: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,120 +28,112 @@ export default function Timeline({
|
||||||
data,
|
data,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
padding = 20,
|
|
||||||
timelinePosition = width / 2,
|
|
||||||
nodeGap = data.length > 1
|
|
||||||
? (height - 2 * padding) / (data.length - 1)
|
|
||||||
: height - 2 * padding,
|
|
||||||
isTimeUppercase = true,
|
isTimeUppercase = true,
|
||||||
timeXOffset = -30,
|
timeWidth = 200,
|
||||||
timeWidth = 100,
|
textWidth = 300,
|
||||||
textXOffset = 30,
|
labelsOffset = 50,
|
||||||
textWidth = 100,
|
|
||||||
textHeight = 100,
|
|
||||||
className,
|
className,
|
||||||
}: TimelineProps) {
|
}: TimelineProps) {
|
||||||
const dataWithPositions = data.map((data, i) => ({
|
|
||||||
x: timelinePosition,
|
|
||||||
y: i * nodeGap + padding,
|
|
||||||
time: isTimeUppercase ? data.time.toUpperCase() : data.time,
|
|
||||||
text: data.text,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg className={className} width={width} height={height}>
|
<div
|
||||||
<LinePath
|
className={
|
||||||
data={dataWithPositions.map((data) => [data.x, data.y])}
|
className ? `${className} ${styles.wrapper}` : `${styles.wrapper}`
|
||||||
stroke="#fff"
|
}
|
||||||
strokeWidth={10}
|
style={{ width: width, height: height }}
|
||||||
/>
|
>
|
||||||
{dataWithPositions.map((data, i) => (
|
<div
|
||||||
<TimelineAnnotation
|
className={styles.line}
|
||||||
positionData={data}
|
style={{ height: height, left: width / 2 }}
|
||||||
timeXOffset={timeXOffset}
|
></div>
|
||||||
timeWidth={timeWidth}
|
<div className={styles.timelineSections} style={{ width: width }}>
|
||||||
textXOffset={textXOffset}
|
{data.map((datum) => (
|
||||||
textWidth={textWidth}
|
<TimelineSection
|
||||||
textHeight={textHeight}
|
key={datum.time}
|
||||||
key={`${data.time}${i}`}
|
datum={datum}
|
||||||
/>
|
width={width}
|
||||||
))}
|
isTimeUppercase={isTimeUppercase}
|
||||||
</svg>
|
timeWidth={timeWidth}
|
||||||
|
textWidth={textWidth}
|
||||||
|
labelsOffset={labelsOffset}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TimelineAnnotationProps {
|
interface TimelineSectionProps {
|
||||||
positionData: {
|
datum: TimelineData;
|
||||||
x: number;
|
width: number;
|
||||||
y: number;
|
isTimeUppercase: boolean;
|
||||||
time: string;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
timeXOffset: number;
|
|
||||||
timeWidth: number;
|
timeWidth: number;
|
||||||
textXOffset: number;
|
|
||||||
textWidth: number;
|
textWidth: number;
|
||||||
textHeight: number;
|
labelsOffset: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TimelineAnnotation({
|
function TimelineSection({
|
||||||
positionData,
|
datum,
|
||||||
timeXOffset,
|
width,
|
||||||
|
isTimeUppercase,
|
||||||
timeWidth,
|
timeWidth,
|
||||||
textXOffset,
|
|
||||||
textWidth,
|
textWidth,
|
||||||
textHeight,
|
labelsOffset,
|
||||||
}: TimelineAnnotationProps) {
|
}: TimelineSectionProps) {
|
||||||
const [hover, setHover] = useState(false);
|
const [onHover, setHover] = useState(false);
|
||||||
|
|
||||||
function handleMouseEnter() {
|
const handleMouseEnter = () => {
|
||||||
setHover(true);
|
setHover(true);
|
||||||
}
|
console.log(onHover);
|
||||||
|
};
|
||||||
|
const handleMouseLeave = () => setHover(false);
|
||||||
|
|
||||||
function handleMouseLeave() {
|
// divs for customizable margins are necessary, absolute positioning loses vertical flex-box functionality
|
||||||
setHover(false);
|
|
||||||
}
|
|
||||||
console.log(hover);
|
|
||||||
return (
|
return (
|
||||||
<Group>
|
<div className={styles.timelineSection}>
|
||||||
<Annotation x={positionData.x} y={positionData.y} dx={timeXOffset} dy={0}>
|
<div
|
||||||
<Connector />
|
style={{
|
||||||
<HtmlLabel showAnchorLine={false} verticalAnchor="start">
|
width: (width - labelsOffset - labelsOffset - 30) / 2 - timeWidth,
|
||||||
<h1
|
}}
|
||||||
onMouseEnter={handleMouseEnter}
|
></div>
|
||||||
onMouseLeave={handleMouseLeave}
|
<div
|
||||||
className={`${styles.timebox} ${hover ? styles.timeboxHover : ""}`}
|
className={onHover ? `${styles.time} ${styles.timeHover}` : styles.time}
|
||||||
style={{ width: timeWidth }}
|
style={{
|
||||||
>
|
width: timeWidth,
|
||||||
{positionData.time}
|
}}
|
||||||
</h1>
|
onMouseEnter={handleMouseEnter}
|
||||||
</HtmlLabel>
|
onMouseLeave={handleMouseLeave}
|
||||||
</Annotation>
|
>
|
||||||
<Annotation x={positionData.x} y={positionData.y} dx={textXOffset} dy={0}>
|
{isTimeUppercase ? datum.time.toUpperCase() : datum.time}
|
||||||
<Connector />
|
</div>
|
||||||
<CircleSubject
|
<div style={{ width: labelsOffset }}></div>
|
||||||
onMouseEnter={handleMouseEnter}
|
<div
|
||||||
onMouseLeave={handleMouseLeave}
|
className={styles.circle}
|
||||||
radius={10}
|
style={{ width: 30 }}
|
||||||
fill="#000"
|
onMouseEnter={handleMouseEnter}
|
||||||
/>
|
onMouseLeave={handleMouseLeave}
|
||||||
<CircleSubject radius={4} fill="red" />
|
>
|
||||||
<HtmlLabel showAnchorLine={false} verticalAnchor="start">
|
<div
|
||||||
<div
|
className={styles.innerCircle}
|
||||||
onMouseEnter={handleMouseEnter}
|
style={{ display: onHover ? "inline" : "none" }}
|
||||||
onMouseLeave={handleMouseLeave}
|
></div>
|
||||||
className={styles.textbox}
|
</div>
|
||||||
style={{ width: textWidth, height: textHeight }}
|
<div style={{ width: labelsOffset }}></div>
|
||||||
>
|
<div
|
||||||
<p
|
className={onHover ? `${styles.text} ${styles.textHover}` : styles.text}
|
||||||
className={styles.textboxText}
|
style={{
|
||||||
style={{ maxHeight: textHeight - 10 }}
|
width: textWidth,
|
||||||
>
|
}}
|
||||||
{positionData.text}
|
onMouseEnter={handleMouseEnter}
|
||||||
</p>
|
onMouseLeave={handleMouseLeave}
|
||||||
</div>
|
>
|
||||||
</HtmlLabel>
|
{datum.text}
|
||||||
</Annotation>
|
</div>
|
||||||
</Group>
|
<div
|
||||||
|
style={{
|
||||||
|
width: (width - labelsOffset - labelsOffset - 30) / 2 - textWidth,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,27 +67,27 @@ export const moreMockCategoricalData = [
|
||||||
|
|
||||||
export const mockTimelineData = [
|
export const mockTimelineData = [
|
||||||
{
|
{
|
||||||
time: "Problem 1",
|
time: "Fall 2020",
|
||||||
text: "Overflow-y scroll text not supported by svg",
|
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: "Problem 2",
|
time: "Winter 2021",
|
||||||
text: "Hover effects don't seem to work with <foreignObject>",
|
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: "Problem 3",
|
time: "Spring 2021",
|
||||||
text: "Need to add a max-height to these boxes",
|
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor i",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: "Problem 4",
|
time: "Fall 2021",
|
||||||
text: "Styling",
|
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proid",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: "Winter 2020",
|
time: "Winter 2022",
|
||||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
|
text: "Lorem ipsum dolor sit amet, consectetur adipi",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: "Spring 2020",
|
time: "Spring 2022",
|
||||||
text: "Lorem ipsum doldolor in repre",
|
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut en",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -68,7 +68,7 @@ export default function Home() {
|
||||||
<h2>
|
<h2>
|
||||||
<code>{"<Timeline />"}</code>
|
<code>{"<Timeline />"}</code>
|
||||||
</h2>
|
</h2>
|
||||||
<Timeline data={mockTimelineData} width={400} height={1200} />
|
<Timeline data={mockTimelineData} width={800} height={1600} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue