Files
kennethreitz.org/templates/base.html
T
kennethreitz 08aad7b40e Complete dropdown z-index fix with proper stacking context
- Add z-index: 9999 to header and nav elements
- Ensure proper stacking context with position: relative
- Fix dropdown rendering underneath H1 and body text
- Comprehensive solution for all dropdown layering issues
2025-09-17 17:57:58 -04:00

563 lines
26 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{% block title %}{{ title }} - Kenneth Reitz{% endblock %}</title>
<!-- SEO and Meta -->
<meta name="description" content="{% block description %}Kenneth Reitz - Creator of Requests and Certifi, trusted by millions of developers worldwide. Thoughts on technology, philosophy, and building software for humans.{% endblock %}" />
<meta name="author" content="Kenneth Reitz" />
<!-- OpenGraph -->
<meta property="og:title" content="{% block og_title %}{{ title }} - Kenneth Reitz{% endblock %}" />
<meta property="og:description" content="{% block og_description %}Creator of Requests and Certifi - libraries trusted by millions of developers worldwide{% endblock %}" />
<meta property="og:type" content="{% block og_type %}website{% endblock %}" />
<meta property="og:url" content="{% block og_url %}https://kennethreitz.org{% endblock %}" />
<meta property="og:image" content="{% block og_image %}https://kennethreitz.org/static/images/social-card.jpg{% endblock %}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:site_name" content="Kenneth Reitz" />
<!-- Twitter Card -->
<meta name="twitter:card" content="{% block twitter_card %}summary_large_image{% endblock %}" />
<meta name="twitter:creator" content="@kennethreitz42" />
<meta name="twitter:title" content="{% block twitter_title %}{{ title }} - Kenneth Reitz{% endblock %}" />
<meta name="twitter:description" content="{% block twitter_description %}Creator of Requests and Certifi - libraries trusted by millions of developers worldwide{% endblock %}" />
<meta name="twitter:image" content="{% block twitter_image %}https://kennethreitz.org/static/images/social-card.jpg{% endblock %}" />
<!-- RSS Feed -->
<link rel="alternate" type="application/rss+xml" title="Kenneth Reitz - Essays &amp; AI Writings" href="/feed.xml" />
<!-- Preload critical resources -->
<link rel="preload" href="/static/tufte/tufte.css" as="style" />
<link rel="preload" href="/static/custom.css" as="style" />
<!-- Tufte CSS -->
<link rel="stylesheet" href="/static/tufte/tufte.css" />
<!-- Custom Site CSS -->
<link rel="stylesheet" href="/static/custom.css" />
<style>
/* Only page-specific or dynamic styles that can't be in external CSS */
/* Legend dots for content guide */
.legend-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 0.3rem;
vertical-align: middle;
}
/* Reading progress indicator */
.reading-progress {
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 2px;
background: #333;
z-index: 1000;
transition: width 0.1s ease-out;
}
/* Header and nav z-index for dropdown stacking */
header {
position: relative;
z-index: 9999;
}
nav {
position: relative;
z-index: 9999;
}
/* Dropdown navigation styles */
.nav-dropdown {
position: relative;
display: inline-block;
padding: 0.5rem;
margin: -0.5rem;
z-index: 9999;
}
.nav-dropdown .dropdown-content {
display: none;
position: absolute;
top: 100%;
left: 0;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
z-index: 9999;
min-width: 280px;
padding: 0.5rem 0;
margin-top: -1px;
}
.nav-dropdown:hover .dropdown-content {
display: block;
}
.nav-dropdown .dropdown-content a {
display: block;
padding: 0.5rem 1rem;
color: #333;
text-decoration: none;
border-bottom: none;
font-size: 0.9rem;
line-height: 1.4;
}
.nav-dropdown .dropdown-content a:hover {
background-color: #f5f5f5;
}
.nav-dropdown .dropdown-content a .index-description {
display: block;
font-size: 0.75rem;
color: #666;
margin-top: 0.1rem;
}
.nav-dropdown > a::after {
content: "\00a0▼";
font-size: 0.7rem;
color: #999;
}
</style>
<!-- Structured Data (JSON-LD) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "{% block schema_type %}WebSite{% endblock %}",
"name": "{% block schema_name %}Kenneth Reitz{% endblock %}",
"url": "https://kennethreitz.org{% block schema_url %}/{% endblock %}",
"description": "{% block schema_description %}Kenneth Reitz - Creator of Requests and Certifi, trusted by millions of developers worldwide. Thoughts on technology, philosophy, and building software for humans.{% endblock %}",
"author": {
"@type": "Person",
"name": "Kenneth Reitz",
"url": "https://kennethreitz.org",
"sameAs": [
"https://github.com/kennethreitz",
"https://twitter.com/kennethreitz42"
],
"jobTitle": "Python Developer",
"worksFor": {
"@type": "Organization",
"name": "Independent"
},
"knowsAbout": [
"Python Programming",
"API Design",
"Software Architecture",
"Open Source Development",
"Artificial Intelligence",
"Mental Health Advocacy"
]
},
"publisher": {
"@type": "Person",
"name": "Kenneth Reitz",
"url": "https://kennethreitz.org"
}{% block schema_extra %}{% endblock %}
}
</script>
{% block extra_head %}{% endblock %}
<!-- Analytics -->
{% if not (config.get('DISABLE_ANALYTICS') or request.environ.get('DISABLE_ANALYTICS')) %}
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-RB9QHYEG2X"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-RB9QHYEG2X');
</script>
<script type="text/javascript">
var _gauges = _gauges || [];
(function() {
var t = document.createElement('script');
t.type = 'text/javascript';
t.async = true;
t.id = 'gauges-tracker';
t.setAttribute('data-site-id', '65529a9abd1a3b3101979d52');
t.setAttribute('data-track-path', 'https://track.gaug.es/track.gif');
t.src = 'https://d2fuc4clr7gvcn.cloudfront.net/track.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(t, s);
})();
</script>
{% endif %}
</head>
<body>
<!-- Reading progress bar -->
<div class="reading-progress" id="reading-progress"></div>
<article>
<header>
<nav>
<a href="/">Home</a>
<a href="/archive">Archive</a>
<a href="/themes/">Themes</a>
<div class="nav-dropdown">
<a href="#">Indexes</a>
<div class="dropdown-content">
<a href="/sidenotes">
Sidenotes Index
<span class="index-description">{{ index_counts.sidenotes|default('1,300+') }} marginalia extracted from across the garden.</span>
</a>
<a href="/outlines">
Outlines Index
<span class="index-description">{{ index_counts.outlines|default('3,000+') }} headings — structural navigation through essays.</span>
</a>
<a href="/connections">
Connections Index
<span class="index-description">{{ index_counts.connections_outgoing|default('1,500+') }} outgoing and {{ index_counts.connections_incoming|default('1,400+') }} incoming cross-references.</span>
</a>
<a href="/quotes">
Quotes Index
<span class="index-description">{{ index_counts.quotes|default('200+') }} quotable insights and distilled wisdom.</span>
</a>
<a href="/terms">
Term Index
<span class="index-description">{{ index_counts.terms|default('200+') }} key terms with {{ index_counts.terms_total_refs|default('1,300+') }} total references.</span>
</a>
<div style="border-top: 1px solid #eee; margin: 0.5rem 0;"></div>
<a href="/graph">
Cross-Reference Graph
<span class="index-description">Interactive network visualization of connections.</span>
</a>
<div style="border-top: 1px solid #eee; margin: 0.5rem 0;"></div>
<a href="/search">
Search
<span class="index-description">Full-text search across all content.</span>
</a>
</div>
</div>
<a href="/random" class="random-link">[random]</a>
</nav>
{% if current_path or breadcrumbs %}
<div class="breadcrumbs">
<a href="/directory">~</a>
{% if breadcrumbs %}
{% for crumb in breadcrumbs %}
<span class="breadcrumb-separator">/</span>
<a href="{{ crumb.url }}">{{ crumb.name }}</a>
{% endfor %}
{% elif current_path %}
{% set path_parts = current_path.strip('/').split('/') %}
{% for part in path_parts if part %}
<span class="breadcrumb-separator">/</span>
{% set partial_path = '/' + path_parts[:loop.index]|join('/') %}
<a href="{{ partial_path }}">{{ part }}</a>
{% endfor %}
{% endif %}
</div>
{% endif %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<div class="footer-content">
<section class="footer-indexes" style="margin-top: 3rem; padding-top: 2rem; border-top: 1px solid #e0e0e0;">
<h3 style="font-size: 1rem; color: #666; margin-bottom: 1rem;">Content Guide</h3>
<div style="display: flex; flex-wrap: wrap; gap: 1.5rem; font-size: 0.9rem;">
<span><span class="legend-dot" style="background: #e74c3c;"></span>Software & Tools</span>
<span><span class="legend-dot" style="background: #3498db;"></span>Essays & Analysis</span>
<span><span class="legend-dot" style="background: #9b59b6;"></span>AI & Consciousness</span>
<span><span class="legend-dot" style="background: #f39c12;"></span>Music & Audio</span>
<span><span class="legend-dot" style="background: #27ae60;"></span>Poetry & Creative</span>
<span><span class="legend-dot" style="background: #95a5a6;"></span>Philosophy & Critique</span>
</div>
<div style="margin-top: 1rem; font-size: 0.85rem; color: #888; line-height: 1.6;">
<a href="/sidenotes" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Sidenotes Index</a> &mdash; 1,300+ marginalia extracted from across the garden<br>
<a href="/outlines" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Outlines Index</a> &mdash; Structural navigation through essay architecture<br>
<a href="/quotes" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Quotes Index</a> &mdash; Quotable insights and distilled wisdom<br>
<a href="/connections" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Connections Index</a> &mdash; The web of cross-references between ideas<br>
<a href="/terms" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Term Index</a> &mdash; Book-style alphabetical index of key concepts<br>
<a href="/graph" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Cross-Reference Graph</a> &mdash; Interactive network visualization of connections<br>
<a href="/search" style="color: #888; text-decoration: none; border-bottom: 1px dotted #aaa;">Search</a> &mdash; Full-text search across all content
</div>
</section>
<div class="footer-note">
<p>&copy; {{ "now"|strftime("%Y") }} Kenneth Reitz. Made with <a href="https://kjvstudy.org/book/1%20Corinthians/chapter/13">love</a>.</p>
</div>
</div>
</footer>
</article>
{% block extra_scripts %}{% endblock %}
<!-- Force light mode, especially on mobile -->
<style>
@media (prefers-color-scheme: dark) {
body {
background-color: rgb(255, 255, 248) !important;
color: #111 !important;
}
h1, h2, h3, h4, h5, h6 {
color: #333 !important;
}
a {
color: #111 !important;
}
/* Force light backgrounds on all elements */
* {
background-color: transparent !important;
color: inherit !important;
}
/* Override any dark mode styling */
body, html {
background: rgb(255, 255, 248) !important;
color: #111 !important;
}
}
/* Mobile-specific light mode enforcement */
@media (max-width: 760px) {
body {
background-color: rgb(255, 255, 248) !important;
color: #111 !important;
}
* {
background-color: transparent !important;
}
/* Exception for dropdown background on mobile */
.nav-dropdown .dropdown-content {
background-color: #fff !important;
}
body, html {
background: rgb(255, 255, 248) !important;
color: #111 !important;
}
}
</style>
<!-- Simplified Color System (light themes only) -->
<script>
(function() {
// Check if user prefers light mode or is on mobile
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
const isMobile = window.innerWidth <= 760;
// Force light mode on mobile or if user prefers dark (override their dark preference)
if (isMobile || prefersDark) {
document.body.style.backgroundColor = 'rgb(255, 255, 248)';
document.body.style.color = '#111';
return; // Skip color schemes entirely
}
const lightColorSchemes = [
'scheme-ocean',
'scheme-forest',
'scheme-sunset',
'scheme-lavender',
'scheme-rose',
'scheme-sage',
'scheme-amber'
];
// Get or generate a scheme based on the current page
let scheme = localStorage.getItem('current-color-scheme');
// Change scheme occasionally (20% chance on page load)
if (!scheme || Math.random() < 0.2) {
scheme = lightColorSchemes[Math.floor(Math.random() * lightColorSchemes.length)];
localStorage.setItem('current-color-scheme', scheme);
}
// Apply the scheme
document.body.className = (document.body.className + ' ' + scheme).trim();
})();
</script>
<script>
// Add copy buttons to code blocks and subtle syntax highlighting
document.addEventListener('DOMContentLoaded', function() {
// Find all pre elements (code blocks)
const codeBlocks = document.querySelectorAll('pre');
// Function to add subtle comment highlighting
function highlightComments(pre) {
const code = pre.querySelector('code') || pre;
let html = code.innerHTML;
// Python/Shell comments (# comment) - both line start and inline
html = html.replace(/(^|\s+)(#.*)$/gm, '$1<span style="color: #888; font-style: italic;">$2</span>');
// Python docstrings (""" or ''')
html = html.replace(/("""[\s\S]*?""")/g, '<span style="color: #888; font-style: italic;">$1</span>');
html = html.replace(/('''[\s\S]*?''')/g, '<span style="color: #888; font-style: italic;">$1</span>');
// Python class names (class ClassName)
html = html.replace(/(\bclass\s+)([A-Za-z_][A-Za-z0-9_]*)/g, '$1<span style="font-weight: bold;">$2</span>');
// JavaScript/C++/Java comments (// comment)
html = html.replace(/(\s*\/\/.*)$/gm, '<span style="color: #888; font-style: italic;">$1</span>');
// CSS/C/Java block comments (/* comment */)
html = html.replace(/(\/\*[\s\S]*?\*\/)/g, '<span style="color: #888; font-style: italic;">$1</span>');
// HTML comments (<!-- comment -->)
html = html.replace(/(&lt;!--[\s\S]*?--&gt;)/g, '<span style="color: #888; font-style: italic;">$1</span>');
code.innerHTML = html;
}
codeBlocks.forEach(function(pre) {
// Add subtle comment highlighting first
highlightComments(pre);
// Skip if already wrapped
if (pre.parentElement.classList.contains('code-block-wrapper')) {
return;
}
// Create wrapper div
const wrapper = document.createElement('div');
wrapper.className = 'code-block-wrapper';
// Create copy button
const copyButton = document.createElement('button');
copyButton.className = 'copy-button';
copyButton.textContent = 'Copy';
copyButton.setAttribute('aria-label', 'Copy code to clipboard');
// Add click handler
copyButton.addEventListener('click', async function() {
try {
// Get the text content of the pre element
const codeText = pre.textContent || pre.innerText;
// Use modern clipboard API if available
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(codeText);
} else {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = codeText;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
textArea.remove();
}
// Show feedback
const originalText = copyButton.textContent;
copyButton.textContent = 'Copied!';
copyButton.classList.add('copied');
setTimeout(function() {
copyButton.textContent = originalText;
copyButton.classList.remove('copied');
}, 2000);
} catch (err) {
console.error('Failed to copy code: ', err);
// Show error feedback
const originalText = copyButton.textContent;
copyButton.textContent = 'Failed';
setTimeout(function() {
copyButton.textContent = originalText;
}, 2000);
}
});
// Wrap the pre element and add the button
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
wrapper.appendChild(copyButton);
});
});
// Reading progress indicator
function updateReadingProgress() {
const progressBar = document.getElementById('reading-progress');
if (!progressBar) return;
const mainContent = document.querySelector('main');
if (!mainContent) return;
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight;
const winHeight = window.innerHeight;
const scrollPercent = scrollTop / (docHeight - winHeight);
const scrollPercentRounded = Math.round(scrollPercent * 100);
progressBar.style.width = scrollPercentRounded + '%';
// Only show progress bar if there's meaningful content to scroll
if (docHeight > winHeight * 1.5) {
progressBar.style.opacity = '1';
} else {
progressBar.style.opacity = '0';
}
}
// Initialize reading progress on pages with substantial content
document.addEventListener('DOMContentLoaded', function() {
// Check if this is a content page (essay/article) rather than an index
const isContentPage = document.querySelector('main').textContent.length > 2000;
if (isContentPage) {
window.addEventListener('scroll', updateReadingProgress);
window.addEventListener('resize', updateReadingProgress);
updateReadingProgress(); // Initial call
}
// Lazy loading for images
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
if (img.dataset.src) {
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
}
});
}, {
rootMargin: '50px 0px'
});
// Apply lazy loading to all images with data-src
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
});
</script>
</body>
</html>