Fraser commited on
Commit
384c29c
·
1 Parent(s): 5db7d9f

fix share log

Browse files
src/lib/components/Piclets/PicletDetail.svelte CHANGED
@@ -3,7 +3,6 @@
3
  import type { PicletInstance } from '$lib/db/schema';
4
  import { deletePicletInstance } from '$lib/db/piclets';
5
  import { uiStore } from '$lib/stores/ui';
6
- import { downloadPicletCard } from '$lib/services/picletExport';
7
  import { TYPE_DATA } from '$lib/types/picletTypes';
8
  import AbilityDisplay from './AbilityDisplay.svelte';
9
  import MoveDisplay from './MoveDisplay.svelte';
@@ -19,7 +18,6 @@
19
 
20
  let { instance, onClose, onDeleted }: Props = $props();
21
  let selectedTab = $state<'about' | 'abilities'>('about');
22
- let isSharing = $state(false);
23
 
24
  // Ensure stats are up-to-date with current level and nature
25
  const updatedInstance = $derived(recalculatePicletStats(instance));
@@ -70,16 +68,8 @@
70
  }
71
 
72
 
73
- async function handleShare() {
74
- isSharing = true;
75
- try {
76
- await downloadPicletCard(instance);
77
- } catch (err) {
78
- console.error('Failed to share piclet:', err);
79
- alert('Failed to create shareable image');
80
- } finally {
81
- isSharing = false;
82
- }
83
  }
84
  </script>
85
 
@@ -106,7 +96,6 @@
106
  <button
107
  class="share-button"
108
  onclick={handleShare}
109
- disabled={isSharing}
110
  aria-label="Share Piclet"
111
  >
112
  <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 
3
  import type { PicletInstance } from '$lib/db/schema';
4
  import { deletePicletInstance } from '$lib/db/piclets';
5
  import { uiStore } from '$lib/stores/ui';
 
6
  import { TYPE_DATA } from '$lib/types/picletTypes';
7
  import AbilityDisplay from './AbilityDisplay.svelte';
8
  import MoveDisplay from './MoveDisplay.svelte';
 
18
 
19
  let { instance, onClose, onDeleted }: Props = $props();
20
  let selectedTab = $state<'about' | 'abilities'>('about');
 
21
 
22
  // Ensure stats are up-to-date with current level and nature
23
  const updatedInstance = $derived(recalculatePicletStats(instance));
 
68
  }
69
 
70
 
71
+ function handleShare() {
72
+ console.log("placeholder");
 
 
 
 
 
 
 
 
73
  }
74
  </script>
75
 
 
96
  <button
97
  class="share-button"
98
  onclick={handleShare}
 
99
  aria-label="Share Piclet"
100
  >
101
  <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
