fix build

This commit is contained in:
Dave Kerr
2025-03-11 10:29:42 +00:00
parent 0a56479bd9
commit 711327b632
9 changed files with 544 additions and 22 deletions

View File

@@ -1,11 +1,5 @@
"""Generate the Hacker Laws website from the Hacker Laws README""" """Generate the Hacker Laws website from the Hacker Laws README"""
# TODO:
# - favicon
# - test share links
# - rubbish at bottom of pate
# - crosslink ES/HL/TAI
# - 'back to top' better text
import argparse import argparse
import os import os
import shutil import shutil
@@ -50,10 +44,13 @@ def prepare_markdown(path: str) -> str:
def parse_markdown(markdown_content: str): def parse_markdown(markdown_content: str):
(_, remains) = bisect_text(markdown_content, "<!-- vim-markdown-toc GFM -->") (_, remains) = bisect_text(markdown_content, "---")
(links, remains) = bisect_text(remains, "---")
(_, content) = bisect_text(remains, "<!-- vim-markdown-toc -->") (_, content) = bisect_text(remains, "<!-- vim-markdown-toc -->")
md = markdown.Markdown(extensions=['toc']) md = markdown.Markdown(extensions=['toc'])
links = md.convert(links)
print(f"links: {links}")
md.convert(content) md.convert(content)
toc = md.toc toc = md.toc
@@ -75,7 +72,7 @@ def parse_markdown(markdown_content: str):
"full_content": full_content "full_content": full_content
}) })
return (sections, toc) return (links, toc, sections)
def extract_static_files(html_content, output_dir): def extract_static_files(html_content, output_dir):
@@ -123,13 +120,13 @@ def generate_site(markdown_content: str, output_dir: str):
"""Generate the static HTML file from Markdown and Jinja2 template.""" """Generate the static HTML file from Markdown and Jinja2 template."""
template = load_template() template = load_template()
(sections, toc) = parse_markdown(markdown_content) (links, toc, sections) = parse_markdown(markdown_content)
# Ensure output directory exists # Ensure output directory exists
os.makedirs(output_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True)
# Render HTML # Render HTML
html_output = template.render(toc=toc, sections=sections) html_output = template.render(links=links, toc=toc, sections=sections)
# Save HTML to output directory # Save HTML to output directory
output_file = os.path.join(output_dir, "index.html") output_file = os.path.join(output_dir, "index.html")

3
.github/website/src/favicon.svg vendored Normal file
View File

@@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16 0 0 7.16 0 16C0 23.08 4.58 29.06 10.94 31.18C11.74 31.32 12.04 30.84 12.04 30.42C12.04 30.04 12.02 28.78 12.02 27.44C8 28.18 6.96 26.46 6.64 25.56C6.46 25.1 5.68 23.68 5 23.3C4.44 23 3.64 22.26 4.98 22.24C6.24 22.22 7.14 23.4 7.44 23.88C8.88 26.3 11.18 25.62 12.1 25.2C12.24 24.16 12.66 23.46 13.12 23.06C9.56 22.66 5.84 21.28 5.84 15.16C5.84 13.42 6.46 11.98 7.48 10.86C7.32 10.46 6.76 8.82 7.64 6.62C7.64 6.62 8.98 6.2 12.04 8.26C13.32 7.9 14.68 7.72 16.04 7.72C17.4 7.72 18.76 7.9 20.04 8.26C23.1 6.18 24.44 6.62 24.44 6.62C25.32 8.82 24.76 10.46 24.6 10.86C25.62 11.98 26.24 13.4 26.24 15.16C26.24 21.3 22.5 22.66 18.94 23.06C19.52 23.56 20.02 24.52 20.02 26.02C20.02 28.16 20 29.88 20 30.42C20 30.84 20.3 31.34 21.1 31.18C27.42 29.06 32 23.06 32 16C32 7.16 24.84 0 16 0V0Z" fill="#24292E"/>
</svg>

After

Width:  |  Height:  |  Size: 959 B

View File

