Skip to content

Commit 2dcc3de

Browse files
fix: download correct variant and fix layout shift on brand page (#2595)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 94ef76d commit 2dcc3de

File tree

2 files changed

+53
-57
lines changed

2 files changed

+53
-57
lines changed

app/components/Brand/Customize.vue

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ async function downloadCustomPng() {
7575
if (!svg) return
7676
pngLoading.value = true
7777
78-
const blob = new Blob([svg], { type: 'image/svg+xml' })
79-
const url = URL.createObjectURL(blob)
78+
const url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
8079
8180
try {
8281
await document.fonts.ready
@@ -108,7 +107,6 @@ async function downloadCustomPng() {
108107
}, 'image/png')
109108
})
110109
} finally {
111-
URL.revokeObjectURL(url)
112110
pngLoading.value = false
113111
}
114112
}
@@ -145,24 +143,30 @@ async function downloadCustomPng() {
145143
<span class="text-sm font-mono text-fg-muted shrink-0">{{
146144
$t('brand.customize.accent_label')
147145
}}</span>
148-
<div class="flex items-center gap-1.5" role="radiogroup">
149-
<ButtonBase
146+
<div class="flex items-center gap-1.5">
147+
<label
150148
v-for="color in pickerColors"
151149
:key="color.id"
152-
role="radio"
153-
:aria-checked="activeAccentId === color.id"
154-
:aria-label="color.label"
155-
class="!w-6 !h-6 !rounded-full !border-2 !p-0 !min-w-0 transition-all duration-150 motion-reduce:transition-none"
150+
class="relative w-6 h-6 rounded-full border-2 cursor-pointer duration-150 motion-reduce:transition-none focus-within:ring-2 focus-within:ring-fg focus-within:ring-offset-2 focus-within:ring-offset-bg"
156151
:class="
157152
activeAccentId === color.id
158-
? '!border-fg scale-110'
153+
? 'border-fg scale-110'
159154
: color.id === 'neutral'
160-
? '!border-border hover:!border-border-hover'
161-
: '!border-transparent hover:!border-border-hover'
155+
? 'border-border hover:border-border-hover'
156+
: 'border-transparent hover:border-border-hover'
162157
"
163158
:style="{ backgroundColor: color.value }"
164-
@click="customAccent = color.id"
165-
/>
159+
>
160+
<input
161+
type="radio"
162+
name="brand-customize-accent"
163+
:value="color.id"
164+
:checked="activeAccentId === color.id"
165+
:aria-label="color.label"
166+
class="sr-only"
167+
@change="customAccent = color.id"
168+
/>
169+
</label>
166170
</div>
167171
</fieldset>
168172

@@ -172,40 +176,33 @@ async function downloadCustomPng() {
172176
<span class="text-sm font-mono text-fg-muted">{{
173177
$t('brand.customize.bg_label')
174178
}}</span>
175-
<div
176-
class="flex items-center border border-border rounded-md overflow-hidden"
177-
role="radiogroup"
178-
>
179-
<ButtonBase
180-
size="md"
181-
role="radio"
182-
:aria-checked="customBgDark"
183-
:aria-label="$t('brand.logos.on_dark')"
184-
class="!border-none !rounded-none motion-reduce:transition-none"
185-
:class="
186-
customBgDark
187-
? 'bg-bg-muted text-fg'
188-
: 'bg-transparent text-fg-muted hover:text-fg'
189-
"
190-
@click="customBgDark = true"
179+
<div class="flex items-center border border-border rounded-md overflow-hidden">
180+
<label
181+
class="px-3 py-1.5 text-sm font-mono cursor-pointer motion-reduce:transition-none focus-within:bg-fg/10"
182+
:class="customBgDark ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'"
191183
>
184+
<input
185+
v-model="customBgDark"
186+
type="radio"
187+
name="brand-customize-bg"
188+
:value="true"
189+
class="sr-only"
190+
/>
192191
{{ $t('brand.logos.on_dark') }}
193-
</ButtonBase>
194-
<ButtonBase
195-
size="md"
196-
role="radio"
197-
:aria-checked="!customBgDark"
198-
:aria-label="$t('brand.logos.on_light')"
199-
class="!border-none !rounded-none border-is border-is-border motion-reduce:transition-none"
200-
:class="
201-
!customBgDark
202-
? 'bg-bg-muted text-fg'
203-
: 'bg-transparent text-fg-muted hover:text-fg'
204-
"
205-
@click="customBgDark = false"
192+
</label>
193+
<label
194+
class="px-3 py-1.5 text-sm font-mono cursor-pointer border-is border-is-border motion-reduce:transition-none focus-within:bg-fg/10"
195+
:class="!customBgDark ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'"
206196
>
197+
<input
198+
v-model="customBgDark"
199+
type="radio"
200+
name="brand-customize-bg"
201+
:value="false"
202+
class="sr-only"
203+
/>
207204
{{ $t('brand.logos.on_light') }}
208-
</ButtonBase>
205+
</label>
209206
</div>
210207
</div>
211208

app/pages/brand.vue

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,16 @@ function handleSvgDownload(src: string) {
5757
}
5858
}
5959
60-
async function handlePngDownload(logo: (typeof logos)[number]) {
61-
if (pngLoading.value.has(logo.src)) return
62-
pngLoading.value.add(logo.src)
60+
async function handlePngDownload(logo: (typeof logos)[number], variant: 'dark' | 'light' = 'dark') {
61+
const src = variant === 'light' ? (logo.srcLight ?? logo.src) : logo.src
62+
if (pngLoading.value.has(src)) return
63+
pngLoading.value.add(src)
6364
try {
64-
const blob = await svgToPng(logo.src, logo.width, logo.height)
65-
const filename = logo.src.replace(/^\//, '').replace('.svg', '.png')
65+
const blob = await svgToPng(src, logo.width, logo.height)
66+
const filename = src.replace(/^\//, '').replace('.svg', '.png')
6667
downloadFile(blob, filename)
6768
} finally {
68-
pngLoading.value.delete(logo.src)
69+
pngLoading.value.delete(src)
6970
}
7071
}
7172
</script>
@@ -224,14 +225,14 @@ async function handlePngDownload(logo: (typeof logos)[number]) {
224225
name: `${logo.name()} (${$t('brand.logos.on_light')})`,
225226
})
226227
"
227-
:disabled="pngLoading.has(logo.src)"
228-
@click="handlePngDownload(logo)"
228+
:disabled="pngLoading.has(logo.srcLight ?? logo.src)"
229+
@click="handlePngDownload(logo, 'light')"
229230
>
230231
<span
231232
class="size-[1em]"
232233
aria-hidden="true"
233234
:class="
234-
pngLoading.has(logo.src)
235+
pngLoading.has(logo.srcLight ?? logo.src)
235236
? 'i-lucide:loader-circle animate-spin'
236237
: 'i-lucide:download'
237238
"
@@ -246,10 +247,8 @@ async function handlePngDownload(logo: (typeof logos)[number]) {
246247
</div>
247248
</section>
248249

249-
<!-- Customize Section (client-only: needs DOM for accent colors + canvas export) -->
250-
<ClientOnly>
251-
<BrandCustomize />
252-
</ClientOnly>
250+
<!-- Customize Section -->
251+
<BrandCustomize />
253252

254253
<!-- Typography Section -->
255254
<section aria-labelledby="brand-typography-heading">

0 commit comments

Comments
 (0)