`, 'api-route': `{% if language === 'TypeScript' %} import { Request, Response } from 'express'; export const {{ routeName | camelCase }} = async (req: Request, res: Response) => { try { // Implementation here res.json({ message: 'Success' }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } }; {% endif %}`, 'test-file': `{% if language === 'TypeScript' %} import { {{ componentName | pascalCase }} } from './{{ componentName | pascalCase }}'; describe('{{ componentName | pascalCase }}', () => { it('should render correctly', () => { // Test implementation }); }); {% endif %}` } if (selectedFile.value && snippets[snippetType]) { selectedFile.value.content = snippets[snippetType] if (autoPreview.value) { debouncedPreviewUpdate() } } } const formatContent = () => { if (selectedFile.value) { // Basic formatting - in real app would use proper formatter selectedFile.value.content = selectedFile.value.content .replace(/\s+$/gm, '') // Remove trailing whitespace .replace(/\n{3,}/g, '\n\n') // Max 2 consecutive newlines } } const validateTemplate = async () => { try { const validation = await $fetch('/api/templates/validate', { method: 'POST', body: template }) syntaxValid.value = validation.valid if (validation.valid) { useToast().add({ title: 'Template valid', description: 'Template syntax and structure are correct', color: 'green' }) } else { useToast().add({ title: 'Validation failed', description: validation.errors.join(', '), color: 'red' }) } } catch (error) { syntaxValid.value = false useToast().add({ title: 'Validation error', description: 'Failed to validate template', color: 'red' }) } } const testTemplate = async () => { try { const result = await $fetch('/api/templates/test', { method: 'POST', body: { template, variables: previewVariables.value } }) testResults.value = result showTestModal.value = true } catch (error: any) { testResults.value = { success: false, error: error.data?.message || 'Test failed' } showTestModal.value = true } } const updatePreview = async () => { if (!template.files?.length) { generatedPreview.value = [] return } generatingPreview.value = true try { const result = await $fetch('/api/templates/preview', { method: 'POST', body: { template, variables: previewVariables.value } }) generatedPreview.value = result.files || [] } catch (error) { console.error('Preview generation failed:', error) generatedPreview.value = [] } finally { generatingPreview.value = false } } const saveTemplate = async () => { saving.value = true try { const method = editing.value ? 'PUT' : 'POST' const url = editing.value ? `/api/templates/${route.params.id}` : '/api/templates' const result = await $fetch(url, { method, body: template }) useToast().add({ title: 'Template saved', description: 'Template has been saved successfully', color: 'green' }) if (!editing.value) { await navigateTo(`/templates/designer/${result.id}`) } } catch (error) { useToast().add({ title: 'Save failed', description: 'Failed to save template', color: 'red' }) } finally { saving.value = false } } const publishTemplate = async () => { publishing.value = true try { await $fetch(`/api/templates/${route.params.id}/publish`, { method: 'POST' }) useToast().add({ title: 'Template published', description: 'Template is now available in the marketplace', color: 'green' }) template.isPublic = true } catch (error) { useToast().add({ title: 'Publish failed', description: 'Failed to publish template', color: 'red' }) } finally { publishing.value = false } } const getFileIcon = (path: string): string => { if (!path) return 'i-heroicons-document' const extension = path.split('.').pop()?.toLowerCase() const icons: Record = { 'ts': 'i-simple-icons-typescript', 'tsx': 'i-simple-icons-react', 'js': 'i-simple-icons-javascript', 'jsx': 'i-simple-icons-react', 'vue': 'i-simple-icons-vuedotjs', 'py': 'i-simple-icons-python', 'go': 'i-simple-icons-go', 'rs': 'i-simple-icons-rust', 'java': 'i-simple-icons-java', 'php': 'i-simple-icons-php', 'rb': 'i-simple-icons-ruby', 'html': 'i-heroicons-code-bracket', 'css': 'i-heroicons-paint-brush', 'json': 'i-heroicons-code-bracket', 'yml': 'i-heroicons-document-text', 'yaml': 'i-heroicons-document-text', 'md': 'i-heroicons-document-text' } return icons[extension || ''] || 'i-heroicons-document' } // Debounced preview update const debouncedPreviewUpdate = debounce(() => { if (autoPreview.value) { updatePreview() } }, 1000) function debounce any>(func: T, wait: number): T { let timeout: NodeJS.Timeout return ((...args: any[]) => { clearTimeout(timeout) timeout = setTimeout(() => func.apply(this, args), wait) }) as T } // Initialize preview variables when template variables change watch(() => template.variables, (newVariables) => { if (newVariables) { newVariables.forEach(variable => { if (!(variable.name in previewVariables.value)) { previewVariables.value[variable.name] = variable.default || '' } }) } }, { deep: true }) // Load existing template if editing onMounted(async () => { if (editing.value && route.params.id) { try { const existingTemplate = await $fetch(`/api/templates/${route.params.id}`) Object.assign(template, existingTemplate) // Initialize preview variables existingTemplate.variables.forEach((variable: TemplateVariable) => { previewVariables.value[variable.name] = variable.default || '' }) updatePreview() } catch (error) { console.error('Failed to load template:', error) useToast().add({ title: 'Load failed', description: 'Failed to load template for editing', color: 'red' }) } } else { // Add initial file for new templates addFile() } }) // Auto-update preview when variables change watch(previewVariables, () => { if (autoPreview.value) { debouncedPreviewUpdate() } }, { deep: true })