+
{props.drawer}
diff --git a/src/components/material/FloatingActionButton.tsx b/src/components/material/FloatingActionButton.tsx
index 557e3689..6732a117 100644
--- a/src/components/material/FloatingActionButton.tsx
+++ b/src/components/material/FloatingActionButton.tsx
@@ -2,7 +2,6 @@ import type { JSXElement, ParentComponent } from 'solid-js'
import clsx from 'clsx'
import ButtonBase, { ButtonBaseProps } from '~/components/material/ButtonBase'
-import Typography from '~/components/material/Typography'
type FloatingActionButtonProps = ButtonBaseProps & {
leading?: JSXElement
@@ -20,7 +19,7 @@ const FloatingActionButton: ParentComponent
= (
onClick={props.onClick}
>
{props.leading}
- {props.children}
+ {props.children}
)
}
diff --git a/src/components/material/List.tsx b/src/components/material/List.tsx
index 565f04dd..af540aef 100644
--- a/src/components/material/List.tsx
+++ b/src/components/material/List.tsx
@@ -2,7 +2,6 @@ import type { JSXElement, ParentComponent, VoidComponent } from 'solid-js'
import clsx from 'clsx'
import ButtonBase from '~/components/material/ButtonBase'
-import Typography from '~/components/material/Typography'
type ListItemContentProps = {
headline: JSXElement
@@ -12,14 +11,8 @@ type ListItemContentProps = {
export const ListItemContent: VoidComponent = (props) => {
return (
-
- {props.headline}
-
- {props.subhead && (
-
- {props.subhead}
-
- )}
+
{props.headline}
+ {props.subhead &&
{props.subhead}
}
)
}
diff --git a/src/components/material/NavigationBar.tsx b/src/components/material/NavigationBar.tsx
index 24d803f1..318aecee 100644
--- a/src/components/material/NavigationBar.tsx
+++ b/src/components/material/NavigationBar.tsx
@@ -3,7 +3,6 @@ import { A } from '@solidjs/router'
import clsx from 'clsx'
import Icon, { IconProps } from '~/components/material/Icon'
-import Typography from '~/components/material/Typography'
type NavigationBarItemProps = {
icon: IconProps['children']
@@ -25,9 +24,9 @@ export const NavigationBarItem: ParentComponent = (
{props.icon}
-
+
{props.children}
-
+
)
}
diff --git a/src/components/material/Ripple.tsx b/src/components/material/Ripple.tsx
deleted file mode 100644
index 3e51ffda..00000000
--- a/src/components/material/Ripple.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { onCleanup } from 'solid-js'
-import type { JSX, VoidComponent } from 'solid-js'
-
-export type RippleEffect = {
- id: number
- style: RippleStyle
- timestamp: number
-}
-
-type RippleStyle = Pick<
- JSX.CSSProperties,
- 'height' | 'width' | 'left' | 'top' | 'z-index'
->
-
-type RippleProps = {
- id: number
- class: string
- style: RippleStyle
- terminate: (id: number) => void
-}
-
-const Ripple: VoidComponent = (props) => {
- const timer = setTimeout(() => props.terminate(props.id), 550)
- onCleanup(() => clearTimeout(timer))
-
- return
-}
-
-export default Ripple
diff --git a/src/components/material/TopAppBar.tsx b/src/components/material/TopAppBar.tsx
index 6ff5442c..fff2f922 100644
--- a/src/components/material/TopAppBar.tsx
+++ b/src/components/material/TopAppBar.tsx
@@ -1,27 +1,38 @@
-import type { JSXElement, ParentComponent } from 'solid-js'
+import { onCleanup, createSignal, ParentComponent, JSX } from 'solid-js'
import clsx from 'clsx'
+import { Dynamic } from 'solid-js/web'
-import Typography from '~/components/material/Typography'
-
-type TopAppBarProps = {
- class?: string
- leading?: JSXElement
- trailing?: JSXElement
- as?: string
+interface TopAppBarProps {
+ leading?: JSX.Element;
+ as?: string;
+ trailing?: JSX.Element;
+ component?: string;
}
-const TopAppBar: ParentComponent = (props) => {
+const TopAppBar: ParentComponent = (props) => {
+ const [isLargeScreen, setIsLargeScreen] = createSignal(false)
+
+ let mql: MediaQueryList
+ if (typeof window !== 'undefined' && typeof window.matchMedia !== 'undefined') {
+ mql = window.matchMedia('(min-width: 1024px)')
+ setIsLargeScreen(mql.matches)
+ mql.addEventListener('change', (e) => setIsLargeScreen(e.matches))
+
+ onCleanup(() => mql.removeEventListener('change', (e) => setIsLargeScreen(e.matches)))
+ }
+
return (
- {props.leading}
-
+ {!isLargeScreen() && props.leading}
+
{props.children}
-
+ {isLargeScreen() &&
logout}
+
{props.trailing}
)
diff --git a/src/components/material/Typography.tsx b/src/components/material/Typography.tsx
deleted file mode 100644
index 4735f228..00000000
--- a/src/components/material/Typography.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import type { ParentComponent } from 'solid-js'
-import { Dynamic } from 'solid-js/web'
-import clsx from 'clsx'
-
-export type TypographyProps = {
- class?: string
- color?:
- | 'inherit'
- | 'on-surface'
- | 'on-surface-variant'
- | 'on-primary'
- | 'on-secondary'
- | 'on-tertiary'
- variant?:
- | 'display-lg'
- | 'display-md'
- | 'display-sm'
- | 'headline-lg'
- | 'headline-md'
- | 'headline-sm'
- | 'title-lg'
- | 'title-md'
- | 'title-sm'
- | 'label-lg'
- | 'label-md'
- | 'label-sm'
- | 'body-lg'
- | 'body-md'
- | 'body-sm'
- weight?:
- | 'thin'
- | 'extra-light'
- | 'light'
- | 'regular'
- | 'medium'
- | 'semi-bold'
- | 'bold'
- | 'extra-bold'
- | 'black'
- as?: string
-}
-
-const Typography: ParentComponent = (props) => {
- // TODO: letter spacing
- const variant = () => props.variant || 'body-md'
- const styles = () =>
- ({
- 'display-lg': 'font-sans text-[57px] leading-[64px]',
- 'display-md': 'font-sans text-[45px] leading-[52px]',
- 'display-sm': 'font-sans text-[36px] leading-[44px]',
- 'headline-lg': 'font-sans text-[32px] leading-[40px]',
- 'headline-md': 'font-sans text-[28px] leading-[36px]',
- 'headline-sm': 'font-sans text-[24px] leading-[32px]',
- 'title-lg': 'font-sans text-[22px] leading-[28px]',
- 'title-md': 'font-sans text-[16px] leading-[24px]',
- 'title-sm': 'font-sans text-[14px] leading-[20px]',
- 'label-lg': 'font-mono text-[14px] leading-[20px] uppercase',
- 'label-md': 'font-mono text-[12px] leading-[16px] uppercase',
- 'label-sm': 'font-mono text-[11px] leading-[16px] uppercase',
- 'body-lg': 'font-sans text-[16px] leading-[24px]',
- 'body-md': 'font-sans text-[14px] leading-[20px]',
- 'body-sm': 'font-sans text-[12px] leading-[16px]',
- }[variant()])
-
- const variantWeight = () =>
- ({
- 'display-lg': 'regular',
- 'display-md': 'regular',
- 'display-sm': 'regular',
- 'headline-lg': 'regular',
- 'headline-md': 'regular',
- 'headline-sm': 'regular',
- 'title-lg': 'regular',
- 'title-md': 'medium',
- 'title-sm': 'medium',
- 'label-lg': 'medium',
- 'label-md': 'medium',
- 'label-sm': 'medium',
- 'body-lg': 'regular',
- 'body-md': 'regular',
- 'body-sm': 'regular',
- }[variant()])
-
- const weight = () => props.weight || variantWeight()
- const weightStyles = () =>
- ({
- light: 'font-light',
- regular: 'font-regular',
- medium: 'font-medium',
- 'semi-bold': 'font-semibold',
- bold: 'font-bold',
- 'extra-bold': 'font-extrabold',
- }[weight() || variantWeight()])
-
- const color = () => props.color || 'inherit'
- const colorStyles = () =>
- ({
- inherit: '',
- 'on-surface': 'text-on-surface',
- 'on-surface-variant': 'text-on-surface-variant',
- 'on-primary': 'text-on-primary',
- 'on-secondary': 'text-on-secondary',
- 'on-tertiary': 'text-on-tertiary',
- }[color()])
-
- return (
-
- {props.children}
-
- )
-}
-
-export default Typography
diff --git a/src/components/store/driveReplayStore.tsx b/src/components/store/driveReplayStore.tsx
new file mode 100644
index 00000000..3f8e354c
--- /dev/null
+++ b/src/components/store/driveReplayStore.tsx
@@ -0,0 +1,14 @@
+import { createSignal } from 'solid-js'
+
+// Create a store
+const [videoTime, setVideoTime] = createSignal(0)
+
+export function videoTimeStore() {
+ return { videoTime, setVideoTime }
+}
+
+const [speed, setSpeed] = createSignal(0)
+
+export function speedStore() {
+ return { speed, setSpeed }
+}
diff --git a/src/index.css b/src/index.css
index 083af6d9..5dd233ce 100644
--- a/src/index.css
+++ b/src/index.css
@@ -3,6 +3,7 @@
@tailwind utilities;
@layer base {
+
/* https://m3.material.io/styles/color/roles */
:root {
--color-primary: rgb(83 90 146);
@@ -114,12 +115,13 @@
@apply select-none selection:bg-transparent;
}
- html, body {
+ html,
+ body {
/*
* fill visible viewport
* https://developers.google.com/web/updates/2016/12/url-bar-resizing
*/
- @apply h-full;
+ @apply h-full overflow-hidden;
}
button {
@@ -206,11 +208,123 @@
}
.hide-scrollbar {
- scrollbar-width: none; /* Firefox */
- -ms-overflow-style: none; /* IE 10+ */
+ scrollbar-width: none;
+ /* Firefox */
+ -ms-overflow-style: none;
+ /* IE 10+ */
&::-webkit-scrollbar {
- display: none; /* Safari and Chrome */
+ display: none;
+ /* Safari and Chrome */
}
}
-}
+
+ .custom-scrollbar {
+ scrollbar-width: thin;
+ scrollbar-color: var(--color-secondary-container) var(--color-surface);
+ }
+
+ .custom-scrollbar::-webkit-scrollbar {
+ width: 4px;
+ }
+
+ .custom-scrollbar::-webkit-scrollbar-thumb {
+ background-color: var(--color-primary);
+ border-radius: 4px;
+ }
+
+ .custom-scrollbar::-webkit-scrollbar-track {
+ background-color: var(--color-surface);
+ }
+
+ .filter-custom-btn {
+ font-size: 13px !important;
+ font-weight: 500;
+ width: fit-content;
+ height: fit-content;
+ padding: 3px 17px;
+ border-radius: 20px;
+ border: 1px solid #4b4b4b;
+ background-color: #4b4b4b;
+ color: #fff;
+ cursor: pointer;
+ white-space: nowrap;
+ }
+
+ .filter-custom-btn:hover {
+ background-color: #3a3a3a;
+ }
+
+ .selected-filter-custom-btn {
+ background-color: #bbc4fd;
+ color: #000;
+ cursor: default;
+ }
+
+ .selected-filter-custom-btn:hover {
+ background-color: #bbc4fd;
+ }
+
+ .custom-card {
+ cursor: pointer;
+ background-color: var(--color-surface-container-low);
+ }
+
+ .custom-card:hover {
+ background-color: var(--color-surface-container);
+ }
+
+ .custom-switch {
+ position: relative;
+ display: inline-block;
+ width: 45px;
+ height: 28px;
+ }
+
+ .custom-switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ }
+
+ .custom-slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #8d8d8d;
+ transition: .4s;
+ }
+
+ .custom-slider:before {
+ position: absolute;
+ content: "";
+ height: 100%;
+ width: 60%;
+ background-color: #fff;
+ transition: .4s;
+ }
+
+ .custom-switch input:checked + .custom-slider {
+ background-color: #32CD32;
+ }
+
+ .custom-switch input:focus + .custom-slider {
+ box-shadow: 0 0 1px #32CD32;
+ }
+
+ .custom-switch input:checked + .custom-slider:before {
+ transform: translateX(26px);
+ }
+
+ .custom-slider.round {
+ border-radius: 34px;
+ }
+
+ .custom-slider.round:before {
+ border-radius: 50%;
+ }
+
+}
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
index 01a890a5..adb2350c 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,15 +1,8 @@
/* @refresh reload */
import './index.css'
-import { Suspense, lazy } from 'solid-js'
import { render } from 'solid-js/web'
-import { Router, Route } from '@solidjs/router'
-
-const Login = lazy(() => import('./pages/auth/login'))
-const Logout = lazy(() => import('./pages/auth/logout'))
-const Auth = lazy(() => import('./pages/auth/auth'))
-
-const Dashboard = lazy(() => import('./pages/dashboard'))
+import App from './App'
const root = document.getElementById('root')
@@ -19,21 +12,4 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
)
}
-render(
- () => (
- (
-
- {props.children}
-
- )}
- >
-
-
-
-
-
-
- ),
- root!,
-)
+render(() => , root!)
diff --git a/src/map/index.ts b/src/map/index.ts
index cd52e234..30aeb6b9 100644
--- a/src/map/index.ts
+++ b/src/map/index.ts
@@ -1,4 +1,5 @@
import polyline from '@mapbox/polyline'
+import type { GeocodeResult } from '~/types'
import {
MAPBOX_USERNAME,
@@ -50,3 +51,50 @@ export function getPathStaticMapUrl(
)})`
return `https://api.mapbox.com/styles/v1/${MAPBOX_USERNAME}/${styleId}/static/${path}/auto/${width}x${height}${hidpiStr}?logo=false&attribution=false&padding=30,30,30,30&access_token=${MAPBOX_TOKEN}`
}
+
+// Concept for later use, if deceided to visualize car events on plotted line
+
+/* type ColorSegment = {
+ color: string;
+ percentage: number;
+};
+
+export function getPathStaticMapUrl(
+ themeId: string,
+ coords: Coords,
+ width: number,
+ height: number,
+ hidpi: boolean,
+ strokeWidth: number = 4,
+ colorSegments: ColorSegment[] = [{ color: 'DFE0FF', percentage: 100 }],
+ opacity: number = 1,
+): string {
+ const styleId = getMapStyleId(themeId)
+ const hidpiStr = hidpi ? '@2x' : ''
+ let start = 0
+ const paths = colorSegments.map(({ color, percentage }) => {
+ const end = start + Math.floor((percentage / 100) * coords.length)
+ const segment = coords.slice(start, end)
+ start = end
+ const encodedPolyline = polyline.encode(
+ prepareCoords(segment, POLYLINE_SAMPLE_SIZE),
+ POLYLINE_PRECISION,
+ )
+ return `path-${strokeWidth}+${color}-${opacity}(${encodeURIComponent(
+ encodedPolyline,
+ )})`
+ }).join(',')
+ return `https://api.mapbox.com/styles/v1/${MAPBOX_USERNAME}/${styleId}/static/${paths}/auto/${width}x${height}${hidpiStr}?logo=false&attribution=false&padding=30,30,30,30&access_token=${MAPBOX_TOKEN}`
+} */
+
+export async function reverseGeocode(lng: number, lat: number): Promise {
+ const url = `https://api.mapbox.com/search/geocode/v6/reverse?longitude=${lng}&latitude=${lat}.733&types=address&worldview=us&access_token=${MAPBOX_TOKEN}`
+ try {
+ const response = await fetch(url)
+ const data = await (response.json() as Promise)
+ return data
+ } catch (error) {
+ console.error(error)
+ throw error
+ }
+}
diff --git a/src/pages/auth/login.tsx b/src/pages/auth/login.tsx
index cc4379c9..7eb64f58 100644
--- a/src/pages/auth/login.tsx
+++ b/src/pages/auth/login.tsx
@@ -2,13 +2,12 @@ import { getGoogleAuthUrl, getAppleAuthUrl, getGitHubAuthUrl } from '~/api/auth'
import { setAccessToken } from '~/api/auth/client'
import Button from '~/components/material/Button'
-import Typography from '~/components/material/Typography'
export default function Login() {
const loginAsDemoUser = function () {
- setAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDg1ODI0NjUsIm5iZiI6MTcxNzA0NjQ2NSwiaWF0IjoxNzE3MDQ2NDY1LCJpZGVudGl0eSI6IjBkZWNkZGNmZGYyNDFhNjAifQ.g3khyJgOkNvZny6Vh579cuQj1HLLGSDeauZbfZri9jw');
- window.location.href = window.location.origin;
- };
+ setAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDg1ODI0NjUsIm5iZiI6MTcxNzA0NjQ2NSwiaWF0IjoxNzE3MDQ2NDY1LCJpZGVudGl0eSI6IjBkZWNkZGNmZGYyNDFhNjAifQ.g3khyJgOkNvZny6Vh579cuQj1HLLGSDeauZbfZri9jw')
+ window.location.href = window.location.origin
+ }
return (
@@ -21,18 +20,8 @@ export default function Login() {
/>
-
- comma connect
-
-
-
- Manage your openpilot experience.
-
+
+
Manage your openpilot experience.
@@ -51,21 +40,18 @@ export default function Login() {
Sign in with Google
+
}
>
- Sign in with Apple
+ Sign in with Apple