v4: Premium reading experience — progress bar, table of contents, author personas, network footer
This commit is contained in:
@@ -30,6 +30,9 @@ IDENTITIES = {
|
||||
"font_heading": "'Space Grotesk', sans-serif",
|
||||
"gradient": "linear-gradient(135deg, #7c3aed, #a78bfa)",
|
||||
"description": "Deep dives into AI, machine learning, LLMs, and the future of intelligence.",
|
||||
"author_name": "Dr. Soren Vale",
|
||||
"author_title": "AI Research Director",
|
||||
"author_bio": "Former research scientist at DeepMind. 15 years in machine learning. Believes the best AI writing explains concepts so clearly that anyone can understand them. Based in London.",
|
||||
},
|
||||
"tech": {
|
||||
"name": "Tech Frontier",
|
||||
@@ -41,6 +44,9 @@ IDENTITIES = {
|
||||
"font_heading": "'JetBrains Mono', monospace",
|
||||
"gradient": "linear-gradient(135deg, #2563eb, #06b6d4)",
|
||||
"description": "Programming, cloud infrastructure, DevOps, and the tools that power the internet.",
|
||||
"author_name": "Maya Chen",
|
||||
"author_title": "Senior Software Architect",
|
||||
"author_bio": "Staff engineer who's shipped products at Stripe and Vercel. Writes about the tools and patterns that actually work in production, not just in blog posts. Based in San Francisco.",
|
||||
},
|
||||
"science": {
|
||||
"name": "Science Decoded",
|
||||
@@ -52,6 +58,9 @@ IDENTITIES = {
|
||||
"font_heading": "'Crimson Text', serif",
|
||||
"gradient": "linear-gradient(135deg, #059669, #06b6d4)",
|
||||
"description": "Physics, biology, chemistry, astronomy — the frontiers of human knowledge.",
|
||||
"author_name": "Dr. James Aldrin",
|
||||
"author_title": "Research Physicist & Science Writer",
|
||||
"author_bio": "PhD in astrophysics from MIT. Left academia to make cutting-edge science accessible. Believes the universe is stranger than fiction and twice as interesting. Based in Cambridge, MA.",
|
||||
},
|
||||
"crypto": {
|
||||
"name": "Crypto Compass",
|
||||
@@ -63,6 +72,9 @@ IDENTITIES = {
|
||||
"font_heading": "'DM Mono', monospace",
|
||||
"gradient": "linear-gradient(135deg, #f59e0b, #ef4444)",
|
||||
"description": "Bitcoin, Ethereum, DeFi, and the technology rebuilding finance.",
|
||||
"author_name": "Satoshi Lane",
|
||||
"author_title": "Crypto Analyst & Security Engineer",
|
||||
"author_bio": "Bitcoin since 2013. Self-custody maximalist. Previously led security at a major exchange. Now writes about the protocols, not the prices. Based nowhere in particular.",
|
||||
},
|
||||
"linux": {
|
||||
"name": "Linux Lab",
|
||||
@@ -74,6 +86,9 @@ IDENTITIES = {
|
||||
"font_heading": "'Fira Code', monospace",
|
||||
"gradient": "linear-gradient(135deg, #f97316, #ef4444)",
|
||||
"description": "Linux, kernel hacking, system administration, and the FOSS ecosystem.",
|
||||
"author_name": "Linus Koval",
|
||||
"author_title": "Systems Engineer & Kernel Contributor",
|
||||
"author_bio": "Linux user since Slackware 3.0. Has submitted patches to the kernel. Runs Arch on the desktop, Debian on the servers, and believes systemd was the right call. Based in Berlin.",
|
||||
},
|
||||
"gaming": {
|
||||
"name": "Game Layer",
|
||||
@@ -85,6 +100,9 @@ IDENTITIES = {
|
||||
"font_heading": "'Press Start 2P', cursive",
|
||||
"gradient": "linear-gradient(135deg, #ec4899, #8b5cf6)",
|
||||
"description": "Video games, game development, esports, hardware, and gaming culture.",
|
||||
"author_name": "Jules Park",
|
||||
"author_title": "Game Designer & Critic",
|
||||
"author_bio": "10 years in game dev across indie and AA studios. Shipped titles on Steam, Switch, and mobile. Now writes about why games work (or don't) with the depth they deserve. Based in Seoul.",
|
||||
},
|
||||
"diy": {
|
||||
"name": "Maker Forge",
|
||||
@@ -96,6 +114,9 @@ IDENTITIES = {
|
||||
"font_heading": "'Oswald', sans-serif",
|
||||
"gradient": "linear-gradient(135deg, #ef4444, #f97316)",
|
||||
"description": "3D printing, woodworking, electronics, home automation, and the maker movement.",
|
||||
"author_name": "Rex Hardwick",
|
||||
"author_title": "Master Maker & Fabricator",
|
||||
"author_bio": "Former aerospace machinist turned full-time maker. Runs a 3,000 sq ft workshop. Believes the best tool is the one you know how to fix. Based in Portland, OR.",
|
||||
},
|
||||
"guides": {
|
||||
"name": "Practical Guides",
|
||||
@@ -107,6 +128,9 @@ IDENTITIES = {
|
||||
"font_heading": "'Inter', sans-serif",
|
||||
"gradient": "linear-gradient(135deg, #0891b2, #06b6d4)",
|
||||
"description": "Clear, practical tutorials and how-to guides for everything that matters.",
|
||||
"author_name": "Nina Okonkwo",
|
||||
"author_title": "Technical Educator",
|
||||
"author_bio": "Taught 10,000+ students to code through bootcamps and online courses. Believes every skill can be taught if you break it down right. Based in Nairobi.",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -946,6 +970,27 @@ ARTICLE_TEMPLATE = """<!DOCTYPE html>
|
||||
.article-header h1{font-size:1.5rem}
|
||||
.related-grid{grid-template-columns:1fr}
|
||||
}
|
||||
|
||||
/* Progress bar */
|
||||
.progress-bar{position:fixed;top:0;left:0;height:3px;background:var(--gradient);z-index:200;width:0;transition:width 0.1s linear}
|
||||
|
||||
/* Table of Contents */
|
||||
.toc-container{background:var(--card-bg);border:1px solid var(--border);border-radius:8px;padding:1rem 1.25rem;margin-bottom:2rem;font-size:0.9rem}
|
||||
.toc-container h3{font-family:var(--font-heading);font-size:0.9rem;margin-bottom:0.5rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.05em}
|
||||
.toc-container ul{list-style:none;margin:0}
|
||||
.toc-container li{margin-bottom:0.3rem}
|
||||
.toc-container a{color:var(--text-muted);text-decoration:none;transition:color 0.2s}
|
||||
.toc-container a:hover{color:var(--accent)}
|
||||
|
||||
/* Author Box */
|
||||
.author-box{display:flex;gap:1rem;align-items:flex-start;background:var(--card-bg);border:1px solid var(--border);border-radius:12px;padding:1.5rem;margin-top:2rem}
|
||||
.author-name{font-family:var(--font-heading);font-weight:600;font-size:1.05rem;margin-bottom:0.15rem}
|
||||
.author-title{color:var(--accent);font-size:0.8rem;margin-bottom:0.5rem}
|
||||
.author-bio{color:var(--text-muted);font-size:0.85rem;line-height:1.5}
|
||||
|
||||
.site-footer{border-top:1px solid var(--border);padding:2.5rem 1.5rem;max-width:1000px;margin:0 auto}
|
||||
.footer-main{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:1rem;color:var(--text-muted);font-size:0.8rem}
|
||||
.footer-main a{color:var(--text-muted);text-decoration:none}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -971,6 +1016,11 @@ ARTICLE_TEMPLATE = """<!DOCTYPE html>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="toc-container" id="toc-container">
|
||||
<h3>In This Article</h3>
|
||||
<ul id="toc-list"></ul>
|
||||
</div>
|
||||
|
||||
<div class="article-content">
|
||||
{{ article.content_html|safe }}
|
||||
</div>
|
||||
@@ -985,6 +1035,14 @@ ARTICLE_TEMPLATE = """<!DOCTYPE html>
|
||||
{% endif %}
|
||||
</footer>
|
||||
</article>
|
||||
<div class="author-box">
|
||||
<div class="author-avatar" style="background:var(--gradient);width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:var(--font-heading);font-size:1.5rem;font-weight:700;color:white;flex-shrink:0">{{ author_name[:1] }}</div>
|
||||
<div class="author-info">
|
||||
<div class="author-name">{{ author_name }}</div>
|
||||
<div class="author-title">{{ author_title }}</div>
|
||||
<div class="author-bio">{{ author_bio }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if related %}
|
||||
<section class="related">
|
||||
@@ -1001,13 +1059,46 @@ ARTICLE_TEMPLATE = """<!DOCTYPE html>
|
||||
{% endif %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<span>© {{ domain }}</span>
|
||||
<nav>
|
||||
<a href="/rss.xml">RSS</a>
|
||||
<a href="/sitemap.xml">Sitemap</a>
|
||||
</nav>
|
||||
<footer class="site-footer">
|
||||
<div class="footer-main">
|
||||
<span>© {{ domain }}</span>
|
||||
<nav>
|
||||
<a href="/rss.xml">RSS</a>
|
||||
<a href="/sitemap.xml">Sitemap</a>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<div class="progress-bar" id="progress"></div>
|
||||
|
||||
<script>
|
||||
// Reading progress bar
|
||||
window.addEventListener('scroll', function(){
|
||||
var winHeight = window.innerHeight;
|
||||
var docHeight = document.documentElement.scrollHeight;
|
||||
var scrollTop = window.scrollY;
|
||||
var progress = Math.min((scrollTop / (docHeight - winHeight)) * 100, 100);
|
||||
document.getElementById('progress').style.width = progress + '%';
|
||||
});
|
||||
|
||||
// Auto-generate table of contents from h2 headings
|
||||
(function(){
|
||||
var toc = document.getElementById('toc-list');
|
||||
if(!toc) return;
|
||||
var headings = document.querySelectorAll('.article-content h2');
|
||||
if(headings.length < 2){ document.getElementById('toc-container').style.display='none'; return; }
|
||||
headings.forEach(function(h, i){
|
||||
var id = 'section-' + i;
|
||||
h.id = id;
|
||||
var li = document.createElement('li');
|
||||
var a = document.createElement('a');
|
||||
a.href = '#' + id;
|
||||
a.textContent = h.textContent;
|
||||
li.appendChild(a);
|
||||
toc.appendChild(li);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<img src="/a/ping?p=/articles/{{ article.slug }}" alt="" width="1" height="1" style="display:none">
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
Reference in New Issue
Block a user