Split mim-api into modular routes, refresh nav brand assets, and pin reusable validate workflow to Order-of-Hospitallers/miracles_in_motion@main. Co-authored-by: Cursor <cursoragent@cursor.com>
80 lines
2.1 KiB
JavaScript
80 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Trace nav PNG lockups to SVG via potrace (high-fidelity paths from approved raster).
|
|
* Usage: node scripts/brand/trace-nav-svg.mjs
|
|
*/
|
|
import { promises as fs } from 'node:fs'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import potrace from 'potrace'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
const brandDir = path.join(__dirname, '../../public/brand')
|
|
|
|
const traces = [
|
|
{
|
|
input: 'logo-horizontal-nav.png',
|
|
output: 'logo-horizontal-nav.svg',
|
|
title: 'Miracles in Motion Foundation',
|
|
potrace: {
|
|
color: 'auto',
|
|
background: 'transparent',
|
|
turdSize: 2,
|
|
optTolerance: 0.2,
|
|
threshold: 180,
|
|
},
|
|
},
|
|
{
|
|
input: 'logo-symbol-nav.png',
|
|
output: 'logo-symbol-nav.svg',
|
|
title: 'Miracles in Motion Foundation symbol',
|
|
potrace: {
|
|
color: 'auto',
|
|
background: 'transparent',
|
|
turdSize: 2,
|
|
optTolerance: 0.15,
|
|
threshold: 200,
|
|
},
|
|
},
|
|
]
|
|
|
|
function tracePng(inputPath, options) {
|
|
return new Promise((resolve, reject) => {
|
|
potrace.trace(inputPath, options, (err, svg) => {
|
|
if (err) reject(err)
|
|
else resolve(svg)
|
|
})
|
|
})
|
|
}
|
|
|
|
function normalizeSvg(svg, title) {
|
|
let out = svg.replace(/<\?xml[^>]*>\s*/i, '')
|
|
out = out.replace(/fill="black"/gi, 'fill="#D9AA45"')
|
|
out = out.replace(/fill="#000000"/gi, 'fill="#D9AA45"')
|
|
out = out.replace(/fill="#000"/gi, 'fill="#D9AA45"')
|
|
if (!out.includes('aria-hidden')) {
|
|
out = out.replace(/<svg\b/, '<svg role="img" aria-hidden="true"')
|
|
}
|
|
if (!out.includes('<title>')) {
|
|
out = out.replace(/<svg([^>]*)>/, `<svg$1>\n <title>${title}</title>`)
|
|
}
|
|
return out.trim() + '\n'
|
|
}
|
|
|
|
async function main() {
|
|
for (const job of traces) {
|
|
const inputPath = path.join(brandDir, job.input)
|
|
const outputPath = path.join(brandDir, job.output)
|
|
await fs.access(inputPath)
|
|
const raw = await tracePng(inputPath, job.potrace)
|
|
const svg = normalizeSvg(raw, job.title)
|
|
await fs.writeFile(outputPath, svg)
|
|
console.log(`Wrote ${job.output} (${svg.length} bytes)`)
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err)
|
|
process.exit(1)
|
|
})
|