- Reduced dependencies from 13 to 5 packages (66% reduction) - Removed unused packages: pydantic, fastapi, uvicorn, pygments, boto3, pillow, background, markdown - Kept essential packages: flask, gunicorn, gevent, mistune, pyyaml - Moved docs/ from data/docs/ to root directory for better organization - Updated all internal documentation links to reflect new location 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
Customization Guide
Making TufteCMS reflect your unique voice and vision
TufteCMS provides a foundation for contemplative digital publishing while remaining flexible enough to adapt to your specific needs and aesthetic preferences.
This guide assumes familiarity with getting started and content structure. For specialized sidenote styling, see the sidenotes guide.
Template System
TufteCMS uses Flask's Jinja2 templating with a clean, semantic structure.
Template Directory
tuftecms/templates/
├── base.html # Master layout template
├── post.html # Individual content pages
├── archive.html # Chronological content listings
├── directory.html # File browser interface
├── sidenotes.html # Sidenotes index
├── outlines.html # Headings index
├── quotes.html # Blockquotes index
├── connections.html # Cross-references index
├── terms.html # Terms index
├── graph.html # Interactive content graph
└── search.html # Full-text search interface
Base Template Structure
The base.html template provides the foundational layout:
<!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 }}{% endblock %}</title>
<!-- Meta tags, CSS, etc. -->
</head>
<body>
<nav>
<!-- Site navigation -->
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<!-- Site footer -->
</footer>
</body>
</html>
Content Template Variables
When customizing templates, you have access to these variables:
All Templates
title: Page titlecurrent_year: Current year for copyrightindex_counts: Statistics for all content indexes
Content Pages (post.html)
content: Rendered HTML contentmetadata: Frontmatter datareading_time: Estimated reading time in minutesword_count: Content word counttags: List of content tagsunique_icon: Custom icon for the contentrelated_posts: Algorithm-suggested related contentadjacent_posts: Previous and next in chronological order
Index Pages
articles: Content items for the indextotal_count: Total items in the index- Specific data based on index type (sidenotes, quotes, etc.)
Styling System
TufteCMS includes Tufte-inspired CSS that you can customize or replace entirely.
CSS Architecture
tuftecms/static/css/
├── tufte.css # Core Tufte-style typography
├── layout.css # Site layout and structure
├── components.css # UI components (navigation, forms)
├── syntax.css # Code syntax highlighting
└── custom.css # Your customizations
Key Design Classes
/* Content layout */
.post-content /* Main content container */
.sidenote /* Marginal annotations */
.margin-toggle /* Sidenote toggle mechanism */
/* Typography */
.subtitle /* Subtitle styling */
.legend-dot /* Colored dots for categorization */
.project-link /* Internal link styling */
/* Navigation */
.pathway-box /* Homepage pathway sections */
.footer-indexes /* Footer navigation links */
/* Content organization */
.color-philosophy /* Philosophy content theme */
.color-software /* Software content theme */
.color-ai /* AI content theme */
.color-essay /* Essay content theme */
Color Theming
TufteCMS uses a semantic color system for content categorization:
:root {
--color-philosophy: #95a5a6;
--color-software: #e74c3c;
--color-ai: #9b59b6;
--color-essay: #3498db;
--color-music: #f39c12;
--color-poetry: #27ae60;
}
.project-link.color-philosophy { color: var(--color-philosophy); }
.project-link.color-software { color: var(--color-software); }
/* etc. */
Custom CSS
Add your customizations to tuftecms/static/css/custom.css:
/* Override typography */
body {
font-family: your-preferred-font, serif;
font-size: 1.1em;
line-height: 1.7;
}
/* Customize sidenote appearance */
.sidenote {
background-color: #f9f9f9;
border-left: 3px solid #ddd;
padding-left: 0.5em;
}
/* Add custom content themes */
.project-link.color-custom {
color: #your-brand-color;
}
/* Modify layout constraints */
.post-content {
max-width: 50rem; /* Adjust reading column width */
}
Navigation Customization
Header Navigation
Modify the site navigation in base.html:
<nav class="site-navigation">
<a href="/" class="home-link">Your Site Name</a>
<div class="nav-links">
<a href="/essays">Essays</a>
<a href="/projects">Projects</a>
<a href="/docs">Documentation</a>
<a href="/search">Search</a>
</div>
</nav>
Footer Indexes
Customize the footer content guides in your index template:
<section class="footer-indexes">
<h3>Navigate This Garden</h3>
<div class="index-links">
<a href="/sidenotes">Marginalia ({{ index_counts.sidenotes }})</a>
<a href="/connections">Cross-References ({{ index_counts.connections_outgoing }})</a>
<a href="/archive">Archive</a>
<a href="/random">Random Discovery</a>
</div>
</section>
Custom Index Pages
Create new index types by adding routes and templates:
# In blueprints/main.py
@main_bp.route("/custom-index")
def custom_index():
# Your custom logic here
return render_template("custom-index.html", data=your_data)
Content Processing Customization
Markdown Extensions
Extend markdown processing in core/markdown.py:
import markdown
from markdown.extensions import codehilite, toc, tables
# Add custom extensions
md = markdown.Markdown(
extensions=[
'codehilite',
'toc',
'tables',
'your_custom_extension'
],
extension_configs={
'codehilite': {'css_class': 'highlight'},
'toc': {'anchorlink': True}
}
)
Custom Content Filters
Add Jinja2 template filters in app.py:
@app.template_filter('your_filter')
def your_custom_filter(text):
"""Custom text processing."""
return process_text(text)
Content Metadata
Extend frontmatter processing to support custom fields:
# In your content processing
def extract_metadata(frontmatter_data):
metadata = {
'title': frontmatter_data.get('title', ''),
'date': frontmatter_data.get('date'),
'your_custom_field': frontmatter_data.get('custom_field'),
# Process custom metadata here
}
return metadata
Brand Integration
Logo and Identity
Replace the site title with your logo in base.html:
<div class="site-header">
<img src="/static/images/logo.svg" alt="Your Site" class="site-logo">
<h1 class="site-title">Your Digital Garden</h1>
</div>
Custom Fonts
Add web fonts in your base template:
<head>
<!-- Google Fonts example -->
<link href="https://fonts.googleapis.com/css2?family=Your+Font:wght@400;600&display=swap" rel="stylesheet">
<!-- Or self-hosted fonts -->
<link href="/static/fonts/your-font.css" rel="stylesheet">
</head>
/* Apply in your CSS */
body {
font-family: 'Your Font', Georgia, serif;
}
.sidenote {
font-family: 'Your Sans Font', 'Helvetica Neue', sans-serif;
}
Color Scheme
Define your brand colors:
:root {
--primary-color: #your-primary;
--secondary-color: #your-secondary;
--accent-color: #your-accent;
--text-color: #your-text;
--background-color: #your-background;
--border-color: #your-border;
}
/* Apply throughout your styles */
.project-link { color: var(--accent-color); }
.sidenote { border-color: var(--border-color); }
Content Organization
Custom Content Types
Create new content categories by adding directories and customizing templates:
data/
├── essays/ # Existing
├── projects/ # Existing
├── reviews/ # New: Book/film reviews
├── tutorials/ # New: Technical guides
└── experiments/ # New: Work-in-progress ideas
Add routing logic in blueprints/content.py for custom handling:
# Special handling for new content types
if path.startswith("reviews/"):
# Custom processing for reviews
return render_review_template(content_data)
elif path.startswith("experiments/"):
# Different template for experimental content
return render_experiment_template(content_data)
Custom Metadata Fields
Extend frontmatter for specific content types:
---
title: "Book Review: Consciousness Explained"
type: "review"
reviewed_item: "Consciousness Explained by Daniel Dennett"
rating: 4
review_date: 2025-01-15
tags: [consciousness, philosophy, books]
---
Process in templates:
{% if metadata.type == 'review' %}
<div class="review-metadata">
<h2>{{ metadata.reviewed_item }}</h2>
<div class="rating">Rating: {{ metadata.rating }}/5</div>
</div>
{% endif %}
Advanced Customization
Custom Caching
Extend the caching system for your content types:
# In core/cache.py
@lru_cache(maxsize=1)
def get_custom_cache():
"""Cache your custom content analysis."""
# Your caching logic
return processed_data
Search Integration
Customize search behavior in your templates and JavaScript:
// Custom search filtering
function filterResults(results, contentType) {
if (contentType === 'essays') {
return results.filter(r => r.path.includes('/essays/'));
}
return results;
}
Analytics and Insights
Add custom analytics while respecting privacy:
<!-- Privacy-respecting analytics -->
<script>
// Your analytics code here
// Consider: Plausible, Simple Analytics, or self-hosted solutions
</script>
Performance Optimization
Static Asset Optimization
# In app.py - add asset versioning
@app.template_filter('asset_version')
def asset_version(filename):
"""Add version hash to asset URLs."""
# Your versioning logic
return f"{filename}?v={get_file_hash(filename)}"
Caching Headers
Customize caching behavior in blueprints/content.py:
# Custom cache headers for different content types
if file_path.suffix == '.md':
# Shorter cache for dynamic content
response.headers['Cache-Control'] = 'public, max-age=3600'
elif file_path.suffix in ['.jpg', '.png', '.svg']:
# Longer cache for images
response.headers['Cache-Control'] = 'public, max-age=604800'
Next Steps
With your customized TufteCMS site:
- Structure your content - Apply customizations to well-organized content using the content structure guide
- Master sidenotes - Style the sidenotes system to match your visual identity
- Deploy to production - Launch your customized site with the deployment guide
- Continue exploring - Return to the documentation index for advanced topics
Remember: Customization should serve your content, not overshadow it. The best modifications enhance readability and discovery while maintaining the contemplative focus that makes your digital garden a place worth visiting.