Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PWA Support #68

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ Thumbs.db
.classpath
*.launch
.settings/
dev-dist/
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not related to PWAs

"singleQuote": true,
"semi": false,
"trailingComma": "all"
}
Binary file modified bun.lockb
Binary file not shown.
35 changes: 18 additions & 17 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="theme-color" content="#1B1B1F" />
<meta name="description" content="manage your openpilot experience" />

<title>connect</title>

<link rel="manifest" href="/manifest.json" />
<link
href="/images/favicon-16x16.png"
rel="icon"
type="image/png"
sizes="16x16"
/>
<link
href="/images/favicon-32x32.png"
rel="icon"
type="image/png"
sizes="32x32"
<meta name="color-scheme" content="light dark" />
<meta
name="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />

<link rel="icon" type="image/png" href="assets/icon/favicon.png" />

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />

<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],400,0..1,0&display=block"
Expand All @@ -29,7 +27,10 @@
href="https://fonts.googleapis.com/css2?family=Inter:[email protected]&family=JetBrains+Mono:wght@400;500&display=swap"
/>
</head>
<body data-theme="dark" class="overflow-x-hidden bg-background text-on-background">
<body
data-theme="dark"
class="overflow-x-hidden bg-background text-on-background"
>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
"type": "module",
"devDependencies": {
"@solidjs/testing-library": "^0.8.8",
"@vite-pwa/assets-generator": "^0.2.4",
"vite-plugin-pwa": "^0.20.0",
"sharp": "0.32.6",
"sharp-ico": "0.1.5",
"workbox-window": "^7.1.0",
Comment on lines +24 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do these 5 new dependencies do?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are required for the minimal config vite-pwa plugin.

They are used generate the assets like splash screens, icons, etc. at build time and are not included in the applications bundle.

There's an alternative way to use "resolutions" in package.json for the sharp and sharp-ico libs but I couldn't get them to work in this repo.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a declarative plugin instead of an imperative config.

"@stylistic/eslint-plugin": "^2.1.0",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/user-event": "^14.5.2",
Expand Down
File renamed without changes
File renamed without changes
31 changes: 31 additions & 0 deletions pwa-assets.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
AllAppleDeviceNames,
combinePresetAndAppleSplashScreens,
defineConfig,
minimal2023Preset,
} from '@vite-pwa/assets-generator/config'

import { readFile } from 'node:fs/promises'

export default defineConfig({
headLinkOptions: {
preset: '2023',
},
preset: combinePresetAndAppleSplashScreens(
minimal2023Preset,
{
// dark splash screens using black background (the default)
darkResizeOptions: { background: 'black', fit: 'contain' },
// or using a custom background color
// darkResizeOptions: { background: '#1f1f1f' },
async darkImageResolver(imageName) {
return imageName === 'public/logo-connect-light.svg'
? await readFile('public/logo-connect-dark.svg')
: undefined
},
},

AllAppleDeviceNames,
),
images: ['public/logo-connect-light.svg'],
})
18 changes: 10 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Route, Router } from '@solidjs/router'
import { Suspense, lazy, type VoidComponent } from 'solid-js'
import { Router, Route } from '@solidjs/router'
import OfflineIndicator from './components/OfflineIndicator'

const Login = lazy(() => import('./pages/auth/login'))
const Logout = lazy(() => import('./pages/auth/logout'))
Expand All @@ -9,13 +10,14 @@ const Dashboard = lazy(() => import('./pages/dashboard'))

const App: VoidComponent = () => {
return (
<Router root={(props) => <Suspense>{props.children}</Suspense>}>
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
<Route path="/auth" component={Auth} />

<Route path="/*dongleId" component={Dashboard} />
</Router>
<OfflineIndicator>
<Router root={(props) => <Suspense>{props.children}</Suspense>}>
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
<Route path="/auth" component={Auth} />
<Route path="/*dongleId" component={Dashboard} />
</Router>
</OfflineIndicator>
)
}

Expand Down
31 changes: 31 additions & 0 deletions src/components/OfflineIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ParentProps, createSignal, onCleanup } from 'solid-js'

const OfflineIndicator = (props: ParentProps) => {
const [isOffline, setIsOffline] = createSignal(!navigator.onLine)

const updateOnlineStatus = () => {
setIsOffline(!navigator.onLine)
}

window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)

onCleanup(() => {
window.removeEventListener('online', updateOnlineStatus)
window.removeEventListener('offline', updateOnlineStatus)
})

