feat: Add mobile task index with 11ty build-time data
Phase 2 of task management consolidation: - Added _data/tasks.js - fetches tasks from Gitea API at build time - Added tasks-index.njk - mobile-friendly task list page - Added node-fetch dependency for API calls - Added .gitignore for node_modules and _site Features: - Shows only open/blocked tasks (filters out complete) - Priority filtering (P1/P2/P3/P4) - Color-coded priority badges (Fire/Gold/Frost/Arcane) - Links to Gitea for full task details - Mobile-optimized touch targets Access at: firefrostgaming.com/tasks-index.html Chronicler #69
This commit is contained in:
128
_data/tasks.js
Normal file
128
_data/tasks.js
Normal file
@@ -0,0 +1,128 @@
|
||||
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
||||
|
||||
module.exports = async function() {
|
||||
const GITEA_API = 'https://git.firefrostgaming.com/api/v1';
|
||||
const REPO_OWNER = 'firefrost-gaming';
|
||||
const REPO_NAME = 'firefrost-operations-manual';
|
||||
const TOKEN = process.env.GITEA_TOKEN || 'e0e330cba1749b01ab505093a160e4423ebbbe36';
|
||||
|
||||
const tasks = [];
|
||||
|
||||
try {
|
||||
// Get list of task directories
|
||||
const response = await fetch(
|
||||
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks?ref=master`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `token ${TOKEN}`,
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
timeout: 30000
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('Failed to fetch task list:', response.status);
|
||||
return [];
|
||||
}
|
||||
|
||||
const dirs = await response.json();
|
||||
const taskDirs = dirs.filter(d => d.type === 'dir' && d.name !== '_archive');
|
||||
|
||||
// Fetch each task's README
|
||||
for (const dir of taskDirs) {
|
||||
try {
|
||||
// Try README.md first
|
||||
let readmePath = `docs/tasks/${dir.name}/README.md`;
|
||||
let readmeResponse = await fetch(
|
||||
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `token ${TOKEN}`,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!readmeResponse.ok) {
|
||||
// Try to find any .md file
|
||||
const filesResponse = await fetch(
|
||||
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/docs/tasks/${encodeURIComponent(dir.name)}?ref=master`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `token ${TOKEN}`,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (filesResponse.ok) {
|
||||
const files = await filesResponse.json();
|
||||
const mdFile = files.find(f => f.name.endsWith('.md'));
|
||||
if (mdFile) {
|
||||
readmePath = `docs/tasks/${dir.name}/${mdFile.name}`;
|
||||
readmeResponse = await fetch(
|
||||
`${GITEA_API}/repos/${REPO_OWNER}/${REPO_NAME}/contents/${encodeURIComponent(readmePath)}?ref=master`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `token ${TOKEN}`,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (readmeResponse && readmeResponse.ok) {
|
||||
const fileData = await readmeResponse.json();
|
||||
const content = Buffer.from(fileData.content, 'base64').toString('utf-8');
|
||||
|
||||
// Parse YAML frontmatter
|
||||
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
||||
if (frontmatterMatch) {
|
||||
const frontmatter = {};
|
||||
frontmatterMatch[1].split('\n').forEach(line => {
|
||||
const match = line.match(/^(\w+):\s*(.+)$/);
|
||||
if (match) {
|
||||
frontmatter[match[1]] = match[2].trim();
|
||||
}
|
||||
});
|
||||
|
||||
// Extract title from first H1
|
||||
const titleMatch = content.match(/^#\s+(.+)$/m);
|
||||
const title = titleMatch ? titleMatch[1] : dir.name;
|
||||
|
||||
tasks.push({
|
||||
slug: dir.name,
|
||||
title: title,
|
||||
status: frontmatter.status || 'open',
|
||||
priority: frontmatter.priority || 'P3',
|
||||
owner: frontmatter.owner || 'Michael',
|
||||
created: frontmatter.created || '2026-01-01',
|
||||
giteaUrl: `https://git.firefrostgaming.com/${REPO_OWNER}/${REPO_NAME}/src/branch/master/docs/tasks/${encodeURIComponent(dir.name)}`
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error processing ${dir.name}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by priority (P1 first) then by title
|
||||
tasks.sort((a, b) => {
|
||||
if (a.priority !== b.priority) {
|
||||
return a.priority.localeCompare(b.priority);
|
||||
}
|
||||
return a.title.localeCompare(b.title);
|
||||
});
|
||||
|
||||
console.log(`[11ty] Loaded ${tasks.length} tasks from Gitea`);
|
||||
return tasks;
|
||||
|
||||
} catch (err) {
|
||||
console.error('[11ty] Error fetching tasks:', err.message);
|
||||
// Return empty array - page will still build, just with no tasks
|
||||
return [];
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user