feat: add landing page and complete app
- EreaderMockup: animated SVG e-reader illustration - DitherComparison: interactive before/after demo - Landing page with hero, features, about sections - Converter with view mode toggle and batch download - Updated exports and theme styles Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
121
src/lib/components/EreaderMockup.svelte
Normal file
121
src/lib/components/EreaderMockup.svelte
Normal file
@@ -0,0 +1,121 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
let { class: className = '' }: Props = $props();
|
||||
</script>
|
||||
|
||||
<svg
|
||||
viewBox="-30 -20 340 440"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class={className}
|
||||
style="overflow: visible;"
|
||||
>
|
||||
<!-- Device body with shadow -->
|
||||
<defs>
|
||||
<filter id="deviceShadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feDropShadow dx="4" dy="12" stdDeviation="16" flood-color="#000" flood-opacity="0.25" />
|
||||
</filter>
|
||||
<linearGradient id="screenGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" stop-color="#f8f8f8" />
|
||||
<stop offset="100%" stop-color="#e8e8e8" />
|
||||
</linearGradient>
|
||||
<clipPath id="screenClip">
|
||||
<rect x="24" y="24" width="232" height="310" rx="2" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<!-- Device outer shell -->
|
||||
<rect
|
||||
x="4"
|
||||
y="4"
|
||||
width="272"
|
||||
height="372"
|
||||
rx="16"
|
||||
fill="#2a2a2a"
|
||||
filter="url(#deviceShadow)"
|
||||
/>
|
||||
|
||||
<!-- Device bezel -->
|
||||
<rect
|
||||
x="8"
|
||||
y="8"
|
||||
width="264"
|
||||
height="364"
|
||||
rx="12"
|
||||
fill="#1a1a1a"
|
||||
/>
|
||||
|
||||
<!-- Screen area -->
|
||||
<rect
|
||||
x="24"
|
||||
y="24"
|
||||
width="232"
|
||||
height="310"
|
||||
rx="2"
|
||||
fill="url(#screenGradient)"
|
||||
/>
|
||||
|
||||
<!-- Sample e-ink image (abstract landscape) -->
|
||||
<g clip-path="url(#screenClip)">
|
||||
<!-- Sky gradient -->
|
||||
<rect x="24" y="24" width="232" height="155" fill="#d4d4d4" />
|
||||
|
||||
<!-- Sun/moon (behind mountains) -->
|
||||
<circle cx="200" cy="70" r="25" fill="#f0f0f0" />
|
||||
|
||||
<!-- Mountains - back layer -->
|
||||
<path
|
||||
d="M24 160 L80 100 L140 140 L200 80 L256 130 L256 334 L24 334 Z"
|
||||
fill="#a0a0a0"
|
||||
/>
|
||||
|
||||
<!-- Mountains - front layer -->
|
||||
<path
|
||||
d="M24 180 L60 130 L120 170 L180 120 L240 160 L256 150 L256 334 L24 334 Z"
|
||||
fill="#707070"
|
||||
/>
|
||||
|
||||
<!-- Hills/foreground -->
|
||||
<path
|
||||
d="M24 200 Q80 180 140 210 Q200 240 256 200 L256 334 L24 334 Z"
|
||||
fill="#505050"
|
||||
/>
|
||||
|
||||
<!-- Trees silhouette -->
|
||||
<g fill="#404040">
|
||||
<path d="M40 210 L50 180 L60 210 Z" />
|
||||
<path d="M55 215 L65 190 L75 215 Z" />
|
||||
<path d="M200 225 L212 195 L224 225 Z" />
|
||||
<path d="M215 230 L225 205 L235 230 Z" />
|
||||
</g>
|
||||
|
||||
<!-- Subtle dither pattern overlay -->
|
||||
<g opacity="0.08">
|
||||
{#each Array(50) as _, i}
|
||||
{#each Array(65) as _, j}
|
||||
{#if (i + j) % 2 === 0}
|
||||
<rect x={24 + j * 3.6} y={24 + i * 6.2} width="1" height="1" fill="#000" />
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Screen bezel inner edge highlight -->
|
||||
<rect
|
||||
x="24"
|
||||
y="24"
|
||||
width="232"
|
||||
height="310"
|
||||
rx="2"
|
||||
fill="none"
|
||||
stroke="#333"
|
||||
stroke-width="1"
|
||||
/>
|
||||
|
||||
<!-- Home button / indicator -->
|
||||
<circle cx="140" cy="356" r="8" fill="#333" stroke="#444" stroke-width="1" />
|
||||
</svg>
|
||||
Reference in New Issue
Block a user