Theme Switching and Navigation Logic Documentation

This is an internal system design — you should fully understand how your _config.yml, front matter, layout files, and navigation interact depending on the theme you choose.


Table of Contents

  1. Theme Declaration (_config.yml)
  2. Front Matter Layout Declaration (layout: base)
  3. base.html Logic: Theme Detection
  4. Theme Layout Includes
    • minimal_default.html
    • minima_default.html
  5. Navigation System
    • Navigation in Minimal
    • Navigation in Minima
  6. Styling
    • TailwindCSS for Minimal
    • SASS Skins for Minima
  7. Important Notes


1. Theme Declaration (_config.yml)

Your theme is declared in _config.yml at the root of the repository.

To use the Minimal theme:

remote_theme: opencodingsociety/minimal@v0.2.0

To use the Minima theme:

remote_theme: jekyll/minima

This remote theme declaration determines which CSS/JS, layout includes, and navigation logic will be used.


2. Front Matter Layout Declaration (layout: base)

In every page or post, you should declare the base layout in the front matter:

layout: base

This ensures that base.html will control the dynamic switching logic.

Example full front matter:

---
layout: base
title: My Post Title
nav: true
---

3. base.html Logic: Theme Detection

Here is the logic in base.html:

<!DOCTYPE html>
<html lang="en">


  <!DOCTYPE html>
<html lang="en"><head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Theme Switching and Navigation Logic Documentation | Open Coding Society</title>
<meta name="generator" content="Jekyll v3.10.0" />
<meta property="og:title" content="Theme Switching and Navigation Logic Documentation" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="Class of 2026" />
<meta property="og:description" content="Class of 2026" />
<link rel="canonical" href="https://open-coding-society.github.io/student_2026/theme_and_nav_docs" />
<meta property="og:url" content="https://open-coding-society.github.io/student_2026/theme_and_nav_docs" />
<meta property="og:site_name" content="Open Coding Society" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Theme Switching and Navigation Logic Documentation" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","description":"Class of 2026","headline":"Theme Switching and Navigation Logic Documentation","url":"https://open-coding-society.github.io/student_2026/theme_and_nav_docs"}</script>
<!-- End Jekyll SEO tag -->
<link id="main-stylesheet" rel="stylesheet" href="/student_2026/assets/css/style.css"><link type="application/atom+xml" rel="alternate" href="https://open-coding-society.github.io/student_2026/feed.xml" title="Open Coding Society" />
</head>
<body><header class="site-header">

  <div class="wrapper">
    <a class="site-title" rel="author" href="/student_2026/">Open Coding Society</a>
      <nav class="site-nav">
        <input type="checkbox" id="nav-trigger" />
        <label for="nav-trigger">
          <span class="menu-icon"></span>
        </label>

        <div class="nav-items">
  <a class="nav-item" href="/student_2026/tools/lessons">Lessons</a>
  <a class="nav-item" href="/student_2026/blogs/">Blogs</a>
  <a class="nav-item" href="/student_2026/search/">Search</a>
  <a class="nav-item" href="/student_2026/documents/">Docs</a>
  <a class="nav-item" href="/student_2026/leaderboard/">Leaderboard</a>
  <a class="nav-item" href="/student_2026/resource/">Resources</a>
  <a class="nav-item" href="/student_2026/login">Login</a>
  <a class="nav-item" href="/student_2026/logout">Logout</a>
</div>

      </nav>
  </div>
