add multi-page notepad and memos toolbox tool
All checks were successful
Deploy Sokko G / deploy (push) Successful in 16s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 16s
This commit is contained in:
parent
fcabbe8029
commit
6125336338
33 changed files with 3787 additions and 138 deletions
|
|
@ -130,6 +130,12 @@ export function validateSiteContent(site) {
|
|||
"toolboxes.storageHelp.title",
|
||||
"toolboxes.storageHelp.text",
|
||||
"toolboxes.modules.notepad.placeholder",
|
||||
"toolboxes.modules.notepad.pagesMenuLabel",
|
||||
"toolboxes.modules.notepad.pagesToggleLabel",
|
||||
"toolboxes.modules.notepad.pagesToggleText",
|
||||
"toolboxes.modules.notepad.addPageLabel",
|
||||
"toolboxes.modules.notepad.renamePageLabel",
|
||||
"toolboxes.modules.notepad.deletePageLabel",
|
||||
"toolboxes.modules.notepad.toolbarLabel",
|
||||
"toolboxes.modules.notepad.textFormatLabel",
|
||||
"toolboxes.modules.notepad.boldTitle",
|
||||
|
|
@ -167,6 +173,28 @@ export function validateSiteContent(site) {
|
|||
"toolboxes.modules.notepad.exportSuccess",
|
||||
"toolboxes.modules.notepad.importError",
|
||||
"toolboxes.modules.notepad.exportInfo",
|
||||
"toolboxes.modules.memos.defaultText",
|
||||
"toolboxes.modules.memos.placeholder",
|
||||
"toolboxes.modules.memos.addButton",
|
||||
"toolboxes.modules.memos.emptyLabel",
|
||||
"toolboxes.modules.memos.editLabel",
|
||||
"toolboxes.modules.memos.deleteTitle",
|
||||
"toolboxes.modules.memos.colorLabel",
|
||||
"toolboxes.modules.memos.reorderTitle",
|
||||
"toolboxes.modules.memos.tickerLabel",
|
||||
"toolboxes.modules.memos.hideTickerTitle",
|
||||
"toolboxes.modules.memos.showTickerTitle",
|
||||
"toolboxes.modules.memos.importPlaceholder",
|
||||
"toolboxes.modules.memos.importOpenButton",
|
||||
"toolboxes.modules.memos.exportOpenButton",
|
||||
"toolboxes.modules.memos.importModalTitle",
|
||||
"toolboxes.modules.memos.exportModalTitle",
|
||||
"toolboxes.modules.memos.importButton",
|
||||
"toolboxes.modules.memos.exportButton",
|
||||
"toolboxes.modules.memos.importSuccess",
|
||||
"toolboxes.modules.memos.exportSuccess",
|
||||
"toolboxes.modules.memos.importError",
|
||||
"toolboxes.modules.memos.exportInfo",
|
||||
"toolboxes.modules.checklist.itemPlaceholder",
|
||||
"toolboxes.modules.checklist.sectionPlaceholder",
|
||||
"toolboxes.modules.checklist.quantityLabel",
|
||||
|
|
@ -621,7 +649,7 @@ export function validateSiteContent(site) {
|
|||
});
|
||||
|
||||
const libraryToolDocs = valueAt(site, "library.toolDocs");
|
||||
["notepad", "checklist", "counters", "images", "imageAnnotation", "links", "calculator", "table", "goalTree", "timer", "calendar", "taskPlanner", "combos", "equipmentPlanner"].forEach((toolType) => {
|
||||
["memos", "notepad", "checklist", "counters", "images", "imageAnnotation", "links", "calculator", "table", "goalTree", "timer", "calendar", "taskPlanner", "combos", "equipmentPlanner"].forEach((toolType) => {
|
||||
const docs = libraryToolDocs?.[toolType];
|
||||
assert.equal(typeof docs, "object", `library.toolDocs.${toolType} must be an object`);
|
||||
assert.ok(Array.isArray(docs.controls), `library.toolDocs.${toolType}.controls must be an array`);
|
||||
|
|
@ -772,9 +800,8 @@ export function validateSiteContent(site) {
|
|||
|
||||
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.memos.title");
|
||||
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.memos.text");
|
||||
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.links.moduleTitle");
|
||||
assertNonEmptyString({ toolboxCreationTemplate }, "toolboxCreationTemplate.links.title");
|
||||
|
||||
|
|
@ -834,7 +861,7 @@ export function validateLibraryData(payload) {
|
|||
assert.deepEqual(new Set(twoColumnIds), moduleIds, "library.toolbox.moduleOrder.two must contain every module exactly once");
|
||||
assert.equal(twoColumnIds.length, moduleIds.size, "library.toolbox.moduleOrder.two must not contain duplicate modules");
|
||||
|
||||
["notepad", "checklist", "images", "links", "counters", "combos", "calculator", "table", "goalTree", "timer", "calendar", "taskPlanner", "equipmentPlanner", "imageAnnotation"].forEach((type) => {
|
||||
["memos", "notepad", "checklist", "images", "links", "counters", "combos", "calculator", "table", "goalTree", "timer", "calendar", "taskPlanner", "equipmentPlanner", "imageAnnotation"].forEach((type) => {
|
||||
assert.ok(payload.toolbox.modules.some((module) => module.type === type), `library must include a ${type} example`);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ test("toolbox storage, cards and pages are wired", async () => {
|
|||
assert.match(toolboxActions, /importAllToolboxesPayload/);
|
||||
assert.match(toolboxActions, /async function addImageFiles/);
|
||||
assert.match(toolboxActions, /creationTemplate/);
|
||||
assert.match(toolboxActions, /type: "notepad"/);
|
||||
assert.match(toolboxActions, /type: "memos"/);
|
||||
assert.match(toolboxActions, /type: "links"/);
|
||||
assert.match(toolboxActions, /#\/library/);
|
||||
assert.match(`${source}\n${toolboxActions}`, /features\/toolboxes\/storage\/toolboxStorage\.js/);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { getMonthOccurrenceSegments, getWeekGridLayout, getWeekMinutePosition, l
|
|||
import { appendChecklistItems, moveChecklistItem, moveChecklistItemToCategory, renameChecklistSection } from "../website/src/features/toolboxes/modules/checklistUtils.js";
|
||||
import { formatUpdatedAt, isHtmlEmpty, queryBlockFormat, queryCommandState } from "../website/src/features/toolboxes/modules/notepadUtils.js";
|
||||
import { getTimePatternRecurrenceMs, getTimePatternTargetMs } from "../website/src/features/toolboxes/modules/timerUtils.js";
|
||||
import { compactModuleDataForStorage, createToolboxExportPayload, normalizeCalculatorData, normalizeChecklistData, normalizeCombosData, normalizeCountersData, normalizeEquipmentPlannerData, normalizeGoalTreeData, normalizeImageAnnotationData, normalizeLinksData, normalizeModuleOrder, normalizeNotepadData, normalizeTableData, normalizeTaskPlannerData, normalizeTimerData, normalizeToolbox, normalizeUrl, summarizeEquipmentPlannerData } from "../website/src/features/toolboxes/storage/toolboxStorage.js";
|
||||
import { compactModuleDataForStorage, createToolboxExportPayload, normalizeCalculatorData, normalizeChecklistData, normalizeCombosData, normalizeCountersData, normalizeEquipmentPlannerData, normalizeGoalTreeData, normalizeImageAnnotationData, normalizeLinksData, normalizeMemosData, normalizeModuleOrder, normalizeNotepadData, normalizeTableData, normalizeTaskPlannerData, normalizeTimerData, normalizeToolbox, normalizeUrl, summarizeEquipmentPlannerData } from "../website/src/features/toolboxes/storage/toolboxStorage.js";
|
||||
import { applyGroupedReorderOperation, completeGroupOrder, getBoundaryItemId, getGroupedEntries, moveGroupOrder, moveGroupOrderToEnd, moveGroupOrderToStart, moveItem, moveItemGroup } from "../website/src/hooks/useGroupedReorder.js";
|
||||
|
||||
function createTextImportContext() {
|
||||
|
|
@ -20,6 +20,7 @@ function createTextImportContext() {
|
|||
return {
|
||||
uid: (prefix) => `${prefix}-${index += 1}`,
|
||||
normalizeNotepadData,
|
||||
normalizeMemosData,
|
||||
normalizeChecklistData,
|
||||
normalizeLinksData,
|
||||
normalizeCountersData,
|
||||
|
|
@ -124,6 +125,11 @@ test("text exchange round trips simple toolbox modules and resets checklist prog
|
|||
const countersImport = importModuleText("counters", exportModuleText("counters", counters), context);
|
||||
assert.equal(countersImport.ok, true);
|
||||
assert.deepEqual(countersImport.data.counters.map((counter) => [counter.label, counter.value]), [["Win", 12], ["Loss", -2]]);
|
||||
|
||||
const memos = normalizeMemosData({ items: [{ id: "m1", text: "Route", color: "#f6c453" }, { id: "m2", text: "Potion", color: "#22d3ee" }] });
|
||||
const memosImport = importModuleText("memos", exportModuleText("memos", memos), context);
|
||||
assert.equal(memosImport.ok, true);
|
||||
assert.deepEqual(memosImport.data.items.map((memo) => [memo.text, memo.color]), [["Route", "#f6c453"], ["Potion", "#22d3ee"]]);
|
||||
});
|
||||
|
||||
test("notepad helpers keep empty html and invalid command states stable", () => {
|
||||
|
|
@ -952,8 +958,8 @@ test("notepad data migrates text, sanitizes html and compacts drawings", () => {
|
|||
drawingMode: "temporary",
|
||||
drawings: { strokes: normalized.drawings.strokes }
|
||||
});
|
||||
assert.equal(compactTemporary.drawings, undefined);
|
||||
assert.equal(compactTemporary.drawingMode, undefined);
|
||||
assert.equal(compactTemporary.pages[0].drawings, undefined);
|
||||
assert.equal(compactTemporary.pages[0].drawingMode, undefined);
|
||||
|
||||
const compactPermanent = compactModuleDataForStorage("notepad", {
|
||||
html: "<p>Note</p>",
|
||||
|
|
@ -962,9 +968,9 @@ test("notepad data migrates text, sanitizes html and compacts drawings", () => {
|
|||
drawingMode: "permanent",
|
||||
drawings: normalized.drawings
|
||||
});
|
||||
assert.equal(compactPermanent.updatedAt, undefined);
|
||||
assert.equal(compactPermanent.drawingMode, "permanent");
|
||||
assert.equal(compactPermanent.drawings.strokes.length, 1);
|
||||
assert.equal(compactPermanent.pages[0].updatedAt, undefined);
|
||||
assert.equal(compactPermanent.pages[0].drawingMode, "permanent");
|
||||
assert.equal(compactPermanent.pages[0].drawings.strokes.length, 1);
|
||||
});
|
||||
|
||||
test("image annotation storage keeps drawing strokes as percent coordinates", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue