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 {
|
||||
margin: 0;
|
||||
.wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timebox:hover {
|
||||
background-color: blueviolet;
|
||||
.line {
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
background-color: var(--secondary-accent);
|
||||
}
|
||||
|
||||
.timeboxHover {
|
||||
background-color: blue;
|
||||
.timelineSections {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.textbox {
|
||||
background-color: maroon;
|
||||
.timelineSection {
|
||||
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;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.textboxText {
|
||||
overflow-y: scroll;
|
||||
word-break: break-all;
|
||||
.textHover {
|
||||
border: 2px solid var(--secondary-accent-light);
|
||||
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 styles from "./Timeline.module.css";
|
||||
|
@ -21,24 +13,14 @@ interface TimelineProps {
|
|||
width: number;
|
||||
/** Height of the entire timeline, in pixels. */
|
||||
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 */
|
||||
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. */
|
||||
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. */
|
||||
textWidth?: number;
|
||||
/** Height of text label, in pixels. */
|
||||
textHeight?: number;
|
||||
/** Distance between labels to middle line, in pixels. */
|
||||
labelsOffset?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
|
@ -46,120 +28,112 @@ export default function Timeline({
|
|||
data,
|
||||
width,
|
||||
height,
|
||||
padding = 20,
|
||||
timelinePosition = width / 2,
|
||||
nodeGap = data.length > 1
|
||||
? (height - 2 * padding) / (data.length - 1)
|
||||
: height - 2 * padding,
|
||||
isTimeUppercase = true,
|
||||
timeXOffset = -30,
|
||||
timeWidth = 100,
|
||||
textXOffset = 30,
|
||||
textWidth = 100,
|
||||
textHeight = 100,
|
||||
timeWidth = 200,
|
||||
textWidth = 300,
|
||||
labelsOffset = 50,
|
||||
className,
|
||||
}: TimelineProps) {
|
||||
const dataWithPositions = data.map((data, i) => ({
|
||||
x: timelinePosition,
|
||||
y: i * nodeGap + padding,
|
||||
time: isTimeUppercase ? data.time.toUpperCase() : data.time,
|
||||
text: data.text,
|
||||
}));
|
||||
|
||||
return (
|
||||
<svg className={className} width={width} height={height}>
|
||||
<LinePath
|
||||
data={dataWithPositions.map((data) => [data.x, data.y])}
|
||||
stroke="#fff"
|
||||
strokeWidth={10}
|
||||
/>
|
||||
{dataWithPositions.map((data, i) => (
|
||||
<TimelineAnnotation
|
||||
positionData={data}
|
||||
timeXOffset={timeXOffset}
|
||||
timeWidth={timeWidth}
|
||||
textXOffset={textXOffset}
|
||||
textWidth={textWidth}
|
||||
textHeight={textHeight}
|
||||
key={`${data.time}${i}`}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
<div
|
||||
className={
|
||||
className ? `${className} ${styles.wrapper}` : `${styles.wrapper}`
|
||||
}
|
||||
style={{ width: width, height: height }}
|
||||
>
|
||||
<div
|
||||
className={styles.line}
|
||||
style={{ height: height, left: width / 2 }}
|
||||
></div>
|
||||
<div className={styles.timelineSections} style={{ width: width }}>
|
||||
{data.map((datum) => (
|
||||
<TimelineSection
|
||||
key={datum.time}
|
||||
datum={datum}
|
||||
width={width}
|
||||
isTimeUppercase={isTimeUppercase}
|
||||
timeWidth={timeWidth}
|
||||
textWidth={textWidth}
|
||||
labelsOffset={labelsOffset}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface TimelineAnnotationProps {
|
||||
positionData: {
|
||||
x: number;
|
||||
y: number;
|
||||
time: string;
|
||||
text: string;
|
||||
};
|
||||
timeXOffset: number;
|
||||
interface TimelineSectionProps {
|
||||
datum: TimelineData;
|
||||
width: number;
|
||||
isTimeUppercase: boolean;
|
||||
timeWidth: number;
|
||||
textXOffset: number;
|
||||
textWidth: number;
|
||||
textHeight: number;
|
||||
labelsOffset: number;
|
||||
}
|
||||
|
||||
function TimelineAnnotation({
|
||||
positionData,
|
||||
timeXOffset,
|
||||
function TimelineSection({
|
||||
datum,
|
||||
width,
|
||||
isTimeUppercase,
|
||||
timeWidth,
|
||||
textXOffset,
|
||||
|
||||
textWidth,
|
||||
textHeight,
|
||||
}: TimelineAnnotationProps) {
|
||||
const [hover, setHover] = useState(false);
|
||||
labelsOffset,
|
||||
}: TimelineSectionProps) {
|
||||
const [onHover, setHover] = useState(false);
|
||||
|
||||
function handleMouseEnter() {
|
||||
const handleMouseEnter = () => {
|
||||
setHover(true);
|
||||
}
|
||||
console.log(onHover);
|
||||
};
|
||||
const handleMouseLeave = () => setHover(false);
|
||||
|
||||
function handleMouseLeave() {
|
||||
setHover(false);
|
||||
}
|
||||
console.log(hover);
|
||||
// divs for customizable margins are necessary, absolute positioning loses vertical flex-box functionality
|
||||
return (
|
||||
<Group>
|
||||
<Annotation x={positionData.x} y={positionData.y} dx={timeXOffset} dy={0}>
|
||||
<Connector />
|
||||
<HtmlLabel showAnchorLine={false} verticalAnchor="start">
|
||||
<h1
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
className={`${styles.timebox} ${hover ? styles.timeboxHover : ""}`}
|
||||
style={{ width: timeWidth }}
|
||||
>
|
||||
{positionData.time}
|
||||
</h1>
|
||||
</HtmlLabel>
|
||||
</Annotation>
|
||||
<Annotation x={positionData.x} y={positionData.y} dx={textXOffset} dy={0}>
|
||||
<Connector />
|
||||
<CircleSubject
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
radius={10}
|
||||
fill="#000"
|
||||
/>
|
||||
<CircleSubject radius={4} fill="red" />
|
||||
<HtmlLabel showAnchorLine={false} verticalAnchor="start">
|
||||
<div
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
className={styles.textbox}
|
||||
style={{ width: textWidth, height: textHeight }}
|
||||
>
|
||||
<p
|
||||
className={styles.textboxText}
|
||||
style={{ maxHeight: textHeight - 10 }}
|
||||
>
|
||||
{positionData.text}
|
||||
</p>
|
||||
</div>
|
||||
</HtmlLabel>
|
||||
</Annotation>
|
||||
</Group>
|
||||
<div className={styles.timelineSection}>
|
||||
<div
|
||||
style={{
|
||||
width: (width - labelsOffset - labelsOffset - 30) / 2 - timeWidth,
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
className={onHover ? `${styles.time} ${styles.timeHover}` : styles.time}
|
||||
style={{
|
||||
width: timeWidth,
|
||||
}}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
{isTimeUppercase ? datum.time.toUpperCase() : datum.time}
|
||||
</div>
|
||||
<div style={{ width: labelsOffset }}></div>
|
||||
<div
|
||||
className={styles.circle}
|
||||
style={{ width: 30 }}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<div
|
||||
className={styles.innerCircle}
|
||||
style={{ display: onHover ? "inline" : "none" }}
|
||||
></div>
|
||||
</div>
|
||||
<div style={{ width: labelsOffset }}></div>
|
||||
<div
|
||||
className={onHover ? `${styles.text} ${styles.textHover}` : styles.text}
|
||||
style={{
|
||||
width: textWidth,
|
||||
}}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
{datum.text}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: (width - labelsOffset - labelsOffset - 30) / 2 - textWidth,
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -67,27 +67,27 @@ export const moreMockCategoricalData = [
|
|||
|
||||
export const mockTimelineData = [
|
||||
{
|
||||
time: "Problem 1",
|
||||
text: "Overflow-y scroll text not supported by svg",
|
||||
time: "Fall 2020",
|
||||
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",
|
||||
text: "Hover effects don't seem to work with <foreignObject>",
|
||||
time: "Winter 2021",
|
||||
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",
|
||||
text: "Need to add a max-height to these boxes",
|
||||
time: "Spring 2021",
|
||||
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",
|
||||
text: "Styling",
|
||||
time: "Fall 2021",
|
||||
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",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
|
||||
time: "Winter 2022",
|
||||
text: "Lorem ipsum dolor sit amet, consectetur adipi",
|
||||
},
|
||||
{
|
||||
time: "Spring 2020",
|
||||
text: "Lorem ipsum doldolor in repre",
|
||||
time: "Spring 2022",
|
||||
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>
|
||||
<code>{"<Timeline />"}</code>
|
||||
</h2>
|
||||
<Timeline data={mockTimelineData} width={400} height={1200} />
|
||||
<Timeline data={mockTimelineData} width={800} height={1600} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue