CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a Jekyll-based static personal tech blog and tools website. The site features blog posts about .NET, infrastructure, and security topics, plus interactive tools like an embedded YouTube player, DNS toolbox, and password generator.

Development Commands

Local Development

Using Docker with hot-reload (recommended for development):

.\local-preview.ps1

This checks for an existing Docker image, builds only if needed, and runs Jekyll with hot-reload, incremental builds, and LiveReload. The site will be available at http://localhost:4000 and auto-refreshes on file changes.

Force rebuild when dependencies change:

.\local-preview.ps1 -Rebuild

Using Docker (clean build each time):

.\run.ps1

Rebuilds the Docker image and runs the Jekyll server. Use this when you need a completely fresh build.

Native Jekyll:

bundle install
bundle exec jekyll serve --host 0.0.0.0

Architecture

Site Structure

Configuration

_config.yml defines:

Key Patterns

Layouts inheritance: Tools and posts extend the default layout, which includes navigation and footer with analytics.

SCSS compilation: Styles are included inline via Liquid templating (`$white: #ffffff; $home-page-boxes: #f8f8f8; $background-color: #F0F2F3; $border-color: #e9e9e9;

$cloud: #BBBBBB; $fossil: #AAAAAA; $shadow: #555555; $shadow-bar: #606060; $charcoal: #363636;

$azure: #4C9CF1;

$font-family-1: “Open Sans”; $font-family-2: “Open Sans Condensed”; $font-family-3: “Roboto”; $font-family-4: Helvetica, Arial, sans-serif;

$paragraph-font-family: $font-family-4; $paragraph-font-size: 14px; $paragraph-color: #626566; $paragraph-line-height: 1.9; $paragraph-letter-spacing: .01em;

$h1-font-size: 30px; $h2-font-size: 26px; $h3-font-size: 22px; $h4-font-size: 18px; $h5-font-size: 14px;

$h1-line-height: 1.8em; $h2-line-height: 1.35em; $h3-line-height: 1.35em; $h4-line-height: 1.32em; $h5-line-height: 1.35em;

$h1-margin: 0px 0 10px 0; $h2-margin: 48px 0 8px; $h3-margin: 48px 0 8px; $h4-margin: 48px 0 8px; $h5-margin: 48px 0 8px;

/**************************/

body { background: $background-color; color: $shadow; }

a { color: $azure; text-decoration: none; }

a:hover { color: $shadow; }

h1, h2, h3, h4, h5 { color: $charcoal; font-family: $font-family-1; text-transform: none; letter-spacing: 0px; font-weight: 300; }

h1 { font-size: $h1-font-size; line-height: $h1-line-height; margin: $h1-margin; }

h2 { font-size: $h2-font-size; line-height: $h2-line-height; margin: $h2-margin; }

h3 { font-size: $h3-font-size; line-height: $h3-line-height; margin: $h3-margin; }

h4 { font-size: $h4-font-size; line-height: $h4-line-height; margin: $h4-margin; font-weight: bold; }

h5 { font-size: $h5-font-size; line-height: $h5-line-height; margin: $h5-margin; font-weight: bold; }

p { font-family: $paragraph-font-family; font-size: $paragraph-font-size; line-height: $paragraph-line-height; letter-spacing: $paragraph-letter-spacing; color: $paragraph-color; margin: 0 0 14px 0; }

p, li, td { word-wrap: break-word; }

section { margin: 80px auto; max-width: 1080px; padding: 20px; position: relative; background-color: $white; border: 1px solid $border-color; }

pre { border: none; border-radius: 0; padding: 0; background-color: #f8f8f8; font-size: 11px; }

code { padding: 2px 4px 1px 4px; font-size: 75%; border-radius: 3px; }

.code pre {
padding: 0 0 0 8px; }

ol, ul { li { padding: 4px 0; } }

button { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }

blockquote { border-left: 5px solid #f1e594; background: #fbfada; }

/**************************/

.navbar { border-radius: 0; min-height: 76px; background: $charcoal; border: none; border-color: transparent;

.navbar-brand {
    text-transform: uppercase;
    font-weight: 300;
    font-style: normal;
    color: $fossil;
    font-family: $font-family-2;
    font-size: 28px;
    letter-spacing: 2px;
    margin-top: 13px;
}

.navbar-brand:hover {
    color: $white;
}
 
.navbar-collapse {
    border: none;
    border-color: transparent;
}

.navbar-toggle {
    margin-top: 20px;
    margin-right: 15px;
    border: none;

    &:hover,
    &:focus {
        background-color: $shadow;
    }

    .icon-bar {
        background-color: $white;
        height: 3px;
    }
}   }

#navbar-main {

margin-top: 23px;

.navbar-nav {

    .dropdown-menu {
        border-radius: 0;
    }

    li a {
        font-family: $font-family-4, $font-family-4;
        font-size: 11px;
        text-transform: uppercase;
        padding: 6px 8px 4px 8px;
        margin: 0 6px;
        border-bottom: solid 2px transparent;
        color: $fossil;
            
        .caret {
            margin-left: 6px;
            top: 0;
        }
    }

    li.open {
        a {
            background-color: $shadow;
            color: $white;
        }
    }

    li a:hover,
    li .active {
        color: $white;
        border-bottom: solid 2px $cloud;
    }

    li .dropdown-menu {
        right: 6px;
        background-color: $shadow;
        border: none;
        margin-top: -2px;

        a {
            text-transform: none;
            color: $fossil;
            font-size: 13px;
            font-family: $font-family-3, $font-family-4;
        }

        a:hover {
            border-bottom: solid 2px transparent;
            color: $white;
        }
    }
    
} }

/**************************/

#index {

h1 {
    margin-top: 20px;
    text-align: center;
}

p {
    text-align: center;
}

.posts {
    ul {
        list-style: none;
        margin: 0;
        padding-left: 0;
    }
    
    li {
        font-family: $font-family-3;
        color: #626566;
        line-height: 1.6;
        letter-spacing: .01em;
        border-bottom: 1px solid rgba(0,0,0,0.05);
        padding: 18px 0;
        position: relative;
        list-style-type: none;
        font-size: $paragraph-font-size;
    }
    
    li:last-child {
        border-bottom: none;
    }
    
    span {
        float: right;
        word-break: none;
        word-wrap: none;
        font-size: 12px;
        font-family: $font-family-4;
        margin-left: 6px;
    }  
}

.assets {
    background-color: $home-page-boxes;
    /*border: 1px solid #e9e9e9;*/
    border-radius: 4px;
    padding: 20px;

    ul { 
        margin: 0;
        list-style: none;
        list-style-type: none;
        padding: 0;
    }
    
    li {
        margin: 0 0 28px 0;

        h2 {
            margin: 0 0 8px 0;
        }

        h3 {
            margin: 0 0 8px 0;
        }

        p {
            text-align: left;
            margin: 0;
        }
    }

    li:last-child {
        margin: 0;
    }
} }

@import url(‘https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css’);

#youtube-embed {

font-family: 'Inter', sans-serif;
font-size: 12px;
text-align: center;

padding: 60px 0;

.container {
    text-align: center;
    width: 80%;
}

#videoId {
    font-size: 14px;
    padding: 10px;
    margin: 10px 0;
    width: 30%;
    color: #444;
}

button {
    font-size: 14px;
    padding: 10px 20px;
    cursor: pointer;
    color: #444;
}

iframe {
    margin-top: 20px;
    border: none;
    width: 100%;
    height: 485px;
    border-radius: 4px;
}

.video-link {
    color: #007BFF;
    font-size: 12px;
    display: none;
}

#youTubeLinkContainer {
    margin-top: 10px;
    font-size: 12px;
    display: none;
}

table {
    border-collapse: collapse;
    border-radius: 6px;
    border-style: hidden; /* hide standard table (collapsed) border */
    box-shadow: 0 0 0 1px #ddd; /* this draws the table border  */
}

td, th {
    background-color: #fafafa;
}

table tr:first-child td:first-child {
    border-top-left-radius: 10px;
}

table tr:first-child td:last-child {
    border-top-right-radius: 10px;
}

table tr:last-child td:first-child {
    border-bottom-left-radius: 10px;
}

table tr:last-child td:last-child {
    border-bottom-right-radius: 10px;
}

#playedVideos {
    margin-top: 20px;
    border-spacing: 0;
    display: none;
}

#playedVideos th,
#playedVideos td {
    padding: 4px 10px;
    text-align: left;
}

#playedVideos th {
    background-color: #f4f4f4;
}

.video-item a {
    color: #007BFF;
    text-decoration: none;
}

.video-item a:hover {
    text-decoration: underline;
}

.youtube-icon {
    font-size: 16px;
    color: #ff0000;
    margin-left: 5px;
}

.forget-all {
    margin-top: 10px;
    color: #ff0000;
    cursor: pointer;
    text-decoration: underline;
}

#recentlyPlayed {
    margin-top: 20px;
    font-weight: bold;
    font-size: 16px;
}

.notes-input, 
.group-input {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 8px;
    margin: 0;
    background-color: transparent;
    border: none;
} }

#dns-toolbox {

overflow-x: auto;
padding-bottom: 20px;
margin-bottom: 40px;

button {
    height: 27px;
    background-color: #f5f5f5;
    border: 1px solid #ccc;
    border-radius: 3px;
    color: #555555;
}

button:hover {
    background-color: #E9E9E9;
}

button:active {
    box-shadow: inset 0 1px 5px rgba(0,0,0,0.125);
}

.formFields input, textarea, select {
    display: inline-block;
    padding: 4px;
    margin-top: 9px;
    font-size: 13px;
    line-height: 18px;
    color: #555555;
    border: 1px solid #cccccc;
    border-radius: 3px;
}

.formFields input, textarea {
    min-width: 260px;
}

.formFields p { 
    margin: 0;
} }

#dns-toolbox-answers {

padding: 40px;
margin-top: 0;
position: relative;
display: none;

h1 {
    margin-top: 0;
}

h2 {
    margin: 28px 0 8px 0;
}

h2:first-child {
    margin: 0 0 8px 0;
}

table, 
td {	
    font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
    font-size: small;
    color: #626566;
    line-height: 1.6;
    letter-spacing: .01em;
}

table {
    margin: 0;
    padding: 0;
    border-spacing: 1px;
    border-collapse: separate;
    border: 1px solid #ddd;
}

td {
    border: 1px solid #ddd;
    padding: 2px 2px 2px 5px;	
    min-width: 70px;		
}

.loadingImage {
    text-align: center;
    position: absolute;
    top: 30px;
    left: 0;
    right: 0;
    margin: 0 auto;
}

#dnsResults {
    overflow: auto;
}

.header {
    background-color: #fafafa;
    border: 1px solid #eee;
    padding: 8px;
    border-radius: 2px;
}

.header p {
    font-family: monospace;
    font-size: smaller;
    margin: 0;
}

.header p:nth-child(3) {
    margin-top: 16px;
}

.ui-state-default {
    padding: 7px 17px;
    border: 1px solid #ddd;
    background-color: #fafafa;
}

.ui-state-active {
    background: #fff;
    border-bottom: 1px solid #fff;
}

.apiErrorMessage {
    background-color: #fafafa;
    padding: 12px 8px;
    border: 1px solid #ddd;
    text-align: center;
}

.childTable {
    border-spacing: 0;
    border: none;
}

.childTable td {
    padding-left: 10px;
    padding-right: 10px;
    border: none; /* important */
    border-right: 2px solid #ddd;
    min-width: 0;
}

.childTable td:first-child {
    padding-left: 2px;
}

.childTable td:last-child {
    padding-right: 10px;
    border: none;
} }

#code {

h2 {
    font-size: 18px;
    margin: 0;
}

li:first-child {
    margin: 35px 0 15px 0;
}

li {
    margin: 15px 0 15px 0;
} }

#disqus_thread { margin: 80px 0 0 0; padding: 16px; background-color: #f9f9f9; border-radius: 3px; }

#generate-passwords { #passwords { margin-bottom: 26px;

    ul {
        list-style: none;
        margin: 15px 0 0 0;
        padding: 0;
    }

    li {
        line-height: 1.8em;
    }

    .password {
        font-family: monospace;
        border: 1px solid #e0e0e0;
        background-color: #fcfcfc;
        margin: 0;
        padding: 2px 8px;
        border-top-left-radius: 2px;
        border-bottom-left-radius: 2px;
    }

    .length {
        font-family: Arial;
        font-size: x-small;
        color: #aaa;
        margin: 0 10px 0 0;

        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }

    .copyButton {
        border: none;
        padding: 0 6px 0 4px;
        margin: 1px 0 0 0;
        font-size: 8pt;
        height: 23px;
        font-family: $font-family-1;
        line-height: 2.3;
        text-transform: uppercase;
        border-top-right-radius: 2px;
        border-bottom-right-radius: 2px;
    }
}

#error {
    background-color: #fafafa;
    padding: 12px 8px;
    border: 1px solid #ddd;
    text-align: center;
    margin-bottom: 16px;
}

}

#about { img { padding: 70px; max-width: 100%; }

h1 {
    text-align: center;
    max-width: 745px;
    margin: 0 auto;
} }

#iis-server-headers { h1 { border-bottom: 1px solid $border-color; } }

#protocol-header-cheetsheets { h1 { border-bottom: 1px solid $border-color; }

hr {
    margin: 80px 0;
    size: 5px;
}

img {
    max-width: 100%;
}
   
table { 
   border: 1px solid $border-color;
}

th {
    background-color: $background-color;
}

th,
td { 
   border: 1px solid $border-color; 
   word-wrap: normal;
   padding: 4px;
   white-space: nowrap;
   vertical-align: top;
}
   
td:last-child {
    word-wrap: break-word;
    white-space: normal;
} }

#post { img { max-width: 100%; }

pre {
	margin: 0;
} }

#footer { blockquote { font-style: italic; font-size: small; margin: 0 auto; max-width: 1080px; text-align: right; padding-bottom: 25px; border: none; background: none; } }

/**************************/

.viewport-max-height { min-height:80vh; }

table.vcruntime {

margin: 0 0 14px 0;
padding: 0;
border-spacing: 1px;
border-collapse: separate;
border: 1px solid #ddd;

th {
	background-color: #fafafa;
	border: 1px solid #ddd;
	padding: 5px 10px 5px 10px;
	min-width: 100px;
}

td {
	border: 1px solid #ddd;
	padding: 3px 10px 3px 10px;
	min-width: 100px;
}

td:nth-child(1) {
	font-family: 'Consolas';
	font-size: 12px;
} }

/* notice this section is MAX width */ @media only screen and (max-width: 768px) {

#navbar-main {
    
    .navbar-nav {
        li,
        li:hover {
            .active,
            a:hover {
                border-bottom: solid 2px transparent;
            }

            .dropdown-menu {
                padding: 0;

                li {
                    padding-left: 16px;
                    border-bottom: 1px solid $shadow-bar;
                }
                
                li:last-child {
                    border-bottom: none;
                }
            }
        }

        li.open {
            a { 
                background-color: transparent;
            }
        }
    }
    
    li a:hover {
        border-bottom: none;
    }
} }

@media only screen and (min-width: 1200px) { .container { max-width: 970px; } }

@media only screen and (max-width: 1100px) { body { background: $white; }

section { 
    border: 0px transparent;
    margin: 0;
}

#footer {
    margin-top: 140px;
}

#protocol-header-cheetsheets {
    td {
        white-space: normal;
    }
}
    
#about {
    img {
        padding: 20px;
    }
} } `) and compiled using the `scssify` filter at build time.

URL redirects: Uses jekyll-redirect-from plugin for legacy URL support (e.g., /yt redirects to YouTube tool).

Interactive tools: Self-contained pages with embedded JavaScript. The YouTube tool uses localStorage to track recently played videos and sanitizes video IDs for security.

Creating Content

New Tool Page

Create a markdown file in tools/ directory with:

---
layout: tools
title: Tool Name
redirect_from: "/shorturl"
---

<div class="container">
  <!-- Tool HTML and JavaScript here -->
</div>

Dependencies

Notes