1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
# Back-to-Top Button Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a fixed bottom-right back-to-top button that appears after 33% scroll depth on article/single pages, with slide-up animation, full accessibility, and hacker-theme styling.
**Architecture:** A new `back-to-top.html` partial uses inline Alpine.js `x-data` with `@scroll.window` to track scroll depth; the button is conditionally included in `baseof.html` on `.Kind "page"` pages (same condition as reading progress bar). CSS lives in a new `.back-to-top` component class in `main.css`.
**Tech Stack:** Hugo partials, Alpine.js 3.x (inline x-data), Tailwind CSS (@apply), Feather Icons (chevron-up inlined SVG)
---
## File Map
| Action | File | Responsibility |
|---|---|---|
| Create | `themes/danix-xyz-hacker/layouts/partials/back-to-top.html` | Button markup + Alpine logic |
| Modify | `themes/danix-xyz-hacker/assets/css/main.css` | `.back-to-top` component class |
| Modify | `themes/danix-xyz-hacker/layouts/_default/baseof.html` | Include partial on `.Kind "page"` |
| Modify | `themes/danix-xyz-hacker/i18n/en.yaml` | `back_to_top` key |
| Modify | `themes/danix-xyz-hacker/i18n/it.yaml` | `back_to_top` key (Italian) |
---
### Task 1: Add `.back-to-top` CSS component class
**Files:**
- Modify: `themes/danix-xyz-hacker/assets/css/main.css` (append inside `@layer components`, after `.toast-container`)
- [ ] **Step 1: Open `main.css` and locate the end of `@layer components`**
Find the closing `}` of `@layer components`. It ends around line 1165 (after `.tooltip-text`). Add the new class block just before that closing brace.
- [ ] **Step 2: Add the `.back-to-top` class**
```css
/* Back to top button */
.back-to-top {
@apply fixed bottom-6 right-6 z-40 w-11 h-11 rounded-full flex items-center justify-content-center;
background: var(--accent);
box-shadow: 0 0 12px rgba(168, 85, 247, 0.4);
transition: background 200ms ease, box-shadow 200ms ease;
color: #fff;
}
.back-to-top:hover {
background: #9333ea;
box-shadow: 0 0 20px var(--accent);
}
.back-to-top:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
```
- [ ] **Step 3: Rebuild CSS**
```bash
cd /home/danix/Programming/GIT/danix.xyz-hacker-theme && npm run build
```
Expected: exits 0, `themes/danix-xyz-hacker/static/css/main.min.css` updated.
- [ ] **Step 4: Commit**
```bash
git add themes/danix-xyz-hacker/assets/css/main.css themes/danix-xyz-hacker/static/css/main.min.css
git commit -m "style: add .back-to-top component class"
```
---
### Task 2: Create `back-to-top.html` partial
**Files:**
- Create: `themes/danix-xyz-hacker/layouts/partials/back-to-top.html`
- [ ] **Step 1: Create the partial file**
```html
<div
x-data="{ visible: false }"
@scroll.window="visible = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) >= 0.33"
>
<button
x-show="visible"
x-cloak
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0"
x-transition:leave-end="opacity-0 translate-y-4"
class="back-to-top"
aria-label="{{ i18n "back_to_top" | default "Back to top" }}"
type="button"
@click="window.scrollTo({ top: 0, behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth' })"
>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<polyline points="18 15 12 9 6 15"></polyline>
</svg>
</button>
</div>
```
Note: SVG is Feather `chevron-up` inlined to avoid race condition with `feather.replace()` running before Alpine shows the button. `aria-hidden="true"` on the SVG because the button has `aria-label`.
- [ ] **Step 2: Add i18n keys**
In `themes/danix-xyz-hacker/i18n/en.yaml`, add:
```yaml
back_to_top: "Back to top"
```
In `themes/danix-xyz-hacker/i18n/it.yaml`, add:
```yaml
back_to_top: "Torna in cima"
```
- [ ] **Step 3: Commit**
```bash
git add themes/danix-xyz-hacker/layouts/partials/back-to-top.html themes/danix-xyz-hacker/i18n/en.yaml themes/danix-xyz-hacker/i18n/it.yaml
git commit -m "feat: add back-to-top partial with Alpine.js and i18n"
```
---
### Task 3: Include partial in `baseof.html`
**Files:**
- Modify: `themes/danix-xyz-hacker/layouts/_default/baseof.html`
- [ ] **Step 1: Locate the `.Kind "page"` block for reading-progress (lines ~28–34)**
```html
{{ if eq .Kind "page" }}
<div
id="reading-progress"
class="fixed top-0 left-0 h-1 transition-all duration-100"
style="width: 0%; background: linear-gradient(to right, var(--accent), var(--accent2)); z-index: 9999;"
></div>
{{ end }}
```
- [ ] **Step 2: Add the partial include inside the same condition block**
```html
{{ if eq .Kind "page" }}
<div
id="reading-progress"
class="fixed top-0 left-0 h-1 transition-all duration-100"
style="width: 0%; background: linear-gradient(to right, var(--accent), var(--accent2)); z-index: 9999;"
></div>
{{ partial "back-to-top.html" . }}
{{ end }}
```
- [ ] **Step 3: Commit**
```bash
git add themes/danix-xyz-hacker/layouts/_default/baseof.html
git commit -m "feat: include back-to-top button on single pages"
```
---
### Task 4: Verify end-to-end
- [ ] **Step 1: Start Hugo dev server**
```bash
cd /home/danix/Programming/GIT/danix.xyz-hacker-theme && hugo server -D
```
- [ ] **Step 2: Open an article page and scroll past 33%**
Navigate to any article. Confirm the purple circle button slides up from bottom-right.
- [ ] **Step 3: Scroll back above 33%**
Confirm button fades/slides out.
- [ ] **Step 4: Click button**
Confirm smooth scroll to top.
- [ ] **Step 5: Keyboard accessibility**
Tab to the button when visible. Confirm focus ring (purple outline). Press Enter — confirm scroll to top.
- [ ] **Step 6: Reduced motion**
DevTools → Rendering → "Emulate prefers-reduced-motion: reduce". Scroll past 33% — button appears instantly (no animation). Click — page jumps instantly (no smooth scroll).
- [ ] **Step 7: z-index layering**
Confirm button sits below fixed header, search modal, and toast notifications.
- [ ] **Step 8: Non-article pages**
Navigate to home or list page. Confirm no button appears.
- [ ] **Step 9: Final CSS rebuild and commit**
```bash
npm run build
git add themes/danix-xyz-hacker/static/css/main.min.css
git commit -m "build: rebuild CSS for back-to-top button"
```
- [ ] **Step 10: Update TODO.md**
```markdown
- [✅] add back-to-top button
```
```bash
git add TODO.md
git commit -m "chore: mark back-to-top as complete in TODO"
```
|