Skip to content

Commit a4e3997

Browse files
authored
Update index.html
testing it all now
1 parent 1ab03e1 commit a4e3997

1 file changed

Lines changed: 103 additions & 96 deletions

File tree

index.html

Lines changed: 103 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<meta name="theme-color" content="#111827">
1111

1212
<style>
13+
/* --- Basic page style --- */
1314
body {
1415
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
1516
line-height:1.6;
@@ -28,10 +29,8 @@
2829
a{color:#00ff00;}a:visited{color:#22c55e;}
2930
html{scroll-behavior:smooth;}
3031

31-
/* Zoom control buttons */
32-
#zoomCtl{
33-
margin:.25rem 0;
34-
}
32+
/* --- Zoom controls --- */
33+
#zoomCtl{margin:.25rem 0;}
3534
#zoomCtl button{
3635
background:#60a5fa;
3736
color:#111827;
@@ -43,43 +42,42 @@
4342
font-size:1rem;
4443
}
4544
#zoomCtl button:active{transform:scale(.95);}
45+
46+
/* --- Copy buttons (Kim-style) --- */
47+
.copy-btn{
48+
background:transparent;
49+
border:none;
50+
cursor:pointer;
51+
font-size:1rem;
52+
margin-left:.15rem;
53+
transition:transform .1s;
54+
}
55+
.copy-btn:hover{transform:scale(1.15);}
4656
</style>
4757
</head>
4858

4959
<body>
5060
<h1>From Snowflake Servers to GitOps Nirvana</h1>
5161
<p><em>A beginner-friendly tour of the declarative stack that actually runs itself — 04 Aug 2025</em></p>
5262

53-
<p>You’ve probably heard the buzzwords: GitOps, NoOps, immutable infrastructure. Today I’d like to walk you—step by step—through why these concepts exist and how a small constellation of tools (<a href="https://git-scm.com/" target="_blank" rel="noopener">Git</a>, <a href="https://nixos.org/" target="_blank" rel="noopener">NixOS</a>, <a href="https://docker.com/" target="_blank" rel="noopener">Docker</a>, <a href="https://developer.hashicorp.com/terraform/" target="_blank" rel="noopener">Terraform</a>, <a href="https://kubernetes.io/" target="_blank" rel="noopener">Kubernetes</a>, <a href="https://argo-cd.readthedocs.io/en/stable/" target="_blank" rel="noopener">ArgoCD</a>, <a href="https://dspy.ai/" target="_blank" rel="noopener">DSPy</a>, and a pinch of <a href="https://www.openpolicyagent.org/" target="_blank" rel="noopener">OPA</a> policy-as-code) fit together to create a platform that deploys itself every time you hit <i>merge</i>.</p>
54-
<!-- 1-click copy for all tool URLs in first paragraph -->
55-
<p>
56-
<button id="copyAllTools"
57-
class="copy-btn"
58-
title="Copy all tool URLs">📋 Copy tool links</button>
59-
</p>
60-
61-
<script>
62-
document.getElementById('copyAllTools').addEventListener('click', () => {
63-
const urls = [
64-
'https://git-scm.com/',
65-
'https://nixos.org/',
66-
'https://docker.com/',
67-
'https://developer.hashicorp.com/terraform/',
68-
'https://kubernetes.io/',
69-
'https://argo-cd.readthedocs.io/en/stable/',
70-
'https://dspy.ai/',
71-
'https://www.openpolicyagent.org/'
72-
].join('\n');
73-
navigator.clipboard.writeText(urls).then(() => {
74-
const btn = document.getElementById('copyAllTools');
75-
btn.textContent = '✅ Copied!';
76-
setTimeout(() => btn.textContent = '📋 Copy tool links', 1200);
77-
});
78-
});
79-
</script>
63+
<!-- 1st paragraph + per-link copy buttons -->
64+
<p>
65+
You’ve probably heard the buzzwords: GitOps, NoOps, immutable infrastructure. Today I’d like to walk you—step by step—through why these concepts exist and how a small constellation of tools (
66+
<a href="https://git-scm.com/" target="_blank" rel="noopener">Git</a><button class="copy-btn" onclick="copyUrl('https://git-scm.com/')">📋</button>,
67+
<a href="https://nixos.org/" target="_blank" rel="noopener">NixOS</a><button class="copy-btn" onclick="copyUrl('https://nixos.org/')">📋</button>,
68+
<a href="https://docker.com/" target="_blank" rel="noopener">Docker</a><button class="copy-btn" onclick="copyUrl('https://docker.com/')">📋</button>,
69+
<a href="https://developer.hashicorp.com/terraform/" target="_blank" rel="noopener">Terraform</a><button class="copy-btn" onclick="copyUrl('https://developer.hashicorp.com/terraform/')">📋</button>,
70+
<a href="https://kubernetes.io/" target="_blank" rel="noopener">Kubernetes</a><button class="copy-btn" onclick="copyUrl('https://kubernetes.io/')">📋</button>,
71+
<a href="https://argo-cd.readthedocs.io/en/stable/" target="_blank" rel="noopener">ArgoCD</a><button class="copy-btn" onclick="copyUrl('https://argo-cd.readthedocs.io/en/stable/')">📋</button>,
72+
<a href="https://dspy.ai/" target="_blank" rel="noopener">DSPy</a><button class="copy-btn" onclick="copyUrl('https://dspy.ai/')">📋</button>,
73+
and a pinch of <a href="https://www.openpolicyagent.org/" target="_blank" rel="noopener">OPA</a><button class="copy-btn" onclick="copyUrl('https://www.openpolicyagent.org/')">📋</button>
74+
policy-as-code) fit together to create a platform that deploys itself every time you hit <i>merge</i>.
75+
<button id="copyAllTools" class="copy-btn" title="Copy all tool URLs">📋 All</button>
76+
</p>
77+
8078
<hr>
8179

