Skip to content

Commit 36634bb

Browse files
committed
refactor(apps): split github thumbnail themes into separate files
1 parent 64c9f04 commit 36634bb

File tree

19 files changed

+1477
-1415
lines changed

19 files changed

+1477
-1415
lines changed

src/pages/apps/github-thumbnail/themes.js

Lines changed: 35 additions & 1415 deletions
Large diffs are not rendered by default.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { wrapText } from '../utils';
2+
3+
export const bauhaus = (ctx, width, height, scale, data) => {
4+
const { repoOwner, repoName, description, language, stars } = data;
5+
// BAUHAUS_GEO
6+
ctx.fillStyle = '#f0f0f0';
7+
ctx.fillRect(0, 0, width, height);
8+
9+
// Geometric Composition
10+
ctx.fillStyle = '#D93025'; // Red
11+
ctx.beginPath();
12+
ctx.arc(width * 0.2, height * 0.3, 150 * scale, 0, Math.PI * 2);
13+
ctx.fill();
14+
15+
ctx.fillStyle = '#F4B400'; // Yellow
16+
ctx.fillRect(width * 0.6, height * 0.1, 400 * scale, 200 * scale);
17+
18+
ctx.fillStyle = '#1A73E8'; // Blue
19+
ctx.beginPath();
20+
ctx.moveTo(width * 0.8, height);
21+
ctx.lineTo(width, height * 0.6);
22+
ctx.lineTo(width, height);
23+
ctx.fill();
24+
25+
// Diagonal Black Bar
26+
ctx.fillStyle = '#000';
27+
ctx.save();
28+
ctx.translate(width/2, height/2);
29+
ctx.rotate(-Math.PI / 12);
30+
ctx.fillRect(-width, 0, width*2, 20 * scale);
31+
ctx.restore();
32+
33+
const font = '"Futura", "Helvetica Neue", "Arial", sans-serif';
34+
35+
// Typography
36+
ctx.fillStyle = '#000';
37+
ctx.textAlign = 'left';
38+
ctx.font = `900 ${120 * scale}px ${font}`;
39+
ctx.fillText(repoName, 60 * scale, height * 0.65);
40+
41+
ctx.font = `bold ${40 * scale}px ${font}`;
42+
ctx.fillText(repoOwner.toUpperCase(), 60 * scale, height * 0.5);
43+
44+
// Description in a block
45+
ctx.fillStyle = '#333';
46+
ctx.font = `normal ${30 * scale}px ${font}`;
47+
wrapText(ctx, description, 60 * scale, height * 0.75, width * 0.6, 40 * scale);
48+
49+
// Side stats vertical
50+
ctx.save();
51+
ctx.translate(width - 60 * scale, 60 * scale);
52+
ctx.rotate(Math.PI / 2);
53+
ctx.textAlign = 'left';
54+
ctx.font = `bold ${24 * scale}px ${font}`;
55+
ctx.fillText(`${language.toUpperCase()} // STARS: ${stars || 0}`, 0, 0);
56+
ctx.restore();
57+
};
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { wrapText } from '../utils';
2+
3+
export const blueprint = (ctx, width, height, scale, data) => {
4+
const { repoOwner, repoName, description, stars, supportUrl } = data;
5+
// Improved Blueprint CAD Style
6+
const blueBg = '#004ecb'; // Deeper, more authentic blueprint blue
7+
ctx.fillStyle = blueBg;
8+
ctx.fillRect(0, 0, width, height);
9+
10+
const padding = 60 * scale;
11+
12+
// Grid (Subtle)
13+
ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';
14+
ctx.lineWidth = 1 * scale;
15+
const gridSize = 40 * scale;
16+
17+
ctx.beginPath();
18+
for (let x = 0; x < width; x += gridSize) ctx.rect(x, 0, 1, height);
19+
for (let y = 0; y < height; y += gridSize) ctx.rect(0, y, width, 1);
20+
ctx.stroke();
21+
22+
// Major Grid Lines
23+
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
24+
ctx.lineWidth = 2 * scale;
25+
ctx.beginPath();
26+
for (let x = 0; x < width; x += gridSize * 4) ctx.rect(x, 0, 1, height);
27+
for (let y = 0; y < height; y += gridSize * 4) ctx.rect(0, y, width, 1);
28+
ctx.stroke();
29+
30+
// Main Frame
31+
ctx.strokeStyle = 'white';
32+
ctx.lineWidth = 6 * scale;
33+
ctx.strokeRect(padding, padding, width - (padding * 2), height - (padding * 2));
34+
35+
// Title Block (Bottom Left)
36+
const blockW = 500 * scale;
37+
const blockH = 180 * scale;
38+
const blockX = padding; // Move to left
39+
const blockY = height - padding - blockH;
40+
41+
ctx.lineWidth = 3 * scale;
42+
ctx.fillStyle = 'white';
43+
ctx.strokeRect(blockX, blockY, blockW, blockH);
44+
45+
// Internal lines of Title Block
46+
const rowH = blockH / 4;
47+
ctx.beginPath();
48+
for(let i=1; i<4; i++) {
49+
ctx.moveTo(blockX, blockY + (i*rowH));
50+
ctx.lineTo(blockX + blockW, blockY + (i*rowH));
51+
}
52+
ctx.moveTo(blockX + (blockW * 0.3), blockY);
53+
ctx.lineTo(blockX + (blockW * 0.3), blockY + blockH);
54+
ctx.stroke();
55+
56+
// Text in Block
57+
ctx.font = `bold ${14 * scale}px "Courier New", monospace`;
58+
ctx.textAlign = 'left';
59+
ctx.textBaseline = 'middle';
60+
61+
const labels = ['PROJECT', 'AUTHOR', 'URL', 'STARS'];
62+
const values = [repoName.substring(0, 20).toUpperCase(), repoOwner.toUpperCase(), (supportUrl || '').toUpperCase(), stars || '0'];
63+
64+
labels.forEach((label, i) => {
65+
ctx.fillText(label, blockX + 10 * scale, blockY + (i * rowH) + (rowH/2));
66+
ctx.fillText(values[i], blockX + (blockW * 0.3) + 10 * scale, blockY + (i * rowH) + (rowH/2));
67+
});
68+
69+
// Main Drawing Area Content
70+
ctx.textAlign = 'center';
71+
ctx.textBaseline = 'middle';
72+
73+
// Center Lines
74+
ctx.setLineDash([20 * scale, 10 * scale, 5 * scale, 10 * scale]);
75+
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
76+
ctx.lineWidth = 1 * scale;
77+
ctx.beginPath();
78+
ctx.moveTo(width/2, padding); ctx.lineTo(width/2, height - padding); // Vert
79+
ctx.moveTo(padding, height/2); ctx.lineTo(width - padding, height/2); // Horiz
80+
ctx.stroke();
81+
ctx.setLineDash([]);
82+
83+
// Project Name (Main) - Moved Up
84+
ctx.font = `bold ${100 * scale}px "Courier New", monospace`;
85+
ctx.fillStyle = 'white';
86+
ctx.fillText(repoName.toUpperCase(), width/2, height/2 - 80 * scale);
87+
88+
// Measurement Lines
89+
const textW = ctx.measureText(repoName.toUpperCase()).width;
90+
const lineY = height/2; // adjusted
91+
92+
ctx.beginPath();
93+
ctx.moveTo(width/2 - textW/2, lineY);
94+
ctx.lineTo(width/2 + textW/2, lineY);
95+
ctx.strokeStyle = 'white';
96+
ctx.lineWidth = 2 * scale;
97+
ctx.stroke();
98+
99+
// Arrows
100+
ctx.beginPath();
101+
ctx.moveTo(width/2 - textW/2 + 20*scale, lineY - 10*scale); ctx.lineTo(width/2 - textW/2, lineY); ctx.lineTo(width/2 - textW/2 + 20*scale, lineY + 10*scale);
102+
ctx.moveTo(width/2 + textW/2 - 20*scale, lineY - 10*scale); ctx.lineTo(width/2 + textW/2, lineY); ctx.lineTo(width/2 + textW/2 - 20*scale, lineY + 10*scale);
103+
ctx.fill();
104+
105+
// Description - Bottom Right
106+
ctx.textAlign = 'left';
107+
ctx.textBaseline = 'top';
108+
ctx.font = `${24 * scale}px "Courier New", monospace`;
109+
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
110+
111+
const descX = width/2 + 40 * scale;
112+
const descY = height/2 + 40 * scale;
113+
const descW = width/2 - padding - 80 * scale;
114+
115+
// Label for description
116+
ctx.fillText("NOTES:", descX, descY);
117+
118+
// Wrap text below "NOTES:"
119+
wrapText(ctx, description.toUpperCase(), descX, descY + 40 * scale, descW, 35 * scale);
120+
};
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { wrapText } from '../utils';
2+
3+
export const brutalist = (ctx, width, height, scale, data) => {
4+
const { primaryColor, secondaryColor, repoOwner, repoName, description, language, stars, forks, supportUrl } = data;
5+
// Brutalist Header Bar
6+
ctx.fillStyle = primaryColor;
7+
ctx.fillRect(0, 0, width, 20 * scale);
8+
9+
const padding = 60 * scale;
10+
const borderW = 4 * scale;
11+
12+
// Main Border
13+
ctx.strokeStyle = '#ffffff';
14+
ctx.lineWidth = borderW;
15+
ctx.strokeRect(padding, padding, width - padding * 2, height - padding * 2);
16+
17+
// Decorative Corners
18+
const cornerSize = 20 * scale;
19+
ctx.fillStyle = '#ffffff';
20+
ctx.fillRect(padding - borderW/2, padding - borderW/2, cornerSize, cornerSize); // TL
21+
ctx.fillRect(width - padding - cornerSize + borderW/2, padding - borderW/2, cornerSize, cornerSize); // TR
22+
ctx.fillRect(padding - borderW/2, height - padding - cornerSize + borderW/2, cornerSize, cornerSize); // BL
23+
ctx.fillRect(width - padding - cornerSize + borderW/2, height - padding - cornerSize + borderW/2, cornerSize, cornerSize); // BR
24+
25+
// Content
26+
ctx.fillStyle = '#ffffff';
27+
ctx.font = `bold ${40 * scale}px "Courier New", monospace`;
28+
ctx.fillText(`USER: ${repoOwner.toUpperCase()}`, padding + 40 * scale, padding + 80 * scale);
29+
30+
ctx.fillStyle = primaryColor;
31+
ctx.font = `900 ${100 * scale}px "Impact", sans-serif`;
32+
ctx.fillText(repoName.toUpperCase(), padding + 35 * scale, padding + 200 * scale);
33+
34+
ctx.fillStyle = '#ffffff';
35+
ctx.font = `${30 * scale}px "Courier New", monospace`;
36+
wrapText(ctx, description, padding + 40 * scale, padding + 300 * scale, width - padding * 3, 40 * scale);
37+
38+
// Footer Info
39+
ctx.fillStyle = secondaryColor;
40+
ctx.fillRect(padding, height - padding - 80 * scale, width - padding * 2, 80 * scale);
41+
42+
ctx.fillStyle = '#000000';
43+
ctx.font = `bold ${30 * scale}px "Courier New", monospace`;
44+
ctx.textBaseline = 'middle';
45+
ctx.textAlign = 'left';
46+
ctx.fillText(`LANG: ${language.toUpperCase()}`, padding + 40 * scale, height - padding - 40 * scale);
47+
48+
ctx.textAlign = 'right';
49+
let statsText = '';
50+
if (stars) statsText += `★ ${stars} `;
51+
if (forks) statsText += `⑂ ${forks}`;
52+
53+
const rightPadding = padding + 40 * scale;
54+
55+
if (supportUrl) {
56+
ctx.font = `${24 * scale}px "Courier New", monospace`;
57+
ctx.fillText(supportUrl.toUpperCase(), width - rightPadding, height - padding - 40 * scale);
58+
59+
const urlWidth = ctx.measureText(supportUrl.toUpperCase()).width;
60+
ctx.font = `bold ${30 * scale}px "Courier New", monospace`;
61+
if (statsText) {
62+
ctx.fillText(statsText, width - rightPadding - urlWidth - 60 * scale, height - padding - 40 * scale);
63+
}
64+
} else {
65+
ctx.fillText(statsText, width - rightPadding, height - padding - 40 * scale);
66+
}
67+
};
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { wrapText } from '../utils';
2+
3+
export const clay = (ctx, width, height, scale, data) => {
4+
const { repoOwner, repoName, description, language, stars, forks, supportUrl } = data;
5+
// PLAYFUL CLAY Style
6+
ctx.fillStyle = '#f0f4f8'; // Light blue-ish grey
7+
ctx.fillRect(0, 0, width, height);
8+
9+
const cardColor = '#ffffff';
10+
const padding = 60 * scale;
11+
// Main Container (Claymorphism: rounded, inner shadow, outer shadow)
12+
const drawClayRect = (x, y, w, h, radius) => {
13+
ctx.save();
14+
// Outer Shadow
15+
ctx.shadowColor = '#b8c2cc';
16+
ctx.shadowBlur = 30 * scale;
17+
ctx.shadowOffsetY = 20 * scale;
18+
ctx.fillStyle = cardColor;
19+
20+
ctx.beginPath();
21+
ctx.roundRect(x, y, w, h, radius);
22+
ctx.fill();
23+
24+
// Inner Highlight (simulated with clipping)
25+
ctx.shadowColor = 'transparent';
26+
ctx.clip();
27+
ctx.strokeStyle = 'rgba(255,255,255,0.8)';
28+
ctx.lineWidth = 10 * scale;
29+
ctx.stroke();
30+
ctx.restore();
31+
};
32+
33+
// Large Card
34+
drawClayRect(padding, padding, width - padding*2, height - padding*2, 60 * scale);
35+
36+
// Content
37+
ctx.textAlign = 'center';
38+
ctx.fillStyle = '#334e68'; // Dark blue-grey text
39+
40+
// Round Font
41+
const roundFont = '"Nunito", "Quicksand", "Arial Rounded MT Bold", sans-serif';
42+
43+
ctx.font = `800 ${90 * scale}px ${roundFont}`;
44+
ctx.fillText(repoName, width/2, height * 0.35);
45+
46+
// Owner & URL Group
47+
const ownerText = `by ${repoOwner}`;
48+
ctx.font = `600 ${30 * scale}px ${roundFont}`;
49+
const ownerWidth = ctx.measureText(ownerText).width;
50+
51+
let totalGroupWidth = ownerWidth;
52+
if (supportUrl) {
53+
ctx.font = `600 ${20 * scale}px ${roundFont}`;
54+
totalGroupWidth += ctx.measureText(supportUrl).width + 30 * scale;
55+
}
56+
57+
const groupX = (width - totalGroupWidth) / 2;
58+
59+
ctx.textAlign = 'left';
60+
ctx.fillStyle = '#829ab1';
61+
ctx.font = `600 ${30 * scale}px ${roundFont}`;
62+
ctx.fillText(ownerText, groupX, height * 0.45);
63+
64+
if (supportUrl) {
65+
ctx.fillStyle = '#bcccdc';
66+
ctx.font = `600 ${20 * scale}px ${roundFont}`;
67+
ctx.fillText(supportUrl, groupX + ownerWidth + 30 * scale, height * 0.45);
68+
}
69+
70+
// Description
71+
ctx.textAlign = 'center';
72+
ctx.fillStyle = '#486581';
73+
ctx.font = `500 ${32 * scale}px ${roundFont}`;
74+
wrapText(ctx, description, width/2, height * 0.55, width * 0.7, 45 * scale);
75+
76+
// Floating Pills for stats
77+
const pillW = 200 * scale;
78+
const pillH = 80 * scale;
79+
const pillY = height * 0.75;
80+
81+
const drawClayPill = (x, text, color) => {
82+
ctx.save();
83+
ctx.shadowColor = color + '66'; // semi transparent
84+
ctx.shadowBlur = 20 * scale;
85+
ctx.shadowOffsetY = 10 * scale;
86+
ctx.fillStyle = color;
87+
88+
ctx.beginPath();
89+
ctx.roundRect(x - pillW/2, pillY, pillW, pillH, 40 * scale);
90+
ctx.fill();
91+
92+
ctx.fillStyle = 'white';
93+
ctx.font = `bold ${24 * scale}px ${roundFont}`;
94+
ctx.fillText(text, x, pillY + pillH/2 + 8*scale);
95+
ctx.restore();
96+
};
97+
98+
let pillX = width / 2;
99+
if (stars) {
100+
drawClayPill(pillX - 250*scale, `${stars} ★`, '#f6ad55'); // Orange
101+
}
102+
drawClayPill(pillX, language, '#63b3ed'); // Blue
103+
if (forks) {
104+
drawClayPill(pillX + 250*scale, `${forks} ⑂`, '#68d391'); // Green
105+
}
106+
};

0 commit comments

Comments
 (0)