diff options
Diffstat (limited to 'static/api-docs-script.js')
-rw-r--r-- | static/api-docs-script.js | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/static/api-docs-script.js b/static/api-docs-script.js new file mode 100644 index 0000000..436067d --- /dev/null +++ b/static/api-docs-script.js @@ -0,0 +1,449 @@ +// DOM Elements +const elements = { + sidebar: document.getElementById('sidebar'), + apiTester: document.getElementById('apiTester'), + closeTester: document.getElementById('closeTester'), + getApiKeyBtn: document.getElementById('getApiKeyBtn'), + tryApiBtn: document.getElementById('tryApiBtn'), + toast: document.getElementById('toast') +}; + +// Navigation and scrolling +const setupNavigation = () => { + // Smooth scrolling for navigation links + document.querySelectorAll('.nav-item').forEach(link => { + link.addEventListener('click', (e) => { + e.preventDefault(); + const targetId = link.getAttribute('href').substring(1); + const targetElement = document.getElementById(targetId); + + if (targetElement) { + targetElement.scrollIntoView({ + behavior: 'smooth', + block: 'start' + }); + + // Update active nav item + document.querySelectorAll('.nav-item').forEach(item => { + item.classList.remove('active'); + }); + link.classList.add('active'); + } + }); + }); + + // Update active nav item on scroll + const observerOptions = { + rootMargin: '-100px 0px -50% 0px', + threshold: 0 + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const id = entry.target.id; + const navLink = document.querySelector(`[href="#${id}"]`); + + if (navLink) { + document.querySelectorAll('.nav-item').forEach(item => { + item.classList.remove('active'); + }); + navLink.classList.add('active'); + } + } + }); + }, observerOptions); + + // Observe all sections + document.querySelectorAll('.doc-section').forEach(section => { + observer.observe(section); + }); +}; + +// Code tabs functionality +const setupCodeTabs = () => { + document.querySelectorAll('.code-tabs').forEach(tabGroup => { + const tabs = tabGroup.querySelectorAll('.tab-btn'); + const codeExample = tabGroup.closest('.code-example'); + const contents = codeExample.querySelectorAll('.tab-content'); + + tabs.forEach(tab => { + tab.addEventListener('click', () => { + const targetTab = tab.dataset.tab; + + // Update active tab + tabs.forEach(t => t.classList.remove('active')); + tab.classList.add('active'); + + // Update active content + contents.forEach(content => { + content.classList.remove('active'); + if (content.id === targetTab) { + content.classList.add('active'); + } + }); + }); + }); + }); +}; + +// Copy to clipboard functionality +const setupCopyButtons = () => { + document.querySelectorAll('.copy-btn').forEach(button => { + button.addEventListener('click', async () => { + const copyTarget = button.dataset.copy; + const targetElement = document.getElementById(copyTarget); + + if (targetElement) { + try { + await navigator.clipboard.writeText(targetElement.textContent); + showToast('Copied to clipboard!', 'success'); + + // Visual feedback + const originalText = button.textContent; + button.textContent = 'Copied!'; + setTimeout(() => { + button.textContent = originalText; + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + showToast('Failed to copy to clipboard', 'error'); + } + } + }); + }); +}; + +// API Tester functionality +const setupApiTester = () => { + const tester = elements.apiTester; + const closeTester = elements.closeTester; + const tryApiBtn = elements.tryApiBtn; + const sendRequestBtn = document.getElementById('sendRequest'); + + // Show API tester + tryApiBtn.addEventListener('click', () => { + tester.classList.add('show'); + document.body.style.overflow = 'hidden'; + }); + + // Close API tester + const closeTesterModal = () => { + tester.classList.remove('show'); + document.body.style.overflow = 'auto'; + }; + + closeTester.addEventListener('click', closeTesterModal); + + // Close on outside click + tester.addEventListener('click', (e) => { + if (e.target === tester) { + closeTesterModal(); + } + }); + + // Close on escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && tester.classList.contains('show')) { + closeTesterModal(); + } + }); + + // Try It buttons for specific endpoints + document.querySelectorAll('.try-it-btn').forEach(button => { + button.addEventListener('click', () => { + const endpoint = button.dataset.endpoint; + populateApiTester(endpoint); + tester.classList.add('show'); + document.body.style.overflow = 'hidden'; + }); + }); + + // Send API request + sendRequestBtn.addEventListener('click', async () => { + await sendApiRequest(); + }); +}; + +// Populate API tester with endpoint data +const populateApiTester = (endpoint) => { + const methodSelect = document.getElementById('testMethod'); + const endpointInput = document.getElementById('testEndpoint'); + const headersTextarea = document.getElementById('testHeaders'); + const bodyTextarea = document.getElementById('testBody'); + + const endpointConfigs = { + projects: { + method: 'GET', + endpoint: '/projects', + headers: `Authorization: Bearer your_api_key_here +Content-Type: application/json`, + body: '' + } + }; + + const config = endpointConfigs[endpoint]; + if (config) { + methodSelect.value = config.method; + endpointInput.value = config.endpoint; + headersTextarea.value = config.headers; + bodyTextarea.value = config.body; + } +}; + +// Send API request (mock implementation) +const sendApiRequest = async () => { + const method = document.getElementById('testMethod').value; + const endpoint = document.getElementById('testEndpoint').value; + const headers = document.getElementById('testHeaders').value; + const body = document.getElementById('testBody').value; + const responseStatus = document.getElementById('responseStatus'); + const responseBody = document.getElementById('responseBody'); + + // Show loading state + responseStatus.textContent = 'Sending request...'; + responseStatus.className = 'response-status'; + responseBody.textContent = ''; + + try { + // Parse headers + const headerLines = headers.split('\n').filter(line => line.trim()); + const headerObj = {}; + headerLines.forEach(line => { + const [key, ...valueParts] = line.split(':'); + if (key && valueParts.length > 0) { + headerObj[key.trim()] = valueParts.join(':').trim(); + } + }); + + // Mock API response based on endpoint + const mockResponse = generateMockResponse(method, endpoint); + + // Simulate network delay + await new Promise(resolve => setTimeout(resolve, 1000)); + + // Display response + responseStatus.textContent = `${mockResponse.status} ${mockResponse.statusText}`; + responseStatus.className = `response-status ${mockResponse.status < 400 ? 'success' : 'error'}`; + responseBody.textContent = JSON.stringify(mockResponse.data, null, 2); + + showToast('Request completed', 'success'); + + } catch (error) { + responseStatus.textContent = '500 Internal Server Error'; + responseStatus.className = 'response-status error'; + responseBody.textContent = JSON.stringify({ + error: { + code: 'request_failed', + message: error.message || 'Failed to send request' + } + }, null, 2); + + showToast('Request failed', 'error'); + } +}; + +// Generate mock API responses +const generateMockResponse = (method, endpoint) => { + const responses = { + 'GET /projects': { + status: 200, + statusText: 'OK', + data: { + data: [ + { + id: 'proj_1234567890', + name: 'Website Redesign', + description: 'Complete overhaul of company website', + status: 'active', + created_at: '2025-01-15T10:30:00Z', + updated_at: '2025-01-20T14:22:00Z', + owner: { + id: 'user_0987654321', + name: 'John Doe', + email: 'john@company.com' + }, + team_id: 'team_1122334455', + task_count: 24, + completed_tasks: 12, + progress: 50.0, + due_date: '2025-03-01T00:00:00Z', + tags: ['design', 'frontend', 'priority-high'] + } + ], + pagination: { + limit: 20, + offset: 0, + total: 1, + has_more: false + } + } + }, + 'POST /projects': { + status: 201, + statusText: 'Created', + data: { + id: 'proj_9876543210', + name: 'Mobile App Development', + description: 'Build iOS and Android mobile applications', + status: 'active', + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + owner: { + id: 'user_0987654321', + name: 'John Doe', + email: 'john@company.com' + }, + team_id: 'team_1122334455', + task_count: 0, + completed_tasks: 0, + progress: 0.0, + due_date: '2025-06-01T00:00:00Z', + tags: ['mobile', 'ios', 'android'] + } + } + }; + + const key = `${method} ${endpoint}`; + return responses[key] || { + status: 404, + statusText: 'Not Found', + data: { + error: { + code: 'endpoint_not_found', + message: 'The requested endpoint was not found' + } + } + }; +}; + +// Toast notifications +const showToast = (message, type = 'success') => { + const toast = elements.toast; + const toastMessage = toast.querySelector('.toast-message'); + const toastIcon = toast.querySelector('.toast-icon'); + + toastMessage.textContent = message; + + if (type === 'success') { + toast.style.background = 'var(--success)'; + toastIcon.textContent = '✓'; + } else { + toast.style.background = 'var(--error)'; + toastIcon.textContent = '✕'; + } + + toast.classList.add('show'); + + setTimeout(() => { + toast.classList.remove('show'); + }, 4000); +}; + +// Get API Key functionality +const setupGetApiKey = () => { + elements.getApiKeyBtn.addEventListener('click', () => { + showToast('Redirecting to API key management...', 'success'); + setTimeout(() => { + // In a real app, this would redirect to the API key management page + window.location.href = 'login.html'; + }, 2000); + }); +}; + +// Navbar background on scroll +const setupNavbarScroll = () => { + window.addEventListener('scroll', () => { + const navbar = document.querySelector('.navbar'); + if (window.scrollY > 50) { + navbar.style.background = 'rgba(255, 255, 255, 0.98)'; + } else { + navbar.style.background = 'rgba(255, 255, 255, 0.95)'; + } + }); +}; + +// Button click handlers +const setupButtonHandlers = () => { + document.querySelectorAll('.btn').forEach(btn => { + btn.addEventListener('click', (e) => { + const buttonText = btn.textContent.toLowerCase(); + + if (buttonText.includes('trial') || buttonText.includes('start')) { + if (!btn.closest('.api-tester') && !btn.id) { + e.preventDefault(); + showToast('Starting your free trial! Redirecting...', 'success'); + setTimeout(() => { + window.location.href = 'signup.html'; + }, 2000); + } + } + }); + }); +}; + +// Syntax highlighting for code blocks (simple implementation) +const setupSyntaxHighlighting = () => { + document.querySelectorAll('pre code').forEach(block => { + const text = block.textContent; + + // Simple JSON highlighting + if (text.trim().startsWith('{') || text.trim().startsWith('[')) { + try { + const parsed = JSON.parse(text); + const highlighted = JSON.stringify(parsed, null, 2) + .replace(/"([^"]+)":/g, '<span style="color: #8b5cf6;">"$1":</span>') + .replace(/: "([^"]+)"/g, ': <span style="color: #10b981;">"$1"</span>') + .replace(/: (\d+)/g, ': <span style="color: #f59e0b;">$1</span>') + .replace(/: (true|false|null)/g, ': <span style="color: #ef4444;">$1</span>'); + + block.innerHTML = highlighted; + } catch (e) { + // If JSON parsing fails, leave as is + } + } + + // Simple curl command highlighting + if (text.includes('curl')) { + const highlighted = text + .replace(/curl/g, '<span style="color: #8b5cf6;">curl</span>') + .replace(/-X (GET|POST|PUT|DELETE)/g, '<span style="color: #f59e0b;">-X</span> <span style="color: #10b981;">$1</span>') + .replace(/-H/g, '<span style="color: #f59e0b;">-H</span>') + .replace(/-d/g, '<span style="color: #f59e0b;">-d</span>'); + + block.innerHTML = highlighted; + } + }); +}; + +// Initialize everything +const init = () => { + setupNavigation(); + setupCodeTabs(); + setupCopyButtons(); + setupApiTester(); + setupGetApiKey(); + setupNavbarScroll(); + setupButtonHandlers(); + setupSyntaxHighlighting(); + + // Set first nav item as active initially + const firstNavItem = document.querySelector('.nav-item'); + if (firstNavItem) { + firstNavItem.classList.add('active'); + } +}; + +// Initialize when DOM is loaded +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} + +// Export for potential external use +window.TaskFlowAPIDocs = { + showToast, + populateApiTester, + sendApiRequest +}; |