feat: add lesson difficulty indicators and improve mobile sidebar
- Add computeLessonDifficulty function to determine lesson difficulty based on selector complexity (easy/medium/hard) - Display difficulty badge with bar indicator in lesson title row - Add mobile navigation links (CSS, HTML, Tailwind) to sidebar - Add mobile auth trigger button in sidebar - Redesign settings section with card layout and native toggles - Add difficulty translations for all 6 languages - Fix module pill overflow on narrow screens
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, test, expect, vi, beforeEach } from "vitest";
|
||||
import { renderModuleList, renderLesson, renderLevelIndicator, showFeedback, clearFeedback } from "../../src/helpers/renderer.js";
|
||||
import { renderModuleList, renderLesson, renderLevelIndicator, showFeedback, clearFeedback, computeLessonDifficulty } from "../../src/helpers/renderer.js";
|
||||
|
||||
describe("Renderer Module", () => {
|
||||
beforeEach(() => {
|
||||
@@ -176,4 +176,68 @@ describe("Renderer Module", () => {
|
||||
clearFeedback();
|
||||
});
|
||||
});
|
||||
|
||||
describe("computeLessonDifficulty", () => {
|
||||
test("should return 'easy' when codePrefix contains selector", () => {
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: ".text {\n ",
|
||||
solution: "color: coral;"
|
||||
})).toBe("easy");
|
||||
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "h1, h2, h3 {\n ",
|
||||
solution: "color: steelblue;"
|
||||
})).toBe("easy");
|
||||
});
|
||||
|
||||
test("should return 'medium' for simple type selector", () => {
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: "p {\n color: steelblue;\n}"
|
||||
})).toBe("medium");
|
||||
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: "a {\n color: coral;\n}"
|
||||
})).toBe("medium");
|
||||
});
|
||||
|
||||
test("should return 'medium' for simple class selector", () => {
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: ".badge {\n background: tomato;\n}"
|
||||
})).toBe("medium");
|
||||
});
|
||||
|
||||
test("should return 'hard' for descendant selectors", () => {
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: ".nav a {\n color: white;\n}"
|
||||
})).toBe("hard");
|
||||
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: ".card p {\n font-size: 0.9rem;\n}"
|
||||
})).toBe("hard");
|
||||
});
|
||||
|
||||
test("should return 'hard' for chained class selectors", () => {
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: ".btn.primary {\n background: steelblue;\n}"
|
||||
})).toBe("hard");
|
||||
});
|
||||
|
||||
test("should return 'hard' for type+class selectors", () => {
|
||||
expect(computeLessonDifficulty({
|
||||
codePrefix: "",
|
||||
solution: "a.btn {\n text-decoration: none;\n}"
|
||||
})).toBe("hard");
|
||||
});
|
||||
|
||||
test("should handle missing fields gracefully", () => {
|
||||
expect(computeLessonDifficulty({})).toBe("medium");
|
||||
expect(computeLessonDifficulty({ codePrefix: null })).toBe("medium");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user