Skip to content

Commit 106fd12

Browse files
Preserve Pages redirect query/hash and welcome UTM visitors (#292)
Co-Authored-By: Taromati2 <taromati2@outlook.com>
1 parent 02f50b2 commit 106fd12

25 files changed

Lines changed: 197 additions & 2 deletions

.github/pages/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
<link rel="stylesheet" href="./base.css" type="text/css" />
2222
<script type="module">
2323
// load 后再跳,给跨文档 VT 留下 old snapshot(未就绪瞬跳容易被 skip)
24-
(f => document.readyState === 'complete' ? f() : window.addEventListener('load', f))(() => { location.href = './wait/install/' })
24+
(f => document.readyState === 'complete' ? f() : window.addEventListener('load', f))(() => {
25+
location.href = './wait/install/' + location.search + location.hash
26+
})
2527
</script>
2628
</head>
2729

.github/pages/test/frontend/smoke.spec.mjs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ test.describe('GitHub Pages smoke', () => {
99
await expect(page.locator('.hero-content.visible-after-intro')).toBeVisible({ timeout: 30_000 })
1010
})
1111

12+
test('root redirect keeps search and hash', async ({ page, baseUrl }) => {
13+
await page.goto(`${baseUrl}/?utm_source=linux.sb&rid=smoke1#welcome`, { waitUntil: 'domcontentloaded' })
14+
await expect(page).toHaveURL(/\/wait\/install\/\?utm_source=linux\.sb&rid=smoke1#welcome$/, { timeout: 30_000 })
15+
})
16+
1217
test('install wait screen loads base + test watch', async ({ page, baseUrl }) => {
1318
await page.goto(`${baseUrl}/wait/install/`, { waitUntil: 'domcontentloaded' })
1419
await expect(page.locator('#launchButton')).toBeVisible({ timeout: 30_000 })
@@ -19,6 +24,25 @@ test.describe('GitHub Pages smoke', () => {
1924
await expect(page.locator('h1').first()).toBeAttached()
2025
})
2126

27+
test('utm_source shows welcome dialog after hero intro', async ({ page, baseUrl }) => {
28+
const dialog = page.locator('#utm-welcome-dialog')
29+
const openWelcome = async () => {
30+
await page.goto(`${baseUrl}/wait/install/?utm_source=linux.sb`, { waitUntil: 'domcontentloaded' })
31+
await expect(page.locator('.hero-content.visible-after-intro')).toBeVisible({ timeout: 30_000 })
32+
await expect(dialog).toBeVisible({ timeout: 5_000 })
33+
await expect(page.locator('#utm-welcome-message')).toContainText('linux.sb')
34+
}
35+
36+
await openWelcome()
37+
await dialog.locator('.modal-action button').click()
38+
await expect(dialog).toBeHidden()
39+
40+
await openWelcome()
41+
// DaisyUI 的 backdrop button 铺满全屏,中心被 modal-box 挡住;点角落才是真实关闭路径
42+
await dialog.locator('.modal-backdrop').click({ position: { x: 8, y: 8 } })
43+
await expect(dialog).toBeHidden()
44+
})
45+
2246
test('protocol shows offline dialog; badges render', async ({ page, baseUrl }) => {
2347
await page.goto(`${baseUrl}/protocol/`, { waitUntil: 'domcontentloaded' })
2448
await expect(page.locator('#offline_dialog')).toBeVisible({ timeout: 30_000 })

.github/pages/wait/install/index.css

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,39 @@ body.scroll-lock {
260260
.shaking {
261261
animation: shake 0.5s ease-in-out infinite;
262262
}
263+
264+
/* UTM welcome:入场 + 来源标签(i18n 插入的 code,原子类够不着) */
265+
.utm-welcome-box {
266+
background-image: radial-gradient(120% 80% at 50% -10%, color-mix(in oklab, var(--color-primary) 16%, transparent), transparent 55%);
267+
}
268+
269+
#utm-welcome-dialog[open] .utm-welcome-box {
270+
animation: utm-welcome-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
271+
}
272+
273+
@keyframes utm-welcome-in {
274+
from {
275+
opacity: 0;
276+
transform: translateY(1rem) scale(0.96);
277+
}
278+
279+
to {
280+
opacity: 1;
281+
transform: none;
282+
}
283+
}
284+
285+
.utm-welcome-message code {
286+
display: inline-block;
287+
padding: 0.1em 0.45em;
288+
border-radius: 0.4em;
289+
font-weight: 600;
290+
color: var(--color-primary);
291+
background: color-mix(in oklab, var(--color-primary) 12%, var(--color-base-200));
292+
}
293+
294+
@media (prefers-reduced-motion: reduce) {
295+
#utm-welcome-dialog[open] .utm-welcome-box {
296+
animation: none;
297+
}
298+
}

.github/pages/wait/install/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,22 @@ <h2 class="text-4xl font-bold mb-4" data-i18n="installer_wait_screen.mini_game.t
294294
</div>
295295
</footer>
296296

297+
<dialog id="utm-welcome-dialog" class="modal">
298+
<div class="modal-box utm-welcome-box max-w-md border border-base-content/10 bg-base-100 text-center shadow-2xl">
299+
<div class="mx-auto mb-5 grid h-14 w-14 place-items-center rounded-2xl bg-primary/10 ring-1 ring-primary/20" aria-hidden="true">
300+
<img src="https://steve02081504.github.io/fount/imgs/icon.svg" alt="" class="h-8 w-8" width="32" height="32" />
301+
</div>
302+
<h2 class="text-2xl font-bold tracking-wide" data-i18n="installer_wait_screen.utm_welcome.title"></h2>
303+
<p id="utm-welcome-message" class="utm-welcome-message py-4 text-base leading-relaxed text-base-content/80"></p>
304+
<div class="modal-action mt-2 justify-center">
305+
<form method="dialog">
306+
<button type="submit" class="btn btn-primary min-w-40" data-i18n="installer_wait_screen.utm_welcome.dismiss"></button>
307+
</form>
308+
</div>
309+
</div>
310+
<form method="dialog" class="modal-backdrop backdrop-blur-sm"><button type="submit" data-i18n="util.common.close"></button></form>
311+
</dialog>
312+
297313
<script type="module" src="index.mjs"></script>
298314

299315
</body>

.github/pages/wait/install/index.mjs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { makeSearchable } from '../../scripts/components/search.mjs'
66
import { renderTemplate, usingTemplates } from '../../scripts/features/template.mjs'
77
import { showToastI18n } from '../../scripts/features/toast.mjs'
88
import { waitForFountService, saveFountHostUrl, getFountHostUrl, pingFount } from '../../scripts/fountHostGetter.mjs'
9-
import { initTranslations, geti18n, console, getAvailableLocales, getLocaleNames, setLocales, onLanguageChange } from '../../scripts/i18n/index.mjs'
9+
import { initTranslations, geti18n, console, getAvailableLocales, getLocaleNames, setLocales, onLanguageChange, setElementI18n } from '../../scripts/i18n/index.mjs'
1010
import { escapeHtml } from '../../scripts/lib/escapeHtml.mjs'
1111
import { viewTransition } from '../../scripts/lib/viewTransition.mjs'
1212
import {
@@ -45,6 +45,8 @@ const starThankYouEl = document.getElementById('star-thank-you')
4545
const testimonialsBlock = document.getElementById('testimonials-block')
4646
const testimonialCurrent = document.getElementById('testimonial-current')
4747
const testimonialNext = document.getElementById('testimonial-next')
48+
const utmWelcomeDialog = document.getElementById('utm-welcome-dialog')
49+
const utmWelcomeMessage = document.getElementById('utm-welcome-message')
4850

4951
/**
5052
* 从指定 URL 获取 JSON 数据。
@@ -159,6 +161,19 @@ async function playHeroAnimation() {
159161
}
160162
}
161163

164+
/**
165+
* 若 URL 带 utm_source,在 hero 入场结束后弹出欢迎对话框。
166+
* @returns {void}
167+
*/
168+
function maybeShowUtmWelcome() {
169+
const source = new URLSearchParams(location.search).get('utm_source')?.trim()
170+
if (!source) return
171+
setElementI18n(utmWelcomeMessage, 'installer_wait_screen.utm_welcome.message', {
172+
source: escapeHtml(source),
173+
})
174+
utmWelcomeDialog.showModal()
175+
}
176+
162177
/**
163178
* 渲染主题预览。
164179
*/
@@ -700,6 +715,7 @@ async function main() {
700715
initTranslations('installer_wait_screen'),
701716
playHeroAnimation()
702717
])
718+
maybeShowUtmWelcome()
703719

704720
adjectiveRotator = createRotatingText(rotatingAdjectiveEl, [], 2500)
705721
nounRotator = createRotatingText(rotatingNounEl, [], 2500)

src/decl/locale_data.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,11 @@ export type LocaleData = {
527527
nouns: string[]
528528
platforms: string[]
529529
}
530+
utm_welcome: {
531+
title: string
532+
message: string
533+
dismiss: string
534+
}
530535
footer: {
531536
ready_text: string
532537
wait_text: string
@@ -6181,6 +6186,7 @@ export type LocaleKeyParams = {
61816186
'import.errors.textImportFailed': { message: string | number }
61826187
'installer_wait_screen.features.aiSources.description': { atlasCloudLink: string | number; evolinkLink: string | number }
61836188
'installer_wait_screen.footer.error_message': { error: string | number }
6189+
'installer_wait_screen.utm_welcome.message': { source: string | number }
61846190
'log_viewer.logs.openSourceFailed': { message: string | number }
61856191
'login_info.modal.retrieve_error': { error: string | number }
61866192
'login_info.modal.transfer_error': { error: string | number }

src/public/locales/ar-SA.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,11 @@
559559
"مشغّل"
560560
]
561561
},
562+
"utm_welcome": {
563+
"title": "من بعيد",
564+
"message": "أهلاً بضيوف `${source}`!\nلا شاي ولا ضيافة هنا — مجرد تحية :)",
565+
"dismiss": "شكراً، سألقي نظرة"
566+
},
562567
"footer": {
563568
"ready_text": "هل أنت مستعد لبدء رحلتك؟",
564569
"wait_text": "يرجى الانتظار لحظة...",

src/public/locales/de-DE.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,11 @@
559559
"Laufzeitumgebung"
560560
]
561561
},
562+
"utm_welcome": {
563+
"title": "Von weit her",
564+
"message": "Willkommen, Gäste von `${source}`!\nTee und Snacks haben wir leider nicht — nur einen herzlichen Gruß :)",
565+
"dismiss": "Danke, ich schaue mich um"
566+
},
562567
"footer": {
563568
"ready_text": "Bereit, Ihre Reise zu beginnen?",
564569
"wait_text": "Bitte warten Sie einen Moment...",

src/public/locales/emoji.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,11 @@
559559
"🏃‍♂️"
560560
]
561561
},
562+
"utm_welcome": {
563+
"title": "🛤️✨",
564+
"message": "👋 ⬅️ ${source}\n🍵❌ 🍪❌ 👋 :)",
565+
"dismiss": "👌👀"
566+
},
562567
"footer": {
563568
"ready_text": "🚀❓",
564569
"wait_text": "⏳…",

src/public/locales/en-UK.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,11 @@
559559
"runtime"
560560
]
561561
},
562+
"utm_welcome": {
563+
"title": "From afar",
564+
"message": "Welcome, visitors from `${source}`!\nWe've no tea or biscuits on offer — just a friendly hello :)",
565+
"dismiss": "Thanks, I'll have a look around"
566+
},
562567
"footer": {
563568
"ready_text": "Ready to start your journey?",
564569
"wait_text": "Please wait a moment...",

0 commit comments

Comments
 (0)