chore: auto format frontend code with prettier

This commit is contained in:
Paul Bienkowski 2021-12-06 08:47:47 +01:00
parent 3db5132199
commit ee13e8e2f5
23 changed files with 153 additions and 103 deletions

View file

@ -5,7 +5,9 @@
flex-direction: column;
justify-content: stretch;
html, body, & {
html,
body,
& {
min-height: 100%;
}
}
@ -18,14 +20,20 @@
background: @obsColorB4;
color: @obsColorW;
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
&:global(.ui.header) {
color: inherit;
}
}
a {
&, &:hover {
&,
&:hover {
color: inherit;
}
@ -65,7 +73,8 @@
font-weight: 600;
font-size: 18pt;
&, &:hover {
&,
&:hover {
color: @obsColorB4;
}
}
@ -114,16 +123,16 @@
.banner {
padding: 8px;
z-index: 100;
border-bottom: 1px solid #DDD;
border-bottom: 1px solid #ddd;
&.warning {
background: #FFD54F;
border-color: #FBC02D;
background: #ffd54f;
border-color: #fbc02d;
color: #263238;
}
&.info {
background: #4FC3F7;
border-color: #0D47A1;
color: #0D47A1;
background: #4fc3f7;
border-color: #0d47a1;
color: #0d47a1;
}
}

View file

@ -51,7 +51,7 @@ function DropdownItemForLink({navigate, ...props}) {
)
}
function Banner({text, style = 'warning'}: {text: string, style: 'warning' | 'info'}) {
function Banner({text, style = 'warning'}: {text: string; style: 'warning' | 'info'}) {
return <div className={classnames(styles.banner, styles[style])}>{text}</div>
}

View file

@ -47,7 +47,7 @@ class API {
async makeLoginUrl() {
const config = await configPromise
const url = new URL(config.loginUrl || (config.apiUrl + '/login'))
const url = new URL(config.loginUrl || config.apiUrl + '/login')
url.searchParams.append('next', window.location.href) // bring us back to the current page
return url.toString()
}

View file

@ -26,13 +26,13 @@ export default function Avatar({user, className}) {
}
if (!username) {
return <div className={classnames(className, "avatar", "empty-avatar")} />
return <div className={classnames(className, 'avatar', 'empty-avatar')} />
}
const color = getColor(username)
return (
<div className={classnames(className, "avatar", "text-avatar")} style={{background: color}}>
<div className={classnames(className, 'avatar', 'text-avatar')} style={{background: color}}>
{username && <span>{username[0]}</span>}
</div>
)

View file

@ -16,12 +16,10 @@
}
}
.avatar.empty-avatar {
background: #AAA;
background: #aaa;
}
.avatar.text-avatar,
.avatar.empty-avatar {
// border-radius: 0.25rem;
@ -40,4 +38,3 @@
height: 64px;
}
}

View file

@ -13,18 +13,18 @@ export default function ColorMapLegend({map}: {map: ColorMap}) {
<defs>
<linearGradient id="gradient" x1="0" x2="1" y1="0" y2="0">
{map.map(([value, color]) => (
<stop key={value} offset={normalizeValue(value) * 100 + '%'} stop-color={color} />
<stop key={value} offset={normalizeValue(value) * 100 + '%'} stopColor={color} />
))}
</linearGradient>
</defs>
<rect id="rect1" x="0" y="0" width="100%" height="100%" fill="url(#gradient)" />
</svg>
{map.map(([value]) => <span className={styles.tick} key={value}
style={{left: normalizeValue(value)*100 + '%'}}
>
{value.toFixed(2)}
</span>)}
{map.map(([value]) => (
<span className={styles.tick} key={value} style={{left: normalizeValue(value) * 100 + '%'}}>
{value.toFixed(2)}
</span>
))}
</div>
)
}

View file