@@ -13,6 +13,7 @@
gtag('config', 'G-RGJ5TDHWY9'); gtag('config', 'G-RGJ5TDHWY9');
</script> </script>
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<!-- Google Fonts --> <!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&family=Inter:wght@400;600&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&family=Inter:wght@400;600&display=swap" rel="stylesheet">
<!-- Bootstrap CSS --> <!-- Bootstrap CSS -->
@@ -45,18 +46,21 @@
</header> </header>
<main class="container"> <main class="container">
{{ toc }} <!-- Quick links. -->
{{ links }}
<hr>
<!-- The table of contents. --> <!-- The table of contents. -->
{{ toc }}
<hr>
<!-- Each of the sections - most of which are laws. --> <!-- Each of the sections - most of which are laws. -->
{% for section in sections %} {% for section in sections %}
<section id="{{ section.id }}" class="law-section"> <section id="{{ section.id }}" class="law-section">
{{ section.full_content | safe }} {{ section.full_content | safe }}
<div class="social-sharing"> <div class="social-sharing">
<a href="https://twitter.com/share?url=#{{ section.id }}" title="Share on Twitter"><i class="bi bi-twitter"></i></a> <a href="https://twitter.com/intent/tweet?url=https://hacker-laws.com/#{{ section.id}}?hashtags=example" title="Share on Twitter" target="_blank"><i class="bi bi-twitter"></i></a>
<a href="https://facebook.com/share?url=#{{ section.id }}" title="Share on Facebook"><i class="bi bi-facebook"></i></a> <a href="https://facebook.com/share?url=https://hacker-laws.com/&num;{{ section.id }}" title="Share on Facebook" target="_blank"><i class="bi bi-facebook"></i></a>
<a href="#" onclick="navigator.clipboard.writeText(window.location.href + '#{{ section.id }}'); alert('Copied!');" title="Copy Link"><i class="bi bi-clipboard"></i></a> <a href="#" onclick="navigator.clipboard.writeText(window.location.href + '#{{ section.id }}'); alert('Copied!');" title="Copy Link" target="_blank"><i class="bi bi-clipboard"></i></a>
</div> </div>
<div class="back-to-top"><a href="#top">↑ Back to Top</a></div> <div class="back-to-top"><a href="#top">↑ Back to Top</a></div>
</section> </section>

View File

@@ -35,6 +35,7 @@ jobs:
run: | run: |
cd .github/website cd .github/website
make build make build
cp build/. '../pages'
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v3 uses: actions/upload-pages-artifact@v3
with: with:

View File

