Files
kennethreitz.org/templates/post.html
T

546 lines
17 KiB
HTML

{% extends "base.html" %}
{% block extra_head %}
<style>
/* Custom Tufte-inspired styles with Kenneth's brand colors */
/* Override some Tufte defaults with Kenneth's branding */
.tufte-content {
margin: 0 auto;
padding: 0;
width: 87.5%;
max-width: 1400px;
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
color: #4e3979;
}
h1 {
font-weight: 400;
margin-top: 2rem;
margin-bottom: 1.5rem;
font-size: 3.2rem;
line-height: 1;
}
h2 {
font-style: italic;
font-weight: 400;
margin-top: 2.5rem;
margin-bottom: 0;
font-size: 2.2rem;
line-height: 1;
}
h3 {
font-style: italic;
font-weight: 400;
font-size: 1.7rem;
margin-top: 2rem;
margin-bottom: 0;
line-height: 1;
}
/* Links with Kenneth's branding */
a:link, a:visited {
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
color: #4e3979;
text-decoration: none;
background: linear-gradient(#fff, #fff), linear-gradient(#fff, #fff), linear-gradient(#4e3979, #4e3979);
background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
background-repeat: no-repeat, no-repeat, repeat-x;
text-shadow: 0.03em 0 #fff, -0.03em 0 #fff, 0 0.03em #fff, 0 -0.03em #fff, 0.06em 0 #fff, -0.06em 0 #fff, 0.09em 0 #fff, -0.09em 0 #fff, 0.12em 0 #fff, -0.12em 0 #fff, 0.15em 0 #fff, -0.15em 0 #fff;
background-position: 0% 93%, 100% 93%, 0% 93%;
transition: color 0.2s ease;
}
a:hover {
color: #6f52b0;
}
/* Sidenotes and margin notes styling with Kenneth's color scheme */
.sidenote, .marginnote {
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: #5c4394;
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
font-style: italic;
}
.sidenote-number {
color: #4e3979;
}
/* Blockquotes with Kenneth's branding */
blockquote {
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
font-size: 1.4rem;
margin: 2rem 0;
padding-left: 2rem;
border-left: 3px solid #9b86d3;
font-style: italic;
line-height: 1.75;
}
/* Figure and caption styling */
figure {
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
max-width: 85%;
-webkit-margin-start: 0;
-webkit-margin-end: 0;
margin: 0 0 3em 0;
}
/* Figure and caption styling */
figcaption {
float: right;
clear: right;
margin-top: 0;
margin-bottom: 0;
font-size: 1.1rem;
line-height: 1.6;
vertical-align: baseline;
position: relative;
max-width: 40%;
color: #5c4394;
font-style: italic;
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
}
/* Code styling with Kenneth's branding */
code {
font-family: 'JetBrains Mono', Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 0.9rem;
line-height: 1.6;
background-color: #e3e0f4;
padding: 0.2rem 0.4rem;
border-radius: 3px;
color: #4e3979;
}
pre {
padding: 1.5rem;
margin: 2rem 0;
background-color: #faf9fd;
border: 1px solid #d0c8ec;
border-radius: 5px;
overflow-x: auto;
}
pre code {
background-color: transparent;
padding: 0;
}
/* Full width figures/tables */
.fullwidth {
max-width: 100%;
clear: both;
}
/* Table styling */
table {
width: 100%;
border-collapse: collapse;
border-spacing: 0;
margin: 2rem 0;
font-size: 1.1rem;
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
}
th {
padding: 0.75rem 1rem;
font-weight: 600;
text-align: left;
border-bottom: 2px solid #4e3979;
color: #4e3979;
}
td {
padding: 0.75rem 1rem;
border-bottom: 1px solid #d0c8ec;
}
tr:nth-child(even) {
background-color: #f8f7fd;
}
/* Copy button for code blocks */
.code-block-container {
position: relative;
}
.copy-button {
position: absolute;
top: 0.75rem;
right: 0.75rem;
background: #4e3979;
color: white;
border: none;
padding: 0.375rem 0.75rem;
border-radius: 0.375rem;
font-size: 0.75rem;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease;
font-family: 'Inter', sans-serif;
font-weight: 500;
}
.code-block-container:hover .copy-button {
opacity: 1;
}
.copy-button:hover {
background: #5c4394;
}
/* Adjustments for mobile responsive design */
@media (max-width: 760px) {
body {
width: 84%;
padding-left: 8%;
padding-right: 8%;
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
}
.tufte-content {
width: 100%;
}
hr, section > p, section > footer, section > table {
width: 100%;
}
pre {
width: 97%;
}
.sidenote, .marginnote {
display: none;
}
.margin-toggle:checked + .sidenote,
.margin-toggle:checked + .marginnote {
display: block;
float: left;
left: 1rem;
clear: both;
width: 95%;
margin: 1rem 2.5%;
vertical-align: baseline;
position: relative;
}
}
</style>
{% endblock %}
{% block content %}
<article class="post">
<!-- Post Header -->
<header class="mb-12 pb-8 border-b-2 border-primary-200">
<h1 class="text-5xl font-bold text-gray-900 mb-6 leading-tight tracking-tight page-title">
{{ title }}
</h1>
{% if metadata %}
<div class="flex flex-wrap gap-6 text-sm text-gray-600">
{% if metadata.author %}
<div class="flex items-center gap-2">
<span class="text-primary-600">👤</span>
<span class="font-medium">{{ metadata.author[0] }}</span>
</div>
{% endif %}
{% if metadata.date %}
<div class="flex items-center gap-2">
<span class="text-primary-600">📅</span>
<span>{{ metadata.date[0] }}</span>
</div>
{% endif %}
{% if metadata.tags %}
<div class="flex items-center gap-2">
<span class="text-primary-600">🏷️</span>
<span>{{ metadata.tags | join(', ') }}</span>
</div>
{% endif %}
</div>
{% endif %}
</header>
<!-- Post Content with Tufte Typography -->
<div class="et-book">
<div class="font-serif content-section">
{{ content | safe }}
</div>
<style>
/* Style for page title to distinguish from content headers */
.page-title {
color: #4e3979 !important;
font-family: 'Inter', system-ui, sans-serif !important;
border-bottom: none !important;
}
/* Ensure proper bullet point display in Markdown content */
.content-section h1,
.content-section h2,
.content-section h3,
.content-section h4,
.content-section h5,
.content-section h6 {
color: #5c4394 !important;
border-bottom: none !important;
font-family: et-book, 'Crimson Text', Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif !important;
}
.content-section h1 {
font-size: 2.5rem !important;
margin-top: 2.5rem !important;
}
.content-section h2 {
font-size: 2.0rem !important;
margin-top: 2.2rem !important;
}
.content-section h3 {
font-size: 1.6rem !important;
margin-top: 1.8rem !important;
}
.content-section ul {
list-style-type: disc !important;
padding-left: 2.5rem !important;
margin: 1rem 0 !important;
}
.content-section ol {
list-style-type: decimal !important;
padding-left: 2.5rem !important;
margin: 1rem 0 !important;
}
.content-section ul ul {
list-style-type: circle !important;
}
.content-section ul ol {
list-style-type: lower-alpha !important;
}
.content-section ol ul {
list-style-type: circle !important;
}
.content-section ol ol {
list-style-type: lower-alpha !important;
}
.content-section li {
display: list-item !important;
margin-bottom: 0.5rem !important;
}
@media (max-width: 760px) {
.content-section ul,
.content-section ol {
width: 100% !important;
padding-left: 1.5rem !important;
}
}
</style>
</div>
<!-- Post Navigation -->
<nav class="mt-16 pt-8 border-t border-gray-200 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
{% if breadcrumbs %}
{% set parent_path = breadcrumbs[-1].url if breadcrumbs else '/' %}
{% else %}
{% set parent_path = '/' %}
{% endif %}
<a href="{{ parent_path }}"
class="inline-flex items-center gap-3 px-6 py-3 text-primary-700 border-2 border-primary-600 rounded-lg hover:bg-primary-600 hover:text-white transition-all duration-200 font-medium group">
<span class="transition-transform group-hover:-translate-x-1"></span>
<span>Back to Directory</span>
</a>
<div class="text-sm text-gray-500 font-medium">
Markdown Document
</div>
</nav>
</article>
{% endblock %}
{% block extra_scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Smooth scrolling for anchor links
const anchorLinks = document.querySelectorAll('.content-section a[href^="#"]');
anchorLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
// Add copy button to code blocks
const codeBlocks = document.querySelectorAll('.content-section pre code');
codeBlocks.forEach(block => {
const pre = block.parentElement;
// Wrap pre in container for positioning
const container = document.createElement('div');
container.className = 'code-block-container';
pre.parentNode.insertBefore(container, pre);
container.appendChild(pre);
// Create copy button
const button = document.createElement('button');
button.textContent = 'Copy';
button.className = 'copy-button';
container.appendChild(button);
button.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(block.textContent);
button.textContent = 'Copied!';
button.style.background = '#10b981';
setTimeout(() => {
button.textContent = 'Copy';
button.style.background = '#4e3979';
}, 2000);
} catch (err) {
console.error('Failed to copy: ', err);
}
});
});
// Add reading progress indicator
const progressBar = document.createElement('div');
progressBar.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 3px;
background: linear-gradient(90deg, #4e3979, #6f52b0);
z-index: 9999;
transition: width 0.2s ease;
`;
document.body.appendChild(progressBar);
window.addEventListener('scroll', () => {
const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scrolled = (winScroll / height) * 100;
progressBar.style.width = scrolled + '%';
});
// Enhance image viewing
const images = document.querySelectorAll('.content-section img');
images.forEach(img => {
// Create figure and figcaption for Tufte-style
if (!img.parentElement.matches('figure')) {
const figure = document.createElement('figure');
img.parentNode.insertBefore(figure, img);
figure.appendChild(img);
// Add caption if alt text exists
if (img.alt && !img.alt.startsWith('_')) {
const figcaption = document.createElement('figcaption');
figcaption.textContent = img.alt;
figure.appendChild(figcaption);
}
}
img.style.cursor = 'pointer';
img.addEventListener('click', () => {
// Simple lightbox effect
const overlay = document.createElement('div');
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.9);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
cursor: pointer;
`;
const enlargedImg = img.cloneNode();
enlargedImg.style.cssText = `
max-width: 90%;
max-height: 90%;
object-fit: contain;
border-radius: 8px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
`;
overlay.appendChild(enlargedImg);
document.body.appendChild(overlay);
overlay.addEventListener('click', () => {
document.body.removeChild(overlay);
});
});
});
// Transform blockquotes with attribution to Tufte style
document.querySelectorAll('.content-section blockquote').forEach(blockquote => {
const lastP = blockquote.querySelector('p:last-child');
if (lastP && lastP.textContent.startsWith('—')) {
lastP.classList.add('attribution');
lastP.style.textAlign = 'right';
lastP.style.marginTop = '0.5rem';
}
});
// Add margin toggle buttons for sidenotes in mobile view
document.querySelectorAll('.content-section .sidenote, .content-section .marginnote').forEach((note, i) => {
const id = 'sidenote-' + i;
// Create the toggle
const toggle = document.createElement('label');
toggle.setAttribute('for', id);
toggle.className = 'margin-toggle sidenote-number';
toggle.textContent = (i + 1);
// Create the checkbox
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = id;
checkbox.className = 'margin-toggle';
// Insert them before the note
note.parentNode.insertBefore(toggle, note);
note.parentNode.insertBefore(checkbox, note);
});
});
</script>
{% endblock %}