feat: update certificate design with SVG template and Poppins font
- Changed certificate background from PNG to SVG for better quality - Added Poppins font import to index.html - Updated certificate layout with Team Name and Person Name in blue (#59bef5) - Repositioned QR code to fit in designated white box placeholder - Removed generated copyright and date overlays (now part of SVG template) - Adjusted text positioning for better alignment with new design - Increased canvas scale to 4x and wait time to 1500ms for sharper rendering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
782cce820b
commit
3ad828e759
@@ -18,6 +18,9 @@
|
|||||||
type="image/svg+xml"
|
type="image/svg+xml"
|
||||||
href="/images/imphnen-logo-simple.svg"
|
href="/images/imphnen-logo-simple.svg"
|
||||||
/>
|
/>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap" rel="stylesheet" />
|
||||||
<link rel="stylesheet" href="/src/index.css" />
|
<link rel="stylesheet" href="/src/index.css" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="https://hackathon.imphnen.dev/" />
|
<meta property="og:url" content="https://hackathon.imphnen.dev/" />
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 263 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 506 KiB |
@@ -115,19 +115,22 @@ const CertificatePage: FC = (): ReactElement => {
|
|||||||
|
|
||||||
setIsGenerating(true);
|
setIsGenerating(true);
|
||||||
try {
|
try {
|
||||||
// Wait a bit for fonts and images to load
|
// Wait longer for fonts and images to load properly
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||||
|
|
||||||
const canvas = await html2canvas(certificateRef.current, {
|
const canvas = await html2canvas(certificateRef.current, {
|
||||||
scale: 2,
|
scale: 4,
|
||||||
useCORS: true,
|
useCORS: true,
|
||||||
backgroundColor: '#ffffff',
|
backgroundColor: '#ffffff',
|
||||||
logging: false,
|
logging: false,
|
||||||
width: 1000,
|
width: 1000,
|
||||||
height: (1000 * 2480) / 3508,
|
height: (1000 * 2480) / 3508,
|
||||||
|
allowTaint: true,
|
||||||
|
imageTimeout: 0,
|
||||||
|
removeContainer: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const imageUrl = canvas.toDataURL('image/png');
|
const imageUrl = canvas.toDataURL('image/png', 1.0);
|
||||||
setCertificateImage(imageUrl);
|
setCertificateImage(imageUrl);
|
||||||
setShowTemplate(false);
|
setShowTemplate(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -315,57 +318,30 @@ const CertificatePage: FC = (): ReactElement => {
|
|||||||
id="certificate-template"
|
id="certificate-template"
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
backgroundImage: 'url(/images/blank_cert.png)',
|
backgroundImage: 'url(/images/blank_cert.svg)',
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: 'center',
|
||||||
width: '1000px',
|
width: '1000px',
|
||||||
height: `${(1000 * 2480) / 3508}px`,
|
height: `${(1000 * 2480) / 3508}px`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* User Name (from session) */}
|
{/* Team Name - positioned in middle between "Diberikan Kepada" and "Telah Berpartisipasi" */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '40%',
|
top: '41%',
|
||||||
left: '50%',
|
left: '3.5%',
|
||||||
transform: 'translateX(-50%)',
|
width: '55%',
|
||||||
width: '80%',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h3
|
|
||||||
ref={userNameRef}
|
|
||||||
style={{
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: '#111827',
|
|
||||||
textAlign: 'center',
|
|
||||||
fontSize: userNameFontSize,
|
|
||||||
lineHeight: '1.2',
|
|
||||||
wordBreak: 'break-word',
|
|
||||||
textShadow: '0 1px 2px rgba(0,0,0,0.1)',
|
|
||||||
margin: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{certificateName || 'N/A'}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Team Name */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: '46%',
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translateX(-50%)',
|
|
||||||
width: '70%',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h3
|
<h3
|
||||||
ref={teamNameRef}
|
ref={teamNameRef}
|
||||||
style={{
|
style={{
|
||||||
fontWeight: '600',
|
fontFamily: 'Poppins, sans-serif',
|
||||||
color: '#1f2937',
|
fontWeight: 'bold',
|
||||||
textAlign: 'center',
|
color: '#59bef5',
|
||||||
fontSize: teamNameFontSize,
|
textAlign: 'left',
|
||||||
|
fontSize: '32px',
|
||||||
lineHeight: '1.2',
|
lineHeight: '1.2',
|
||||||
wordBreak: 'break-word',
|
wordBreak: 'break-word',
|
||||||
margin: 0,
|
margin: 0,
|
||||||
@@ -375,82 +351,53 @@ const CertificatePage: FC = (): ReactElement => {
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Participation Text */}
|
{/* User Name - positioned below team name */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '60%',
|
top: '45%',
|
||||||
left: '50%',
|
left: '3.5%',
|
||||||
transform: 'translateX(-50%)',
|
width: '55%',
|
||||||
width: '70%',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p
|
<h3
|
||||||
|
ref={userNameRef}
|
||||||
style={{
|
style={{
|
||||||
textAlign: 'center',
|
fontFamily: 'Poppins, sans-serif',
|
||||||
color: '#374151',
|
fontWeight: 'bold',
|
||||||
fontSize: '18px',
|
color: '#59bef5',
|
||||||
fontWeight: '500',
|
textAlign: 'left',
|
||||||
|
fontSize: '40px',
|
||||||
|
lineHeight: '1.2',
|
||||||
|
wordBreak: 'break-word',
|
||||||
margin: 0,
|
margin: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontWeight: 'bold' }}>
|
{certificateName || 'N/A'}
|
||||||
Peserta Hackathon IMPHNEN x KOLOSAL AI
|
</h3>
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* QR Code */}
|
{/* QR Code - positioned in the white box area */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: '8%',
|
top: '33%',
|
||||||
left: '8%',
|
right: '9.3%',
|
||||||
|
width: '190px',
|
||||||
|
height: '190px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{qrCodeUrl && (
|
{qrCodeUrl && (
|
||||||
<div
|
<img
|
||||||
style={{
|
src={qrCodeUrl}
|
||||||
backgroundColor: '#ffffff',
|
alt="Certificate QR Code"
|
||||||
padding: '8px',
|
style={{ width: '190px', height: '190px', display: 'block' }}
|
||||||
borderRadius: '4px',
|
/>
|
||||||
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={qrCodeUrl}
|
|
||||||
alt="Certificate QR Code"
|
|
||||||
style={{ width: '96px', height: '96px' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Date */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: '8%',
|
|
||||||
right: '8%',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontSize: '14px',
|
|
||||||
color: '#374151',
|
|
||||||
margin: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{new Date().toLocaleDateString(
|
|
||||||
'id-ID',
|
|
||||||
{
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user