feat: Implement marketing page layout, core sections, and shared UI components.

This commit is contained in:
2026-01-06 12:53:57 +01:00
parent 170c2e9c80
commit 2a057ae3e3
9 changed files with 44 additions and 20 deletions

View File

@@ -45,7 +45,7 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
const svgData = new XMLSerializer().serializeToString(svg);
const blob = new Blob([svgData], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
img.onload = () => {
canvas.width = size;
canvas.height = size;
@@ -93,50 +93,59 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<label htmlFor="foreground-color" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.foreground}
</label>
<div className="flex items-center space-x-2">
<input
id="foreground-color"
type="color"
value={foregroundColor}
onChange={(e) => setForegroundColor(e.target.value)}
className="w-12 h-10 rounded border border-gray-300"
aria-label="Foreground color picker"
/>
<Input
id="foreground-color-text"
value={foregroundColor}
onChange={(e) => setForegroundColor(e.target.value)}
className="flex-1"
aria-label="Foreground color hex value"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<label htmlFor="background-color" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.background}
</label>
<div className="flex items-center space-x-2">
<input
id="background-color"
type="color"
value={backgroundColor}
onChange={(e) => setBackgroundColor(e.target.value)}
className="w-12 h-10 rounded border border-gray-300"
aria-label="Background color picker"
/>
<Input
id="background-color-text"
value={backgroundColor}
onChange={(e) => setBackgroundColor(e.target.value)}
className="flex-1"
aria-label="Background color hex value"
/>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<label htmlFor="corner-style" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.corners}
</label>
<select
id="corner-style"
value={cornerStyle}
onChange={(e) => setCornerStyle(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
@@ -147,21 +156,23 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<label htmlFor="qr-size" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.size}
</label>
<input
id="qr-size"
type="range"
min="100"
max="400"
value={size}
onChange={(e) => setSize(Number(e.target.value))}
className="w-full"
aria-label={`QR code size: ${size} pixels`}
/>
<div className="text-sm text-gray-500 text-center mt-1">{size}px</div>
<div className="text-sm text-gray-500 text-center mt-1" aria-hidden="true">{size}px</div>
</div>
</div>
<div className="flex items-center justify-between">
<Badge variant={hasGoodContrast ? 'success' : 'warning'}>
{hasGoodContrast ? t.generator.contrast_good : 'Low contrast'}
@@ -201,7 +212,7 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
/>
</div>
) : (
<div
<div
className="bg-gray-200 flex items-center justify-center text-gray-500"
style={{ width: 200, height: 200 }}
>