Skip to content

Commit 233a279

Browse files
committed
feat: add neon-vapor, cad-technical and retro-dos themes to github thumbnail generator
1 parent 7842c69 commit 233a279

File tree

5 files changed

+364
-1
lines changed

5 files changed

+364
-1
lines changed

src/pages/apps/github-thumbnail/GithubThumbnailGeneratorPage.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ const THEME_OPTIONS = [
5050
{ value: 'neoBrutalist', label: 'NEO_BRUTALIST' },
5151
{ value: 'quantumOverlay', label: 'QUANTUM_OVERLAY' },
5252
{ value: 'terminalPro', label: 'TERMINAL_PRO_CLI' },
53+
{ value: 'neonVapor', label: 'NEON_VAPORWAVE' },
54+
{ value: 'cadTech', label: 'CAD_TECHNICAL' },
55+
{ value: 'retroDos', label: 'RETRO_DOS_SHELL' },
5356
];
5457

5558
const GithubThumbnailGeneratorPage = () => {
@@ -90,7 +93,7 @@ const GithubThumbnailGeneratorPage = () => {
9093
ctx.globalAlpha = 0.05;
9194
ctx.fillStyle = '#ffffff';
9295

93-
if (['brutalist', 'neoBrutalist', 'terminalPro'].includes(theme)) {
96+
if (['brutalist', 'neoBrutalist', 'terminalPro', 'retroDos', 'cadTech'].includes(theme)) {
9497
// Grid Pattern
9598
const gridSize = 40 * scale;
9699
for (let x = 0; x < width; x += gridSize) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ import { cybernetic } from './themes/cybernetic';
3030
import { neoBrutalist } from './themes/neoBrutalist';
3131
import { quantumOverlay } from './themes/quantumOverlay';
3232
import { terminalPro } from './themes/terminalPro';
33+
import { neonVapor } from './themes/neonVapor';
34+
import { cadTech } from './themes/cadTech';
35+
import { retroDos } from './themes/retroDos';
3336

3437
export const themeRenderers = {
3538
modern,
@@ -64,4 +67,7 @@ export const themeRenderers = {
6467
neoBrutalist,
6568
quantumOverlay,
6669
terminalPro,
70+
neonVapor,
71+
cadTech,
72+
retroDos,
6773
};
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { wrapText } from '../utils';
2+
3+
export const cadTech = (ctx, width, height, scale, data) => {
4+
const {
5+
primaryColor,
6+
secondaryColor,
7+
bgColor,
8+
repoOwner,
9+
repoName,
10+
description,
11+
language,
12+
stars,
13+
} = data;
14+
15+
const padding = 60 * scale;
16+
const borderWidth = 4; // Fixed value
17+
18+
// 1. Engineering Background (Blueprint/CAD Style)
19+
ctx.fillStyle = bgColor;
20+
ctx.fillRect(0, 0, width, height);
21+
22+
// 2. Technical Grid (CAD Style)
23+
ctx.strokeStyle = '#ffffff';
24+
ctx.globalAlpha = 0.05;
25+
ctx.lineWidth = 1 * scale;
26+
const gridSize = 40 * scale;
27+
for (let x = 0; x < width; x += gridSize) {
28+
ctx.beginPath();
29+
ctx.moveTo(x, 0);
30+
ctx.lineTo(x, height);
31+
ctx.stroke();
32+
}
33+
for (let y = 0; y < height; y += gridSize) {
34+
ctx.beginPath();
35+
ctx.moveTo(0, y);
36+
ctx.lineTo(width, y);
37+
ctx.stroke();
38+
}
39+
ctx.globalAlpha = 1.0;
40+
41+
// 3. Technical Border (using borderWidth and secondaryColor)
42+
ctx.strokeStyle = secondaryColor;
43+
ctx.lineWidth = borderWidth * scale;
44+
ctx.strokeRect(padding, padding, width - padding * 2, height - padding * 2);
45+
46+
// Corner Accents (Measurement lines)
47+
ctx.lineWidth = 2 * scale;
48+
ctx.strokeStyle = primaryColor;
49+
const cornerSize = 40 * scale;
50+
51+
// Top Left Accents
52+
ctx.beginPath();
53+
ctx.moveTo(padding - 20 * scale, padding);
54+
ctx.lineTo(padding + cornerSize, padding);
55+
ctx.stroke();
56+
ctx.beginPath();
57+
ctx.moveTo(padding, padding - 20 * scale);
58+
ctx.lineTo(padding, padding + cornerSize);
59+
ctx.stroke();
60+
61+
// 4. Content - Architectural Layout
62+
ctx.textAlign = 'left';
63+
64+
// Project Info Box (Top Right)
65+
const infoW = 300 * scale;
66+
const infoH = 100 * scale;
67+
const infoX = width - padding - infoW - 20 * scale;
68+
const infoY = padding + 20 * scale;
69+
70+
ctx.strokeStyle = secondaryColor;
71+
ctx.strokeRect(infoX, infoY, infoW, infoH);
72+
73+
ctx.font = `bold ${16 * scale}px "JetBrains Mono", monospace`;
74+
ctx.fillStyle = secondaryColor;
75+
ctx.fillText('REF_NODE: 0x2026', infoX + 15 * scale, infoY + 30 * scale);
76+
ctx.fillText(`OWNER: ${repoOwner.toUpperCase()}`, infoX + 15 * scale, infoY + 60 * scale);
77+
ctx.fillText(`DATE: ${new Date().toLocaleDateString()}`, infoX + 15 * scale, infoY + 85 * scale);
78+
79+
// Main Heading (Blueprint style)
80+
ctx.font = `900 ${110 * scale}px "Inter", sans-serif`;
81+
ctx.fillStyle = '#ffffff';
82+
ctx.fillText(repoName, padding + 40 * scale, padding + 160 * scale);
83+
84+
// Underline with Measurement labels
85+
ctx.lineWidth = 2 * scale;
86+
ctx.strokeStyle = primaryColor;
87+
ctx.beginPath();
88+
ctx.moveTo(padding + 40 * scale, padding + 180 * scale);
89+
ctx.lineTo(width - padding - 40 * scale, padding + 180 * scale);
90+
ctx.stroke();
91+
92+
ctx.font = `bold ${12 * scale}px "JetBrains Mono", monospace`;
93+
ctx.fillStyle = primaryColor;
94+
ctx.fillText(`${width - padding * 2}mm_REF`, width / 2, padding + 175 * scale);
95+
96+
// Description (Architectural notes)
97+
ctx.font = `${30 * scale}px "Inter", sans-serif`;
98+
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
99+
wrapText(
100+
ctx,
101+
description.toUpperCase(),
102+
padding + 40 * scale,
103+
padding + 250 * scale,
104+
width - padding * 3,
105+
45 * scale
106+
);
107+
108+
// 5. Tech Metadata (Bottom)
109+
const footerY = height - padding - 40 * scale;
110+
111+
// Language Chip
112+
ctx.fillStyle = secondaryColor;
113+
ctx.fillRect(padding + 40 * scale, footerY, 180 * scale, 60 * scale);
114+
ctx.fillStyle = '#000000';
115+
ctx.font = `bold ${24 * scale}px "JetBrains Mono", monospace`;
116+
ctx.textAlign = 'center';
117+
ctx.fillText(language.toUpperCase(), padding + 40 * scale + 90 * scale, footerY + 38 * scale);
118+
// Metrics (Table style)
119+
ctx.textAlign = 'right';
120+
ctx.font = `bold ${20 * scale}px "JetBrains Mono", monospace`;
121+
ctx.fillStyle = '#ffffff';
122+
ctx.fillText(`| ST_REF: ${stars} | FK_REF: ${stars / 2} |`, width - padding - 40 * scale, footerY + 35 * scale);
123+
};
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { wrapText } from '../utils';
2+
3+
export const neonVapor = (ctx, width, height, scale, data) => {
4+
const {
5+
primaryColor,
6+
secondaryColor,
7+
bgColor,
8+
repoOwner,
9+
repoName,
10+
description,
11+
language,
12+
stars,
13+
} = data;
14+
15+
const padding = 60 * scale;
16+
const glowIntensity = 50; // Fixed intensity
17+
18+
// 1. Deep Space Background
19+
ctx.fillStyle = bgColor;
20+
ctx.fillRect(0, 0, width, height);
21+
22+
// 2. Glowing Sun (Vaporwave style)
23+
const sunRadius = 200 * scale;
24+
const sunX = width * 0.75;
25+
const sunY = height * 0.3;
26+
27+
const sunGradient = ctx.createLinearGradient(sunX, sunY - sunRadius, sunX, sunY + sunRadius);
28+
sunGradient.addColorStop(0, primaryColor);
29+
sunGradient.addColorStop(0.5, secondaryColor);
30+
sunGradient.addColorStop(1, primaryColor);
31+
32+
ctx.save();
33+
ctx.shadowColor = secondaryColor;
34+
ctx.shadowBlur = (glowIntensity / 100) * 80 * scale;
35+
ctx.fillStyle = sunGradient;
36+
ctx.beginPath();
37+
ctx.arc(sunX, sunY, sunRadius, 0, Math.PI * 2);
38+
ctx.fill();
39+
40+
// Retro Sun Scanlines
41+
ctx.globalCompositeOperation = 'destination-out';
42+
for (let i = sunY - sunRadius; i < sunY + sunRadius; i += 20 * scale) {
43+
const scanHeight = 4 * scale * (1 + (i - (sunY - sunRadius)) / (sunRadius * 2));
44+
ctx.fillRect(sunX - sunRadius, i, sunRadius * 2, scanHeight);
45+
}
46+
ctx.restore();
47+
48+
// 3. Perspectives Grid (Vaporwave floor)
49+
ctx.save();
50+
ctx.strokeStyle = primaryColor;
51+
ctx.lineWidth = 1 * scale;
52+
ctx.globalAlpha = 0.3;
53+
const gridY = height * 0.6;
54+
for (let x = -width; x < width * 2; x += 60 * scale) {
55+
ctx.beginPath();
56+
ctx.moveTo(width / 2, gridY);
57+
ctx.lineTo(x, height);
58+
ctx.stroke();
59+
}
60+
for (let y = gridY; y < height; y += (y - gridY + 10) * 0.5) {
61+
ctx.beginPath();
62+
ctx.moveTo(0, y);
63+
ctx.lineTo(width, y);
64+
ctx.stroke();
65+
}
66+
ctx.restore();
67+
68+
// 4. Main Typography
69+
ctx.textAlign = 'left';
70+
71+
// Repo Owner
72+
ctx.font = `italic bold ${30 * scale}px "Inter", sans-serif`;
73+
ctx.fillStyle = secondaryColor;
74+
ctx.fillText(repoOwner.toUpperCase(), padding, padding + 40 * scale);
75+
// Repo Name
76+
ctx.save();
77+
ctx.font = `italic 900 ${130 * scale}px "Inter", "Arial Black", sans-serif`;
78+
// Double glow
79+
ctx.shadowColor = primaryColor;
80+
ctx.shadowBlur = (glowIntensity / 100) * 40 * scale;
81+
ctx.fillStyle = '#ffffff';
82+
ctx.fillText(repoName, padding, padding + 180 * scale);
83+
84+
ctx.shadowColor = secondaryColor;
85+
ctx.shadowBlur = (glowIntensity / 100) * 20 * scale;
86+
ctx.fillText(repoName, padding + 4 * scale, padding + 180 * scale);
87+
ctx.restore();
88+
89+
// Description
90+
ctx.font = `bold ${36 * scale}px "Inter", sans-serif`;
91+
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
92+
wrapText(
93+
ctx,
94+
description,
95+
padding,
96+
padding + 280 * scale,
97+
width * 0.6,
98+
50 * scale
99+
);
100+
101+
// 5. Retro Stats Pills
102+
const drawRetroPill = (x, y, label, value, color) => {
103+
ctx.font = `bold ${24 * scale}px "JetBrains Mono", monospace`;
104+
const text = `${label}: ${value}`;
105+
const tw = ctx.measureText(text).width + 40 * scale;
106+
107+
ctx.fillStyle = color;
108+
ctx.globalAlpha = 0.2;
109+
ctx.roundRect(x, y - 30 * scale, tw, 60 * scale, 30 * scale);
110+
ctx.fill();
111+
ctx.globalAlpha = 1.0;
112+
113+
ctx.strokeStyle = color;
114+
ctx.lineWidth = 2 * scale;
115+
ctx.strokeRect(x, y - 30 * scale, tw, 60 * scale, 30 * scale);
116+
117+
ctx.fillStyle = '#ffffff';
118+
ctx.fillText(text, x + 20 * scale, y + 8 * scale);
119+
return tw;
120+
};
121+
122+
const footerY = height - padding - 20 * scale;
123+
let curX = padding;
124+
curX += drawRetroPill(curX, footerY, 'STARS', stars, primaryColor) + 20 * scale;
125+
drawRetroPill(curX, footerY, 'LANG', language.toUpperCase(), secondaryColor);
126+
};
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { wrapText } from '../utils';
2+
3+
export const retroDos = (ctx, width, height, scale, data) => {
4+
const {
5+
primaryColor,
6+
secondaryColor,
7+
bgColor,
8+
repoOwner,
9+
repoName,
10+
description,
11+
language,
12+
stars,
13+
} = data;
14+
15+
const padding = 60 * scale;
16+
const borderWidth = 4; // Fixed value
17+
18+
// 1. Classic DOS Blue Background (Default DOS blue, or bgColor)
19+
ctx.fillStyle = bgColor;
20+
ctx.fillRect(0, 0, width, height);
21+
22+
// 2. DOS Frame (using borderWidth and secondaryColor)
23+
ctx.strokeStyle = secondaryColor;
24+
ctx.lineWidth = borderWidth * scale;
25+
ctx.strokeRect(padding, padding, width - padding * 2, height - padding * 2);
26+
27+
// Internal Header line
28+
ctx.lineWidth = borderWidth / 2 * scale;
29+
const headerY = padding + 80 * scale;
30+
ctx.beginPath();
31+
ctx.moveTo(padding, headerY);
32+
ctx.lineTo(width - padding, headerY);
33+
ctx.stroke();
34+
35+
// 3. Header Text (BIOS Style)
36+
ctx.textAlign = 'left';
37+
ctx.textBaseline = 'middle';
38+
ctx.font = `bold ${32 * scale}px "Courier New", monospace`;
39+
ctx.fillStyle = '#ffffff';
40+
ctx.fillText(`FEZ-BIOS V2.0 // SYSTEM: ${repoOwner.toUpperCase()}`, padding + 30 * scale, padding + 42 * scale);
41+
42+
ctx.textAlign = 'right';
43+
ctx.fillText('0x2026_INIT', width - padding - 30 * scale, padding + 42 * scale);
44+
45+
// 4. Main Body - Command Interface
46+
const bodyX = padding + 40 * scale;
47+
const bodyY = headerY + 60 * scale;
48+
49+
// Prompt line
50+
ctx.textAlign = 'left';
51+
ctx.fillStyle = primaryColor;
52+
ctx.fillText('C:\\\\PROJECTS\\\\> LIST_DATA --VERBOSE', bodyX, bodyY);
53+
54+
// Repo Name (Blocky DOS title)
55+
ctx.font = `bold ${100 * scale}px "Courier New", monospace`;
56+
ctx.fillStyle = primaryColor;
57+
ctx.fillText(repoName.toUpperCase(), bodyX, bodyY + 110 * scale);
58+
59+
// Divider
60+
ctx.strokeStyle = secondaryColor;
61+
ctx.lineWidth = 1 * scale;
62+
ctx.beginPath();
63+
ctx.moveTo(bodyX, bodyY + 140 * scale);
64+
ctx.lineTo(width - padding - 100 * scale, bodyY + 140 * scale);
65+
ctx.stroke();
66+
67+
// Description (RAW LOG)
68+
ctx.font = `${30 * scale}px "Courier New", monospace`;
69+
ctx.fillStyle = '#ffffff';
70+
ctx.fillText('LOG_DESC:', bodyX, bodyY + 190 * scale);
71+
72+
wrapText(
73+
ctx,
74+
description.toUpperCase(),
75+
bodyX,
76+
bodyY + 240 * scale,
77+
width - padding * 3,
78+
45 * scale
79+
);
80+
81+
// 5. System Stats (Bottom area)
82+
const footerY = height - padding - 60 * scale;
83+
84+
// Progress Bar (DOS style)
85+
ctx.font = `bold ${24 * scale}px "Courier New", monospace`;
86+
ctx.fillStyle = '#ffffff';
87+
ctx.fillText('BOOTING_CORE: [', bodyX, footerY);
88+
89+
const barW = 300 * scale;
90+
const barX = bodyX + 220 * scale;
91+
ctx.strokeStyle = '#ffffff';
92+
ctx.lineWidth = 2 * scale;
93+
ctx.strokeRect(barX, footerY - 20 * scale, barW, 25 * scale);
94+
95+
ctx.fillStyle = primaryColor;
96+
ctx.fillRect(barX + 5 * scale, footerY - 15 * scale, barW * 0.85 * scale, 15 * scale);
97+
ctx.fillStyle = '#ffffff';
98+
ctx.fillText('] 85%', barX + barW + 15 * scale, footerY);
99+
100+
// Metadata Footer
101+
ctx.textAlign = 'right';
102+
ctx.font = `bold ${22 * scale}px "Courier New", monospace`;
103+
ctx.fillStyle = secondaryColor;
104+
ctx.fillText(`★:${stars} | ⑂:${stars / 2} | LANG:${language.toUpperCase()}`, width - padding - 40 * scale, footerY);
105+
};

0 commit comments

Comments
 (0)