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/blog.json

# Playground: vendored from web/ui/src/ for local-dev preview only.
# CI rebuilds these from source on every publish. To preview locally:
Expand Down
13 changes: 13 additions & 0 deletions site/blog/build_blog.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,19 @@ def main():
(out / 'files' / 'news.json').write_text(
json.dumps(top_news, indent=2), encoding='utf-8')

# 7. blog.json — drives the "N NEW" nav chip. baseline_date is the
# date of the second-newest post: a first-time visitor (no
# localStorage) sees exactly one post counted as new (the newest).
newest_date = posts[0].date if posts else '1970-01-01'
baseline_date = posts[1].date if len(posts) >= 2 else '1970-01-01'
blog_data = {
'newest_date': newest_date,
'baseline_date': baseline_date,
'posts': [{'slug': p.slug, 'date': p.date} for p in posts],
}
(out / 'files' / 'blog.json').write_text(
json.dumps(blog_data, indent=2), encoding='utf-8')

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


Expand Down
5 changes: 5 additions & 0 deletions site/blog/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
<link rel="stylesheet" href="{{root}}files/forge.css" />
<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>

<!-- Analytics -->
<script data-goatcounter="https://borisbat.goatcounter.com/count"
async src="//gc.zgo.at/count.js"></script>
</head>
<body>
<div class="forge-page">
Expand Down
1 change: 1 addition & 0 deletions site/downloads.html
Original file line number Diff line number Diff line change
Expand Up @@ -202,5 +202,6 @@ <h2 class="forge-h2">Where to learn more.</h2>
</footer>

</div>
<script src="files/blog-counter.js" defer></script>
</body>
</html>
103 changes: 103 additions & 0 deletions site/files/blog-counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* Forge nav — "N NEW" blog chip.
*
* Data source: files/blog.json (built by site/blog/build_blog.py).
* Storage: localStorage["daslang:blog:lastSeen"] = "YYYY-MM-DD".
*
* Semantics:
* - First-time visitor (no key) → seeded from blog.json baseline_date,
* which is the 2nd-newest post's date.
* So count = 1 (just the newest).
* - Visiting /blog/ (the index) → key set to newest_date; chip clears.
* - count > 9 → render "9+ NEW".
* - count === 0 → chip not rendered.
*/
(function () {
'use strict';

var STORAGE_KEY = 'daslang:blog:lastSeen';

function isBlogIndex() {
var p = window.location.pathname;
return p.endsWith('/blog/') || p.endsWith('/blog/index.html');
}

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 blogJsonUrl() {
// Locate our own <script> tag and derive blog.json sitting 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('blog-counter.js') !== -1) {
return src.replace(/blog-counter\.js(\?.*)?$/, 'blog.json');
}
}
return 'files/blog.json';
}

function findBlogLinks() {
var links = document.querySelectorAll('a[href]');
var out = [];
for (var i = 0; i < links.length; i++) {
// .href resolves the relative href against the page URL.
var resolved = links[i].href;
if (resolved.endsWith('/blog/index.html') ||
resolved.endsWith('/blog/')) {
// Skip the footer link — only chip the top nav. Heuristic:
// the nav link sits inside .forge-nav__links.
if (links[i].closest('.forge-nav__links')) {
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 update(data) {
// On the blog index itself: mark seen, render nothing.
if (isBlogIndex()) {
writeLastSeen(data.newest_date);
return;
}
var lastSeen = readLastSeen() || data.baseline_date;
var count = 0;
for (var i = 0; i < data.posts.length; i++) {
if (data.posts[i].date > lastSeen) count++;
}
if (count <= 0) return;
var anchors = findBlogLinks();
for (var j = 0; j < anchors.length; j++) {
renderChip(anchors[j], count);
}
}

function start() {
fetch(blogJsonUrl(), { 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();
}
})();
22 changes: 22 additions & 0 deletions site/files/forge.css
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,28 @@ button { font: inherit; border: 0; background: none; color: inherit; cursor: poi
}
.forge-nav__install:hover { color: var(--bg); background: #f4b04a; }

/* "N NEW" blog chip injected by files/blog-counter.js */
.forge-nav__links a.forge-blog-link {
display: inline-flex;
align-items: center;
gap: 6px;
}
.forge-blog-chip {
display: inline-flex;
align-items: center;
min-width: 16px;
padding: 1px 6px;
border: 1px solid var(--amber);
border-radius: 3px;
color: var(--amber);
font-family: var(--font-mono);
font-size: 10px;
font-weight: 600;
line-height: 1.4;
letter-spacing: 0.6px;
text-transform: uppercase;
}

/* Logo mark */
.forge-mark {
display: flex;
Expand Down
5 changes: 5 additions & 0 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<link rel="stylesheet" href="files/forge.css" />
<link rel="stylesheet" href="files/cm/codemirror.min.css" />
<link rel="stylesheet" href="files/cm/cm-forge.css" />

<!-- Analytics -->
<script data-goatcounter="https://borisbat.goatcounter.com/count"
async src="//gc.zgo.at/count.js"></script>
</head>
<body>
<div class="forge-page">
Expand Down Expand Up @@ -378,5 +382,6 @@ <h2 class="forge-h2">Recent activity.</h2>
<script src="files/highlight.js" defer></script>
<script src="files/runner.js" defer></script>
<script src="files/forge.js" defer></script>
<script src="files/blog-counter.js" defer></script>
</body>
</html>
Loading