Files
kennethreitz.org/templates/post.html
T
2025-09-12 16:48:24 -04:00

231 lines
6.8 KiB
HTML

{% extends "base.html" %}
{% block og_title %}{{ title }}{% endblock %}
{% block og_description %}{% if description %}{{ description[:160] }}{% else %}{{ content | striptags | truncate(160) }}{% endif %}{% endblock %}
{% block og_type %}article{% endblock %}
{% block og_url %}https://kennethreitz.org{{ request.path }}{% endblock %}
{% block twitter_title %}{{ title }}{% endblock %}
{% block twitter_description %}{% if description %}{{ description[:160] }}{% else %}{{ content | striptags | truncate(160) }}{% endif %}{% endblock %}
{% block description %}{% if description %}{{ description }}{% else %}{{ content | striptags | truncate(200) }}{% endif %}{% endblock %}
{% block schema_type %}Article{% endblock %}
{% block schema_name %}{{ title }}{% endblock %}
{% block schema_url %}{{ current_path }}{% endblock %}
{% block schema_description %}{% if metadata.description %}{{ metadata.description }}{% else %}{{ title }} - An essay by Kenneth Reitz{% endif %}{% endblock %}
{% block schema_extra %},
"headline": "{{ title }}",
"articleSection": "{% if 'artificial-intelligence' in current_path %}AI & Consciousness{% elif 'essays' in current_path %}Essays{% else %}Writing{% endif %}",
"wordCount": {{ (content | length / 5) | int }},
{% if metadata and metadata.date %}
"datePublished": "{{ metadata.date[0] if metadata.date is iterable and metadata.date is not string else metadata.date }}",
"dateModified": "{{ metadata.date[0] if metadata.date is iterable and metadata.date is not string else metadata.date }}",
{% endif %}
"keywords": [
"{% if 'artificial-intelligence' in current_path %}artificial intelligence, consciousness, philosophy{% elif 'mental-health' in current_path %}mental health, bipolar disorder, tech industry{% elif 'essays' in current_path %}technology, software development, python{% else %}writing, thoughts{% endif %}"
],
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://kennethreitz.org{{ current_path }}"
}{% endblock %}
{% block extra_head %}
<style>
/* Tufte-style typography - minimal and elegant */
.post-header {
margin-bottom: 3rem;
width: 100%;
}
article h1 {
font-size: 3.2rem;
font-style: italic;
font-weight: 400;
line-height: 1;
margin-bottom: 0.5rem;
color: #111;
text-rendering: optimizeLegibility;
width: 70%;
}
.post-subtitle {
font-variant: small-caps;
font-size: 1.1rem;
color: #666;
letter-spacing: 0.1em;
margin-bottom: 3rem;
font-weight: 400;
}
.post-date-note {
float: right;
clear: right;
margin-right: -60%;
width: 50%;
margin-top: 0;
margin-bottom: 0;
font-size: 1.1rem;
line-height: 1.3;
vertical-align: baseline;
position: relative;
color: #666;
font-style: italic;
}
/* Reading progress indicator */
.reading-progress {
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 2px;
background: linear-gradient(to right, #007acc, #0099ff);
z-index: 1000;
transition: width 0.25s ease-out;
opacity: 0;
}
.reading-progress.visible {
opacity: 1;
}
/* Text alignment */
section p,
article p:not(.sidenote):not(.marginnote) {
text-align: justify;
text-justify: inter-word;
hyphens: auto;
-webkit-hyphens: auto;
-ms-hyphens: auto;
word-break: normal;
overflow-wrap: break-word;
}
/* Asterism HR styling */
article hr {
width: 65%;
max-width: 65%;
margin: 4rem 0;
}
/* Simple footer styling */
.post-footer {
margin-top: 3rem;
font-size: 1rem;
color: #666;
}
.post-footer a {
color: #666;
text-decoration: none;
}
.post-footer a:hover {
color: #111;
}
@media (max-width: 760px) {
article h1 {
font-size: 2.5rem;
width: 100%;
}
.post-subtitle {
font-size: 1rem;
margin-bottom: 2rem;
}
.post-date-note {
float: none;
width: auto;
margin: 1rem 0;
}
article hr {
width: 100%;
max-width: 100%;
}
section p,
article p:not(.sidenote):not(.marginnote) {
width: 100% !important;
max-width: 100% !important;
}
}
</style>
{% endblock %}
{% block content %}
<div class="reading-progress"></div>
<article>
<h1>{{ title }}</h1>
{% if metadata and metadata.date %}
<div class="post-subtitle">{{ metadata.date if metadata.date is string else metadata.date[0] }}</div>
<div class="post-date-note">
{% if reading_time %}
{{ reading_time }} min read
{% endif %}
</div>
{% elif reading_time %}
<div class="post-date-note">{{ reading_time }} min read</div>
{% endif %}
<section>
{{ content | safe }}
</section>
<footer class="post-footer">
<p><a href="/directory">← Back to Directory</a></p>
</footer>
</article>
<script>
document.addEventListener('DOMContentLoaded', function() {
const progressBar = document.querySelector('.reading-progress');
const article = document.querySelector('article');
if (!progressBar || !article) return;
function updateProgress() {
const rect = article.getBoundingClientRect();
const articleTop = rect.top + window.pageYOffset;
const articleHeight = rect.height;
const windowHeight = window.innerHeight;
// Calculate how much of the article has been scrolled past
const scrollTop = window.pageYOffset;
const progress = Math.max(0, Math.min(100,
((scrollTop - articleTop + windowHeight * 0.5) / articleHeight) * 100
));
progressBar.style.width = progress + '%';
// Show progress bar when scrolling
if (progress > 5 && progress < 95) {
progressBar.classList.add('visible');
} else {
progressBar.classList.remove('visible');
}
}
// Throttle scroll events for performance
let ticking = false;
function onScroll() {
if (!ticking) {
requestAnimationFrame(() => {
updateProgress();
ticking = false;
});
ticking = true;
}
}
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', updateProgress, { passive: true });
updateProgress(); // Initial call
});
</script>
{% endblock %}