Skip to content

Commit

Permalink
feat(pwa): implement PWA
Browse files Browse the repository at this point in the history
  • Loading branch information
s0up4200 committed Nov 6, 2024
1 parent 9b67bc7 commit 6cfc2de
Show file tree
Hide file tree
Showing 14 changed files with 3,012 additions and 444 deletions.
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react-masonry-css": "^1.0.16",
"react-router-dom": "^6.27.0",
"tailwind-lerp-colors": "^1.2.6",
"vite-plugin-pwa": "^0.20.5",
"vite-plugin-svgr": "^4.3.0"
},
"devDependencies": {
Expand All @@ -59,6 +60,11 @@
"typescript": "~5.6.3",
"typescript-eslint": "^8.13.0",
"vite": "^5.4.10",
"vite-svg-loader": "^5.1.0"
"vite-svg-loader": "^5.1.0",
"workbox-expiration": "^7.3.0",
"workbox-precaching": "^7.3.0",
"workbox-routing": "^7.3.0",
"workbox-strategies": "^7.3.0",
"workbox-window": "^7.3.0"
}
}
3,315 changes: 2,878 additions & 437 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Binary file modified public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/pwa-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/pwa-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 50 additions & 5 deletions scripts/generate-pwa-icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,62 @@ const inputSvg = readFileSync(join(process.cwd(), "src/assets/logo.svg"));

async function generateIcons() {
try {
// Generate PWA icons
for (const size of sizes) {
await sharp(inputSvg)
.resize(size, size)
// Create a dark background with correct color #18181B
const background = await sharp({
create: {
width: size,
height: size,
channels: 4,
background: { r: 24, g: 24, b: 27, alpha: 1 }, // #18181B
},
})
.png()
.toBuffer();

// Resize the logo
const resizedLogo = await sharp(inputSvg)
.resize(Math.round(size * 0.7), Math.round(size * 0.7)) // Make logo slightly smaller than background
.toBuffer();

// Composite them together
await sharp(background)
.composite([
{
input: resizedLogo,
blend: "over",
gravity: "center",
},
])
.png()
.toFile(join(process.cwd(), `public/pwa-${size}x${size}.png`));
}

// Generate apple-touch-icon (180x180 is standard for Apple)
await sharp(inputSvg)
.resize(180, 180)
const size = 180;
const background = await sharp({
create: {
width: size,
height: size,
channels: 4,
background: { r: 24, g: 24, b: 27, alpha: 1 }, // #18181B
},
})
.png()
.toBuffer();

const resizedLogo = await sharp(inputSvg)
.resize(Math.round(size * 0.7), Math.round(size * 0.7))
.toBuffer();

await sharp(background)
.composite([
{
input: resizedLogo,
blend: "over",
gravity: "center",
},
])
.png()
.toFile(join(process.cwd(), "public/apple-touch-icon.png"));

Expand Down
Binary file added src/assets/apple-touch-icon-ipad-76x76.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/apple-touch-icon-iphone-60x60.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@ import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { registerSW } from "virtual:pwa-register";

// Force dark mode
document.documentElement.classList.add("dark");

// Register service worker with auto update handling
const updateSW = registerSW({
onNeedRefresh() {
if (confirm("New version available! Click OK to update.")) {
updateSW(true);
}
},
onOfflineReady() {
console.log("App ready to work offline");
},
});

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
Expand Down
13 changes: 13 additions & 0 deletions src/vite-pwa.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// <reference types="vite-plugin-pwa/client" />

declare module 'virtual:pwa-register' {
export interface RegisterSWOptions {
immediate?: boolean
onNeedRefresh?: () => void
onOfflineReady?: () => void
onRegistered?: (registration: ServiceWorkerRegistration | undefined) => void
onRegisterError?: (error: Error) => void
}

export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise<void>
}
52 changes: 51 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,60 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'

// https://vite.dev/config/
export default defineConfig({
plugins: [
react()
react(),
VitePWA({
registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'],
manifest: {
name: 'dashbrr',
short_name: 'dashbrr',
description: 'A dashboard for monitoring autobrr and related services',
theme_color: '#18181B',
background_color: '#18181B',
display: 'standalone',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
}
],
start_url: '.',
orientation: 'portrait'
},
devOptions: {
enabled: true,
type: 'module'
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
runtimeCaching: [
{
urlPattern: /^https?:\/\/localhost:3000\/api\/.*/i,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
networkTimeoutSeconds: 10,
cacheableResponse: {
statuses: [0, 200]
}
}
}
],
cleanupOutdatedCaches: true,
sourcemap: true
}
})
],
build: {
outDir: 'dist',
Expand Down

0 comments on commit 6cfc2de

Please sign in to comment.