jekyll-theme-manpage 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +193 -0
  4. data/_includes/comments.html +21 -0
  5. data/_includes/fun_facts.html +9 -0
  6. data/_includes/head-custom-google-analytics.html +10 -0
  7. data/_includes/head-custom.html +64 -0
  8. data/_includes/read_time.html +11 -0
  9. data/_includes/skin.html +4 -0
  10. data/_includes/social_links.html +8 -0
  11. data/_layouts/default.html +63 -0
  12. data/_layouts/home.html +19 -0
  13. data/_layouts/post.html +29 -0
  14. data/_layouts/writing.html +173 -0
  15. data/_sass/jekyll-theme-manpage.scss +825 -0
  16. data/_sass/normalize.scss +426 -0
  17. data/_sass/skins/_dracula.scss +118 -0
  18. data/_sass/skins/_github.scss +118 -0
  19. data/_sass/skins/_monokai.scss +118 -0
  20. data/_sass/skins/_nord.scss +118 -0
  21. data/_sass/skins/_purple.scss +118 -0
  22. data/_sass/skins/_tomorrow.scss +118 -0
  23. data/_sass/variables.scss +61 -0
  24. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_AMS-Regular.ttf +0 -0
  25. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_AMS-Regular.woff +0 -0
  26. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  27. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  28. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  29. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  30. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  31. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  32. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  33. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  34. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  35. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  36. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  37. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  38. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  39. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Bold.ttf +0 -0
  40. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Bold.woff +0 -0
  41. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Bold.woff2 +0 -0
  42. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  43. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  44. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  45. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Italic.ttf +0 -0
  46. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Italic.woff +0 -0
  47. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Italic.woff2 +0 -0
  48. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Regular.ttf +0 -0
  49. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Regular.woff +0 -0
  50. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Main-Regular.woff2 +0 -0
  51. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  52. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  53. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  54. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Math-Italic.ttf +0 -0
  55. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Math-Italic.woff +0 -0
  56. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Math-Italic.woff2 +0 -0
  57. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  58. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  59. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  60. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  61. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  62. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  63. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  64. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  65. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  66. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Script-Regular.ttf +0 -0
  67. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Script-Regular.woff +0 -0
  68. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Script-Regular.woff2 +0 -0
  69. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size1-Regular.ttf +0 -0
  70. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size1-Regular.woff +0 -0
  71. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  72. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size2-Regular.ttf +0 -0
  73. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size2-Regular.woff +0 -0
  74. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  75. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size3-Regular.ttf +0 -0
  76. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size3-Regular.woff +0 -0
  77. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  78. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size4-Regular.ttf +0 -0
  79. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size4-Regular.woff +0 -0
  80. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  81. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  82. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  83. data/assets/css/plugins/katex.0.11.1/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  84. data/assets/css/plugins/katex.0.11.1/katex.min.css +1 -0
  85. data/assets/css/style.scss +7 -0
  86. data/assets/images/favicon.svg +3 -0
  87. data/assets/images/profile.png +0 -0
  88. data/assets/js/theme-switcher.js +47 -0
  89. data/assets/readme/preview.png +0 -0
  90. data/assets/themes/dracula.png +0 -0
  91. data/assets/themes/dracula_dark.png +0 -0
  92. data/assets/themes/github.png +0 -0
  93. data/assets/themes/github_dark.png +0 -0
  94. data/assets/themes/monokai.png +0 -0
  95. data/assets/themes/monokai_dark.png +0 -0
  96. data/assets/themes/nord.png +0 -0
  97. data/assets/themes/nord_dark.png +0 -0
  98. data/assets/themes/purple.png +0 -0
  99. data/assets/themes/purple_dark.png +0 -0
  100. data/assets/themes/tomorrow.png +0 -0
  101. data/assets/themes/tomorrow_dark.png +0 -0
  102. metadata +269 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bb5cb53e1adde0574281d3c8b1fb171253760abfe92ba4ac5ad03f288a65f81f
4
+ data.tar.gz: 6955c84eefa6f386f3c289262861f608896fb91e84fc8f72f36ece80b290fb30
5
+ SHA512:
6
+ metadata.gz: 53e1cfb61ca31dff33ac66e6294f8c0379a975eec7009630f0d1abfda62faf1b7ff7815e88124c80777b4fec4ae50dfe41f09d277c068944d6bc5ebaea20c5f2
7
+ data.tar.gz: 2afdf5844b528b4ba34d0a60cc411fb8522112d9b116d296295d36ef00f2023041dbdecd898c4971c92d00f70a577304471ffab42cdff119cd36c68358008961
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Drshika Asher
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,193 @@
1
+ # 📇 Jekyll Theme Manpage
2
+
3
+ > This theme is currently being beta tested and any feedback is greatly appreciated!
4
+
5
+ [![Netlify Status](https://api.netlify.com/api/v1/badges/d2497628-6688-4ba9-909c-4680a22f2a72/deploy-status)](https://app.netlify.com/sites/jekyll-theme-manpage/deploys)
6
+
7
+ A minimalist Jekyll theme inspired by Linux man pages. Perfect for personal websites, portfolios, and blogs with a technical focus.
8
+
9
+ ![Preview](assets/readme/preview.png)
10
+
11
+ ## Features
12
+
13
+ - 🖥️ Linux man page inspired design
14
+ - 📱 Fully responsive layout
15
+ - 🌙 Automatic dark mode support
16
+ - ✍️ Blog/writing section with:
17
+ - Full-text search
18
+ - Tag filtering
19
+ - Table of contents
20
+ - Reading Time
21
+ - 📐 LaTeX support for mathematical expressions
22
+ - 🎨 Multiple color themes with light/dark variants
23
+ - 🚀 Fast and lightweight
24
+ - 📱 Mobile-first approach
25
+ - 🔍 SEO optimized
26
+ - 📊 Sitemap generation
27
+ - 💬 Giscus comments integration
28
+ - 📡 RSS feed support
29
+
30
+ ## Installation
31
+
32
+ ### Local Installation
33
+
34
+ Add this line to your Jekyll site's `Gemfile`:
35
+
36
+ ```ruby
37
+ gem "jekyll-theme-manpage"
38
+ ```
39
+
40
+ And add this line to your Jekyll site's `_config.yml`:
41
+
42
+ ```yaml
43
+ theme: jekyll-theme-manpage
44
+ ```
45
+
46
+ Then run
47
+
48
+ ```bash
49
+ bundle install
50
+ ```
51
+
52
+ ### GitHub Pages Installation
53
+
54
+ (NOT SUPPORTED YET) For GitHub Pages, add this to your site's `_config.yml`:
55
+
56
+ ```yaml
57
+ remote_theme: drshika/jekyll-theme-manpage
58
+ plugins:
59
+ - jekyll-remote-theme
60
+ ```
61
+
62
+ Add `jekyll-remote-theme` to the Gemfile:
63
+
64
+ ```ruby:Gemfile
65
+ gem 'jekyll-remote-theme'
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ### Basic Setup
71
+
72
+ 1. Create your site structure following Jekyll conventions
73
+ 2. Configure `_config.yml` with your settings
74
+ 3. Add content to `index.md` using the provided template
75
+
76
+ ### Writing Posts
77
+
78
+ Create posts in `_posts` directory following this format:
79
+
80
+ ```markdown
81
+ ---
82
+ layout: post
83
+ title: Your Post Title
84
+ description: Brief description
85
+ tags: [tag1, tag2]
86
+ toc: true # Optional table of contents
87
+ ---
88
+ Your content here...
89
+ ```
90
+
91
+ Make sure to name the file with the `YYYY-MM-DD-Title.md`.
92
+
93
+
94
+ ### Customization
95
+
96
+ #### Color Themes
97
+
98
+ The theme comes with several preset color schemes. Currently changing the theme is only supported for local development.
99
+
100
+ ### Light Themes
101
+ | Theme | Preview |
102
+ |-------|---------|
103
+ | Purple | ![Purple Theme](assets/themes/purple.png) |
104
+ | Tomorrow | ![Tomorrow Theme](assets/themes/tomorrow.png) |
105
+ | GitHub | ![GitHub Theme](assets/themes/github.png) |
106
+ | Dracula | ![Dracula Theme](assets/themes/dracula.png) |
107
+ | Nord | ![Nord Theme](assets/themes/nord.png) |
108
+ | Monokai | ![Monokai Theme](assets/themes/monokai.png) |
109
+
110
+ ### Dark Themes
111
+ | Theme | Preview |
112
+ |-------|---------|
113
+ | Purple | ![Purple Dark Theme](assets/themes/purple_dark.png) |
114
+ | Tomorrow | ![Tomorrow Dark Theme](assets/themes/tomorrow_dark.png) |
115
+ | GitHub | ![GitHub Dark Theme](assets/themes/github_dark.png) |
116
+ | Dracula | ![Dracula Dark Theme](assets/themes/dracula_dark.png) |
117
+ | Nord | ![Nord Dark Theme](assets/themes/nord_dark.png) |
118
+ | Monokai | ![Monokai Dark Theme](assets/themes/monokai_dark.png) |
119
+
120
+
121
+ To use any of these themes, update your `_sass/variables.scss`:
122
+
123
+ ```scss
124
+ // Theme selection
125
+ $default-theme: 'nord';
126
+ $default-mode: 'light';
127
+ ```
128
+
129
+ #### Typography
130
+
131
+ This theme uses Nitti as its default font. You can purchase Nitti from [Adobe Fonts](https://fonts.adobe.com/fonts/nitti). If you don't have Nitti, the theme will fallback to Fira Code.
132
+
133
+ ## Development
134
+
135
+ (For local use only!) To set up your environment to develop this theme:
136
+
137
+ 1. Clone this repo
138
+ 2. Run `bundle install`
139
+ 3. Run `bundle exec jekyll serve`
140
+ 4. Visit `http://localhost:4000`
141
+
142
+ ## Optional Features
143
+
144
+ Enable optional features in your `_config.yml`:
145
+
146
+ ```yaml
147
+ features:
148
+ comments: true # Set to true to enable Giscus comments
149
+ rss_feed: true # Set to true to enable RSS feed
150
+ search: true # Set to true to enable search
151
+ google_analytics: false # Set to true to enable Google Analytics
152
+ tags: true # Set to true to enable tags
153
+ read_time: true # Set to true to enable read time
154
+ back_to_top: false # Set to true to enable back to top button
155
+ ```
156
+
157
+ ### Comments
158
+
159
+ To enable comments:
160
+
161
+ 1. Set `features.comments: true` in your `_config.yml`
162
+ 2. Get your Giscus script from [giscus.app](https://giscus.app)
163
+ 3. Paste the generated script into `_includes/comments.html`
164
+
165
+ Disable comments for specific posts by adding `comments: false` to the post's front matter.
166
+
167
+ ### RSS Feed
168
+
169
+ To enable RSS feed:
170
+
171
+ 1. Set `features.rss_feed: true` in your `_config.yml`
172
+
173
+ Your feed will be available at `/feed.xml`.
174
+
175
+ ### RSS Feed
176
+
177
+ To enable RSS feed:
178
+
179
+ 1. Set `features.rss_feed: true` in your `_config.yml`
180
+
181
+ Your feed will be available at `/feed.xml`. See [Jekyll Feed documentation](https://github.com/jekyll/jekyll-feed) for additional configuration options.
182
+
183
+ ## Contributing
184
+
185
+ Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct.
186
+
187
+ ## License
188
+
189
+ The theme is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
190
+
191
+ ## Credits
192
+
193
+ Created with ❤️ by Drshika Asher
@@ -0,0 +1,21 @@
1
+ {% if site.features.comments %}
2
+ <div class="comments">
3
+ <h2>Comments</h2>
4
+ <script src="https://giscus.app/client.js"
5
+ data-repo="drshika/jekyll-theme-manpage"
6
+ data-repo-id="R_kgDONlmNQQ"
7
+ data-category="Announcements"
8
+ data-category-id="DIC_kwDONlmNQc4Clurt"
9
+ data-mapping="og:title"
10
+ data-strict="0"
11
+ data-reactions-enabled="1"
12
+ data-emit-metadata="1"
13
+ data-input-position="top"
14
+ data-theme="preferred_color_scheme"
15
+ data-lang="en"
16
+ data-loading="lazy"
17
+ crossorigin="anonymous"
18
+ async>
19
+ </script>
20
+ </div>
21
+ {% endif %}
@@ -0,0 +1,9 @@
1
+ <div class="fun-facts">
2
+ {% for fact in site.data.facts.facts %}
3
+ <div class="fact-item">
4
+ [{{ forloop.index0 }}] {{ fact }}
5
+ <div class="arrow">↓</div>
6
+ </div>
7
+ {% endfor %}
8
+ <div class="fact-item">nullptr</div>
9
+ </div>
@@ -0,0 +1,10 @@
1
+ {% if site.google_analytics %}
2
+ <script>
3
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
4
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
5
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
6
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
7
+ ga('create', '{{ site.google_analytics }}', 'auto');
8
+ ga('send', 'pageview');
9
+ </script>
10
+ {% endif %}
@@ -0,0 +1,64 @@
1
+ <!-- start custom head snippets -->
2
+
3
+ <!-- Theme Switcher -->
4
+ <script src="{{ '/assets/js/theme-switcher.js' | relative_url }}"></script>
5
+
6
+ <!-- Common meta tags -->
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com">
9
+
10
+ <!-- KaTeX - only load if page.katex is true -->
11
+ {% if page.katex %}
12
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.19/dist/katex.min.css"
13
+ integrity="sha384-7lU0muIg/i1plk7MgygDUp3/bNRA65orrBub4/OSWHECgwEsY83HaS1x3bljA/XV" crossorigin="anonymous">
14
+ <!-- The loading of KaTeX is deferred to speed up page rendering -->
15
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.19/dist/katex.min.js"
16
+ integrity="sha384-RdymN7NRJ+XoyeRY4185zXaxq9QWOOx3O7beyyrRK4KQZrPlCDQQpCu95FoCGPAE"
17
+ crossorigin="anonymous"></script>
18
+ <!-- To automatically render math in text elements, include the auto-render extension: -->
19
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.19/dist/contrib/auto-render.min.js"
20
+ integrity="sha384-hCXGrW6PitJEwbkoStFjeJxv+fSOOQKOPbJxSfM6G5sWZjAyWhXiTIIAmQqnlLlh" crossorigin="anonymous"
21
+ onload="renderMathInElement(document.body);"></script>
22
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.19/dist/contrib/mhchem.min.js"
23
+ integrity="sha384-F2ptQFZqNJuqfGGl28mIXyQ5kXH48spn7rcoS0Y9psqIKAcZPLd1NzwFlm/bl1mH"
24
+ crossorigin="anonymous"></script>
25
+ <script>
26
+ document.addEventListener("DOMContentLoaded", function () {
27
+ renderMathInElement(document.body, {
28
+ delimiters: [
29
+ { left: "$$", right: "$$", display: true },
30
+ { left: "\\[", right: "\\]", display: true },
31
+ { left: "$", right: "$", display: false },
32
+ { left: "\\(", right: "\\)", display: false }
33
+ ]
34
+
35
+ });
36
+ });
37
+ </script>
38
+ {% endif %}
39
+
40
+ <!-- Favicons -->
41
+ {% if site.favicon %}
42
+ {% if site.favicon.svg %}
43
+ <link rel="icon" type="image/svg+xml" href="{{ site.favicon.svg | relative_url }}">
44
+ {% endif %}
45
+ {% if site.favicon.ico %}
46
+ <link rel="alternate icon" type="image/x-icon" href="{{ site.favicon.ico | relative_url }}">
47
+ {% endif %}
48
+ {% if site.favicon.png32 %}
49
+ <link rel="alternate icon" type="image/png" sizes="32x32" href="{{ site.favicon.png32 | relative_url }}">
50
+ {% endif %}
51
+ {% if site.favicon.png16 %}
52
+ <link rel="alternate icon" type="image/png" sizes="16x16" href="{{ site.favicon.png16 | relative_url }}">
53
+ {% endif %}
54
+ {% endif %}
55
+
56
+ <!-- RSS Feed -->
57
+ {% if site.features.rss_feed %}
58
+ {% feed_meta %}
59
+ {% endif %}
60
+
61
+ <!-- Google Analytics -->
62
+ {% include head-custom-google-analytics.html %}
63
+
64
+ <!-- end custom head snippets -->
@@ -0,0 +1,11 @@
1
+ <!-- Credits: https://carlosbecker.com/posts/jekyll-reading-time-without-plugins/ -->
2
+
3
+ <span class="reading-time" title="Estimated read time">
4
+ {% assign words = content | number_of_words %}
5
+ {% if words < 360 %}
6
+ 1 min read
7
+ {% else %}
8
+ {{ words | divided_by:180 }} min read
9
+ {% endif %}
10
+ </span>
11
+
@@ -0,0 +1,4 @@
1
+ {% assign skin = site.skin %}
2
+ <style>
3
+ {% include_relative _sass/skins/{{ site.skin }}.css %}
4
+ </style>
@@ -0,0 +1,8 @@
1
+ <div class="social-links">
2
+ <span class="link-group">
3
+ [<a href="{{ site.data.social_links.resume.url }}">{{ site.data.social_links.resume.text }}</a>][{{ site.data.social_links.email }}]
4
+ </span>
5
+ <span class="link-group">
6
+ {% for link in site.data.social_links.social %}[{{ link.name | capitalize }}:<a href="{{ link.url }}">{{ link.text }}</a>]{% endfor %}
7
+ </span>
8
+ </div>
@@ -0,0 +1,63 @@
1
+ <!DOCTYPE html>
2
+ <html lang="{{ site.lang | default: " en-US" }}">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ {% seo %}
7
+ <link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
8
+ {% include head-custom.html %}
9
+ </head>
10
+
11
+ <body>
12
+ <header class="page-header">
13
+ <h1 class="project-name">{{ page.title | default: site.title | default: site.github.repository_name }}</h1>
14
+ </header>
15
+
16
+ <main id="content" class="main-content" role="main">
17
+ {{ content }}
18
+ <button id="scrollToTop" title="Go to top">↑</button>
19
+ <footer class="site-footer">
20
+
21
+ {% if page.layout == 'post' %}
22
+ <a href="/writing" class="back-link">← back to Writing</a>
23
+ {% else %}
24
+ <span class="site-footer-credits" style="text-align: center;">{{ site.author }}, 2025</span>
25
+ {% endif %}
26
+ </footer>
27
+ </main>
28
+ <script>
29
+ console.log({
30
+ 'data-theme': document.documentElement.getAttribute('data-theme'),
31
+ 'color-scheme': document.documentElement.getAttribute('color-scheme'),
32
+ 'root-bg': getComputedStyle(document.documentElement).getPropertyValue('--bg-color'),
33
+ 'root-color': getComputedStyle(document.documentElement).getPropertyValue('--text-color')
34
+ });
35
+ </script>
36
+ {% if site.features.back_to_top %}
37
+ <script>
38
+ document.addEventListener('DOMContentLoaded', function () {
39
+ // Get the button
40
+ const scrollButton = document.getElementById("scrollToTop");
41
+
42
+ if (scrollButton) {
43
+ // Show button when user scrolls down 20px from top
44
+ window.onscroll = function () {
45
+ if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
46
+ scrollButton.style.display = "block";
47
+ } else {
48
+ scrollButton.style.display = "none";
49
+ }
50
+ };
51
+
52
+ // Scroll to top when button is clicked
53
+ scrollButton.onclick = function () {
54
+ document.body.scrollTop = 0; // For Safari
55
+ document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
56
+ };
57
+ }
58
+ });
59
+ </script>
60
+ {% endif %}
61
+ </body>
62
+
63
+ </html>
@@ -0,0 +1,19 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ <!-- Nav Links -->
5
+ {% for item in site.data.navigation.pages %}
6
+ {% if item.name == "Writing" %}
7
+ <a href="{{item.link}}" alt="{{item.name}}" style="text-transform: uppercase;">{{item.name}}</a>
8
+ {% else %}
9
+ <a href="{{item.link}}" alt="{{item.name}}" style="text-transform: uppercase;">{{item.name}}</a> |
10
+ {% endif %}
11
+ {% endfor %}
12
+ <!-- End Nav Links -->
13
+
14
+ {{ content | replace: '<h2>NEWS</h2>', '<h2>NEWS</h2>
15
+ <div class="news-section">' |
16
+ replace: '<h2>EXTRAS</h2>', '</div>
17
+ <h2>EXTRAS</h2>' |
18
+ replace: '<ul>', '<ul class="linked-list">' |
19
+ replace: '<p><strong>', '<p class="role"><strong class="title">' }}
@@ -0,0 +1,29 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ <div class="post-meta">
5
+ <span class="post-date">{{ page.date | date_to_string: "ordinal", "US" }}</span>
6
+ {% if page.tags %}
7
+ <div class="post-tags">
8
+ {% for tag in page.tags %}
9
+ <span class="tag">{{ tag }}</span>
10
+ {% endfor %}
11
+ </div>
12
+ {% endif %}
13
+
14
+ {% if site.features.read_time %}
15
+ {% include read_time.html %}
16
+ {% endif %}
17
+
18
+ {% if page.toc %}
19
+ <div class="toc">
20
+ <h2>Table of Contents</h2>
21
+ {% toc %}
22
+ </div>
23
+ {% endif %}
24
+
25
+ </div>
26
+
27
+ {{ content }}
28
+
29
+ {% include comments.html %}
@@ -0,0 +1,173 @@
1
+ <!DOCTYPE html>
2
+ <html lang="{{ site.lang | default: " en-US" }}">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ {% seo %}
7
+ <link rel="preconnect" href="https://fonts.gstatic.com">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1">
9
+ <link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
10
+ <title>{{ page.title }}</title>
11
+ {% include head-custom.html %}
12
+ </head>
13
+
14
+ <body>
15
+ <header class="page-header">
16
+ <h1 class="project-name">→ ~ ls -lt /writing</h1>
17
+
18
+ <!-- Search bar -->
19
+ <div class="search-container" {% unless site.features.search %}style="display: none;" {% endunless %}>
20
+ <input type="text" id="search-input" placeholder="Search posts...">
21
+ </div>
22
+
23
+ <!-- Tag filter -->
24
+ <div class="tag-container" {% unless site.features.tags %}style="display: none;" {% endunless %}>
25
+ {% capture tags_string %}{% for tag in site.tags %}{{ tag | first }}:{{ tag | last | size }}|{% endfor %}{% endcapture %}
26
+ {% assign tags = tags_string | split: '|' | pop | sort | reverse %}
27
+ {% for tag_info in tags %}
28
+ {% assign tag_parts = tag_info | split: ':' %}
29
+ {% assign tag_name = tag_parts[0] | strip %}
30
+ {% assign tag_count = tag_parts[1] | strip %}
31
+ <button class="tag-button" data-tag="{{ tag_name }}">
32
+ {{ tag_name }} ({{ tag_count }})
33
+ </button>
34
+ {% endfor %}
35
+ </div>
36
+ </header>
37
+
38
+ <main id="content" class="main-content" role="main">
39
+ <!-- Post listing -->
40
+ <div class="posts-container">
41
+ {% for post in site.posts %}
42
+ <article class="post-preview" data-tags="{{ post.tags | join: ' ' }}">
43
+ <h2>
44
+ <span class="post-date">{{ post.date | date: "%Y-%m-%d" }}</span>
45
+ <a href="{{ post.url }}">{{ post.title }}</a>
46
+ </h2>
47
+ {% if post.tags %}
48
+ <div class="post-tags">
49
+ {% for tag in post.tags %}
50
+ <span class="tag">{{ tag }}</span>
51
+ {% endfor %}
52
+ </div>
53
+ {% endif %}
54
+ <div class="post-excerpt">
55
+ {{ post.excerpt | strip_html | truncatewords:25 }}
56
+ </div>
57
+ </article>
58
+ {% endfor %}
59
+ </div>
60
+
61
+ <!-- No results message -->
62
+ <div id="no-results" class="hidden">
63
+ No posts found matching your criteria.
64
+ </div>
65
+
66
+ <footer class="site-footer">
67
+ <a href="/" class="back-link">← back to Home</a>
68
+ </footer>
69
+ </main>
70
+
71
+ <!-- ... existing code ... -->
72
+
73
+ <!-- Search and filter script -->
74
+ <script>
75
+ document.addEventListener('DOMContentLoaded', function () {
76
+ const searchInput = document.getElementById('search-input')
77
+ const postsContainer = document.querySelector('.posts-container')
78
+ const noResults = document.getElementById('no-results')
79
+ const tagButtons = document.querySelectorAll('.tag-button')
80
+ const activeTags = new Set()
81
+ let searchIndex = null
82
+
83
+ // Load and cache search index
84
+ async function loadSearchIndex() {
85
+ if (searchIndex) return searchIndex
86
+
87
+ try {
88
+ const response = await fetch('/search_index.json')
89
+ searchIndex = await response.json()
90
+ return searchIndex
91
+ } catch (error) {
92
+ console.error('Error loading search index:', error)
93
+ return { posts: [] }
94
+ }
95
+ }
96
+
97
+ function renderPost(post) {
98
+ return `
99
+ <article class="post-preview" data-tags="${post.tags.join(' ')}">
100
+ <h2>
101
+ <span class="post-date">${post.date}</span>
102
+ <a href="${post.url}">${post.title}</a>
103
+ </h2>
104
+ ${post.tags.length ? `
105
+ <div class="post-tags">
106
+ ${post.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
107
+ </div>
108
+ ` : ''}
109
+ <div class="post-excerpt">
110
+ ${post.excerpt}
111
+ </div>
112
+ </article>
113
+ `
114
+ }
115
+
116
+ async function filterPosts() {
117
+ const searchTerm = searchInput.value.toLowerCase()
118
+ const data = await loadSearchIndex()
119
+
120
+ const filteredPosts = data.posts.filter(post => {
121
+ const matchesSearch = searchTerm === '' ||
122
+ post.title.toLowerCase().includes(searchTerm) ||
123
+ post.content.toLowerCase().includes(searchTerm)
124
+
125
+ const postTags = new Set(post.tags)
126
+ const matchesTags = activeTags.size === 0 ||
127
+ Array.from(activeTags).every(tag => postTags.has(tag))
128
+
129
+ return matchesSearch && matchesTags
130
+ })
131
+
132
+ postsContainer.innerHTML = filteredPosts.map(renderPost).join('')
133
+ noResults.classList.toggle('hidden', filteredPosts.length > 0)
134
+ }
135
+
136
+ // Debounce function to limit how often filterPosts runs
137
+ function debounce(func, wait) {
138
+ let timeout
139
+ return function executedFunction(...args) {
140
+ const later = () => {
141
+ clearTimeout(timeout)
142
+ func(...args)
143
+ }
144
+ clearTimeout(timeout)
145
+ timeout = setTimeout(later, wait)
146
+ }
147
+ }
148
+
149
+ // Add event listeners
150
+ searchInput.addEventListener('input', debounce(filterPosts, 300))
151
+
152
+ tagButtons.forEach(button => {
153
+ button.addEventListener('click', () => {
154
+ const tag = button.dataset.tag
155
+ if (activeTags.has(tag)) {
156
+ activeTags.delete(tag)
157
+ button.classList.remove('active')
158
+ } else {
159
+ activeTags.add(tag)
160
+ button.classList.add('active')
161
+ }
162
+ filterPosts()
163
+ })
164
+ })
165
+
166
+ // Initial load of search index
167
+ loadSearchIndex()
168
+ })
169
+ </script>
170
+
171
+ </body>
172
+
173
+ </html>