Add guided onboarding tour for first toolbox creation
All checks were successful
Deploy Sokko G / deploy (push) Successful in 14s

This commit is contained in:
Shinuwa 2026-08-14 13:20:47 +02:00
parent 3007aa1389
commit 4f73e0068b
20 changed files with 470 additions and 20 deletions

View file

@ -596,6 +596,8 @@ export function validateSiteContent(site) {
}
});
assertNonEmptyString(site, "home.onboarding.primaryAction");
const onboardingCards = valueAt(site, "home.onboarding.cards");
assert.ok(Array.isArray(onboardingCards), "home.onboarding.cards must be an array");
assert.ok(onboardingCards.length >= 2, "home.onboarding.cards must contain at least 2 items");
@ -629,6 +631,35 @@ export function validateSiteContent(site) {
assertNonEmptyString({ slide }, "slide.text");
});
const toolboxCreationTemplate = valueAt(site, "toolboxes.creationTemplate");
assert.equal(typeof toolboxCreationTemplate, "object", "toolboxes.creationTemplate must be an object");
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.notepad.title");
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.notepad.text");
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.notepad.html");
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.links.moduleTitle");
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.links.title");
const toolboxTutorial = valueAt(site, "toolboxes.tutorial");
assert.equal(typeof toolboxTutorial, "object", "toolboxes.tutorial must be an object");
assertNonEmptyString({ toolboxTutorial }, "toolboxTutorial.eyebrow");
assertNonEmptyString({ toolboxTutorial }, "toolboxTutorial.title");
assertNonEmptyString({ toolboxTutorial }, "toolboxTutorial.text");
assertNonEmptyString({ toolboxTutorial }, "toolboxTutorial.dismissLabel");
assertNonEmptyString({ toolboxTutorial }, "toolboxTutorial.nextLabel");
assertNonEmptyString({ toolboxTutorial }, "toolboxTutorial.doneLabel");
assert.ok(Array.isArray(toolboxTutorial.items), "toolboxes.tutorial.items must be an array");
assert.ok(toolboxTutorial.items.length >= 4, "toolboxes.tutorial.items must contain at least 4 items");
toolboxTutorial.items.forEach((item, index) => {
assertNonEmptyString({ item }, "item.target");
assertNonEmptyString({ item }, "item.icon");
assertNonEmptyString({ item }, "item.title");
assertNonEmptyString({ item }, "item.text");
if (item.placement) {
assert.ok(["above", "below", "right"].includes(item.placement), "item.placement must be above, below or right");
}
assert.ok(index < 6, "toolboxes.tutorial.items should stay compact");
});
const lines = valueAt(site, "home.origin.lines");
assert.ok(Array.isArray(lines), "home.origin.lines must be an array");
assert.ok(lines.length >= 2, "home.origin.lines must contain at least 2 items");

View file

@ -64,9 +64,12 @@ test("vite entrypoint and app shell are wired", async () => {
assert.match(homePage, /export function HomePage/);
assert.match(homePage, /HomeOnboardingSection/);
assert.match(homePage, /import\.meta\.env\.DEV \|\| toolboxes\.length === 0/);
assert.match(homePage, /setCreateModal\(\{ tutorial: true \}\)/);
assert.match(homePage, /dragon-home\.png/);
assert.match(homeOnboarding, /export function HomeOnboardingSection/);
assert.match(homeOnboarding, /prefers-reduced-motion: reduce/);
assert.match(homeOnboarding, /onCreateToolbox/);
assert.match(homeOnboarding, /content\.primaryAction/);
assert.match(homeOnboarding, /content\.sliderTitle/);
assert.match(homeOnboarding, /home-onboarding-dots/);
assert.match(aboutPage, /export function AboutPage/);

View file

@ -21,6 +21,7 @@ test("toolbox storage, cards and pages are wired", async () => {
const indexedToolboxesHook = await readFile("website/src/features/toolboxes/storage/useIndexedToolboxes.js", "utf8");
const storageQuota = await readFile("website/src/components/StorageQuota.jsx", "utf8");
const importButton = await readFile("website/src/components/ImportButton.jsx", "utf8");
const guidedTooltipTour = await readFile("website/src/components/GuidedTooltipTour.jsx", "utf8");
const reorderHook = await readFile("website/src/hooks/usePointerReorder.js", "utf8");
const groupedReorderHook = await readFile("website/src/hooks/useGroupedReorder.js", "utf8");
const inlineEditHook = await readFile("website/src/hooks/useInlineEdit.js", "utf8");
@ -34,6 +35,10 @@ test("toolbox storage, cards and pages are wired", async () => {
assert.match(toolboxActions, /export function useToolboxActions/);
assert.match(toolboxActions, /importAllToolboxesPayload/);
assert.match(toolboxActions, /async function addImageFiles/);
assert.match(toolboxActions, /creationTemplate/);
assert.match(toolboxActions, /type: "notepad"/);
assert.match(toolboxActions, /type: "links"/);
assert.match(toolboxActions, /#\/library/);
assert.match(`${source}\n${toolboxActions}`, /features\/toolboxes\/storage\/toolboxStorage\.js/);
assert.match(toolboxStorage, /TOOLBOX_ICON_FILES/);
assert.match(toolboxStorage, /export function normalizeToolboxIcon/);
@ -85,6 +90,14 @@ test("toolbox storage, cards and pages are wired", async () => {
assert.match(toolboxPages, /moduleColumns/);
assert.match(toolboxPages, /normalizeCombosData/);
assert.match(toolboxPages, /function ToolboxView/);
assert.match(toolboxPages, /GuidedTooltipTour/);
assert.match(toolboxPages, /data-toolbox-tutorial-target/);
assert.match(guidedTooltipTour, /document\.querySelector/);
assert.match(guidedTooltipTour, /--tutorial-arrow-left/);
assert.match(guidedTooltipTour, /--tutorial-arrow-top/);
assert.match(guidedTooltipTour, /data-placement/);
assert.match(toolboxPages, /toolbox\.tutorial === true/);
assert.match(toolboxPages, /tutorial: false/);
assert.doesNotMatch(toolboxPages, /usePointerReorder/);
assert.match(storageQuota, /export function StorageQuota/);
assert.match(storageQuota, /role="progressbar"/);