refactor: centralize theme/config/utils + fix data and console bugs
Phase 1 of the cohesion refactor (behavior-preserving): Single source of truth: - New src/lib/theme.ts: category colors (moved from data.ts, re-exported for back-compat), derived hex strings, nebula palette, UI colors, CSS var map - New src/lib/config.ts: breakpoint, zoom, parallax, node radii, particle counts, animation timings (previously scattered magic numbers) - New src/lib/utils/tree.ts: getNodeById, getNodeRadius, getDistanceFromOrigin, getBeamIntensity (pure helpers lifted out of onMount) - New src/lib/utils/stats.ts: branch ids/labels, proficiency order, and the stats-panel aggregation helpers (deduped from inline copies) - SkillTree.svelte now imports all of the above; removed the duplicated getCategoryColorHex, stats helpers, branch id/label lists, and inline magic numbers - Populated src/lib/index.ts barrel Bug fixes: - data.ts: tmdbAPI pypiUrl pointed at tvdbAPI -> corrected to tmdbAPI - Removed/ gated stray console.log noise (skill-tree-loaded, SW logs) - Removed dead vars (maxAlpha, glowMaxAlpha) and unused catch binding Tooling: ESLint + Prettier now clean; added Vitest unit tests for the new pure utils (14 tests). svelte-check: 0 errors. build: ok. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
aa58425f1a
commit
6c652e7138
12 files changed
+491
-219
No files matched your search
@@ -0,0 +1,82 @@
|
||||
// ==========================================================================
|
||||
// STATS UTILS — pure aggregation for the RPG-style character panel.
|
||||
// ==========================================================================
|
||||
|
||||
import { treeNodes, type TreeNode } from '$lib/data';
|
||||
|
||||
/** Skill branch ids and their display labels (single source of truth). */
|
||||
export const BRANCH_IDS = [
|
||||
'concepts',
|
||||
'tools-devops',
|
||||
'frontend',
|
||||
'backend-real-time',
|
||||
'languages'
|
||||
] as const;
|
||||
|
||||
export const BRANCH_LABELS: Record<string, string> = {
|
||||
concepts: 'Concepts',
|
||||
'tools-devops': 'Tools & DevOps',
|
||||
frontend: 'Frontend',
|
||||
'backend-real-time': 'Backend & Real-Time',
|
||||
languages: 'Languages'
|
||||
};
|
||||
|
||||
/** Proficiency sort order (best first). */
|
||||
export const PROFICIENCY_ORDER: Record<string, number> = {
|
||||
expert: 0,
|
||||
advanced: 1,
|
||||
intermediate: 2,
|
||||
beginner: 3
|
||||
};
|
||||
|
||||
/** Character "level" derived from years since the first job started. */
|
||||
export function calculatePlayerLevel(): number {
|
||||
const earliestStart = new Date('2020-10-01'); // First job
|
||||
const now = new Date();
|
||||
const millisPerYear = 1000 * 60 * 60 * 24 * 365.25;
|
||||
const years = (now.getTime() - earliestStart.getTime()) / millisPerYear;
|
||||
return Math.floor(years);
|
||||
}
|
||||
|
||||
/** Character "class" — the origin node's job title. */
|
||||
export function getPlayerClass(): string {
|
||||
const originNode = treeNodes.find((node) => node.id === 'origin');
|
||||
return originNode?.jobTitle || 'Software Engineer';
|
||||
}
|
||||
|
||||
/** Group skill nodes by branch, sorted by proficiency. */
|
||||
export function aggregateSkills(): Record<string, { label: string; skills: TreeNode[] }> {
|
||||
const result: Record<string, { label: string; skills: TreeNode[] }> = {};
|
||||
|
||||
BRANCH_IDS.forEach((branchId) => {
|
||||
const skills = treeNodes.filter(
|
||||
(node) => node.parentId === branchId && node.category === 'skills'
|
||||
);
|
||||
|
||||
skills.sort((a, b) => {
|
||||
const aOrder = PROFICIENCY_ORDER[a.proficiency || 'beginner'];
|
||||
const bOrder = PROFICIENCY_ORDER[b.proficiency || 'beginner'];
|
||||
return aOrder - bOrder;
|
||||
});
|
||||
|
||||
result[branchId] = { label: BRANCH_LABELS[branchId], skills };
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Count all skill nodes by proficiency tier. */
|
||||
export function countByProficiency(): {
|
||||
expert: number;
|
||||
advanced: number;
|
||||
intermediate: number;
|
||||
beginner: number;
|
||||
} {
|
||||
const counts = { expert: 0, advanced: 0, intermediate: 0, beginner: 0 };
|
||||
treeNodes.forEach((node) => {
|
||||
if (node.proficiency) {
|
||||
counts[node.proficiency]++;
|
||||
}
|
||||
});
|
||||
return counts;
|
||||
}
|
||||
Reference in new issue
Block a user