feat: AI Pricing Transparency Scanner Chrome Extension v1.0.0

This commit is contained in:
Bun Bun
2026-06-22 05:47:35 +00:00
commit 4906edb65a
18 changed files with 1631 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
// scripts/build.mjs — copies src to dist (no transpilation needed, plain JS)
import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync, copyFileSync, existsSync } from 'fs';
import { join, dirname, relative } from 'path';
const root = dirname(new URL(import.meta.url).pathname);
const projectRoot = join(root, '..');
const srcDir = join(projectRoot, 'src');
const distDir = join(projectRoot, 'dist');
function copyDir(src, dest) {
mkdirSync(dest, { recursive: true });
const entries = readdirSync(src);
for (const entry of entries) {
const srcPath = join(src, entry);
const destPath = join(dest, entry);
const stat = statSync(srcPath);
if (stat.isDirectory()) {
copyDir(srcPath, destPath);
} else {
copyFileSync(srcPath, destPath);
}
}
}
// Clean dist
if (existsSync(distDir)) {
// Just overwrite files
}
copyDir(srcDir, distDir);
console.log('Build complete: src → dist');
+96
View File
@@ -0,0 +1,96 @@
// Generate PNG icons for the Chrome extension
import { writeFileSync, mkdirSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import zlib from 'zlib';
const __dirname = dirname(fileURLToPath(import.meta.url));
const iconsDir = join(__dirname, '..', 'src', 'icons');
mkdirSync(iconsDir, { recursive: true });
function crc32(buf) {
var crc = 0xFFFFFFFF;
for (var i = 0; i < buf.length; i++) {
crc ^= buf[i];
for (var j = 0; j < 8; j++) {
crc = (crc >>> 1) ^ (crc & 1 ? 0xEDB88320 : 0);
}
}
return (crc ^ 0xFFFFFFFF) >>> 0;
}
function makeChunk(type, data) {
var len = Buffer.alloc(4);
len.writeUInt32BE(data.length, 0);
var typeBuffer = Buffer.from(type, 'ascii');
var crcData = Buffer.concat([typeBuffer, data]);
var crc = crc32(crcData);
var crcBuf = Buffer.alloc(4);
crcBuf.writeUInt32BE(crc, 0);
return Buffer.concat([len, typeBuffer, data, crcBuf]);
}
function createPNG(width, height) {
var signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
var ihdrData = Buffer.alloc(13);
ihdrData.writeUInt32BE(width, 0);
ihdrData.writeUInt32BE(height, 4);
ihdrData[8] = 8; ihdrData[9] = 2; ihdrData[10] = 0; ihdrData[11] = 0; ihdrData[12] = 0;
var ihdr = makeChunk('IHDR', ihdrData);
var rawData = [];
var cx = width / 2, cy = height / 2;
var maxDist = Math.sqrt(cx * cx + cy * cy);
var innerR = Math.min(width, height) * 0.35;
var handleR = Math.min(width, height) * 0.08;
for (var y = 0; y < height; y++) {
rawData.push(0); // filter byte
for (var x = 0; x < width; x++) {
var dist = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
var t = dist / maxDist;
// Background gradient: #667eea to #764ba2
var bgR = Math.round(102 * (1 - t) + 118 * t);
var bgG = Math.round(126 * (1 - t) + 75 * t);
var bgB = Math.round(234 * (1 - t) + 162 * t);
var pr = bgR, pg = bgG, pb = bgB;
// White circle (magnifying glass lens)
if (dist < innerR) {
pr = 255; pg = 255; pb = 255;
// Inner dark ring (lens border)
if (dist > innerR * 0.8) {
pr = 80; pg = 80; pb = 120;
}
}
// Handle (bottom-right diagonal)
var handleStart = innerR * 0.9;
var handleLen = maxDist * 0.5;
var hx = x - cx, hy = y - cy;
var proj = (hx + hy) / Math.sqrt(2);
var perp = Math.abs(hx - hy) / Math.sqrt(2);
if (proj > handleStart && proj < handleStart + handleLen && perp < handleR) {
pr = 200; pg = 200; pb = 220;
}
rawData.push(pr, pg, pb);
}
}
var deflated = zlib.deflateSync(Buffer.from(rawData));
var idat = makeChunk('IDAT', deflated);
var iend = makeChunk('IEND', Buffer.alloc(0));
return Buffer.concat([signature, ihdr, idat, iend]);
}
var sizes = [16, 48, 128];
sizes.forEach(function (size) {
var png = createPNG(size, size);
var filepath = join(iconsDir, 'icon-' + size + '.png');
writeFileSync(filepath, png);
console.log('Created ' + filepath + ' (' + png.length + ' bytes)');
});
console.log('Icons generated.');