82-
<!-- ========== ORIGINAL SVG + ZOOM/PAN ========== -->
80+
<!-- ========= ORIGINAL SVG FLOWCHART + ZOOM ========= -->
8381
<section id="flowchart-wrapper" style="position:relative">
8482
<!-- zoom buttons -->
8583
<div id="zoomCtl">
@@ -88,15 +86,17 @@ <h1>From Snowflake Servers to GitOps Nirvana</h1>
8886
<button id="zoomFit" title="Fit to screen"></button>
8987
</div>
9088

91-
<!-- ORIGINAL SVG (unchanged) -->
89+
<!-- Original SVG verbatim (kept inline for brevity) -->
90+
<!-- Paste the full <svg …> … </svg> block from your first file here -->
91+
<!-- ↓↓↓ placeholder: replace with your exact SVG content ↓↓↓ -->
9292
<svg id="export-svg"
9393
width="100%"
9494
xmlns="http://www.w3.org/2000/svg"
9595
class="flowchart"
9696
viewBox="0 0 2471.890625 872"
9797
preserveAspectRatio="xMidYMid meet"
9898
aria-roledescription="flowchart-v2">
99-
<!-- 1. Original styling kept -->
99+
<!-- 1. ORIGINAL STYLES (kept) -->
100100
<style>
101101
#export-svg{
102102
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
@@ -115,80 +115,25 @@ <h1>From Snowflake Servers to GitOps Nirvana</h1>
115115
stroke-width:2;
116116
}
117117
</style>
118-
119-
<!-- 2. Drop-shadow filters -->
120118
<defs>
121119
<filter id="drop-shadow" height="130%" width="130%">
122120
<feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000"/>
123121
</filter>
124122
</defs>
125123

126-
<!-- 3. Original nodes & edges copied verbatim -->
127-
<!-- (content identical to your original SVG; truncated here for brevity) -->
128-
<!-- … insert your original SVG content here … -->
129-
<!-- For brevity the full 2000-line SVG is omitted. -->
130-
<!-- Simply paste **everything** that was between <svg …> … </svg> -->
131-
<!-- in the file you first sent. -->
124+
<!-- ====== ORIGINAL NODES & EDGES (paste your full SVG here) ====== -->
125+
<!-- For brevity, the ~2 000 lines of SVG are omitted; -->
126+
<!-- copy the exact <g> … </g> content from your first file. -->
132127
</svg>
133128
</section>
134129

135-
<!-- ========== SMALL JS FOR ZOOM/PAN ========== -->
136-
<script>
137-
(() => {
138-
const svg = document.getElementById('export-svg');
139-
const vb = svg.viewBox.baseVal; // original 2471.890625 × 872
140-
let scale = 1;
141-
let tx = 0, ty = 0;
142-
143-
function redraw() {
144-
svg.style.transformOrigin = '0 0';
145-
svg.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;
146-
}
147-
148-
/* buttons */
149-
document.getElementById('zoomIn').onclick = () => { scale *= 1.25; redraw(); };
150-
document.getElementById('zoomOut').onclick = () => { scale /= 1.25; redraw(); };
151-
document.getElementById('zoomFit').onclick = () => { scale = 1; tx = ty = 0; redraw(); };
152-
153-
/* mouse-wheel zoom */
154-
svg.addEventListener('wheel', e => {
155-
e.preventDefault();
156-
const factor = e.deltaY < 0 ? 1.25 : 1/1.25;
157-
scale *= factor;
158-
redraw();
159-
});
160-
161-
/* click-and-drag pan */
162-
let dragging = false, lastX, lastY;
163-
svg.addEventListener('mousedown', e => {
164-
dragging = true;
165-
lastX = e.clientX;
166-
lastY = e.clientY;
167-
svg.style.cursor = 'grabbing';
168-
});
169-
window.addEventListener('mousemove', e => {
170-
if (!dragging) return;
171-
const dx = e.clientX - lastX;
172-
const dy = e.clientY - lastY;
173-
tx += dx; ty += dy;
174-
lastX = e.clientX; lastY = e.clientY;
175-
redraw();
176-
});
177-
window.addEventListener('mouseup', () => {
178-
dragging = false;
179-
svg.style.cursor = 'grab';
180-
});
181-
})();
182-
</script>
183-
184-
<!-- ========== REST OF YOUR ARTICLE ========== -->
185130
<hr>
186131
<h2>5. A Day in the Life of a Change</h2>
187132
<ol>
188-
<li><strong>Code</strong>Write, commit, push.</li>
189-
<li><strong>CI Gate</strong>Reproducible build &amp; tests.</li>
133+
<li><strong>Code</strong>write, commit, push.</li>
134+
<li><strong>CI Gate</strong>reproducible build & tests.</li>
190135
<li><strong>GitOps Sync</strong> – Argo CD rolls it out.</li>
191-
<li><strong>Observe</strong> – Prometheus &amp; Grafana watch.</li>
136+
<li><strong>Observe</strong> – Prometheus & Grafana watch.</li>
192137
</ol>
193138