</header>
<main class="page-content" aria-label="Content">
      <div class="wrapper"><h1 class="page-title">Theme Switching and Navigation Logic Documentation</h1><div class="post-meta-block">
  
      
        
        
        
        
        
        
  
        
        
        
        
  
        
        
        
        
  
        
          
          
        
  
        
  
        
        
        
      
  
      
      
  
      <ul class="inline_toc">
        <ul><li><a href="#2>Snake">Snake</a>
      </ul><!-- Comments powered by Utterances --></div>
        
        <style>

    body{
    }
    .wrap{
        margin-left: auto;
        margin-right: auto;
    }

    canvas{
        display: none;
        border-style: solid;
        border-width: 10px;
        border-color: #FFFFFF;
    }
    canvas:focus{
        outline: none;
    }

    /* All screens style */
    #gameover p, #setting p, #menu p{
        font-size: 20px;
    }

    #gameover a, #setting a, #menu a{
        font-size: 30px;
        display: block;
    }

    #gameover a:hover, #setting a:hover, #menu a:hover{
        cursor: pointer;
    }

    #gameover a:hover::before, #setting a:hover::before, #menu a:hover::before{
        content: ">";
        margin-right: 10px;
    }

    #menu{
        display: block;
    }

    #gameover{
        display: none;
    }

    #setting{
        display: none;
    }

    #setting input{
        display:none;
    }

    #setting label{
        cursor: pointer;
    }

    #setting input:checked + label{
        background-color: #FFF;
        color: #000;
    }
</style>

<h2>Snake</h2>
<div class="container">
    <p class="fs-4">Score: <span id="score_value">0</span></p>

    <div class="container bg-secondary" style="text-align:center;">
        <!-- Main Menu -->
        <div id="menu" class="py-4 text-light">
            <p>Welcome to Snake, press <span style="background-color: #FFFFFF; color: #000000">space</span> to begin</p>
            <a id="new_game" class="link-alert">new game</a>
            <a id="setting_menu" class="link-alert">settings</a>
        </div>
        <!-- Game Over -->
        <div id="gameover" class="py-4 text-light">
            <p>Game Over, press <span style="background-color: #FFFFFF; color: #000000">space</span> to try again</p>
            <a id="new_game1" class="link-alert">new game</a>
            <a id="setting_menu1" class="link-alert">settings</a>
        </div>
        <!-- Play Screen -->
        <canvas id="snake" class="wrap" width="320" height="320" tabindex="1"></canvas>
        <!-- Settings Screen -->
        <div id="setting" class="py-4 text-light">
            <p>Settings Screen, press <span style="background-color: #FFFFFF; color: #000000">space</span> to go back to playing</p>
            <a id="new_game2" class="link-alert">new game</a>
            <br />
            <p>Speed:
                <input id="speed1" type="radio" name="speed" value="120" checked="" />
                <label for="speed1">Slow</label>
                <input id="speed2" type="radio" name="speed" value="75" />
                <label for="speed2">Normal</label>
                <input id="speed3" type="radio" name="speed" value="35" />
                <label for="speed3">Fast</label>
            </p>
            <p>Wall:
                <input id="wallon" type="radio" name="wall" value="1" checked="" />
                <label for="wallon">On</label>
                <input id="walloff" type="radio" name="wall" value="0" />
                <label for="walloff">Off</label>
            </p>
        </div>
    </div>
</div>

