Skip to content

Commit 19fe374

Browse files
committed
feat: add hero statistics and scroll spy navigation while improving UI component stability and robustness
1 parent 9202122 commit 19fe374

1 file changed

Lines changed: 106 additions & 25 deletions

File tree

‎docs/index.html‎

Lines changed: 106 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,36 @@
192192
color: var(--primary);
193193
}
194194

195+
.nav-links a.active {
196+
color: var(--primary);
197+
font-weight: 700;
198+
}
199+
200+
.hero-stats {
201+
display: inline-flex;
202+
gap: 24px;
203+
margin-top: 24px;
204+
border-top: 1px solid var(--outline-variant);
205+
padding-top: 24px;
206+
}
207+
208+
.hero-stat {
209+
display: flex;
210+
flex-direction: column;
211+
}
212+
213+
.hero-stat strong {
214+
font-size: 1.4rem;
215+
color: var(--primary);
216+
}
217+
218+
.hero-stat span {
219+
font-size: 0.75rem;
220+
color: var(--on-surface-variant);
221+
text-transform: uppercase;
222+
letter-spacing: 0.5px;
223+
}
224+
195225
.header-download {
196226
background: var(--primary);
197227
border-radius: var(--radius);
@@ -572,13 +602,14 @@
572602

573603
.download-select {
574604
appearance: none;
575-
background: var(--surface);
605+
background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2372777F'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E") no-repeat right 12px center;
606+
background-size: 18px;
576607
border: 1px solid var(--outline-variant);
577608
border-radius: var(--radius);
578609
color: var(--on-background);
579610
margin-bottom: 12px;
580611
min-height: 46px;
581-
padding: 10px 12px;
612+
padding: 10px 38px 10px 12px;
582613
width: 100%;
583614
}
584615

@@ -863,8 +894,6 @@
863894
<a href="#screenshots">Screenshots</a>
864895
<a href="#download">Download</a>
865896
<a href="#privacy">Privacy</a>
866-
<a href="https://github.com/Coding-Meet/DevAnalyzer" rel="noopener noreferrer"
867-
target="_blank">GitHub</a>
868897
</div>
869898
<a class="button header-download" href="#download">Download</a>
870899
</nav>
@@ -906,6 +935,16 @@ <h1>DevAnalyzer</h1>
906935
<span class="chip">Windows, macOS, Linux</span>
907936
<span class="chip">Android & Kotlin Projects</span>
908937
</div>
938+
<div class="hero-stats">
939+
<div class="hero-stat">
940+
<strong data-stat="stars">Loading</strong>
941+
<span>GitHub Stars</span>
942+
</div>
943+
<div class="hero-stat">
944+
<strong data-stat="downloads">Loading</strong>
945+
<span>Total Downloads</span>
946+
</div>
947+
</div>
909948
</div>
910949
<div class="showcase animate-right" aria-label="DevAnalyzer interface preview">
911950
<div class="window-frame">
@@ -1130,19 +1169,30 @@ <h2>Get the installer made for your system.</h2>
11301169
<h2>Private by default.</h2>
11311170
<p>DevAnalyzer is designed to inspect development folders, project metadata, and toolchain paths locally.</p>
11321171
</div>
1133-
<div class="privacy-list">
1134-
<article class="privacy-item">
1135-
<h3>Local processing</h3>
1136-
<p>Project analysis and storage scans run on your machine.</p>
1137-
</article>
1138-
<article class="privacy-item">
1139-
<h3>Optional diagnostics</h3>
1140-
<p>Crash reporting and usage analytics can be managed from the app settings.</p>
1141-
</article>
1142-
<article class="privacy-item">
1143-
<h3>No project upload</h3>
1144-
<p>Source code, project names, and file paths are never uploaded or sent to remote servers.</p>
1145-
</article>
1172+
<div class="gallery">
1173+
<div class="privacy-list" style="grid-template-columns: 1fr;">
1174+
<article class="privacy-item">
1175+
<h3>Local processing</h3>
1176+
<p>Project analysis and storage scans run on your machine.</p>
1177+
</article>
1178+
<article class="privacy-item">
1179+
<h3>Optional diagnostics</h3>
1180+
<p>Crash reporting and usage analytics can be managed from the app settings.</p>
1181+
</article>
1182+
<article class="privacy-item">
1183+
<h3>No project upload</h3>
1184+
<p>Source code, project names, and file paths are never uploaded or sent to remote servers.</p>
1185+
</article>
1186+
</div>
1187+
<div class="window-frame" style="align-self: start;">
1188+
<div class="window-bar">
1189+
<span class="dot"></span>
1190+
<span class="dot"></span>
1191+
<span class="dot"></span>
1192+
</div>
1193+
<img alt="DevAnalyzer privacy settings and diagnostics switches"
1194+
src="screenshot/setting/img_2_diagnostics_section_all_feature_switch_crash_analytics.png">
1195+
</div>
11461196
</div>
11471197
</div>
11481198
</section>
@@ -1260,9 +1310,9 @@ <h3>No project upload</h3>
12601310

12611311
const meta = document.querySelector("[data-release-meta]");
12621312
if (asset) {
1263-
meta.textContent = `${asset.name} selected from the latest GitHub release.`;
1313+
if (meta) meta.textContent = `${asset.name} selected from the latest GitHub release.`;
12641314
} else {
1265-
meta.textContent = "Could not match a release asset. The button opens the GitHub releases page.";
1315+
if (meta) meta.textContent = "Could not match a release asset. The button opens the GitHub releases page.";
12661316
}
12671317
}
12681318

