From c50a601199dfc792f2e948aec561b4e928e62fff Mon Sep 17 00:00:00 2001 From: jellydeck <91427591+jellydeck@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:09:42 +0530 Subject: [PATCH] chore: add canvas & background --- {static => src/lib}/assets/arctic_pulse.webp | Bin {static => src/lib}/assets/cosmic_night.webp | Bin {static => src/lib}/assets/deep_horizon.webp | Bin {static => src/lib}/assets/demo.webp | Bin {static => src/lib}/assets/mint_breeze.webp | Bin {static => src/lib}/assets/molten_dusk.webp | Bin {static => src/lib}/assets/monochrome.png | Bin {static => src/lib}/assets/neon_heat.webp | Bin {static => src/lib}/assets/neon_midnight.webp | Bin {static => src/lib}/assets/ocean_breeze.png | Bin {static => src/lib}/assets/ocean_glow.webp | Bin {static => src/lib}/assets/purple_haze.png | Bin {static => src/lib}/assets/purple_magic.png | Bin {static => src/lib}/assets/rainbow_dreams.png | Bin {static => src/lib}/assets/summer_vibes.png | Bin {static => src/lib}/assets/sunset_glow.png | Bin .../lib}/assets/twilight_ember.webp | Bin {static => src/lib}/assets/warm_embrace.png | Bin src/lib/components/Button.svelte | 11 +- src/lib/editor/Backgrounds.svelte | 286 +++++++++++ src/lib/editor/Canvas.svelte | 484 ++++++++++++++++++ src/lib/editor/Navbar.svelte | 58 +-- src/lib/styles/global.css | 24 +- src/lib/utils.ts | 59 +++ src/routes/+layout.ts | 3 + src/routes/+page.svelte | 9 +- src/routes/layout.css | 1 - 27 files changed, 884 insertions(+), 51 deletions(-) rename {static => src/lib}/assets/arctic_pulse.webp (100%) rename {static => src/lib}/assets/cosmic_night.webp (100%) rename {static => src/lib}/assets/deep_horizon.webp (100%) rename {static => src/lib}/assets/demo.webp (100%) rename {static => src/lib}/assets/mint_breeze.webp (100%) rename {static => src/lib}/assets/molten_dusk.webp (100%) rename {static => src/lib}/assets/monochrome.png (100%) rename {static => src/lib}/assets/neon_heat.webp (100%) rename {static => src/lib}/assets/neon_midnight.webp (100%) rename {static => src/lib}/assets/ocean_breeze.png (100%) rename {static => src/lib}/assets/ocean_glow.webp (100%) rename {static => src/lib}/assets/purple_haze.png (100%) rename {static => src/lib}/assets/purple_magic.png (100%) rename {static => src/lib}/assets/rainbow_dreams.png (100%) rename {static => src/lib}/assets/summer_vibes.png (100%) rename {static => src/lib}/assets/sunset_glow.png (100%) rename {static => src/lib}/assets/twilight_ember.webp (100%) rename {static => src/lib}/assets/warm_embrace.png (100%) create mode 100644 src/lib/editor/Backgrounds.svelte create mode 100644 src/lib/editor/Canvas.svelte create mode 100644 src/routes/+layout.ts delete mode 100644 src/routes/layout.css diff --git a/static/assets/arctic_pulse.webp b/src/lib/assets/arctic_pulse.webp similarity index 100% rename from static/assets/arctic_pulse.webp rename to src/lib/assets/arctic_pulse.webp diff --git a/static/assets/cosmic_night.webp b/src/lib/assets/cosmic_night.webp similarity index 100% rename from static/assets/cosmic_night.webp rename to src/lib/assets/cosmic_night.webp diff --git a/static/assets/deep_horizon.webp b/src/lib/assets/deep_horizon.webp similarity index 100% rename from static/assets/deep_horizon.webp rename to src/lib/assets/deep_horizon.webp diff --git a/static/assets/demo.webp b/src/lib/assets/demo.webp similarity index 100% rename from static/assets/demo.webp rename to src/lib/assets/demo.webp diff --git a/static/assets/mint_breeze.webp b/src/lib/assets/mint_breeze.webp similarity index 100% rename from static/assets/mint_breeze.webp rename to src/lib/assets/mint_breeze.webp diff --git a/static/assets/molten_dusk.webp b/src/lib/assets/molten_dusk.webp similarity index 100% rename from static/assets/molten_dusk.webp rename to src/lib/assets/molten_dusk.webp diff --git a/static/assets/monochrome.png b/src/lib/assets/monochrome.png similarity index 100% rename from static/assets/monochrome.png rename to src/lib/assets/monochrome.png diff --git a/static/assets/neon_heat.webp b/src/lib/assets/neon_heat.webp similarity index 100% rename from static/assets/neon_heat.webp rename to src/lib/assets/neon_heat.webp diff --git a/static/assets/neon_midnight.webp b/src/lib/assets/neon_midnight.webp similarity index 100% rename from static/assets/neon_midnight.webp rename to src/lib/assets/neon_midnight.webp diff --git a/static/assets/ocean_breeze.png b/src/lib/assets/ocean_breeze.png similarity index 100% rename from static/assets/ocean_breeze.png rename to src/lib/assets/ocean_breeze.png diff --git a/static/assets/ocean_glow.webp b/src/lib/assets/ocean_glow.webp similarity index 100% rename from static/assets/ocean_glow.webp rename to src/lib/assets/ocean_glow.webp diff --git a/static/assets/purple_haze.png b/src/lib/assets/purple_haze.png similarity index 100% rename from static/assets/purple_haze.png rename to src/lib/assets/purple_haze.png diff --git a/static/assets/purple_magic.png b/src/lib/assets/purple_magic.png similarity index 100% rename from static/assets/purple_magic.png rename to src/lib/assets/purple_magic.png diff --git a/static/assets/rainbow_dreams.png b/src/lib/assets/rainbow_dreams.png similarity index 100% rename from static/assets/rainbow_dreams.png rename to src/lib/assets/rainbow_dreams.png diff --git a/static/assets/summer_vibes.png b/src/lib/assets/summer_vibes.png similarity index 100% rename from static/assets/summer_vibes.png rename to src/lib/assets/summer_vibes.png diff --git a/static/assets/sunset_glow.png b/src/lib/assets/sunset_glow.png similarity index 100% rename from static/assets/sunset_glow.png rename to src/lib/assets/sunset_glow.png diff --git a/static/assets/twilight_ember.webp b/src/lib/assets/twilight_ember.webp similarity index 100% rename from static/assets/twilight_ember.webp rename to src/lib/assets/twilight_ember.webp diff --git a/static/assets/warm_embrace.png b/src/lib/assets/warm_embrace.png similarity index 100% rename from static/assets/warm_embrace.png rename to src/lib/assets/warm_embrace.png diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button.svelte index 4086e58..7416bc0 100644 --- a/src/lib/components/Button.svelte +++ b/src/lib/components/Button.svelte @@ -10,12 +10,11 @@ {#if children} diff --git a/src/lib/editor/Backgrounds.svelte b/src/lib/editor/Backgrounds.svelte new file mode 100644 index 0000000..2736e47 --- /dev/null +++ b/src/lib/editor/Backgrounds.svelte @@ -0,0 +1,286 @@ + + + +{#snippet gradientGrid()} +
+

Background Gradients

+
+ + + + + {#each [...mockupStore.customBackgrounds, ...gradientPresets] as gradient, i (gradient.name + i)} + + {/each} +
+
+{/snippet} + + + + + + + + (isSheetOpen = false)} /> + + +
+
+
+
+ {@render gradientGrid()} +
+
+
+
+ + + + + + + + + + + Upload Custom Background + +

+ Add a custom background to personalise your creation. +

+ + +
{ + e.preventDefault(); + isDragOver = true; + }} + ondragleave={() => (isDragOver = false)} + onclick={() => fileInputRef?.click()} + role="button" + tabindex="0" + onkeydown={(e) => e.key === 'Enter' && fileInputRef?.click()} + > + +

