feat(native): TREK's own app icon and launch screen, named just TREK
The shells still carried Capacitor's placeholder icon and splash, the blue X on a grid. They now show the white TREK mark on a dark, slightly glassy tile: a soft light from the top left and a sheen over the upper half, in the app's launch colour #09090b. Android 12+ draws its launch screen on the same colour instead of light grey. scripts/generate-app-icons.mjs renders the sources into assets/ from public/icons/icon-white.svg, and `npm run icons:app` turns them into every size both platforms ask for through @capacitor/assets. The Android foreground mark is sized for the adaptive icon's round mask. The home screen label is TREK: the old "TREK - Plan your trips!" was cut off under the icon, and the longer title belongs to the store listings.
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 8.3 KiB |
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background>
|
||||
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||
</background>
|
||||
<foreground>
|
||||
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background>
|
||||
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||
</background>
|
||||
<foreground>
|
||||
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||
<color name="ic_launcher_background">#09090B</color>
|
||||
<color name="launch_background">#09090B</color>
|
||||
</resources>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">TREK - Plan your trips!</string>
|
||||
<string name="title_activity_main">TREK - Plan your trips!</string>
|
||||
<string name="app_name">TREK</string>
|
||||
<string name="title_activity_main">TREK</string>
|
||||
<string name="package_name">com.liketrek.trek</string>
|
||||
<string name="custom_url_scheme">com.liketrek.trek</string>
|
||||
</resources>
|
||||
|
||||
@@ -18,5 +18,8 @@
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
<!-- Android 12+ draws its own launch screen: the app icon on this colour.
|
||||
The same near-black as the icon tile and the first painted frame. -->
|
||||
<item name="windowSplashScreenBackground">@color/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
@@ -5,7 +5,9 @@ import { KeyboardResize } from '@capacitor/keyboard';
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'com.liketrek.trek',
|
||||
appName: 'TREK - Plan your trips!',
|
||||
// What the home screen shows under the icon; the longer title belongs to
|
||||
// the store listings.
|
||||
appName: 'TREK',
|
||||
// The app ships only the address screen. Once a server is picked, the native
|
||||
// side points the WebView at it (TrekBridgeViewController.swift,
|
||||
// MainActivity.java) and the UI comes from that server, always in the version
|
||||
|
||||
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 104 KiB |
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"images" : [
|
||||
"images": [
|
||||
{
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
"idiom": "universal",
|
||||
"size": "1024x1024",
|
||||
"filename": "AppIcon-512@2x.png",
|
||||
"platform": "ios"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,56 @@
|
||||
{
|
||||
"images" : [
|
||||
"images": [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-2.png",
|
||||
"scale" : "1x"
|
||||
"idiom": "universal",
|
||||
"filename": "Default@1x~universal~anyany.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-1.png",
|
||||
"scale" : "2x"
|
||||
"idiom": "universal",
|
||||
"filename": "Default@2x~universal~anyany.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732.png",
|
||||
"scale" : "3x"
|
||||
"idiom": "universal",
|
||||
"filename": "Default@3x~universal~anyany.png",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"appearances": [
|
||||
{
|
||||
"appearance": "luminosity",
|
||||
"value": "dark"
|
||||
}
|
||||
],
|
||||
"idiom": "universal",
|
||||
"scale": "1x",
|
||||
"filename": "Default@1x~universal~anyany-dark.png"
|
||||
},
|
||||
{
|
||||
"appearances": [
|
||||
{
|
||||
"appearance": "luminosity",
|
||||
"value": "dark"
|
||||
}
|
||||
],
|
||||
"idiom": "universal",
|
||||
"scale": "2x",
|
||||
"filename": "Default@2x~universal~anyany-dark.png"
|
||||
},
|
||||
{
|
||||
"appearances": [
|
||||
{
|
||||
"appearance": "luminosity",
|
||||
"value": "dark"
|
||||
}
|
||||
],
|
||||
"idiom": "universal",
|
||||
"scale": "3x",
|
||||
"filename": "Default@3x~universal~anyany-dark.png"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB |
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>TREK - Plan your trips!</string>
|
||||
<string>TREK</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"dev": "vite",
|
||||
"prebuild": "node scripts/patch-maplibre.mjs && node scripts/generate-icons.mjs",
|
||||
"icons:native": "node scripts/generate-native-icons.mjs",
|
||||
"icons:app": "node scripts/generate-app-icons.mjs && npx @capacitor/assets generate --android --ios --iconBackgroundColor #09090b --iconBackgroundColorDark #09090b --splashBackgroundColor #09090b --splashBackgroundColorDark #09090b",
|
||||
"build:native": "vite build --config vite.native.config.js",
|
||||
"cap:sync": "npm run build:native && cap sync",
|
||||
"build": "vite build",
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Renders the native apps' icon and splash sources into assets/, from the
|
||||
* white TREK mark in public/icons/icon-white.svg. `npx @capacitor/assets
|
||||
* generate --android --ios` then turns them into every size both platforms
|
||||
* ask for (see the icons:app script).
|
||||
*
|
||||
* The look: a dark, slightly glassy tile (a soft light from the top left and a
|
||||
* sheen over the upper half) under the white mark. Dark because that is the
|
||||
* app's launch background (#09090b) and its default scheme.
|
||||
*
|
||||
* Android's adaptive icon masks the foreground to a circle inside the
|
||||
* canvas, so the mark there sits smaller than on the iOS tile.
|
||||
*/
|
||||
import { mkdirSync, readFileSync } from 'fs'
|
||||
import { dirname, join } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import sharp from 'sharp'
|
||||
|
||||
const clientDir = join(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const outDir = join(clientDir, 'assets')
|
||||
mkdirSync(outDir, { recursive: true })
|
||||
|
||||
const source = readFileSync(join(clientDir, 'public', 'icons', 'icon-white.svg'), 'utf8')
|
||||
const markPath = [...source.matchAll(/<path d="([^"]+)"/g)].map((m) => m[1]).find((d) => d.length > 500)
|
||||
if (!markPath) throw new Error('No mark path found in icon-white.svg')
|
||||
// The mark's extent inside its 1500 x 1500 viewBox.
|
||||
const MARK = { x: 40, y: 5, w: 1420, h: 1490 }
|
||||
|
||||
const LAUNCH_BG = '#09090b'
|
||||
|
||||
function tile(size) {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 1024 1024">
|
||||
<defs>
|
||||
<linearGradient id="base" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#2a2a31"/>
|
||||
<stop offset="0.55" stop-color="#141418"/>
|
||||
<stop offset="1" stop-color="#08080a"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="light" cx="0.22" cy="0.12" r="0.75">
|
||||
<stop offset="0" stop-color="#ffffff" stop-opacity="0.20"/>
|
||||
<stop offset="0.45" stop-color="#ffffff" stop-opacity="0.05"/>
|
||||
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="sheen" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#ffffff" stop-opacity="0.10"/>
|
||||
<stop offset="0.48" stop-color="#ffffff" stop-opacity="0.03"/>
|
||||
<stop offset="0.5" stop-color="#ffffff" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="depth" cx="0.8" cy="0.95" r="0.7">
|
||||
<stop offset="0" stop-color="#000000" stop-opacity="0.35"/>
|
||||
<stop offset="1" stop-color="#000000" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect width="1024" height="1024" fill="url(#base)"/>
|
||||
<rect width="1024" height="1024" fill="url(#depth)"/>
|
||||
<rect width="1024" height="1024" fill="url(#light)"/>
|
||||
<rect width="1024" height="1024" fill="url(#sheen)"/>
|
||||
</svg>`
|
||||
}
|
||||
|
||||
/** The white mark, `share` of the canvas tall, centred, with a soft shadow for depth. */
|
||||
function mark(size, share, shadow = true) {
|
||||
const scale = (1024 * share) / MARK.h
|
||||
const w = MARK.w * scale
|
||||
const h = MARK.h * scale
|
||||
const tx = (1024 - w) / 2 - MARK.x * scale
|
||||
const ty = (1024 - h) / 2 - MARK.y * scale
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 1024 1024">
|
||||
<defs>
|
||||
<linearGradient id="ink" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#ffffff"/>
|
||||
<stop offset="1" stop-color="#e7e7ec"/>
|
||||
</linearGradient>
|
||||
<filter id="lift" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="14" stdDeviation="22" flood-color="#000000" flood-opacity="0.45"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g ${shadow ? 'filter="url(#lift)"' : ''}>
|
||||
<path transform="translate(${tx} ${ty}) scale(${scale})" fill="url(#ink)" d="${markPath}"/>
|
||||
</g>
|
||||
</svg>`
|
||||
}
|
||||
|
||||
async function render(svg, file) {
|
||||
await sharp(Buffer.from(svg)).png().toFile(join(outDir, file))
|
||||
}
|
||||
|
||||
async function composite(background, overlay, file, size) {
|
||||
const base = await sharp(Buffer.from(background)).resize(size, size).png().toBuffer()
|
||||
const top = await sharp(Buffer.from(overlay)).resize(size, size).png().toBuffer()
|
||||
await sharp(base).composite([{ input: top }]).flatten({ background: LAUNCH_BG }).png().toFile(join(outDir, file))
|
||||
}
|
||||
|
||||
// iOS and store listings: one opaque tile, the mark at about half its height.
|
||||
await composite(tile(1024), mark(1024, 0.5), 'icon-only.png', 1024)
|
||||
// Android adaptive icon: the two layers apart, the mark inside the safe circle.
|
||||
await render(tile(1024), 'icon-background.png')
|
||||
await render(mark(1024, 0.58), 'icon-foreground.png')
|
||||
// Splash: the launch background with the mark, light and dark alike.
|
||||
const splashBg = `<svg xmlns="http://www.w3.org/2000/svg" width="2732" height="2732"><rect width="2732" height="2732" fill="${LAUNCH_BG}"/></svg>`
|
||||
await composite(splashBg, mark(2732, 0.2, false), 'splash.png', 2732)
|
||||
await composite(splashBg, mark(2732, 0.2, false), 'splash-dark.png', 2732)
|
||||
|
||||
console.log(`[app-icons] wrote icon and splash sources to ${outDir}`)
|
||||