Greetings, intrepid static site architect! You stand before the great Hall of Collections—a mystical chamber where scattered content transforms into organized, filterable, and dynamic displays. In this quest, you shall master the ancient arts of Jekyll collections, forging powerful layouts that respond to frontmatter incantations and user interactions alike.

The knowledge you gain here will allow you to build quest tracking systems, portfolio galleries, documentation hubs, and any content collection that demands organization and discovery. Whether you seek to catalog your own adventures or create portals for fellow travelers, this quest will arm you with the spells needed to succeed.

📜 The Legend Behind This Quest

In the realm of static site generators, Jekyll reigns as the venerable wizard-king—simple yet powerful, transforming markdown into magnificent web pages. But many who wield Jekyll’s power never venture beyond basic posts and pages, missing the treasure trove of collections.

Collections are Jekyll’s secret weapon for organizing related content: quests, products, team members, portfolio pieces—anything that shares a common structure. Combined with Liquid templating and frontmatter metadata, collections become the foundation for dynamic, data-driven interfaces that rival server-rendered applications.

This quest was born from a real implementation: building a quest tracking system for IT-Journey that displays quests by tier, allows filtering by type/difficulty/technology, shows statistics, and supports level-specific views. You will recreate this system, learning production-ready patterns along the way.


🎯 Quest Objectives

By the time you complete this epic journey, you will have mastered:

Primary Objectives (Required for Quest Completion)

Secondary Objectives (Bonus Achievements)

Mastery Indicators

You’ll know you’ve truly mastered this quest when you can:


🗺️ Quest Prerequisites

📋 Knowledge Requirements

🛠️ System Requirements

🧠 Skill Level Indicators

This 🔴 Hard quest expects:


🌍 Choose Your Adventure Platform

Different platforms offer unique advantages for this quest. Choose the path that best fits your current setup and learning goals.

# Start Jekyll development environment
docker-compose up -d

# Verify Jekyll is running
docker-compose exec jekyll bundle exec jekyll --version

# Build site with trace for debugging
docker-compose exec jekyll bundle exec jekyll build --trace

# Serve with live reload
docker-compose exec jekyll bundle exec jekyll serve --host 0.0.0.0 --port 4000 --livereload

Docker ensures consistent Ruby/Jekyll versions across all team members and CI/CD pipelines. This is the path of the wise.

🍎 macOS Kingdom Path

# Install Jekyll via Homebrew
brew install ruby
gem install bundler jekyll

# Navigate to project
cd ~/github/it-journey

# Install dependencies
bundle install

# Build and serve
bundle exec jekyll serve --port 4000 --livereload

macOS provides a native development experience. Ensure you’re using a Ruby version manager (rbenv or rvm) to avoid permission issues.

🪟 Windows Empire Path

# Using WSL2 (recommended) or RubyInstaller
wsl --install  # If WSL not installed

# In WSL terminal
sudo apt update
sudo apt install ruby-full build-essential zlib1g-dev
gem install bundler jekyll

# Navigate and serve
cd /mnt/c/Users/YourName/github/it-journey
bundle install
bundle exec jekyll serve --port 4000

WSL2 provides a Linux environment within Windows, making Jekyll development smooth.

🐧 Linux Territory Path

# Install Ruby and Jekyll (Ubuntu/Debian)
sudo apt update
sudo apt install ruby-full build-essential zlib1g-dev
gem install bundler jekyll

# Navigate to project
cd ~/github/it-journey

# Install and serve
bundle install
bundle exec jekyll serve --port 4000 --livereload

Linux is Jekyll’s native habitat. Most commands work identically to macOS.


🧙‍♂️ Chapter 1: Understanding Jekyll Collections

Before we forge our quest tracking system, we must understand the mystical nature of Jekyll collections—repositories of related content that share structure and purpose.

⚔️ Skills You’ll Forge in This Chapter

🏗️ The Collection Configuration Spell

Open your _config.yml and examine (or add) the collections configuration:

