From 89151a9356fe145b46b8c4cffe8ff3fd4a23367d Mon Sep 17 00:00:00 2001 From: glenneth1 Date: Tue, 3 Dec 2024 05:01:12 +0300 Subject: [PATCH] Add Practical Scheme blog post and fix og:url formatting --- .../posts/2024-12-03-practical-scheme.html | 273 ++++++++++++++ content/posts/2024-12-03-practical-scheme.md | 171 +++++++++ .../posts/2024-12-03-practical-scheme.html | 273 ++++++++++++++ deploy/dist/styles.css | 2 +- deploy/index.html | 347 ++++++++++++++++++ deploy/js/md-to-html.js | 142 +++++-- dist/styles.css | 2 +- index.html | 23 ++ src/js/md-to-html.js | 142 +++++-- website-deploy.zip | Bin 71335 -> 77571 bytes 10 files changed, 1317 insertions(+), 58 deletions(-) create mode 100644 content/posts/2024-12-03-practical-scheme.html create mode 100644 content/posts/2024-12-03-practical-scheme.md create mode 100644 deploy/content/posts/2024-12-03-practical-scheme.html create mode 100644 deploy/index.html diff --git a/content/posts/2024-12-03-practical-scheme.html b/content/posts/2024-12-03-practical-scheme.html new file mode 100644 index 0000000..d766567 --- /dev/null +++ b/content/posts/2024-12-03-practical-scheme.html @@ -0,0 +1,273 @@ + + + + + + + + + + Beyond Theory: Building Practical Tools with Guile Scheme - Glenn Thompson + + + + + + + +
+
+
+
+ + + + + Back to Home + + +
+ +
+

Beyond Theory: Building Practical Tools with Guile Scheme

+
+ + + 5 min read + + By Glenn Thompson +
+
+ +
+

Beyond Theory: Building Practical Tools with Guile Scheme

+

Introduction

+

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world problems is where the most valuable lessons emerge. This post explores what I've learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way.

+

The Power of Modular Design

+

One of the most important lessons I learned was the value of modular design. Breaking down a program into focused, single-responsibility modules not only makes the code more maintainable but also helps in reasoning about the program's behavior. Here's how I structured stash:

+
(use-modules (ice-9 getopt-long)
+             (stash help)         ;; Help module
+             (stash colors)       ;; ANSI colors
+             (stash log)          ;; Logging module
+             (stash paths)        ;; Path handling module
+             (stash conflict)     ;; Conflict resolution module
+             (stash file-ops))    ;; File and symlink operations module
+
+

Each module has a specific responsibility:

+
    +
  • colors.scm: Handles ANSI color formatting for terminal output
  • +
  • conflict.scm: Manages conflict resolution when files already exist
  • +
  • file-ops.scm: Handles file system operations
  • +
  • help.scm: Provides usage information
  • +
  • log.scm: Manages logging operations
  • +
  • paths.scm: Handles path manipulation and normalization
  • +
+

Robust Path Handling

+

One of the first challenges in building a file management tool is handling paths correctly. Here's how I approached it:

+
(define (expand-home path)
+  "Expand ~ to the user's home directory."
+  (if (string-prefix? "~" path)
+      (string-append (getenv "HOME") (substring path 1))
+      path))
+
+(define (concat-path base path)
+  "Concatenate two paths, ensuring there are no double slashes."
+  (if (string-suffix? "/" base)
+      (string-append (string-drop-right base 1) "/" path)
+      (string-append base "/" path)))
+
+(define (ensure-config-path target-dir)
+  "Ensure that the target directory has .config appended, avoiding double slashes."
+  (let ((target-dir (expand-home target-dir)))
+    (if (string-suffix? "/" target-dir)
+        (set! target-dir (string-drop-right target-dir 1)))
+    (if (not (string-suffix? "/.config" target-dir))
+        (string-append target-dir "/.config")
+        target-dir)))
+
+

This approach ensures that:

+
    +
  • Home directory references (~) are properly expanded
  • +
  • Path concatenation doesn't create double slashes
  • +
  • Configuration paths are consistently structured
  • +
+

Interactive Conflict Resolution

+

Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system:

