Merge pull request #212 from GRA0007/feat/palettes
Additional colour palettes
This commit is contained in:
commit
583671bd5e
|
|
@ -14,6 +14,7 @@
|
|||
"dayjs": "^1.11.5",
|
||||
"gapi-script": "^1.2.0",
|
||||
"goober": "^2.1.10",
|
||||
"hue-map": "^0.1.1",
|
||||
"i18next": "^21.9.0",
|
||||
"i18next-browser-languagedetector": "^6.1.5",
|
||||
"i18next-http-backend": "^1.4.1",
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@
|
|||
},
|
||||
"language": {
|
||||
"label": "Language"
|
||||
},
|
||||
"colormap": {
|
||||
"label": "Heatmap colors",
|
||||
"classic": "Crab Fit (classic)"
|
||||
}
|
||||
},
|
||||
"video": {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import dayjs from 'dayjs'
|
|||
import localeData from 'dayjs/plugin/localeData'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import createPalette from 'hue-map'
|
||||
|
||||
import { useSettingsStore, useLocaleUpdateStore } from '/src/stores'
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ const AvailabilityViewer = ({
|
|||
const [tooltip, setTooltip] = useState(null)
|
||||
const timeFormat = useSettingsStore(state => state.timeFormat)
|
||||
const highlight = useSettingsStore(state => state.highlight)
|
||||
const colormap = useSettingsStore(state => state.colormap)
|
||||
const [filteredPeople, setFilteredPeople] = useState([])
|
||||
const [touched, setTouched] = useState(false)
|
||||
const [tempFocus, setTempFocus] = useState(null)
|
||||
|
|
@ -65,6 +67,13 @@ const AvailabilityViewer = ({
|
|||
setTouched(people.length <= 1)
|
||||
}, [people])
|
||||
|
||||
const [palette, setPalette] = useState([])
|
||||
|
||||
useEffect(() => setPalette(createPalette({
|
||||
map: colormap === 'crabfit' ? [[0, [247,158,0,0]], [1, [247,158,0,255]]] : colormap,
|
||||
steps: tempFocus !== null ? 2 : Math.min(max, filteredPeople.length)+1,
|
||||
})), [tempFocus, filteredPeople, max, colormap])
|
||||
|
||||
const heatmap = useMemo(() => (
|
||||
<Container>
|
||||
<TimeLabels>
|
||||
|
|
@ -104,7 +113,8 @@ const AvailabilityViewer = ({
|
|||
key={i}
|
||||
$time={time}
|
||||
className="time"
|
||||
$peopleCount={focusCount !== null && focusCount !== peopleHere.length ? 0 : peopleHere.length}
|
||||
$peopleCount={focusCount !== null && focusCount !== peopleHere.length ? null : peopleHere.length}
|
||||
$palette={palette}
|
||||
aria-label={peopleHere.join(', ')}
|
||||
$maxPeople={tempFocus !== null ? 1 : Math.min(max, filteredPeople.length)}
|
||||
$minPeople={tempFocus !== null ? 0 : Math.min(min, filteredPeople.length)}
|
||||
|
|
@ -129,9 +139,7 @@ const AvailabilityViewer = ({
|
|||
})}
|
||||
</Times>
|
||||
</Date>
|
||||
{last && dates.length !== i+1 && (
|
||||
<Spacer />
|
||||
)}
|
||||
{last && dates.length !== i+1 && <Spacer />}
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
|
|
@ -151,6 +159,7 @@ const AvailabilityViewer = ({
|
|||
timeFormat,
|
||||
timeLabels,
|
||||
times,
|
||||
palette,
|
||||
])
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -86,15 +86,15 @@ export const Time = styled('div')`
|
|||
border-top: 2px dotted var(--text);
|
||||
`}
|
||||
|
||||
background-color: ${props => `#F79E00${Math.round((props.$peopleCount/props.$maxPeople)*255).toString(16)}`};
|
||||
background-color: ${props => props.$palette[props.$peopleCount] ?? 'transparent'};
|
||||
|
||||
${props => props.$highlight && props.$peopleCount === props.$maxPeople && props.$peopleCount > 0 && `
|
||||
background-image: repeating-linear-gradient(
|
||||
45deg,
|
||||
transparent,
|
||||
transparent 4.3px,
|
||||
var(--shadow) 4.3px,
|
||||
var(--shadow) 8.6px
|
||||
rgba(0,0,0,.5) 4.3px,
|
||||
rgba(0,0,0,.5) 8.6px
|
||||
);
|
||||
`}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import createPalette from 'hue-map'
|
||||
|
||||
import { useSettingsStore } from '/src/stores'
|
||||
|
||||
|
|
@ -17,8 +19,16 @@ const Legend = ({
|
|||
}) => {
|
||||
const { t } = useTranslation('event')
|
||||
const highlight = useSettingsStore(state => state.highlight)
|
||||
const colormap = useSettingsStore(state => state.colormap)
|
||||
const setHighlight = useSettingsStore(state => state.setHighlight)
|
||||
|
||||
const [palette, setPalette] = useState([])
|
||||
|
||||
useEffect(() => setPalette(createPalette({
|
||||
map: colormap === 'crabfit' ? [[0, [247,158,0,0]], [1, [247,158,0,255]]] : colormap,
|
||||
steps: max+1-min,
|
||||
})), [min, max, colormap])
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Label>{min}/{total} {t('event:available')}</Label>
|
||||
|
|
@ -31,7 +41,7 @@ const Legend = ({
|
|||
{[...Array(max+1-min).keys()].map(i => i+min).map(i =>
|
||||
<Grade
|
||||
key={i}
|
||||
$color={`#F79E00${Math.round((i/(max))*255).toString(16)}`}
|
||||
$color={palette[i]}
|
||||
$highlight={highlight && i === max && max > 0}
|
||||
onMouseOver={() => onSegmentFocus(i)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ export const Grade = styled('div')`
|
|||
${props => props.$highlight && `
|
||||
background-image: repeating-linear-gradient(
|
||||
45deg,
|
||||
var(--primary),
|
||||
var(--primary) 4.5px,
|
||||
var(--shadow) 4.5px,
|
||||
var(--shadow) 9px
|
||||
transparent,
|
||||
transparent 4.5px,
|
||||
rgba(0,0,0,.5) 4.5px,
|
||||
rgba(0,0,0,.5) 9px
|
||||
);
|
||||
`}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useLocation } from 'react-router-dom'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import dayjs from 'dayjs'
|
||||
import { Settings as SettingsIcon } from 'lucide-react'
|
||||
import { maps } from 'hue-map'
|
||||
|
||||
import { ToggleField, SelectField } from '/src/components'
|
||||
|
||||
|
|
@ -125,6 +126,24 @@ const Settings = () => {
|
|||
onChange={value => store.setTheme(value)}
|
||||
/>
|
||||
|
||||
<SelectField
|
||||
label={t('options.colormap.label')}
|
||||
name="colormap"
|
||||
id="colormap"
|
||||
options={{
|
||||
'crabfit': t('options.colormap.classic'),
|
||||
...Object.fromEntries(Object.keys(maps).map(palette => [
|
||||
palette,
|
||||
palette.split('-')
|
||||
.map(w => w[0].toLocaleUpperCase() + w.substring(1).toLocaleLowerCase())
|
||||
.join(' '),
|
||||
])),
|
||||
}}
|
||||
small
|
||||
value={store.colormap}
|
||||
onChange={event => store.setColormap(event.target.value)}
|
||||
/>
|
||||
|
||||
<ToggleField
|
||||
label={t('options.highlight.label')}
|
||||
name="highlight"
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ const useSettingsStore = create(persist(
|
|||
timeFormat: '12h',
|
||||
theme: 'System',
|
||||
highlight: false,
|
||||
colormap: 'crabfit',
|
||||
|
||||
setWeekStart: weekStart => set({ weekStart }),
|
||||
setTimeFormat: timeFormat => set({ timeFormat }),
|
||||
setTheme: theme => set({ theme }),
|
||||
setHighlight: highlight => set({ highlight }),
|
||||
setColormap: colormap => set({ colormap }),
|
||||
}),
|
||||
{ name: 'crabfit-settings' },
|
||||
))
|
||||
|
|
|
|||
|
|
@ -2185,6 +2185,11 @@ html-parse-stringify@^3.0.1:
|
|||
dependencies:
|
||||
void-elements "3.1.0"
|
||||
|
||||
hue-map@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/hue-map/-/hue-map-0.1.1.tgz#d6b199f4121df56aaf1901222323545f0607a31d"
|
||||
integrity sha512-aH3Maa39vHN+yTkWXdLcTN8M+ftGOX6NvGuMObl2puWxwoUZhm3gLlKA6SdpqJphF1RzQo0ntsm0Psg0uc7ouQ==
|
||||
|
||||
i18next-browser-languagedetector@^6.1.5:
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.5.tgz#ed8c9319a8d246995d8ec8fccb5bf5f4248d0fb1"
|
||||
|
|
|
|||
Loading…
Reference in a new issue