Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions site/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ blog/feed.xml
changelist.html
news/
files/news.json
files/news-meta.json
files/blog.json

# Playground: vendored from web/ui/src/ for local-dev preview only.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
date: 2026-05-27
tag: dasImgui
title: 0.6.3 is just around the corner. In the meantime, check out dasImgui — now with imgui_playwright.
link: https://borisbat.github.io/dasImgui/
---
18 changes: 17 additions & 1 deletion site/blog/build_blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
blog/feed.xml — Atom feed of posts
news/<slug>.html — one per news entry that has a body
changelist.html — full long-form news list (all entries by date desc)
files/news.json — top-N news for forge.js to render landing § 05
files/news.json — top-N news for forge.js to render landing § 06
files/news-meta.json — newest_date + baseline_date + all dates, drives
the "N NEW" nav chip via files/news-counter.js

Hexo extensions translated:
<!-- more --> → excerpt boundary (excerpt above used on index)
Expand Down Expand Up @@ -553,6 +555,20 @@ def main():
(out / 'files' / 'blog.json').write_text(
json.dumps(blog_data, indent=2), encoding='utf-8')

# 8. news-meta.json — parallel of blog.json for the news feed; same
# metadata fields (newest_date, baseline_date), entries live under
# `news` instead of `posts`. Drives the "N NEW" chip on the news
# nav link via news-counter.js.
newest_news = news[0].date if news else '1970-01-01'
baseline_news = news[1].date if len(news) >= 2 else '1970-01-01'
news_meta = {
'newest_date': newest_news,
'baseline_date': baseline_news,
'news': [{'slug': n.slug, 'date': n.date} for n in news],
}
(out / 'files' / 'news-meta.json').write_text(
json.dumps(news_meta, indent=2), encoding='utf-8')

print(f"built {len(posts)} posts, {len(news)} news entries -> {out}/")


Expand Down
2 changes: 2 additions & 0 deletions site/blog/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<script src="{{root}}files/cm/daslang-keywords.js" defer></script>
<script src="{{root}}files/highlight.js" defer></script>
<script src="{{root}}files/blog-counter.js" defer></script>
<script src="{{root}}files/news-counter.js" defer></script>

<!-- Analytics -->
<script data-goatcounter="https://borisbat.goatcounter.com/count"
Expand All @@ -31,6 +32,7 @@
<span class="forge-mark__tld">.io</span>
</a>
<div class="forge-nav__links">
<a href="{{root}}index.html#news">news</a>
<a href="{{root}}doc/index.html">docs</a>
<a href="{{root}}index.html#benchmarks">benchmarks</a>
<a href="{{root}}downloads.html">downloads</a>
Expand Down
1 change: 1 addition & 0 deletions site/daspkg.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<span class="forge-mark__tld">.io</span>
</a>
<div class="forge-nav__links">
<a href="index.html#news">news</a>
<a href="doc/index.html">docs</a>
<a href="index.html#benchmarks">benchmarks</a>
<a href="downloads.html">downloads</a>
Expand Down
2 changes: 2 additions & 0 deletions site/downloads.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<span class="forge-mark__tld">.io</span>
</a>
<div class="forge-nav__links">
<a href="index.html#news">news</a>
<a href="doc/index.html">docs</a>
<a href="index.html#benchmarks">benchmarks</a>
<a href="downloads.html">downloads</a>
Expand Down Expand Up @@ -206,5 +207,6 @@ <h2 class="forge-h2">Where to learn more.</h2>

</div>
<script src="files/blog-counter.js" defer></script>
<script src="files/news-counter.js" defer></script>
</body>
</html>
2 changes: 1 addition & 1 deletion site/files/forge.js
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ def main() {
`<a href="/playground/index.html?example=${slug}">try <span class="forge-bench__playground-test">${escapeHtml(benchBm)}</span> on the playground →</a>`;
}