<script>
    (function(){
        /* Attributes of Game */
        /////////////////////////////////////////////////////////////
        // Canvas & Context
        const canvas = document.getElementById("snake");
        const ctx = canvas.getContext("2d");
        // HTML Game IDs
        const SCREEN_SNAKE = 0;
        const screen_snake = document.getElementById("snake");
        const ele_score = document.getElementById("score_value");
        const speed_setting = document.getElementsByName("speed");
        const wall_setting = document.getElementsByName("wall");
        // HTML Screen IDs (div)
        const SCREEN_MENU = -1, SCREEN_GAME_OVER=1, SCREEN_SETTING=2;
        const screen_menu = document.getElementById("menu");
        const screen_game_over = document.getElementById("gameover");
        const screen_setting = document.getElementById("setting");
        // HTML Event IDs (a tags)
        const button_new_game = document.getElementById("new_game");
        const button_new_game1 = document.getElementById("new_game1");
        const button_new_game2 = document.getElementById("new_game2");
        const button_setting_menu = document.getElementById("setting_menu");
        const button_setting_menu1 = document.getElementById("setting_menu1");
        // Game Control
        const BLOCK = 10;   // size of block rendering
        let SCREEN = SCREEN_MENU;
        let snake;
        let snake_dir;
        let snake_next_dir;
        let snake_speed;
        let food = {x: 0, y: 0};
        let score;
        let wall;
        /* Display Control */
        /////////////////////////////////////////////////////////////
        // 0 for the game
        // 1 for the main menu
        // 2 for the settings screen
        // 3 for the game over screen
        let showScreen = function(screen_opt){
            SCREEN = screen_opt;
            switch(screen_opt){
                case SCREEN_SNAKE:
                    screen_snake.style.display = "block";
                    screen_menu.style.display = "none";
                    screen_setting.style.display = "none";
                    screen_game_over.style.display = "none";
                    break;
                case SCREEN_GAME_OVER:
                    screen_snake.style.display = "block";
                    screen_menu.style.display = "none";
                    screen_setting.style.display = "none";
                    screen_game_over.style.display = "block";
                    break;
                case SCREEN_SETTING:
                    screen_snake.style.display = "none";
                    screen_menu.style.display = "none";
                    screen_setting.style.display = "block";
                    screen_game_over.style.display = "none";
                    break;
            }
        }
        /* Actions and Events  */
        /////////////////////////////////////////////////////////////
        window.onload = function(){
            // HTML Events to Functions
            button_new_game.onclick = function(){newGame();};
            button_new_game1.onclick = function(){newGame();};
            button_new_game2.onclick = function(){newGame();};
            button_setting_menu.onclick = function(){showScreen(SCREEN_SETTING);};
            button_setting_menu1.onclick = function(){showScreen(SCREEN_SETTING);};
            // speed
            setSnakeSpeed(150);
            for(let i = 0; i < speed_setting.length; i++){
                speed_setting[i].addEventListener("click", function(){
                    for(let i = 0; i < speed_setting.length; i++){
                        if(speed_setting[i].checked){
                            setSnakeSpeed(speed_setting[i].value);
                        }
                    }
                });
            }
            // wall setting
            setWall(1);
            for(let i = 0; i < wall_setting.length; i++){
                wall_setting[i].addEventListener("click", function(){
                    for(let i = 0; i < wall_setting.length; i++){
                        if(wall_setting[i].checked){
                            setWall(wall_setting[i].value);
                        }
                    }
                });
            }
            // activate window events
            window.addEventListener("keydown", function(evt) {
                // spacebar detected
                if(evt.code === "Space" && SCREEN !== SCREEN_SNAKE)
                    newGame();
            }, true);
        }
        /* Snake is on the Go (Driver Function)  */
        /////////////////////////////////////////////////////////////
        let mainLoop = function(){
            let _x = snake[0].x;
            let _y = snake[0].y;
            snake_dir = snake_next_dir;   // read async event key
            // Direction 0 - Up, 1 - Right, 2 - Down, 3 - Left
            switch(snake_dir){
                case 0: _y--; break;
                case 1: _x++; break;
                case 2: _y++; break;
                case 3: _x--; break;
            }
            snake.pop(); // tail is removed
            snake.unshift({x: _x, y: _y}); // head is new in new position/orientation
            // Wall Checker
            if(wall === 1){
                // Wall on, Game over test
                if (snake[0].x < 0 || snake[0].x === canvas.width / BLOCK || snake[0].y < 0 || snake[0].y === canvas.height / BLOCK){
                    showScreen(SCREEN_GAME_OVER);
                    return;
                }
            }else{
                // Wall Off, Circle around
                for(let i = 0, x = snake.length; i < x; i++){
                    if(snake[i].x < 0){
                        snake[i].x = snake[i].x + (canvas.width / BLOCK);
                    }
                    if(snake[i].x === canvas.width / BLOCK){
                        snake[i].x = snake[i].x - (canvas.width / BLOCK);
                    }
                    if(snake[i].y < 0){
                        snake[i].y = snake[i].y + (canvas.height / BLOCK);
                    }
                    if(snake[i].y === canvas.height / BLOCK){
                        snake[i].y = snake[i].y - (canvas.height / BLOCK);
                    }
                }
            }
            // Snake vs Snake checker
            for(let i = 1; i < snake.length; i++){
                // Game over test
                if (snake[0].x === snake[i].x && snake[0].y === snake[i].y){
                    showScreen(SCREEN_GAME_OVER);
                    return;
                }
            }
            // Snake eats food checker
            if(checkBlock(snake[0].x, snake[0].y, food.x, food.y)){
                snake[snake.length] = {x: snake[0].x, y: snake[0].y};
                altScore(++score);
                addFood();
                activeDot(food.x, food.y);
            }
            // Repaint canvas
            ctx.beginPath();
            ctx.fillStyle = "royalblue";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            // Paint snake
            for(let i = 0; i < snake.length; i++){
                activeDot(snake[i].x, snake[i].y);
            }
            // Paint food
            activeDot(food.x, food.y);
            // Debug
            //document.getElementById("debug").innerHTML = snake_dir + " " + snake_next_dir + " " + snake[0].x + " " + snake[0].y;
            // Recursive call after speed delay, déjà vu
            setTimeout(mainLoop, snake_speed);
        }
        /* New Game setup */
        /////////////////////////////////////////////////////////////
        let newGame = function(){
            // snake game screen
            showScreen(SCREEN_SNAKE);
            screen_snake.focus();
            // game score to zero
            score = 0;
            altScore(score);
            // initial snake
            snake = [];
            snake.push({x: 0, y: 15});
            snake_next_dir = 1;
            // food on canvas
            addFood();
            // activate canvas event
            canvas.onkeydown = function(evt) {
                changeDir(evt.keyCode);
            }
            mainLoop();
        }
        /* Key Inputs and Actions */
        /////////////////////////////////////////////////////////////
        let changeDir = function(key){
            // test key and switch direction
            switch(key) {
                case 37:    // left arrow
                    if (snake_dir !== 1)    // not right
                        snake_next_dir = 3; // then switch left
                    break;
                case 38:    // up arrow
                    if (snake_dir !== 2)    // not down
                        snake_next_dir = 0; // then switch up
                    break;
                case 39:    // right arrow
                    if (snake_dir !== 3)    // not left
                        snake_next_dir = 1; // then switch right
                    break;
                case 40:    // down arrow
                    if (snake_dir !== 0)    // not up
                        snake_next_dir = 2; // then switch down
                    break;
            }
        }
        /* Dot for Food or Snake part */
        /////////////////////////////////////////////////////////////
        let activeDot = function(x, y){
            ctx.fillStyle = "#FFFFFF";
            ctx.fillRect(x * BLOCK, y * BLOCK, BLOCK, BLOCK);
        }
        /* Random food placement */
        /////////////////////////////////////////////////////////////
        let addFood = function(){
            food.x = Math.floor(Math.random() * ((canvas.width / BLOCK) - 1));
            food.y = Math.floor(Math.random() * ((canvas.height / BLOCK) - 1));
            for(let i = 0; i < snake.length; i++){
                if(checkBlock(food.x, food.y, snake[i].x, snake[i].y)){
                    addFood();
                }
            }
        }
        /* Collision Detection */
        /////////////////////////////////////////////////////////////
        let checkBlock = function(x, y, _x, _y){
            return (x === _x && y === _y);
        }
        /* Update Score */
        /////////////////////////////////////////////////////////////
        let altScore = function(score_val){
            ele_score.innerHTML = String(score_val);
        }
        /////////////////////////////////////////////////////////////
        // Change the snake speed...
        // 150 = slow
        // 100 = normal
        // 50 = fast
        let setSnakeSpeed = function(speed_value){
            snake_speed = speed_value;
        }
        /////////////////////////////////////////////////////////////
        let setWall = function(wall_value){
            wall = wall_value;
            if(wall === 0){screen_snake.style.borderColor = "#606060";}
            if(wall === 1){screen_snake.style.borderColor = "#FFFFFF";}
        }
    })();
