summaryrefslogtreecommitdiff
path: root/static/api-docs-script.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/api-docs-script.js')
-rw-r--r--static/api-docs-script.js449
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
+};