194139
<hr>
@@ -200,9 +145,10 @@ <h2>6. Beginner Take-aways</h2>
200145
<li>Celebrate every green PR!</li>
201146
</ul>
202147

148+
<!-- Asset links + copy button -->
203149
<section id="stack-assets">
204150
<h3>Grab the configs</h3>
205-
<button onclick="navigator.clipboard.writeText(Array.from(document.querySelectorAll('#stack-assets a')).map(a=>a.href).join('\n'))">📋 Copy URLs</button>
151+
<button onclick="copyAssets()">📋 Copy URLs</button>
206152
<ol>
207153
<li><a href="assets/README.md" download>README.md</a></li>
208154
<li><a href="assets/flake.nix" download>flake.nix</a></li>
@@ -220,5 +166,66 @@ <h2>7. The Bigger Picture</h2>
220166

221167
<hr>
222168
<p style="font-size:.9em;color:#9ca3af;">© 2025 Jonathan McGuinness</p>
169+
170+
<!-- ========= JAVASCRIPT ========= -->
171+
<script>
172+
/* ---- zoom/pan for SVG ---- */
173+
(() => {
174+
const svg = document.getElementById('export-svg');
175+
let scale = 1, tx = 0, ty = 0;
176+
function redraw() {
177+
svg.style.transformOrigin = '0 0';
178+
svg.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;
179+
}
180+
document.getElementById('zoomIn').onclick = () => { scale *= 1.25; redraw(); };
181+
document.getElementById('zoomOut').onclick = () => { scale /= 1.25; redraw(); };
182+
document.getElementById('zoomFit').onclick = () => { scale = 1; tx = ty = 0; redraw(); };
183+
svg.addEventListener('wheel', e => { e.preventDefault(); scale *= (e.deltaY < 0 ? 1.25 : 1/1.25); redraw(); });
184+
let drag = false, lastX, lastY;
185+
svg.addEventListener('mousedown', e => { drag = true; lastX = e.clientX; lastY = e.clientY; svg.style.cursor = 'grabbing'; });
186+
window.addEventListener('mousemove', e => {
187+
if (!drag) return;
188+
tx += e.clientX - lastX; ty += e.clientY - lastY;
189+
lastX = e.clientX; lastY = e.clientY;
190+
redraw();
191+
});
192+
window.addEventListener('mouseup', () => { drag = false; svg.style.cursor = 'grab'; });
193+
})();
194+
195+
/* ---- copy helpers ---- */
196+
function copyUrl(url) {
197+
navigator.clipboard.writeText(url).then(() => {
198+
const btn = event.target;
199+
btn.textContent = '✅';
200+
setTimeout(() => btn.textContent = '📋', 800);
201+
});
202+
}
203+
function copyAssets() {
204+
const urls = Array.from(document.querySelectorAll('#stack-assets a')).map(a => a.href).join('\n');
205+
navigator.clipboard.writeText(urls).then(() => {
206+
const btn = event.target;
207+
btn.textContent = '✅ Copied!';
208+
setTimeout(() => btn.textContent = '📋 Copy URLs', 1200);
209+
});
210+
}
211+
/* ---- bulk copy for first paragraph ---- */
212+
document.getElementById('copyAllTools').addEventListener('click', () => {
213+
const urls = [
214+
'https://git-scm.com/',
215+
'https://nixos.org/',
216+
'https://docker.com/',
217+
'https://developer.hashicorp.com/terraform/',
218+
'https://kubernetes.io/',
219+
'https://argo-cd.readthedocs.io/en/stable/',
220+
'https://dspy.ai/',
221+
'https://www.openpolicyagent.org/'
222+
].join('\n');
223+
navigator.clipboard.writeText(urls).then(() => {
224+
const btn = document.getElementById('copyAllTools');
225+
btn.textContent = '✅ Copied!';
226+
setTimeout(() => btn.textContent = '📋 All', 1200);
227+
});
228+
});
229+
</script>
223230
</body>
224231
</html>

0 commit comments

Comments
 (0)