+
(define (prompt-user-for-action)
+  "Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c)."
+  (display (color-message 
+    "A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): " 
+    yellow-text))
+  (let ((response (read-line)))
+    (cond
+      ((string-ci=? response "o") 'overwrite)
+      ((string-ci=? response "s") 'skip)
+      ((string-ci=? response "c") 'cancel)
+      (else
+       (display "Invalid input. Please try again.\n")
+       (prompt-user-for-action)))))
+
+

This provides a user-friendly interface for resolving conflicts while maintaining data safety.

+

Logging for Debugging and Auditing

+

Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system:

+
(define (current-timestamp)
+  "Return the current date and time as a formatted string."
+  (let* ((time (current-time))
+         (seconds (time-second time)))
+    (strftime "%Y-%m-%d-%H-%M-%S" (localtime seconds))))
+
+(define (log-action message)
+  "Log an action with a timestamp to the stash.log file."
+  (let ((log-port (open-file "stash.log" "a")))
+    (display (color-message 
+      (string-append "[" (current-timestamp) "] " message) 
+      green-text) log-port)
+    (newline log-port)
+    (close-port log-port)))
+
+

This logging system:

+
    +
  • Timestamps each action
  • +
  • Uses color coding for better readability
  • +
  • Maintains a persistent log file
  • +
  • Properly handles file operations
  • +
+

File Operations with Safety

+

When dealing with file system operations, safety is paramount. Here's how I handle moving directories:

+
(define (move-source-to-target source-dir target-dir)
+  "Move the entire source directory to the target directory, ensuring .config in the target path."
+  (let* ((target-dir (ensure-config-path target-dir))
+         (source-dir (expand-home source-dir))
+         (source-name (basename source-dir))
+         (target-source-dir (concat-path target-dir source-name)))
+    (if (not (file-exists? target-dir))
+        (mkdir target-dir #o755))
+    (if (file-exists? target-source-dir)
+        (handle-conflict target-source-dir source-dir delete-directory log-action)
+        (begin
+          (rename-file source-dir target-source-dir)
+          (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir))
+          (log-action (format #f "Moved ~a to ~a" source-dir target-source-dir))))
+    target-source-dir))
+
+

This implementation:

+
    +
  • Ensures paths are properly formatted
  • +
  • Creates necessary directories
  • +
  • Handles conflicts gracefully
  • +
  • Logs all operations
  • +
  • Returns the new path for further operations
  • +
+

Lessons Learned

+

What Worked Well

+
    +
  1. Modular Design: Breaking the code into focused modules made it easier to maintain and test
  2. +
  3. Functional Approach: Using pure functions where possible made the code more predictable
  4. +
  5. Interactive Interface: Providing clear user prompts and colored output improved usability
  6. +
  7. Robust Logging: Detailed logging helped with debugging and understanding program flow
  8. +
+

Challenges Faced

+
    +
  1. Path Handling: Dealing with different path formats and edge cases required careful attention
  2. +
  3. Error States: Managing various error conditions while keeping the code clean
  4. +
  5. User Interface: Balancing between automation and user control
  6. +
  7. Documentation: Writing clear documentation that helps users understand the tool
  8. +
+

Moving Forward

+

Building stash has taught me that while functional programming principles are valuable, pragmatism is equally important. The key is finding the right balance between elegant functional code and practical solutions.

+

Resources

+
    +
  1. Guile Manual
  2. +
  3. My Previous Scheme Journey Post
  4. +
  5. System Crafters Community
  6. +
  7. Stash on Codeberg
  8. +
+

The code examples in this post are from my actual implementation of stash. Feel free to explore, use, and improve upon them!

+ +
+
+
+
+ + + \ No newline at end of file diff --git a/content/posts/2024-12-03-practical-scheme.md b/content/posts/2024-12-03-practical-scheme.md new file mode 100644 index 0000000..8f460a0 --- /dev/null +++ b/content/posts/2024-12-03-practical-scheme.md @@ -0,0 +1,171 @@ +--- +title: Beyond Theory: Building Practical Tools with Guile Scheme +author: Glenn Thompson +date: 2024-12-03 10:00 +tags: tech, guile, scheme, development, functional-programming +--- + +# Beyond Theory: Building Practical Tools with Guile Scheme + +## Introduction + +A few months ago, I shared my journey into learning Scheme through building `stash`, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world problems is where the most valuable lessons emerge. This post explores what I've learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way. + +## The Power of Modular Design + +One of the most important lessons I learned was the value of modular design. Breaking down a program into focused, single-responsibility modules not only makes the code more maintainable but also helps in reasoning about the program's behavior. Here's how I structured `stash`: + +```scheme +(use-modules (ice-9 getopt-long) + (stash help) ;; Help module + (stash colors) ;; ANSI colors + (stash log) ;; Logging module + (stash paths) ;; Path handling module + (stash conflict) ;; Conflict resolution module + (stash file-ops)) ;; File and symlink operations module +``` + +Each module has a specific responsibility: +- `colors.scm`: Handles ANSI color formatting for terminal output +- `conflict.scm`: Manages conflict resolution when files already exist +- `file-ops.scm`: Handles file system operations +- `help.scm`: Provides usage information +- `log.scm`: Manages logging operations +- `paths.scm`: Handles path manipulation and normalization + +## Robust Path Handling + +One of the first challenges in building a file management tool is handling paths correctly. Here's how I approached it: + +```scheme +(define (expand-home path) + "Expand ~ to the user's home directory." + (if (string-prefix? "~" path) + (string-append (getenv "HOME") (substring path 1)) + path)) + +(define (concat-path base path) + "Concatenate two paths, ensuring there are no double slashes." + (if (string-suffix? "/" base) + (string-append (string-drop-right base 1) "/" path) + (string-append base "/" path))) + +(define (ensure-config-path target-dir) + "Ensure that the target directory has .config appended, avoiding double slashes." + (let ((target-dir (expand-home target-dir))) + (if (string-suffix? "/" target-dir) + (set! target-dir (string-drop-right target-dir 1))) + (if (not (string-suffix? "/.config" target-dir)) + (string-append target-dir "/.config") + target-dir))) +``` + +This approach ensures that: +- Home directory references (`~`) are properly expanded +- Path concatenation doesn't create double slashes +- Configuration paths are consistently structured + +## Interactive Conflict Resolution + +Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system: + +```scheme +(define (prompt-user-for-action) + "Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c)." + (display (color-message + "A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): " + yellow-text)) + (let ((response (read-line))) + (cond + ((string-ci=? response "o") 'overwrite) + ((string-ci=? response "s") 'skip) + ((string-ci=? response "c") 'cancel) + (else + (display "Invalid input. Please try again.\n") + (prompt-user-for-action))))) +``` + +This provides a user-friendly interface for resolving conflicts while maintaining data safety. + +## Logging for Debugging and Auditing + +Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system: + +```scheme +(define (current-timestamp) + "Return the current date and time as a formatted string." + (let* ((time (current-time)) + (seconds (time-second time))) + (strftime "%Y-%m-%d-%H-%M-%S" (localtime seconds)))) + +(define (log-action message) + "Log an action with a timestamp to the stash.log file." + (let ((log-port (open-file "stash.log" "a"))) + (display (color-message + (string-append "[" (current-timestamp) "] " message) + green-text) log-port) + (newline log-port) + (close-port log-port))) +``` + +This logging system: +- Timestamps each action +- Uses color coding for better readability +- Maintains a persistent log file +- Properly handles file operations + +## File Operations with Safety + +When dealing with file system operations, safety is paramount. Here's how I handle moving directories: + +```scheme +(define (move-source-to-target source-dir target-dir) + "Move the entire source directory to the target directory, ensuring .config in the target path." + (let* ((target-dir (ensure-config-path target-dir)) + (source-dir (expand-home source-dir)) + (source-name (basename source-dir)) + (target-source-dir (concat-path target-dir source-name))) + (if (not (file-exists? target-dir)) + (mkdir target-dir #o755)) + (if (file-exists? target-source-dir) + (handle-conflict target-source-dir source-dir delete-directory log-action) + (begin + (rename-file source-dir target-source-dir) + (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir)) + (log-action (format #f "Moved ~a to ~a" source-dir target-source-dir)))) + target-source-dir)) +``` + +This implementation: +- Ensures paths are properly formatted +- Creates necessary directories +- Handles conflicts gracefully +- Logs all operations +- Returns the new path for further operations + +## Lessons Learned + +### What Worked Well +1. **Modular Design**: Breaking the code into focused modules made it easier to maintain and test +2. **Functional Approach**: Using pure functions where possible made the code more predictable +3. **Interactive Interface**: Providing clear user prompts and colored output improved usability +4. **Robust Logging**: Detailed logging helped with debugging and understanding program flow + +### Challenges Faced +1. **Path Handling**: Dealing with different path formats and edge cases required careful attention +2. **Error States**: Managing various error conditions while keeping the code clean +3. **User Interface**: Balancing between automation and user control +4. **Documentation**: Writing clear documentation that helps users understand the tool + +## Moving Forward + +Building `stash` has taught me that while functional programming principles are valuable, pragmatism is equally important. The key is finding the right balance between elegant functional code and practical solutions. + +## Resources + +1. [Guile Manual](https://www.gnu.org/software/guile/manual/) +2. [My Previous Scheme Journey Post](/content/posts/scheme-journey.html) +3. [System Crafters Community](https://systemcrafters.net/community) +4. [Stash on Codeberg](https://codeberg.org/glenneth/stash) + +The code examples in this post are from my actual implementation of `stash`. Feel free to explore, use, and improve upon them! diff --git a/deploy/content/posts/2024-12-03-practical-scheme.html b/deploy/content/posts/2024-12-03-practical-scheme.html new file mode 100644 index 0000000..d766567 --- /dev/null +++ b/deploy/content/posts/2024-12-03-practical-scheme.html @@ -0,0 +1,273 @@ + + + + + + + + + + Beyond Theory: Building Practical Tools with Guile Scheme - Glenn Thompson + + + + + + + +
+
+
+
+ + + + + Back to Home + + +
+ +
+

Beyond Theory: Building Practical Tools with Guile Scheme

+
+ + + 5 min read + + By Glenn Thompson +
+
+ +
+

Beyond Theory: Building Practical Tools with Guile Scheme

+

Introduction

+

A few months ago, I shared my journey into learning Scheme through building stash, a symlink manager. Since then, I've discovered that the gap between learning Scheme and applying it to real-world problems is where the most valuable lessons emerge. This post explores what I've learned about building practical tools with Guile Scheme, sharing both successes and challenges along the way.

+

The Power of Modular Design

+

One of the most important lessons I learned was the value of modular design. Breaking down a program into focused, single-responsibility modules not only makes the code more maintainable but also helps in reasoning about the program's behavior. Here's how I structured stash:

+
(use-modules (ice-9 getopt-long)
+             (stash help)         ;; Help module
+             (stash colors)       ;; ANSI colors
+             (stash log)          ;; Logging module
+             (stash paths)        ;; Path handling module
+             (stash conflict)     ;; Conflict resolution module
+             (stash file-ops))    ;; File and symlink operations module
+
+

Each module has a specific responsibility:

+
    +
  • colors.scm: Handles ANSI color formatting for terminal output
  • +
  • conflict.scm: Manages conflict resolution when files already exist
  • +
  • file-ops.scm: Handles file system operations
  • +
  • help.scm: Provides usage information
  • +
  • log.scm: Manages logging operations
  • +
  • paths.scm: Handles path manipulation and normalization
  • +
+

Robust Path Handling

+

One of the first challenges in building a file management tool is handling paths correctly. Here's how I approached it:

+
(define (expand-home path)
+  "Expand ~ to the user's home directory."
+  (if (string-prefix? "~" path)
+      (string-append (getenv "HOME") (substring path 1))
+      path))
+
+(define (concat-path base path)
+  "Concatenate two paths, ensuring there are no double slashes."
+  (if (string-suffix? "/" base)
+      (string-append (string-drop-right base 1) "/" path)
+      (string-append base "/" path)))
+
+(define (ensure-config-path target-dir)
+  "Ensure that the target directory has .config appended, avoiding double slashes."
+  (let ((target-dir (expand-home target-dir)))
+    (if (string-suffix? "/" target-dir)
+        (set! target-dir (string-drop-right target-dir 1)))
+    (if (not (string-suffix? "/.config" target-dir))
+        (string-append target-dir "/.config")
+        target-dir)))
+
+

This approach ensures that:

+
    +
  • Home directory references (~) are properly expanded
  • +
  • Path concatenation doesn't create double slashes
  • +
  • Configuration paths are consistently structured
  • +
+

Interactive Conflict Resolution

+

Real-world tools often need to handle conflicts. I implemented an interactive conflict resolution system:

+
(define (prompt-user-for-action)
+  "Prompt the user to decide how to handle a conflict: overwrite (o), skip (s), or cancel (c)."
+  (display (color-message 
+    "A conflict was detected. Choose action - Overwrite (o), Skip (s), or Cancel (c): " 
+    yellow-text))
+  (let ((response (read-line)))
+    (cond
+      ((string-ci=? response "o") 'overwrite)
+      ((string-ci=? response "s") 'skip)
+      ((string-ci=? response "c") 'cancel)
+      (else
+       (display "Invalid input. Please try again.\n")
+       (prompt-user-for-action)))))
+
+

This provides a user-friendly interface for resolving conflicts while maintaining data safety.

+

Logging for Debugging and Auditing

+

Proper logging is crucial for debugging and auditing. I implemented a simple but effective logging system:

+
(define (current-timestamp)
+  "Return the current date and time as a formatted string."
+  (let* ((time (current-time))
+         (seconds (time-second time)))
+    (strftime "%Y-%m-%d-%H-%M-%S" (localtime seconds))))
+
+(define (log-action message)
+  "Log an action with a timestamp to the stash.log file."
+  (let ((log-port (open-file "stash.log" "a")))
+    (display (color-message 
+      (string-append "[" (current-timestamp) "] " message) 
+      green-text) log-port)
+    (newline log-port)
+    (close-port log-port)))
+
+

This logging system:

+
    +
  • Timestamps each action
  • +
  • Uses color coding for better readability
  • +
  • Maintains a persistent log file
  • +
  • Properly handles file operations
  • +
+

File Operations with Safety

+

When dealing with file system operations, safety is paramount. Here's how I handle moving directories:

+
(define (move-source-to-target source-dir target-dir)
+  "Move the entire source directory to the target directory, ensuring .config in the target path."
+  (let* ((target-dir (ensure-config-path target-dir))
+         (source-dir (expand-home source-dir))
+         (source-name (basename source-dir))
+         (target-source-dir (concat-path target-dir source-name)))
+    (if (not (file-exists? target-dir))
+        (mkdir target-dir #o755))
+    (if (file-exists? target-source-dir)
+        (handle-conflict target-source-dir source-dir delete-directory log-action)
+        (begin
+          (rename-file source-dir target-source-dir)
+          (display (format #f "Moved ~a to ~a\n" source-dir target-source-dir))
+          (log-action (format #f "Moved ~a to ~a" source-dir target-source-dir))))
+    target-source-dir))
+
+

This implementation:

+
    +
  • Ensures paths are properly formatted
  • +
  • Creates necessary directories
  • +
  • Handles conflicts gracefully
  • +
  • Logs all operations
  • +
  • Returns the new path for further operations
  • +
+

Lessons Learned

+

What Worked Well

+
    +
  1. Modular Design: Breaking the code into focused modules made it easier to maintain and test
  2. +
  3. Functional Approach: Using pure functions where possible made the code more predictable
  4. +
  5. Interactive Interface: Providing clear user prompts and colored output improved usability
  6. +
  7. Robust Logging: Detailed logging helped with debugging and understanding program flow
  8. +
+

Challenges Faced

+
    +
  1. Path Handling: Dealing with different path formats and edge cases required careful attention
  2. +
  3. Error States: Managing various error conditions while keeping the code clean
  4. +
  5. User Interface: Balancing between automation and user control
  6. +
  7. Documentation: Writing clear documentation that helps users understand the tool
  8. +
+

Moving Forward

+

Building stash has taught me that while functional programming principles are valuable, pragmatism is equally important. The key is finding the right balance between elegant functional code and practical solutions.

+

Resources

+
    +
  1. Guile Manual
  2. +
  3. My Previous Scheme Journey Post
  4. +
  5. System Crafters Community
  6. +
  7. Stash on Codeberg
  8. +
+

The code examples in this post are from my actual implementation of stash. Feel free to explore, use, and improve upon them!

+ +
+
+
+
+ + + \ No newline at end of file diff --git a/deploy/dist/styles.css b/deploy/dist/styles.css index 4245ab3..09802e2 100644 --- a/deploy/dist/styles.css +++ b/deploy/dist/styles.css @@ -1 +1 @@ -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{scroll-behavior:smooth}body{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:Merriweather,serif}.nav-link{display:inline-flex;align-items:center;padding-left:.25rem;padding-right:.25rem;padding-top:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.nav-link:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.static{position:static}.fixed{position:fixed}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-16{height:4rem}.h-5{height:1.25rem}.w-5{width:1.25rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-7xl{max-width:80rem}.max-w-none{max-width:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.space-x-6>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1.5rem*var(--tw-space-x-reverse));margin-left:calc(1.5rem*(1 - var(--tw-space-x-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-accent-blue{--tw-border-opacity:1;border-color:rgb(130 170 255/var(--tw-border-opacity,1))}.border-palenight-400\/20{border-color:rgba(68,75,106,.2)}.bg-base-bg{--tw-bg-opacity:1;background-color:rgb(41 45 62/var(--tw-bg-opacity,1))}.bg-base-darker{--tw-bg-opacity:1;background-color:rgb(36 40 55/var(--tw-bg-opacity,1))}.bg-base-darker\/80{background-color:rgba(36,40,55,.8)}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-16{padding-bottom:4rem}.pt-24{padding-top:6rem}.text-center{text-align:center}.font-sans{font-family:Inter,system-ui,sans-serif}.font-serif{font-family:Merriweather,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.leading-8{line-height:2rem}.tracking-tight{letter-spacing:-.025em}.text-accent-blue{--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1))}.text-accent-cyan{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.text-accent-purple{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.text-accent-yellow{--tw-text-opacity:1;color:rgb(255 203 107/var(--tw-text-opacity,1))}.text-palenight-100{--tw-text-opacity:1;color:rgb(169 184 232/var(--tw-text-opacity,1))}.text-palenight-200{--tw-text-opacity:1;color:rgb(130 139 184/var(--tw-text-opacity,1))}.text-palenight-300{--tw-text-opacity:1;color:rgb(103 110 149/var(--tw-text-opacity,1))}.text-palenight-50{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.prose{max-width:none}.prose img{border-radius:.5rem;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:border-accent-purple\/40:hover{border-color:rgba(199,146,234,.4)}.hover\:bg-accent-blue:hover{--tw-bg-opacity:1;background-color:rgb(130 170 255/var(--tw-bg-opacity,1))}.hover\:text-accent-cyan:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.hover\:text-base-bg:hover{--tw-text-opacity:1;color:rgb(41 45 62/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:ml-6{margin-left:1.5rem}.sm\:flex{display:flex}.sm\:space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem*var(--tw-space-x-reverse));margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)))}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-24{padding-bottom:6rem}.sm\:pt-32{padding-top:8rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}} \ No newline at end of file +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{scroll-behavior:smooth}body{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:Merriweather,serif}.nav-link{display:inline-flex;align-items:center;padding-left:.25rem;padding-right:.25rem;padding-top:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.nav-link:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.static{position:static}.fixed{position:fixed}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-16{height:4rem}.h-5{height:1.25rem}.w-5{width:1.25rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-none{max-width:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-accent-blue{--tw-border-opacity:1;border-color:rgb(130 170 255/var(--tw-border-opacity,1))}.border-palenight-400\/20{border-color:rgba(68,75,106,.2)}.bg-base-bg{--tw-bg-opacity:1;background-color:rgb(41 45 62/var(--tw-bg-opacity,1))}.bg-base-darker{--tw-bg-opacity:1;background-color:rgb(36 40 55/var(--tw-bg-opacity,1))}.bg-base-darker\/80{background-color:rgba(36,40,55,.8)}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-16{padding-bottom:4rem}.pt-24{padding-top:6rem}.text-center{text-align:center}.font-serif{font-family:Merriweather,serif}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.leading-8{line-height:2rem}.tracking-tight{letter-spacing:-.025em}.text-accent-blue{--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1))}.text-accent-cyan{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.text-accent-purple{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.text-accent-yellow{--tw-text-opacity:1;color:rgb(255 203 107/var(--tw-text-opacity,1))}.text-palenight-100{--tw-text-opacity:1;color:rgb(169 184 232/var(--tw-text-opacity,1))}.text-palenight-200{--tw-text-opacity:1;color:rgb(130 139 184/var(--tw-text-opacity,1))}.text-palenight-300{--tw-text-opacity:1;color:rgb(103 110 149/var(--tw-text-opacity,1))}.text-palenight-50{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.prose{max-width:none}.prose img{border-radius:.5rem;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:border-accent-purple\/40:hover{border-color:rgba(199,146,234,.4)}.hover\:bg-accent-blue:hover{--tw-bg-opacity:1;background-color:rgb(130 170 255/var(--tw-bg-opacity,1))}.hover\:text-accent-cyan:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.hover\:text-accent-purple:hover{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.hover\:text-base-bg:hover{--tw-text-opacity:1;color:rgb(41 45 62/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:ml-6{margin-left:1.5rem}.sm\:flex{display:flex}.sm\:space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem*var(--tw-space-x-reverse));margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)))}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-24{padding-bottom:6rem}.sm\:pt-32{padding-top:8rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}} \ No newline at end of file diff --git a/deploy/index.html b/deploy/index.html new file mode 100644 index 0000000..a55d877 --- /dev/null +++ b/deploy/index.html @@ -0,0 +1,347 @@ + + + + + + + + + + + Glenn Thompson - Technology, Engineering & Travel + + + + + + + + +
+ +
+
+
+

+ Technology, Engineering & Travel +

+

+ Exploring the intersection of electrical engineering, technology, and cultural experiences from + two decades in the Middle East. +

+
+
+
+ + +
+
+

Blog Posts

+
+ + + + + + + + + + + + + + +
+
+
+ + +
+
+

Projects

+
+ +
+

Personal Website

+

A modern, responsive personal website built with HTML, + TailwindCSS, and JavaScript. Features a dark theme and blog functionality.

+
+ HTML + TailwindCSS + JavaScript +
+ View Source → +
+ + +
+

Scheme Symlink Manager

+

A command-line tool built with Guile Scheme for managing + symbolic links in Unix-like systems. Simplifies dotfile management.

+
+ Scheme + Guile + CLI +
+ Coming Soon + → +
+ + +
+
+

More projects coming soon!

+

Stay tuned...

+
+
+
+
+
+ + +
+
+
+
+

About Me

+

+ With over 20 years in the electrical engineering field, I've had the privilege of working on + groundbreaking projects across the Middle East. My journey has been marked by continuous + learning, cultural exploration, and technological innovation. +

+

+ Beyond my professional work, I'm passionate about technology, particularly static site + generation, Scheme programming, and tools like GNU Guix and Haunt. This blog is where I + share my experiences, insights, and the lessons learned along the way. +

+
+
+

Areas of Focus

+
    +
  • + + + + Electrical Engineering +
  • +
  • + + + + Static Site Generation +
  • +
  • + + + + Scheme Programming +
  • +
  • + + + + Middle Eastern Culture +
  • +
+
+
+
+
+ + +
+
+
+

Get in Touch

+

+ Interested in connecting? Feel free to reach out for discussions about technology, engineering, + or sharing travel stories. +

+ + Send a Message + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/deploy/js/md-to-html.js b/deploy/js/md-to-html.js index 45aa27e..d21ea0f 100644 --- a/deploy/js/md-to-html.js +++ b/deploy/js/md-to-html.js @@ -40,16 +40,30 @@ function convertMarkdownToHtml(mdFilePath) { const metadata = {}; const content = markdown.replace(/^---\n([\s\S]*?)\n---\n/, (_, frontMatter) => { frontMatter.split('\n').forEach(line => { - const [key, value] = line.split(': '); - if (key && value) { - metadata[key.trim()] = value.trim(); + const [key, ...valueParts] = line.split(':'); + if (key && valueParts.length > 0) { + metadata[key.trim()] = valueParts.join(':').trim(); } }); return ''; }); + // Configure marked options for proper heading rendering + const markedOptions = { + headerIds: true, + gfm: true, + breaks: true, + pedantic: false, + smartLists: true, + smartypants: true + }; + // Convert markdown to HTML - const articleContent = marked.parse(content, options); + const articleContent = marked.parse(content, markedOptions); + + // Calculate read time (rough estimate: 200 words per minute) + const wordCount = content.trim().split(/\s+/).length; + const readTime = Math.ceil(wordCount / 200); // Create full HTML document const html = ` @@ -57,36 +71,108 @@ function convertMarkdownToHtml(mdFilePath) { + + + + ${metadata.title || 'Blog Post'} - Glenn Thompson - - - - + + + - -
-
+ + -
-
-
-

${metadata.title || 'Blog Post'}

-
- ${metadata.category || 'Blog'} - - +
+
+
+
+ + + + + Back to Home + +
- ${articleContent} -
+ +
+

${metadata.title || 'Blog Post'}

+
+ + + ${readTime} min read + + By ${metadata.author || 'Glenn Thompson'} +
+
+ +
+ ${articleContent} +
+
${footer}`; diff --git a/dist/styles.css b/dist/styles.css index ae53320..09802e2 100644 --- a/dist/styles.css +++ b/dist/styles.css @@ -1 +1 @@ -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{scroll-behavior:smooth}body{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:Merriweather,serif}.nav-link{display:inline-flex;align-items:center;padding-left:.25rem;padding-right:.25rem;padding-top:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.nav-link:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.static{position:static}.fixed{position:fixed}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-16{height:4rem}.h-5{height:1.25rem}.w-5{width:1.25rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-7xl{max-width:80rem}.max-w-none{max-width:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.space-x-6>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1.5rem*var(--tw-space-x-reverse));margin-left:calc(1.5rem*(1 - var(--tw-space-x-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-accent-blue{--tw-border-opacity:1;border-color:rgb(130 170 255/var(--tw-border-opacity,1))}.border-palenight-400\/20{border-color:rgba(68,75,106,.2)}.bg-base-bg{--tw-bg-opacity:1;background-color:rgb(41 45 62/var(--tw-bg-opacity,1))}.bg-base-darker{--tw-bg-opacity:1;background-color:rgb(36 40 55/var(--tw-bg-opacity,1))}.bg-base-darker\/80{background-color:rgba(36,40,55,.8)}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-16{padding-bottom:4rem}.pt-24{padding-top:6rem}.text-center{text-align:center}.font-sans{font-family:Inter,system-ui,sans-serif}.font-serif{font-family:Merriweather,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.leading-8{line-height:2rem}.tracking-tight{letter-spacing:-.025em}.text-accent-blue{--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1))}.text-accent-cyan{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.text-accent-purple{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.text-accent-yellow{--tw-text-opacity:1;color:rgb(255 203 107/var(--tw-text-opacity,1))}.text-palenight-100{--tw-text-opacity:1;color:rgb(169 184 232/var(--tw-text-opacity,1))}.text-palenight-200{--tw-text-opacity:1;color:rgb(130 139 184/var(--tw-text-opacity,1))}.text-palenight-300{--tw-text-opacity:1;color:rgb(103 110 149/var(--tw-text-opacity,1))}.text-palenight-50{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.prose{max-width:none}.prose img{border-radius:.5rem;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:border-accent-purple\/40:hover{border-color:rgba(199,146,234,.4)}.hover\:bg-accent-blue:hover{--tw-bg-opacity:1;background-color:rgb(130 170 255/var(--tw-bg-opacity,1))}.hover\:text-accent-cyan:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.hover\:text-accent-purple:hover{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.hover\:text-base-bg:hover{--tw-text-opacity:1;color:rgb(41 45 62/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:ml-6{margin-left:1.5rem}.sm\:flex{display:flex}.sm\:space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem*var(--tw-space-x-reverse));margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)))}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-24{padding-bottom:6rem}.sm\:pt-32{padding-top:8rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}} \ No newline at end of file +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.15 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{scroll-behavior:smooth}body{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{font-family:Merriweather,serif}.nav-link{display:inline-flex;align-items:center;padding-left:.25rem;padding-right:.25rem;padding-top:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.nav-link:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.static{position:static}.fixed{position:fixed}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-16{height:4rem}.h-5{height:1.25rem}.w-5{width:1.25rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-none{max-width:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-accent-blue{--tw-border-opacity:1;border-color:rgb(130 170 255/var(--tw-border-opacity,1))}.border-palenight-400\/20{border-color:rgba(68,75,106,.2)}.bg-base-bg{--tw-bg-opacity:1;background-color:rgb(41 45 62/var(--tw-bg-opacity,1))}.bg-base-darker{--tw-bg-opacity:1;background-color:rgb(36 40 55/var(--tw-bg-opacity,1))}.bg-base-darker\/80{background-color:rgba(36,40,55,.8)}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-16{padding-bottom:4rem}.pt-24{padding-top:6rem}.text-center{text-align:center}.font-serif{font-family:Merriweather,serif}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.leading-8{line-height:2rem}.tracking-tight{letter-spacing:-.025em}.text-accent-blue{--tw-text-opacity:1;color:rgb(130 170 255/var(--tw-text-opacity,1))}.text-accent-cyan{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.text-accent-purple{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.text-accent-yellow{--tw-text-opacity:1;color:rgb(255 203 107/var(--tw-text-opacity,1))}.text-palenight-100{--tw-text-opacity:1;color:rgb(169 184 232/var(--tw-text-opacity,1))}.text-palenight-200{--tw-text-opacity:1;color:rgb(130 139 184/var(--tw-text-opacity,1))}.text-palenight-300{--tw-text-opacity:1;color:rgb(103 110 149/var(--tw-text-opacity,1))}.text-palenight-50{--tw-text-opacity:1;color:rgb(200 211 245/var(--tw-text-opacity,1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.prose{max-width:none}.prose img{border-radius:.5rem;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:border-accent-purple\/40:hover{border-color:rgba(199,146,234,.4)}.hover\:bg-accent-blue:hover{--tw-bg-opacity:1;background-color:rgb(130 170 255/var(--tw-bg-opacity,1))}.hover\:text-accent-cyan:hover{--tw-text-opacity:1;color:rgb(137 221 255/var(--tw-text-opacity,1))}.hover\:text-accent-purple:hover{--tw-text-opacity:1;color:rgb(199 146 234/var(--tw-text-opacity,1))}.hover\:text-base-bg:hover{--tw-text-opacity:1;color:rgb(41 45 62/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:ml-6{margin-left:1.5rem}.sm\:flex{display:flex}.sm\:space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(2rem*var(--tw-space-x-reverse));margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)))}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-24{padding-bottom:6rem}.sm\:pt-32{padding-top:8rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}} \ No newline at end of file diff --git a/index.html b/index.html index 628dac4..a55d877 100644 --- a/index.html +++ b/index.html @@ -57,6 +57,29 @@

Blog Posts

+ +
diff --git a/src/js/md-to-html.js b/src/js/md-to-html.js index 45aa27e..702d969 100644 --- a/src/js/md-to-html.js +++ b/src/js/md-to-html.js @@ -40,16 +40,30 @@ function convertMarkdownToHtml(mdFilePath) { const metadata = {}; const content = markdown.replace(/^---\n([\s\S]*?)\n---\n/, (_, frontMatter) => { frontMatter.split('\n').forEach(line => { - const [key, value] = line.split(': '); - if (key && value) { - metadata[key.trim()] = value.trim(); + const [key, ...valueParts] = line.split(':'); + if (key && valueParts.length > 0) { + metadata[key.trim()] = valueParts.join(':').trim(); } }); return ''; }); + // Configure marked options for proper heading rendering + const markedOptions = { + headerIds: true, + gfm: true, + breaks: true, + pedantic: false, + smartLists: true, + smartypants: true + }; + // Convert markdown to HTML - const articleContent = marked.parse(content, options); + const articleContent = marked.parse(content, markedOptions); + + // Calculate read time (rough estimate: 200 words per minute) + const wordCount = content.trim().split(/\s+/).length; + const readTime = Math.ceil(wordCount / 200); // Create full HTML document const html = ` @@ -57,36 +71,108 @@ function convertMarkdownToHtml(mdFilePath) { + + + + ${metadata.title || 'Blog Post'} - Glenn Thompson - - - - + + + - -
-
+
+ -
-
-
-

${metadata.title || 'Blog Post'}

-
- ${metadata.category || 'Blog'} - - +
+
+
+
+ + + + + Back to Home + +
- ${articleContent} -
+ +
+

${metadata.title || 'Blog Post'}

+
+ + + ${readTime} min read + + By ${metadata.author || 'Glenn Thompson'} +
+
+ +
+ ${articleContent} +
+
${footer}`; diff --git a/website-deploy.zip b/website-deploy.zip index d10fd242120ca35639edca5a515f3ffbc3e1ccdd..0748bf8a7792102d76d5fafe30d4daaec95f6622 100644 GIT binary patch delta 15026 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≪2Z!bq>J_5y?&~ds)dzZrm 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 delta 8751 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