diff --git a/public/admin/editorial-guidelines.html b/public/admin/editorial-guidelines.html new file mode 100644 index 00000000..32074c0a --- /dev/null +++ b/public/admin/editorial-guidelines.html @@ -0,0 +1,94 @@ + + + + + + Editorial Guidelines | Tractatus Admin + + + + + +
+ +
+ +
+

Editorial Guidelines Manager

+

Publication targets, submission requirements, and editorial guidelines for external communications

+
+ + +
+
+
Total Publications
+
-
+
+
+
Premier Tier
+
-
+
+
+
High Value
+
-
+
+
+
Strategic
+
-
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
+ + + + + diff --git a/public/js/admin/editorial-guidelines.js b/public/js/admin/editorial-guidelines.js new file mode 100644 index 00000000..21d45a2c --- /dev/null +++ b/public/js/admin/editorial-guidelines.js @@ -0,0 +1,197 @@ +/** + * Editorial Guidelines Manager + * Displays publication targets with submission requirements + */ + +let allTargets = []; +let filteredTargets = []; + +// Initialize page +document.addEventListener('DOMContentLoaded', async () => { + await loadPublicationTargets(); + setupFilters(); +}); + +async function loadPublicationTargets() { + try { + const response = await fetch('/api/publications/targets'); + if (!response.ok) throw new Error('Failed to load publication targets'); + + const data = await response.json(); + allTargets = data.targets; + filteredTargets = [...allTargets]; + + updateStats(); + renderPublications(); + } catch (error) { + console.error('Error loading publication targets:', error); + showError('Failed to load publication targets'); + } +} + +function updateStats() { + const stats = { + total: allTargets.length, + premier: allTargets.filter(t => t.tier === 'premier').length, + highValue: allTargets.filter(t => t.tier === 'high-value').length, + strategic: allTargets.filter(t => t.tier === 'strategic').length + }; + + document.getElementById('stat-total').textContent = stats.total; + document.getElementById('stat-premier').textContent = stats.premier; + document.getElementById('stat-high-value').textContent = stats.highValue; + document.getElementById('stat-strategic').textContent = stats.strategic; +} + +function setupFilters() { + const filters = ['tier', 'type', 'language', 'region']; + filters.forEach(filterId => { + document.getElementById(`filter-${filterId}`).addEventListener('change', applyFilters); + }); +} + +function applyFilters() { + const tierFilter = document.getElementById('filter-tier').value; + const typeFilter = document.getElementById('filter-type').value; + const languageFilter = document.getElementById('filter-language').value; + const regionFilter = document.getElementById('filter-region').value; + + filteredTargets = allTargets.filter(target => { + if (tierFilter && target.tier !== tierFilter) return false; + if (typeFilter && target.type !== typeFilter) return false; + if (languageFilter && target.requirements?.language !== languageFilter) return false; + if (regionFilter && target.country !== regionFilter) return false; + return true; + }); + + renderPublications(); +} + +function renderPublications() { + const container = document.getElementById('publications-container'); + + if (filteredTargets.length === 0) { + container.innerHTML = ` +
+

No publications match the selected filters.

+
+ `; + return; + } + + container.innerHTML = filteredTargets.map(target => createPublicationCard(target)).join(''); +} + +function createPublicationCard(target) { + const tierColors = { + 'premier': 'blue', + 'high-value': 'green', + 'strategic': 'purple' + }; + const color = tierColors[target.tier] || 'gray'; + + const wordCount = target.requirements?.wordCount + ? `${target.requirements.wordCount.min}-${target.requirements.wordCount.max} words${target.requirements.wordCount.strict ? ' (strict)' : ''}` + : 'N/A'; + + return ` +
+ +
+
+
+

${target.name}

+

${target.country} | Rank #${target.rank} | Score: ${target.score}

+
+ + ${target.tier.replace('-', ' ')} + +
+
+ + +
+
+

Submission Requirements

+
+
+ Type: + ${target.type} +
+
+ Language: + ${target.requirements?.language?.toUpperCase() || 'N/A'} +
+
+ Word Count: + ${wordCount} +
+ ${target.requirements?.exclusivity ? '
⚠ Exclusive submission required
' : ''} +
+
+ + +
+

How to Submit

+
+
Method: ${target.submission?.method || 'N/A'}
+
Email: ${target.submission?.email || 'N/A'}
+
Response Time: ${target.submission?.responseTime ? `${target.submission.responseTime.min}-${target.submission.responseTime.max} ${target.submission.responseTime.unit}` : 'N/A'}
+
+
+ + + ${target.editorial ? ` +
+

Editorial Guidelines

+
+ ${target.editorial.tone ? ` +
+ Tone: +
+ ${target.editorial.tone.map(t => `${t}`).join('')} +
+
+ ` : ''} + ${target.editorial.focus ? ` +
+ Focus Areas: +
+ ${target.editorial.focus.map(f => `${f}`).join('')} +
+
+ ` : ''} + ${target.editorial.avoid ? ` +
+ Avoid: +
+ ${target.editorial.avoid.map(a => `${a}`).join('')} +
+
+ ` : ''} +
+
+ ` : ''} + + + ${target.audience ? ` +
+

Target Audiences

+
+ ${target.audience.map(a => `${a}`).join('')} +
+
+ ` : ''} +
+
+ `; +} + +function showError(message) { + const container = document.getElementById('publications-container'); + container.innerHTML = ` +
+

${message}

+
+ `; +} diff --git a/src/routes/publications.routes.js b/src/routes/publications.routes.js index 1c0a0cc2..d1cd3f48 100644 --- a/src/routes/publications.routes.js +++ b/src/routes/publications.routes.js @@ -1,33 +1,31 @@ -/** - * Publications Routes - * API endpoints for publication targets - */ - const express = require('express'); const router = express.Router(); -const publicationsController = require('../controllers/publications.controller'); -const { authenticateToken, requireAdmin } = require('../middleware/auth.middleware'); +const publicationTargets = require('../config/publication-targets.config'); /** - * GET /api/publications - * Get all publications with optional filtering - * Query params: type, tier, culture, minRank, maxRank, language - * Public endpoint + * GET /api/publications/targets + * Returns all publication targets with guidelines */ -router.get('/', publicationsController.getPublications); +router.get('/targets', (req, res) => { + try { + // Convert to array and enrich with metadata + const targets = Object.entries(publicationTargets.PUBLICATION_TARGETS).map(([key, target]) => ({ + ...target, + key + })); -/** - * GET /api/publications/summary - * Get publication summary statistics - * Public endpoint - */ -router.get('/summary', publicationsController.getPublicationsSummary); - -/** - * GET /api/publications/:id - * Get specific publication by ID - * Public endpoint - */ -router.get('/:id', publicationsController.getPublicationById); + res.json({ + success: true, + total: targets.length, + targets + }); + } catch (error) { + console.error('Error fetching publication targets:', error); + res.status(500).json({ + success: false, + error: 'Failed to fetch publication targets' + }); + } +}); module.exports = router;