@@ -1,10 +1,14 @@
# 💻📖 hacker-laws <h1 align="center">hacker-laws 💻📖 </h1>
<h4 align="center">🧠 Laws, Theories, Principles and Patterns that developers will find useful.</h4>
Laws, Theories, Principles and Patterns that developers will find useful. ---
[Translations](#translations): [🇮🇩](./translations/id.md) [🇧🇷](./translations/pt-BR.md) [🇨🇳](https://github.com/nusr/hacker-laws-zh) [🇩🇪](./translations/de.md) [🇫🇷](./translations/fr.md) [🇬🇷](./translations/el.md) [🇮🇹](https://github.com/csparpa/hacker-laws-it) [🇱🇻](./translations/lv.md) [🇰🇷](https://github.com/codeanddonuts/hacker-laws-kr) [🇵🇱](./translations/pl.md) [🇷🇺](https://github.com/solarrust/hacker-laws) [🇪🇸](./translations/es-ES.md) [🇹🇷](https://github.com/umutphp/hacker-laws-tr) [🇯🇵](./translations/jp.md) [🇺🇦](./translations/uk.md) [🇻🇳](./translations/vi.md) - 📖 Check out my new book [Effective Shell](https://effective-shell)
- 🌍 Check out the website [hacker-laws.com](https://hacker-laws.com)
Like this project? Please considering [sponsoring me](https://github.com/sponsors/dwmkerr) and the [translators](#translations). Also check out this podcast on [The Changelog - Laws for Hackers to Live By](https://changelog.com/podcast/403) to learn more about the project! You can also [download the latest PDF eBook](https://github.com/dwmkerr/hacker-laws/releases/latest/download/hacker-laws.pdf). Check the [Contributor Guide](./.github/contributing.md) if you are keen to contribute! - ☕️ Like this project? Consider [buying me a coffee with a one-off donation](https://github.com/sponsors/dwmkerr?frequency=one-time)
- 🧠 Check out my new project [Terminal AI](https://github.com/terminal-ai)
- 🎧 Try the podcast [The Changelog - Laws for Hackers to Live By](https://changelog.com/podcast/403)
- 📖 Download the [PDF eBook](https://github.com/dwmkerr/hacker-laws/releases/latest/download/hacker-laws.pd)
--- ---
@@ -95,8 +99,7 @@ There are lots of laws which people discuss when talking about development. This
## Laws ## Laws
And here we go! Laws can be opinions on inevitabilities in the world of software engineering, or wry observations on unavoidable realities.
### 9091 Principle (1% Rule) ### 9091 Principle (1% Rule)

119
assets/site/index.html Normal file
View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Interactive Hacker Laws Stack</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
margin: 0;
font-family: Arial, sans-serif;
}
#stack {
width: 400px;
height: 500px;
overflow-y: auto;
position: relative;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
}
.law-item {
text-align: left;
padding: 4px;
transition: transform 0.2s ease, opacity 0.2s;
transform-origin: left;
font-size: 16px;
color: #333;
margin: 6px 0;
position: relative;
display: flex;
align-items: center;
}
.law-item::before {
content: '';
display: block;
width: 6px;
height: 6px;
border-radius: 50%;
background-color: #aaa;
margin-right: 8px;
transition: height 0.2s, background-color 0.2s;
}
</style>
</head>
<body>
<div id="stack" class="stack"></div>
<script>
const laws = [
"9091 Principle (1% Rule)", "9090 Rule", "Amdahl's Law", "The Broken Windows Theory",
"Brooks' Law", "CAP Theorem (Brewer's Theorem)", "Clarke's Three Laws", "Conway's Law",
"Cunningham's Law", "Dunbar's Number", "The Dunning-Kruger Effect", "Fitts' Law",
"Gall's Law", "Goodhart's Law", "Hanlon's Razor", "Hofstadter's Law", "Hutber's Law",
"The Hype Cycle & Amara's Law", "Hyrum's Law (The Law of Implicit Interfaces)",
"Metcalfe's Law", "Moore's Law", "Murphy's Law / Sod's Law", "Occam's Razor",
"Parkinson's Law", "Premature Optimization Effect", "Putt's Law", "Reed's Law",
"The Law of Conservation of Complexity (Tesler's Law)", "The Law of Leaky Abstractions",
"The Law of Triviality", "The Unix Philosophy", "The Spotify Model", "Wadler's Law",
"Wheaton's Law", "The Dilbert Principle", "The Pareto Principle (The 80/20 Rule)",
"The Peter Principle", "The Robustness Principle (Postel's Law)", "SOLID",
"The Single Responsibility Principle", "The Open/Closed Principle", "The Liskov Substitution Principle",
"The Interface Segregation Principle", "The Dependency Inversion Principle", "The DRY Principle",
"The KISS Principle", "YAGNI"
];
const stack = document.getElementById('stack');
const maxZoom = 1.5;
const minZoom = 0.6;
laws.forEach(title => {
const div = document.createElement('div');
div.className = 'law-item';
div.innerText = title;
stack.appendChild(div);
});
function updateScale(e) {
const items = document.querySelectorAll('.law-item');
items.forEach(item => {
const itemRect = item.getBoundingClientRect();
const itemCenter = (itemRect.top + itemRect.bottom) / 2;
const distance = Math.abs(e.clientY - itemCenter);
const scale = Math.max(maxZoom - distance / 150, minZoom);
const opacity = Math.max(1 - distance / 300, 0.3);
item.style.transform = `scale(${scale})`;
item.style.opacity = opacity;
const dot = item.querySelector('::before');
const barHeight = Math.max(6, 30 - distance / 10);
item.style.setProperty('--dot-height', barHeight + 'px');
item.style.setProperty('--dot-color', distance < 50 ? '#333' : '#aaa');
item.querySelector('::before');
item.style.setProperty('--dot-height', barHeight + 'px');
});
}
document.addEventListener('mousemove', updateScale);
// Initial positioning
updateScale({ clientY: window.innerHeight / 2 });
</script>
<style>
.law-item::before {
height: var(--dot-height, 6px);
background-color: var(--dot-color, #aaa);
}
</style>
</body>
</html>

110
assets/site/index2.html Normal file
View File

@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Interactive Hacker Laws Stack</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
margin: 0;
font-family: Arial, sans-serif;
}
#stack {
width: 400px;
height: 500px;
overflow-y: auto;
position: relative;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
}
.law-item {
text-align: left;
padding: 2px 4px;
transition: transform 0.2s ease, opacity 0.2s;
transform-origin: left;
font-size: 15px;
color: #333;
margin: 4px 0;
position: relative;
display: flex;
align-items: center;
}
.law-item::before {
content: '';
display: block;
width: var(--bar-width, 6px);
height: 6px;
border-radius: 3px;
background-color: var(--bar-color, #aaa);
margin-right: 10px;
transition: width 0.2s, background-color 0.2s;
}
</style>
</head>
<body>
<div id="stack" class="stack"></div>
<script>
const laws = [
"9091 Principle (1% Rule)", "9090 Rule", "Amdahl's Law", "The Broken Windows Theory",
"Brooks' Law", "CAP Theorem (Brewer's Theorem)", "Clarke's Three Laws", "Conway's Law",
"Cunningham's Law", "Dunbar's Number", "The Dunning-Kruger Effect", "Fitts' Law",
"Gall's Law", "Goodhart's Law", "Hanlon's Razor", "Hofstadter's Law", "Hutber's Law",
"The Hype Cycle & Amara's Law", "Hyrum's Law (The Law of Implicit Interfaces)",
"Metcalfe's Law", "Moore's Law", "Murphy's Law / Sod's Law", "Occam's Razor",
"Parkinson's Law", "Premature Optimization Effect", "Putt's Law", "Reed's Law",
"The Law of Conservation of Complexity (Tesler's Law)", "The Law of Leaky Abstractions",
"The Law of Triviality", "The Unix Philosophy", "The Spotify Model", "Wadler's Law",
"Wheaton's Law", "The Dilbert Principle", "The Pareto Principle (The 80/20 Rule)",
"The Peter Principle", "The Robustness Principle (Postel's Law)", "SOLID",
"The Single Responsibility Principle", "The Open/Closed Principle", "The Liskov Substitution Principle",
"The Interface Segregation Principle", "The Dependency Inversion Principle", "The DRY Principle",
"The KISS Principle", "YAGNI"
];
const stack = document.getElementById('stack');
const maxZoom = 1.8;
const minZoom = 0.5;
laws.forEach(title => {
const div = document.createElement('div');
div.className = 'law-item';
div.innerText = title;
stack.appendChild(div);
});
function updateScale(e) {
const items = document.querySelectorAll('.law-item');
items.forEach(item => {
const itemRect = item.getBoundingClientRect();
const itemCenter = (itemRect.top + itemRect.bottom) / 2;
const distance = Math.abs(e.clientY - itemCenter);
const scale = Math.max(maxZoom - distance / 120, minZoom);
const opacity = Math.max(1 - distance / 250, 0.2);
const barWidth = Math.max(6, 60 - distance / 5);
item.style.transform = `scale(${scale})`;
item.style.opacity = opacity;
item.style.setProperty('--bar-width', barWidth + 'px');
item.style.setProperty('--bar-color', distance < 50 ? '#333' : '#aaa');
});
}
document.addEventListener('mousemove', updateScale);
// Initial positioning
updateScale({ clientY: window.innerHeight / 2 });
</script>
</body>
</html>

127
assets/site/index3.html Normal file
View File

@@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Interactive Hacker Laws Stack</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
margin: 0;
font-family: Arial, sans-serif;
overflow: hidden;
}
#stack-container {
width: 400px;
height: 500px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
overflow: hidden;
position: relative;
}
#stack {
position: absolute;
width: 100%;
}
.law-item {
text-align: left;
padding: 2px 4px;
transition: transform 0.2s ease, opacity 0.2s;
transform-origin: left;
font-size: 15px;
color: #333;
margin: 4px 0;
position: relative;
display: flex;
align-items: center;
}
.law-item::before {
content: '';
display: block;
width: var(--bar-width, 6px);
height: 6px;
border-radius: 3px;
background-color: var(--bar-color, #aaa);
margin-right: 10px;
transition: width 0.2s, background-color 0.2s;
}
</style>
</head>
<body>
<div id="stack-container">
<div id="stack"></div>
</div>
<script>
const laws = [
"9091 Principle (1% Rule)", "9090 Rule", "Amdahl's Law", "The Broken Windows Theory",
"Brooks' Law", "CAP Theorem (Brewer's Theorem)", "Clarke's Three Laws", "Conway's Law",
"Cunningham's Law", "Dunbar's Number", "The Dunning-Kruger Effect", "Fitts' Law",
"Gall's Law", "Goodhart's Law", "Hanlon's Razor", "Hofstadter's Law", "Hutber's Law",
"The Hype Cycle & Amara's Law", "Hyrum's Law (The Law of Implicit Interfaces)",
"Metcalfe's Law", "Moore's Law", "Murphy's Law / Sod's Law", "Occam's Razor",
"Parkinson's Law", "Premature Optimization Effect", "Putt's Law", "Reed's Law",
"The Law of Conservation of Complexity (Tesler's Law)", "The Law of Leaky Abstractions",
"The Law of Triviality", "The Unix Philosophy", "The Spotify Model", "Wadler's Law",
"Wheaton's Law", "The Dilbert Principle", "The Pareto Principle (The 80/20 Rule)",
"The Peter Principle", "The Robustness Principle (Postel's Law)", "SOLID",
"The Single Responsibility Principle", "The Open/Closed Principle", "The Liskov Substitution Principle",
"The Interface Segregation Principle", "The Dependency Inversion Principle", "The DRY Principle",
"The KISS Principle", "YAGNI"
];
const stack = document.getElementById('stack');
const stackContainer = document.getElementById('stack-container');
const maxZoom = 1.8;
const minZoom = 0.5;
let offsetY = 0;
laws.forEach(title => {
const div = document.createElement('div');
div.className = 'law-item';
div.innerText = title;
stack.appendChild(div);
});
function updateScale() {
const items = document.querySelectorAll('.law-item');
items.forEach(item => {
const itemRect = item.getBoundingClientRect();
const containerRect = stackContainer.getBoundingClientRect();
const itemCenter = (itemRect.top + itemRect.bottom) / 2;
const containerCenter = (containerRect.top + containerRect.bottom) / 2;
const distance = Math.abs(containerCenter - itemCenter);
const scale = Math.max(maxZoom - distance / 120, minZoom);
const opacity = Math.max(1 - distance / 300, 0.3);
const barWidth = Math.max(6, 60 - distance / 3);
item.style.transform = `scale(${scale})`;
item.style.opacity = opacity;
item.style.setProperty('--bar-width', barWidth + 'px');
item.style.setProperty('--bar-color', distance < 50 ? '#333' : '#aaa');
});
}
stackContainer.addEventListener('wheel', (e) => {
e.preventDefault();
offsetY = (offsetY + e.deltaY) % stack.scrollHeight;
if (offsetY < 0) offsetY += stack.scrollHeight;
stack.style.top = `${-offsetY}px`;
updateScale();
});
document.addEventListener('mousemove', updateScale);
updateScale();
</script>
</body>
</html>

158
assets/site/index4.html Normal file
View File

@@ -0,0 +1,158 @@
<!--
Interactive Hacker Laws Stack - Specification:
1. User Experience:
- Display a vertically scrolling list of items ("laws") in a visually appealing, interactive format.
- The list infinitely loops seamlessly; scrolling beyond the first or last item cycles continuously.
- Mouse scrolling moves the entire list vertically within a fixed viewport (no internal scrollbar visible).
- The item under the mouse cursor smoothly scales up (zooms) and becomes clearly highlighted.
- Items further from the cursor scale down smoothly, fade out gradually, and become visually less prominent.
- To the left of each text item, a horizontal bar visually represents the focus, forming a bell-curve-like effect.
The bar is smallest (circular) when far from the cursor, and smoothly expands (rectangular with rounded corners) when close.
2. Sources:
- Original Interaction Design Inspiration: https://press.stripe.com/
- Data Source (list of "Hacker Laws"): https://github.com/dwmkerr/hacker-laws/
3. Technical Details:
- Implemented using plain HTML, CSS, and JavaScript without third-party libraries.
- Clearly defined parameters for customization:
- `maxZoom`: maximum scale factor for the item closest to the cursor.
- `minZoom`: minimum scale factor for items furthest from the cursor.
- Styling is clean, minimalist, and customizable via CSS variables.
This specification allows easy adjustments, maintenance, and future enhancements of the interactive list.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Interactive Hacker Laws Stack</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
margin: 0;
font-family: Arial, sans-serif;
overflow: hidden;
}
#stack-container {
width: 400px;
height: 500px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
overflow: hidden;
position: relative;
}
#stack {
position: absolute;
width: 100%;
}
.law-item {
text-align: left;
padding: 2px 4px;
transition: transform 0.2s ease, opacity 0.2s;
transform-origin: left;
font-size: 15px;
color: #333;
margin: 4px 0;
position: relative;
display: flex;
align-items: center;
}
.law-item::before {
content: '';
display: block;
width: var(--bar-width, 6px);
height: 6px;
border-radius: 3px;
background-color: var(--bar-color, #aaa);
margin-right: 10px;
transition: width 0.2s, background-color 0.2s;
}
</style>
</head>
<body>
<div id="stack-container">
<div id="stack"></div>
</div>
<script>
const laws = [
"9091 Principle (1% Rule)", "9090 Rule", "Amdahl's Law", "The Broken Windows Theory",
"Brooks' Law", "CAP Theorem (Brewer's Theorem)", "Clarke's Three Laws", "Conway's Law",
"Cunningham's Law", "Dunbar's Number", "The Dunning-Kruger Effect", "Fitts' Law",
"Gall's Law", "Goodhart's Law", "Hanlon's Razor", "Hofstadter's Law", "Hutber's Law",
"The Hype Cycle & Amara's Law", "Hyrum's Law (The Law of Implicit Interfaces)",
"Metcalfe's Law", "Moore's Law", "Murphy's Law / Sod's Law", "Occam's Razor",
"Parkinson's Law", "Premature Optimization Effect", "Putt's Law", "Reed's Law",
"The Law of Conservation of Complexity (Tesler's Law)", "The Law of Leaky Abstractions",
"The Law of Triviality", "The Unix Philosophy", "The Spotify Model", "Wadler's Law",
"Wheaton's Law", "The Dilbert Principle", "The Pareto Principle (The 80/20 Rule)",
"The Peter Principle", "The Robustness Principle (Postel's Law)", "SOLID",
"The Single Responsibility Principle", "The Open/Closed Principle", "The Liskov Substitution Principle",
"The Interface Segregation Principle", "The Dependency Inversion Principle", "The DRY Principle",
"The KISS Principle", "YAGNI"
];
const stack = document.getElementById('stack');
const stackContainer = document.getElementById('stack-container');
const maxZoom = 1.8;
const minZoom = 0.5;
let offsetY = 0;
// Create seamless infinite scrolling
const extendedLaws = [...laws, ...laws, ...laws];
extendedLaws.forEach(title => {
const div = document.createElement('div');
div.className = 'law-item';
div.innerText = title;
stack.appendChild(div);
});
const totalHeight = stack.scrollHeight / 3;
stack.style.top = `-${totalHeight}px`;
offsetY = totalHeight;
function updateScale(e) {
const items = document.querySelectorAll('.law-item');
items.forEach(item => {
const itemRect = item.getBoundingClientRect();
const distance = e.clientY ? Math.abs(e.clientY - (itemRect.top + itemRect.bottom) / 2) : 0;
const scale = Math.max(maxZoom - distance / 120, minZoom);
const opacity = Math.max(1 - distance / 300, 0.3);
const barWidth = Math.max(6, 60 - distance / 3);
item.style.transform = `scale(${scale})`;
item.style.opacity = opacity;
item.style.setProperty('--bar-width', barWidth + 'px');
item.style.setProperty('--bar-color', distance < 50 ? '#333' : '#aaa');
});
}
stackContainer.addEventListener('wheel', (e) => {
e.preventDefault();
offsetY += e.deltaY;
if (offsetY >= totalHeight * 2) offsetY -= totalHeight;
if (offsetY < totalHeight) offsetY += totalHeight;
stack.style.top = `-${offsetY}px`;
updateScale(e);
});
stackContainer.addEventListener('mousemove', updateScale);
// Initial scale update
updateScale({ clientY: window.innerHeight / 2 });
</script>
</body>
</html>