From 7dbc09e6cc990a77df99dd750610b77d7240d835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Tue, 26 Dec 2023 14:53:07 +0100 Subject: [PATCH] feat: custom source image for apple dark splash screens (#31) --- playground/pwa-assets.config.mts | 10 ++++++++-- playground/pwa/public/splash-dark.svg | 5 +++++ src/api/apple-icons-helper.ts | 25 +++++++++++++++++++++++-- src/api/instructions-resolver.ts | 5 ++++- src/splash.ts | 20 ++++++++++++++++++++ src/types.ts | 11 +++++++++++ 6 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 playground/pwa/public/splash-dark.svg diff --git a/playground/pwa-assets.config.mts b/playground/pwa-assets.config.mts index adcf166..f4fbabd 100644 --- a/playground/pwa-assets.config.mts +++ b/playground/pwa-assets.config.mts @@ -1,4 +1,5 @@ import { createAppleSplashScreens, defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' +import { readFile } from 'node:fs/promises' export default defineConfig({ headLinkOptions: { @@ -7,10 +8,15 @@ export default defineConfig({ preset: { ...minimal2023Preset, appleSplashScreens: createAppleSplashScreens({ + async darkImageResolver(imageName) { + return imageName === 'pwa/public/favicon.svg' + ? await readFile('pwa/public/splash-dark.svg') + : undefined + }, padding: 0.3, resizeOptions: { fit: 'contain', background: 'white' }, - // to test issue #28 - //darkResizeOptions: { fit: 'contain', background: 'black' }, + // to test issue #28, comment the line below + darkResizeOptions: { fit: 'contain', background: 'black' }, linkMediaOptions: { log: true, addMediaScreen: true, diff --git a/playground/pwa/public/splash-dark.svg b/playground/pwa/public/splash-dark.svg new file mode 100644 index 0000000..c683dd2 --- /dev/null +++ b/playground/pwa/public/splash-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/api/apple-icons-helper.ts b/src/api/apple-icons-helper.ts index 3d628c9..2df8915 100644 --- a/src/api/apple-icons-helper.ts +++ b/src/api/apple-icons-helper.ts @@ -95,17 +95,36 @@ export function resolveAppleSplashScreensInstructions( sizesMap.clear() + // eslint-disable-next-line n/prefer-global/buffer + const cache: Record> = {} + const originalName = imageAssets.originalName! + + // eslint-disable-next-line n/prefer-global/buffer + const imageResolver = (dark: boolean): Promise => { + if (!dark || typeof appleSplashScreens.darkImageResolver !== 'function') + return Promise.resolve(image) + + const cached = cache[originalName] + if (cached) + return cached + + return cache[originalName] = appleSplashScreens + .darkImageResolver(originalName) + .then(darkImage => Promise.resolve(darkImage ?? image)) + } + for (const size of splashScreens) { const name = resolveName(size.landscape, size.size, size.dark) const url = `${imageAssets.basePath}${name}` - const promise = () => generateMaskableAsset('png', image, size.size, { + const promise = () => imageResolver(size.dark === true).then(i => generateMaskableAsset('png', i, size.size, { padding: size.padding, resizeOptions: { ...size.resizeOptions, background: size.resizeOptions?.background ?? (size.dark ? 'black' : 'white'), }, outputOptions: size.png, - }) + })) + instructions.appleSplashScreen[url] = { name, url, @@ -159,6 +178,7 @@ function resolveAppleSplashScreens( sizes, name = defaultSplashScreenName, png: usePng = {}, + darkImageResolver, } = useAppleSplashScreens // Initialize defaults @@ -186,6 +206,7 @@ function resolveAppleSplashScreens( xhtml = false, } = useLinkMediaOptions appleSplashScreens = { + darkImageResolver, padding, sizes, linkMediaOptions: { diff --git a/src/api/instructions-resolver.ts b/src/api/instructions-resolver.ts index 947697d..dc43cd9 100644 --- a/src/api/instructions-resolver.ts +++ b/src/api/instructions-resolver.ts @@ -89,7 +89,10 @@ export async function resolveInstructions(imageAssets: ImageAssets) { return instructions } -async function resolvePreset(preset: BuiltInPreset | Preset, faviconPreset?: HtmlLinkPreset): Promise<[Preset, HtmlLinkPreset]> { +async function resolvePreset( + preset: BuiltInPreset | Preset, + faviconPreset?: HtmlLinkPreset, +): Promise<[preset: Preset, htmlLinkPreset: HtmlLinkPreset]> { if (typeof preset === 'object') return [preset, faviconPreset ?? 'default'] diff --git a/src/splash.ts b/src/splash.ts index 9a8254a..4099cd3 100644 --- a/src/splash.ts +++ b/src/splash.ts @@ -95,6 +95,15 @@ export const AllAppleDeviceNames = Array.from(Object.keys(appleSplashScreenSizes export function createAppleSplashScreens( options: { + /** + * The image to use for generating dark apple splash screens assets. + * + * By default, it will use the original image. + * + * @param imageName The image name configured in images. + */ + // eslint-disable-next-line n/prefer-global/buffer + darkImageResolver?: (imageName: string) => Promise padding?: number resizeOptions?: ResizeOptions darkResizeOptions?: ResizeOptions @@ -105,6 +114,7 @@ export function createAppleSplashScreens( devices: AppleDeviceName[] = AllAppleDeviceNames, ) { const { + darkImageResolver, padding, resizeOptions, darkResizeOptions, @@ -114,6 +124,7 @@ export function createAppleSplashScreens( } = options return { + darkImageResolver, sizes: devices.map(deviceName => appleSplashScreenSizes[deviceName]), padding, resizeOptions, @@ -127,6 +138,15 @@ export function createAppleSplashScreens( export function combinePresetAndAppleSplashScreens( preset: Preset, options: { + /** + * The image to use for generating dark apple splash screens assets. + * + * By default, it will use the original image. + * + * @param imageName The image name configured in images. + */ + // eslint-disable-next-line n/prefer-global/buffer + darkImageResolver?: (imageName: string) => Promise padding?: number resizeOptions?: ResizeOptions darkResizeOptions?: ResizeOptions diff --git a/src/types.ts b/src/types.ts index a17ff93..3bffe7d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -83,6 +83,15 @@ export interface AppleTouchStartupImageOptions { } export interface AppleSplashScreens { + /** + * The image to use for generating dark apple splash screens assets. + * + * By default, it will use the original image. + * + * @param imageName The image name configured in images. + */ + // eslint-disable-next-line n/prefer-global/buffer + darkImageResolver?: (imageName: string) => Promise sizes: AppleDeviceSize[] /** * The padding to add to the splash screen. @@ -124,6 +133,8 @@ export interface AppleSplashScreens { } export interface ResolvedAppleSplashScreens { + // eslint-disable-next-line n/prefer-global/buffer + darkImageResolver?: (imageName: string) => Promise padding: number sizes: AppleDeviceSize[] linkMediaOptions: Required