diff --git a/src/components/FeaturedSponsors.astro b/src/components/FeaturedSponsors.astro index 157f2037..4daca6e3 100644 --- a/src/components/FeaturedSponsors.astro +++ b/src/components/FeaturedSponsors.astro @@ -7,8 +7,7 @@ import featuredSponsors from "../featured-sponsors.json" * you need to add one. */ const nudges = { - "Platform.sh": "mt-12 h-11", - Tag1: "h-9", + Tag1: "h-9 self-center", // Added self-center to align it vertically "Oliver Wand": "h-12 w-12", DrupalEasy: "h-10", "Redfin Solutions": "h-16 w-16", @@ -19,41 +18,69 @@ const nudges = { "1xINTERNET": "h-11", } +// Separate lead sponsors from regular sponsors +const leadSponsors = featuredSponsors.filter(sponsor => sponsor.isLeading === true) +const regularSponsors = featuredSponsors.filter(sponsor => sponsor.isLeading !== true) + // Add class property to relevant sponsor objects -featuredSponsors.map((sponsor) => { +regularSponsors.map((sponsor) => { if (sponsor.name in nudges) { sponsor.class = nudges[sponsor.name] } }) --- -
+
+ {/* Lead Sponsors Section */} + {leadSponsors.length > 0 && ( +
+ {leadSponsors.map((sponsor) => ( + + + + {`${sponsor.name} + + + ))} +
+ )} + + {/* Regular Sponsors Section */}
- { - featuredSponsors.map((sponsor) => ( + {regularSponsors.map((sponsor) => ( - - - {`${sponsor.name} - + + + {`${sponsor.name} + - )) - } + ))}
-
+
\ No newline at end of file diff --git a/src/featured-sponsors.json b/src/featured-sponsors.json index 7d2589d3..f4f6c2ac 100644 --- a/src/featured-sponsors.json +++ b/src/featured-sponsors.json @@ -5,7 +5,8 @@ "logo": "/logos/platform.sh.svg", "darklogo": "/logos/platform.sh-darkmode.svg", "squareLogo": "/logos/platform.sh-square.svg", - "url": "https://platform.sh" + "url": "https://platform.sh", + "isLeading": true }, { "name": "Tag1", @@ -13,7 +14,8 @@ "logo": "/logos/tag1.svg", "darklogo": "/logos/dark-tag1.svg", "squareLogo": "/logos/tag1-square.svg", - "url": "https://tag1.com" + "url": "https://tag1.com", + "isLeading": false }, { "name": "i-gelb", @@ -22,7 +24,8 @@ "darklogo": "/logos/dark-i-gelb.svg", "squareLogo": "/logos/i-gelb-square.svg", "url": "https://i-gelb.net", - "github": "i-gelb" + "github": "i-gelb", + "isLeading": false }, { "name": "Open Strategy Partners", diff --git a/src/pages/resources/featured-sponsors-darkmode.svg.js b/src/pages/resources/featured-sponsors-darkmode.svg.js index c6a90170..67bfc425 100644 --- a/src/pages/resources/featured-sponsors-darkmode.svg.js +++ b/src/pages/resources/featured-sponsors-darkmode.svg.js @@ -7,54 +7,128 @@ const baseUrl = import.meta.env.SITE // Width of the composed SVG const overallWidth = 814 -// Maximum height a darklogo may have +// Maximum height a logo may have const maxHeight = 50 -// Maximum width a darklogo may have +// Lead sponsor height (doubled from regular sponsors) +const leadSponsorHeight = maxHeight * 2 +// Maximum width a logo may have const maxWidth = 200 -// Horizontal padding between darklogos +// Lead sponsor maximum width (doubled from regular sponsors) +const leadSponsorMaxWidth = maxWidth * 2 +// Horizontal padding between logos const xPadding = 40 -// Vertical padding between rows of darklogos +// Vertical padding between rows of logos const yPadding = 20 +// Additional padding below lead sponsors +const leadSponsorBottomPadding = 80 -/** - * Build an SVG response body with rows of evenly-spaced sponsor darklogos wrapped in anchors. - * @returns string - */ const buildResponse = () => { let images = [] - let totalHeight = 0 - let currentX = 0 - let currentY = 0 - let rowCount = 1 - - featuredSponsors.map((sponsor, index) => { - const dimensions = sizeOf("./public/" + sponsor.darklogo) + let currentY = 30 + + // First process lead sponsors + const leadSponsors = featuredSponsors.filter(sponsor => sponsor.isLeading === true) + const regularSponsors = featuredSponsors.filter(sponsor => sponsor.isLeading !== true) + + console.log("Processing lead sponsors") + + // Handle lead sponsors (centered, own row) + if (leadSponsors.length > 0) { + // Get dimensions for lead sponsors + const leadSponsorInfo = leadSponsors.map(sponsor => { + // Ensure we have a valid logo path + const logoPath = sponsor.darklogo ? `./public${sponsor.darklogo}` : null + if (!logoPath) { + console.error(`Missing logo path for sponsor: ${sponsor.name}`) + return null + } + + try { + const dimensions = sizeOf(logoPath) + const [width, height] = getScaledImageDimensions( + dimensions.width, + dimensions.height, + true + ) + return { sponsor, width, height, logoPath } + } catch (error) { + console.error(`Error processing logo for ${sponsor.name}:`, error) + return null + } + }).filter(Boolean) // Remove any null entries + + // Calculate total width including padding between lead sponsors + const totalLeadWidth = leadSponsorInfo.reduce((sum, info, index) => { + return sum + info.width + (index < leadSponsors.length - 1 ? xPadding : 0) + }, 0) + + // Center the lead sponsors + let startX = (overallWidth - totalLeadWidth) / 2 + + // Place lead sponsors + leadSponsorInfo.forEach(({ sponsor, width, height, logoPath }) => { + images.push({ + href: baseUrl + sponsor.darklogo, + path: logoPath, + x: startX, + y: currentY + (leadSponsorHeight - height) / 2, + height, + width, + url: sponsor.url, + isLead: true + }) + + startX += width + xPadding + }) - let [w, h] = getScaledImageDimensions(dimensions.width, dimensions.height) + currentY += leadSponsorHeight + leadSponsorBottomPadding + } - if (currentX + w + xPadding > overallWidth) { - currentX = 0 - currentY += maxHeight + yPadding - rowCount += 1 + // Now process regular sponsors + let currentX = 0 + regularSponsors.forEach((sponsor) => { + // Ensure we have a valid logo path + const logoPath = sponsor.darklogo ? `./public${sponsor.darklogo}` : null + if (!logoPath) { + console.error(`Missing logo path for sponsor: ${sponsor.name}`) + return } - let yOffset = (maxHeight - h) / 2 - - images.push({ - href: baseUrl + sponsor.darklogo, - path: `./public/${sponsor.darklogo}`, - x: currentX, - y: currentY + yOffset, - height: h, - width: w, - url: sponsor.url, - }) - - currentX += w + xPadding + try { + const dimensions = sizeOf(logoPath) + let [width, height] = getScaledImageDimensions( + dimensions.width, + dimensions.height, + false + ) + + // Start new row if needed + if (currentX + width > overallWidth) { + currentX = 0 + currentY += maxHeight + yPadding + } + + images.push({ + href: baseUrl + sponsor.darklogo, + path: logoPath, + x: currentX, + y: currentY + (maxHeight - height) / 2, + height, + width, + url: sponsor.url, + isLead: false + }) + + currentX += width + xPadding + } catch (error) { + console.error(`Error processing logo for ${sponsor.name}:`, error) + } }) - totalHeight = (maxHeight + yPadding) * rowCount + // Calculate total height needed + const totalHeight = currentY + maxHeight + yPadding + // Generate SVG let response = ` { > ` - images.map((image) => { + images.forEach((image) => { response += ` - + ` }) response += `` - - return response; + return response } function imgToBase64(filePath) { - let extname = path.extname(filePath).slice(1) || 'png'; - + let extname = path.extname(filePath).slice(1) || 'png' if (extname === 'svg') { extname = "svg+xml" } - - return 'data:image/' + extname + ';base64,' + fs.readFileSync(filePath).toString('base64'); + return 'data:image/' + extname + ';base64,' + fs.readFileSync(filePath).toString('base64') } -/** - * Take the original width and height of an image and proportionally scale it - * for optical balance in this layout. - * @param {*} width - * @param {*} height - * @returns [w, h] - */ -const getScaledImageDimensions = (width, height) => { - let h = height - let w = width - const ratio = w / h - - if (ratio < 1) { - h = maxHeight - w = (maxHeight / height) * width - } +const getScaledImageDimensions = (width, height, isLeadSponsor = false) => { + const ratio = width / height + const maxH = isLeadSponsor ? leadSponsorHeight : maxHeight + const maxW = isLeadSponsor ? leadSponsorMaxWidth : maxWidth - if (ratio === 1) { - h = maxHeight - w = maxHeight - } + let h = maxH + let w = (maxH / height) * width - if (ratio > 1) { - h = maxHeight - w = (maxHeight / height) * width + if (w > maxW) { + w = maxW + h = (maxW / width) * height } - if (ratio > 2) { - h = maxHeight * 0.75 - w = ((maxHeight * 0.75) / height) * width - } - - if (ratio > 3) { - w = maxWidth - h = (maxWidth / width) * height - } - - return [w, h]; + return [w, h] } export async function GET({ params, request }) { return new Response(buildResponse()) -} +} \ No newline at end of file diff --git a/src/pages/resources/featured-sponsors.svg.js b/src/pages/resources/featured-sponsors.svg.js index 5c64c248..c1ea6e0c 100644 --- a/src/pages/resources/featured-sponsors.svg.js +++ b/src/pages/resources/featured-sponsors.svg.js @@ -9,52 +9,126 @@ const baseUrl = import.meta.env.SITE const overallWidth = 814 // Maximum height a logo may have const maxHeight = 50 +// Lead sponsor height (doubled from regular sponsors) +const leadSponsorHeight = maxHeight * 2 // Maximum width a logo may have const maxWidth = 200 +// Lead sponsor maximum width (doubled from regular sponsors) +const leadSponsorMaxWidth = maxWidth * 2 // Horizontal padding between logos const xPadding = 40 // Vertical padding between rows of logos const yPadding = 20 +// Additional padding below lead sponsors +const leadSponsorBottomPadding = 80 -/** - * Build an SVG response body with rows of evenly-spaced sponsor logos wrapped in anchors. - * @returns string - */ const buildResponse = () => { let images = [] - let totalHeight = 0 - let currentX = 0 - let currentY = 0 - let rowCount = 1 - - featuredSponsors.map((sponsor, index) => { - const dimensions = sizeOf("./public/" + sponsor.logo) + let currentY = 30 + + // First process lead sponsors + const leadSponsors = featuredSponsors.filter(sponsor => sponsor.isLeading === true) + const regularSponsors = featuredSponsors.filter(sponsor => sponsor.isLeading !== true) + + console.log("Processing lead sponsors") + + // Handle lead sponsors (centered, own row) + if (leadSponsors.length > 0) { + // Get dimensions for lead sponsors + const leadSponsorInfo = leadSponsors.map(sponsor => { + // Ensure we have a valid logo path + const logoPath = sponsor.logo ? `./public${sponsor.logo}` : null + if (!logoPath) { + console.error(`Missing logo path for sponsor: ${sponsor.name}`) + return null + } + + try { + const dimensions = sizeOf(logoPath) + const [width, height] = getScaledImageDimensions( + dimensions.width, + dimensions.height, + true + ) + return { sponsor, width, height, logoPath } + } catch (error) { + console.error(`Error processing logo for ${sponsor.name}:`, error) + return null + } + }).filter(Boolean) // Remove any null entries + + // Calculate total width including padding between lead sponsors + const totalLeadWidth = leadSponsorInfo.reduce((sum, info, index) => { + return sum + info.width + (index < leadSponsors.length - 1 ? xPadding : 0) + }, 0) + + // Center the lead sponsors + let startX = (overallWidth - totalLeadWidth) / 2 + + // Place lead sponsors + leadSponsorInfo.forEach(({ sponsor, width, height, logoPath }) => { + images.push({ + href: baseUrl + sponsor.logo, + path: logoPath, + x: startX, + y: currentY + (leadSponsorHeight - height) / 2, + height, + width, + url: sponsor.url, + isLead: true + }) + + startX += width + xPadding + }) - let [w, h] = getScaledImageDimensions(dimensions.width, dimensions.height) + currentY += leadSponsorHeight + leadSponsorBottomPadding + } - if (currentX + w + xPadding > overallWidth) { - currentX = 0 - currentY += maxHeight + yPadding - rowCount += 1 + // Now process regular sponsors + let currentX = 0 + regularSponsors.forEach((sponsor) => { + // Ensure we have a valid logo path + const logoPath = sponsor.logo ? `./public${sponsor.logo}` : null + if (!logoPath) { + console.error(`Missing logo path for sponsor: ${sponsor.name}`) + return } - let yOffset = (maxHeight - h) / 2 - - images.push({ - href: baseUrl + sponsor.logo, - path: `./public/${sponsor.logo}`, - x: currentX, - y: currentY + yOffset, - height: h, - width: w, - url: sponsor.url, - }) - - currentX += w + xPadding + try { + const dimensions = sizeOf(logoPath) + let [width, height] = getScaledImageDimensions( + dimensions.width, + dimensions.height, + false + ) + + // Start new row if needed + if (currentX + width > overallWidth) { + currentX = 0 + currentY += maxHeight + yPadding + } + + images.push({ + href: baseUrl + sponsor.logo, + path: logoPath, + x: currentX, + y: currentY + (maxHeight - height) / 2, + height, + width, + url: sponsor.url, + isLead: false + }) + + currentX += width + xPadding + } catch (error) { + console.error(`Error processing logo for ${sponsor.name}:`, error) + } }) - totalHeight = (maxHeight + yPadding) * rowCount + // Calculate total height needed + const totalHeight = currentY + maxHeight + yPadding + // Generate SVG let response = ` { > ` - images.map((image) => { + images.forEach((image) => { response += ` - + ` }) response += `` - - return response; + return response } function imgToBase64(filePath) { - let extname = path.extname(filePath).slice(1) || 'png'; - + let extname = path.extname(filePath).slice(1) || 'png' if (extname === 'svg') { extname = "svg+xml" } - - return 'data:image/' + extname + ';base64,' + fs.readFileSync(filePath).toString('base64'); + return 'data:image/' + extname + ';base64,' + fs.readFileSync(filePath).toString('base64') } -/** - * Take the original width and height of an image and proportionally scale it - * for optical balance in this layout. - * @param {*} width - * @param {*} height - * @returns [w, h] - */ -const getScaledImageDimensions = (width, height) => { - let h = height - let w = width - const ratio = w / h - - if (ratio < 1) { - h = maxHeight - w = (maxHeight / height) * width - } +const getScaledImageDimensions = (width, height, isLeadSponsor = false) => { + const ratio = width / height + const maxH = isLeadSponsor ? leadSponsorHeight : maxHeight + const maxW = isLeadSponsor ? leadSponsorMaxWidth : maxWidth - if (ratio === 1) { - h = maxHeight - w = maxHeight - } + let h = maxH + let w = (maxH / height) * width - if (ratio > 1) { - h = maxHeight - w = (maxHeight / height) * width + if (w > maxW) { + w = maxW + h = (maxW / width) * height } - if (ratio > 2) { - h = maxHeight * 0.75 - w = ((maxHeight * 0.75) / height) * width - } - - if (ratio > 3) { - w = maxWidth - h = (maxWidth / width) * height - } - - return [w, h]; + return [w, h] } export async function GET({ params, request }) { return new Response(buildResponse()) -} +} \ No newline at end of file