Skip to main content

Overview

The plantilla.html file serves as a reusable template that’s filled with dynamically generated content. It includes a responsive design, sidebar navigation, and a clean card-based layout.

Template Structure

The template uses a simple variable substitution system with placeholder tags:
plantilla.html
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Historia Diaria Automatizada</title>
    <style>
        /* Embedded CSS styles */
    </style>
</head>
<body>
    <button id="menu-btn" onclick="toggleMenu()"></button>
    
    <nav id="sidebar">
        <button id="close-btn" onclick="toggleMenu()"></button>
        <h2>Historial</h2>
        {{MENU}}
    </nav>
    
    <div class="container">
        <h1>{{TITULO}}</h1>
        <img src="{{IMAGEN_URL}}" alt="Imagen del día" class="imagen-dia">
        <div class="historia-texto">
            <p>{{HISTORIA}}</p>
        </div>
    </div>
    
    <script>
        function toggleMenu() {
            const sidebar = document.getElementById('sidebar');
            sidebar.classList.toggle('abierto');
        }
    </script>
</body>
</html>

Variable Placeholders

The template uses four dynamic placeholders that are replaced by the Python script:
Location: <h1>{{TITULO}}</h1>Replaced with the AI-generated story title extracted from the <TITULO> tag in the API response.
contenido_html = contenido_html.replace('{{TITULO}}', nuevo_titulo)
Location: <p>{{HISTORIA}}</p>Replaced with the story content extracted from the <HISTORIA> tag. Supports multi-paragraph text.
contenido_html = contenido_html.replace('{{HISTORIA}}', nueva_historia)
Location: <img src="{{IMAGEN_URL}}" ...>Replaced with the Picsum Photos URL generated using a random UUID seed.
contenido_html = contenido_html.replace('{{IMAGEN_URL}}', url_imagen)

Replacement Process

The Python script performs simple string replacement:
generar_historia.py
# 7. Load template
with open('plantilla.html', 'r', encoding='utf-8') as archivo:
    contenido_html = archivo.read()

# Replace all placeholders
contenido_html = contenido_html.replace('{{TITULO}}', nuevo_titulo)
contenido_html = contenido_html.replace('{{HISTORIA}}', nueva_historia)
contenido_html = contenido_html.replace('{{IMAGEN_URL}}', url_imagen)
contenido_html = contenido_html.replace('{{MENU}}', menu_html)

# 8. Save final files
with open('index.html', 'w', encoding='utf-8') as archivo:
    archivo.write(contenido_html)

with open(nombre_archivo_hoy, 'w', encoding='utf-8') as archivo:
    archivo.write(contenido_html)
This approach is simple and doesn’t require a templating engine like Jinja2. It works perfectly for this use case since the placeholders are unique and don’t conflict with HTML syntax.

Styling System

The template includes embedded CSS with a modern, clean design:

Color Palette

plantilla.html
body {
    background-color: #f0f2f5;  /* Light gray background */
}

.container {
    background-color: #ffffff;  /* White card */
}

h1 {
    color: #2d3748;  /* Dark gray headings */
}

.historia-texto {
    color: #4a5568;  /* Medium gray text */
}

Layout Components

plantilla.html
.container {
    background-color: #ffffff;
    padding: 40px;
    border-radius: 16px;
    box-shadow: 0 10px 25px rgba(0,0,0,0.1);
    max-width: 600px;
    width: 100%;
    text-align: center;
    margin-top: 40px;
}
Creates a centered card with rounded corners and subtle shadow.
The sidebar navigation is dynamically built from historial.json:
generar_historia.py
# 6. Generate sidebar menu HTML
menu_html = ""
for mes, historias in historial.items():
    menu_html += f'<h3 class="mes-titulo">{mes}</h3>'
    menu_html += '<ul class="lista-historias">'
    for item in historias:
        menu_html += f'<li><a href="{item["archivo"]}">{item["titulo"]}</a></li>'
    menu_html += '</ul>'

Generated Menu Example

Based on the actual historial.json data:
Generated Output
<h3 class="mes-titulo">Marzo 2026</h3>
<ul class="lista-historias">
    <li><a href="historia-2026-03-04.html">El Guardián del Faro de las Sombras</a></li>
    <li><a href="historia-2026-03-03.html">El Guardián del Laberinto Cuántico</a></li>
    <li><a href="historia-2026-03-02.html">El Código de las Estrellas</a></li>
