diff --git a/src/routes/embed/pets.js/+server.ts b/src/routes/embed/pets.js/+server.ts new file mode 100644 index 0000000..3d86f9a --- /dev/null +++ b/src/routes/embed/pets.js/+server.ts @@ -0,0 +1,104 @@ +import type { RequestHandler } from './$types'; +import { db } from '$lib/server/db'; +import { pets, petPhotos } from '$lib/server/schema'; +import { eq, and } from 'drizzle-orm'; + +export const GET: RequestHandler = async ({ url }) => { + // Fetch available pets with primary photos + const rows = await db + .select({ + id: pets.id, + name: pets.name, + slug: pets.slug, + breed: pets.breed, + age: pets.age, + sex: pets.sex, + species: pets.species, + photoUrl: petPhotos.url + }) + .from(pets) + .leftJoin(petPhotos, and(eq(petPhotos.petId, pets.id), eq(petPhotos.isPrimary, true))) + .where(and(eq(pets.status, 'available'), eq(pets.published, true))) + .limit(20); + + const petsJson = JSON.stringify(rows); + const siteUrl = process.env.PUBLIC_SITE_URL || url.origin; + + const js = ` +(function() { + var container = document.getElementById('fosterflow-pets'); + if (!container) { console.warn('FosterFlow: #fosterflow-pets not found'); return; } + + var limit = parseInt(container.dataset.limit || '12'); + var species = container.dataset.species || ''; + var columns = parseInt(container.dataset.columns || '3'); + var theme = container.dataset.theme || 'light'; + + var pets = ${petsJson}; + if (species) pets = pets.filter(function(p) { return p.species === species; }); + pets = pets.slice(0, limit); + + var shadow = container.attachShadow({ mode: 'open' }); + + var style = document.createElement('style'); + style.textContent = \` + :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } + .ff-grid { display: grid; grid-template-columns: repeat(\${columns}, 1fr); gap: 16px; } + @media (max-width: 768px) { .ff-grid { grid-template-columns: repeat(2, 1fr); } } + @media (max-width: 480px) { .ff-grid { grid-template-columns: 1fr; } } + .ff-card { border-radius: 12px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); transition: box-shadow 0.2s; background: \${theme === 'dark' ? '#1f2937' : '#fff'}; } + .ff-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.15); } + .ff-card a { text-decoration: none; color: inherit; display: block; } + .ff-img { aspect-ratio: 4/3; background: \${theme === 'dark' ? '#374151' : '#f3f4f6'}; overflow: hidden; display: flex; align-items: center; justify-content: center; } + .ff-img img { width: 100%; height: 100%; object-fit: cover; } + .ff-img .ff-placeholder { font-size: 2rem; } + .ff-info { padding: 12px; } + .ff-name { font-weight: 700; font-size: 1rem; color: \${theme === 'dark' ? '#f9fafb' : '#111827'}; margin: 0 0 4px; } + .ff-meta { font-size: 0.8rem; color: \${theme === 'dark' ? '#9ca3af' : '#6b7280'}; margin: 0; } + .ff-footer { text-align: center; padding: 12px; font-size: 0.75rem; color: #9ca3af; } + .ff-footer a { color: #0d9488; text-decoration: none; } + .ff-empty { text-align: center; padding: 24px; color: #9ca3af; } + \`; + shadow.appendChild(style); + + var wrapper = document.createElement('div'); + + if (pets.length === 0) { + wrapper.innerHTML = '
No pets available at the moment.
'; + } else { + var grid = document.createElement('div'); + grid.className = 'ff-grid'; + pets.forEach(function(pet) { + var card = document.createElement('div'); + card.className = 'ff-card'; + var photoHtml = pet.photoUrl + ? '' + pet.name + '' + : '🐾'; + card.innerHTML = '' + + '
' + photoHtml + '
' + + '
' + + '

' + pet.name + '

' + + '

' + (pet.breed || pet.species) + (pet.age ? ' · ' + pet.age : '') + ' · ' + pet.sex + '

' + + '
'; + grid.appendChild(card); + }); + wrapper.appendChild(grid); + } + + var footer = document.createElement('div'); + footer.className = 'ff-footer'; + footer.innerHTML = 'Powered by FosterFlow'; + wrapper.appendChild(footer); + + shadow.appendChild(wrapper); +})(); +`; + + return new Response(js, { + headers: { + 'Content-Type': 'application/javascript', + 'Cache-Control': 'public, max-age=300', + 'Access-Control-Allow-Origin': '*' + } + }); +};