</script>



      </div>
    </main><link id="fa-stylesheet" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@latest/css/all.min.css">

<footer class="site-footer h-card">
  <data class="u-url" value="/student_2026/"></data>

  <div class="wrapper">

    <div class="footer-col-wrapper">
      <div class="footer-col">
      </div>
      <div class="footer-col">
        <p>Class of 2026</p>
      </div>
    </div>

    <div class="social-links"><ul class="social-media-list"><li>
    <a rel="me" href="" target="_blank" title="">
      <span class="grey fa-brands fa- fa-lg"></span>
    </a>
  </li><li>
    <a rel="me" href="" target="_blank" title="">
      <span class="grey fa-brands fa- fa-lg"></span>
    </a>
  </li><li>
    <a rel="me" href="" target="_blank" title="">
      <span class="grey fa-brands fa- fa-lg"></span>
    </a>
  </li>
  <li>
    <a href="https://open-coding-society.github.io/student_2026/feed.xml" target="_blank" title="Subscribe to syndication feed">
      <svg class="svg-icon grey" viewbox="0 0 16 16">
        <path d="M12.8 16C12.8 8.978 7.022 3.2 0 3.2V0c8.777 0 16 7.223 16 16h-3.2zM2.194
          11.61c1.21 0 2.195.985 2.195 2.196 0 1.21-.99 2.194-2.2 2.194C.98 16 0 15.017 0
          13.806c0-1.21.983-2.195 2.194-2.195zM10.606
          16h-3.11c0-4.113-3.383-7.497-7.496-7.497v-3.11c5.818 0 10.606 4.79 10.606 10.607z"
        />
      </svg>
    </a>
  </li>
