feat(design): v2 becomes the default — drop beta conversation
CI / test (push) Has been cancelled

Atmospheric design is now the default for everyone:
- User.getDesignVersion() returns 'v2' when unset (was 'v1')
- All Twig templates default the cookie read to 'v2'
- SettingsView 'Design (beta)' section removed entirely along with the
  selectDesign() handler and currentDesign computed

The /api/user/design endpoint stays in place so the design_version column
can still be set programmatically (or migrated later), but the UI no
longer exposes it as a user-facing choice. Existing users with explicit
'v1' in their DB row continue to see v1 — their preference persists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 20:22:18 -04:00
parent c794878e5e
commit 019a3363c5
21 changed files with 21 additions and 73 deletions
-52
View File
@@ -38,36 +38,6 @@
</div>
</section>
<section class="settings__section">
<h2 class="settings__section-title">Design (beta)</h2>
<p class="settings__hint">
Try the new atmospheric look. Your theme picks above still apply
v2 just renders them as dusks over a Camogli harbor backdrop.
</p>
<div class="design-toggle" role="radiogroup" aria-label="Design version">
<button
type="button"
role="radio"
:aria-checked="currentDesign === 'v1'"
:class="['design-toggle__opt', { 'design-toggle__opt--active': currentDesign === 'v1' }]"
@click="selectDesign('v1')"
>
<span class="design-toggle__label">Original</span>
<span class="design-toggle__sub">cream &amp; terracotta</span>
</button>
<button
type="button"
role="radio"
:aria-checked="currentDesign === 'v2'"
:class="['design-toggle__opt', { 'design-toggle__opt--active': currentDesign === 'v2' }]"
@click="selectDesign('v2')"
>
<span class="design-toggle__label">Atmospheric</span>
<span class="design-toggle__sub">harbor dusks · beta</span>
</button>
</div>
</section>
<section v-if="!isStandalone" class="settings__section">
<h2 class="settings__section-title">Install app</h2>
<p class="settings__hint">
@@ -207,34 +177,12 @@ const { saveTheme } = useTheme()
const { isStandalone, isIOS, canPromptInstall, install } = usePwaInstall()
const currentTheme = computed(() => auth.user?.theme ?? 'warm-craft')
const currentDesign = computed(() => auth.user?.designVersion ?? 'v1')
const showIosInstructions = ref(false)
function select(themeId: string) {
saveTheme(themeId)
}
async function selectDesign(version: 'v1' | 'v2') {
if (currentDesign.value === version) return
const prev = currentDesign.value
// Optimistic local update so the SPA flips immediately.
if (auth.user) auth.user.designVersion = version
document.documentElement.setAttribute('data-design', version)
try {
const res = await fetch('/api/user/design', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ designVersion: version }),
})
if (!res.ok) throw new Error('save failed')
// Cookie is set in the response — read-once nothing else to do here.
} catch {
// Revert on failure.
if (auth.user) auth.user.designVersion = prev
document.documentElement.setAttribute('data-design', prev)
}
}
async function onNativeInstall() {
const accepted = await install()
// If the native prompt failed for any reason (rare — e.g. the event
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -17,7 +17,7 @@
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="WeVisto" />
<script type="module" crossorigin src="/build/assets/index-CdLYHZeF.js"></script>
<script type="module" crossorigin src="/build/assets/index-B_gtMXqz.js"></script>
<link rel="modulepreload" crossorigin href="/build/assets/_plugin-vue_export-helper-BNDVmFr7.js">
<link rel="stylesheet" crossorigin href="/build/assets/index-CUd6onTU.css">
</head>
+2 -2
View File
@@ -113,10 +113,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
/** Returns 'v1' or 'v2'; defaults to 'v1' when unset. */
/** Returns 'v1' or 'v2'; defaults to 'v2' (current default). */
public function getDesignVersion(): string
{
return $this->designVersion ?? 'v1';
return $this->designVersion ?? 'v2';
}
public function setDesignVersion(?string $version): static
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v1') }}">
<html lang="en" data-design="{{ app.request.cookies.get('wevisto_design')|default('v2') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">