@ -1,18 +1,25 @@
import React from 'react'
import {Button} from 'semantic-ui-react'
import {Button} from 'semantic-ui-react'
import api from 'api'
export default function LoginButton(props) {
export default function LoginButton(props) {
const [busy, setBusy] = React.useState(false)
const onClick = React.useCallback(async (e) => {
e.preventDefault()
setBusy(true)
const url = await api.makeLoginUrl()
window.location.href = url
setBusy(false)
}, [setBusy])
const onClick = React.useCallback(
async (e) => {
e.preventDefault()
setBusy(true)
const url = await api.makeLoginUrl()
window.location.href = url
setBusy(false)
},
[setBusy]
)
return <Button onClick={busy ? null : onClick} loading={busy} {...props}>Login</Button>
return (
<Button onClick={busy ? null : onClick} loading={busy} {...props}>
Login
</Button>
)
}

View file

@ -12,7 +12,11 @@ import {baseMapStyles} from '../../mapstyles'
import styles from './styles.module.less'
interface Viewport {longitude: number; latitude: number; zoom: number}
interface Viewport {
longitude: number
latitude: number
zoom: number
}
const EMPTY_VIEWPORT: Viewport = {longitude: 0, latitude: 0, zoom: 0}
export const withBaseMapStyle = connect((state) => ({baseMapStyle: state.mapConfig?.baseMap?.style ?? 'positron'}))
@ -32,7 +36,7 @@ function buildHash(v: Viewport): string {
return `${v.zoom.toFixed(2)}/${v.latitude}/${v.longitude}`
}
function useViewportFromUrl(): [Viewport|null, (v: Viewport) => void] {
function useViewportFromUrl(): [Viewport | null, (v: Viewport) => void] {
const history = useHistory()
const location = useLocation()
const value = useMemo(() => parseHash(location.hash), [location.hash])

View file

@ -4,9 +4,26 @@ import {Container} from 'semantic-ui-react'
import styles from './Page.module.less'
export default function Page({small, children, fullScreen, stage}: {small?: boolean, children: ReactNode, fullScreen?: boolean,stage?: ReactNode}) {
export default function Page({
small,
children,
fullScreen,
stage,
}: {
small?: boolean
children: ReactNode
fullScreen?: boolean
stage?: ReactNode
}) {
return (
<main className={classnames(styles.page, small && styles.small, fullScreen && styles.fullScreen,stage && styles.hasStage)}>
<main
className={classnames(
styles.page,
small && styles.small,
fullScreen && styles.fullScreen,
stage && styles.hasStage
)}
>
{stage}
{fullScreen ? children : <Container>{children}</Container>}
</main>

View file

@ -1,14 +1,16 @@
import React from 'react'
export type MapSoure = {
type: 'vector'
url: string,
} | {
type: 'vector',
tiles: string[],
minzoom: number,
maxzoom: number,
}
export type MapSoure =
| {
type: 'vector'
url: string
}
| {
type: 'vector'
tiles: string[]
minzoom: number
maxzoom: number
}
export interface Config {
apiUrl: string
@ -22,7 +24,7 @@ export interface Config {
privacyPolicyUrl?: string
banner?: {
text: string
style?: "warning" | "info"
style?: 'warning' | 'info'
}
}

View file

@ -8,18 +8,17 @@ import viridisBase from 'colormap/res/res/viridis'
export {bright, positron}
export const baseMapStyles = {bright, positron}
function simplifyColormap(colormap, maxCount = 16) {
const result = []
const step = Math.ceil(colormap.length / maxCount)
for (let i = 0; i < colormap.length; i+= step) {
for (let i = 0; i < colormap.length; i += step) {
result.push(colormap[i])
}
return result
}
function rgbArrayToColor(arr) {
return ['rgb', ...arr.map(v => Math.round(v*255))]
return ['rgb', ...arr.map((v) => Math.round(v * 255))]
}
export function colormapToScale(colormap, value, min, max) {
@ -27,24 +26,19 @@ export function colormapToScale(colormap, value, min, max) {
'interpolate-hcl',
['linear'],
value,
...colormap.flatMap((v, i, a) => [
(i / (a.length - 1)) * (max - min) + min,
v,
])
...colormap.flatMap((v, i, a) => [(i / (a.length - 1)) * (max - min) + min, v]),
]
}
export const viridis = simplifyColormap(viridisBase.map(rgbArrayToColor), 20);
export const viridis = simplifyColormap(viridisBase.map(rgbArrayToColor), 20)
export const grayscale = ['#FFFFFF', '#000000']
export const reds = [['rgba', 255, 0, 0, 0], ['rgba', 255, 0, 0, 1]]
export const reds = [
['rgba', 255, 0, 0, 0],
['rgba', 255, 0, 0, 1],
]
export function colorByCount(attribute = 'event_count', maxCount, colormap = viridis) {
return colormapToScale(
colormap,
['case', ['to-boolean', ['get', attribute]], ['get', attribute], 0],
0,
maxCount
)
return colormapToScale(colormap, ['case', ['to-boolean', ['get', attribute]], ['get', attribute], 0], 0, maxCount)
}
export function colorByDistance(attribute = 'distance_overtaker_mean', fallback = '#ABC') {
@ -68,13 +62,12 @@ export function colorByDistance(attribute = 'distance_overtaker_mean', fallback
]
}
export const trackLayer = {
type: 'line',
paint: {
'line-width': ['interpolate', ['linear'], ['zoom'], 14, 2, 17, 5],
'line-color': '#F06292',
}
},
}
export const basemap = positron

View file

@ -1,4 +1,4 @@
@import "styles.less";
@import 'styles.less';
.welcomeMap {
height: 60rem;

View file

@ -5,9 +5,7 @@ import {Redirect} from 'react-router-dom'
import api from 'api'
const LogoutPage = connect(
(state) => ({loggedIn: Boolean(state.login)}),
)(function LogoutPage({loggedIn}) {
const LogoutPage = connect((state) => ({loggedIn: Boolean(state.login)}))(function LogoutPage({loggedIn}) {
React.useEffect(() => {
// no await, just trigger it
if (loggedIn) {

View file

@ -107,16 +107,18 @@ function LayerSidebar({
<Header as="h4">Event points</Header>
</label>
</List.Item>
{showEvents && <><List.Item>
<ColorMapLegend map={_.chunk(colorByDistance('distance_overtaker')[3].slice(3), 2)} />
</List.Item>
</>}
{showEvents && (
<>
<List.Item>
<ColorMapLegend map={_.chunk(colorByDistance('distance_overtaker')[3].slice(3), 2)} />
</List.Item>
</>
)}
</List>
</div>
)
}
export default connect(
(state) => ({
mapConfig: _.merge(

View file

@ -88,7 +88,7 @@ const getEventsTextLayer = () => ({
'text-keep-upright': false,
'text-anchor': 'left',
'text-radial-offset': 1,
'text-rotate': ['-', 90, ['*', ['get', 'course'], 180/Math.PI]],
'text-rotate': ['-', 90, ['*', ['get', 'course'], 180 / Math.PI]],
'text-rotation-alignment': 'map',
},
paint: {

View file

@ -2,7 +2,7 @@
.mapContainer {
height: calc(100vh - @menuHeight);
background: #F0F0F3;
background: #f0f0f3;
position: relative;
display: flex;
align-items: stretch;
@ -28,4 +28,3 @@
overflow: auto;
margin: 20px;
}

View file

@ -54,7 +54,13 @@ const SettingsPage = connect((state) => ({login: state.login}), {setLogin})(func
<Form onSubmit={handleSubmit(onSave)} loading={loading}>
<Ref innerRef={findInput(register)}>
<Form.Input error={errors?.username} label="Username" name="username" defaultValue={login.username} disabled />
<Form.Input
error={errors?.username}
label="Username"
name="username"
defaultValue={login.username}
disabled
/>
</Ref>
<Form.Field error={errors?.bio}>
<label>Bio</label>
@ -148,7 +154,7 @@ function ApiKeyDialog({login, onGenerateNewKey}) {
<CopyInput label="Personal API Key" value={login.apiKey} />
</Ref>
) : (
<Message warning content='You have no API Key, please generate one below.' />
<Message warning content="You have no API Key, please generate one below." />
)
) : (
<Button onClick={onClick}>

View file

@ -1,7 +1,20 @@
import React from 'react'
import _ from 'lodash'
import {connect} from 'react-redux'
import {Divider, Message, Confirm, Grid, Button, Icon, Popup, Form, Ref, TextArea, Checkbox, Header} from 'semantic-ui-react'
import {
Divider,
Message,
Confirm,
Grid,
Button,
Icon,
Popup,
Form,
Ref,
TextArea,
Checkbox,
Header,
} from 'semantic-ui-react'
import {useHistory, useParams, Link} from 'react-router-dom'
import {concat, of, from} from 'rxjs'
import {pluck, distinctUntilChanged, map, switchMap} from 'rxjs/operators'

View file

@ -20,10 +20,7 @@ export default function TrackDetails({track, isAuthor}) {
{track.originalFileName != null && (
<List.Item>
{isAuthor && (
<div style={{float: 'right'}}>
</div>
)}
{isAuthor && <div style={{float: 'right'}}></div>}
<List.Header>Original Filename</List.Header>
<code>{track.originalFileName}</code>
@ -72,7 +69,6 @@ export default function TrackDetails({track, isAuthor}) {
</List.Item>
)}
{track?.processingStatus != null && track?.processingStatus != 'error' && (
<List.Item>
<List.Header>Processing</List.Header>

View file

@ -1,4 +1,4 @@
@import "styles.less";
@import 'styles.less';
.stage {
position: relative;

View file

@ -26,9 +26,15 @@ function TracksPageTabs() {
return (
<Menu pointing secondary>
<Menu.Item name="/tracks" active={!isOwnTracksPage} {...{onClick}}>Tracks</Menu.Item>
<Menu.Item name="/tracks" active={!isOwnTracksPage} {...{onClick}}>
Tracks
</Menu.Item>
<Menu.Item name="/my/tracks" active={isOwnTracksPage} {...{onClick}} />
<Menu.Item name="/upload" position='right' {...{onClick}}><Button color='green' compact size='small'>Upload</Button></Menu.Item>
<Menu.Item name="/upload" position="right" {...{onClick}}>
<Button color="green" compact size="small">
Upload
</Button>
</Menu.Item>
</Menu>
)
}
@ -131,7 +137,8 @@ export function TrackListItem({track, privateTracks = false}) {
)}
<span style={{marginLeft: '1em'}}>
<Icon color={COLOR_BY_STATUS[track.processingStatus]} name="bolt" fitted /> Processing {track.processingStatus}
<Icon color={COLOR_BY_STATUS[track.processingStatus]} name="bolt" fitted /> Processing{' '}
{track.processingStatus}
</span>
</Item.Extra>
)}

View file

@ -1,15 +1,15 @@
@obsColorB4: #114594;
@obsColorG1: #76520E;
@obsColorW: #FFFFFF;
@obsColorG1: #76520e;
@obsColorW: #ffffff;
@obsColorB1: #122037;
@obsColorG6: #EFB509;
@obsColorG6: #efb509;
@obsColorS: #000000;
@primaryColor: @obsColorB4;
@secondaryColor: @obsColorG1;
@borderColor: #E0E0E0;
@borderColor: #e0e0e0;
@menuHeight: 50px;
@mobile: ~"screen and (max-width: 767px)";
@desktop: ~"screen and (min-width: 768px)";
@mobile: ~'screen and (max-width: 767px)';
@desktop: ~'screen and (min-width: 768px)';

View file

@ -7,9 +7,9 @@ export type UserProfile = {
}
export type TrackData = {
track: Feature<LineString>,
measurements: FeatureCollection,
overtakingEvents: FeatureCollection,
track: Feature<LineString>
measurements: FeatureCollection
overtakingEvents: FeatureCollection
}
export type Track = {
@ -30,12 +30,12 @@ export type Track = {
}
export type TrackPoint = {
type: 'Feature',
geometry: Point,
type: 'Feature'
geometry: Point
properties: {
distanceOvertaker: null | number,
distanceStationary: null | number,
},
distanceOvertaker: null | number
distanceStationary: null | number
}
}
export type TrackComment = {