content-calendar-v1 / index.html
JayStormX8's picture
Add 3 files
7a961df verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real Estate Content Calendar Pro</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#4F46E5',
secondary: '#10B981',
accent: '#F59E0B',
dark: '#1F2937',
light: '#F3F4F6'
}
}
}
}
</script>
<style>
.timeline-connector {
position: absolute;
left: 24px;
top: 36px;
bottom: -12px;
width: 2px;
background-color: #E5E7EB;
}
.draggable {
cursor: move;
}
.draggable.dragging {
opacity: 0.5;
background-color: #E5E7EB;
}
.platform-tag {
font-size: 0.7rem;
padding: 0.2rem 0.4rem;
border-radius: 0.25rem;
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="mb-8">
<div class="flex justify-between items-center">
<div>
<h1 class="text-3xl font-bold text-dark">Content Calendar Pro</h1>
<p class="text-gray-600">30-Day Real Estate Content Planner</p>
</div>
<div class="flex items-center space-x-4">
<button id="aiSuggestBtn" class="bg-primary hover:bg-primary-dark text-white px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-magic mr-2"></i> AI Suggestions
</button>
<button id="exportBtn" class="border border-primary text-primary hover:bg-primary hover:text-white px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-file-export mr-2"></i> Export
</button>
</div>
</div>
</header>
<!-- Main Content -->
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
<!-- Left Sidebar -->
<div class="lg:col-span-1 bg-white rounded-xl shadow p-6 h-fit">
<h2 class="text-xl font-semibold mb-4 text-dark">Content Library</h2>
<div class="mb-6">
<h3 class="font-medium text-gray-700 mb-2">Content Types</h3>
<div class="space-y-2">
<div class="draggable bg-light p-3 rounded-lg border border-gray-200" draggable="true" data-type="property-showcase">
<div class="flex items-center">
<i class="fas fa-home text-accent mr-3"></i>
<span>Property Showcase</span>
</div>
</div>
<div class="draggable bg-light p-3 rounded-lg border border-gray-200" draggable="true" data-type="market-update">
<div class="flex items-center">
<i class="fas fa-chart-line text-secondary mr-3"></i>
<span>Market Update</span>
</div>
</div>
<div class="draggable bg-light p-3 rounded-lg border border-gray-200" draggable="true" data-type="client-testimonial">
<div class="flex items-center">
<i class="fas fa-quote-left text-primary mr-3"></i>
<span>Client Testimonial</span>
</div>
</div>
<div class="draggable bg-light p-3 rounded-lg border border-gray-200" draggable="true" data-type="neighborhood-guide">
<div class="flex items-center">
<i class="fas fa-map-marked-alt text-green-500 mr-3"></i>
<span>Neighborhood Guide</span>
</div>
</div>
<div class="draggable bg-light p-3 rounded-lg border border-gray-200" draggable="true" data-type="home-tips">
<div class="flex items-center">
<i class="fas fa-lightbulb text-yellow-500 mr-3"></i>
<span>Home Tips</span>
</div>
</div>
</div>
</div>
<div class="mb-6">
<h3 class="font-medium text-gray-700 mb-2">Time Blocks</h3>
<div class="grid grid-cols-2 gap-2">
<div class="draggable bg-light p-2 rounded-lg border border-gray-200 text-center" draggable="true" data-time="15">
<span>15 min</span>
</div>
<div class="draggable bg-light p-2 rounded-lg border border-gray-200 text-center" draggable="true" data-time="30">
<span>30 min</span>
</div>
<div class="draggable bg-light p-2 rounded-lg border border-gray-200 text-center" draggable="true" data-time="45">
<span>45 min</span>
</div>
<div class="draggable bg-light p-2 rounded-lg border border-gray-200 text-center" draggable="true" data-time="60">
<span>1 hour</span>
</div>
</div>
</div>
<div>
<h3 class="font-medium text-gray-700 mb-2">Platforms</h3>
<div class="flex flex-wrap gap-2">
<span class="platform-tag bg-blue-100 text-blue-800 border border-blue-200">Instagram</span>
<span class="platform-tag bg-blue-600 text-white">Facebook</span>
<span class="platform-tag bg-black text-white">TikTok</span>
<span class="platform-tag bg-blue-700 text-white">LinkedIn</span>
</div>
</div>
</div>
<!-- Calendar View -->
<div class="lg:col-span-3">
<div class="bg-white rounded-xl shadow overflow-hidden">
<!-- Calendar Header -->
<div class="border-b border-gray-200 p-4">
<div class="flex justify-between items-center">
<h2 class="text-xl font-semibold text-dark">30-Day Content Plan</h2>
<div class="flex items-center space-x-2">
<button id="prevMonth" class="p-2 rounded-full hover:bg-gray-100">
<i class="fas fa-chevron-left"></i>
</button>
<span class="font-medium">June 2023</span>
<button id="nextMonth" class="p-2 rounded-full hover:bg-gray-100">
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
</div>
<!-- Days of Week -->
<div class="grid grid-cols-7 bg-gray-50 text-gray-500 text-sm font-medium">
<div class="py-2 text-center">Sun</div>
<div class="py-2 text-center">Mon</div>
<div class="py-2 text-center">Tue</div>
<div class="py-2 text-center">Wed</div>
<div class="py-2 text-center">Thu</div>
<div class="py-2 text-center">Fri</div>
<div class="py-2 text-center">Sat</div>
</div>
<!-- Calendar Grid -->
<div id="calendarGrid" class="grid grid-cols-7 gap-px bg-gray-200">
<!-- Days will be populated by JavaScript -->
</div>
</div>
<!-- Timeline View -->
<div class="mt-6 bg-white rounded-xl shadow p-6">
<h2 class="text-xl font-semibold mb-4 text-dark">Content Workflow Timeline</h2>
<div id="timelineContainer" class="space-y-4">
<!-- Timeline items will be added here -->
<div class="text-center py-8 text-gray-400">
<i class="fas fa-plus-circle text-3xl mb-2"></i>
<p>Drag content items from the library to begin planning</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- AI Suggestions Modal -->
<div id="aiModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-xl p-6 w-full max-w-2xl">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-semibold">AI Content Suggestions</h3>
<button id="closeAiModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Focus Area</label>
<select id="aiFocus" class="w-full p-2 border border-gray-300 rounded-lg">
<option value="listings">Property Listings</option>
<option value="market">Market Updates</option>
<option value="testimonials">Client Success Stories</option>
<option value="neighborhood">Neighborhood Highlights</option>
<option value="tips">Home Buying/Selling Tips</option>
</select>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Platforms</label>
<div class="flex flex-wrap gap-2">
<label class="inline-flex items-center">
<input type="checkbox" class="form-checkbox" value="instagram" checked>
<span class="ml-2">Instagram</span>
</label>
<label class="inline-flex items-center">
<input type="checkbox" class="form-checkbox" value="facebook" checked>
<span class="ml-2">Facebook</span>
</label>
<label class="inline-flex items-center">
<input type="checkbox" class="form-checkbox" value="tiktok">
<span class="ml-2">TikTok</span>
</label>
<label class="inline-flex items-center">
<input type="checkbox" class="form-checkbox" value="linkedin">
<span class="ml-2">LinkedIn</span>
</label>
</div>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Content Style</label>
<select id="aiStyle" class="w-full p-2 border border-gray-300 rounded-lg">
<option value="professional">Professional</option>
<option value="casual">Casual/Friendly</option>
<option value="humorous">Humorous</option>
<option value="educational">Educational</option>
</select>
</div>
<button id="generateSuggestions" class="w-full bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-lg flex items-center justify-center">
<i class="fas fa-magic mr-2"></i> Generate 30-Day Content Plan
</button>
<div id="aiLoading" class="hidden mt-4 text-center py-8">
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary mx-auto"></div>
<p class="mt-4 text-gray-600">Generating your personalized content plan...</p>
</div>
<div id="aiResults" class="hidden mt-4 space-y-4 max-h-96 overflow-y-auto p-2"></div>
</div>
</div>
<!-- Task Detail Modal -->
<div id="taskModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-xl p-6 w-full max-w-md">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-semibold">Content Task Details</h3>
<button id="closeTaskModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Content Type</label>
<input type="text" id="taskType" class="w-full p-2 border border-gray-300 rounded-lg" readonly>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Title/Description</label>
<textarea id="taskDescription" class="w-full p-2 border border-gray-300 rounded-lg" rows="3"></textarea>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Platforms</label>
<div class="flex flex-wrap gap-2">
<label class="inline-flex items-center">
<input type="checkbox" class="platform-checkbox" value="instagram">
<span class="ml-2">Instagram</span>
</label>
<label class="inline-flex items-center">
<input type="checkbox" class="platform-checkbox" value="facebook">
<span class="ml-2">Facebook</span>
</label>
<label class="inline-flex items-center">
<input type="checkbox" class="platform-checkbox" value="tiktok">
<span class="ml-2">TikTok</span>
</label>
<label class="inline-flex items-center">
<input type="checkbox" class="platform-checkbox" value="linkedin">
<span class="ml-2">LinkedIn</span>
</label>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-gray-700 mb-2">Start Date</label>
<input type="date" id="taskStartDate" class="w-full p-2 border border-gray-300 rounded-lg">
</div>
<div>
<label class="block text-gray-700 mb-2">Time Required</label>
<select id="taskTime" class="w-full p-2 border border-gray-300 rounded-lg">
<option value="15">15 minutes</option>
<option value="30">30 minutes</option>
<option value="45">45 minutes</option>
<option value="60">1 hour</option>
<option value="90">1.5 hours</option>
<option value="120">2 hours</option>
</select>
</div>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">Dependencies</label>
<select id="taskDependencies" class="w-full p-2 border border-gray-300 rounded-lg" multiple>
<!-- Will be populated with other tasks -->
</select>
</div>
<div class="flex justify-end space-x-2">
<button id="saveTask" class="bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-lg">
Save Changes
</button>
<button id="deleteTask" class="bg-red-500 hover:bg-red-600 text-white py-2 px-4 rounded-lg">
Delete Task
</button>
</div>
</div>
</div>
<script>
// Sample data
let currentDate = new Date();
let tasks = [];
let currentTaskId = null;
// DOM Elements
const calendarGrid = document.getElementById('calendarGrid');
const timelineContainer = document.getElementById('timelineContainer');
const aiModal = document.getElementById('aiModal');
const aiSuggestBtn = document.getElementById('aiSuggestBtn');
const closeAiModal = document.getElementById('closeAiModal');
const generateSuggestions = document.getElementById('generateSuggestions');
const aiResults = document.getElementById('aiResults');
const aiLoading = document.getElementById('aiLoading');
const taskModal = document.getElementById('taskModal');
const closeTaskModal = document.getElementById('closeTaskModal');
const saveTask = document.getElementById('saveTask');
const deleteTask = document.getElementById('deleteTask');
// Initialize the app
document.addEventListener('DOMContentLoaded', function() {
renderCalendar();
setupDragAndDrop();
setupEventListeners();
});
// Render the calendar
function renderCalendar() {
calendarGrid.innerHTML = '';
// Get the first day of the month and total days
const firstDay = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1).getDay();
const daysInMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0).getDate();
// Add empty cells for days before the first day of the month
for (let i = 0; i < firstDay; i++) {
const dayCell = document.createElement('div');
dayCell.className = 'bg-gray-50 h-32 p-2';
calendarGrid.appendChild(dayCell);
}
// Add cells for each day of the month
for (let i = 1; i <= daysInMonth; i++) {
const dayCell = document.createElement('div');
dayCell.className = 'bg-white h-32 p-2 relative';
const dayNumber = document.createElement('div');
dayNumber.className = 'font-medium text-gray-700';
dayNumber.textContent = i;
dayCell.appendChild(dayNumber);
// Add tasks for this day
const dayTasks = tasks.filter(task => {
const taskDate = new Date(task.startDate);
return taskDate.getDate() === i &&
taskDate.getMonth() === currentDate.getMonth() &&
taskDate.getFullYear() === currentDate.getFullYear();
});
const tasksContainer = document.createElement('div');
tasksContainer.className = 'mt-1 space-y-1 overflow-y-auto max-h-24';
dayTasks.forEach(task => {
const taskElement = document.createElement('div');
taskElement.className = 'text-xs p-1 rounded truncate cursor-pointer';
// Set color based on content type
if (task.type === 'property-showcase') {
taskElement.className += ' bg-yellow-100 text-yellow-800';
} else if (task.type === 'market-update') {
taskElement.className += ' bg-green-100 text-green-800';
} else if (task.type === 'client-testimonial') {
taskElement.className += ' bg-blue-100 text-blue-800';
} else if (task.type === 'neighborhood-guide') {
taskElement.className += ' bg-purple-100 text-purple-800';
} else {
taskElement.className += ' bg-gray-100 text-gray-800';
}
taskElement.textContent = task.title || task.type;
taskElement.addEventListener('click', () => openTaskModal(task.id));
tasksContainer.appendChild(taskElement);
});
dayCell.appendChild(tasksContainer);
calendarGrid.appendChild(dayCell);
}
// Render timeline
renderTimeline();
}
// Render the timeline view
function renderTimeline() {
if (tasks.length === 0) {
timelineContainer.innerHTML = `
<div class="text-center py-8 text-gray-400">
<i class="fas fa-plus-circle text-3xl mb-2"></i>
<p>Drag content items from the library to begin planning</p>
</div>
`;
return;
}
timelineContainer.innerHTML = '';
// Sort tasks by date
const sortedTasks = [...tasks].sort((a, b) => new Date(a.startDate) - new Date(b.startDate));
sortedTasks.forEach((task, index) => {
const taskElement = document.createElement('div');
taskElement.className = 'relative pl-12';
taskElement.dataset.taskId = task.id;
// Add connector line except for last item
if (index < sortedTasks.length - 1) {
const connector = document.createElement('div');
connector.className = 'timeline-connector';
taskElement.appendChild(connector);
}
// Task card
const card = document.createElement('div');
card.className = 'bg-white border border-gray-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow cursor-pointer';
card.addEventListener('click', () => openTaskModal(task.id));
// Task header
const header = document.createElement('div');
header.className = 'flex justify-between items-start mb-2';
const title = document.createElement('h3');
title.className = 'font-medium text-dark';
title.textContent = task.title || formatTaskType(task.type);
const platforms = document.createElement('div');
platforms.className = 'flex space-x-1';
task.platforms.forEach(platform => {
const platformTag = document.createElement('span');
platformTag.className = 'platform-tag text-xs';
if (platform === 'instagram') {
platformTag.className += ' bg-blue-100 text-blue-800 border border-blue-200';
} else if (platform === 'facebook') {
platformTag.className += ' bg-blue-600 text-white';
} else if (platform === 'tiktok') {
platformTag.className += ' bg-black text-white';
} else if (platform === 'linkedin') {
platformTag.className += ' bg-blue-700 text-white';
}
platformTag.textContent = platform.charAt(0).toUpperCase() + platform.slice(1);
platforms.appendChild(platformTag);
});
header.appendChild(title);
header.appendChild(platforms);
card.appendChild(header);
// Task details
const details = document.createElement('div');
details.className = 'text-sm text-gray-600 mb-2';
details.textContent = task.description || 'No description provided';
card.appendChild(details);
// Task footer
const footer = document.createElement('div');
footer.className = 'flex justify-between items-center text-xs text-gray-500';
const date = document.createElement('div');
date.textContent = formatDate(new Date(task.startDate));
const time = document.createElement('div');
time.className = 'font-medium';
time.textContent = `${task.time} min`;
footer.appendChild(date);
footer.appendChild(time);
card.appendChild(footer);
// Icon
const icon = document.createElement('div');
icon.className = 'absolute left-0 top-4 flex items-center justify-center w-10 h-10 rounded-full bg-primary text-white';
const iconElement = document.createElement('i');
if (task.type === 'property-showcase') {
iconElement.className = 'fas fa-home';
} else if (task.type === 'market-update') {
iconElement.className = 'fas fa-chart-line';
} else if (task.type === 'client-testimonial') {
iconElement.className = 'fas fa-quote-left';
} else if (task.type === 'neighborhood-guide') {
iconElement.className = 'fas fa-map-marked-alt';
} else {
iconElement.className = 'fas fa-lightbulb';
}
icon.appendChild(iconElement);
taskElement.appendChild(icon);
taskElement.appendChild(card);
timelineContainer.appendChild(taskElement);
});
}
// Setup drag and drop functionality
function setupDragAndDrop() {
const draggables = document.querySelectorAll('.draggable');
const calendarCells = document.querySelectorAll('#calendarGrid > div');
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', () => {
draggable.classList.add('dragging');
});
draggable.addEventListener('dragend', () => {
draggable.classList.remove('dragging');
});
});
calendarCells.forEach(cell => {
cell.addEventListener('dragover', e => {
e.preventDefault();
const dragging = document.querySelector('.dragging');
if (dragging) {
cell.classList.add('bg-blue-50');
}
});
cell.addEventListener('dragleave', () => {
cell.classList.remove('bg-blue-50');
});
cell.addEventListener('drop', e => {
e.preventDefault();
cell.classList.remove('bg-blue-50');
const dragging = document.querySelector('.dragging');
if (dragging) {
const day = parseInt(cell.firstChild.textContent);
const date = new Date(currentDate.getFullYear(), currentDate.getMonth(), day);
if (dragging.dataset.type) {
// It's a content type
const newTask = {
id: Date.now().toString(),
type: dragging.dataset.type,
title: '',
description: '',
platforms: ['instagram', 'facebook'], // Default platforms
startDate: date.toISOString().split('T')[0],
time: 30, // Default time
dependencies: []
};
tasks.push(newTask);
renderCalendar();
openTaskModal(newTask.id);
} else if (dragging.dataset.time) {
// It's a time block - find if there's a task for this day
const dayTasks = tasks.filter(task => {
const taskDate = new Date(task.startDate);
return taskDate.getDate() === day &&
taskDate.getMonth() === currentDate.getMonth() &&
taskDate.getFullYear() === currentDate.getFullYear();
});
if (dayTasks.length > 0) {
const task = dayTasks[0];
task.time = parseInt(dragging.dataset.time);
renderCalendar();
renderTimeline();
}
}
}
});
});
// Also allow dropping on timeline
timelineContainer.addEventListener('dragover', e => {
e.preventDefault();
const dragging = document.querySelector('.dragging');
if (dragging && dragging.dataset.time) {
timelineContainer.classList.add('bg-blue-50');
}
});
timelineContainer.addEventListener('dragleave', () => {
timelineContainer.classList.remove('bg-blue-50');
});
timelineContainer.addEventListener('drop', e => {
e.preventDefault();
timelineContainer.classList.remove('bg-blue-50');
const dragging = document.querySelector('.dragging');
if (dragging && dragging.dataset.time) {
// Find the task that was hovered over
const taskElement = document.elementFromPoint(e.clientX, e.clientY);
const taskId = taskElement.closest('[data-task-id]')?.dataset.taskId;
if (taskId) {
const task = tasks.find(t => t.id === taskId);
if (task) {
task.time = parseInt(dragging.dataset.time);
renderTimeline();
}
}
}
});
}
// Setup event listeners
function setupEventListeners() {
// AI Modal
aiSuggestBtn.addEventListener('click', () => {
aiModal.classList.remove('hidden');
});
closeAiModal.addEventListener('click', () => {
aiModal.classList.add('hidden');
aiResults.innerHTML = '';
aiResults.classList.add('hidden');
aiLoading.classList.add('hidden');
});
generateSuggestions.addEventListener('click', generateAiSuggestions);
// Task Modal
closeTaskModal.addEventListener('click', () => {
taskModal.classList.add('hidden');
});
saveTask.addEventListener('click', saveCurrentTask);
deleteTask.addEventListener('click', () => {
if (currentTaskId && confirm('Are you sure you want to delete this task?')) {
tasks = tasks.filter(task => task.id !== currentTaskId);
renderCalendar();
renderTimeline();
taskModal.classList.add('hidden');
}
});
// Navigation
document.getElementById('prevMonth').addEventListener('click', () => {
currentDate.setMonth(currentDate.getMonth() - 1);
renderCalendar();
});
document.getElementById('nextMonth').addEventListener('click', () => {
currentDate.setMonth(currentDate.getMonth() + 1);
renderCalendar();
});
// Export
document.getElementById('exportBtn').addEventListener('click', exportCalendar);
}
// Open task modal for editing
function openTaskModal(taskId) {
const task = tasks.find(t => t.id === taskId);
if (!task) return;
currentTaskId = taskId;
// Populate modal fields
document.getElementById('taskType').value = formatTaskType(task.type);
document.getElementById('taskDescription').value = task.description || '';
document.getElementById('taskStartDate').value = task.startDate;
document.getElementById('taskTime').value = task.time;
// Clear and set platforms
document.querySelectorAll('.platform-checkbox').forEach(checkbox => {
checkbox.checked = task.platforms.includes(checkbox.value);
});
// Populate dependencies
const dependenciesSelect = document.getElementById('taskDependencies');
dependenciesSelect.innerHTML = '';
tasks.filter(t => t.id !== taskId).forEach(t => {
const option = document.createElement('option');
option.value = t.id;
option.textContent = `${formatTaskType(t.type)} - ${formatDate(new Date(t.startDate))}`;
option.selected = task.dependencies.includes(t.id);
dependenciesSelect.appendChild(option);
});
taskModal.classList.remove('hidden');
}
// Save current task changes
function saveCurrentTask() {
if (!currentTaskId) return;
const taskIndex = tasks.findIndex(t => t.id === currentTaskId);
if (taskIndex === -1) return;
// Get platform selections
const platforms = [];
document.querySelectorAll('.platform-checkbox:checked').forEach(checkbox => {
platforms.push(checkbox.value);
});
// Get dependencies
const dependencies = [];
const options = document.getElementById('taskDependencies').options;
for (let i = 0; i < options.length; i++) {
if (options[i].selected) {
dependencies.push(options[i].value);
}
}
// Update task
tasks[taskIndex] = {
...tasks[taskIndex],
title: document.getElementById('taskDescription').value.split('\n')[0] || '',
description: document.getElementById('taskDescription').value,
platforms,
startDate: document.getElementById('taskStartDate').value,
time: parseInt(document.getElementById('taskTime').value),
dependencies
};
renderCalendar();
renderTimeline();
taskModal.classList.add('hidden');
}
// Generate AI suggestions
function generateAiSuggestions() {
const focus = document.getElementById('aiFocus').value;
const style = document.getElementById('aiStyle').value;
// Get selected platforms
const platforms = [];
document.querySelectorAll('#aiModal input[type="checkbox"]:checked').forEach(checkbox => {
platforms.push(checkbox.value);
});
if (platforms.length === 0) {
alert('Please select at least one platform');
return;
}
aiResults.innerHTML = '';
aiResults.classList.add('hidden');
aiLoading.classList.remove('hidden');
// Simulate API call (in a real app, you would call the DeepSeek API here)
setTimeout(() => {
aiLoading.classList.add('hidden');
aiResults.classList.remove('hidden');
// Generate sample suggestions based on focus
const suggestions = generateSampleSuggestions(focus, platforms, style);
suggestions.forEach((suggestion, index) => {
const suggestionElement = document.createElement('div');
suggestionElement.className = 'border border-gray-200 rounded-lg p-4';
const header = document.createElement('div');
header.className = 'flex justify-between items-center mb-2';
const day = document.createElement('span');
day.className = 'font-medium text-primary';
day.textContent = `Day ${index + 1}`;
const platforms = document.createElement('div');
platforms.className = 'flex space-x-1';
suggestion.platforms.forEach(platform => {
const platformTag = document.createElement('span');
platformTag.className = 'platform-tag text-xs';
if (platform === 'instagram') {
platformTag.className += ' bg-blue-100 text-blue-800 border border-blue-200';
} else if (platform === 'facebook') {
platformTag.className += ' bg-blue-600 text-white';
} else if (platform === 'tiktok') {
platformTag.className += ' bg-black text-white';
} else if (platform === 'linkedin') {
platformTag.className += ' bg-blue-700 text-white';
}
platformTag.textContent = platform.charAt(0).toUpperCase() + platform.slice(1);
platforms.appendChild(platformTag);
});
header.appendChild(day);
header.appendChild(platforms);
suggestionElement.appendChild(header);
const title = document.createElement('h4');
title.className = 'font-medium text-lg mb-1';
title.textContent = suggestion.title;
suggestionElement.appendChild(title);
const content = document.createElement('p');
content.className = 'text-gray-600 mb-2';
content.textContent = suggestion.content;
suggestionElement.appendChild(content);
const hashtags = document.createElement('div');
hashtags.className = 'text-sm text-blue-500';
hashtags.textContent = suggestion.hashtags;
suggestionElement.appendChild(hashtags);
const addButton = document.createElement('button');
addButton.className = 'mt-2 w-full bg-secondary hover:bg-green-700 text-white py-1 px-3 rounded text-sm';
addButton.textContent = 'Add to Calendar';
addButton.addEventListener('click', () => addAiSuggestionToCalendar(suggestion, index + 1));
suggestionElement.appendChild(addButton);
aiResults.appendChild(suggestionElement);
});
}, 1500);
}
// Add AI suggestion to calendar
function addAiSuggestionToCalendar(suggestion, dayOffset) {
const date = new Date();
date.setDate(date.getDate() + dayOffset);
const newTask = {
id: Date.now().toString(),
type: suggestion.type || 'custom',
title: suggestion.title,
description: suggestion.content + '\n\n' + suggestion.hashtags,
platforms: suggestion.platforms,
startDate: date.toISOString().split('T')[0],
time: 45, // Default time for AI suggestions
dependencies: []
};
tasks.push(newTask);
renderCalendar();
renderTimeline();
// Scroll to the new task in timeline
setTimeout(() => {
const taskElement = document.querySelector(`[data-task-id="${newTask.id}"]`);
if (taskElement) {
taskElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}, 100);
}
// Export calendar
function exportCalendar() {
if (tasks.length === 0) {
alert('No content to export');
return;
}
// Sort tasks by date
const sortedTasks = [...tasks].sort((a, b) => new Date(a.startDate) - new Date(b.startDate));
// Create CSV content
let csvContent = "Date,Content Type,Title,Platforms,Time (min),Description\n";
sortedTasks.forEach(task => {
const date = formatDate(new Date(task.startDate));
const type = formatTaskType(task.type);
const title = task.title || '';
const platforms = task.platforms.map(p => p.charAt(0).toUpperCase() + p.slice(1)).join(', ');
const time = task.time;
const description = task.description.replace(/"/g, '""').replace(/\n/g, ' ');
csvContent += `"${date}","${type}","${title}","${platforms}","${time}","${description}"\n`;
});
// Create download link
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `content_calendar_${formatDate(new Date())}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Helper functions
function formatDate(date) {
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
}
function formatTaskType(type) {
return type.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
}
function generateSampleSuggestions(focus, platforms, style) {
const suggestions = [];
const contentTypes = {
listings: 'property-showcase',
market: 'market-update',
testimonials: 'client-testimonial',
neighborhood: 'neighborhood-guide',
tips: 'home-tips'
};
const type = contentTypes[focus] || 'custom';
for (let i = 1; i <= 30; i++) {
let title, content, hashtags;
switch (focus) {
case 'listings':
title = `New Listing Alert: Beautiful ${i % 2 === 0 ? '3BR Home' : 'Downtown Condo'}`;
content = `Just listed! This stunning property features ${i % 2 === 0 ? 'a spacious backyard and modern kitchen' : 'floor-to-ceiling windows and luxury finishes'}. DM me for a private showing!`;
hashtags = '#RealEstate #NewListing #DreamHome #HouseHunting';
break;
case 'market':
title = `${['June', 'July', 'August'][i % 3]} Market Update`;
content = `The local real estate market is ${['heating up', 'staying steady', 'seeing more inventory'][i % 3]}. Here are the latest stats and what they mean for ${['buyers', 'sellers', 'investors'][i % 3]}.`;
hashtags = '#MarketUpdate #RealEstateTrends #LocalMarket';
break;
case 'testimonials':
title = `Success Story: ${['First-Time', 'Move-Up', 'Downsizing'][i % 3]} Buyers`;
content = `"Working with me made the ${['home buying', 'selling', 'investment'][i % 3]} process so smooth!" Hear from my recent clients about their experience.`;
hashtags = '#ClientSuccess #Testimonial #HappyClients';
break;
case 'neighborhood':
title = `Neighborhood Spotlight: ${['Downtown', 'Suburban', 'Waterfront'][i % 3]} Area`;
content = `What makes ${['the downtown core', 'this family-friendly suburb', 'this waterfront community'][i % 3]} so special? Here are the top ${['5', '7', '3'][i % 3]} reasons to consider living here.`;
hashtags = '#NeighborhoodGuide #LocalLife #Community';
break;
case 'tips':
title = `Tip #${i}: ${['Pricing', 'Staging', 'Negotiation'][i % 3]} Strategies`;
content = `My top ${['3', '5', '7'][i % 3]} ${['pricing', 'staging', 'negotiation'][i % 3]} tips for ${['sellers', 'buyers', 'investors'][i % 3]} in today's market.`;
hashtags = '#RealEstateTips #HomeBuying #SellingSmart';
break;
default:
title = `Content Idea ${i}`;
content = `This is a sample content idea for your real estate business. Customize it with your specific details and expertise.`;
hashtags = '#RealEstate #ContentMarketing';
}
// Adjust content based on style
if (style === 'casual') {
content = content.replace(/Here are/g, "Check out these").replace(/This is/g, "Here's");
if (!content.includes("!")) content += "!";
} else if (style === 'humorous') {
content = content.replace(/The local/g, "So, the local").replace(/Just listed/g, "Hot off the presses");
if (!content.includes("πŸ˜‚")) content += " πŸ˜‚";
} else if (style === 'educational') {
content = content.replace(/Here are/g, "In this post, we'll examine").replace(/This stunning/g, "From an investment perspective, this");
}
suggestions.push({
type,
title,
content,
hashtags,
platforms: platforms.length > 2 ? [platforms[i % platforms.length]] : platforms
});
}
return suggestions;
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=JayStormX8/content-calendar-v1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>