chore: auto format frontend code with prettier
This commit is contained in:
parent
3db5132199
commit
ee13e8e2f5
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "styles.less";
|
||||
@import 'styles.less';
|
||||
|
||||
.welcomeMap {
|
||||
height: 60rem;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "styles.less";
|
||||
@import 'styles.less';
|
||||
|
||||
.stage {
|
||||
position: relative;
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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)';
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in a new issue