// ─── § 05 News feed (top 5 from news.json) ─────────────────────
// ─── § 06 News feed (top 5 from news.json) ─────────────────────
async function loadNews() {
const rowsEl = document.getElementById('news-rows');
if (!rowsEl) return;
Expand Down
115 changes: 115 additions & 0 deletions site/files/news-counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* Forge nav — "N NEW" news chip.
*
* Data source: files/news-meta.json (built by site/blog/build_blog.py).
* Storage: localStorage["daslang:news:lastSeen"] = "YYYY-MM-DD".
*
* Semantics (mirrors blog-counter.js):
* - First-time visitor (no key) → seeded from news-meta.json baseline_date,
* which is the 2nd-newest entry's date.
* So count = 1 (just the newest).
* - Landing with hash "#news" → key set to newest_date; chip clears.
* - Click on the news nav link → key set to newest_date.
* - count > 9 → render "9+ NEW".
* - count === 0 → chip not rendered.
*
* Nav anchors are matched by link.hash === "#news" so the same script works
* from any page that links to "#news" / "index.html#news" / "../index.html#news".
*/
(function () {
'use strict';

var STORAGE_KEY = 'daslang:news:lastSeen';

function readLastSeen() {
try { return window.localStorage.getItem(STORAGE_KEY); }
catch (_) { return null; }
}

function writeLastSeen(date) {
try { window.localStorage.setItem(STORAGE_KEY, date); }
catch (_) { /* private mode / quota — silent */ }
}

function newsJsonUrl() {
// Locate our own <script> tag and derive news-meta.json next to it.
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
var src = scripts[i].getAttribute('src') || '';
if (src.indexOf('news-counter.js') !== -1) {
return src.replace(/news-counter\.js(\?.*)?$/, 'news-meta.json');
}
}
return 'files/news-meta.json';
}

function findNewsLinks() {
// Match any nav link whose URL hash is "#news" — works for
// "#news", "index.html#news", "../index.html#news".
var links = document.querySelectorAll('.forge-nav__links a[href]');
var out = [];
for (var i = 0; i < links.length; i++) {
if (links[i].hash === '#news') out.push(links[i]);
}
return out;
}

function renderChip(anchor, count) {
if (anchor.querySelector('.forge-blog-chip')) return;
var chip = document.createElement('span');
chip.className = 'forge-blog-chip';
chip.textContent = (count > 9 ? '9+' : count) + ' NEW';
anchor.appendChild(chip);
anchor.classList.add('forge-blog-link');
}

function clearChips() {
var chips = document.querySelectorAll('.forge-nav__links a .forge-blog-chip');
for (var i = 0; i < chips.length; i++) {
var parent = chips[i].parentNode;
if (parent && parent.hash === '#news') {
chips[i].remove();
}
}
}

function update(data) {
// Landing-with-#news: mark seen and render nothing. Early-return so
// that a silently-failed writeLastSeen (private mode / quota) cannot
// still cause the chip to render — we are already on the destination.
if (window.location.hash === '#news') {
writeLastSeen(data.newest_date);
return;
}
var anchors = findNewsLinks();
for (var k = 0; k < anchors.length; k++) {
(function (a) {
a.addEventListener('click', function () {
writeLastSeen(data.newest_date);
clearChips();
});
})(anchors[k]);
}
var lastSeen = readLastSeen() || data.baseline_date;
var count = 0;
for (var i = 0; i < data.news.length; i++) {
if (data.news[i].date > lastSeen) count++;
}
if (count <= 0) return;
Comment thread
borisbat marked this conversation as resolved.
for (var j = 0; j < anchors.length; j++) {
renderChip(anchors[j], count);
}
}

function start() {
fetch(newsJsonUrl(), { cache: 'no-cache' })
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (data) { if (data) update(data); })
.catch(function () { /* offline / missing — silent */ });
}

if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
})();
4 changes: 3 additions & 1 deletion site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<span class="forge-mark__tld">.io</span>
</a>
<div class="forge-nav__links">
<a href="#news">news</a>
<a href="doc/index.html">docs</a>
<a href="#benchmarks">benchmarks</a>
<a href="downloads.html">downloads</a>
Expand Down Expand Up @@ -374,7 +375,7 @@ <h2>
</section>

<!-- ───── § 06 Changelog / news ───── -->
<section class="forge-section forge-section--alt">
<section class="forge-section forge-section--alt" id="news">
<div class="forge-container">
<div class="forge-section-label">
<span class="forge-section-label__num">§ 06</span>
Expand Down Expand Up @@ -452,5 +453,6 @@ <h2 class="forge-h2">Recent activity.</h2>
<script src="files/runner.js" defer></script>
<script src="files/forge.js" defer></script>
<script src="files/blog-counter.js" defer></script>
<script src="files/news-counter.js" defer></script>
</body>
</html>
1 change: 1 addition & 0 deletions site/playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<span class="forge-mark__tld">.io</span>
</a>
<div class="forge-nav__links">
<a href="../index.html#news">news</a>
<a href="../doc/index.html">docs</a>
<a href="../index.html#benchmarks">benchmarks</a>
<a href="../downloads.html">downloads</a>
Expand Down
Loading