feat: add PWA

This commit is contained in:
MAZE 2025-03-25 17:09:19 +03:30
parent 11e0ba2f93
commit 761c730129
17 changed files with 955 additions and 227 deletions

View File

@ -78,7 +78,8 @@
"rules": {
"prettier/prettier": "error",
"react/no-unknown-property": "off",
"react/jsx-key": "off"
"react/jsx-key": "off",
"react/jsx-no-undef": "off"
},
"globals": {
"Astro": "readonly"

View File

@ -1,7 +1,36 @@
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import AstroPWA from '@vite-pwa/astro';
export default defineConfig({
integrations: [react()],
integrations: [
react(),
AstroPWA({
manifest: {
background_color: '#09090b',
description: 'Ambient sounds for focus and calm.',
display: 'standalone',
icons: [
...[72, 128, 144, 152, 192, 256, 512].map(size => ({
sizes: `${size}x${size}`,
src: `/assets/pwa/${size}.png`,
type: 'image/png',
})),
],
name: 'Moodist',
orientation: 'any',
scope: '/',
short_name: 'Moodist',
start_url: '/',
theme_color: '#09090b',
},
registerType: 'prompt',
workbox: {
globPatterns: ['**/*'],
maximumFileSizeToCacheInBytes: Number.MAX_SAFE_INTEGER,
navigateFallback: '/',
},
}),
],
});

1050
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
"@types/howler": "2.2.10",
"@types/react": "^18.2.25",
"@types/react-dom": "^18.2.10",
"@vite-pwa/astro": "0.5.0",
"astro": "4.10.3",
"deepmerge": "4.3.1",
"focus-trap-react": "10.2.3",

BIN
public/assets/pwa/128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
public/assets/pwa/144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
public/assets/pwa/152.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
public/assets/pwa/192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
public/assets/pwa/256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
public/assets/pwa/512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/assets/pwa/72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
export { Reload } from './reload';

View File

@ -0,0 +1,36 @@
import { useRegisterSW } from 'virtual:pwa-register/react'; // eslint-disable-line
import { Modal } from '@/components/modal';
import styles from './reload.module.css';
export function ReloadModal() {
const {
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker,
} = useRegisterSW();
const close = () => {
setNeedRefresh(false);
};
return (
<Modal show={needRefresh} onClose={close}>
<h2 className={styles.title}>New Content</h2>
<p className={styles.desc}>
New content available, click on reload button to update.
</p>
<div className={styles.buttons}>
<button onClick={close}>Close</button>
<button
className={styles.primary}
onClick={() => updateServiceWorker(true)}
>
Reload
</button>
</div>
</Modal>
);
}

View File

@ -0,0 +1,38 @@
.title {
font-family: var(--font-heading);
font-size: var(--font-md);
font-weight: 600;
}
.desc {
margin-top: 8px;
color: var(--color-foreground-subtle);
}
.buttons {
display: flex;
column-gap: 8px;
align-items: center;
justify-content: flex-end;
margin-top: 20px;
& button {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
padding: 0 12px;
font-size: var(--font-sm);
font-weight: 500;
color: var(--color-foreground-subtle);
cursor: pointer;
background-color: var(--color-neutral-200);
border: none;
border-radius: 8px;
&.primary {
color: var(--color-neutral-50);
background-color: var(--color-neutral-950);
}
}
}

View File

@ -0,0 +1,11 @@
import { useEffect, useState } from 'react';
import { ReloadModal } from './reload-modal';
export function Reload() {
const [isBrowser, setIsBrowser] = useState(false);
useEffect(() => setIsBrowser(true), []);
return isBrowser ? <ReloadModal /> : null;
}

View File

@ -1,4 +1,8 @@
---
import { pwaInfo } from 'virtual:pwa-info'; // eslint-disable-line
import { Reload } from '@/components/reload';
import { count } from '@/lib/sounds';
import '@/styles/global.css';
@ -35,8 +39,12 @@ const description =
<meta content="https://moodist.app/og.png" property="og:image" />
<meta content="summary_large_image" name="twitter:card" />
{pwaInfo && <Fragment set:html={pwaInfo.webManifest.linkTag} />}
</head>
<body>
<slot />
<Reload client:load />
</body>
</html>

View File

@ -6,6 +6,7 @@
"baseUrl": "./src",
"paths": {
"@/*": ["./*"]
}
},
"types": ["vite-plugin-pwa/react", "vite-plugin-pwa/info"]
}
}