- Replace safe-area-inset padding with fixed 42px right / 24px left (safe-area was 59px on both sides of iPhone Pro Max, too aggressive) - Move center-label/eye-button hiding to height-based media query covering all landscape phones, not just >851px - Add compact h1 (24px), smaller month-preview donuts (28px) for larger landscape phones - Server: add Cache-Control: no-cache, strip query strings from URLs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
74 lines
2.2 KiB
JavaScript
74 lines
2.2 KiB
JavaScript
const http = require('http');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const PORT = 3000;
|
|
const DATA_DIR = process.env.DATA_DIR || '.';
|
|
|
|
const MIME_TYPES = {
|
|
'.html': 'text/html',
|
|
'.css': 'text/css',
|
|
'.js': 'text/javascript',
|
|
'.json': 'application/json',
|
|
'.csv': 'text/csv',
|
|
};
|
|
|
|
const server = http.createServer((req, res) => {
|
|
// API endpoint to list available months
|
|
if (req.url === '/api/months') {
|
|
fs.readdir(DATA_DIR, (err, files) => {
|
|
if (err) {
|
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ error: 'Failed to read directory' }));
|
|
return;
|
|
}
|
|
|
|
// Find CSV files matching altcats-YYYY-MM.csv pattern
|
|
const monthPattern = /^altcats-(\d{4}-\d{2})\.csv$/;
|
|
const months = files
|
|
.map(file => {
|
|
const match = file.match(monthPattern);
|
|
return match ? match[1] : null;
|
|
})
|
|
.filter(Boolean)
|
|
.sort();
|
|
|
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify(months));
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Handle URL (strip query string)
|
|
const urlPath = req.url.split('?')[0];
|
|
let filePath = '.' + urlPath;
|
|
if (filePath === './') {
|
|
filePath = './index.html';
|
|
} else if (filePath.endsWith('.csv')) {
|
|
filePath = path.join(DATA_DIR, path.basename(filePath));
|
|
}
|
|
|
|
const extname = path.extname(filePath);
|
|
const contentType = MIME_TYPES[extname] || 'application/octet-stream';
|
|
|
|
fs.readFile(filePath, (err, data) => {
|
|
if (err) {
|
|
if (err.code === 'ENOENT') {
|
|
res.writeHead(404);
|
|
res.end('File not found');
|
|
} else {
|
|
res.writeHead(500);
|
|
res.end('Server error: ' + err.code);
|
|
}
|
|
return;
|
|
}
|
|
|
|
res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': 'no-cache' });
|
|
res.end(data);
|
|
});
|
|
});
|
|
|
|
server.listen(PORT, () => {
|
|
console.log(`Server running at http://localhost:${PORT}/`);
|
|
console.log(`Visualizing spending data with ECharts...`);
|
|
});
|