Paste your Google Apps Script Web App URL below to connect your Drive JSON storage.
Available for new projects
I Build Things for the Web.
// Full-stack developer crafting digital experiences from concept to deployment. Clean code. Real results.
01
Projects
0
Total
0
Websites
0
Web Apps
0
Other
{}
// Connecting to Google Drive... Set up your backend to get started.
โ
Admin Panel
Not connected
// Add New Project
// Loading preview...
Saving to Drive...
// Manage Projects (stored in Drive)
// Admin Access
This area is private. Enter credentials.
// Access denied. Check credentials.
// Google Apps Script Setup (5 min)
1
Go to script.google.com โ click New Project
2
Delete all existing code, paste the script below, click Save
3
Click Deploy โ New Deployment โ Web App
4
Set Execute as: Me | Who has access: Anyone โ Deploy
5
Copy the Web App URL and paste it in the portfolio Connect box
// ============================================
// PASTE THIS INTO Google Apps Script
// script.google.com โ New Project
// ============================================
const FILE_NAME = 'portfolio_projects.json';
const SECRET_KEY = 'my_secret_2024'; // Change this!
function getOrCreateFile() {
const files = DriveApp.getFilesByName(FILE_NAME);
if (files.hasNext()) return files.next();
const file = DriveApp.createFile(FILE_NAME, '[]', MimeType.PLAIN_TEXT);
return file;
}
function doGet(e) {
const params = e.parameter;
const key = params.key;
if (key !== SECRET_KEY) {
return ContentService.createTextOutput(
JSON.stringify({ error: 'Unauthorized' })
).setMimeType(ContentService.MimeType.JSON);
}
const file = getOrCreateFile();
const data = file.getBlob().getDataAsString();
return ContentService.createTextOutput(data)
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
const body = JSON.parse(e.postData.contents);
const key = body.key;
if (key !== SECRET_KEY) {
return ContentService.createTextOutput(
JSON.stringify({ error: 'Unauthorized' })
).setMimeType(ContentService.MimeType.JSON);
}
const action = body.action;
// Upload image (base64 data URL) and return file URL
if (action === 'upload') {
try {
const imgData = body.image.replace(/^data:image\/[^;]+;base64,/, '');
const contentTypeMatch = body.image.match(/^data:(image\/[^;]+);base64,/);
const contentType = contentTypeMatch ? contentTypeMatch[1] : 'image/png';
const bytes = Utilities.base64Decode(imgData);
const blob = Utilities.newBlob(bytes, contentType, body.filename || 'upload.png');
const file = DriveApp.createFile(blob);
// Make the file accessible by anyone with the link
try { file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW); } catch(e) {}
return ContentService.createTextOutput(JSON.stringify({ success: true, fileUrl: file.getUrl() })).setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService.createTextOutput(JSON.stringify({ error: String(err) })).setMimeType(ContentService.MimeType.JSON);
}
}
const file = getOrCreateFile();
let projects = JSON.parse(file.getBlob().getDataAsString());
if (action === 'add') {
projects.unshift(body.project);
} else if (action === 'update') {
projects = projects.map(p =>
p.id === body.project.id ? body.project : p
);
} else if (action === 'delete') {
projects = projects.filter(p => p.id !== body.id);
}
file.setContent(JSON.stringify(projects, null, 2));
return ContentService.createTextOutput(
JSON.stringify({ success: true, count: projects.length })
).setMimeType(ContentService.MimeType.JSON);
}
// Note: Change SECRET_KEY in the script to match the one in the portfolio settings. Your JSON file will appear in your Google Drive as portfolio_projects.json