Skip to content

Commit 575eefa

Browse files
Merge pull request #2 from danilhendras/geist-ui
Implemented Geist UI
2 parents 784b1da + 75da379 commit 575eefa

File tree

7 files changed

+172
-87
lines changed

7 files changed

+172
-87
lines changed

components/ChartWrapper.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
export const ChartWrapper: React.FC<{ bars: JSX.Element[] }> = (props) => {
22
const { bars } = props
3-
return <div className="flex w-min mx-auto h-5/6 space-x-1 items-end">{bars}</div>
3+
return (
4+
<div
5+
style={{
6+
height: "80vh",
7+
display: "flex",
8+
alignItems: "flex-end",
9+
margin: "0 auto",
10+
width: "fit-content",
11+
}}>
12+
{bars}
13+
</div>
14+
)
415
}

components/SortButton.tsx

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,43 @@
1-
import { useState } from "react"
1+
import { useEffect, useState } from "react"
2+
import { Button, Spacer } from "@geist-ui/react"
3+
import { Check } from "@geist-ui/react-icons"
24

3-
export const SortButton: React.FC<{ clickAction: () => void }> = (props) => {
4-
const [text, setText] = useState("Sort!")
5-
const { clickAction } = props
5+
type SortingState = "Sort" | "Sorting" | "Sorted"
6+
7+
interface SortButtonProps {
8+
clickAction: () => void
9+
sortState: SortingState
10+
}
11+
12+
export const SortButton: React.FC<SortButtonProps> = (props) => {
13+
const { sortState, clickAction } = props
14+
const [text, setText] = useState<SortingState>("Sort")
15+
16+
useEffect(() => {
17+
if (sortState !== text) {
18+
setText(sortState)
19+
}
20+
}, [sortState])
21+
22+
let isSorting = text === "Sorting"
23+
let isSorted = text === "Sorted"
24+
const onClick = () => {
25+
if (isSorted) return
26+
clickAction()
27+
}
628
return (
7-
<button
8-
disabled={text === "Sorting!"}
9-
className="border rounded-md text-white bg-black font-bold shadow-md px-5 py-2 mx-auto w-32 block mt-8 transition-all disabled:opacity-60 disabled:bg-gray-400"
10-
onClick={() => {
11-
clickAction()
12-
setText("Sorting!")
13-
}}>
29+
<Button
30+
loading={isSorting}
31+
type={"secondary"}
32+
onClick={onClick}
33+
style={{ display: "block", margin: "0 auto" }}>
34+
{isSorted && (
35+
<>
36+
<Check size={20} />
37+
<Spacer inline x={0.2} />
38+
</>
39+
)}
1440
{text}
15-
</button>
41+
</Button>
1642
)
1743
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"start": "next start"
99
},
1010
"dependencies": {
11+
"@geist-ui/react": "^2.1.0-canary.2",
12+
"@geist-ui/react-icons": "^1.0.1",
1113
"autoprefixer": "^10.2.1",
1214
"next": "10.0.5",
1315
"postcss": "^8.2.4",

pages/_app.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
import "tailwindcss/tailwind.css"
1+
import { GeistProvider, CssBaseline } from "@geist-ui/react"
2+
import "../styles/globals.css"
23

34
function MyApp({ Component, pageProps }) {
4-
return <Component {...pageProps} />
5+
return (
6+
<GeistProvider>
7+
<CssBaseline />
8+
<Component {...pageProps} />
9+
</GeistProvider>
10+
)
511
}
612

713
export default MyApp

pages/index.tsx

Lines changed: 56 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,140 +4,110 @@ import { Bar } from "../components/Bar"
44
import { ChartWrapper } from "../components/ChartWrapper"
55
import { SortButton } from "../components/SortButton"
66
import { generateNewBarHeights } from "../utils/index"
7+
import { Grid } from "@geist-ui/react"
78

89
/**
910
* Tailwind class of the active bar
1011
*/
11-
const ACTIVE_BAR_CLASS = "bg-black"
12+
const ACTIVE_BAR_COLOR = "#111"
1213

1314
/**
1415
* Tailwind class of the default bar
1516
*/
16-
const DEFAULT_BAR_CLASS = "bg-red-600"
17+
const INACTIVE_BAR_COLOR = "#ff1a1a"
1718

1819
/**
1920
* Sorting speed in miliseconds
2021
*/
2122
const SORTING_SPEED = 50
2223

23-
interface changeElementClassParam {
24-
add?: string
25-
remove?: string
26-
}
27-
2824
/**
29-
* Change an element's classList, can be adding or removing item from classList depending on the
30-
* 2nd param's properties
31-
* @param element A bar DOM element which will be modified
32-
* @param operations An object containing 2 optional property, add and remove. The presence
33-
* of one or both of it will determine what kind of operation will be done to the classList
25+
* Change element backgroundColor to a given value
26+
* @param element The DOM element
27+
* @param toColor The value in which the background color will be changed to
3428
*/
35-
const changeElementClass = (
36-
element: Element,
37-
operations: changeElementClassParam
38-
): void => {
39-
let isAdd = operations.add
40-
let isRemove = operations.remove
41-
let isRemoveAndAdd = isRemove && isAdd
42-
43-
if (isRemoveAndAdd) {
44-
element.classList.remove(operations.remove)
45-
element.classList.add(operations.add)
46-
} else if (isAdd) {
47-
element.classList.add(operations.add)
48-
} else if (isRemove) {
49-
element.classList.remove(operations.remove)
50-
}
29+
const changeBarColor = (element: HTMLElement, toColor: string): void => {
30+
element.style.backgroundColor = toColor
5131
}
5232

5333
/**
5434
* Revert each bar in the given collection bars from active bar to default bar
5535
* @param bars HTMLCollection of bar elements
5636
*/
57-
const revertBarsColor = (bars: Element[]): void => {
37+
const revertBarsColor = (bars: HTMLElement[]): void => {
5838
for (const bar of bars) {
59-
changeElementClass(bar, {
60-
add: DEFAULT_BAR_CLASS,
61-
remove: ACTIVE_BAR_CLASS,
62-
})
39+
changeBarColor(bar, INACTIVE_BAR_COLOR)
6340
}
6441
}
6542

6643
/**
67-
* Turn 2 previously active bars back into default bars
44+
* Turn 2 previously active bars back into inactive bars
6845
* @param prevBarsIndexes Previous bars' indexes in the current DOM
69-
* @param barDomElements Array/HTMLCollection of the bar's DOM elemnt
46+
* @param bars Array/HTMLCollection of the bar's DOM elemnt
7047
*/
7148
const revertPreviousBarsColors = (
7249
prevBarsIndexes: [number, number],
73-
barDomElements: HTMLCollectionOf<Element>
50+
bars: HTMLCollectionOf<HTMLElement>
7451
): void => {
7552
let [prevBar1Idx, prevBar2Idx] = prevBarsIndexes
7653

77-
let prevActiveBar1 = barDomElements[prevBar1Idx]
78-
let prevActiveBar2 = barDomElements[prevBar2Idx]
54+
let prevActiveBar1 = bars[prevBar1Idx]
55+
let prevActiveBar2 = bars[prevBar2Idx]
7956

8057
let previousActiveBars = [prevActiveBar1, prevActiveBar2]
8158

8259
revertBarsColor(previousActiveBars)
8360
}
8461

85-
type BarToActiveBar = { element: Element; newHeight: number }
62+
type BarToActiveBar = { element: HTMLElement; newHeight: number }
8663

8764
/**
88-
* Turn each bar element in the bars param into an active bar
65+
* Turn each bar in the given array into an active bar, then set the height of it
66+
* to the given newHeight property
8967
* @param bars Array of object, each item is an object containing the element which
9068
* will be changed and the new height for that element
9169
*/
9270
const makeBarsActive = (bars: BarToActiveBar[]): void => {
9371
for (const bar of bars) {
94-
changeElementClass(bar.element, {
95-
add: ACTIVE_BAR_CLASS,
96-
remove: DEFAULT_BAR_CLASS,
97-
})
98-
99-
// @ts-ignore
72+
changeBarColor(bar.element, ACTIVE_BAR_COLOR)
10073
bar.element.style.height = `${bar.newHeight}%`
10174
}
10275
}
10376

10477
/**
105-
* Turn every bar in the DOM into an active bar (black bar) one by one, from first bar to last bar
106-
* @param barsEl Array/HTML Collection of the bar's DOM elements
78+
* Turn every bar in the given array into an active bar one by one, from first bar to last bar
79+
* @param bars Array/HTML Collection of the bar's DOM elements
10780
*/
108-
const postSortAnimation = (barsEl: HTMLCollectionOf<Element>): void => {
109-
for (let s = 0; s < barsEl.length; s++) {
81+
const postSortAnimation = (bars: HTMLCollectionOf<HTMLElement>): void => {
82+
for (let n = 0; n < bars.length; n++) {
11083
setTimeout(() => {
111-
let sThBar = barsEl[s]
84+
let nThBar = bars[n]
11285

113-
changeElementClass(sThBar, {
114-
remove: DEFAULT_BAR_CLASS,
115-
add: ACTIVE_BAR_CLASS,
116-
})
117-
}, s * 10)
86+
changeBarColor(nThBar, ACTIVE_BAR_COLOR)
87+
}, n * 10)
11888
}
11989
}
12090

121-
const animateSelectionSort = (bars: number[]): void => {
122-
const [arrayStates, animationSequence] = selectionSort(bars)
123-
const barDomElements = document.getElementsByClassName("bar")
91+
const animateSelectionSort = (barHeights: number[], postSortFunc?: () => void): void => {
92+
const [arrayStates, animationSequence] = selectionSort(barHeights)
93+
const bars = document.getElementsByClassName("bar") as HTMLCollectionOf<HTMLElement>
12494

12595
for (let i = 0; i < animationSequence.length; i++) {
12696
let firstIteration = i === 0
12797
let lastIteration = i === animationSequence.length - 1
12898

12999
const [bar1Idx, bar2Idx] = animationSequence[i]
130100

131-
const activeBar1 = barDomElements[bar1Idx]
132-
const activeBar2 = barDomElements[bar2Idx]
101+
const activeBar1 = bars[bar1Idx]
102+
const activeBar2 = bars[bar2Idx]
133103

134104
const activeBar1Height = arrayStates[i][bar2Idx]
135105
const activeBar2Height = arrayStates[i][bar1Idx]
136106

137107
setTimeout(() => {
138108
if (!firstIteration) {
139109
let prevAnimationSequence = animationSequence[i - 1]
140-
revertPreviousBarsColors(prevAnimationSequence, barDomElements)
110+
revertPreviousBarsColors(prevAnimationSequence, bars)
141111
}
142112

143113
let barsToActiveBars: BarToActiveBar[] = [
@@ -154,11 +124,18 @@ const animateSelectionSort = (bars: number[]): void => {
154124
makeBarsActive(barsToActiveBars)
155125

156126
if (lastIteration) {
127+
// Revert the last bar to an inactive bar
157128
setTimeout(() => {
158129
let lastBar = activeBar1
159130
revertBarsColor([lastBar])
160131

161-
postSortAnimation(barDomElements)
132+
// Because this animate function executes asynchronous function (setTimeout)
133+
// if we wanted to do something right after this function is done running,
134+
// we have to put the code inside the setTimeout and set it to run at the last iteration.
135+
// Otherwise, the code will be executed before the setTimeouts get
136+
// executed (because it is asynchronous).
137+
postSortAnimation(bars)
138+
if (postSortFunc) postSortFunc()
162139
}, SORTING_SPEED)
163140
}
164141
}, i * SORTING_SPEED)
@@ -167,21 +144,32 @@ const animateSelectionSort = (bars: number[]): void => {
167144

168145
const Home: React.FC = () => {
169146
const [barHeights, setBarHeights] = useState([])
147+
const [sortState, setSortState] = useState<"Sort" | "Sorting" | "Sorted">("Sort")
170148

171149
const bars = barHeights.map((heightValue, idx) => (
172150
<Bar key={idx} height={heightValue} />
173151
))
174152

175153
useEffect(() => {
176-
const newBarHeights = generateNewBarHeights(150)
154+
const newBarHeights = generateNewBarHeights(100)
177155
setBarHeights(newBarHeights)
178156
}, [])
179157

180158
return (
181-
<div className="h-screen mt-8 mx-auto">
182-
<ChartWrapper bars={bars} />
183-
<SortButton clickAction={() => animateSelectionSort(barHeights)} />
184-
</div>
159+
<Grid.Container justify="center" style={{ height: "100vh" }}>
160+
<Grid xs={24} style={{ paddingTop: "40px" }}>
161+
<ChartWrapper bars={bars} />
162+
</Grid>
163+
<Grid xs={24}>
164+
<SortButton
165+
sortState={sortState}
166+
clickAction={() => {
167+
setSortState("Sorting")
168+
animateSelectionSort(barHeights, () => setSortState("Sorted"))
169+
}}
170+
/>
171+
</Grid>
172+
</Grid.Container>
185173
)
186174
}
187175

styles/globals.css

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ html,
22
body {
33
padding: 0;
44
margin: 0;
5-
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6-
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
5+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
6+
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
77
}
88

99
a {
@@ -14,3 +14,12 @@ a {
1414
* {
1515
box-sizing: border-box;
1616
}
17+
18+
.big-wrapper {
19+
height: 100vh;
20+
width: 100%;
21+
}
22+
23+
.bar {
24+
width: 2px;
25+
}

0 commit comments

Comments
 (0)