feat(export-ui): Display 드롭다운/테마컬러 HEX 검증 반영(TDD)
This commit is contained in:
@@ -223,7 +223,13 @@ export default function BuilderClientPage() {
|
|||||||
if (manifestShortName && manifestShortName.trim().length > 0) manifestOverrideBase.short_name = manifestShortName.trim()
|
if (manifestShortName && manifestShortName.trim().length > 0) manifestOverrideBase.short_name = manifestShortName.trim()
|
||||||
if (manifestStartUrl && manifestStartUrl.trim().length > 0) manifestOverrideBase.start_url = manifestStartUrl.trim()
|
if (manifestStartUrl && manifestStartUrl.trim().length > 0) manifestOverrideBase.start_url = manifestStartUrl.trim()
|
||||||
if (manifestDisplay && manifestDisplay.trim().length > 0) manifestOverrideBase.display = manifestDisplay.trim()
|
if (manifestDisplay && manifestDisplay.trim().length > 0) manifestOverrideBase.display = manifestDisplay.trim()
|
||||||
if (manifestThemeColor && manifestThemeColor.trim().length > 0) manifestOverrideBase.theme_color = manifestThemeColor.trim()
|
if (manifestThemeColor && manifestThemeColor.trim().length > 0) {
|
||||||
|
const v = manifestThemeColor.trim()
|
||||||
|
const hexOk = /^#([0-9a-fA-F]{3}){1,2}$/.test(v)
|
||||||
|
if (hexOk) {
|
||||||
|
manifestOverrideBase.theme_color = v
|
||||||
|
}
|
||||||
|
}
|
||||||
const manifestOverride = Object.keys(manifestOverrideBase).length > 0 ? (manifestOverrideBase as { name?: string; short_name?: string; start_url?: string; display?: string; theme_color?: string }) : undefined
|
const manifestOverride = Object.keys(manifestOverrideBase).length > 0 ? (manifestOverrideBase as { name?: string; short_name?: string; start_url?: string; display?: string; theme_color?: string }) : undefined
|
||||||
const robotsTextOverride = (() => {
|
const robotsTextOverride = (() => {
|
||||||
const lines = (robotsDisallow || '').split(/\n+/).map((s) => s.trim()).filter((s) => s.length > 0)
|
const lines = (robotsDisallow || '').split(/\n+/).map((s) => s.trim()).filter((s) => s.length > 0)
|
||||||
@@ -334,14 +340,18 @@ export default function BuilderClientPage() {
|
|||||||
</label>
|
</label>
|
||||||
<label className="block" htmlFor="ins-manifest-display">
|
<label className="block" htmlFor="ins-manifest-display">
|
||||||
<span className="sr-only">Manifest Display</span>
|
<span className="sr-only">Manifest Display</span>
|
||||||
<input
|
<select
|
||||||
id="ins-manifest-display"
|
id="ins-manifest-display"
|
||||||
aria-label="Manifest Display"
|
aria-label="Manifest Display"
|
||||||
className="border rounded px-3 py-2 w-full"
|
className="border rounded px-3 py-2 w-full"
|
||||||
value={manifestDisplay}
|
value={manifestDisplay}
|
||||||
onChange={(e) => setManifestDisplay(e.target.value)}
|
onChange={(e) => setManifestDisplay(e.target.value)}
|
||||||
placeholder="standalone"
|
>
|
||||||
/>
|
<option value="">(default)</option>
|
||||||
|
<option value="standalone">standalone</option>
|
||||||
|
<option value="minimal-ui">minimal-ui</option>
|
||||||
|
<option value="browser">browser</option>
|
||||||
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label className="block" htmlFor="ins-manifest-theme-color">
|
<label className="block" htmlFor="ins-manifest-theme-color">
|
||||||
<span className="sr-only">Manifest Theme Color</span>
|
<span className="sr-only">Manifest Theme Color</span>
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { describe, it, expect, vi } from 'vitest'
|
||||||
|
import { render, screen, fireEvent } from '@testing-library/react'
|
||||||
|
import BuilderClientPage from '@/components/BuilderClientPage'
|
||||||
|
|
||||||
|
vi.mock('next-intl', () => {
|
||||||
|
return {
|
||||||
|
useTranslations: () => (key: string) => key,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const buildZipSpy = vi.fn(async (_arg: {
|
||||||
|
html: string
|
||||||
|
css: string
|
||||||
|
js: string
|
||||||
|
assets: Record<string, Uint8Array>
|
||||||
|
extras?: Record<string, Uint8Array>
|
||||||
|
}) => new Uint8Array([80, 75]))
|
||||||
|
|
||||||
|
vi.mock('@/lib/exporter/zip', () => {
|
||||||
|
return {
|
||||||
|
buildZip: (arg: {
|
||||||
|
html: string
|
||||||
|
css: string
|
||||||
|
js: string
|
||||||
|
assets: Record<string, Uint8Array>
|
||||||
|
extras?: Record<string, Uint8Array>
|
||||||
|
}) => buildZipSpy(arg),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Export Options UI polish', () => {
|
||||||
|
it('uses a dropdown for Manifest Display and passes selected value', async () => {
|
||||||
|
render(<BuilderClientPage />)
|
||||||
|
|
||||||
|
// choose display = minimal-ui
|
||||||
|
const displaySelect = await screen.findByLabelText('Manifest Display')
|
||||||
|
fireEvent.change(displaySelect, { target: { value: 'minimal-ui' } })
|
||||||
|
|
||||||
|
const exportBtn = await screen.findByRole('button', { name: 'builder.action.export' })
|
||||||
|
fireEvent.click(exportBtn)
|
||||||
|
|
||||||
|
const first = buildZipSpy.mock.calls[0]
|
||||||
|
const extras: Record<string, Uint8Array> = (first![0] as { extras: Record<string, Uint8Array> }).extras
|
||||||
|
const td = new TextDecoder()
|
||||||
|
const manifest = JSON.parse(td.decode(extras['site.webmanifest']))
|
||||||
|
expect(manifest.display).toBe('minimal-ui')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ignores invalid theme_color override and keeps default theme when not a hex', async () => {
|
||||||
|
render(<BuilderClientPage />)
|
||||||
|
|
||||||
|
const colorInput = await screen.findByLabelText('Manifest Theme Color')
|
||||||
|
fireEvent.change(colorInput, { target: { value: 'blue' } }) // invalid hex
|
||||||
|
|
||||||
|
const exportBtn = await screen.findByRole('button', { name: 'builder.action.export' })
|
||||||
|
fireEvent.click(exportBtn)
|
||||||
|
|
||||||
|
const first = buildZipSpy.mock.calls[0]
|
||||||
|
const extras: Record<string, Uint8Array> = (first![0] as { extras: Record<string, Uint8Array> }).extras
|
||||||
|
const td = new TextDecoder()
|
||||||
|
const manifest = JSON.parse(td.decode(extras['site.webmanifest']))
|
||||||
|
expect(manifest.theme_color).toBe('#0ea5e9') // default from page.theme.primaryColor
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user