Code review fixes
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
3de0f67ccb
commit
4f6f3265fd
|
@ -1,15 +1,17 @@
|
||||||
.wrapper {
|
.wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: calc(5rem / 16);
|
height: 100%;
|
||||||
|
border-radius: calc(10rem / 16);
|
||||||
background-color: var(--secondary-accent);
|
background-color: var(--secondary-accent);
|
||||||
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timelineSections {
|
.timelineSections {
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -20,7 +22,7 @@
|
||||||
|
|
||||||
.timelineSection {
|
.timelineSection {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: inherit;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -35,15 +37,7 @@
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeHover {
|
|
||||||
color: var(--secondary-accent-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
margin-left: calc(2rem / 16);
|
|
||||||
width: calc(30rem / 16);
|
|
||||||
height: calc(30rem / 16);
|
|
||||||
border-radius: calc(30rem / 16);
|
|
||||||
background-color: var(--secondary-accent);
|
background-color: var(--secondary-accent);
|
||||||
box-shadow: calc(0rem / 16) calc(0rem / 16) calc(30rem / 16) var(--secondary-accent);
|
box-shadow: calc(0rem / 16) calc(0rem / 16) calc(30rem / 16) var(--secondary-accent);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -52,10 +46,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.innerCircle {
|
.innerCircle {
|
||||||
width: calc(15rem / 16);
|
|
||||||
height: calc(15rem / 16);
|
|
||||||
border-radius: calc(15rem / 16);
|
|
||||||
background-color: var(--label);
|
background-color: var(--label);
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
@ -66,12 +58,21 @@
|
||||||
font-size: calc(20rem / 16);
|
font-size: calc(20rem / 16);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--label);
|
color: var(--label);
|
||||||
|
border: calc(2rem / 16) solid var(--card-background);
|
||||||
background-color: var(--card-background);
|
background-color: var(--card-background);
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textHover {
|
.timelineSection:hover .time {
|
||||||
|
color: var(--secondary-accent-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timelineSection:hover .innerCircle {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timelineSection:hover .text {
|
||||||
border: calc(2rem / 16) solid var(--secondary-accent-light);
|
border: calc(2rem / 16) solid var(--secondary-accent-light);
|
||||||
box-shadow: calc(0rem / 16) calc(0rem / 16) calc(20rem / 16) var(--secondary-accent);
|
box-shadow: calc(0rem / 16) calc(0rem / 16) calc(20rem / 16) var(--secondary-accent);
|
||||||
}
|
}
|
|
@ -11,50 +11,78 @@ interface TimelineProps {
|
||||||
data: TimelineData[];
|
data: TimelineData[];
|
||||||
/** Width of the entire timeline, in pixels. */
|
/** Width of the entire timeline, in pixels. */
|
||||||
width: number;
|
width: number;
|
||||||
/** Height of the entire timeline, in pixels. */
|
/** Whether the time is transformed to uppercase. */
|
||||||
height: number;
|
|
||||||
/** Whether the time is transformed to uppercase */
|
|
||||||
isTimeUppercase?: boolean;
|
isTimeUppercase?: boolean;
|
||||||
|
/** Width of the middle timeline line, in pixels */
|
||||||
|
lineWidth?: number;
|
||||||
|
/** Width of the outer circles on the timeline, in pixels. */
|
||||||
|
outerCircleWidth?: number;
|
||||||
|
/** Width of the inner circles on the timeline, in pixels. */
|
||||||
|
innerCircleWidth?: number;
|
||||||
/** Width of time label, in pixels. */
|
/** Width of time label, in pixels. */
|
||||||
timeWidth?: number;
|
timeWidth?: number;
|
||||||
/** Width of text label, in pixels. */
|
/** Width of text label, in pixels. */
|
||||||
textWidth?: number;
|
textWidth?: number;
|
||||||
/** Distance between labels to middle line, in pixels. */
|
/** Distance between the time label AND the text label to middle line, in pixels. */
|
||||||
labelsOffset?: number;
|
gap?: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Timeline({
|
export default function Timeline({
|
||||||
data,
|
data,
|
||||||
width,
|
width,
|
||||||
height,
|
|
||||||
isTimeUppercase = true,
|
isTimeUppercase = true,
|
||||||
|
lineWidth = 5,
|
||||||
|
outerCircleWidth = 30,
|
||||||
|
innerCircleWidth = 15,
|
||||||
timeWidth = 200,
|
timeWidth = 200,
|
||||||
textWidth = 300,
|
textWidth = 300,
|
||||||
labelsOffset = 50,
|
gap = 50,
|
||||||
className,
|
className,
|
||||||
}: TimelineProps) {
|
}: TimelineProps) {
|
||||||
|
const largerMiddleElemeent =
|
||||||
|
outerCircleWidth > lineWidth ? outerCircleWidth : lineWidth;
|
||||||
|
const requestedWidth =
|
||||||
|
timeWidth + gap + largerMiddleElemeent + gap + textWidth;
|
||||||
|
if (requestedWidth > width) {
|
||||||
|
throw new Error(
|
||||||
|
`<Timeline /> - timeWidth + gap + ${
|
||||||
|
outerCircleWidth > lineWidth ? "outerCircleWidth" : "lineWidth"
|
||||||
|
} + gap + textWidth (${timeWidth} + ${gap} + ${largerMiddleElemeent} + ${gap} + ${textWidth} = ${requestedWidth}) is larger than width (${width})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (innerCircleWidth > outerCircleWidth) {
|
||||||
|
throw new Error(
|
||||||
|
`<Timeline /> - innerCircleWidth (${innerCircleWidth}) is larger than outerCircleWidth (${outerCircleWidth})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
className ? `${className} ${styles.wrapper}` : `${styles.wrapper}`
|
className ? `${className} ${styles.wrapper}` : `${styles.wrapper}`
|
||||||
}
|
}
|
||||||
style={{ width: width, height: height }}
|
style={{ width: width }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={styles.line}
|
className={styles.line}
|
||||||
style={{ height: height, left: width / 2 }}
|
style={{
|
||||||
></div>
|
width: lineWidth,
|
||||||
<div className={styles.timelineSections} style={{ width: width }}>
|
left: width / 2 - lineWidth / 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className={styles.timelineSections}>
|
||||||
{data.map((datum) => (
|
{data.map((datum) => (
|
||||||
<TimelineSection
|
<TimelineSection
|
||||||
key={datum.time}
|
key={datum.time}
|
||||||
datum={datum}
|
datum={datum}
|
||||||
width={width}
|
width={width}
|
||||||
isTimeUppercase={isTimeUppercase}
|
isTimeUppercase={isTimeUppercase}
|
||||||
|
outerCircleWidth={outerCircleWidth}
|
||||||
|
innerCircleWidth={innerCircleWidth}
|
||||||
timeWidth={timeWidth}
|
timeWidth={timeWidth}
|
||||||
textWidth={textWidth}
|
textWidth={textWidth}
|
||||||
labelsOffset={labelsOffset}
|
gap={gap}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,74 +94,73 @@ interface TimelineSectionProps {
|
||||||
datum: TimelineData;
|
datum: TimelineData;
|
||||||
width: number;
|
width: number;
|
||||||
isTimeUppercase: boolean;
|
isTimeUppercase: boolean;
|
||||||
|
outerCircleWidth: number;
|
||||||
|
innerCircleWidth: number;
|
||||||
timeWidth: number;
|
timeWidth: number;
|
||||||
textWidth: number;
|
textWidth: number;
|
||||||
labelsOffset: number;
|
gap: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TimelineSection({
|
function TimelineSection({
|
||||||
datum,
|
datum,
|
||||||
width,
|
width,
|
||||||
isTimeUppercase,
|
isTimeUppercase,
|
||||||
|
outerCircleWidth,
|
||||||
|
innerCircleWidth,
|
||||||
timeWidth,
|
timeWidth,
|
||||||
|
|
||||||
textWidth,
|
textWidth,
|
||||||
labelsOffset,
|
gap,
|
||||||
}: TimelineSectionProps) {
|
}: TimelineSectionProps) {
|
||||||
const [onHover, setHover] = useState(false);
|
const [onHover, setHover] = useState(false);
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
const handleMouseEnter = () => {
|
||||||
setHover(true);
|
setHover(true);
|
||||||
console.log(onHover);
|
|
||||||
};
|
};
|
||||||
const handleMouseLeave = () => setHover(false);
|
const handleMouseLeave = () => setHover(false);
|
||||||
|
|
||||||
// divs for customizable margins are necessary, absolute positioning loses vertical flex-box functionality
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.timelineSection}>
|
<div className={styles.timelineSection} style={{ gap: gap }}>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: (width - labelsOffset - labelsOffset - 30) / 2 - timeWidth,
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<div
|
<div
|
||||||
className={onHover ? `${styles.time} ${styles.timeHover}` : styles.time}
|
className={onHover ? `${styles.time} ${styles.timeHover}` : styles.time}
|
||||||
style={{
|
style={{
|
||||||
width: timeWidth,
|
width: timeWidth,
|
||||||
|
marginLeft: (width - 2 * gap - outerCircleWidth) / 2 - timeWidth,
|
||||||
}}
|
}}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
>
|
>
|
||||||
{isTimeUppercase ? datum.time.toUpperCase() : datum.time}
|
{isTimeUppercase ? datum.time.toUpperCase() : datum.time}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: labelsOffset }}></div>
|
|
||||||
<div
|
<div
|
||||||
className={styles.circle}
|
className={styles.circle}
|
||||||
style={{ width: 30 }}
|
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
|
style={{
|
||||||
|
width: outerCircleWidth,
|
||||||
|
height: outerCircleWidth,
|
||||||
|
borderRadius: outerCircleWidth,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={styles.innerCircle}
|
className={styles.innerCircle}
|
||||||
style={{ display: onHover ? "inline" : "none" }}
|
style={{
|
||||||
></div>
|
width: innerCircleWidth,
|
||||||
|
height: innerCircleWidth,
|
||||||
|
borderRadius: innerCircleWidth,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: labelsOffset }}></div>
|
|
||||||
<div
|
<div
|
||||||
className={onHover ? `${styles.text} ${styles.textHover}` : styles.text}
|
className={onHover ? `${styles.text} ${styles.textHover}` : styles.text}
|
||||||
style={{
|
style={{
|
||||||
width: textWidth,
|
width: textWidth,
|
||||||
|
marginRight: (width - 2 * gap - outerCircleWidth) / 2 - textWidth,
|
||||||
}}
|
}}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
>
|
>
|
||||||
{datum.text}
|
{datum.text}
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: (width - labelsOffset - labelsOffset - 30) / 2 - textWidth,
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ export default function Home() {
|
||||||
<h2>
|
<h2>
|
||||||
<code>{"<Timeline />"}</code>
|
<code>{"<Timeline />"}</code>
|
||||||
</h2>
|
</h2>
|
||||||
<Timeline data={mockTimelineData} width={800} height={1500} />
|
<Timeline data={mockTimelineData} width={800} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue