// 뷰 헬퍼 — 빌드/프런트 프레임워크 없이 서버에서 SVG 를 직접 만들어 EJS 로 출력한다.
// (디자인 레퍼런스의 Octicon 패스 / identicon 알고리즘 / 언어색을 그대로 포팅)
// res.locals 에 실어 모든 뷰에서 icon()/identicon()/langColor() 로 사용.
// GitHub Octicon 16x16 패스 모음.
const OCTICONS = {
code: '',
search: '',
sun: '',
moon: '',
caret: '',
signout: '',
lock: '',
globe: '',
repo: '',
starFill: '',
star: '',
heart: '',
heartFill: '',
comment: '',
plus: '',
x: '',
reply: '',
check: '',
ext: '',
trash: '',
};
// 인라인 SVG 아이콘 문자열. fill 기본은 currentColor(부모 색 상속).
export function icon(name, opts = {}) {
const size = opts.size || 16;
const fill = opts.fill || "currentColor";
const path = OCTICONS[name] || OCTICONS.repo;
return (
``
);
}
// 언어 → 색(카드의 언어 점).
const LANG_COLORS = {
Python: "#3572A5", TypeScript: "#3178c6", JavaScript: "#f1e05a",
Go: "#00ADD8", Rust: "#dea584", Shell: "#89e051", Java: "#b07219",
};
export function langColor(lang) {
return LANG_COLORS[lang] || "#8b949e";
}
// 태그에서 대표 언어 추론(프로젝트 등록 시 lang 저장용).
export function langFromTags(tags) {
const t = (tags || []).map((x) => String(x).toLowerCase());
if (t.includes("fastapi") || t.includes("python") || t.includes("django")) return "Python";
if (t.includes("react") || t.includes("ts") || t.includes("typescript") || t.includes("next")) return "TypeScript";
if (t.includes("go") || t.includes("golang")) return "Go";
if (t.includes("rust")) return "Rust";
if (t.includes("node") || t.includes("js")) return "JavaScript";
return "TypeScript";
}
// 문자열 → 결정적 해시(아바타/색 시드).
function hashSeed(seed) {
let h = 0;
const s = String(seed);
for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0;
return h;
}
// 사번 기반 identicon 아바타(5x5 대칭 격자). 디자인과 동일한 시각.
export function identicon(seed, size = 28) {
const h = hashSeed(seed);
const hue = h % 360;
const sat = 48 + (h % 22);
const color = `hsl(${hue},${sat}%,52%)`;
const grid = 5;
const on = new Array(25).fill(false);
for (let col = 0; col < 3; col++) {
for (let row = 0; row < 5; row++) {
const bit = (h >> (col * 5 + row)) & 1;
on[row * 5 + col] = !!bit;
on[row * 5 + (4 - col)] = !!bit;
}
}
const inner = Math.round(size * 0.74);
const cell = inner / grid;
let rects = "";
for (let r = 0; r < grid; r++) {
for (let c = 0; c < grid; c++) {
if (on[r * grid + c]) {
rects += ``;
}
}
}
const radius = Math.max(5, Math.round(size * 0.2));
const svg = ``;
return (
`${svg}`
);
}