-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
224 lines (197 loc) · 8.13 KB
/
Copy pathscript.js
File metadata and controls
224 lines (197 loc) · 8.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
const root = document.documentElement;
window.addEventListener("pointermove", (event) => {
root.style.setProperty("--pointer-x", `${event.clientX}px`);
root.style.setProperty("--pointer-y", `${event.clientY}px`);
}, { passive: true });
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.dataset.visible = "true";
observer.unobserve(entry.target);
}
}
}, { threshold: 0.15 });
const observeProject = (element) => observer.observe(element);
document.querySelectorAll(".project").forEach(observeProject);
const addProjectNumber = (project, number) => {
const visual = project.querySelector(".project-visual");
if (!visual || visual.querySelector(".project-number")) return;
const label = document.createElement("b");
label.className = "project-number";
label.textContent = String(number).padStart(2, "0");
visual.append(label);
};
document.querySelectorAll(".work > article.project").forEach((project, index) => {
addProjectNumber(project, index + 1);
});
const featuredProjects = new Set([
"engineer-mcp",
"agent-trace-workbench",
"engineer-profile",
"signal-garden",
"dot-matrix-deck",
"cinderstore",
"DanielCuevas1208.github.io",
"DanielCuevas1208",
"localprofilecoder",
]);
const projectOverrides = {
"sprout-lang": {
language: "Go",
description: "A small programming language with an interpreter and a bytecode virtual machine. It supports file modules, imports, exports, and cycle checks.",
},
"gatework": {
language: "Haskell",
description: "An event-driven digital-logic simulator. It reads plain-text netlists and writes VCD waveform files and text reports.",
},
"tumble-lab": {
language: "Lua",
description: "A deterministic 2D rigid-body simulation lab with collision handling and a headless runner. Interactive presentation is planned.",
},
"latch": {
language: "Erlang",
description: "An experimental encrypted-messaging library with ratchet-based message keys. Handshake authentication is planned. The current release requires a trusted transport.",
},
"inkline-maps": {
language: "Kotlin",
description: "An offline renderer for local OpenStreetMap XML extracts. It uses a plain-text style sheet and writes PNG and SVG maps.",
},
"engineering-design-assistant": {
language: "Dart",
description: "A local tool that stores typed engineering requirements and checks units and constraints. It provides a Flutter app, a CLI, and an MCP server.",
},
"turtleyard": {
language: "Pharo Smalltalk",
description: "A compact Pharo Smalltalk environment for turtle graphics. It supports live drawing, L-system expansion, and PNG export.",
},
"paper-orrery": {
language: "F#",
description: "An astronomy calculator that uses bundled orbital elements. It converts positions to the local horizon and writes SVG sky charts.",
},
"rota-forge": {
language: "Scala",
description: "A staff-rostering solver that reads staff, shifts, and rules from CSV files. It writes scored schedules as CSV and HTML.",
},
"specimen-press": {
language: "Swift",
description: "A font-inspection toolkit that reads TrueType tables. It extracts glyph outlines and metrics and writes SVG specimen sheets.",
},
"morphoscope": {
language: "Prolog",
description: "A SWI-Prolog morphological analyzer. It applies documented English and Spanish inflection rules in both directions.",
},
"clausecraft": {
language: "OCaml",
description: "A compact SAT solver with DIMACS input, DPLL search, unit propagation, model checks, and a Sudoku demo. Clause learning and restarts are planned.",
},
"gtfs-accessibility-auditor": {
language: "TypeScript",
description: "A CLI that audits GTFS wheelchair data and route-level gaps. It writes JSON and HTML reports.",
},
};
const hasTopic = (repo, topic) =>
Array.isArray(repo.topics) && repo.topics.includes(topic);
const displayName = (name) => name
.split("-")
.map((word) => word ? `${word[0].toUpperCase()}${word.slice(1)}` : word)
.join(" ");
const graphicByRepo = {
"dungeonwright": "map",
"gatework": "logic",
"sprout-lang": "terminal",
"latch": "network",
"driftlog": "merge",
"stonehue": "board",
"tumble-lab": "physics",
"patchbay-synth": "wave",
"personal-ledger-lab": "bars",
"packet-forensics-lab": "packets",
"local-first-job-queue": "queue",
"shader-sketchbook": "shader",
};
const createGraphic = (repo) => {
const variant = graphicByRepo[repo.name] || "network";
const graphic = document.createElement("div");
graphic.className = `auto-visual graphic-${variant}`;
const languageLabel = document.createElement("strong");
languageLabel.textContent = repo.language || "SOFTWARE";
const marks = document.createElement("div");
marks.className = "graphic-marks";
for (let index = 0; index < 6; index += 1) {
const mark = document.createElement("span");
mark.className = `mark-${index + 1}`;
marks.append(mark);
}
const caption = document.createElement("small");
caption.textContent = "showcase project";
graphic.append(languageLabel, marks, caption);
return graphic;
};
function renderProjects(targetId, sectionId, repositories, category) {
if (repositories.length === 0) return;
const shelf = document.querySelector(`#${targetId}`);
if (!shelf) return;
repositories.forEach((repo, index) => {
const showcase = category === "Showcase";
const article = document.createElement("article");
const palette = ["project-blue", "project-pink", "project-yellow", "project-green"][index % 4];
article.className = showcase ? `project compact-project ${palette}` : "shelf-card";
const label = document.createElement("p");
label.className = "project-type";
label.textContent = `${repo.language || "Software project"} / ${category}`;
const title = document.createElement("h3");
title.textContent = displayName(repo.name);
const description = document.createElement("p");
description.textContent = repo.description || "A recent software experiment.";
const copy = document.createElement("div");
copy.className = "project-copy";
const link = document.createElement("a");
link.href = repo.html_url;
link.textContent = "View project ->";
if (showcase) {
const highlights = document.createElement("ul");
highlights.setAttribute("aria-label", "Project details");
for (const detail of [repo.language || "Software", "Showcase project"]) {
const item = document.createElement("li");
item.textContent = detail;
highlights.append(item);
}
const visual = document.createElement("div");
visual.className = "project-visual";
visual.setAttribute("aria-hidden", "true");
visual.append(createGraphic(repo));
copy.append(label, title, description, highlights, link);
article.append(copy, visual);
addProjectNumber(article, index + 7);
observeProject(article);
} else {
article.append(label, title, description, link);
}
shelf.append(article);
});
const section = document.querySelector(`#${sectionId}`);
if (section) section.hidden = false;
}
async function loadPortfolioProjects() {
const response = await fetch(
"https://api.github.com/users/DanielCuevas1208/repos?sort=pushed&per_page=100",
{ headers: { Accept: "application/vnd.github+json" } },
);
if (!response.ok) return;
const repositories = await response.json();
const projects = repositories
.filter((repo) =>
!repo.fork &&
!featuredProjects.has(repo.name) &&
Array.isArray(repo.topics) &&
repo.topics.includes("portfolio")
)
.map((repo) => ({ ...repo, ...(projectOverrides[repo.name] || {}) }));
const showcase = projects.filter((repo) => hasTopic(repo, "showcase-project"));
const supporting = projects.filter((repo) =>
!hasTopic(repo, "showcase-project") && hasTopic(repo, "supporting-project")
);
renderProjects("github-showcase-projects", "github-showcase", showcase, "Showcase");
renderProjects("github-supporting-projects", "supporting", supporting, "Supporting");
}
loadPortfolioProjects().catch(() => undefined);