From 16cdc1ae58d28158937f268ffab0c2478fc095fc Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Wed, 19 Aug 2026 09:28:57 +0200 Subject: [PATCH 1/5] fix(onboarding): support dark welcome theme --- src/components/dashboard/AppOnboardingWelcome.vue | 10 ++-------- tests/app-onboarding-welcome.unit.test.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/dashboard/AppOnboardingWelcome.vue b/src/components/dashboard/AppOnboardingWelcome.vue index 9bf3b137f7..8ca18b85ca 100644 --- a/src/components/dashboard/AppOnboardingWelcome.vue +++ b/src/components/dashboard/AppOnboardingWelcome.vue @@ -59,8 +59,8 @@ const { t } = useI18n() .onboarding-welcome { isolation: isolate; background: - radial-gradient(circle at 50% 40%, rgb(59 130 246 / 12%), transparent 29rem), - linear-gradient(180deg, #fff 0%, #f8fafc 58%, #f1f5f9 100%); + radial-gradient(circle at 50% 40%, rgb(59 130 246 / 14%), transparent 29rem), + linear-gradient(180deg, var(--color-base-100) 0%, var(--color-base-200) 58%, var(--color-base-300) 100%); } .onboarding-welcome::before, @@ -177,12 +177,6 @@ const { t } = useI18n() z-index: 1; } -:global(.dark) .onboarding-welcome { - background: - radial-gradient(circle at 50% 40%, rgb(59 130 246 / 18%), transparent 29rem), - linear-gradient(180deg, #020617 0%, #0f172a 58%, #111827 100%); -} - @keyframes onboarding-status-pulse { 0%, 34% { diff --git a/tests/app-onboarding-welcome.unit.test.ts b/tests/app-onboarding-welcome.unit.test.ts index 7bcbff09cf..268c416f81 100644 --- a/tests/app-onboarding-welcome.unit.test.ts +++ b/tests/app-onboarding-welcome.unit.test.ts @@ -25,6 +25,15 @@ describe('app onboarding welcome', () => { expect(source).not.toContain('Takes about') }) + it.concurrent('uses DaisyUI theme colors for the welcome canvas', async () => { + const source = await readFile(new URL('../src/components/dashboard/AppOnboardingWelcome.vue', import.meta.url), 'utf8') + + expect(source).toContain('var(--color-base-100)') + expect(source).toContain('var(--color-base-200)') + expect(source).toContain('var(--color-base-300)') + expect(source).not.toContain(':global(.dark) .onboarding-welcome') + }) + it.concurrent('shows only for fresh or restarted desktop pre-organization onboarding', async () => { const source = await readFile(new URL('../src/components/dashboard/AppOnboardingFlow.vue', import.meta.url), 'utf8') const resumeFlow = source.slice( From a40968f983f4b58d5056e5417f63898df2029b25 Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Wed, 19 Aug 2026 09:36:35 +0200 Subject: [PATCH 2/5] test(onboarding): scope welcome theme assertion --- tests/app-onboarding-welcome.unit.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/app-onboarding-welcome.unit.test.ts b/tests/app-onboarding-welcome.unit.test.ts index 268c416f81..b30afde7be 100644 --- a/tests/app-onboarding-welcome.unit.test.ts +++ b/tests/app-onboarding-welcome.unit.test.ts @@ -27,10 +27,12 @@ describe('app onboarding welcome', () => { it.concurrent('uses DaisyUI theme colors for the welcome canvas', async () => { const source = await readFile(new URL('../src/components/dashboard/AppOnboardingWelcome.vue', import.meta.url), 'utf8') + const welcomeRule = source.match(/\.onboarding-welcome\s*\{([\s\S]*?)\n\}/)?.[1] ?? '' + const backgroundDeclaration = welcomeRule.match(/background:\s*([\s\S]*?);/)?.[1] ?? '' - expect(source).toContain('var(--color-base-100)') - expect(source).toContain('var(--color-base-200)') - expect(source).toContain('var(--color-base-300)') + expect(backgroundDeclaration).toContain('var(--color-base-100)') + expect(backgroundDeclaration).toContain('var(--color-base-200)') + expect(backgroundDeclaration).toContain('var(--color-base-300)') expect(source).not.toContain(':global(.dark) .onboarding-welcome') }) From 657168a2f54108865ff073fba457631f813fad16 Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Wed, 19 Aug 2026 10:06:59 +0200 Subject: [PATCH 3/5] fix(onboarding): clarify optional icon action --- messages/en.json | 1 + src/components/dashboard/AppOnboardingFlow.vue | 4 +--- tests/app-onboarding-v3.unit.test.ts | 11 ++++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/messages/en.json b/messages/en.json index 14375a1d4a..458c0e15a5 100644 --- a/messages/en.json +++ b/messages/en.json @@ -518,6 +518,7 @@ "app-onboarding-store-link-placeholder": "https://apps.apple.com/... or https://play.google.com/store/apps/details?id=com.example.app", "app-onboarding-store-screenshot-alt": "Store screenshot preview", "app-onboarding-skip-app-id": "Skip", + "app-onboarding-skip-icon": "Skip", "app-onboarding-subtitle": "The app is created immediately in Capgo. From there you can either connect your real project in the CLI or explore the dashboard with temporary demo data.", "app-onboarding-summary-method": "Setup method", "app-onboarding-summary-source": "Starting point", diff --git a/src/components/dashboard/AppOnboardingFlow.vue b/src/components/dashboard/AppOnboardingFlow.vue index 1f94bcbc47..1efdbbf2f6 100644 --- a/src/components/dashboard/AppOnboardingFlow.vue +++ b/src/components/dashboard/AppOnboardingFlow.vue @@ -2447,9 +2447,7 @@ defineExpose({ > {{ appDetailsStep === 'icon' - ? props.preOrg - ? t('app-onboarding-continue') - : t('app-onboarding-finish-details') + ? iconPreview ? t('app-onboarding-continue') : t('app-onboarding-skip-icon') : appDetailsStep === 'app_id' && !hasProvidedAppId ? t('app-onboarding-skip-app-id') : t('app-onboarding-continue') }} diff --git a/tests/app-onboarding-v3.unit.test.ts b/tests/app-onboarding-v3.unit.test.ts index fbbc3eb27f..7cbb7c6bfa 100644 --- a/tests/app-onboarding-v3.unit.test.ts +++ b/tests/app-onboarding-v3.unit.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest' const onboardingSource = readFileSync(new URL('../src/components/dashboard/AppOnboardingFlow.vue', import.meta.url), 'utf8') const iconInputSource = readFileSync(new URL('../src/components/dashboard/AppOnboardingIconInput.vue', import.meta.url), 'utf8') +const messages = JSON.parse(readFileSync(new URL('../messages/en.json', import.meta.url), 'utf8')) as Record function sliceBetween(source: string, startMarker: string, endMarker: string) { const start = source.indexOf(startMarker) @@ -152,9 +153,13 @@ describe('pre-organization onboarding v3', () => { expect(onboardingSource.match(/:disabled="isAppDetailsNavigationPending"/g)).toHaveLength(2) }) - it.concurrent('continues to organization creation after the pre-org icon step', () => { - expect(onboardingSource).toContain("t('app-onboarding-continue')") - expect(onboardingSource).toContain("t('app-onboarding-finish-details')") + it.concurrent('labels the icon action as skip until an icon is provided', () => { + const iconAction = sliceBetween(onboardingSource, ':data-test="appDetailsStep === \'app_id\'', ' { From 10efa77b3b712ca7ed223c77ff55832b40fd1bb4 Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Wed, 19 Aug 2026 10:12:53 +0200 Subject: [PATCH 4/5] fix(i18n): add icon skip translator context --- messages/en.context.json | 1 + 1 file changed, 1 insertion(+) diff --git a/messages/en.context.json b/messages/en.context.json index 88bd92be9f..17124acdc8 100644 --- a/messages/en.context.json +++ b/messages/en.context.json @@ -3098,6 +3098,7 @@ "app-onboarding-name-step-title": "Used in app onboarding details wizard. Role: step title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "app-onboarding-remove-icon": "Used in app onboarding details wizard. Role: button label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "app-onboarding-skip-app-id": "Used in app onboarding details wizard. Role: button label that accepts Capgo's generated App ID. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", + "app-onboarding-skip-icon": "Used in app onboarding details wizard. Role: button label that continues without an optional app icon. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "app-onboarding-toast-store-icon-error": "Used in app onboarding details wizard. Role: error toast. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "app-onboarding-use-different-icon": "Used in app onboarding details wizard. Role: section label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "app-onboarding-use-imported-icon": "Used in app onboarding details wizard. Role: button label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", From f19cab8a28b29b8268d37104c7b578362e748f6f Mon Sep 17 00:00:00 2001 From: WcaleNieWolny Date: Wed, 19 Aug 2026 10:45:43 +0200 Subject: [PATCH 5/5] refactor(onboarding): clarify primary action label --- src/components/dashboard/AppOnboardingFlow.vue | 15 ++++++++++----- tests/app-onboarding-v3.unit.test.ts | 8 ++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/components/dashboard/AppOnboardingFlow.vue b/src/components/dashboard/AppOnboardingFlow.vue index 1efdbbf2f6..7914c4656e 100644 --- a/src/components/dashboard/AppOnboardingFlow.vue +++ b/src/components/dashboard/AppOnboardingFlow.vue @@ -304,6 +304,15 @@ const suggestedAppId = computed(() => { }) const generatedAppId = computed(() => createdApp.value?.app_id || manualAppId.value.trim() || suggestedAppId.value) const hasProvidedAppId = computed(() => Boolean(manualAppId.value.trim() || importedStoreAppId.value.trim())) +const appDetailsPrimaryActionLabel = computed(() => { + if (appDetailsStep.value === 'icon') + return iconPreview.value ? t('app-onboarding-continue') : t('app-onboarding-skip-icon') + + if (appDetailsStep.value === 'app_id' && !hasProvidedAppId.value) + return t('app-onboarding-skip-app-id') + + return t('app-onboarding-continue') +}) const appNameInitial = computed(() => Array.from(appName.value.trim())[0]?.toLocaleUpperCase() ?? '') const selectedAppIdSource = computed>(() => { if (manualAppId.value.trim()) @@ -2446,11 +2455,7 @@ defineExpose({ @click="continueFromCurrentAppDetailsStep" > - {{ appDetailsStep === 'icon' - ? iconPreview ? t('app-onboarding-continue') : t('app-onboarding-skip-icon') - : appDetailsStep === 'app_id' && !hasProvidedAppId - ? t('app-onboarding-skip-app-id') - : t('app-onboarding-continue') }} + {{ appDetailsPrimaryActionLabel }} diff --git a/tests/app-onboarding-v3.unit.test.ts b/tests/app-onboarding-v3.unit.test.ts index 7cbb7c6bfa..e750524442 100644 --- a/tests/app-onboarding-v3.unit.test.ts +++ b/tests/app-onboarding-v3.unit.test.ts @@ -155,10 +155,14 @@ describe('pre-organization onboarding v3', () => { it.concurrent('labels the icon action as skip until an icon is provided', () => { const iconAction = sliceBetween(onboardingSource, ':data-test="appDetailsStep === \'app_id\'', ' {', 'const appNameInitial = computed') expect(messages['app-onboarding-skip-icon']).toBe('Skip') - expect(iconAction).toContain("appDetailsStep === 'icon'") - expect(iconAction).toContain("iconPreview ? t('app-onboarding-continue') : t('app-onboarding-skip-icon')") + expect(primaryActionLabel).toContain("if (appDetailsStep.value === 'icon')") + expect(primaryActionLabel).toContain("return iconPreview.value ? t('app-onboarding-continue') : t('app-onboarding-skip-icon')") + expect(primaryActionLabel).toContain("if (appDetailsStep.value === 'app_id' && !hasProvidedAppId.value)") + expect(primaryActionLabel).toContain("return t('app-onboarding-skip-app-id')") + expect(iconAction).toContain('{{ appDetailsPrimaryActionLabel }}') expect(iconAction).not.toContain("t('app-onboarding-finish-details')") })