hms / index.html
deepak191z's picture
Update index.html
f75fa0e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Google Apps Script Generator</title>
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
<style>
/* Base body padding for fixed header */
body {
padding-top: 5rem; /* Start with a base padding */
}
/* Hero section base style */
#heroSection {
display: flex; /* Use flex by default */
transition: opacity 0.3s ease-out, max-height 0.3s ease-out; /* Add transition */
opacity: 1;
max-height: 500px; /* Estimate max height */
overflow: hidden;
}
/* Style to hide hero section smoothly */
#heroSection.hidden-section {
opacity: 0;
max-height: 0;
padding-top: 0;
padding-bottom: 0;
margin-bottom: 0;
/* display: none; /* Re-add if transition is not desired or causes layout shifts */
}
/* Progress steps base style */
#progressSteps {
display: flex; /* Use flex by default */
transition: opacity 0.3s ease-out, max-height 0.3s ease-out; /* Add transition */
opacity: 1;
max-height: 100px; /* Estimate max height */
overflow: hidden;
}
/* Style to hide steps smoothly */
#progressSteps.hidden-section {
opacity: 0;
max-height: 0;
margin-bottom: 0;
/* display: none; */
}
.code-block {
font-family: 'Courier New', Courier, monospace;
white-space: pre-wrap;
background: #000000;
color: #e2e8f0;
padding: 1rem;
border-radius: 0.5rem;
height: calc(80vh - 22rem); /* Adjusted height slightly */
min-height: 150px; /* Adjusted min-height */
overflow-y: auto;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.section { display: none; }
.section.active { display: block; }
.input-field {
transition: border-color 0.2s ease, box-shadow 0.2s ease;
background: rgba(255, 255, 255, 0.25);
color: #1e293b;
border: 1px solid rgba(255, 255, 255, 0.4);
width: 100%;
padding: 0.65rem 0.75rem; /* Adjusted padding slightly */
border-radius: 0.375rem; /* Standard Tailwind rounded-md */
}
.input-field::placeholder { color: #4b5563; opacity: 1; }
.input-field:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.4);
background: rgba(255, 255, 255, 0.35);
}
.btn {
transition: background-color 0.2s ease, transform 0.1s ease, box-shadow 0.1s ease;
backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 0.75rem 1.25rem; /* Default padding */
border-radius: 0.375rem; /* Standard Tailwind rounded-md */
font-weight: 500; /* Medium weight */
text-align: center;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.btn:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
/* Specific Button Colors */
.btn-blue { background: #2563eb; color: white; } .btn-blue:hover { background: #1d4ed8; }
.btn-green { background: #16a34a; color: white; } .btn-green:hover { background: #15803d; }
.btn-gray-dark { background: #374151; color: white; } .btn-gray-dark:hover { background: #1f2937; }
.btn-gray { background: #4b5563; color: white; } .btn-gray:hover { background: #374151; }
.btn-red { background: #dc2626; color: white; } .btn-red:hover { background: #b91c1c; }
.btn-light { background: #e5e7eb; color: #1f2937; } .btn-light:hover { background: #d1d5db; }
.btn-light-active { background: #dbeafe; color: #1e40af; } /* For active cURL button */
/* Small icon button style (e.g., delete, copy) */
.btn-icon {
padding: 0.5rem; /* Smaller padding for icons */
flex-shrink: 0; /* Prevent shrinking */
line-height: 1; /* Ensure icon aligns well */
}
.btn-icon svg {
width: 1.25rem; /* w-5 */
height: 1.25rem; /* h-5 */
}
.step-indicator {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.2);
width: 2.5rem; /* w-10 */
height: 2.5rem; /* h-10 */
border-radius: 9999px; /* rounded-full */
display: flex;
align-items: center;
justify-content: center;
font-weight: 600; /* semibold */
color: #4b5563; /* gray-600 text */
transition: all 0.3s ease-in-out;
}
.step-indicator.active {
background: rgba(59, 130, 246, 0.9);
color: white;
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3);
}
.step-indicator.completed { /* Style for completed steps */
background: rgba(22, 163, 74, 0.8); /* Green */
color: white;
}
.glass-container {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.25);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
border-radius: 0.75rem; /* rounded-xl */
padding: 1.5rem; /* Default padding */
}
/* --- Mobile-specific styles --- */
@media (max-width: 640px) {
body {
padding-top: 4.5rem; /* Adjust for potentially smaller header */
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.glass-container {
padding: 1rem; /* Reduce padding slightly */
}
.code-block {
height: calc(70vh - 15rem); /* Adjust height calc for mobile */
padding: 0.75rem;
min-height: 120px;
}
/* Input row layout */
.column-input-row {
flex-direction: row; /* Keep input and button in a row */
align-items: center;
gap: 0.75rem; /* space-x-3 equivalent */
}
.column-input-row input {
flex-grow: 1; /* Allow input to take space */
}
.column-input-row .btn-icon {
/* Delete button already has flex-shrink-0 */
}
/* Button container for main actions */
.button-container-mobile-stack {
display: flex;
flex-direction: column;
width: 100%;
gap: 0.75rem; /* space-y-3 */
}
.button-container-mobile-stack .btn {
width: 100%; /* Make buttons full width */
}
/* Make specific containers stack buttons */
#columns .button-container,
#code .button-container,
#howto .button-container {
flex-direction: column;
gap: 0.75rem;
}
#columns .button-container .btn,
#code .button-container .btn,
#howto .button-container .btn {
width: 100%; /* Ensure buttons inside stack full width */
margin-left: 0 !important; /* Override potential sm: space-x */
}
.step-indicator {
width: 2.25rem; height: 2.25rem; /* Slightly smaller */
font-size: 0.875rem; /* text-sm */
}
/* Adjust heading sizes for mobile */
.text-4xl { font-size: 1.875rem; line-height: 2.25rem; } /* text-3xl */
.text-2xl { font-size: 1.25rem; line-height: 1.75rem; } /* text-xl */
.text-xl { font-size: 1.125rem; line-height: 1.75rem; } /* text-lg */
.text-lg { font-size: 1rem; line-height: 1.5rem; } /* text-base */
/* Adjust margins */
.mb-12 { margin-bottom: 2rem; } /* mb-8 */
.mb-8 { margin-bottom: 1.5rem; } /* mb-6 */
.mb-6 { margin-bottom: 1rem; } /* mb-4 */
.mt-6 { margin-top: 1rem; } /* mt-4 */
.py-16 { padding-top: 2.5rem; padding-bottom: 2.5rem; } /* py-10 */
/* cURL buttons adjustments */
#howto .flex-wrap {
gap: 0.5rem; /* gap-2 */
}
#howto .flex-wrap .btn {
padding: 0.5rem 0.75rem; /* Smaller padding */
font-size: 0.875rem; /* text-sm */
}
/* Copy button on mobile */
#code .flex > .btn-icon {
/* padding: 0.6rem; /* Slightly larger tap area if needed */
}
}
/* Larger screen adjustments */
@media (min-width: 641px) {
body {
padding-top: 6rem; /* Restore larger padding */
padding-left: 1rem;
padding-right: 1rem;
}
.glass-container {
padding: 2rem; /* Restore larger padding */
}
/* Restore row layout for buttons on desktop */
#columns .button-container,
#code .button-container {
flex-direction: row;
justify-content: space-between;
gap: 1rem; /* space-x-4 */
}
#columns .button-container .btn,
#code .button-container .btn {
width: auto; /* Allow buttons to size naturally */
}
/* How-to back button on desktop */
#howto .button-container {
justify-content: flex-start;
flex-direction: row; /* Ensure it's row */
}
#howto .button-container .btn {
width: auto;
}
}
</style>
</head>
<body class="bg-gradient-to-br from-gray-200 via-gray-300 to-gray-400 min-h-screen font-sans text-gray-800">
<header class="fixed top-0 left-0 w-full bg-white shadow-md p-4 z-50">
<div class="max-w-6xl mx-auto text-xl font-bold text-gray-900">GSheet2DB</div>
</header>
<section id="heroSection" class="flex flex-col justify-center items-center text-center px-6 py-16 mb-12">
<h1 class="text-4xl font-bold text-gray-900">Convert Google Sheets to a Database</h1>
<p class="text-lg text-gray-700 mt-3 max-w-2xl">
Generate Google Apps Script code to turn your spreadsheet into a simple REST API. Fast, simple, and free!
</p>
</section>
<div id="progressSteps" class="max-w-xl mx-auto flex justify-center space-x-4 mb-8 px-4">
<div data-step="columns" class="step-indicator">1</div>
<div data-step="code" class="step-indicator">2</div>
<div data-step="howto" class="step-indicator">3</div>
</div>
<div class="max-w-4xl mx-auto glass-container mb-12">
<div id="columns" class="section active">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 text-center">Step 1: Define Your Columns</h2>
<div id="columnInputs" class="space-y-4 mb-6">
<div class="flex items-center space-x-3 column-input-row">
<input type="text" class="column-input input-field flex-1" placeholder="Column name (e.g., Status)" value="word">
<button onclick="removeColumn(this)" class="btn btn-icon btn-red" aria-label="Remove column">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
</button>
</div>
<div class="flex items-center space-x-3 column-input-row">
<input type="text" class="column-input input-field flex-1" placeholder="Column name (e.g., Category)" value="meaning">
<button onclick="removeColumn(this)" class="btn btn-icon btn-red" aria-label="Remove column">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
</button>
</div>
</div>
<div class="mt-6 button-container"> <button onclick="addColumn()" class="btn btn-blue w-full sm:w-auto">Add Column</button>
<button onclick="nextSection('code')" class="btn btn-green w-full sm:w-auto">Next: Generate Code</button>
</div>
</div>
<div id="code" class="section">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 text-center">Step 2: Generated Apps Script Code</h2>
<div class="flex flex-col sm:flex-row justify-between items-center mb-4 gap-3 sm:gap-0"> <h3 class="text-xl font-semibold text-gray-800">Code Preview</h3>
<button onclick="copyCode()" class="btn btn-icon btn-gray-dark self-end sm:self-center" title="Copy to clipboard" aria-label="Copy code to clipboard">
<svg class="w-6 h-6 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V7a2 2 0 00-2-2h-2M8 5a2 2 0 002 2h4a2 2 0 002-2M8 5a2 2 0 012-2h4a2 2 0 012 2"></path></svg>
<span class="sr-only">Copy Code</span>
</button>
</div>
<div id="codePreview" class="code-block mb-6"></div>
<div class="mt-6 button-container"> <button onclick="nextSection('columns')" class="btn btn-gray w-full sm:w-auto">Back</button>
<button onclick="nextSection('howto')" class="btn btn-green w-full sm:w-auto">Next: How to Use</button>
</div>
</div>
<div id="howto" class="section">
<h2 class="text-2xl font-extrabold text-gray-900 mb-6 text-center">Step 3: How to Use the API</h2>
<h3 class="text-lg font-semibold text-gray-800 mb-3">Example cURL Commands:</h3>
<div class="flex flex-wrap gap-2 mb-6 pb-2">
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('appendSingle', this)">Append Single</button>
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('appendMultiple', this)">Append Multiple</button>
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('fetchAll', this)">Fetch All</button>
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('fetchRange', this)">Fetch Range</button>
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('search', this)">Search</button>
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('update', this)">Update</button>
<button class="curl-button btn btn-light text-sm px-3 py-1.5" onclick="showCurlExample('delete', this)">Delete</button>
</div>
<div id="curlExamples" class="code-block mb-6"></div>
<div class="mt-6 flex justify-start button-container"> <button onclick="nextSection('code')" class="btn btn-gray w-full sm:w-auto">Back</button>
</div>
</div>
</div>
<section class="px-4 py-16 max-w-5xl mx-auto">
<h2 class="text-3xl font-semibold text-center mb-10">Why Use This Tool?</h2>
<div class="grid gap-8 md:grid-cols-3 text-center">
<div>
<div class="text-4xl mb-4"></div>
<h3 class="text-xl font-medium mb-2">Fast Setup</h3>
<p class="text-gray-600 text-sm">Turn your Google Sheet into a REST API in under a minute. No server, no hosting required.</p>
</div>
<div>
<div class="text-4xl mb-4">🧠</div>
<h3 class="text-xl font-medium mb-2">No Coding Needed</h3>
<p class="text-gray-600 text-sm">Generate the exact Google Apps Script code you need—just copy and paste.</p>
</div>
<div>
<div class="text-4xl mb-4">💸</div>
<h3 class="text-xl font-medium mb-2">Completely Free</h3>
<p class="text-gray-600 text-sm">No signup, no cost, no limits. Just paste your spreadsheet and go.</p>
</div>
</div>
</section>
<!-- FAQ Section -->
<section class="px-4 py-16 max-w-2xl mx-auto">
<h2 class="text-3xl font-semibold text-center mb-10">FAQs</h2>
<div class="space-y-4">
<!-- FAQ Item -->
<div>
<button class="w-full text-left flex justify-between items-center text-lg font-medium faq-toggle">
<span>What does this tool do?</span>
<svg class="w-5 h-5 transition-transform duration-200" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M6 9l6 6 6-6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div class="mt-2 text-gray-600 hidden text-sm faq-content">
It generates Google Apps Script code to convert your spreadsheet into a REST API.
</div>
</div>
<div>
<button class="w-full text-left flex justify-between items-center text-lg font-medium faq-toggle">
<span>Is it really free?</span>
<svg class="w-5 h-5 transition-transform duration-200" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M6 9l6 6 6-6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div class="mt-2 text-gray-600 hidden text-sm faq-content">
Yes, it's completely free. No signups, no limits.
</div>
</div>
<div>
<button class="w-full text-left flex justify-between items-center text-lg font-medium faq-toggle">
<span>Do I need to know coding?</span>
<svg class="w-5 h-5 transition-transform duration-200" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M6 9l6 6 6-6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div class="mt-2 text-gray-600 hidden text-sm faq-content">
Nope. Just copy the generated code and paste it into your Apps Script editor.
</div>
</div>
</div>
</section>
<!-- FAQ Toggle Script -->
<script>
document.querySelectorAll('.faq-toggle').forEach(button => {
button.addEventListener('click', () => {
const content = button.nextElementSibling;
const icon = button.querySelector('svg');
const isOpen = !content.classList.contains('hidden');
// Close all
document.querySelectorAll('.faq-content').forEach(el => el.classList.add('hidden'));
document.querySelectorAll('.faq-toggle svg').forEach(i => i.classList.remove('rotate-180'));
// Open if not already open
if (!isOpen) {
content.classList.remove('hidden');
icon.classList.add('rotate-180');
}
});
});
</script>
<script>
function nextSection(sectionId) {
// Toggle section visibility
document.querySelectorAll('.section').forEach(section => section.classList.remove('active'));
document.getElementById(sectionId).classList.add('active');
// Update step indicators
const steps = ['columns', 'code', 'howto'];
const currentStep = steps.indexOf(sectionId);
document.querySelectorAll('.step-indicator').forEach((indicator, index) => {
indicator.classList.toggle('active', index === currentStep);
indicator.classList.toggle('completed', index < currentStep); // Optional: mark previous steps as completed
});
// Show hero section only on the first step (columns)
const heroSection = document.getElementById('heroSection');
if (sectionId === 'columns') {
heroSection.classList.remove('hidden-section');
} else {
heroSection.classList.add('hidden-section');
}
}
// Initialize the first step as active
document.querySelector('.step-indicator[data-step="columns"]').classList.add('active');
</script>
<script src="script.js"></script>
</body>
</html>