# _config.yml

# Collections configuration
collections_dir: pages  # Optional: group collections in a subdirectory
collections:
  quests:
    output: true  # Generate individual pages for each quest
    permalink: /:collection/:categories/:name/
    sort_by: level  # Optional: default sort order

# Default frontmatter for quests
defaults:
  - scope:
      path: ""
      type: quests
    values:
      layout: journals  # Default layout for quest pages
      fmContentType: quest

Key Configuration Options:

📁 Collection Directory Structure

pages/
└── _quests/
    ├── README.md           # Collection index
    ├── templates/          # Quest templates
    │   └── main-quest-template.md
    ├── 0000/               # Level 0000 quests
    │   ├── README.md       # Level index
    │   └── hello-world.md
    ├── 0001/               # Level 0001 quests
    │   └── ...
    └── 0101/               # Level 0101 quests (your current level!)
        ├── README.md
        └── jekyll-quest-tracking.md  # This quest!

🔍 Accessing Collection Data in Liquid


{%- comment -%} All quests in the collection {%- endcomment -%}
{% assign all_quests = site.quests %}

{%- comment -%} Filter quests with a specific attribute {%- endcomment -%}
{% assign hard_quests = site.quests | where: "difficulty", "🔴 Hard" %}

{%- comment -%} Filter using expressions {%- endcomment -%}
{% assign level_0101 = site.quests | where: "level", "0101" %}

{%- comment -%} Map to extract specific values {%- endcomment -%}
{% assign all_levels = site.quests | map: "level" | compact | uniq | sort %}

{%- comment -%} Count quests {%- endcomment -%}
{% assign quest_count = site.quests | size %}

🔮 Knowledge Check: Collection Fundamentals

⚡ Quick Wins


🧙‍♂️ Chapter 2: Building the Quest Collection Layout

Now we forge the heart of our system—a layout that transforms raw quest data into an organized, tier-based display.

⚔️ Skills You’ll Forge in This Chapter

🏗️ The Collection Layout Architecture

Create _layouts/quest-collection.html:


---
layout: default
---
{%- comment -%}
Quest Collection Layout
Displays quests from the site.quests collection using frontmatter data.
Supports filtering by level (pass level parameter to filter to specific level).
{%- endcomment -%}

<div class="quest-collection">
  <header class="quest-collection-header">
    <h1>{{ page.title | default: "Quest Collection" }}</h1>
    {% if page.description %}
    <p class="lead">{{ page.description }}</p>
    {% endif %}
  </header>

  {%- comment -%} Quest Statistics {%- endcomment -%}
  {% include quest-stats.html level=page.level %}

  {%- comment -%} Quest Filters {%- endcomment -%}
  {% include quest-filters.html level=page.level %}

  {%- comment -%} 
  Determine which quests to display:
  - If page.level is set, filter to that level only
  - Otherwise show all quests
  {%- endcomment -%}
  
  {% if page.level %}
    {% assign filtered_quests = site.quests | where: "level", page.level %}
  {% else %}
    {% assign filtered_quests = site.quests %}
  {% endif %}

  {%- comment -%} Group quests by level tier {%- endcomment -%}
  {% assign level_0000 = filtered_quests | where: "level", "0000" %}
  {% assign level_0001 = filtered_quests | where: "level", "0001" %}
  {% assign level_0010 = filtered_quests | where: "level", "0010" %}
  {% assign level_0011 = filtered_quests | where: "level", "0011" %}
  
  {%- comment -%} Continue for all 16 levels... {%- endcomment -%}

  {%- comment -%} Apprentice Tier (0000-0011) {%- endcomment -%}
  {% assign apprentice_quests = level_0000 | concat: level_0001 | concat: level_0010 | concat: level_0011 %}
  {% if apprentice_quests.size > 0 and page.level == nil %}
  <section class="quest-tier quest-tier-apprentice" data-tier="apprentice">
    <h2 class="tier-header">
      <span class="tier-icon">🌱</span>
      <span class="tier-name">Apprentice Tier</span>
      <span class="tier-levels">(Levels 0000-0011)</span>
      <span class="tier-count">{{ apprentice_quests.size }} quests</span>
    </h2>
    <p class="tier-description">Foundation skills for beginning your IT journey.</p>
    <div class="quest-grid">
      {% for quest in apprentice_quests %}
        {% include quest-card.html quest=quest %}
      {% endfor %}
    </div>
  </section>
  {% endif %}

  {%- comment -%} Repeat for Adventurer, Warrior, Master tiers... {%- endcomment -%}

  {%- comment -%} Page Content (for additional markdown content) {%- endcomment -%}
  {% if content != "" %}
  <section class="quest-collection-content">
    {{ content }}
  </section>
  {% endif %}
