diff --git a/sample-vault/.obsidian/plugins/leif/main.js b/sample-vault/.obsidian/plugins/leif/main.js index fa2e114..1ff2287 100644 --- a/sample-vault/.obsidian/plugins/leif/main.js +++ b/sample-vault/.obsidian/plugins/leif/main.js @@ -445,6 +445,18 @@ var DomHelpers = class { row.append(labelEl, valueEl); return row; } + /** + * Creates a compact label/value metric for scannable list rows. + */ + static createMetric(label, value) { + const metric = this.createElement("div", "leif-metric"); + const labelEl = this.createElement("span", "leif-metric-label"); + labelEl.textContent = label; + const valueEl = this.createElement("span", "leif-metric-value"); + valueEl.textContent = value; + metric.append(labelEl, valueEl); + return metric; + } /** * Creates a table with headers and rows. * @param headers - Column headers @@ -2702,30 +2714,29 @@ var ContestsTab = class { }) ); } - const header = DomHelpers.createElement("div", "leif-contest-card-header"); const titleGroup = DomHelpers.createElement("div", "leif-contest-card-title-group"); const title = DomHelpers.createElement("strong", "leif-contest-card-title"); title.textContent = contest.name; const status = DomHelpers.createElement("span", isActive ? "leif-status-active" : "leif-status-inactive"); status.textContent = isActive ? "Estudando agora" : "Guardado"; titleGroup.append(title, status); - header.append(titleGroup, actions); const notes = DomHelpers.createParagraph(contest.wall.notes?.trim() || "Sem notas ainda."); + notes.classList.add("leif-contest-notes"); const meta = DomHelpers.createElement("div", "leif-contest-meta"); - meta.append(this.renderMetaChip("ID", contest.id)); + meta.append(DomHelpers.createMetric("ID", contest.id)); if (contest.examPlan?.examDate) { - meta.append(this.renderMetaChip("Prova", contest.examPlan.examDate)); + meta.append(DomHelpers.createMetric("Prova", contest.examPlan.examDate)); } if (contest.examPlan?.board) { - meta.append(this.renderMetaChip("Banca", contest.examPlan.board)); + meta.append(DomHelpers.createMetric("Banca", contest.examPlan.board)); } if (contest.examPlan?.weeklyStudyHours !== void 0) { - meta.append(this.renderMetaChip("Carga", `${contest.examPlan.weeklyStudyHours} h/semana`)); + meta.append(DomHelpers.createMetric("Carga", `${contest.examPlan.weeklyStudyHours} h/semana`)); } if (contest.examPlan?.weeklyQuestionGoal !== void 0) { - meta.append(this.renderMetaChip("Meta", `${contest.examPlan.weeklyQuestionGoal} quest\xF5es/semana`)); + meta.append(DomHelpers.createMetric("Meta", `${contest.examPlan.weeklyQuestionGoal} quest\xF5es/semana`)); } - card.append(header, notes, meta); + card.append(titleGroup, meta, actions, notes); return card; } renderEditableCard(contest, data) { @@ -2832,15 +2843,6 @@ var ContestsTab = class { ); return form; } - renderMetaChip(label, value) { - const chip = DomHelpers.createElement("span", "leif-next-activity-chip"); - const labelEl = DomHelpers.createElement("span", "leif-next-activity-chip-label"); - labelEl.textContent = `${label}:`; - const valueEl = DomHelpers.createElement("span", "leif-next-activity-chip-value"); - valueEl.textContent = value; - chip.append(labelEl, valueEl); - return chip; - } readOptionalNumber(value) { if (!value.trim()) { return void 0; @@ -2946,8 +2948,8 @@ var CycleTab = class { ); const meta = DomHelpers.createElement("div", "leif-cycle-card-meta"); meta.append( - this.renderCycleMetric("Tempo", `${subject.plannedStudyMinutes} min`), - this.renderCycleMetric("Etapa", subject.currentStage ?? "\u2014") + DomHelpers.createMetric("Tempo", `${subject.plannedStudyMinutes} min`), + DomHelpers.createMetric("Etapa", subject.currentStage ?? "\u2014") ); card.append(titleGroup, meta, actions); return card; @@ -3083,15 +3085,6 @@ var CycleTab = class { chip.append(labelEl, valueEl); return chip; } - renderCycleMetric(label, value) { - const metric = DomHelpers.createElement("div", "leif-cycle-metric"); - const labelEl = DomHelpers.createElement("span", "leif-cycle-metric-label"); - labelEl.textContent = label; - const valueEl = DomHelpers.createElement("span", "leif-cycle-metric-value"); - valueEl.textContent = value; - metric.append(labelEl, valueEl); - return metric; - } async moveSubject(subjects, sourceIndex, targetIndex, activeContestId) { try { if (!activeContestId) { @@ -3341,13 +3334,7 @@ var DashboardTab = class { return panel; } renderActivityMeta(label, value) { - const item = DomHelpers.createElement("span", "leif-next-activity-chip"); - const labelEl = DomHelpers.createElement("span", "leif-next-activity-chip-label"); - labelEl.textContent = `${label}:`; - const valueEl = DomHelpers.createElement("span", "leif-next-activity-chip-value"); - valueEl.textContent = value; - item.append(labelEl, valueEl); - return item; + return DomHelpers.createMetric(label, value); } formatDaysUntilExam(examDate) { const now = /* @__PURE__ */ new Date(); @@ -5057,17 +5044,26 @@ var WallTab = class { } else { const subjectMap = new Map(data.subjects.map((s) => [s.id, s.name])); const itemMap = new Map(data.studyItems.map((item) => [item.id, item.title])); - card.appendChild( - DomHelpers.createTable( - ["Mat\xE9ria", "Peso", "Pontua\xE7\xE3o", "Itens alvo"], - activeContest.wall.subjectSnapshots.map((snapshot) => [ - subjectMap.get(snapshot.subjectId) ?? snapshot.subjectId, - snapshot.weight !== void 0 ? String(snapshot.weight) : "\u2014", - snapshot.score !== void 0 ? String(snapshot.score) : "\u2014", + const list = DomHelpers.createElement("div", "leif-wall-snapshot-list"); + activeContest.wall.subjectSnapshots.forEach((snapshot) => { + const row = DomHelpers.createElement("section", "leif-wall-snapshot-card"); + const titleGroup = DomHelpers.createElement("div", "leif-wall-snapshot-title-group"); + const title = DomHelpers.createElement("strong", "leif-wall-snapshot-title"); + title.textContent = subjectMap.get(snapshot.subjectId) ?? snapshot.subjectId; + titleGroup.appendChild(title); + const metrics = DomHelpers.createElement("div", "leif-wall-snapshot-meta"); + metrics.append( + DomHelpers.createMetric("Peso", snapshot.weight !== void 0 ? String(snapshot.weight) : "\u2014"), + DomHelpers.createMetric("Pontua\xE7\xE3o", snapshot.score !== void 0 ? String(snapshot.score) : "\u2014"), + DomHelpers.createMetric( + "Itens alvo", snapshot.targetItems?.map((itemId) => itemMap.get(itemId) ?? itemId).join(", ") ?? "\u2014" - ]) - ) - ); + ) + ); + row.append(titleGroup, metrics); + list.appendChild(row); + }); + card.appendChild(list); } return card; } diff --git a/sample-vault/.obsidian/plugins/leif/styles.css b/sample-vault/.obsidian/plugins/leif/styles.css index 1353e62..6e1e397 100644 --- a/sample-vault/.obsidian/plugins/leif/styles.css +++ b/sample-vault/.obsidian/plugins/leif/styles.css @@ -268,6 +268,25 @@ text-align: right; } +.leif-metric { + display: flex; + flex-direction: column; + gap: var(--size-2-1); + min-width: 0; +} + +.leif-metric-label { + color: var(--text-muted); + font-size: 12px; + line-height: 1.2; +} + +.leif-metric-value { + color: var(--text-normal); + line-height: 1.3; + overflow-wrap: anywhere; +} + .leif-toolbar { display: flex; gap: var(--size-4-3); @@ -567,23 +586,10 @@ min-width: 0; } -.leif-cycle-metric { - display: flex; - flex-direction: column; - gap: var(--size-2-1); - min-width: 0; -} - -.leif-cycle-metric-label { - color: var(--text-muted); - font-size: 12px; - line-height: 1.2; -} - -.leif-cycle-metric-value { - color: var(--text-normal); - line-height: 1.3; - overflow-wrap: anywhere; +.leif-cycle-card > .leif-inline-actions, +.leif-contest-card > .leif-inline-actions { + justify-content: flex-end; + align-items: center; } .leif-cycle-edit-form { @@ -599,9 +605,10 @@ } .leif-contest-card { - display: flex; - flex-direction: column; - gap: var(--size-4-3); + display: grid; + grid-template-columns: minmax(240px, 1.2fr) minmax(260px, 1fr) auto; + align-items: center; + gap: var(--size-4-4); padding: var(--size-4-3) 0; border-top: 1px solid var(--leif-border); } @@ -632,10 +639,14 @@ } .leif-contest-meta { - display: flex; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: var(--size-4-3); - flex-wrap: wrap; - color: var(--text-muted); + min-width: 0; +} + +.leif-contest-notes { + grid-column: 1 / -1; } .leif-contest-edit-form { @@ -801,6 +812,37 @@ align-self: flex-end; } +.leif-wall-snapshot-list { + display: flex; + flex-direction: column; +} + +.leif-wall-snapshot-card { + display: grid; + grid-template-columns: minmax(220px, 0.9fr) minmax(300px, 1.4fr); + align-items: start; + gap: var(--size-4-4); + padding: var(--size-4-3) 0; + border-top: 1px solid var(--leif-border); +} + +.leif-wall-snapshot-card:first-child { + border-top: 0; + padding-top: 0; +} + +.leif-wall-snapshot-title { + font-size: var(--font-ui-medium); + line-height: 1.3; + overflow-wrap: anywhere; +} + +.leif-wall-snapshot-meta { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: var(--size-4-3); +} + /* Dashboard next activity */ .leif-next-activity { display: flex; @@ -827,6 +869,11 @@ justify-content: center; } +.leif-next-activity-meta .leif-metric { + align-items: flex-end; + text-align: right; +} + .leif-next-activity-label { font-size: 13px; color: var(--text-muted); @@ -1067,6 +1114,11 @@ align-items: flex-start; } + .leif-next-activity-meta .leif-metric { + align-items: flex-start; + text-align: left; + } + .leif-next-activity-chip { justify-content: flex-start; } @@ -1079,13 +1131,17 @@ flex-direction: column; } + .leif-contest-card, .leif-cycle-card { grid-template-columns: 1fr; gap: var(--size-4-3); } + .leif-contest-meta, .leif-cycle-card-meta, - .leif-cycle-edit-form { + .leif-cycle-edit-form, + .leif-wall-snapshot-card, + .leif-wall-snapshot-meta { grid-template-columns: 1fr; } diff --git a/src/ui/view/components/ContestsTab.ts b/src/ui/view/components/ContestsTab.ts index 2f6eab9..6af9d85 100644 --- a/src/ui/view/components/ContestsTab.ts +++ b/src/ui/view/components/ContestsTab.ts @@ -138,32 +138,31 @@ export class ContestsTab { ); } - const header = DomHelpers.createElement("div", "leif-contest-card-header"); const titleGroup = DomHelpers.createElement("div", "leif-contest-card-title-group"); const title = DomHelpers.createElement("strong", "leif-contest-card-title"); title.textContent = contest.name; const status = DomHelpers.createElement("span", isActive ? "leif-status-active" : "leif-status-inactive"); status.textContent = isActive ? "Estudando agora" : "Guardado"; titleGroup.append(title, status); - header.append(titleGroup, actions); const notes = DomHelpers.createParagraph(contest.wall.notes?.trim() || "Sem notas ainda."); + notes.classList.add("leif-contest-notes"); const meta = DomHelpers.createElement("div", "leif-contest-meta"); - meta.append(this.renderMetaChip("ID", contest.id)); + meta.append(DomHelpers.createMetric("ID", contest.id)); if (contest.examPlan?.examDate) { - meta.append(this.renderMetaChip("Prova", contest.examPlan.examDate)); + meta.append(DomHelpers.createMetric("Prova", contest.examPlan.examDate)); } if (contest.examPlan?.board) { - meta.append(this.renderMetaChip("Banca", contest.examPlan.board)); + meta.append(DomHelpers.createMetric("Banca", contest.examPlan.board)); } if (contest.examPlan?.weeklyStudyHours !== undefined) { - meta.append(this.renderMetaChip("Carga", `${contest.examPlan.weeklyStudyHours} h/semana`)); + meta.append(DomHelpers.createMetric("Carga", `${contest.examPlan.weeklyStudyHours} h/semana`)); } if (contest.examPlan?.weeklyQuestionGoal !== undefined) { - meta.append(this.renderMetaChip("Meta", `${contest.examPlan.weeklyQuestionGoal} questões/semana`)); + meta.append(DomHelpers.createMetric("Meta", `${contest.examPlan.weeklyQuestionGoal} questões/semana`)); } - card.append(header, notes, meta); + card.append(titleGroup, meta, actions, notes); return card; } @@ -285,16 +284,6 @@ export class ContestsTab { return form; } - private renderMetaChip(label: string, value: string): HTMLElement { - const chip = DomHelpers.createElement("span", "leif-next-activity-chip"); - const labelEl = DomHelpers.createElement("span", "leif-next-activity-chip-label"); - labelEl.textContent = `${label}:`; - const valueEl = DomHelpers.createElement("span", "leif-next-activity-chip-value"); - valueEl.textContent = value; - chip.append(labelEl, valueEl); - return chip; - } - private readOptionalNumber(value: string): number | undefined { if (!value.trim()) { return undefined; diff --git a/src/ui/view/components/CycleTab.ts b/src/ui/view/components/CycleTab.ts index 8e23981..160877a 100644 --- a/src/ui/view/components/CycleTab.ts +++ b/src/ui/view/components/CycleTab.ts @@ -139,8 +139,8 @@ export class CycleTab { const meta = DomHelpers.createElement("div", "leif-cycle-card-meta"); meta.append( - this.renderCycleMetric("Tempo", `${subject.plannedStudyMinutes} min`), - this.renderCycleMetric("Etapa", subject.currentStage ?? "—") + DomHelpers.createMetric("Tempo", `${subject.plannedStudyMinutes} min`), + DomHelpers.createMetric("Etapa", subject.currentStage ?? "—") ); card.append(titleGroup, meta, actions); @@ -302,16 +302,6 @@ export class CycleTab { return chip; } - private renderCycleMetric(label: string, value: string): HTMLElement { - const metric = DomHelpers.createElement("div", "leif-cycle-metric"); - const labelEl = DomHelpers.createElement("span", "leif-cycle-metric-label"); - labelEl.textContent = label; - const valueEl = DomHelpers.createElement("span", "leif-cycle-metric-value"); - valueEl.textContent = value; - metric.append(labelEl, valueEl); - return metric; - } - private async moveSubject( subjects: Subject[], sourceIndex: number, diff --git a/src/ui/view/components/DashboardTab.ts b/src/ui/view/components/DashboardTab.ts index cb9d00e..dfe6a4b 100644 --- a/src/ui/view/components/DashboardTab.ts +++ b/src/ui/view/components/DashboardTab.ts @@ -216,13 +216,7 @@ export class DashboardTab { } private renderActivityMeta(label: string, value: string): HTMLElement { - const item = DomHelpers.createElement("span", "leif-next-activity-chip"); - const labelEl = DomHelpers.createElement("span", "leif-next-activity-chip-label"); - labelEl.textContent = `${label}:`; - const valueEl = DomHelpers.createElement("span", "leif-next-activity-chip-value"); - valueEl.textContent = value; - item.append(labelEl, valueEl); - return item; + return DomHelpers.createMetric(label, value); } private formatDaysUntilExam(examDate: string): string { diff --git a/src/ui/view/components/WallTab.ts b/src/ui/view/components/WallTab.ts index ea0eecc..4beade9 100644 --- a/src/ui/view/components/WallTab.ts +++ b/src/ui/view/components/WallTab.ts @@ -159,17 +159,28 @@ export class WallTab { } else { const subjectMap = new Map(data.subjects.map((s) => [s.id, s.name])); const itemMap = new Map(data.studyItems.map((item) => [item.id, item.title])); - card.appendChild( - DomHelpers.createTable( - ["Matéria", "Peso", "Pontuação", "Itens alvo"], - activeContest.wall.subjectSnapshots.map((snapshot) => [ - subjectMap.get(snapshot.subjectId) ?? snapshot.subjectId, - snapshot.weight !== undefined ? String(snapshot.weight) : "—", - snapshot.score !== undefined ? String(snapshot.score) : "—", + const list = DomHelpers.createElement("div", "leif-wall-snapshot-list"); + activeContest.wall.subjectSnapshots.forEach((snapshot) => { + const row = DomHelpers.createElement("section", "leif-wall-snapshot-card"); + const titleGroup = DomHelpers.createElement("div", "leif-wall-snapshot-title-group"); + const title = DomHelpers.createElement("strong", "leif-wall-snapshot-title"); + title.textContent = subjectMap.get(snapshot.subjectId) ?? snapshot.subjectId; + titleGroup.appendChild(title); + + const metrics = DomHelpers.createElement("div", "leif-wall-snapshot-meta"); + metrics.append( + DomHelpers.createMetric("Peso", snapshot.weight !== undefined ? String(snapshot.weight) : "—"), + DomHelpers.createMetric("Pontuação", snapshot.score !== undefined ? String(snapshot.score) : "—"), + DomHelpers.createMetric( + "Itens alvo", snapshot.targetItems?.map((itemId) => itemMap.get(itemId) ?? itemId).join(", ") ?? "—" - ]) - ) - ); + ) + ); + + row.append(titleGroup, metrics); + list.appendChild(row); + }); + card.appendChild(list); } return card; } diff --git a/src/ui/view/shared/DomHelpers.ts b/src/ui/view/shared/DomHelpers.ts index 1d8637e..b53392a 100644 --- a/src/ui/view/shared/DomHelpers.ts +++ b/src/ui/view/shared/DomHelpers.ts @@ -223,6 +223,19 @@ export class DomHelpers { return row; } + /** + * Creates a compact label/value metric for scannable list rows. + */ + static createMetric(label: string, value: string): HTMLElement { + const metric = this.createElement("div", "leif-metric"); + const labelEl = this.createElement("span", "leif-metric-label"); + labelEl.textContent = label; + const valueEl = this.createElement("span", "leif-metric-value"); + valueEl.textContent = value; + metric.append(labelEl, valueEl); + return metric; + } + /** * Creates a table with headers and rows. * @param headers - Column headers diff --git a/styles.css b/styles.css index 1353e62..6e1e397 100644 --- a/styles.css +++ b/styles.css @@ -268,6 +268,25 @@ text-align: right; } +.leif-metric { + display: flex; + flex-direction: column; + gap: var(--size-2-1); + min-width: 0; +} + +.leif-metric-label { + color: var(--text-muted); + font-size: 12px; + line-height: 1.2; +} + +.leif-metric-value { + color: var(--text-normal); + line-height: 1.3; + overflow-wrap: anywhere; +} + .leif-toolbar { display: flex; gap: var(--size-4-3); @@ -567,23 +586,10 @@ min-width: 0; } -.leif-cycle-metric { - display: flex; - flex-direction: column; - gap: var(--size-2-1); - min-width: 0; -} - -.leif-cycle-metric-label { - color: var(--text-muted); - font-size: 12px; - line-height: 1.2; -} - -.leif-cycle-metric-value { - color: var(--text-normal); - line-height: 1.3; - overflow-wrap: anywhere; +.leif-cycle-card > .leif-inline-actions, +.leif-contest-card > .leif-inline-actions { + justify-content: flex-end; + align-items: center; } .leif-cycle-edit-form { @@ -599,9 +605,10 @@ } .leif-contest-card { - display: flex; - flex-direction: column; - gap: var(--size-4-3); + display: grid; + grid-template-columns: minmax(240px, 1.2fr) minmax(260px, 1fr) auto; + align-items: center; + gap: var(--size-4-4); padding: var(--size-4-3) 0; border-top: 1px solid var(--leif-border); } @@ -632,10 +639,14 @@ } .leif-contest-meta { - display: flex; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: var(--size-4-3); - flex-wrap: wrap; - color: var(--text-muted); + min-width: 0; +} + +.leif-contest-notes { + grid-column: 1 / -1; } .leif-contest-edit-form { @@ -801,6 +812,37 @@ align-self: flex-end; } +.leif-wall-snapshot-list { + display: flex; + flex-direction: column; +} + +.leif-wall-snapshot-card { + display: grid; + grid-template-columns: minmax(220px, 0.9fr) minmax(300px, 1.4fr); + align-items: start; + gap: var(--size-4-4); + padding: var(--size-4-3) 0; + border-top: 1px solid var(--leif-border); +} + +.leif-wall-snapshot-card:first-child { + border-top: 0; + padding-top: 0; +} + +.leif-wall-snapshot-title { + font-size: var(--font-ui-medium); + line-height: 1.3; + overflow-wrap: anywhere; +} + +.leif-wall-snapshot-meta { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: var(--size-4-3); +} + /* Dashboard next activity */ .leif-next-activity { display: flex; @@ -827,6 +869,11 @@ justify-content: center; } +.leif-next-activity-meta .leif-metric { + align-items: flex-end; + text-align: right; +} + .leif-next-activity-label { font-size: 13px; color: var(--text-muted); @@ -1067,6 +1114,11 @@ align-items: flex-start; } + .leif-next-activity-meta .leif-metric { + align-items: flex-start; + text-align: left; + } + .leif-next-activity-chip { justify-content: flex-start; } @@ -1079,13 +1131,17 @@ flex-direction: column; } + .leif-contest-card, .leif-cycle-card { grid-template-columns: 1fr; gap: var(--size-4-3); } + .leif-contest-meta, .leif-cycle-card-meta, - .leif-cycle-edit-form { + .leif-cycle-edit-form, + .leif-wall-snapshot-card, + .leif-wall-snapshot-meta { grid-template-columns: 1fr; } diff --git a/tests/ui/LeifView.test.ts b/tests/ui/LeifView.test.ts index e644c44..a595a3e 100644 --- a/tests/ui/LeifView.test.ts +++ b/tests/ui/LeifView.test.ts @@ -313,7 +313,7 @@ describe("LeifView", () => { expect(cycleCards.length).toBeGreaterThanOrEqual(2); expect(cycleCards[0]?.querySelector(".leif-cycle-card-order")?.textContent).toContain("1"); expect(cycleCards[0]?.querySelector(".leif-cycle-card-title")?.textContent).toBeTruthy(); - expect(cycleCards[0]?.querySelectorAll(".leif-cycle-metric").length).toBe(2); + expect(cycleCards[0]?.querySelectorAll(".leif-metric").length).toBe(2); expect(cycleCards[0]?.querySelector(".leif-key-value")).toBeNull(); expect(cycleCards[0]?.textContent).toContain("No ciclo"); expect(cycleCards[0]?.textContent).toContain("Tempo"); @@ -510,6 +510,35 @@ describe("LeifView", () => { it("organizes the wall into clear edital, prova and notes sections", async () => { const dataStore = new InMemoryPluginDataStore(); await seedUiData(dataStore); + const data = await dataStore.load(); + const activeContest = data.contests.find((contest) => contest.id === data.activeContestId); + const subject = data.subjects[0]; + const item = data.studyItems[0]; + + if (!activeContest || !subject || !item) { + throw new Error("Seed data was not created."); + } + + const updateContestWall = new UpdateContestWallUseCase( + dataStore, + new EntityRepositoryFactory(dataStore) + ); + await updateContestWall.execute({ + contestId: activeContest.id, + wall: { + noticeLinks: activeContest.wall.noticeLinks, + examLinks: activeContest.wall.examLinks, + notes: activeContest.wall.notes, + subjectSnapshots: [ + { + subjectId: subject.id, + weight: 2, + score: 8, + targetItems: [item.id] + } + ] + } + }); const { leaf } = await openLeifView(dataStore); const wallTabButton = leaf.containerEl.querySelector("[data-tab='wall']"); @@ -531,6 +560,9 @@ describe("LeifView", () => { expect(leaf.containerEl.querySelector(".leif-wall-links")).toBeNull(); expect(leaf.containerEl.querySelector(".leif-wall-card-wide")).toBeNull(); expect(leaf.containerEl.querySelector("button.leif-wall-save")).not.toBeNull(); + expect(leaf.containerEl.querySelector(".leif-wall-snapshot-card")).not.toBeNull(); + expect(leaf.containerEl.querySelector(".leif-wall-snapshot-card .leif-metric")).not.toBeNull(); + expect(leaf.containerEl.querySelector(".leif-wall-snapshot-list table.leif-table")).toBeNull(); expect(leaf.containerEl.textContent).toContain("Salvar mural"); });