return (
<div>
{isOffline() ? (
<div style={{ background: 'red', color: 'white', padding: '10px' }}>
You are currently offline
</div>
) : (
props.children
)}
</div>
)
}

export default OfflineIndicator
30 changes: 15 additions & 15 deletions src/pages/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Navigate, useLocation, type RouteSectionProps } from '@solidjs/router'
import type { Component } from 'solid-js'
import {
Accessor,
createContext,
createResource,
createSignal,
Match,
Setter,
Show,
Switch,
createContext,
createResource,
createSignal,
} from 'solid-js'
import type { Component } from 'solid-js'
import { Navigate, type RouteSectionProps, useLocation } from '@solidjs/router'

import { getDevices } from '~/api/devices'
import { getProfile } from '~/api/profile'
Expand All @@ -20,10 +20,10 @@ import Drawer from '~/components/material/Drawer'
import IconButton from '~/components/material/IconButton'
import TopAppBar from '~/components/material/TopAppBar'

import DeviceList from './components/DeviceList'
import storage from '~/utils/storage'
import DeviceActivity from './activities/DeviceActivity'
import RouteActivity from './activities/RouteActivity'
import storage from '~/utils/storage'
import DeviceList from './components/DeviceList'

type DashboardState = {
drawer: Accessor<boolean>
Expand All @@ -45,15 +45,15 @@ const DashboardDrawer = (props: {
>
comma connect
</TopAppBar>
<h2 class="mx-4 mb-2 text-label-sm">
Devices
</h2>
<h2 class="mx-4 mb-2 text-label-sm">Devices</h2>
<Show when={props.devices} keyed>
{(devices: Device[]) => <DeviceList class="p-2" devices={devices} />}
</Show>
<div class="grow" />
<hr class="mx-4 opacity-20" />
<Button class="m-4" href="/logout">Sign out</Button>
<Button class="m-4" href="/logout">
Sign out
</Button>
</>
)
}
Expand All @@ -78,7 +78,8 @@ const DashboardLayout: Component<RouteSectionProps> = () => {
if (dongleId()) return undefined

const lastSelectedDongleId = storage.getItem('lastSelectedDongleId')
if (devices()?.some((device) => device.dongle_id === lastSelectedDongleId)) return lastSelectedDongleId
if (devices()?.some((device) => device.dongle_id === lastSelectedDongleId))
return lastSelectedDongleId
return devices()?.[0]?.dongle_id
}

Expand Down Expand Up @@ -108,9 +109,8 @@ const DashboardLayout: Component<RouteSectionProps> = () => {
<Match when={dongleId()} keyed>
<DeviceActivity dongleId={dongleId()} />
</Match>
<Match when={getDefaultDongleId()} keyed>{(defaultDongleId) => (
<Navigate href={`/${defaultDongleId}`} />
)}
<Match when={getDefaultDongleId()} keyed>
{(defaultDongleId) => <Navigate href={`/${defaultDongleId}`} />}
</Match>
</Switch>
</Drawer>
Expand Down
6 changes: 5 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"allowJs": true,
"noEmit": true,
"strict": true,
"types": ["vite/client", "@testing-library/jest-dom"],
"types": [
"vite/client",
"@testing-library/jest-dom",
"vite-plugin-pwa/client"
],
"isolatedModules": true,
"paths": {
"~/*": ["./src/*"]
Expand Down
3 changes: 3 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also unrelated?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove - was just for my testing on vercel

"rewrites": [{ "source": "/(.*)", "destination": "/" }]
}
33 changes: 32 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,44 @@
import devtools from 'solid-devtools/vite'
import { defineConfig } from 'vite'
import { VitePWA } from 'vite-plugin-pwa'
import solid from 'vite-plugin-solid'
import devtools from 'solid-devtools/vite'

export default defineConfig({
plugins: [
devtools(),
solid({
ssr: false,
}),
VitePWA({
registerType: 'autoUpdate',
injectRegister: 'auto',

pwaAssets: {
disabled: false,
config: true,
},

manifest: {
name: 'connect',
short_name: 'conect',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

misspelled

description: 'manage your openpilot experience',
theme_color: '#1B1B1F',
background_color: '#1B1B1F',
},

workbox: {
globPatterns: ['**/*.{js,css,html,svg,png,ico}'],
cleanupOutdatedCaches: true,
clientsClaim: true,
},

devOptions: {
enabled: true,
navigateFallback: 'index.html',
suppressWarnings: true,
type: 'module',
},
}),
],
server: {
port: 3000,
Expand Down