@@ -1277,25 +1327,32 @@ <h3>No project upload</h3>
12771327
if (repoResponse.ok) {
12781328
const repo = await repoResponse.json();
12791329
state.stars = repo.stargazers_count;
1280-
document.querySelector("[data-stat='stars']").textContent = formatNumber(state.stars);
1330+
document.querySelectorAll("[data-stat='stars']").forEach(el => {
1331+
el.textContent = formatNumber(state.stars);
1332+
});
12811333
}
12821334

12831335
if (latestResponse.ok) {
12841336
const latest = await latestResponse.json();
12851337
state.version = cleanVersion(latest.tag_name || latest.name);
12861338
state.assets = Array.isArray(latest.assets) ? latest.assets : [];
1287-
document.querySelector("[data-stat='version']").textContent = state.version || "Latest";
1339+
document.querySelectorAll("[data-stat='version']").forEach(el => {
1340+
el.textContent = state.version || "Latest";
1341+
});
12881342
}
12891343

12901344
if (releasesResponse.ok) {
12911345
const releases = await releasesResponse.json();
12921346
state.downloads = releases.reduce((total, release) => {
12931347
return total + (release.assets || []).reduce((sum, asset) => sum + (asset.download_count || 0), 0);
12941348
}, 0);
1295-
document.querySelector("[data-stat='downloads']").textContent = formatNumber(state.downloads);
1349+
document.querySelectorAll("[data-stat='downloads']").forEach(el => {
1350+
el.textContent = formatNumber(state.downloads);
1351+
});
12961352
}
12971353
} catch (error) {
1298-
document.querySelector("[data-release-meta]").textContent = "GitHub release data is unavailable right now. The button opens the releases page.";
1354+
const meta = document.querySelector("[data-release-meta]");
1355+
if (meta) meta.textContent = "GitHub release data is unavailable right now. The button opens the releases page.";
12991356
} finally {
13001357
updateDownloadUi();
13011358
}
@@ -1316,12 +1373,14 @@ <h3>No project upload</h3>
13161373

13171374
async function initDownloads() {
13181375
const select = document.querySelector("#installer-select");
1376+
if (!select) return;
13191377
state.selected = await detectInstaller();
13201378
select.value = state.selected;
1321-
document.querySelector("[data-detected-os]").textContent = `Detected: ${installers[state.selected].detect}`;
1379+
const detectedOs = document.querySelector("[data-detected-os]");
1380+
if (detectedOs) detectedOs.textContent = `Detected: ${installers[state.selected].detect}`;
13221381
select.addEventListener("change", () => {
13231382
state.selected = select.value;
1324-
document.querySelector("[data-detected-os]").textContent = `Selected: ${installers[state.selected].detect}`;
1383+
if (detectedOs) detectedOs.textContent = `Selected: ${installers[state.selected].detect}`;
13251384
updateDownloadUi();
13261385
});
13271386
await loadReleaseData();
@@ -1360,10 +1419,32 @@ <h3>No project upload</h3>
13601419
document.querySelectorAll(".reveal").forEach(el => observer.observe(el));
13611420
}
13621421

1422+
function initScrollSpy() {
1423+
const links = document.querySelectorAll(".nav-links a[href^='#']");
1424+
const sections = Array.from(links).map(link => document.querySelector(link.getAttribute("href")));
1425+
1426+
window.addEventListener("scroll", () => {
1427+
let current = "";
1428+
const scrollPos = window.scrollY + 120;
1429+
1430+
sections.forEach(section => {
1431+
if (section && scrollPos >= section.offsetTop) {
1432+
current = section.getAttribute("id");
1433+
}
1434+
});
1435+
1436+
links.forEach(link => {
1437+
link.classList.toggle("active", link.getAttribute("href") === `#${current}`);
1438+
});
1439+
});
1440+
}
1441+
13631442
document.addEventListener("DOMContentLoaded", () => {
13641443
initGallery();
13651444
initDownloads();
13661445
initReveal();
1446+
initScrollSpy();
1447+
loadReleaseData();
13671448
});
13681449
</script>
13691450
</body>

0 commit comments

Comments
 (0)