</div>

🎨 Tier Styling Magic

/* Quest Tier Sections */
.quest-tier {
  margin-bottom: 3rem;
  padding: 1.5rem;
  border-radius: 8px;
  background: var(--bg-secondary, #f8f9fa);
}

/* Tier Colors */
.quest-tier-apprentice { border-left: 4px solid #28a745; }  /* 🌱 Green */
.quest-tier-adventurer { border-left: 4px solid #fd7e14; }  /* ⚔️ Orange */
.quest-tier-warrior { border-left: 4px solid #dc3545; }     /* 🔥 Red */
.quest-tier-master { border-left: 4px solid #6f42c1; }      /* 👑 Purple */

/* Quest Grid */
.quest-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 1.5rem;
}

🔍 Knowledge Check: Layout Architecture

⚡ Quick Wins


🧙‍♂️ Chapter 3: Forging the Quest Card Component

Each quest deserves a beautifully crafted card that displays its vital statistics. We shall create a reusable include component.

⚔️ Skills You’ll Forge in This Chapter

🏗️ The Quest Card Include

Create _includes/quest-card.html:


{% comment %}
  Quest Card Include
  
  Usage: {% include quest-card.html quest=quest %}
  
  Required frontmatter in quest pages:
  - title, difficulty, estimated_time, quest_type, level, description
{% endcomment %}

{% assign quest = include.quest %}

<article class="quest-card" 
         data-difficulty="{{ quest.difficulty | default: 'Unknown' }}"
         data-quest-type="{{ quest.quest_type | default: 'main_quest' }}"
         data-level="{{ quest.level | default: '0000' }}"
         data-technology="{{ quest.primary_technology | default: '' }}"
         data-skill-focus="{{ quest.skill_focus | default: '' }}"
         data-title="{{ quest.title | escape }}"
         data-description="{{ quest.description | default: '' | strip_html | escape }}">
  
  <div class="quest-card-header">
    {% if quest.difficulty %}
      {% assign diff = quest.difficulty | split: ' ' | first %}
      <span class="quest-difficulty" title="{{ quest.difficulty }}">{{ diff }}</span>
    {% endif %}
    
    {% if quest.quest_type %}
      {% case quest.quest_type %}
        {% when 'main_quest' %}
          <span class="quest-type quest-type-main" title="Main Quest">🏰</span>
        {% when 'side_quest' %}
          <span class="quest-type quest-type-side" title="Side Quest">⚔️</span>
        {% when 'bonus_quest' %}
          <span class="quest-type quest-type-bonus" title="Bonus Quest">🎁</span>
        {% when 'epic_quest' %}
          <span class="quest-type quest-type-epic" title="Epic Quest">👑</span>
      {% endcase %}
    {% endif %}
  </div>
  
  <h3 class="quest-card-title">
    <a href="{{ quest.url | relative_url }}">{{ quest.title | default: 'Untitled Quest' }}</a>
  </h3>
  
  {% if quest.description %}
    <p class="quest-card-description">{{ quest.description | truncate: 120 }}</p>
  {% endif %}
  
  <div class="quest-card-meta">
    {% if quest.estimated_time %}
      <span class="quest-time" title="Estimated Time">🕐 {{ quest.estimated_time }}</span>
    {% endif %}
    {% if quest.level %}
      <span class="quest-level" title="Level {{ quest.level }}">📊 Lvl {{ quest.level }}</span>
    {% endif %}
    {% if quest.primary_technology %}
      <span class="quest-tech" title="Primary Technology">🛠️ {{ quest.primary_technology }}</span>
    {% endif %}
  </div>
  
  <a href="{{ quest.url | relative_url }}" class="quest-card-link">Begin Quest →</a>
</article>

💡 The Power of Data Attributes

Data attributes (data-*) are the bridge between server-rendered HTML and client-side JavaScript:

<article class="quest-card" 
         data-difficulty="🔴 Hard"
         data-quest-type="side_quest"
         data-level="0101"
         data-technology="jekyll">

JavaScript can then read these attributes:

const card = document.querySelector('.quest-card');
console.log(card.dataset.difficulty);  // "🔴 Hard"
console.log(card.dataset.questType);   // "side_quest" (camelCase conversion)

🔍 Knowledge Check: Component Design

⚡ Quick Wins


🧙‍♂️ Chapter 4: The Filtering Enchantment

Now we weave JavaScript magic to enable real-time filtering of our quest collection.

⚔️ Skills You’ll Forge in This Chapter

🏗️ The Quest Filters Include

Create _includes/quest-filters.html:


{%- comment -%}
Quest Filters Include
Provides interactive filtering UI for quest collections.
{%- endcomment -%}

{%- comment -%} Collect unique values for filter dropdowns {%- endcomment -%}
{% assign all_quests = site.quests | where_exp: "q", "q.title != nil" %}
{%- if include.level and include.level != '' -%}
  {% assign all_quests = all_quests | where: "level", include.level %}
{%- endif -%}

{%- comment -%} Get unique quest types {%- endcomment -%}
{% assign quest_types = all_quests | map: "quest_type" | compact | uniq | sort %}

{%- comment -%} Get unique difficulties {%- endcomment -%}
{% assign difficulties = all_quests | map: "difficulty" | compact | uniq | sort %}

{%- comment -%} 
IMPORTANT: Level sorting edge case fix!
Some frontmatter has level: 1100 (Integer), others level: "1100" (String).
Liquid's sort filter fails on mixed types. We coerce all to strings.
{%- endcomment -%}
{% assign levels_raw = all_quests | map: "level" | compact | uniq %}
{% assign levels_joined = "" %}
{% for lval in levels_raw %}
  {% assign levels_joined = levels_joined | append: lval | append: "," %}
{% endfor %}
{% assign levels = levels_joined | split: "," | uniq | sort %}

<div class="quest-filters" id="quest-filters">
  <div class="filters-header">
    <h3>🔍 Filter Quests</h3>
    <button type="button" class="btn-reset-filters" onclick="resetAllFilters()">
      Reset All
    </button>
  </div>
  
  <div class="filters-grid">
    {%- comment -%} Quest Type Filter {%- endcomment -%}
    <div class="filter-group">
      <label for="filter-quest-type">Quest Type</label>
      <select id="filter-quest-type" onchange="applyFilters()">
        <option value="">All Types</option>
        {% for type in quest_types %}
        <option value="{{ type }}">
          {% case type %}
            {% when 'main_quest' %}🏰 Main Quest
            {% when 'side_quest' %}⚔️ Side Quest
            {% when 'bonus_quest' %}🎁 Bonus Quest
            {% when 'epic_quest' %}👑 Epic Quest
            {% else %}{{ type | replace: "_", " " | capitalize }}
          {% endcase %}
        </option>
        {% endfor %}
      </select>
    </div>

    {%- comment -%} Additional filters: difficulty, level, technology, skill_focus, search {%- endcomment -%}
    {%- comment -%} ... (similar pattern for each filter) ... {%- endcomment -%}
  </div>
</div>

<script>
function applyFilters() {
  const questType = document.getElementById('filter-quest-type').value.toLowerCase();
  const difficulty = document.getElementById('filter-difficulty').value.toLowerCase();
  const level = document.getElementById('filter-level').value.toLowerCase();
  const technology = document.getElementById('filter-technology').value.toLowerCase();
  const skillFocus = document.getElementById('filter-skill-focus').value.toLowerCase();
  const searchTerm = document.getElementById('filter-search').value.toLowerCase().trim();

  const questCards = document.querySelectorAll('.quest-card');
  let visibleCount = 0;

  questCards.forEach(card => {
    const cardType = (card.dataset.questType || '').toLowerCase();
    const cardDifficulty = (card.dataset.difficulty || '').toLowerCase();
    const cardLevel = (card.dataset.level || '').toLowerCase();
    const cardTechnology = (card.dataset.technology || '').toLowerCase();
    const cardSkillFocus = (card.dataset.skillFocus || '').toLowerCase();
    const cardTitle = (card.dataset.title || '').toLowerCase();
    const cardDescription = (card.dataset.description || '').toLowerCase();

    let show = true;

    // Apply each filter
    if (questType && !cardType.includes(questType)) show = false;
    if (show && difficulty && !cardDifficulty.includes(difficulty)) show = false;
    if (show && level && cardLevel !== level) show = false;
    if (show && technology && !cardTechnology.includes(technology)) show = false;
    if (show && skillFocus && !cardSkillFocus.includes(skillFocus)) show = false;
    if (show && searchTerm) {
      const matchesSearch = cardTitle.includes(searchTerm) || 
                           cardDescription.includes(searchTerm) ||
                           cardTechnology.includes(searchTerm);
      if (!matchesSearch) show = false;
    }

    if (show) {
      card.classList.remove('filtered-out');
      visibleCount++;
    } else {
      card.classList.add('filtered-out');
    }
  });

  // Update tier visibility
  updateTierVisibility();
  
  // Update results count
  document.getElementById('results-count').textContent = 
    `Showing ${visibleCount} of ${questCards.length} quests`;
}

function updateTierVisibility() {
  const tiers = document.querySelectorAll('.quest-tier');
  tiers.forEach(tier => {
    const visibleCards = tier.querySelectorAll('.quest-card:not(.filtered-out)');
    tier.classList.toggle('filtered-empty', visibleCards.length === 0);
  });
}

function resetAllFilters() {
  document.getElementById('filter-quest-type').value = '';
  document.getElementById('filter-difficulty').value = '';
  document.getElementById('filter-level').value = '';
  document.getElementById('filter-technology').value = '';
  document.getElementById('filter-skill-focus').value = '';
  document.getElementById('filter-search').value = '';
  applyFilters();
}

// Initialize on page load
document.addEventListener('DOMContentLoaded', applyFilters);
</script>

⚠️ The Integer/String Sorting Trap

The Problem: Jekyll’s Liquid will fail with comparison of Integer with String failed when sorting an array containing both 1100 (Integer) and "1100" (String).

The Solution: Coerce all values to strings using the join/split pattern:


{% assign levels_raw = all_quests | map: "level" | compact | uniq %}
{% assign levels_joined = "" %}
{% for lval in levels_raw %}
  {% assign levels_joined = levels_joined | append: lval | append: "," %}
{% endfor %}
{% assign levels = levels_joined | split: "," | uniq | sort %}

This forces all values through string concatenation, ensuring uniform types.

🔍 Knowledge Check: Filtering Logic

⚡ Quick Wins


🧙‍♂️ Chapter 5: Python Automation for Frontmatter

Manual frontmatter updates are tedious and error-prone. We shall forge a Python spell to automate the task.

⚔️ Skills You’ll Forge in This Chapter

🏗️ The Frontmatter Update Script

Create scripts/development/update_level_readmes.py:

#!/usr/bin/env python3
"""
Script to ensure all level README files have consistent frontmatter:
- layout: quest-collection
- level: <directory_name>
- categories: quests

Only updates README.md files in direct child directories of pages/_quests
where the directory name is a 4-digit binary string (e.g., 0101, 1100).
"""

import os
import re
from pathlib import Path

# Calculate repo root: script is in scripts/development/
ROOT = Path(__file__).resolve().parents[2]
QUESTS_DIR = ROOT / 'pages' / '_quests'

# Regex to match binary level directories (0000-1111)
LEVEL_DIR_RE = re.compile(r'^[01]{4}$')


def process_readme(path: Path, level: str):
    """Update a README.md with required frontmatter fields."""
    text = path.read_text(encoding='utf-8')
    
    # Check for frontmatter
    if not text.startswith('---'):
        print(f"Skipping {path}: no frontmatter detected")
        return

    # Split into header and body
    parts = text.split('---', 2)
    header = parts[1]
    body = parts[2] if len(parts) > 2 else ''

    # Parse header into lines
    lines = [line.rstrip('\n') for line in header.split('\n')]

    # Check for required keys
    has_layout = any(re.match(r'\s*layout\s*:', line) for line in lines)
    has_level = any(re.match(r'\s*level\s*:', line) for line in lines)
    has_categories = any(re.match(r'\s*categories\s*:', line) for line in lines)

    # Append missing keys
    new_lines = lines.copy()
    appended = False
    
    if not has_layout:
        new_lines.append('layout: quest-collection')
        appended = True
    if not has_level:
        new_lines.append(f'level: {level}')
        appended = True
    if not has_categories:
        new_lines.append('categories: quests')
        appended = True

    # Write back if changes made
    if appended:
        new_header = '\n'.join(new_lines)
        new_text = '---\n' + new_header + '\n---' + body
        path.write_text(new_text, encoding='utf-8')
        print(f"Updated frontmatter for {path}")
    else:
        print(f"No changes for {path}")


def main():
    """Process all level directories."""
    if not QUESTS_DIR.exists():
        print("Quests directory not found at:", QUESTS_DIR)
        return

    for entry in QUESTS_DIR.iterdir():
        if entry.is_dir() and LEVEL_DIR_RE.match(entry.name):
            readme = entry / 'README.md'
            if readme.exists():
                process_readme(readme, entry.name)
            else:
                print(f"Skipping {entry}: README.md not present")


if __name__ == '__main__':
    main()

🔧 Running the Script

# From repo root with Python virtual environment
python scripts/development/update_level_readmes.py

# Or using the venv explicitly
.venv/bin/python scripts/development/update_level_readmes.py

Expected Output:

Updated frontmatter for /Users/you/github/it-journey/pages/_quests/0000/README.md
Updated frontmatter for /Users/you/github/it-journey/pages/_quests/0001/README.md
No changes for /Users/you/github/it-journey/pages/_quests/0101/README.md
Skipping /Users/you/github/it-journey/pages/_quests/1001: README.md not present

🔍 Knowledge Check: Automation Patterns

⚡ Quick Wins


🎮 Mastery Challenges

🟢 Novice Challenge: Add a New Filter

Goal: Add a “Learning Style” filter to the quest filters

Requirements:

Success Criteria: Filtering by learning style works correctly

Estimated Time: 30 minutes

🟡 Apprentice Challenge: Statistics Enhancement

Goal: Add technology distribution to quest statistics

Requirements:

Success Criteria: Stats show technology breakdown

Estimated Time: 45 minutes

🔴 Expert Challenge: Pagination

Goal: Implement pagination for large quest collections

Requirements:

Success Criteria: Pagination improves page load and UX for large collections

Estimated Time: 1-2 hours

⚔️ Master Challenge: Search Autocomplete

Goal: Add autocomplete suggestions to the search filter

Requirements:

Success Criteria: Professional-quality search autocomplete

Estimated Time: 2-3 hours


🏆 Quest Completion Validation

Portfolio Artifacts Created

Skills Demonstrated

Knowledge Gained

Final Validation

Build the site and verify:

docker-compose exec jekyll bundle exec jekyll build --trace

Check for:


🗺️ Quest Network Position

graph TB
    subgraph Prerequisites
        A[Level 0100: Frontend Docker] --> B[This Quest]
        C[Level 0001: GitHub Pages] -.-> B
        D[Level 0010: Terminal Enhancement] -.-> B
    end
    
    subgraph Current
        B[Level 0101: Jekyll Quest Tracking]
    end
    
    subgraph Unlocks
        B --> E[Level 1010: Automation & Testing]
        B --> F[Level 1011: Feature Development]
        B --> G[Level 1010: Hyperlink Guardian]
    end
    
    subgraph Parallel
        B ~~~ H[Level 0101: Docker Mastery]
        B ~~~ I[Level 0101: LazyTeX CV]
    end
    
    style B fill:#6f42c1,color:#fff
    style A fill:#28a745,color:#fff
    style E fill:#dc3545,color:#fff
    style F fill:#dc3545,color:#fff

⚙️ Implementation Flow Diagram

flowchart LR
    subgraph Data Layer
        A[Quest Markdown Files] --> B[YAML Frontmatter]
        B --> C[site.quests Collection]
    end
    
    subgraph Template Layer
        C --> D[quest-collection.html Layout]
        D --> E[quest-stats.html Include]
        D --> F[quest-filters.html Include]
        D --> G[quest-card.html Include]
    end
    
    subgraph Output Layer
        E --> H[Statistics Display]
        F --> I[Filter Dropdowns]
        G --> J[Quest Cards with Data Attrs]
    end
    
    subgraph Client Layer
        I --> K[JavaScript applyFilters]
        J --> K
        K --> L[Filtered Quest Display]
    end
    
    subgraph Automation
        M[Python Script] --> B
    end
    
    style A fill:#0d6efd,color:#fff
    style D fill:#6f42c1,color:#fff
    style K fill:#28a745,color:#fff
    style M fill:#fd7e14,color:#fff

🎉 Congratulations, Collection Architect!

You have successfully forged the Jekyll Quest Tracking system! Your mastery of collections, Liquid templating, and client-side filtering has created a powerful, reusable system for organizing and discovering content.

🌟 What’s Next?

Your newfound powers open several paths:

📚 Additional Resources

Resource Description
Jekyll Collections Docs Official documentation
Liquid Reference Complete Liquid syntax
CSS Grid Guide Grid layout mastery
JavaScript Dataset API Data attribute access

📓 AI Collaboration Log

This quest was developed through AI-assisted content generation:

Phase AI Contribution Human Validation
Planning Analyzed open commits to understand implementation Confirmed scope and objectives
Structure Generated quest outline following templates Reviewed for accuracy
Code Examples Created Liquid/JS/Python snippets Tested in Jekyll environment
Diagrams Generated Mermaid visualizations Verified relationships

Key AI Insights:


🧠 Lessons & Next Steps

Key Takeaways

  1. Collections are powerful - They transform Jekyll from a blog engine into a CMS
  2. Data attributes bridge static/dynamic - Server-render data, filter client-side
  3. Automation saves time - Batch frontmatter updates prevent manual errors
  4. Edge cases matter - The Integer/String issue only surfaces with mixed data

Future Enhancements

README Updates Required


✅ Quest Validation Checklist

Before committing, verify:


🔧 Kaizen Hooks

Suggested Improvements for Future Revisions

  1. Add more detailed CSS styling examples
  2. Include unit tests for the Python automation script
  3. Create a video walkthrough companion
  4. Add troubleshooting section for common Jekyll errors

Metrics to Monitor

Derivative Quest Ideas


May your collections be organized, your filters be fast, and your frontmatter be consistent! Ready for your next adventure? Check the Quest Map for your next challenge! ⚔️✨