diff --git a/frontend/public/img/wallpapers/sky-phone-demo-gradient.png b/frontend/public/img/wallpapers/sky-phone-demo-gradient.png new file mode 100644 index 0000000..2c7f53a Binary files /dev/null and b/frontend/public/img/wallpapers/sky-phone-demo-gradient.png differ diff --git a/frontend/src/App.vue b/frontend/src/App.vue index dc8cd20..5289d74 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -268,8 +268,13 @@ const PHONE_BASE_SCALE = 0.69 * 1.2 const PHONE_PORTRAIT_WIDTH = 390 const PHONE_PORTRAIT_HEIGHT = 844 const MIN_PRODUCTION_PHONE_ZOOM = 260 / PHONE_PORTRAIT_WIDTH -const isDevelopment = import.meta.env.DEV const developmentParameters = new URLSearchParams(window.location.search) +const isBrowserPreview = + developmentParameters.has('browserPreview') && + developmentParameters.get('apiBase')?.startsWith('/') === true +const isDevelopment = + import.meta.env.DEV || + developmentParameters.get('apiBase')?.startsWith('/') === true const developmentLockScreenPreview = isDevelopment && developmentParameters.has('lockScreenPreview') @@ -433,6 +438,14 @@ let simPickerClosePending = false function getViewportScale(): number { const heightScale = window.innerHeight / REFERENCE_VIEWPORT_HEIGHT + if (isBrowserPreview) { + const availableScale = Math.min( + window.innerWidth / PHONE_PORTRAIT_WIDTH, + window.innerHeight / PHONE_PORTRAIT_HEIGHT, + ) + + return (availableScale * 0.94) / PHONE_BASE_SCALE + } if (isDevelopment) return heightScale return Math.min(window.innerWidth / REFERENCE_VIEWPORT_WIDTH, heightScale) @@ -1583,6 +1596,7 @@ onBeforeUnmount(() => { " class="phone-stage" :class="{ + 'phone-stage--browser-preview': isBrowserPreview, 'phone-stage--landscape': phone.cameraLandscape, 'phone-stage--peek': notifications.isPeeking, }" diff --git a/frontend/src/AppDevelopmentPreview.contract.test.ts b/frontend/src/AppDevelopmentPreview.contract.test.ts index af0d7eb..3246879 100644 --- a/frontend/src/AppDevelopmentPreview.contract.test.ts +++ b/frontend/src/AppDevelopmentPreview.contract.test.ts @@ -84,4 +84,16 @@ describe('browser development preview contract', () => { ) expect(mainCss).not.toContain('.phone-stage--dev') }) + + it('fills the dedicated browser embed without clipping the hardware controls', () => { + expect(source).toContain("developmentParameters.has('browserPreview')") + expect(source).toContain("'phone-stage--browser-preview': isBrowserPreview") + expect(source).toContain('return (availableScale * 0.94) / PHONE_BASE_SCALE') + expect(mainCss).toMatch( + /\.phone-stage--browser-preview\s*\{[^}]*place-items:\s*center;[^}]*padding:\s*0;/s, + ) + expect(mainCss).toMatch( + /\.phone-stage--browser-preview \.phone-device\s*\{[^}]*filter:\s*none;/s, + ) + }) }) diff --git a/frontend/src/assets/img/app-icons/billing.svg b/frontend/src/assets/img/app-icons/billing.svg deleted file mode 100644 index 5cc30ba..0000000 --- a/frontend/src/assets/img/app-icons/billing.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/billing.webp b/frontend/src/assets/img/app-icons/billing.webp new file mode 100644 index 0000000..9ee5e84 Binary files /dev/null and b/frontend/src/assets/img/app-icons/billing.webp differ diff --git a/frontend/src/assets/img/app-icons/calendar.svg b/frontend/src/assets/img/app-icons/calendar.svg deleted file mode 100644 index 6c34aa8..0000000 --- a/frontend/src/assets/img/app-icons/calendar.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/calendar.webp b/frontend/src/assets/img/app-icons/calendar.webp new file mode 100644 index 0000000..af607ad Binary files /dev/null and b/frontend/src/assets/img/app-icons/calendar.webp differ diff --git a/frontend/src/assets/img/app-icons/citywarn.webp b/frontend/src/assets/img/app-icons/citywarn.webp index d15f7c6..083957e 100644 Binary files a/frontend/src/assets/img/app-icons/citywarn.webp and b/frontend/src/assets/img/app-icons/citywarn.webp differ diff --git a/frontend/src/assets/img/app-icons/companies.svg b/frontend/src/assets/img/app-icons/companies.svg deleted file mode 100644 index b52f7ce..0000000 --- a/frontend/src/assets/img/app-icons/companies.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/companies.webp b/frontend/src/assets/img/app-icons/companies.webp new file mode 100644 index 0000000..5f5ee8e Binary files /dev/null and b/frontend/src/assets/img/app-icons/companies.webp differ diff --git a/frontend/src/assets/img/app-icons/crewlink.svg b/frontend/src/assets/img/app-icons/crewlink.svg deleted file mode 100644 index 27e2f21..0000000 --- a/frontend/src/assets/img/app-icons/crewlink.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/crewlink.webp b/frontend/src/assets/img/app-icons/crewlink.webp new file mode 100644 index 0000000..7e35b75 Binary files /dev/null and b/frontend/src/assets/img/app-icons/crewlink.webp differ diff --git a/frontend/src/assets/img/app-icons/crypto-header-logo.png b/frontend/src/assets/img/app-icons/crypto-header-logo.png deleted file mode 100644 index 734bf52..0000000 Binary files a/frontend/src/assets/img/app-icons/crypto-header-logo.png and /dev/null differ diff --git a/frontend/src/assets/img/app-icons/crypto-header-logo.webp b/frontend/src/assets/img/app-icons/crypto-header-logo.webp new file mode 100644 index 0000000..1fe2223 Binary files /dev/null and b/frontend/src/assets/img/app-icons/crypto-header-logo.webp differ diff --git a/frontend/src/assets/img/app-icons/feather.svg b/frontend/src/assets/img/app-icons/feather.svg deleted file mode 100644 index 6f3a090..0000000 --- a/frontend/src/assets/img/app-icons/feather.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/feather.webp b/frontend/src/assets/img/app-icons/feather.webp new file mode 100644 index 0000000..fb96e3b Binary files /dev/null and b/frontend/src/assets/img/app-icons/feather.webp differ diff --git a/frontend/src/assets/img/app-icons/flare.svg b/frontend/src/assets/img/app-icons/flare.svg deleted file mode 100644 index 3cad880..0000000 --- a/frontend/src/assets/img/app-icons/flare.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/flare.webp b/frontend/src/assets/img/app-icons/flare.webp new file mode 100644 index 0000000..4999692 Binary files /dev/null and b/frontend/src/assets/img/app-icons/flare.webp differ diff --git a/frontend/src/assets/img/app-icons/house.svg b/frontend/src/assets/img/app-icons/house.svg deleted file mode 100644 index 050488a..0000000 --- a/frontend/src/assets/img/app-icons/house.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/house.webp b/frontend/src/assets/img/app-icons/house.webp new file mode 100644 index 0000000..575b2d2 Binary files /dev/null and b/frontend/src/assets/img/app-icons/house.webp differ diff --git a/frontend/src/assets/img/app-icons/local-pages.webp b/frontend/src/assets/img/app-icons/local-pages.webp index 91bd3b1..94d92fa 100644 Binary files a/frontend/src/assets/img/app-icons/local-pages.webp and b/frontend/src/assets/img/app-icons/local-pages.webp differ diff --git a/frontend/src/assets/img/app-icons/memos.webp b/frontend/src/assets/img/app-icons/memos.webp index 589e615..8bd9bd5 100644 Binary files a/frontend/src/assets/img/app-icons/memos.webp and b/frontend/src/assets/img/app-icons/memos.webp differ diff --git a/frontend/src/assets/img/app-icons/music.svg b/frontend/src/assets/img/app-icons/music.svg deleted file mode 100644 index 308c035..0000000 --- a/frontend/src/assets/img/app-icons/music.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/music.webp b/frontend/src/assets/img/app-icons/music.webp new file mode 100644 index 0000000..db954d0 Binary files /dev/null and b/frontend/src/assets/img/app-icons/music.webp differ diff --git a/frontend/src/assets/img/app-icons/neon-drop-source.png b/frontend/src/assets/img/app-icons/neon-drop-source.png deleted file mode 100644 index fb2efc7..0000000 Binary files a/frontend/src/assets/img/app-icons/neon-drop-source.png and /dev/null differ diff --git a/frontend/src/assets/img/app-icons/picstagram.webp b/frontend/src/assets/img/app-icons/picstagram.webp index 6512bb2..68dcd58 100644 Binary files a/frontend/src/assets/img/app-icons/picstagram.webp and b/frontend/src/assets/img/app-icons/picstagram.webp differ diff --git a/frontend/src/assets/img/app-icons/radio.webp b/frontend/src/assets/img/app-icons/radio.webp index bbce3fa..bc8fa54 100644 Binary files a/frontend/src/assets/img/app-icons/radio.webp and b/frontend/src/assets/img/app-icons/radio.webp differ diff --git a/frontend/src/assets/img/app-icons/sky-flappy.svg b/frontend/src/assets/img/app-icons/sky-flappy.svg deleted file mode 100644 index 2588494..0000000 --- a/frontend/src/assets/img/app-icons/sky-flappy.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/skyride.svg b/frontend/src/assets/img/app-icons/skyride.svg deleted file mode 100644 index 00e99ca..0000000 --- a/frontend/src/assets/img/app-icons/skyride.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/skyride.webp b/frontend/src/assets/img/app-icons/skyride.webp new file mode 100644 index 0000000..84eec27 Binary files /dev/null and b/frontend/src/assets/img/app-icons/skyride.webp differ diff --git a/frontend/src/assets/img/app-icons/weazel-news.svg b/frontend/src/assets/img/app-icons/weazel-news.svg deleted file mode 100644 index c98d991..0000000 --- a/frontend/src/assets/img/app-icons/weazel-news.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/img/app-icons/weazel-news.webp b/frontend/src/assets/img/app-icons/weazel-news.webp new file mode 100644 index 0000000..17d140d Binary files /dev/null and b/frontend/src/assets/img/app-icons/weazel-news.webp differ diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index c490e5f..816d110 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -248,6 +248,13 @@ button { padding: 0 var(--phone-edge-gap, 24px) var(--phone-edge-gap, 24px) 0; pointer-events: none; } +.phone-stage--browser-preview { + place-items: center; + padding: 0; +} +.phone-stage--browser-preview .phone-device { + filter: none; +} .phone-stage--peek .phone-resolution-wrapper--primary .phone-device { transform: translateY(calc(100% - 190px)); transform-origin: right bottom; diff --git a/frontend/src/config/apps.ts b/frontend/src/config/apps.ts index bca3955..0cda34d 100644 --- a/frontend/src/config/apps.ts +++ b/frontend/src/config/apps.ts @@ -45,7 +45,7 @@ import appStoreIcon from '@/assets/img/app-icons/apps.webp' import calculatorIcon from '@/assets/img/app-icons/calculator.webp' import cameraIcon from '@/assets/img/app-icons/camera.webp' import clockIcon from '@/assets/img/app-icons/clock.webp' -import calendarIcon from '@/assets/img/app-icons/calendar.svg' +import calendarIcon from '@/assets/img/app-icons/calendar.webp' import mailIcon from '@/assets/img/app-icons/mail.webp' import mapIcon from '@/assets/img/app-icons/map.webp' import messagesIcon from '@/assets/img/app-icons/sms.webp' @@ -67,20 +67,20 @@ import weatherIcon from '@/assets/img/app-icons/weather.webp' import healthIcon from '@/assets/img/app-icons/health.webp' import bankingIcon from '@/assets/img/app-icons/banking.webp' import cryptoIcon from '@/assets/img/app-icons/crypto.webp' -import billingIcon from '@/assets/img/app-icons/billing.svg' +import billingIcon from '@/assets/img/app-icons/billing.webp' import garageIcon from '@/assets/img/app-icons/garage.webp' -import houseIcon from '@/assets/img/app-icons/house.svg' +import houseIcon from '@/assets/img/app-icons/house.webp' import citymarktIcon from '@/assets/img/app-icons/citymarkt.webp' import localPagesIcon from '@/assets/img/app-icons/local-pages.webp' -import flareIcon from '@/assets/img/app-icons/flare.svg' +import flareIcon from '@/assets/img/app-icons/flare.webp' import flipTokIcon from '@/assets/img/app-icons/fliptok.webp' import picstagramIcon from '@/assets/img/app-icons/picstagram.webp' -import skyRideIcon from '@/assets/img/app-icons/skyride.svg' -import musicIcon from '@/assets/img/app-icons/music.svg' -import featherIcon from '@/assets/img/app-icons/feather.svg' -import crewLinkIcon from '@/assets/img/app-icons/crewlink.svg' -import companiesIcon from '@/assets/img/app-icons/companies.svg' -import weazelNewsIcon from '@/assets/img/app-icons/weazel-news.svg' +import skyRideIcon from '@/assets/img/app-icons/skyride.webp' +import musicIcon from '@/assets/img/app-icons/music.webp' +import featherIcon from '@/assets/img/app-icons/feather.webp' +import crewLinkIcon from '@/assets/img/app-icons/crewlink.webp' +import companiesIcon from '@/assets/img/app-icons/companies.webp' +import weazelNewsIcon from '@/assets/img/app-icons/weazel-news.webp' import cityWarnIcon from '@/assets/img/app-icons/citywarn.webp' import type { BuiltinPhoneAppDefinition, diff --git a/frontend/src/utils/nui.ts b/frontend/src/utils/nui.ts index eecee7e..02a40e4 100644 --- a/frontend/src/utils/nui.ts +++ b/frontend/src/utils/nui.ts @@ -11,18 +11,21 @@ export async function nuiCall( endpoint: string, data: Record = {}, ): Promise> { - const developmentPort = new URLSearchParams(window.location.search).get( - 'apiPort', - ) - const baseUrl = import.meta.env.DEV - ? `http://localhost:${developmentPort ?? '3002'}/api` - : `https://${resourceName}` - const requestData = import.meta.env.DEV + const developmentParameters = new URLSearchParams(window.location.search) + const developmentPort = developmentParameters.get('apiPort') + const configuredApiBase = developmentParameters.get('apiBase') + const browserApiBase = configuredApiBase?.startsWith('/') + ? configuredApiBase.replace(/\/$/, '') + : null + const baseUrl = browserApiBase + ?? (import.meta.env.DEV + ? `http://localhost:${developmentPort ?? '3002'}/api` + : `https://${resourceName}`) + const requestData = browserApiBase || import.meta.env.DEV ? { ...data, _testScenario: - new URLSearchParams(window.location.search).get('testScenario') ?? - undefined, + developmentParameters.get('testScenario') ?? undefined, } : data const controller = new AbortController() diff --git a/frontend/src/views/apps/CryptoApp.vue b/frontend/src/views/apps/CryptoApp.vue index e99d5a8..1cd357f 100644 --- a/frontend/src/views/apps/CryptoApp.vue +++ b/frontend/src/views/apps/CryptoApp.vue @@ -25,7 +25,7 @@ import { WalletCards, } from 'lucide-vue-next' import { computed, onMounted, onUnmounted, ref, watch } from 'vue' -import cryptoHeaderLogo from '@/assets/img/app-icons/crypto-header-logo.png' +import cryptoHeaderLogo from '@/assets/img/app-icons/crypto-header-logo.webp' import CryptoLogo from '@/components/crypto/CryptoLogo.vue' import { useAccountStore } from '@/stores/account' import { useCryptoStore } from '@/stores/crypto' diff --git a/frontend/testserver/index.cjs b/frontend/testserver/index.cjs index c1b6eda..c70b2ab 100644 --- a/frontend/testserver/index.cjs +++ b/frontend/testserver/index.cjs @@ -2906,6 +2906,50 @@ let calendarEvents = [ title: 'Beach cruise', }, ] +const demoInstalledAppIds = [ + 'citywarn', + 'crypto', + 'health', + 'weazel-news', + 'companies', + 'music', + 'picstagram', + 'feather', + 'fliptok', + 'flare', + 'calendar', + 'radio', + 'local-pages', + 'crewlink', + 'phone', + 'messages', + 'darkchat', + 'garage', + 'house', + 'map', + 'skyride', + 'banking', + 'billing', + 'mail', + 'notes', + 'memos', + 'calculator', + 'camera', + 'clock', + 'weather', + 'photos', + 'app-store', + 'settings', + 'snake', + 'memory', + 'number-merge', + 'minesweeper', + 'tower-stack', + 'sky-flappy', + 'citymarkt', + 'neon-drop', +] +const demoWallpaperUrl = '/img/wallpapers/sky-phone-demo-gradient.png' const deviceData = { appAuth: { payload: { @@ -2949,7 +2993,7 @@ const deviceData = { }, apps: { payload: { - claimedApps: [], + claimedApps: [...demoInstalledAppIds], }, revision: 2, }, @@ -3042,6 +3086,8 @@ const deviceData = { airplaneMode: false, appearanceMode: 'automatic', frame: 'black', + lockWallpaper: 'custom', + lockWallpaperImageUrl: demoWallpaperUrl, notificationDurationSeconds: 10, notificationSound: 'chime', notificationVolume: 70, @@ -3049,7 +3095,11 @@ const deviceData = { ringtone: 'skyline', ringtoneVolume: 80, streamerMode: false, - wallpaper: 'midnight', + wallpaper: 'custom', + wallpaperHistory: [ + { imageUrl: demoWallpaperUrl, wallpaper: 'custom' }, + ], + wallpaperImageUrl: demoWallpaperUrl, }, version: 1, }, @@ -9716,7 +9766,33 @@ app.post('/api/:endpoint', (request, response) => { }, }, } - : deviceData + : testScenario === '' + ? { + ...deviceData, + apps: { + ...deviceData.apps, + payload: { + claimedApps: [...demoInstalledAppIds], + }, + }, + settings: { + ...deviceData.settings, + payload: { + ...deviceData.settings.payload, + settings: { + ...deviceData.settings.payload.settings, + lockWallpaper: 'custom', + lockWallpaperImageUrl: demoWallpaperUrl, + wallpaper: 'custom', + wallpaperHistory: [ + { imageUrl: demoWallpaperUrl, wallpaper: 'custom' }, + ], + wallpaperImageUrl: demoWallpaperUrl, + }, + }, + }, + } + : deviceData response.json({ success: true, data: { diff --git a/frontend/testserver/smoke.cjs b/frontend/testserver/smoke.cjs index 73a8129..fb00c9e 100644 --- a/frontend/testserver/smoke.cjs +++ b/frontend/testserver/smoke.cjs @@ -109,6 +109,31 @@ function verifyBrowserTestData(dataByEndpoint) { 'camera captures', 2, ) + expectItems( + development.device.data.apps.payload.claimedApps, + 'installed demo apps', + 41, + ) + assert.equal( + new Set(development.device.data.apps.payload.claimedApps).size, + 41, + 'browser demo apps were not uniquely installed', + ) + assert.equal( + development.device.data.settings.payload.settings.wallpaper, + 'custom', + 'browser demo home wallpaper was not configured', + ) + assert.equal( + development.device.data.settings.payload.settings.lockWallpaper, + 'custom', + 'browser demo Lock Screen wallpaper was not configured', + ) + assert.match( + development.device.data.settings.payload.settings.wallpaperImageUrl, + /sky-phone-demo-gradient\.png$/, + 'browser demo wallpaper image was not configured', + ) expectItems(development.memos, 'memos', 3) expectItems(development.notes, 'notes', 4) assert(