Skip to content

Commit

Permalink
Merge pull request #25 from gov4git/fix-scroller-bubble
Browse files Browse the repository at this point in the history
Fix scroller bubble
  • Loading branch information
dworthen authored Oct 26, 2023
2 parents ab8530e + 0533f5d commit 0d855b6
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 107 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-carrots-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gov4git-desktop-app': patch
---

Fix scroller bubble position
39 changes: 39 additions & 0 deletions src/renderer/src/components/BubbleSlider.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { makeStyles, shorthands } from '@fluentui/react-components'

import { gov4GitTokens } from '../App/theme/tokens.js'

export const useBubbleSliderStyles = makeStyles({
sliderArea: {
position: 'relative',
marginBottom: '36px',
width: '90%',
},
slider: {
display: 'block',
appearance: 'none',
height: '4px',
width: '100%',
backgroundColor: gov4GitTokens.g4gColorPrimaryGreen2,
...shorthands.outline('none'),
...shorthands.borderRadius(gov4GitTokens.borderRadiusLarge),
'::-webkit-slider-thumb': {
content: 'hello',
appearance: 'none',
backgroundColor: gov4GitTokens.g4gColorSecondaryGreen8,
width: '20px',
height: '16px',
...shorthands.borderRadius(gov4GitTokens.borderRadiusCircular),
...shorthands.border('2px', 'solid', gov4GitTokens.g4gColorNeutral),
},
},
bubble: {
fontSize: '0.7rem',
color: gov4GitTokens.g4gColorNeutral,
backgroundColor: gov4GitTokens.g4gColorSecondaryGreen8,
...shorthands.padding('1px', '6px'),
...shorthands.borderRadius(gov4GitTokens.borderRadiusMedium),
position: 'absolute',
top: '0.8rem',
transform: 'translateX(-50%)',
},
})
87 changes: 87 additions & 0 deletions src/renderer/src/components/BubbleSlider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {
type ChangeEventHandler,
type FC,
useCallback,
useEffect,
useMemo,
useState,
} from 'react'

import { formatDecimal } from '../lib/numbers.js'
import { useBubbleSliderStyles } from './BubbleSlider.styles.js'

export type BubbleSliderProps = {
value: number
min?: number
max?: number
step?: string
onChange: (value: number) => void
ariaLabel: string
hideBubble?: boolean
}

export const BubbleSlider: FC<BubbleSliderProps> = function BubbleSilder({
value: v = 0,
min = 0,
max = 100,
step = '1',
onChange,
ariaLabel,
hideBubble = false,
}) {
const styles = useBubbleSliderStyles()
const [value, setValue] = useState(v)
const [left, setLeft] = useState('0%')

useEffect(() => {
setValue(v)
}, [v])

const bubbleStyles = useMemo(() => {
return {
left: left,
}
}, [left])

const calculateLeft = useCallback(
(value: number) => {
const slideVal = Number(((value - min) * 100) / (max - min))
const newPosition = 10 - slideVal * 0.2
return `calc(${slideVal}% + (${newPosition}px))`
},
[min, max],
)

useEffect(() => {
const left = calculateLeft(value)
setLeft(left)
}, [calculateLeft, setLeft, value])

const onSlide: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
const rangeVal = +e.target.value
onChange(rangeVal)
},
[onChange],
)

