80 lines
2.8 KiB
JavaScript
80 lines
2.8 KiB
JavaScript
/* Syntax highlighting (Prism) + file-type icon metadata. */
|
|
(function () {
|
|
const EXT_LANG = {
|
|
php: "php", js: "javascript", mjs: "javascript", cjs: "javascript",
|
|
jsx: "jsx", ts: "typescript", tsx: "tsx", py: "python",
|
|
html: "markup", xml: "markup", svg: "markup", vue: "markup",
|
|
css: "css", scss: "css", json: "json", md: "markdown",
|
|
sh: "bash", bash: "bash", yml: "yaml", yaml: "yaml", env: "bash",
|
|
};
|
|
|
|
function ext(path) {
|
|
const base = path.split("/").pop() || "";
|
|
if (base === ".env" || base.startsWith(".env")) return "env";
|
|
const i = base.lastIndexOf(".");
|
|
return i >= 0 ? base.slice(i + 1).toLowerCase() : "";
|
|
}
|
|
|
|
function langFor(path) { return EXT_LANG[ext(path)] || null; }
|
|
|
|
function langLabel(path) {
|
|
const e = ext(path);
|
|
const map = {
|
|
php: "PHP", js: "JavaScript", mjs: "JavaScript", ts: "TypeScript",
|
|
tsx: "TypeScript", jsx: "JavaScript", py: "Python", html: "HTML",
|
|
css: "CSS", json: "JSON", md: "Markdown", sh: "Shell", env: "Dotenv",
|
|
yml: "YAML", yaml: "YAML",
|
|
};
|
|
return map[e] || (e ? e.toUpperCase() : "Plain Text");
|
|
}
|
|
|
|
function escapeHtml(s) {
|
|
return s.replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" }[c]));
|
|
}
|
|
|
|
// highlight a single line independently (keeps line numbering robust)
|
|
function hlLine(line, lang) {
|
|
if (line === "") return " ";
|
|
try {
|
|
const grammar = lang && window.Prism && Prism.languages[lang];
|
|
if (grammar) return Prism.highlight(line, grammar, lang);
|
|
} catch (e) { /* fall through */ }
|
|
return escapeHtml(line);
|
|
}
|
|
|
|
// ---- file-type icon: colored monogram chip --------------------------
|
|
const ICONS = {
|
|
php: { c: "#a78bdb", t: "php" },
|
|
js: { c: "#e6c860", t: "js" },
|
|
mjs: { c: "#e6c860", t: "js" },
|
|
ts: { c: "#5a9bd6", t: "ts" },
|
|
tsx: { c: "#5a9bd6", t: "ts" },
|
|
jsx: { c: "#5a9bd6", t: "jsx" },
|
|
py: { c: "#5fa8d6", t: "py" },
|
|
html: { c: "#e08b6a", t: "<>" },
|
|
css: { c: "#5a9bd6", t: "{}" },
|
|
scss: { c: "#d6699e", t: "{}" },
|
|
json: { c: "#d8a85c", t: "{}" },
|
|
md: { c: "#9aa0a8", t: "md" },
|
|
env: { c: "#7fc6a0", t: "$" },
|
|
sh: { c: "#7fc6a0", t: "$" },
|
|
yml: { c: "#cf7a6a", t: "yml" },
|
|
yaml: { c: "#cf7a6a", t: "yml" },
|
|
lock: { c: "#8a8f98", t: "lk" },
|
|
};
|
|
const NAME_ICONS = {
|
|
"composer.json": { c: "#a78bdb", t: "co" },
|
|
"package.json": { c: "#cf7a6a", t: "pk" },
|
|
"README.md": { c: "#5a9bd6", t: "md" },
|
|
".env": { c: "#7fc6a0", t: "$" },
|
|
};
|
|
|
|
function iconFor(path) {
|
|
const base = path.split("/").pop() || "";
|
|
if (NAME_ICONS[base]) return NAME_ICONS[base];
|
|
return ICONS[ext(path)] || { c: "#7d838c", t: base.slice(0, 2) || "·" };
|
|
}
|
|
|
|
window.HL = { ext, langFor, langLabel, hlLine, iconFor, escapeHtml };
|
|
})();
|