Skip to content

Commit

Permalink
Add "leading sponsor" setup to sponsors display, fixes #44 (#275)
Browse files Browse the repository at this point in the history
Co-authored-by: Bernardo Martinez <[email protected]>
Co-authored-by: Stanislav Zhuk <[email protected]>
  • Loading branch information
3 people authored Nov 12, 2024
1 parent 1676416 commit af9c9e1
Show file tree
Hide file tree
Showing 4 changed files with 316 additions and 180 deletions.
81 changes: 54 additions & 27 deletions src/components/FeaturedSponsors.astro
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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]
}
})
---

<div class="relative">
<div class="relative flex flex-col items-center space-y-12">
{/* Lead Sponsors Section */}
{leadSponsors.length > 0 && (
<div class="w-full flex justify-center pb-8 border-b border-gray-200 dark:border-white">
{leadSponsors.map((sponsor) => (
<a
class="block relative overflow-hidden cursor-pointer h-16 mx-6"
title={sponsor.name}
href={sponsor.url}
target="_blank"
>
<picture>
<source
srcset={sponsor.darklogo}
media="(prefers-color-scheme: dark)">
<img
src={sponsor.logo}
class="block w-auto h-full"
alt={`${sponsor.name} logo`}
/>
</picture>
</a>
))}
</div>
)}

{/* Regular Sponsors Section */}
<div
class={`flex flex-wrap space-y-12 -mt-12 justify-center items-center content-center`}
class="flex flex-wrap gap-y-12 justify-center items-center"
>
{
featuredSponsors.map((sponsor) => (
{regularSponsors.map((sponsor) => (
<a
class={
`block relative overflow-hidden cursor-pointer h-12 mx-6` +
(sponsor.hasOwnProperty("class") ? ` ` + sponsor.class : ``)
}
title={sponsor.name}
href={sponsor.url}
target="_blank"
class={
`block relative overflow-hidden cursor-pointer h-12 mx-6` +
(sponsor.hasOwnProperty("class") ? ` ` + sponsor.class : ``)
}
title={sponsor.name}
href={sponsor.url}
target="_blank"
>
<picture>
<source
srcset={sponsor.darklogo}
media="(prefers-color-scheme: dark)">
<img
src={sponsor.logo}
class="block w-auto h-full"
alt={`${sponsor.name} logo`}
/>
</picture>
<picture>
<source
srcset={sponsor.darklogo}
media="(prefers-color-scheme: dark)">
<img
src={sponsor.logo}
class="block w-auto h-full"
alt={`${sponsor.name} logo`}
/>
</picture>
</a>
))
}
))}
</div>
</div>
</div>
9 changes: 6 additions & 3 deletions src/featured-sponsors.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
"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",
"type": "major",
"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",
Expand All @@ -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",
Expand Down
207 changes: 130 additions & 77 deletions src/pages/resources/featured-sponsors-darkmode.svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = `
<svg
width="${overallWidth}"
Expand All @@ -65,69 +139,48 @@ const buildResponse = () => {
>
`

images.map((image) => {
images.forEach((image) => {
response += `
<a xlink:href="${image.url}" target="_blank">
<image href="${imgToBase64(image.path)}" x="${image.x}" y="${image.y}" height="${image.height}" width="${image.width}" />
<image
href="${imgToBase64(image.path)}"
x="${image.x}"
y="${image.y}"
height="${image.height}"
width="${image.width}"
/>
</a>
`
})

response += `</svg>`

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())
}
}
Loading

0 comments on commit af9c9e1

Please sign in to comment.