src/lib/services/picletExport.ts DELETED
@@ -1,233 +0,0 @@
1
- import type { PicletInstance } from '$lib/db/schema';
2
- import { embedPicletMetadata } from './picletMetadata';
3
-
4
- /**
5
- * Generates a shareable image of a piclet with embedded metadata
6
- */
7
- export async function generateShareableImage(piclet: PicletInstance): Promise<Blob> {
8
- // Create canvas
9
- const canvas = document.createElement('canvas');
10
- const ctx = canvas.getContext('2d');
11
- if (!ctx) throw new Error('Could not create canvas context');
12
-
13
- // Polyfill for roundRect if not available
14
- if (!ctx.roundRect) {
15
- ctx.roundRect = function(x: number, y: number, width: number, height: number, radius: number) {
16
- ctx.beginPath();
17
- ctx.moveTo(x + radius, y);
18
- ctx.lineTo(x + width - radius, y);
19
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
20
- ctx.lineTo(x + width, y + height - radius);
21
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
22
- ctx.lineTo(x + radius, y + height);
23
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
24
- ctx.lineTo(x, y + radius);
25
- ctx.quadraticCurveTo(x, y, x + radius, y);
26
- ctx.closePath();
27
- };
28
- }
29
-
30
- // Set canvas size - full piclet size plus padding for name and stats
31
- const canvasWidth = 1024;
32
- const canvasHeight = 1400; // Extra height for name and stats
33
- canvas.width = canvasWidth;
34
- canvas.height = canvasHeight;
35
-
36
- // Fill with striped background like battle view
37
- ctx.fillStyle = '#f8f9fa';
38
- ctx.fillRect(0, 0, canvasWidth, canvasHeight);
39
-
40
- // Create striped pattern
41
- const stripeHeight = 10;
42
- ctx.fillStyle = 'rgba(76, 175, 80, 0.2)'; // Light green
43
- for (let y = 0; y < canvasHeight; y += stripeHeight * 2) {
44
- ctx.fillRect(0, y, canvasWidth, stripeHeight);
45
- }
46
-
47
- // Add alternating darker stripes
48
- ctx.fillStyle = 'rgba(76, 175, 80, 0.1)'; // Lighter green
49
- for (let y = stripeHeight; y < canvasHeight; y += stripeHeight * 2) {
50
- ctx.fillRect(0, y, canvasWidth, stripeHeight);
51
- }
52
-
53
- // Load piclet image first
54
- const picletImg = await loadImage(piclet.imageData || piclet.imageUrl);
55
- const picletSize = 1024; // Full size!
56
- const picletX = 0;
57
- const picletY = 150; // Leave room for name at top
58
-
59
- // Load and draw grass platform positioned under the piclet
60
- const grassImg = await loadImage('/assets/grass.PNG');
61
- const platformSize = 1200; // Larger than piclet for proper positioning
62
- const platformX = (canvasWidth - platformSize) / 2;
63
- const platformY = picletY + picletSize - 300 - 384; // Platform moved up by 384px
64
- ctx.drawImage(grassImg, platformX, platformY, platformSize, platformSize);
65
-
66
- // Draw piclet on top of platform
67
- ctx.drawImage(picletImg, picletX, picletY, picletSize, picletSize);
68
-
69
- // Add sleek modern text styling
70
- const nameText = piclet.nickname || piclet.typeId;
71
-
72
- // Create gradient for text
73
- const gradient = ctx.createLinearGradient(0, 50, 0, 120);
74
- gradient.addColorStop(0, '#ffffff');
75
- gradient.addColorStop(1, '#e0e0e0');
76
-
77
- // Modern sleek font with gradient and subtle shadow
78
- ctx.font = 'bold 72px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif';
79
- ctx.textAlign = 'center';
80
- ctx.textBaseline = 'middle';
81
-
82
- // Subtle shadow for depth
83
- ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
84
- ctx.shadowBlur = 15;
85
- ctx.shadowOffsetX = 0;
86
- ctx.shadowOffsetY = 3;
87
-
88
- // Dark outline for contrast
89
- ctx.strokeStyle = '#2c3e50';
90
- ctx.lineWidth = 4;
91
- ctx.strokeText(nameText.toUpperCase(), canvasWidth / 2, 80);
92
-
93
- // Fill with gradient
94
- ctx.fillStyle = gradient;
95
- ctx.fillText(nameText.toUpperCase(), canvasWidth / 2, 80);
96
-
97
- // Reset shadow
98
- ctx.shadowColor = 'transparent';
99
- ctx.shadowBlur = 0;
100
- ctx.shadowOffsetX = 0;
101
- ctx.shadowOffsetY = 0;
102
-
103
- // Draw base stats in a sleek format
104
- const statsY = picletY + picletSize + 50; // Position below piclet
105
- const stats = [
106
- { label: 'HP', value: piclet.baseHp, color: '#4caf50' },
107
- { label: 'ATK', value: piclet.baseAttack, color: '#f44336' },
108
- { label: 'DEF', value: piclet.baseDefense, color: '#2196f3' },
109
- { label: 'S.ATK', value: piclet.baseFieldAttack, color: '#ff9800' },
110
- { label: 'S.DEF', value: piclet.baseFieldDefense, color: '#9c27b0' },
111
- { label: 'SPD', value: piclet.baseSpeed, color: '#00bcd4' }
112
- ];
113
-
114
- // Stats container background
115
- const containerX = 100;
116
- const containerY = statsY - 20;
117
- const containerWidth = canvasWidth - 200;
118
- const containerHeight = 150;
119
-
120
- // Draw semi-transparent background using the polyfilled roundRect
121
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
122
- ctx.beginPath();
123
- (ctx as any).roundRect(containerX, containerY, containerWidth, containerHeight, 20);
124
- ctx.fill();
125
-
126
- // Draw stats bars
127
- const barHeight = 16;
128
- const barSpacing = 20;
129
- const maxStatValue = 255;
130
- const barMaxWidth = containerWidth - 240; // Leave room for labels and values
131
-
132
- stats.forEach((stat, index) => {
133
- const y = statsY + (index * barSpacing);
134
-
135
- // Draw stat label
136
- ctx.font = 'bold 14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif';
137
- ctx.fillStyle = '#ffffff';
138
- ctx.textAlign = 'left';
139
- ctx.fillText(stat.label, containerX + 20, y + 3);
140
-
141
- // Draw stat value
142
- ctx.textAlign = 'right';
143
- ctx.fillText(stat.value.toString(), containerX + 100, y + 3);
144
-
145
- // Draw background bar
146
- const barX = containerX + 120;
147
- ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
148
- ctx.beginPath();
149
- (ctx as any).roundRect(barX, y - 8, barMaxWidth, barHeight, 8);
150
- ctx.fill();
151
-
152
- // Draw filled bar
153
- const fillWidth = (stat.value / maxStatValue) * barMaxWidth;
154
- ctx.fillStyle = stat.color;
155
- ctx.beginPath();
156
- (ctx as any).roundRect(barX, y - 8, fillWidth, barHeight, 8);
157
- ctx.fill();
158
-
159
- // Add shine effect
160
- const shineGradient = ctx.createLinearGradient(barX, y - 8, barX, y - 8 + barHeight);
161
- shineGradient.addColorStop(0, 'rgba(255, 255, 255, 0.3)');
162
- shineGradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.1)');
163
- shineGradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
164
- ctx.fillStyle = shineGradient;
165
- ctx.beginPath();
166
- (ctx as any).roundRect(barX, y - 8, fillWidth, barHeight / 2, 8);
167
- ctx.fill();
168
- });
169
-
170
- // Draw BST (Base Stat Total)
171
- const bst = piclet.bst || (piclet.baseHp + piclet.baseAttack + piclet.baseDefense +
172
- piclet.baseFieldAttack + piclet.baseFieldDefense + piclet.baseSpeed);
173
- ctx.font = 'bold 18px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif';
174
- ctx.fillStyle = '#ffd700'; // Gold color
175
- ctx.textAlign = 'center';
176
- ctx.fillText(`BST: ${bst}`, canvasWidth / 2, containerY + containerHeight - 10);
177
-
178
- // Load and draw translucent watermark in top-right
179
- const logoImg = await loadImage('/assets/snap_logo.png');
180
- const logoSize = 120; // Slightly smaller for top placement
181
- ctx.globalAlpha = 0.3; // More translucent
182
- ctx.drawImage(logoImg, canvasWidth - logoSize - 30, 30, logoSize, logoSize);
183
- ctx.globalAlpha = 1.0;
184
-
185
- // Get the image as blob
186
- const blob = await canvasToBlob(canvas);
187
-
188
- // Embed metadata in the blob
189
- return embedPicletMetadata(blob, piclet);
190
- }
191
-
192
- /**
193
- * Downloads a piclet card image
194
- */
195
- export async function downloadPicletCard(piclet: PicletInstance, filename?: string): Promise<void> {
196
- const blob = await generateShareableImage(piclet);
197
- const url = URL.createObjectURL(blob);
198
-
199
- const a = document.createElement('a');
200
- a.href = url;
201
- a.download = filename || `Piclet_${piclet.nickname || piclet.typeId}_Lv${piclet.level}.png`;
202
- document.body.appendChild(a);
203
- a.click();
204
- document.body.removeChild(a);
205
-
206
- URL.revokeObjectURL(url);
207
- }
208
-
209
- /**
210
- * Helper to load an image
211
- */
212
- function loadImage(src: string): Promise<HTMLImageElement> {
213
- return new Promise((resolve, reject) => {
214
- const img = new Image();
215
- img.crossOrigin = 'anonymous';
216
- img.onload = () => resolve(img);
217
- img.onerror = reject;
218
- img.src = src;
219
- });
220
- }
221
-
222
- /**
223
- * Convert canvas to blob
224
- */
225
- function canvasToBlob(canvas: HTMLCanvasElement): Promise<Blob> {
226
- return new Promise((resolve, reject) => {
227
- canvas.toBlob((blob) => {
228
- if (blob) resolve(blob);
229
- else reject(new Error('Failed to create blob'));
230
- }, 'image/png');
231
- });
232
- }
233
-