Asked by ABAINEH
CREAT THE BIRTHDAY CARD APP
All Answers 1
Answered by
GPT-5 mini
AI
I’ll create a simple, working birthday-card web app you can run locally right away. It supports selecting a template, editing recipient/name and message, uploading an image, previewing the card, and downloading the finished card as a PNG.
Files to create:
- index.html
- style.css
- script.js
Save each file and open index.html in your browser.
index.html
(put this content into a file named index.html)
```
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Birthday Card Maker</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="app">
<header>
<h1>Birthday Card Maker</h1>
</header>
<main>
<section class="controls">
<div class="control-row">
<label>Template:</label>
<select id="templateSelect">
<option value="classic">Classic</option>
<option value="modern">Modern</option>
<option value="party">Party</option>
</select>
</div>
<div class="control-row">
<label>Recipient name:</label>
<input id="recipientInput" type="text" placeholder="e.g., Sarah" />
</div>
<div class="control-row">
<label>Message:</label>
<textarea id="messageInput" rows="4" placeholder="Write your birthday message..."></textarea>
</div>
<div class="control-row">
<label>Upload photo (optional):</label>
<input id="photoInput" type="file" accept="image/*" />
</div>
<div class="control-row">
<label>Background color:</label>
<input id="bgColor" type="color" value="#ffefd5" />
</div>
<div class="control-row buttons">
<button id="downloadBtn">Download PNG</button>
<button id="printBtn">Print</button>
<button id="resetBtn">Reset</button>
</div>
</section>
<section class="preview">
<h2>Preview</h2>
<div id="card" class="card classic">
<div class="card-image-wrap">
<img id="cardImage" src="" alt="" />
<div id="imagePlaceholder">Add photo</div>
</div>
<div class="card-content">
<h1 id="cardTitle">Happy Birthday</h1>
<h3 id="cardRecipient"></h3>
<p id="cardMessage">Wishing you a wonderful birthday and a year full of joy!</p>
</div>
</div>
</section>
</main>
<footer>
<small>Simple birthday card maker — edit and download</small>
</footer>
</div>
<!-- html2canvas for export -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="script.js"></script>
</body>
</html>
```
style.css
(put this content into a file named style.css)
```
:root{
--app-bg: #f7f7f9;
--control-bg: #ffffff;
--card-w: 600px;
--card-h: 400px;
--accent: #ff6b6b;
}
*{box-sizing:border-box}
body{
margin:0;
font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial;
background:var(--app-bg);
color:#222;
}
.app{
max-width:1100px;
margin:24px auto;
padding:18px;
}
header h1{margin:0 0 12px 0}
main{
display:flex;
gap:20px;
align-items:flex-start;
}
.controls{
width:360px;
background:var(--control-bg);
padding:16px;
border-radius:8px;
box-shadow:0 2px 8px rgba(0,0,0,0.06);
}
.control-row{
margin-bottom:12px;
display:flex;
flex-direction:column;
}
.control-row label{
font-weight:600;
margin-bottom:6px;
}
.control-row input[type="text"],
.control-row select,
.control-row textarea,
.control-row input[type="color"]{
padding:8px;
border-radius:6px;
border:1px solid #ddd;
font-size:14px;
}
.control-row.buttons{
display:flex;
gap:8px;
}
button{
padding:10px 12px;
border-radius:6px;
border: none;
background:var(--accent);
color:#fff;
cursor:pointer;
}
button:hover{opacity:0.95}
.preview{
flex:1;
}
.preview h2{margin-top:0}
.card{
width:var(--card-w);
height:var(--card-h);
border-radius:12px;
box-shadow:0 8px 30px rgba(0,0,0,0.12);
overflow:hidden;
display:flex;
flex-direction:column;
align-items:stretch;
background:linear-gradient(180deg,#fff,#fff);
}
/* image area */
.card-image-wrap{
height:45%;
background:#f0f0f0;
position:relative;
display:flex;
align-items:center;
justify-content:center;
overflow:hidden;
}
.card-image-wrap img{
max-width:100%;
max-height:100%;
display:block;
}
#imagePlaceholder{
position:absolute;
color:#666;
font-weight:600;
}
/* content area */
.card-content{
padding:18px;
text-align:center;
display:flex;
flex-direction:column;
justify-content:center;
gap:6px;
height:55%;
}
.card-content h1{
margin:0;
font-size:28px;
letter-spacing:0.5px;
}
.card-content h3{
margin:0;
font-weight:600;
color:#444;
}
.card-content p{
margin:6px 0 0 0;
color:#333;
}
/* template variations */
.card.classic{ background:linear-gradient(180deg,#fff7ec,#fff) }
.card.modern{ background:linear-gradient(180deg,#e7f7ff,#ffffff) }
.card.party{ background:linear-gradient(180deg,#fff0fb,#fff) }
/* small screens */
@media (max-width:900px){
main{flex-direction:column}
.controls{width:100%}
.card{width:100%; max-width:600px}
}
```
script.js
(put this content into a file named script.js)
```
const templateSelect = document.getElementById('templateSelect');
const recipientInput = document.getElementById('recipientInput');
const messageInput = document.getElementById('messageInput');
const photoInput = document.getElementById('photoInput');
const bgColorInput = document.getElementById('bgColor');
const card = document.getElementById('card');
const cardTitle = document.getElementById('cardTitle');
const cardRecipient = document.getElementById('cardRecipient');
const cardMessage = document.getElementById('cardMessage');
const cardImage = document.getElementById('cardImage');
const imagePlaceholder = document.getElementById('imagePlaceholder');
const downloadBtn = document.getElementById('downloadBtn');
const printBtn = document.getElementById('printBtn');
const resetBtn = document.getElementById('resetBtn');
// Initialize
function applyTemplate(t){
card.classList.remove('classic','modern','party');
card.classList.add(t);
}
applyTemplate(templateSelect.value);
// Events
templateSelect.addEventListener('change', e => {
applyTemplate(e.target.value);
});
recipientInput.addEventListener('input', e => {
const v = e.target.value.trim();
cardRecipient.textContent = v ? `Dear ${v},` : '';
});
messageInput.addEventListener('input', e => {
cardMessage.textContent = e.target.value || 'Wishing you a wonderful birthday and a year full of joy!';
});
bgColorInput.addEventListener('input', e => {
const color = e.target.value;
card.style.background = color;
// if you want to keep templates' look, comment the above line and use CSS templates
});
// Photo upload
photoInput.addEventListener('change', e=>{
const file = e.target.files[0];
if(!file) return;
const reader = new FileReader();
reader.onload = function(ev){
cardImage.src = ev.target.result;
cardImage.style.display = 'block';
imagePlaceholder.style.display = 'none';
};
reader.readAsDataURL(file);
});
// Download using html2canvas
downloadBtn.addEventListener('click', async () => {
// temporarily remove controls or scale adjustments if needed
const oldTransform = card.style.transform;
// increase scale for better resolution
const scale = 2;
const origWidth = card.offsetWidth;
const origHeight = card.offsetHeight;
// Use html2canvas
html2canvas(card, { scale: scale, useCORS: true }).then(canvas=>{
const link = document.createElement('a');
link.download = `birthday-card.png`;
link.href = canvas.toDataURL('image/png');
link.click();
}).catch(err=>{
alert('Error exporting image: ' + err.message);
}).finally(()=>{
card.style.transform = oldTransform;
});
});
printBtn.addEventListener('click', () => {
// open new window with only the card for printing
html2canvas(card, { scale: 2, useCORS:true }).then(canvas=>{
const dataUrl = canvas.toDataURL('image/png');
const w = window.open('');
w.document.write('<img src="'+dataUrl+'" style="max-width:100%;"/>');
w.document.title = 'Print birthday card';
w.focus();
w.print();
});
});
resetBtn.addEventListener('click', () => {
recipientInput.value = '';
messageInput.value = '';
photoInput.value = '';
cardImage.src = '';
cardImage.style.display = 'none';
imagePlaceholder.style.display = 'block';
applyTemplate('classic');
bgColorInput.value = '#ffefd5';
card.style.background = '';
cardRecipient.textContent = '';
cardMessage.textContent = 'Wishing you a wonderful birthday and a year full of joy!';
});
```
How to run
- Place the three files in the same folder.
- Open index.html in a modern browser (Chrome, Firefox, Edge).
- Edit fields, upload a photo, choose template, then click "Download PNG".
Notes and next steps (optional enhancements)
- Save/share: add a backend to save cards (e.g., Node/Express + S3 / database) and generate shareable links.
- Templates: add more templates, fonts, sticker/emoji overlays, and drag/resize of the uploaded image (use interact.js or fabric.js).
- Mobile app: wrap in Capacitor or build with React Native / Flutter for push notifications and scheduled sending.
- Email/schedule: add server-side scheduling (e.g., cron jobs, queue) to email the card on a selected date.
- Higher-resolution export: render on a larger off-screen canvas for print-quality output or use vector templates.
If you want, I can:
- Extend this to let users position/resize images and text.
- Add social sharing (Facebook, Twitter, WhatsApp).
- Turn it into a small React app or mobile app template (React Native / Flutter).
Tell me which direction you prefer and I’ll continue.
Files to create:
- index.html
- style.css
- script.js
Save each file and open index.html in your browser.
index.html
(put this content into a file named index.html)
```
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Birthday Card Maker</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="app">
<header>
<h1>Birthday Card Maker</h1>
</header>
<main>
<section class="controls">
<div class="control-row">
<label>Template:</label>
<select id="templateSelect">
<option value="classic">Classic</option>
<option value="modern">Modern</option>
<option value="party">Party</option>
</select>
</div>
<div class="control-row">
<label>Recipient name:</label>
<input id="recipientInput" type="text" placeholder="e.g., Sarah" />
</div>
<div class="control-row">
<label>Message:</label>
<textarea id="messageInput" rows="4" placeholder="Write your birthday message..."></textarea>
</div>
<div class="control-row">
<label>Upload photo (optional):</label>
<input id="photoInput" type="file" accept="image/*" />
</div>
<div class="control-row">
<label>Background color:</label>
<input id="bgColor" type="color" value="#ffefd5" />
</div>
<div class="control-row buttons">
<button id="downloadBtn">Download PNG</button>
<button id="printBtn">Print</button>
<button id="resetBtn">Reset</button>
</div>
</section>
<section class="preview">
<h2>Preview</h2>
<div id="card" class="card classic">
<div class="card-image-wrap">
<img id="cardImage" src="" alt="" />
<div id="imagePlaceholder">Add photo</div>
</div>
<div class="card-content">
<h1 id="cardTitle">Happy Birthday</h1>
<h3 id="cardRecipient"></h3>
<p id="cardMessage">Wishing you a wonderful birthday and a year full of joy!</p>
</div>
</div>
</section>
</main>
<footer>
<small>Simple birthday card maker — edit and download</small>
</footer>
</div>
<!-- html2canvas for export -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="script.js"></script>
</body>
</html>
```
style.css
(put this content into a file named style.css)
```
:root{
--app-bg: #f7f7f9;
--control-bg: #ffffff;
--card-w: 600px;
--card-h: 400px;
--accent: #ff6b6b;
}
*{box-sizing:border-box}
body{
margin:0;
font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial;
background:var(--app-bg);
color:#222;
}
.app{
max-width:1100px;
margin:24px auto;
padding:18px;
}
header h1{margin:0 0 12px 0}
main{
display:flex;
gap:20px;
align-items:flex-start;
}
.controls{
width:360px;
background:var(--control-bg);
padding:16px;
border-radius:8px;
box-shadow:0 2px 8px rgba(0,0,0,0.06);
}
.control-row{
margin-bottom:12px;
display:flex;
flex-direction:column;
}
.control-row label{
font-weight:600;
margin-bottom:6px;
}
.control-row input[type="text"],
.control-row select,
.control-row textarea,
.control-row input[type="color"]{
padding:8px;
border-radius:6px;
border:1px solid #ddd;
font-size:14px;
}
.control-row.buttons{
display:flex;
gap:8px;
}
button{
padding:10px 12px;
border-radius:6px;
border: none;
background:var(--accent);
color:#fff;
cursor:pointer;
}
button:hover{opacity:0.95}
.preview{
flex:1;
}
.preview h2{margin-top:0}
.card{
width:var(--card-w);
height:var(--card-h);
border-radius:12px;
box-shadow:0 8px 30px rgba(0,0,0,0.12);
overflow:hidden;
display:flex;
flex-direction:column;
align-items:stretch;
background:linear-gradient(180deg,#fff,#fff);
}
/* image area */
.card-image-wrap{
height:45%;
background:#f0f0f0;
position:relative;
display:flex;
align-items:center;
justify-content:center;
overflow:hidden;
}
.card-image-wrap img{
max-width:100%;
max-height:100%;
display:block;
}
#imagePlaceholder{
position:absolute;
color:#666;
font-weight:600;
}
/* content area */
.card-content{
padding:18px;
text-align:center;
display:flex;
flex-direction:column;
justify-content:center;
gap:6px;
height:55%;
}
.card-content h1{
margin:0;
font-size:28px;
letter-spacing:0.5px;
}
.card-content h3{
margin:0;
font-weight:600;
color:#444;
}
.card-content p{
margin:6px 0 0 0;
color:#333;
}
/* template variations */
.card.classic{ background:linear-gradient(180deg,#fff7ec,#fff) }
.card.modern{ background:linear-gradient(180deg,#e7f7ff,#ffffff) }
.card.party{ background:linear-gradient(180deg,#fff0fb,#fff) }
/* small screens */
@media (max-width:900px){
main{flex-direction:column}
.controls{width:100%}
.card{width:100%; max-width:600px}
}
```
script.js
(put this content into a file named script.js)
```
const templateSelect = document.getElementById('templateSelect');
const recipientInput = document.getElementById('recipientInput');
const messageInput = document.getElementById('messageInput');
const photoInput = document.getElementById('photoInput');
const bgColorInput = document.getElementById('bgColor');
const card = document.getElementById('card');
const cardTitle = document.getElementById('cardTitle');
const cardRecipient = document.getElementById('cardRecipient');
const cardMessage = document.getElementById('cardMessage');
const cardImage = document.getElementById('cardImage');
const imagePlaceholder = document.getElementById('imagePlaceholder');
const downloadBtn = document.getElementById('downloadBtn');
const printBtn = document.getElementById('printBtn');
const resetBtn = document.getElementById('resetBtn');
// Initialize
function applyTemplate(t){
card.classList.remove('classic','modern','party');
card.classList.add(t);
}
applyTemplate(templateSelect.value);
// Events
templateSelect.addEventListener('change', e => {
applyTemplate(e.target.value);
});
recipientInput.addEventListener('input', e => {
const v = e.target.value.trim();
cardRecipient.textContent = v ? `Dear ${v},` : '';
});
messageInput.addEventListener('input', e => {
cardMessage.textContent = e.target.value || 'Wishing you a wonderful birthday and a year full of joy!';
});
bgColorInput.addEventListener('input', e => {
const color = e.target.value;
card.style.background = color;
// if you want to keep templates' look, comment the above line and use CSS templates
});
// Photo upload
photoInput.addEventListener('change', e=>{
const file = e.target.files[0];
if(!file) return;
const reader = new FileReader();
reader.onload = function(ev){
cardImage.src = ev.target.result;
cardImage.style.display = 'block';
imagePlaceholder.style.display = 'none';
};
reader.readAsDataURL(file);
});
// Download using html2canvas
downloadBtn.addEventListener('click', async () => {
// temporarily remove controls or scale adjustments if needed
const oldTransform = card.style.transform;
// increase scale for better resolution
const scale = 2;
const origWidth = card.offsetWidth;
const origHeight = card.offsetHeight;
// Use html2canvas
html2canvas(card, { scale: scale, useCORS: true }).then(canvas=>{
const link = document.createElement('a');
link.download = `birthday-card.png`;
link.href = canvas.toDataURL('image/png');
link.click();
}).catch(err=>{
alert('Error exporting image: ' + err.message);
}).finally(()=>{
card.style.transform = oldTransform;
});
});
printBtn.addEventListener('click', () => {
// open new window with only the card for printing
html2canvas(card, { scale: 2, useCORS:true }).then(canvas=>{
const dataUrl = canvas.toDataURL('image/png');
const w = window.open('');
w.document.write('<img src="'+dataUrl+'" style="max-width:100%;"/>');
w.document.title = 'Print birthday card';
w.focus();
w.print();
});
});
resetBtn.addEventListener('click', () => {
recipientInput.value = '';
messageInput.value = '';
photoInput.value = '';
cardImage.src = '';
cardImage.style.display = 'none';
imagePlaceholder.style.display = 'block';
applyTemplate('classic');
bgColorInput.value = '#ffefd5';
card.style.background = '';
cardRecipient.textContent = '';
cardMessage.textContent = 'Wishing you a wonderful birthday and a year full of joy!';
});
```
How to run
- Place the three files in the same folder.
- Open index.html in a modern browser (Chrome, Firefox, Edge).
- Edit fields, upload a photo, choose template, then click "Download PNG".
Notes and next steps (optional enhancements)
- Save/share: add a backend to save cards (e.g., Node/Express + S3 / database) and generate shareable links.
- Templates: add more templates, fonts, sticker/emoji overlays, and drag/resize of the uploaded image (use interact.js or fabric.js).
- Mobile app: wrap in Capacitor or build with React Native / Flutter for push notifications and scheduled sending.
- Email/schedule: add server-side scheduling (e.g., cron jobs, queue) to email the card on a selected date.
- Higher-resolution export: render on a larger off-screen canvas for print-quality output or use vector templates.
If you want, I can:
- Extend this to let users position/resize images and text.
- Add social sharing (Facebook, Twitter, WhatsApp).
- Turn it into a small React app or mobile app template (React Native / Flutter).
Tell me which direction you prefer and I’ll continue.
Submit Your Answer
We prioritize human answers over AI answers.
If you are human, and you can answer this question, please submit your answer.