Google Business Profile Posts Generator
/* Reset and base styles scoped to prevent conflicts */
.gbp-post-tool-container * {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.gbp-post-tool-container {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
position: relative;
}
.gbp-post-tool-header {
text-align: center;
margin-bottom: 30px;
}
.gbp-post-tool-header h1 {
color: #1a73e8;
font-size: 28px;
font-weight: 700;
margin-bottom: 10px;
}
.gbp-post-tool-header p {
color: #5f6368;
font-size: 16px;
line-height: 1.5;
}
.gbp-post-tool-form {
display: flex;
flex-direction: column;
gap: 20px;
}
.gbp-post-tool-field {
display: flex;
flex-direction: column;
gap: 8px;
}
.gbp-post-tool-label {
font-weight: 600;
color: #202124;
font-size: 14px;
}
.gbp-post-tool-label .required {
color: #ea4335;
margin-left: 2px;
}
.gbp-post-tool-input,
.gbp-post-tool-textarea,
.gbp-post-tool-select {
padding: 12px 16px;
border: 2px solid #e8eaed;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
background: #ffffff;
color: #202124;
}
.gbp-post-tool-input:focus,
.gbp-post-tool-textarea:focus,
.gbp-post-tool-select:focus {
outline: none;
border-color: #1a73e8;
box-shadow: 0 0 0 3px rgba(26, 115, 232, 0.1);
}
.gbp-post-tool-textarea {
resize: vertical;
min-height: 80px;
font-family: inherit;
}
.gbp-post-tool-number-field {
display: flex;
align-items: center;
gap: 12px;
padding: 16px 20px;
background: #f8f9fa;
border-radius: 8px;
border: 2px solid #e8eaed;
}
.gbp-post-tool-number-input {
width: 80px;
padding: 8px 12px;
border: 1px solid #dadce0;
border-radius: 6px;
font-size: 16px;
text-align: center;
}
.gbp-post-tool-button {
padding: 14px 24px;
background: linear-gradient(135deg, #1a73e8 0%, #4285f4 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin-top: 10px;
}
.gbp-post-tool-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(26, 115, 232, 0.3);
}
.gbp-post-tool-button:active {
transform: translateY(0);
}
.gbp-post-tool-button:disabled {
background: #dadce0;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.gbp-post-tool-loading {
display: none;
text-align: center;
padding: 20px;
color: #5f6368;
}
.gbp-post-tool-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #e8eaed;
border-top: 2px solid #1a73e8;
border-radius: 50%;
animation: gbp-spin 1s linear infinite;
margin-right: 10px;
}
.gbp-post-tool-progress {
margin-top: 15px;
font-size: 14px;
color: #5f6368;
}
.gbp-post-tool-progress-bar {
width: 100%;
height: 6px;
background: #e8eaed;
border-radius: 3px;
margin: 10px 0;
overflow: hidden;
}
.gbp-post-tool-progress-fill {
height: 100%;
background: linear-gradient(90deg, #1a73e8, #4285f4);
width: 0%;
transition: width 0.3s ease;
border-radius: 3px;
}
.gbp-post-tool-countdown {
font-size: 16px;
font-weight: 600;
color: #1a73e8;
margin-top: 10px;
}
@keyframes gbp-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.gbp-post-tool-results {
margin-top: 30px;
display: none;
}
.gbp-post-tool-results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.gbp-post-tool-results-title {
font-size: 20px;
font-weight: 600;
color: #202124;
}
.gbp-post-tool-download-all {
padding: 10px 20px;
background: #34a853;
color: white;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background 0.3s ease;
}
.gbp-post-tool-download-all:hover {
background: #2d8f44;
}
.gbp-post-tool-post {
background: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin-bottom: 16px;
border: 1px solid #e8eaed;
position: relative;
}
.gbp-post-tool-post-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.gbp-post-tool-post-number {
font-size: 14px;
font-weight: 600;
color: #5f6368;
}
.gbp-post-tool-copy-btn {
padding: 8px 16px;
background: #1a73e8;
color: white;
border: none;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 6px;
}
.gbp-post-tool-copy-btn:hover {
background: #1557b0;
}
.gbp-post-tool-copy-btn.copied {
background: #34a853;
}
.gbp-post-tool-post-content {
font-size: 16px;
line-height: 1.6;
color: #202124;
white-space: pre-wrap;
}
.gbp-post-tool-error {
background: #fce8e6;
color: #d93025;
padding: 16px;
border-radius: 8px;
margin-top: 20px;
border: 1px solid #f28b82;
}
.gbp-post-tool-error-title {
font-weight: 600;
margin-bottom: 8px;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.gbp-post-tool-container {
margin: 10px;
padding: 16px;
}
.gbp-post-tool-header h1 {
font-size: 24px;
}
.gbp-post-tool-results-header {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.gbp-post-tool-post-header {
flex-direction: column;
gap: 10px;
align-items: stretch;
}
.gbp-post-tool-number-field {
flex-direction: column;
align-items: stretch;
text-align: center;
}
}
/* Validation styles */
.gbp-post-tool-field.error .gbp-post-tool-input {
border-color: #ea4335;
}
.gbp-post-tool-field-error {
color: #ea4335;
font-size: 12px;
margin-top: 4px;
}
Generate
post(s)
class GBPPostGenerator {
constructor() {
this.form = document.getElementById('gbp-form');
this.loadingDiv = document.getElementById('loading');
this.resultsDiv = document.getElementById('results');
this.errorDiv = document.getElementById('error');
this.generateBtn = document.getElementById('generate-btn');
this.downloadAllBtn = document.getElementById('download-all-btn');
this.postsContainer = document.getElementById('posts-container');
this.generatedPosts = [];
this.initializeEventListeners();
}
initializeEventListeners() {
this.form.addEventListener('submit', (e) => this.handleSubmit(e));
this.downloadAllBtn.addEventListener('click', () => this.downloadAllPosts());
}
handleSubmit(e) {
e.preventDefault();
if (!this.validateForm()) {
return;
}
this.generatePosts();
}
validateForm() {
const businessName = document.getElementById('business-name').value.trim();
const numberOfPosts = parseInt(document.getElementById('number-of-posts').value);
let isValid = true;
// Clear previous errors
this.clearErrors();
// Validate business name
if (!businessName) {
this.showFieldError('business-name', 'Business name is required');
isValid = false;
}
// Validate number of posts
if (!numberOfPosts || numberOfPosts 5) {
this.showFieldError('number-of-posts', 'Please select between 1 and 5 posts');
isValid = false;
}
return isValid;
}
clearErrors() {
const errorElements = document.querySelectorAll('.gbp-post-tool-field-error');
errorElements.forEach(el => el.textContent = '');
const fieldElements = document.querySelectorAll('.gbp-post-tool-field');
fieldElements.forEach(el => el.classList.remove('error'));
this.errorDiv.style.display = 'none';
}
showFieldError(fieldId, message) {
const field = document.getElementById(fieldId);
const errorElement = document.getElementById(`${fieldId}-error`);
if (field && errorElement) {
field.parentElement.classList.add('error');
errorElement.textContent = message;
}
}
showError(message) {
document.getElementById('error-message').textContent = message;
this.errorDiv.style.display = 'block';
}
async generatePosts() {
const formData = new FormData(this.form);
const businessName = formData.get('businessName');
const serviceKeyword = formData.get('serviceKeyword');
const pageContent = formData.get('pageContent');
const customInstructions = formData.get('customInstructions');
const numberOfPosts = parseInt(formData.get('numberOfPosts'));
// Show loading state
this.showLoading(true);
this.resultsDiv.style.display = 'none';
this.errorDiv.style.display = 'none';
// Initialize progress tracking
this.initializeProgress(numberOfPosts);
try {
this.generatedPosts = [];
// Generate posts one by one
for (let i = 0; i {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
if (minutes > 0) {
countdownElement.textContent = `Estimated time: ${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
} else {
countdownElement.textContent = `Estimated time: ${remainingSeconds}s`;
}
seconds--;
if (seconds {
const postElement = this.createPostElement(post, index + 1);
this.postsContainer.appendChild(postElement);
});
this.resultsDiv.style.display = 'block';
}
createPostElement(postContent, postNumber) {
const postDiv = document.createElement('div');
postDiv.className = 'gbp-post-tool-post';
postDiv.innerHTML = `
${postContent}
`;
return postDiv;
}
async copyPost(index) {
const post = this.generatedPosts[index];
const copyBtn = document.querySelectorAll('.gbp-post-tool-copy-btn')[index];
try {
await navigator.clipboard.writeText(post);
// Visual feedback
const originalText = copyBtn.textContent;
copyBtn.textContent = '✅ Copied!';
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.textContent = originalText;
copyBtn.classList.remove('copied');
}, 2000);
} catch (err) {
console.error('Failed to copy: ', err);
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = post;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
copyBtn.textContent = '✅ Copied!';
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.textContent = '📋 Copy Post';
copyBtn.classList.remove('copied');
}, 2000);
}
}
downloadAllPosts() {
if (this.generatedPosts.length === 0) {
return;
}
const businessName = document.getElementById('business-name').value.trim();
const timestamp = new Date().toISOString().slice(0, 10);
const filename = `${businessName.replace(/[^a-z0-9]/gi, '_')}_GBP_Posts_${timestamp}.txt`;
let content = `Google Business Profile Posts - ${businessName}\n`;
content += `Generated on: ${new Date().toLocaleDateString()}\n`;
content += `Total Posts: ${this.generatedPosts.length}\n`;
content += '='.repeat(50) + '\n\n';
this.generatedPosts.forEach((post, index) => {
content += `POST ${index + 1}:\n`;
content += post.trim() + '\n\n';
content += '-'.repeat(30) + '\n\n';
});
// Create and download file
const blob = new Blob([content], { type: 'text/plain' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
}
// Initialize the generator when the page loads
let gbpGenerator;
document.addEventListener('DOMContentLoaded', () => {
gbpGenerator = new GBPPostGenerator();
});