Skip to content

Commit 70a90a8

Browse files
authored
Draft design of sponsor social card. (#1241)
![Screen Shot 2025-05-17 at 17 05 25](https://github.com/user-attachments/assets/e076d7b3-cf57-4f1e-82a0-d365cff14129) Close #1216.
1 parent 7e4c360 commit 70a90a8

File tree

11 files changed

+332
-81
lines changed

11 files changed

+332
-81
lines changed

astro.config.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ export default defineConfig({
9090
metaTags(),
9191
pagefind(),
9292
deleteUnusedImages(),
93-
compress(),
93+
(await import("astro-compress")).default({
94+
SVG: false,
95+
}),
9496
],
9597
output: "static",
9698
build: {

public/social/bg2.png

45.4 KB
Loading

public/social/bg3.png

591 KB
Loading

public/social/bg4.png

423 KB
Loading

scripts/download_social.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const puppeteer = require("puppeteer");
66
args: ["--no-sandbox", "--disable-setuid-sandbox"],
77
});
88
const page = await browser.newPage();
9-
await page.goto("http://localhost:4321/media/social_media_cards");
9+
await page.goto("http://localhost:4321/media/speakers");
1010

1111
const elements = await page.$$(".social");
1212

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
import { getEntry } from "astro:content";
3+
import { sponsorLogos } from "@data/sponsorLogos";
4+
5+
const { sponsor } = Astro.props;
6+
7+
const {
8+
name: title,
9+
url: website,
10+
logo_padding = false,
11+
} = sponsor.data;
12+
13+
14+
const logo = sponsorLogos[sponsor.id];
15+
// Assuming logo.width and logo.height are known
16+
const targetWidth = 400;
17+
const originalWidth = logo.width;
18+
const originalHeight = logo.height;
19+
const aspectRatio = originalWidth / originalHeight;
20+
21+
let width = targetWidth;
22+
let height = width / aspectRatio;
23+
24+
const maxHeight = 220;
25+
if (height > maxHeight) {
26+
height = maxHeight;
27+
width = height * aspectRatio ;
28+
}
29+
30+
const x = 450 - width / 2;
31+
const y = 650 - height / 2;
32+
33+
---
34+
<svg width="900" height="900" class="h-full w-full -z-10">
35+
<image href="/social/bg4.png" width="900" height="900" />
36+
</svg>
37+
<svg width="900" height="900">
38+
39+
<image
40+
class="sponsor_logo"
41+
href={logo.src}
42+
x={x}
43+
y={y}
44+
width={width}
45+
height={height}
46+
style={{
47+
padding: logo_padding ? logo_padding : undefined,
48+
}}
49+
clip-path="url(#curvedCornerClip)"
50+
preserveAspectRatio="xMidYMid meet"
51+
/>
52+
</svg>
53+
54+
<p lang="en" class="box2 fit-text">
55+
{title}
56+
</p>
57+
58+
59+
<style>
60+
.box {
61+
margin-top:250px;
62+
width: 630px;
63+
height: 150px;
64+
font-size: 100px;
65+
color: rgb(239, 215, 123);
66+
padding: 1rem;
67+
opacity: 0;
68+
}
69+
70+
.box2 {
71+
margin-top:320px;
72+
margin-left:150px;
73+
width: 640px;
74+
height: 180px;
75+
font-size: 70px;
76+
color:white;
77+
padding: 2rem;
78+
}
79+
80+
.box3 {
81+
margin-top:280px;
82+
width: 800px;
83+
height: 300px;
84+
font-size: 100px;
85+
color: rgb(239, 215, 123);
86+
padding: 1rem;
87+
}
88+
89+
.box4 {
90+
91+
width: 580px;
92+
height: 200px;
93+
font-size: 70px;
94+
color:white;
95+
padding: 2rem;
96+
}
97+
98+
99+
.box, .box2, .box3, .box4 {
100+
box-sizing: border-box;
101+
overflow: hidden;
102+
display: flex;
103+
align-items: center;
104+
justify-content: center;
105+
text-align: center;
106+
font-family: Inter, sans-serif !important;
107+
font-weight: bold;
108+
line-height: 1em;
109+
}
110+
111+
.sponsor_logo {
112+
max-height:120px;
113+
}
114+
</style>

src/pages/media/social_media.csv.ts

Lines changed: 0 additions & 78 deletions
This file was deleted.

src/pages/media/social_media_cards.astro renamed to src/pages/media/speakers.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type Speaker = CollectionEntry<"speakers">;
2020
<body class="overflow-auto">
2121
{
2222
speakers.map((entry: Speaker) => (
23-
<a href=`/media/card/${entry.data.slug}`>
23+
<a href=`/media/speaker/${entry.data.slug}`>
2424
<div class="social relative w-[900px] h-[900px] overflow-hidden" data-slug={entry.data.slug}>
2525
<SocialMediaCard entry={entry} />
2626
</div>

src/pages/media/sponsor/[slug].astro

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
import { getEntry, getCollection} from "astro:content";
3+
import SocialMediaSponsorCard from "@components/SocialMediaSponsorCard.astro";
4+
5+
export async function getStaticPaths() {
6+
const entries = await getCollection("sponsors");
7+
return entries.map((entry) => ({
8+
params: { slug: entry.id},
9+
props: { entry },
10+
}));
11+
}
12+
13+
const { entry:sponsor } = Astro.props;
14+
15+
---
16+
<!DOCTYPE html>
17+
<html lang="en">
18+
<head>
19+
<meta charset="utf-8" />
20+
<meta name="viewport" content="width=device-width,initial-scale=1" />
21+
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
22+
<link rel="preconnect" href="https://fonts.googleapis.com">
23+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
24+
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
25+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js"></script>
26+
</head>
27+
<body class="overflow-auto">
28+
{
29+
sponsor &&
30+
<div class="social relative w-[900px] h-[900px] overflow-hidden">
31+
<SocialMediaSponsorCard {sponsor} />
32+
</div>
33+
}
34+
35+
</body>
36+
</html>
37+
38+
<style is:global>
39+
40+
.social {
41+
width: 900px;
42+
height: 900px;
43+
}
44+
45+
.social svg {
46+
position: absolute;
47+
top:0;
48+
left:0;
49+
width: 100%;
50+
height: 100%;
51+
object-fit: contain;
52+
}
53+
54+
body * {
55+
font-family: Inter, sans-serif;
56+
}
57+
58+
.avatar {
59+
object-position:50% 25%;
60+
}
61+
62+
</style>
63+
64+
<script is:inline>
65+
function fitText(container) {
66+
let fontSize = 100; // Start big
67+
container.style.fontSize = fontSize + 'px';
68+
69+
while (
70+
(container.scrollWidth > container.clientWidth || container.scrollHeight > container.clientHeight)
71+
&& fontSize > 5
72+
) {
73+
fontSize -= 1;
74+
container.style.fontSize = fontSize + 'px';
75+
}
76+
}
77+
78+
function fitAllText() {
79+
const boxes = document.querySelectorAll('.fit-text');
80+
boxes.forEach(box => fitText(box));
81+
}
82+
83+
fitAllText();
84+
85+
window.addEventListener('resize', fitAllText);
86+
</script>
87+
88+
<script is:inline define:vars={{slug: sponsor.id}}>
89+
document.addEventListener('DOMContentLoaded', () => {
90+
document.querySelectorAll('.social').forEach((socialDiv, index) => {
91+
92+
socialDiv.addEventListener('click', () => {
93+
const svgs = socialDiv.querySelectorAll('svg');
94+
95+
if (svgs.length === 0) {
96+
alert('No SVGs found!');
97+
return;
98+
}
99+
100+
const xmlns = "http://www.w3.org/2000/svg";
101+
const combinedSvg = document.createElementNS(xmlns, "svg");
102+
combinedSvg.setAttribute("xmlns", xmlns);
103+
combinedSvg.setAttribute("width", "900");
104+
combinedSvg.setAttribute("height", "900");
105+
combinedSvg.setAttribute("viewBox", "0 0 900 900");
106+
107+
svgs.forEach(svg => {
108+
const g = document.createElementNS(xmlns, "g");
109+
g.innerHTML = svg.innerHTML;
110+
combinedSvg.appendChild(g);
111+
});
112+
113+
const serializer = new XMLSerializer();
114+
const svgString = serializer.serializeToString(combinedSvg);
115+
116+
const blob = new Blob([svgString], {type: "image/svg+xml"});
117+
const url = URL.createObjectURL(blob);
118+
119+
const a = document.createElement('a');
120+
a.href = url;
121+
a.download = slug ? `social-${slug}.svg` : `social-${index +1}.svg`;
122+
a.style.display = "none";
123+
document.body.appendChild(a);
124+
a.click();
125+
126+
URL.revokeObjectURL(url);
127+
document.body.removeChild(a);
128+
});
129+
});
130+
});
131+
</script>

0 commit comments

Comments
 (0)