← back to Dw Fleet Registry
fix-hero-ideas.mjs
74 lines
#!/usr/bin/env node
// Fleet template fix (Steve 2026-06-01): every DW sister site shows ONE big
// full-bleed hero (no 2×2 "four-square" grid) and ONE Ideas rail.
// - removes any LIVE <script src="/hero-4grid.js"> (leaves HTML comments untouched)
// - strips the inert 4-grid CSS rules (.cinema-grid / .hero4-cell / [data-hero-mode])
// - collapses the Ideas section to a single rail-block (drops the 2nd: "Curated picks" etc.)
// - deletes public/hero-4grid.js and public/hero-4grid.json
//
// node fix-hero-ideas.mjs --dry # report what would change, no writes
// node fix-hero-ideas.mjs # apply across all fleet repos
// node fix-hero-ideas.mjs --repo <path> # one repo
import fs from 'node:fs';
import path from 'node:path';
const DIR = path.dirname(new URL(import.meta.url).pathname);
const reg = JSON.parse(fs.readFileSync(path.join(DIR, 'dw-fleet-registry.json'), 'utf8'));
const DRY = process.argv.includes('--dry');
const oneRepo = process.argv.includes('--repo') ? process.argv[process.argv.indexOf('--repo') + 1] : null;
function transform(html) {
const notes = [];
let h = html;
// 1) Remove LIVE hero-4grid script tags. The alternation matches whole HTML
// comments FIRST (returned verbatim), so script tags *inside* comments are
// never touched — only genuinely live tags get removed.
let liveRemoved = 0;
h = h.replace(/<!--[\s\S]*?-->|<script[^>]*src=["']\/hero-4grid\.js["'][^>]*><\/script>/g,
(m) => { if (m.startsWith('<!--')) return m; liveRemoved++; return ''; });
// drop the now-orphaned "activate 2x2 hero" enabler comment too
h = h.replace(/\s*<!--\s*hero4-fix:[^>]*-->/g, '');
if (liveRemoved) notes.push('removed ' + liveRemoved + ' live hero-4grid script');
// 2) Strip inert 4-grid CSS rules + their comment.
const before2 = h;
h = h.replace(/\/\*[^*]*hero-4grid[\s\S]*?\*\//g, '');
h = h.replace(/\s*\.cinema-grid\s*\{[^}]*\}/g, '');
h = h.replace(/\s*\.hero4-cell\s*\{[^}]*\}/g, '');
h = h.replace(/\s*\[data-hero-mode="four-square"\][^{]*\{[^}]*\}/g, '');
h = h.replace(/\.cinema-bg,\s*\.hero4-cell,\s*\.cell/g, '.cinema-bg, .cell');
if (h !== before2) notes.push('stripped 4-grid CSS');
// 3) Collapse Ideas to a single rail-block (remove the 2nd).
const blockRe = /<div class="rail-block">[\s\S]*?<div class="rail" id="[^"]*"><\/div>\s*<\/div>/g;
const blocks = [...h.matchAll(blockRe)];
if (blocks.length >= 2) {
const b = blocks[1];
h = h.slice(0, b.index) + h.slice(b.index + b[0].length);
notes.push('removed 2nd ideas rail');
}
return { html: h, notes };
}
const repos = oneRepo ? [oneRepo] : [...new Set(reg.sites.map(s => s.local?.repoPath).filter(Boolean))];
let changed = 0, filesDeleted = 0;
const summary = [];
for (const rp of repos.sort()) {
const f = path.join(rp, 'public', 'index.html');
if (!fs.existsSync(f)) continue;
const orig = fs.readFileSync(f, 'utf8');
const { html, notes } = transform(orig);
const delFiles = ['hero-4grid.js', 'hero-4grid.json'].map(n => path.join(rp, 'public', n)).filter(fs.existsSync);
if (html === orig && !delFiles.length) continue;
changed++;
summary.push(path.basename(rp).padEnd(28) + (notes.join('; ') || 'no html change') + (delFiles.length ? '; del ' + delFiles.length + ' file(s)' : ''));
if (!DRY) {
if (html !== orig) fs.writeFileSync(f, html);
for (const df of delFiles) { fs.unlinkSync(df); filesDeleted++; }
}
}
console.log(summary.join('\n'));
console.log('\n' + (DRY ? '[DRY] ' : '') + 'repos affected: ' + changed + (DRY ? '' : ('; files deleted: ' + filesDeleted)));