1
0

WIP Feedback

This commit is contained in:
2026-03-25 18:32:58 +01:00
parent 4e97b5214e
commit 0566d9db10
10 changed files with 315 additions and 80 deletions

View File

@@ -0,0 +1,41 @@
.feedback {
display: flex;
align-items: center;
gap: 0.75rem;
}
.feedback-text {
font-size: 0.88rem;
}
.feedback-buttons {
display: flex;
gap: 0.35rem;
margin-left: auto;
}
.feedback-btn {
font-size: 1rem;
padding: 0.2rem 0.55rem;
background: transparent;
border: 1px solid var(--info-border);
border-radius: 999px;
cursor: pointer;
transition: all 0.15s ease;
color: inherit;
line-height: 1.3;
}
.feedback-btn:hover {
background: rgba(255, 255, 255, 0.5);
}
.feedback-btn--selected {
background: rgba(255, 255, 255, 0.5);
border-color: var(--info-text);
}
.feedback-thanks {
font-size: 0.85rem;
font-weight: 600;
}

View File

@@ -69,7 +69,7 @@ select + .fallback-hint {
}
.restart-hint {
margin-top: 1.5rem;
margin-top: 1rem;
font-size: 0.78rem;
color: var(--text-muted);
}

View File

@@ -11,6 +11,7 @@
@import './components/info-card.css';
@import './components/step-nav.css';
@import './components/modal.css';
@import './components/feedback.css';
@import './layout/hero.css';
@import './layout/steps.css';
@import './layout/footer.css';

View File

@@ -305,7 +305,15 @@
<strong>Safely eject your Kobo and let it reboot.</strong> Please be patient, NickelMenu will be automatically removed during the reboot.
A "glitchy" horizontal line may briefly appear on screen after restarting — this is normal, as NickelMenu removes itself.
</p>
<p class="restart-hint">You can always restart the entire flow by reloading the page.</p>
<p class="restart-hint">You can always restart the entire flow by reloading the page, if you want to try again for another configuration or undo the changes that were made.</p>
<div class="banner banner--info feedback" hidden>
<span class="feedback-text">Did you find the wizard easy to use?</span>
<span class="feedback-thanks" hidden>Thank you for your feedback!</span>
<span class="feedback-buttons">
<button class="feedback-btn" data-vote="up" type="button">&#x1F44D;</button>
<button class="feedback-btn" data-vote="down" type="button">&#x1F44E;</button>
</span>
</div>
</section>
<!-- Step 2 (patches path): Configure patches -->
@@ -378,7 +386,15 @@
<li>The device will reboot and apply the patches automatically.</li>
</ol>
</div>
<p class="restart-hint">You can always restart the entire flow by reloading the page.</p>
<p class="restart-hint">You can always restart the entire flow by reloading the page, if you want to try again for another configuration or undo the changes that were made.</p>
<div class="banner banner--info feedback" hidden>
<span class="feedback-text">Did you find the wizard easy to use?</span>
<span class="feedback-thanks" hidden>Thank you for your feedback!</span>
<span class="feedback-buttons">
<button class="feedback-btn" data-vote="up" type="button">&#x1F44D;</button>
<button class="feedback-btn" data-vote="down" type="button">&#x1F44E;</button>
</span>
</div>
</section>
<!-- Error state -->

View File

@@ -97,6 +97,33 @@ export async function fetchOrThrow(url, errorPrefix = 'Fetch failed') {
return resp;
}
/**
* Wire up a .feedback banner inside a container element.
* Shows text + vote buttons; clicking one replaces all with a thank-you message.
* @param {HTMLElement} container - element containing the .feedback widget
* @param {function} onVote - callback receiving 'up' or 'down'
*/
export function setupFeedback(container, onVote) {
const widget = container.querySelector('.feedback');
if (!widget) return;
widget.hidden = false;
const text = widget.querySelector('.feedback-text');
const buttons = widget.querySelectorAll('.feedback-btn');
const thanks = widget.querySelector('.feedback-thanks');
text.hidden = false;
thanks.hidden = true;
buttons.forEach((btn) => {
btn.hidden = false;
btn.disabled = false;
btn.addEventListener('click', () => {
text.hidden = true;
buttons.forEach((b) => { b.hidden = true; });
thanks.hidden = false;
onVote(btn.dataset.vote);
}, { once: true });
});
}
/**
* Trigger a browser download of in-memory data.
* Creates a temporary object URL, clicks a hidden <a>, then revokes it.

View File

@@ -13,11 +13,11 @@
* `resetNickelMenuState`.
*/
import { $, $q, $qa, triggerDownload, renderNmCheckboxList, populateList } from '../dom.js';
import { $, $q, $qa, triggerDownload, renderNmCheckboxList, populateList, setupFeedback } from '../dom.js';
import { showStep, setNavStep } from '../nav.js';
import { ALL_FEATURES } from '../../nickelmenu/installer.js';
import { TL } from '../strings.js';
import { track } from '../analytics.js';
import { isEnabled as analyticsEnabled, track } from '../analytics.js';
export function initNickelMenu(state) {
@@ -366,6 +366,12 @@ export function initNickelMenu(state) {
track('flow-end', { result: 'nm-download' });
}
if (analyticsEnabled()) {
setupFeedback(stepNmDone, (vote) => {
track('feedback', { vote });
});
}
setNavStep(5);
showStep(stepNmDone);
}

View File

@@ -14,11 +14,11 @@
* `updatePatchCount`, and `configureFirmwareStep`.
*/
import { $, formatMB, triggerDownload, populateList } from '../dom.js';
import { $, formatMB, triggerDownload, populateList, setupFeedback } from '../dom.js';
import { showStep, setNavLabels, setNavStep } from '../nav.js';
import { KoboModels } from '../services/kobo-device.js';
import { TL } from '../strings.js';
import { track } from '../analytics.js';
import { isEnabled as analyticsEnabled, track } from '../analytics.js';
import JSZip from 'jszip';
export function initPatchesFlow(state) {
@@ -249,6 +249,12 @@ export function initPatchesFlow(state) {
downloadInstructions.hidden = true;
existingTgzWarning.hidden = true;
if (analyticsEnabled()) {
setupFeedback(stepDone, (vote) => {
track('feedback', { vote });
});
}
setNavStep(5);
showStep(stepDone);

View File

@@ -17,8 +17,8 @@ export const TL = {
STATUS: {
DEVICE_RECOGNIZED: 'Your device has been recognized. You can continue to the next step!',
NM_REMOVED_ON_REBOOT: 'NickelMenu will be removed on next reboot.',
NM_INSTALLED: 'NickelMenu has been installed on your Kobo.',
NM_DOWNLOAD_READY: 'Your NickelMenu package is ready to download.',
NM_INSTALLED: 'NickelMenu has been prepared for your Kobo. To complete the installation, follow the instructions below.',
NM_DOWNLOAD_READY: 'Your NickelMenu package is ready to download. After downloading, a list of installation steps will be displayed.',
NM_WILL_BE_REMOVED: 'NickelMenu will be updated and marked for removal. It will uninstall itself when your Kobo reboots.',
NM_WILL_BE_INSTALLED: 'The following will be installed on your Kobo:',
NM_NICKEL_ROOT_TGZ: 'NickelMenu (KoboRoot.tgz)',