</ul>
</div>

  </div>

</footer>
</body>

</html>



</html>

What This Does:

The base.html is acting like a smart router that switches the layout depending on your theme.


4. Theme Layout Includes

minimal_default.html

This layout is structured for Tailwind CSS based design — simple, clean, and flexible.

It uses Tailwind utility classes to handle spacing, sidebar, and responsive behavior.

It also defines a custom navigation logic (explained below).


minima_default.html

This layout uses the standard Minima theme structure.

It inherits SASS styling and includes default header, footer, and content areas as provided by Minima.

The navigation and structure are entirely based on Jekyll’s default Minima logic.


5. Navigation System

The navigation bar is different depending on the theme.


Minimal uses front matter to determine navigation links. Pages must explicitly opt-in to navigation.

Here is the logic:

<!-- NAVIGATION -->
<nav class="mb-10 border-b pb-4 flex flex-col gap-2 text-sm text-blue-600">
  
  
    <a href="/student_2026/blogs/" class="hover:underline">Blogs</a>
  
    <a href="/student_2026/documents/" class="hover:underline">Docs</a>
  
    <a href="/student_2026/github/readme" class="hover:underline">Readme</a>
  
    <a href="/student_2026/readme/" class="hover:underline">Readme</a>
  
    <a href="/student_2026/leaderboard/" class="hover:underline">Leaderboard</a>
  
    <a href="/student_2026/resource/" class="hover:underline">Resources</a>
  
    <a href="/student_2026/search/" class="hover:underline">Search</a>
  
</nav>

How to Add a Page to the Navigation Bar in Minimal

In your page’s front matter, add:

nav: true

This opt-in system gives you full control over what shows up in the sidebar.


Minima uses the _config.yml file to configure the navigation:

# Example _config.yml
header_pages:
  - about.md
  - contact.md
  - blog.md

You list the page filenames under header_pages, and they will be included in the top navbar automatically.

There is no need for nav: true front matter in Minima — the system is entirely controlled by _config.yml.


6. Styling

TailwindCSS for Minimal

When using the Minimal theme:

No Tailwind Typography plugin is used, to prevent interference with Markdown.


SASS Skins for Minima

When using the Minima theme:

Example snippet in custom-styles.scss:

// Custom color overrides
$primary-color: #1a202c;
$link-color: #3182ce;

Changes here allow you to apply a custom “skin” to Minima without disrupting its structure.


7. Important Notes