</ul>
<h3 class="mes-titulo">Febrero 2026</h3>
<ul class="lista-historias">
    <li><a href="historia-2026-02-26.html">El Eco de los Días Perdidos</a></li>
    <li><a href="historia-2026-02-25.html">El Eco del Ayer</a></li>
</ul>
plantilla.html
#sidebar {
    position: fixed;
    top: 0;
    left: -300px;  /* Hidden by default */
    width: 250px;
    height: 100%;
    background-color: #ffffff;
    box-shadow: 2px 0 15px rgba(0,0,0,0.2);
    transition: left 0.3s ease;  /* Smooth slide animation */
    padding: 20px;
    overflow-y: auto;
    z-index: 1001;
}

#sidebar.abierto {
    left: 0;  /* Slides into view */
}
The sidebar uses a translate animation instead of display toggling, providing a smooth slide-in effect.
plantilla.html
<button id="menu-btn" onclick="toggleMenu()"></button>
plantilla.html
#menu-btn {
    position: fixed;
    top: 20px;
    left: 20px;
    font-size: 24px;
    background: #ffffff;
    border: none;
    padding: 10px 15px;
    border-radius: 8px;
    cursor: pointer;
    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    z-index: 1000;
}

Responsive Design

The template is mobile-friendly:

Viewport Meta Tag

plantilla.html
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Ensures proper scaling on mobile devices.

Flexible Layout

plantilla.html
body {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 90vh;
}

.container {
    max-width: 600px;
    width: 100%;  /* Scales down on smaller screens */
}

.imagen-dia {
    max-width: 100%;  /* Never exceeds container */
    height: auto;     /* Maintains aspect ratio */
}
The card layout automatically adapts to screen width, maintaining readability on phones, tablets, and desktops.

JavaScript Functionality

The template includes minimal JavaScript for sidebar toggling:
plantilla.html
function toggleMenu() {
    const sidebar = document.getElementById('sidebar');
    sidebar.classList.toggle('abierto');
}

How It Works

  1. User clicks the hamburger button ()
  2. toggleMenu() is called
  3. The abierto class is toggled on the sidebar
  4. CSS transition animates the sidebar sliding in/out
  5. Close button () uses the same function to hide the menu

Month Grouping Styles

Month headers and story lists have distinct styling:
plantilla.html
.mes-titulo {
    color: #2d3748;
    border-bottom: 2px solid #e2e8f0;
    padding-bottom: 5px;
    margin-top: 20px;
}

.lista-historias {
    list-style-type: none;
    padding: 0;
}

.lista-historias li {
    margin-bottom: 10px;
}

.lista-historias a {
    text-decoration: none;
    color: #4a5568;
    font-size: 0.95rem;
}

.lista-historias a:hover {
    color: #3182ce;
    text-decoration: underline;
}
This creates clear visual separation between months and provides hover feedback on links.

Complete Rendering Example

<div class="container">
    <h1>{{TITULO}}</h1>
    <img src="{{IMAGEN_URL}}" alt="Imagen del día" class="imagen-dia">
    <div class="historia-texto">
        <p>{{HISTORIA}}</p>
    </div>
</div>

Template Advantages

No Build Step

Pure HTML/CSS/JS means instant page loads without bundlers or frameworks

Simple Maintenance

Easy to update styles or layout without complex tooling

GitHub Pages Ready

Static files deploy directly without server-side rendering

Offline Capable

All assets embedded means pages work without internet (except images)

Customization Guide

Changing Colors

Edit the color values in the embedded <style> block:
plantilla.html
body {
    background-color: #yourcolor;  /* Change background */
}

h1 {
    color: #yourcolor;  /* Change title color */
}

Adjusting Layout Width

plantilla.html
.container {
    max-width: 800px;  /* Wider cards */
}

Modifying Image Dimensions

Change the Picsum URL dimensions in the Python script:
generar_historia.py
url_imagen = f"https://picsum.photos/seed/{codigo_unico}/800/450"  # Wider aspect ratio

Next Steps

How It Works

Understand the complete system architecture

Customization

Learn how to customize colors, fonts, and layouts

Build docs developers (and LLMs) love