Drop image here or click to upload

+

Supports JPG, PNG

+ + {#if isDragOver} +
+ + Drop image here + +
+ {/if} +
+ + + + + ✕ + +
+
+
diff --git a/src/lib/editor/Canvas.svelte b/src/lib/editor/Canvas.svelte new file mode 100644 index 0000000..48c8e51 --- /dev/null +++ b/src/lib/editor/Canvas.svelte @@ -0,0 +1,484 @@ + + +
+
+
+ {#if mockupStore.uploadedImage} +
+
+ Uploaded mockup e.stopPropagation()} + /> + + {#if isDragOver} +
+
+ Drop to replace image +
+
+ {/if} + + {#if showPasteHint} +
+
+ + Image ready to paste! +
+
+ {/if} +
+
+ {:else} +
fileInputRef?.click()} + role="button" + tabindex="0" + onkeydown={(e) => e.key === 'Enter' && fileInputRef?.click()} + > +
+ + +
+

+ Drop image here or click to upload +

+

+ Supports JPG, PNG +

+
+ + + Or paste image (Ctrl+V) + +
+
+ + +
+ + {#if isDragOver} +
+
+ Drop image here +
+
+ {/if} +
+ {/if} +
+ + +
+
diff --git a/src/lib/editor/Navbar.svelte b/src/lib/editor/Navbar.svelte index dd61eae..f6cfd80 100644 --- a/src/lib/editor/Navbar.svelte +++ b/src/lib/editor/Navbar.svelte @@ -78,22 +78,22 @@ } } - async function handleAllFormatsExport() { - if (!uploadedImage) { - toast.error('Please upload an image first'); - return; - } - isExporting = true; - const formats = ['PNG', 'JPEG', 'WebP']; - try { - await Promise.all(formats.map((f) => exportImage(f, parseInt(quality)))); - toast.success(`Successfully exported all formats (${formats.join(', ')})!`); - } catch { - toast.error('Failed to export some formats. Please try again.'); - } finally { - isExporting = false; - } - } + // async function handleAllFormatsExport() { + // if (!uploadedImage) { + // toast.error('Please upload an image first'); + // return; + // } + // isExporting = true; + // const formats = ['PNG', 'JPEG', 'WebP']; + // try { + // await Promise.all(formats.map((f) => exportImage(f, parseInt(quality)))); + // toast.success(`Successfully exported all formats (${formats.join(', ')})!`); + // } catch { + // toast.error('Failed to export some formats. Please try again.'); + // } finally { + // isExporting = false; + // } + // } @@ -154,13 +154,13 @@ {/if} - + + {#snippet child({ props })} + + {/snippet} {@render exportOptions()} diff --git a/src/lib/styles/global.css b/src/lib/styles/global.css index cb4b00e..cd868cd 100644 --- a/src/lib/styles/global.css +++ b/src/lib/styles/global.css @@ -2,12 +2,15 @@ @import 'tailwindcss'; :root { - --bg: oklch(0.979 0.004 360); - --text: oklch(0.291 0.006 301.2); - --accent: oklch(0.663 0.22 28.2); - --peach: oklch(0.38 0.133 8.5); - --border: oklch(0.663 0.195 28.2 / 0.3); - --highlight: oklch(0.439 0.144 27.5); + --bg: #100d0b; + --text: #f6eae4; + --accent: #e8cff1; + + --pine: #262913; + --pine-text: #6e803b; + + --white: #f3efef; + --border: #232b21; --mono: 0; /* Monospace: Sans (natural-width) or Mono (fixed-width) */ --casl: 0; /* Casual: Linear to Casual */ @@ -17,9 +20,12 @@ --color-bg: var(--bg); --color-text: var(--text); --color-accent: var(--accent); - --color-peach: var(--peach); - /*--color-border: var(--border);*/ - /*--color-highlight: var(--highlight);*/ + + --color-pine: var(--pine); + --color-pine-text: var(--pine-text); + + --color-white: var(--white); + --color-border: var(--border); } * { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 256f86f..992e2e9 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,3 +4,62 @@ import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } + +export const extractDominantColor = (imageUrl: string): Promise => { + return new Promise((resolve) => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + const img = new Image(); + + img.crossOrigin = 'anonymous'; + img.onload = () => { + canvas.width = img.width; + canvas.height = img.height; + ctx?.drawImage(img, 0, 0); + + const imageData = ctx?.getImageData(0, 0, canvas.width, canvas.height); + if (!imageData) { + resolve('#9CA389'); // fallback color + return; + } + + const colorMap = new Map(); + const data = imageData.data; + + // Sample every 10th pixel for performance + for (let i = 0; i < data.length; i += 40) { + const r = data[i]; + const g = data[i + 1]; + const b = data[i + 2]; + const alpha = data[i + 3]; + + // Skip transparent pixels + if (alpha < 128) continue; + + // Convert to hex + const hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; + + colorMap.set(hex, (colorMap.get(hex) || 0) + 1); + } + + // Find the most frequent color + let dominantColor = '#9CA389'; + let maxCount = 0; + + for (const [color, count] of colorMap.entries()) { + if (count > maxCount) { + maxCount = count; + dominantColor = color; + } + } + + resolve(dominantColor); + }; + + img.onerror = () => { + resolve('#9CA389'); // fallback color + }; + + img.src = imageUrl; + }); +}; diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts new file mode 100644 index 0000000..0bf6a84 --- /dev/null +++ b/src/routes/+layout.ts @@ -0,0 +1,3 @@ +// app is SPA +export const ssr = false; +export const prerender = false; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index aa9edec..ea19b31 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,8 +1,7 @@ -

Welcome to SvelteKit

-

Visit svelte.dev/docs/kit to read the documentation

- - - + + diff --git a/src/routes/layout.css b/src/routes/layout.css deleted file mode 100644 index d4b5078..0000000 --- a/src/routes/layout.css +++ /dev/null @@ -1 +0,0 @@ -@import 'tailwindcss'; -- 2.51.2