feat(events): wire VITE_APP_NAME through PWA manifest, HTML, runtime

The standalone events app was hardcoded to "Sortir" branding (PWA name
"Sortir — Activités & Événements", HTML title, console logs, URL token
handler ID). VITE_APP_NAME was already plumbed per-standalone via NixOS
`services.webapp-standalones.<app>.displayName` in server-deploy, but
nothing inside the app consumed it.

Routes the env through every app-name display point:

- PWA manifest `name` / `short_name` (vite.events.config.ts): both pull
  from `process.env.VITE_APP_NAME`, defaulting to `'Events'` when
  unset. Description, `id`, and `lang` un-frenched to brand-agnostic
  defaults. The Vite config also writes the resolved value back to
  `process.env` so Vite's built-in HTML `%VITE_APP_NAME%` substitution
  picks up the fallback.

- HTML title + apple-mobile-web-app-title + description (events.html):
  use `%VITE_APP_NAME%` for build-time substitution. `<html lang>` drops
  the hardcoded `fr` (locale is now runtime-driven via i18n).

- Runtime branding (events-app/app.ts, main.ts): a top-level
  `APP_NAME = (import.meta.env.VITE_APP_NAME as string) || 'Events'`
  feeds the console logs, the offline-ready notification, and the
  `acceptTokenFromUrl()` cross-subdomain handler.

- Main events route title (modules/events/index.ts:32): reads
  VITE_APP_NAME so document.title / breadcrumbs show the deployment
  brand. Sub-route titles (Calendar, Map, Favorites) stay literal —
  they're contextual labels, not the app name.

- .env.example now explains the per-standalone scoping and points at
  the NixOS knob for production deploys.

Domain-noun strings ("Search events…", RSVP labels, "Your event was
created") stay in i18n and translate per language — VITE_APP_NAME does
not flow into those.

Verification: `pnpm dev:events` → default `Events` brand;
`VITE_APP_NAME=Bouge pnpm dev:events` → PWA manifest, tab title, console
logs all show "Bouge". cfaun's existing `displayName = "Sortir"` keeps
producing a Sortir-branded build via the same path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-09 19:37:32 +02:00
commit a7ffe74337
6 changed files with 33 additions and 17 deletions

View file

@ -1,4 +1,10 @@
# App Configuration
# Per-standalone display name — sets browser tab title, PWA install
# name/short_name, and the brand string in console logs. Each standalone
# (events, wallet, chat, market, …) gets its own VITE_APP_NAME at build
# time via NixOS `services.webapp-standalones.<app>.displayName` (see
# server-deploy). cfaun ships the events app as "Sortir"; defaults to
# "Events" / "Wallet" / etc. when unset.
VITE_APP_NAME=MyApp
# Nostr Configuration

View file

@ -1,5 +1,5 @@
<!doctype html>
<html lang="fr">
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
@ -9,9 +9,9 @@
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
<title>Sortir — Events</title>
<meta name="apple-mobile-web-app-title" content="Sortir">
<meta name="description" content="Découvrez les événements près de chez vous">
<title>%VITE_APP_NAME%</title>
<meta name="apple-mobile-web-app-title" content="%VITE_APP_NAME%">
<meta name="description" content="Discover %VITE_APP_NAME% near you">
</head>
<body>
<div id="app"></div>

View file

@ -16,14 +16,16 @@ import { i18n, changeLocale, type AvailableLocale } from '@/i18n'
import { installLenientAuthGuard, markAuthReady, catchAllRoute } from '@/lib/router-helpers'
import { acceptTokenFromUrl } from '@/lib/url-token'
const APP_NAME = (import.meta.env.VITE_APP_NAME as string) || 'Events'
/**
* Initialize the standalone events app
*/
export async function createAppInstance() {
console.log('🚀 Starting Sortir — Events App...')
console.log(`🚀 Starting ${APP_NAME}...`)
// Accept token from URL before anything else (cross-subdomain auth relay)
acceptTokenFromUrl('Sortir')
acceptTokenFromUrl(APP_NAME)
const app = createApp(App)
@ -114,7 +116,7 @@ export async function createAppInstance() {
;(window as any).__container = container
}
console.log('✅ Sortir app initialized')
console.log(`${APP_NAME} initialized`)
return { app, router }
}
@ -122,10 +124,10 @@ export async function startApp() {
try {
const { app } = await createAppInstance()
app.mount('#app')
console.log('🎉 Sortir app started!')
console.log(`🎉 ${APP_NAME} started!`)
eventBus.emit('app:started', {}, 'app')
} catch (error) {
console.error('💥 Failed to start Sortir app:', error)
console.error(`💥 Failed to start ${APP_NAME}:`, error)
document.getElementById('app')!.innerHTML = `
<div style="padding: 20px; text-align: center; color: red;">
<h1>Failed to Start</h1>

View file

@ -14,7 +14,7 @@ registerSW({
}, intervalMS)
},
onOfflineReady() {
console.log('Sortir app ready to work offline')
console.log(`${(import.meta.env.VITE_APP_NAME as string) || 'Events'} ready to work offline`)
}
})

View file

@ -29,7 +29,7 @@ export const eventsModule = createModulePlugin({
name: 'events',
component: () => import('./views/EventsPage.vue'),
meta: {
title: 'Events',
title: (import.meta.env.VITE_APP_NAME as string) || 'Events',
requiresAuth: false,
},
},

View file

@ -35,12 +35,21 @@ function eventsHtmlPlugin(): Plugin {
}
/**
* Vite config for the standalone standalone events app.
* Vite config for the standalone events app.
*
* Set VITE_BASE_PATH to deploy under a path prefix:
* VITE_BASE_PATH=/sortir/ app.ariege.io/sortir/ (shared auth)
* (default: /) sortir.ariege.io (standalone subdomain)
*
* Set VITE_APP_NAME to brand the standalone (PWA name, HTML title, console
* logs). cfaun sets "Sortir" via NixOS; future deployments can override
* (e.g. "Bouge"). Defaults to "Events".
*/
const APP_NAME = process.env.VITE_APP_NAME || 'Events'
// Surface the resolved value back into env so Vite's HTML %VITE_APP_NAME%
// substitution picks up the fallback when nothing was explicitly set.
process.env.VITE_APP_NAME = APP_NAME
export default defineConfig(({ mode }) => ({
base: process.env.VITE_BASE_PATH || '/',
// Per-app dep cache so concurrent dev servers don't race on .vite/deps
@ -76,18 +85,17 @@ export default defineConfig(({ mode }) => ({
'icon-maskable-512.png',
],
manifest: {
name: 'Sortir — Activités & Événements',
short_name: 'Sortir',
description: 'Découvrez les activités et événements près de chez vous',
name: APP_NAME,
short_name: APP_NAME,
description: `Discover ${APP_NAME.toLowerCase()} near you`,
theme_color: '#1f2937',
background_color: '#ffffff',
display: 'standalone',
orientation: 'portrait-primary',
start_url: process.env.VITE_BASE_PATH || '/',
scope: process.env.VITE_BASE_PATH || '/',
id: 'sortir-activities',
id: 'aiolabs-events',
categories: ['social', 'entertainment', 'lifestyle'],
lang: 'fr',
icons: [
{ src: 'icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
{ src: 'icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },