diff --git a/.github/website/generate.py b/.github/website/generate.py index d332812..4fbbf7b 100644 --- a/.github/website/generate.py +++ b/.github/website/generate.py @@ -1,8 +1,9 @@ +"""Generate the Hacker Laws website from the Hacker Laws README""" import argparse -import markdown import os import shutil from jinja2 import Environment, FileSystemLoader +import markdown from bs4 import BeautifulSoup @@ -43,19 +44,31 @@ def prepare_markdown(path: str) -> str: def parse_markdown(markdown_content: str): (_, remains) = bisect_text(markdown_content, "") - (toc, content) = bisect_text(remains, "") + (_, content) = bisect_text(remains, "") - sections = content.split("\n## ") # Split by Markdown headings + md = markdown.Markdown(extensions=['toc']) + md.convert(content) + toc = md.toc + + markdown_sections = content.split("\n#") # Split by Markdown headings + sections = [] laws = [] - for section in sections: - if section.strip(): - lines = section.split("\n", 1) + for markdown_section in markdown_sections: + if markdown_section.strip(): + lines = markdown_section.split("\n", 1) title = lines[0].strip("# ").strip() - content = markdown.markdown(lines[1] if len(lines) > 1 else "") - law_id = title.lower().replace(" ", "-") - laws.append({"title": title, "content": content, "id": law_id}) + content = md.convert(lines[1] if len(lines) > 1 else "") + full_content = md.convert(markdown_section) + id = title.lower().replace(" ", "-") + laws.append({"title": title, "content": content, "id": id}) + sections.append({ + "title": title, + "content": content, + "id": id, + "full_content": full_content + }) - return (markdown.markdown(toc), laws) + return (sections, toc) def extract_static_files(html_content, output_dir): @@ -103,13 +116,13 @@ def generate_site(markdown_content: str, output_dir: str): """Generate the static HTML file from Markdown and Jinja2 template.""" template = load_template() - (toc, laws) = parse_markdown(markdown_content) + (sections, toc) = parse_markdown(markdown_content) # Ensure output directory exists os.makedirs(output_dir, exist_ok=True) # Render HTML - html_output = template.render(toc=toc, laws=laws) + html_output = template.render(toc=toc, sections=sections) # Save HTML to output directory output_file = os.path.join(output_dir, "index.html") diff --git a/.github/website/makefile b/.github/website/makefile index 305b7df..898e437 100644 --- a/.github/website/makefile +++ b/.github/website/makefile @@ -27,9 +27,9 @@ serve: # ๐Ÿš€ start local server python3 -m http.server 8000 .PHONY: watch -watch: # ๐Ÿ‘€ Watch for changes... +watch: build # ๐Ÿ‘€ Watch for changes... @echo "๐Ÿ‘€ Watching for changes..." - watchmedo shell-command --patterns="$(MARKDOWN_FILE);*.py;./src/*.*" --command="make build" . + watchmedo shell-command --patterns="$(MARKDOWN_FILE);*.py;src/*" --command="make build" . .PHONY: clean clean: #๐Ÿงน Clean up generated files diff --git a/.github/website/src/index.html.jinja b/.github/website/src/index.html.jinja index 2f39638..29c8950 100644 --- a/.github/website/src/index.html.jinja +++ b/.github/website/src/index.html.jinja @@ -44,21 +44,18 @@
- {{ toc }} - - {% for law in laws %} -
-

- {{ law.title }} - -

- {{ law.content | safe }} + + + + {% for section in sections %} +
+ {{ section.full_content | safe }}
@@ -69,5 +66,8 @@

© 2025 Hacker Laws

+ + + diff --git a/.github/website/src/script.js b/.github/website/src/script.js new file mode 100644 index 0000000..0dd5292 --- /dev/null +++ b/.github/website/src/script.js @@ -0,0 +1,18 @@ +$(document).ready(function() { + $("h1, h2, h3, h4, h5, h6").each(function() { + var $heading = $(this); + var headingId = $heading.attr("id") || $heading.text().trim().toLowerCase().replace(/\s+/g, "-"); + + // Ensure a unique ID + $heading.attr("id", headingId); + + // Create the anchor link + var $anchor = $('') + .attr("href", "#" + headingId) + .addClass("header-link") + .html("#"); + + // Append to the heading + $heading.append($anchor); + }); +}); diff --git a/.github/website/src/styles.css b/.github/website/src/styles.css index 5c1ae37..6437939 100644 --- a/.github/website/src/styles.css +++ b/.github/website/src/styles.css @@ -1,67 +1,82 @@ - body { - font-family: 'Inter', sans-serif; - background-color: #fff; - color: #333; - padding-top: 70px; - } - .container { - max-width: 800px; - } - .navbar-custom { - background-color: #fff; - border-bottom: 1px solid #e5e5e5; - } - .navbar-brand, .nav-link { - font-weight: 700; - } - header { - text-align: center; - margin-bottom: 2rem; - padding: 2rem 0; - border-bottom: 1px solid #e5e5e5; - } - h1, h2 { - font-family: 'Libre Baskerville', serif; - } - .law-section { - margin-bottom: 2rem; - padding: 1.5rem; - background-color: #fff; - border-bottom: 1px solid #e5e5e5; - position: relative; - } - .law-section h2 { - position: relative; - display: flex; - align-items: center; - } - .law-section h2 a.anchor { - text-decoration: none; - color: #999; - margin-left: 0.5rem; - visibility: hidden; - } - .law-section:hover h2 a.anchor { - visibility: visible; - } - a { - color: #0056b3; - text-decoration: none; - } - a:hover { - text-decoration: underline; - } - .social-sharing a { - margin-right: 0.75rem; - font-size: 1.2rem; - color: #555; - text-decoration: none; - } - .social-sharing a:hover { - color: #000; - } - .back-to-top { - margin-top: 1rem; - } +body { + font-family: 'Inter', sans-serif; + background-color: #fff; + color: #333; + padding-top: 70px; +} +.container { + max-width: 800px; +} +.navbar-custom { + background-color: #fff; + border-bottom: 1px solid #e5e5e5; +} +.navbar-brand, .nav-link { + font-weight: 700; +} +header { + text-align: center; + margin-bottom: 2rem; + padding: 2rem 0; + border-bottom: 1px solid #e5e5e5; +} +h1, h2 { + font-family: 'Libre Baskerville', serif; +} +.law-section { + margin-bottom: 2rem; + padding: 1.5rem; + background-color: #fff; + border-bottom: 1px solid #e5e5e5; + position: relative; +} +.law-section h2 { + position: relative; + display: flex; + align-items: center; +} +.law-section h2 a.anchor { + text-decoration: none; + color: #999; + margin-left: 0.5rem; + visibility: hidden; +} +.law-section:hover h2 a.anchor { + visibility: visible; +} +a { + color: #0056b3; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +.social-sharing a { + margin-right: 0.75rem; + font-size: 1.2rem; + color: #555; + text-decoration: none; +} +.social-sharing a:hover { + color: #000; +} +.back-to-top { + margin-top: 1rem; +} +/* Initially hide the hash link */ +.header-link { + text-decoration: none; + margin-left: 12px; /* Increased left padding */ + opacity: 0; + transition: opacity 0.2s; + font-size: inherit; /* Matches the heading size */ +} + +/* Only show the hash when the whole section is hovered */ +section:hover .header-link, +article:hover .header-link, +div:hover .header-link { + opacity: 1; +}