return (
<div className={styles.sliderArea}>
<input
className={styles.slider}
type="range"
aria-label={ariaLabel}
step={step}
min={min}
max={max}
value={value}
onChange={onSlide}
/>
{!hideBubble && (
<div style={bubbleStyles} className={styles.bubble}>
{formatDecimal(value)}
</div>
)}
</div>
)
}
35 changes: 1 addition & 34 deletions src/renderer/src/components/IssueBallot2.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const useIssueBallotStyles = makeStyles({
},
},
votingArea: {
width: '220px',
width: '250px',
...shorthands.padding('0'),
...shorthands.margin('0'),
flexShrink: '0',
Expand All @@ -36,42 +36,9 @@ export const useIssueBallotStyles = makeStyles({
fontSize: '1.3rem',
...shorthands.padding(gov4GitTokens.spacingHorizontalM),
},
sliderArea: {
position: 'relative',
marginBottom: '36px',
// display: 'flex',
// alignItems: 'center',
},
bubble: {
fontSize: '0.7rem',
color: gov4GitTokens.g4gColorNeutral,
backgroundColor: gov4GitTokens.g4gColorSecondaryGreen8,
...shorthands.padding('1px', '6px'),
...shorthands.borderRadius(gov4GitTokens.borderRadiusMedium),
position: 'absolute',
top: '0.8rem',
transform: 'translateX(-50%)',
},
buttonArea: {
height: '20px',
},
slider: {
display: 'block',
appearance: 'none',
height: '4px',
backgroundColor: gov4GitTokens.g4gColorPrimaryGreen2,
...shorthands.outline('none'),
...shorthands.borderRadius(gov4GitTokens.borderRadiusLarge),
'::-webkit-slider-thumb': {
content: 'hello',
appearance: 'none',
backgroundColor: gov4GitTokens.g4gColorSecondaryGreen8,
width: '20px',
height: '16px',
...shorthands.borderRadius(gov4GitTokens.borderRadiusCircular),
...shorthands.border('2px', 'solid', gov4GitTokens.g4gColorNeutral),
},
},
issueArea: {
flexGrow: '2',
flexShrink: '1',
Expand Down
89 changes: 16 additions & 73 deletions src/renderer/src/components/IssueBallot2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,7 @@ import {
} from '@fluentui/react-components'
import { useAtomValue } from 'jotai'
import { parse } from 'marked'
import {
ChangeEventHandler,
FC,
memo,
useCallback,
useEffect,
useMemo,
useState,
} from 'react'
import { FC, useCallback, useEffect, useMemo, useState } from 'react'

import { Ballot } from '~/shared'

Expand All @@ -31,6 +23,7 @@ import { ballotService } from '../services/index.js'
import { configAtom } from '../state/config.js'
import { userAtom } from '../state/user.js'
import { useButtonStyles } from '../styles/buttons.js'
import { BubbleSlider } from './BubbleSlider.js'
import { useIssueBallotStyles } from './IssueBallot2.styles.js'

export type IssueBallotProps = {
Expand All @@ -47,7 +40,6 @@ export const IssueBallot2: FC<IssueBallotProps> = function IssueBallot2({
const [newTotalVoteScore, setNewTotalVoteScore] = useState(0)
const [existingSpentCredits, setExistingSpentCredits] = useState(0)
const catchError = useCatchError()
const [left, setLeft] = useState('50%')
const buttonStyles = useButtonStyles()
const [dialogOpen, setDialogOpen] = useState(false)
const user = useAtomValue(userAtom)
Expand Down Expand Up @@ -202,45 +194,17 @@ export const IssueBallot2: FC<IssueBallotProps> = function IssueBallot2({
setFetchingNewBallot,
])

const tally = useCallback(
(name: string) => {
async function run() {
await ballotService.tallyBallot(name).catch(async (ex) => {
await catchError(`Failed to tally votes. Error ${ex}`)
})
}
void run()
const onSlideChange = useCallback(
(newValue: number) => {
setVoteScore(newValue)
},
[catchError],
)

const onSlide: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
if (user != null) {
const rangeVal = +e.target.value
const slideVal = Number(
((rangeVal - -user.voting_score) * 100) /
(user.voting_score - -user.voting_score),
)
const newPosition = 10 - slideVal * 0.2
setVoteScore(rangeVal)
setLeft(`calc(${slideVal}% + (${newPosition}px))`)
}
},
[setVoteScore, setLeft, user],
[setVoteScore],
)

const cancelVote = useCallback(() => {
setVoteScore(0)
setDialogOpen(false)
setLeft('50%')
}, [setVoteScore, setDialogOpen, setLeft])

const bubbleStyles = useMemo(() => {
return {
left: left,
}
}, [left])
}, [setVoteScore, setDialogOpen])

return (
<Card className={styles.card}>
Expand All @@ -261,26 +225,15 @@ export const IssueBallot2: FC<IssueBallotProps> = function IssueBallot2({
__html: ballot.user.contributionMessage,
}}
/>
<div className={styles.sliderArea}>
{/* <i className="codicon codicon-chevron-down" /> */}
<input
className={styles.slider}
id={`vote-slider-${ballot.identifier}`}
aria-label={`Vote stength is ${voteScore}`}
step="1"
type="range"
min={Math.ceil(minScore)}
max={Math.floor(maxScore)}
value={voteScore}
onChange={onSlide}
></input>
{voteScore !== 0 && (
<div style={bubbleStyles} className={styles.bubble}>
{formatDecimal(voteScore)}
</div>
)}
{/* <i className="codicon codicon-chevron-up" /> */}
</div>
<BubbleSlider
ariaLabel={`Vote strength is ${voteScore}`}
min={Math.ceil(minScore)}
max={Math.floor(maxScore)}
step="1"
value={voteScore}
onChange={onSlideChange}
hideBubble={voteScore === 0}
/>
<div className={styles.buttonArea}>
{voteScore !== 0 && (
<Dialog open={dialogOpen} modalType="alert">
Expand Down Expand Up @@ -330,16 +283,6 @@ export const IssueBallot2: FC<IssueBallotProps> = function IssueBallot2({
</div>
)}
</div>
{/* {user?.is_maintainer && (
<div>
<Button
className={buttonStyles.primary}
onClick={() => tally(ballot.identifier)}
>
Tally
</Button>
</div>
)} */}
</div>
</Card>
)
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './Loader.js'
export * from './LogViewer.js'
export * from './LicenseViewer.js'
export * from './RefreshButton.js'
export * from './BubbleSlider.js'

0 comments on commit 0d855b6

Please sign in to comment.