mirror of
https://github.com/kennethreitz/kennethreitz.org.git
synced 2026-06-05 22:50:17 +00:00
339 lines
15 KiB
HTML
339 lines
15 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 & AI Writings" href="/feed.xml" />
|
|
|
|
<!-- 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 */
|
|
</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')) %}
|
|
<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>
|
|
<article>
|
|
<header>
|
|
<nav>
|
|
<a href="/">Home</a>
|
|
<a href="/archive">Archive</a>
|
|
<a href="/themes">Themes</a>
|
|
<a href="/directory">Directory</a>
|
|
<a href="/random" class="random-link">[random]</a>
|
|
</nav>
|
|
|
|
{% if current_path or breadcrumbs %}
|
|
<div class="breadcrumbs">
|
|
<a href="/">Home</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">
|
|
<div class="footer-note">
|
|
<p>© {{ "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;
|
|
}
|
|
|
|
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(/(<!--[\s\S]*?-->)/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);
|
|
});
|
|
});
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|