mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-19 05:41:22 +02:00
@mana/shared-pwa gains PWAShareTarget + PWAShareTargetParams types
plus ManifestConfig.share_target pass-through. createPWAConfig now
accepts an optional `shareTarget` and threads it into the generated
manifest. Other apps keep working unchanged — the field is omitted
unless set.
Web app wiring:
- vite.config.ts passes shareTarget: { action: '/articles/add',
method: 'GET', params: { title, text, url } } so the installed PWA
shows up as a destination in the Android / Chromium share sheet.
- AddUrlForm reads ?url / ?text / ?title in onMount; falls back to
the first URL-shaped token in ?text because some senders (Chrome
Android, WhatsApp) put the shared link there instead of ?url. When
a URL is pre-filled the Readability preview auto-triggers, so the
user just hits "In Leseliste speichern" to confirm.
- New /articles/settings route hosts the bookmarklet (drag-to-
bookmarks-bar button + copy-to-clipboard + expandable snippet
viewer) and a short Share-Target explainer with an iOS-Safari
caveat. Linked from the ListView via a new gear button next to
"+ Neu speichern".
Bookmarklet form (origin-prefixed so it works across tenants):
javascript:void(window.open('${origin}/articles/add?url='+…))
Not in scope (plan marked optional): _pendingUrls offline queue.
Share without internet shows the existing error + retry state today;
can slot in as M7b if users hit it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
157 lines
3.9 KiB
TypeScript
157 lines
3.9 KiB
TypeScript
/**
|
|
* PWA Configuration Factory
|
|
*
|
|
* Creates a complete @vite-pwa/sveltekit configuration with sensible defaults
|
|
* and preset-based caching strategies.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* import { createPWAConfig } from '@mana/shared-pwa';
|
|
* import { SvelteKitPWA } from '@vite-pwa/sveltekit';
|
|
*
|
|
* export default defineConfig({
|
|
* plugins: [
|
|
* sveltekit(),
|
|
* SvelteKitPWA(createPWAConfig({
|
|
* name: 'Calendar - Kalender',
|
|
* shortName: 'Calendar',
|
|
* description: 'Kalender mit Offline-Unterstützung',
|
|
* themeColor: '#3b82f6',
|
|
* preset: 'standard',
|
|
* })),
|
|
* ],
|
|
* });
|
|
* ```
|
|
*/
|
|
|
|
import type { PWAConfigOptions, PWAConfig, ManifestConfig, WorkboxConfig } from './types.js';
|
|
import {
|
|
DEFAULT_BACKGROUND_COLOR,
|
|
DEFAULT_CATEGORIES,
|
|
DEFAULT_INCLUDE_ASSETS,
|
|
DEFAULT_GLOB_PATTERNS,
|
|
DEFAULT_GLOB_IGNORES,
|
|
DEFAULT_NAVIGATE_FALLBACK_DENYLIST,
|
|
DEFAULT_ICONS,
|
|
} from './defaults.js';
|
|
import { getPresetRuntimeCaching } from './presets.js';
|
|
|
|
/**
|
|
* Create a complete PWA configuration for SvelteKit apps
|
|
*/
|
|
export function createPWAConfig(options: PWAConfigOptions): PWAConfig {
|
|
const {
|
|
name,
|
|
shortName,
|
|
description,
|
|
themeColor,
|
|
backgroundColor = DEFAULT_BACKGROUND_COLOR,
|
|
preset = 'standard',
|
|
shortcuts = [],
|
|
shareTarget,
|
|
categories = DEFAULT_CATEGORIES,
|
|
includeAssets = [],
|
|
globIgnores = [],
|
|
additionalRuntimeCaching = [],
|
|
navigateFallback = '/offline',
|
|
navigateFallbackDenylist = DEFAULT_NAVIGATE_FALLBACK_DENYLIST,
|
|
devEnabled = true,
|
|
registerType = 'autoUpdate',
|
|
lang = 'de',
|
|
startUrl = '/',
|
|
} = options;
|
|
|
|
// Build manifest
|
|
const manifest: ManifestConfig = {
|
|
// Pin the app identity to the start URL. Without `id`, Chrome derives
|
|
// one from start_url and warns in DevTools; it also refuses to
|
|
// re-prompt an install if start_url ever changes.
|
|
id: startUrl,
|
|
name,
|
|
short_name: shortName,
|
|
description,
|
|
theme_color: themeColor,
|
|
background_color: backgroundColor,
|
|
display: 'standalone',
|
|
orientation: 'any',
|
|
scope: '/',
|
|
start_url: startUrl,
|
|
lang,
|
|
categories,
|
|
icons: DEFAULT_ICONS,
|
|
};
|
|
|
|
// Add shortcuts if provided
|
|
if (shortcuts.length > 0) {
|
|
manifest.shortcuts = shortcuts.map((shortcut) => ({
|
|
name: shortcut.name,
|
|
short_name: shortcut.short_name,
|
|
description: shortcut.description,
|
|
url: shortcut.url,
|
|
icons: [{ src: 'pwa-192x192.png', sizes: '192x192' }],
|
|
}));
|
|
}
|
|
|
|
// Web Share Target — lets installed PWAs appear in the OS share
|
|
// sheet. Browsers that don't support the spec ignore the field.
|
|
if (shareTarget) {
|
|
manifest.share_target = {
|
|
action: shareTarget.action,
|
|
method: shareTarget.method ?? 'GET',
|
|
enctype: shareTarget.enctype,
|
|
params: shareTarget.params,
|
|
};
|
|
}
|
|
|
|
// Build workbox config
|
|
const workbox: WorkboxConfig = {
|
|
globPatterns: DEFAULT_GLOB_PATTERNS,
|
|
globIgnores: [...DEFAULT_GLOB_IGNORES, ...globIgnores],
|
|
cleanupOutdatedCaches: true,
|
|
clientsClaim: true,
|
|
skipWaiting: true,
|
|
navigateFallback,
|
|
navigateFallbackDenylist,
|
|
runtimeCaching: [...getPresetRuntimeCaching(preset), ...additionalRuntimeCaching],
|
|
maximumFileSizeToCacheInBytes: 8 * 1024 * 1024, // 8 MiB for large unified apps
|
|
};
|
|
|
|
// Return complete config
|
|
return {
|
|
registerType,
|
|
devOptions: {
|
|
enabled: devEnabled,
|
|
},
|
|
includeAssets: [...DEFAULT_INCLUDE_ASSETS, ...includeAssets],
|
|
manifest,
|
|
workbox,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create PWA config with SQLite WASM support (for offline-first apps)
|
|
* Adds proper glob ignores and OPFS configuration
|
|
*/
|
|
export function createOfflineFirstPWAConfig(
|
|
options: PWAConfigOptions & {
|
|
/**
|
|
* Additional packages to exclude from precaching
|
|
*/
|
|
excludePackages?: string[];
|
|
}
|
|
): PWAConfig {
|
|
const { excludePackages = [], globIgnores = [], ...rest } = options;
|
|
|
|
// Add SQLite-specific ignores
|
|
const allGlobIgnores = [
|
|
'**/*sqlite*',
|
|
'**/*wasm*',
|
|
...excludePackages.map((pkg) => `**/${pkg}/**`),
|
|
...globIgnores,
|
|
];
|
|
|
|
return createPWAConfig({
|
|
...rest,
|
|
globIgnores: allGlobIgnores,
|
|
});
|
|
}
|