diff --git a/25f2fc-homework-grader/CardListing/7ef038b7-c15c-497a-b3bc-2b0042cc131b.json b/25f2fc-homework-grader/CardListing/7ef038b7-c15c-497a-b3bc-2b0042cc131b.json index 7cce3c69..aa68ec40 100644 --- a/25f2fc-homework-grader/CardListing/7ef038b7-c15c-497a-b3bc-2b0042cc131b.json +++ b/25f2fc-homework-grader/CardListing/7ef038b7-c15c-497a-b3bc-2b0042cc131b.json @@ -9,7 +9,7 @@ "type": "card", "attributes": { "name": "Homework Grader", - "summary": "The HomeworkGrader component is a comprehensive card interface designed for assessing and providing feedback on student homework assignments. It visually summarizes the overall grade, question-by-question scores, and detailed feedback, offering an interactive experience for instructors to review answers, assign grades, and monitor grading progress. The component supports multiple display formats for different device sizes, facilitates real-time grading updates, and integrates with AI-based grading skills. Its primary purpose is to streamline the grading process by presenting scores, feedback, and grading controls in an organized, adaptable layout.", + "summary": "Grading a stack of homework means reading every answer twice — once to score it, once to write feedback the student can actually learn from. Homework Grader does both in one pass: an assignment card holds your questions and each student's answers, and with a grading skill linked, one click returns an A–F grade, a score for every question, and a short written comment under each answer. Change the questions and stale grades clear themselves, so the score always matches what's on the page.\n\nOpen the demo to see it shine: History Homework shows a finished report — a 96/100 hero with a per-question score breakdown — and the Questions tab puts each answer's feedback right where the student wrote. Press Re-grade Assignment to watch the AI grade the arithmetic set live, or start from the blank assignment and type new questions and answers directly on the card.", "cardInfo": { "name": null, "notes": null, @@ -18,6 +18,26 @@ } }, "relationships": { + "images.0": { + "links": { + "self": "../Screenshots/01-hero-graded.png" + } + }, + "images.1": { + "links": { + "self": "../Screenshots/02-empty-assignment.png" + } + }, + "images.2": { + "links": { + "self": "../Screenshots/03-question-feedback.png" + } + }, + "images.3": { + "links": { + "self": "../Screenshots/04-grade-with-ai.png" + } + }, "tags.0": { "links": { "self": "../../Tag/ai" @@ -43,11 +63,6 @@ "self": "../Spec/5455e5c1-1d62-41c9-ae39-f2ff09da9b83" } }, - "images.0": { - "links": { - "self": "../Screenshots/homework-grader-screenshot.png" - } - }, "skills.0": { "links": { "self": "../Skill/dc116967-432e-4864-93aa-d7ea3f335d24" @@ -82,7 +97,12 @@ "links": { "self": "../ListingThumbnails/homeworkgrader-73e64906.png" } + }, + "examples.2": { + "links": { + "self": "../HomeworkGrader/fresh-assignment" + } } } } -} \ No newline at end of file +} diff --git a/25f2fc-homework-grader/HomeworkGrader/67432ef8-6493-4ad7-aa3f-335d24e7213f.json b/25f2fc-homework-grader/HomeworkGrader/67432ef8-6493-4ad7-aa3f-335d24e7213f.json index caa46941..8d9e2086 100644 --- a/25f2fc-homework-grader/HomeworkGrader/67432ef8-6493-4ad7-aa3f-335d24e7213f.json +++ b/25f2fc-homework-grader/HomeworkGrader/67432ef8-6493-4ad7-aa3f-335d24e7213f.json @@ -15,7 +15,12 @@ 25, 46 ], - "overallFeedback": "Excellent work! Your responses demonstrate exceptional understanding of US History with thorough analysis, specific historical examples, and clear connections between events and their impacts.\n\n**Question 1: The American Revolution (25/25 points)**\nOutstanding analysis of the American Revolution's causes. You effectively identified three major causes with specific acts and dates, provided strong justification for why taxation without representation was most significant, and made excellent connections to how these grievances shaped early American government. Your use of specific legislation (Sugar Act 1764, Stamp Act 1765, Townshend Acts 1767, Quartering Act 1765, Coercive Acts 1774) demonstrates strong factual knowledge. The connection between colonial grievances and constitutional principles — including the Third Amendment and the federal system — was very well-developed. Full marks!\n\n**Question 2: Civil War Impact (25/25 points)**\nExemplary examination of the Civil War's long-term impacts. Your response expertly covered all required elements: the immediate Reconstruction era, the shift in federal-state power, and lasting racial impacts. The specific examples (13th–15th Amendments, Freedmen's Bureau, sharecropping, Jim Crow laws) and your analysis of how these issues persisted into the Civil Rights Movement showed sophisticated historical thinking. Your note on the economic transformation from an agricultural to an industrial power was particularly insightful. Full marks!\n\n**Question 3: The Progressive Era (46/50 points)**\nVery strong evaluation of Progressive Era reforms. You identified a comprehensive range of reform categories, provided detailed analysis of two major initiatives with specific outcomes, and effectively connected these reforms to modern America. Your choices of the Pure Food and Drug Act and Women's Suffrage were well-supported with solid evidence. The connections to modern regulatory agencies (EPA, OSHA, FDA) were excellent. Minor deductions: You could have explored some limitations or unintended consequences of Progressive reforms (e.g., the exclusion of minorities from many labor protections), and discussed opposition to these reforms in greater detail.\n\n**Overall Assessment:**\nYour writing is clear, well-organized, and demonstrates an excellent command of historical chronology and causation. You consistently support arguments with specific evidence and make meaningful connections between historical events and their long-term consequences. Keep up the outstanding work!\n\n**Total Score: 96 out of 100 points (96% — A)**" + "overallFeedback": "Excellent work! Your responses demonstrate exceptional understanding of US History with thorough analysis, specific historical examples, and clear connections between events and their impacts.", + "questionFeedbacks": [ + "Outstanding analysis of the American Revolution's causes. You effectively identified three major causes with specific acts and dates, provided strong justification for why taxation without representation was most significant, and made excellent connections to how these grievances shaped early American government. Your use of specific legislation (Sugar Act 1764, Stamp Act 1765, Townshend Acts 1767, Quartering Act 1765, Coercive Acts 1774) demonstrates strong factual knowledge. The connection between colonial grievances and constitutional principles — including the Third Amendment and the federal system — was very well-developed. Full marks!", + "Exemplary examination of the Civil War's long-term impacts. Your response expertly covered all required elements: the immediate Reconstruction era, the shift in federal-state power, and lasting racial impacts. The specific examples (13th–15th Amendments, Freedmen's Bureau, sharecropping, Jim Crow laws) and your analysis of how these issues persisted into the Civil Rights Movement showed sophisticated historical thinking. Your note on the economic transformation from an agricultural to an industrial power was particularly insightful. Full marks!", + "Very strong evaluation of Progressive Era reforms. You identified a comprehensive range of reform categories, provided detailed analysis of two major initiatives with specific outcomes, and effectively connected these reforms to modern America. Your choices of the Pure Food and Drug Act and Women's Suffrage were well-supported with solid evidence. The connections to modern regulatory agencies (EPA, OSHA, FDA) were excellent. Minor deductions: You could have explored some limitations or unintended consequences of Progressive reforms (e.g., the exclusion of minorities from many labor protections), and discussed opposition to these reforms in greater detail.\n\nOverall Assessment:\nYour writing is clear, well-organized, and demonstrates an excellent command of historical chronology and causation. You consistently support arguments with specific evidence and make meaningful connections between historical events and their long-term consequences. Keep up the outstanding work!\n\nTotal Score: 96 out of 100 points (96% — A)" + ] }, "cardInfo": { "name": "History Homework", @@ -63,4 +68,4 @@ } } } -} \ No newline at end of file +} diff --git a/25f2fc-homework-grader/HomeworkGrader/b0092d07-cc3e-405d-9fe4-c9542d7397b2.json b/25f2fc-homework-grader/HomeworkGrader/b0092d07-cc3e-405d-9fe4-c9542d7397b2.json index 24e15c48..48595a06 100644 --- a/25f2fc-homework-grader/HomeworkGrader/b0092d07-cc3e-405d-9fe4-c9542d7397b2.json +++ b/25f2fc-homework-grader/HomeworkGrader/b0092d07-cc3e-405d-9fe4-c9542d7397b2.json @@ -9,14 +9,22 @@ "type": "card", "attributes": { "grade": { - "overallGrade": "E", + "overallGrade": "B", + "overallFeedback": "Strong work overall — 20 out of 25 points (80%). Your addition, division, multiplication, and word-problem skills are solid. The one slip was subtraction: slow down and double-check with the inverse operation (add your answer back to the number you subtracted).", "questionPoints": [ 5, - 0, 5, - 0 + 5, + 0, + 5 ], - "overallFeedback": "### Homework Grade: E (50%)\n\n**Question-by-Question Feedback:**\n\n1. **Addition (15 + 27 = ?)**: Your answer \"42\" is **CORRECT!** ✓ (5/5 points)\n - Great work! 15 + 27 = 42.\n\n2. **Division (48 ÷ 6 = ?)**: **NO ANSWER PROVIDED** ✗ (0/5 points)\n - The correct answer is **8**.\n - Tip: Division and multiplication are inverses — 6 × 8 = 48, so 48 ÷ 6 = 8.\n\n3. **Multiplication (13 × 4 = ?)**: Your answer \"52\" is **CORRECT!** ✓ (5/5 points)\n - Well done! You can verify with (10 × 4) + (3 × 4) = 40 + 12 = 52.\n\n4. **Subtraction (45 - 19 = ?)**: Your answer \"100\" is **INCORRECT** ✗ (0/5 points)\n - The correct answer is **26**.\n - Tip: Try 45 - 20 = 25, then add back 1 to get 26.\n\n**Total Score: 10 out of 20 points (50%)**\n\n**Areas for Improvement:**\n- Attempt every question — a blank answer guarantees 0 points.\n- Review division as the inverse of multiplication.\n- Double-check subtraction answers; 45 - 19 cannot be larger than 45!\n- Show your working to help catch arithmetic mistakes early.\n\n**What You Did Well:**\n- Strong performance on addition and multiplication — keep it up!\n- When you attempt a problem, your method appears solid.\n\n**Next Steps:**\n- Practice division and subtraction fact families.\n- Always sanity-check answers (e.g., a subtraction result can't exceed the starting number).\n- Attempt every question, even if unsure — partial credit is better than zero!\n\nYou clearly have a good grasp of addition and multiplication. Focus on division and subtraction practice, and always attempt every question to maximise your score!" + "questionFeedbacks": [ + "Correct! 15 + 27 = 42. Clean addition with carrying.", + "Correct! 48 ÷ 6 = 8. You can verify with 6 × 8 = 48.", + "Correct! 13 × 4 = 52. Nice use of (10 × 4) + (3 × 4).", + "Incorrect — the answer is 26, not 100. Try 45 − 20 = 25, then add back 1. Always sanity-check: subtracting should make the number smaller.", + "Correct! 6 eggs × 7 boxes = 42 eggs. Good translation of a word problem into multiplication." + ] }, "cardInfo": { "name": "Math Homework", @@ -26,31 +34,38 @@ }, "questions": [ { - "cardTitle": "Addition", + "cardTitle": null, "questionText": "What is 15 + 27?", "answer": "42", "maxPoints": 5 }, { - "cardTitle": "Division", + "cardTitle": null, "questionText": "What is 48 ÷ 6?", - "answer": "", + "answer": "8", "maxPoints": 5 }, { - "cardTitle": "Multiplication", + "cardTitle": null, "questionText": "What is 13 × 4?", "answer": "52", "maxPoints": 5 }, { - "cardTitle": "Subtraction", - "questionText": "What is 45 - 19?", + "cardTitle": null, + "questionText": "What is 45 − 19?", "answer": "100", "maxPoints": 5 + }, + { + "cardTitle": null, + "questionText": "A box holds 6 eggs. How many eggs are in 7 boxes?", + "answer": "42", + "maxPoints": 5 } ], - "instructions": "Solve the following arithmetic problems. Show your work where necessary." + "instructions": "Solve the following arithmetic problems. Show your work where necessary.", + "cardTitle": "Basic Arithmetic Practice" }, "relationships": { "gradingSkill": { @@ -70,4 +85,4 @@ } } } -} \ No newline at end of file +} diff --git a/25f2fc-homework-grader/HomeworkGrader/fresh-assignment.json b/25f2fc-homework-grader/HomeworkGrader/fresh-assignment.json new file mode 100644 index 00000000..56fc25bd --- /dev/null +++ b/25f2fc-homework-grader/HomeworkGrader/fresh-assignment.json @@ -0,0 +1,44 @@ +{ + "data": { + "type": "card", + "attributes": { + "instructions": null, + "questions": [], + "grade": { + "overallGrade": null, + "overallFeedback": null, + "questionPoints": [], + "questionFeedbacks": [] + }, + "cardInfo": { + "name": null, + "notes": null, + "summary": "", + "cardThumbnailURL": null + } + }, + "relationships": { + "gradingSkill": { + "links": { + "self": "../Skill/dc116967-432e-4864-93aa-d7ea3f335d24" + } + }, + "cardInfo.theme": { + "links": { + "self": null + } + }, + "cardInfo.cardThumbnail": { + "links": { + "self": null + } + } + }, + "meta": { + "adoptsFrom": { + "module": "../homework-grader", + "name": "HomeworkGrader" + } + } + } +} diff --git a/25f2fc-homework-grader/Screenshots/01-hero-graded.png b/25f2fc-homework-grader/Screenshots/01-hero-graded.png new file mode 100644 index 00000000..089c5515 Binary files /dev/null and b/25f2fc-homework-grader/Screenshots/01-hero-graded.png differ diff --git a/25f2fc-homework-grader/Screenshots/02-empty-assignment.png b/25f2fc-homework-grader/Screenshots/02-empty-assignment.png new file mode 100644 index 00000000..bd46de3e Binary files /dev/null and b/25f2fc-homework-grader/Screenshots/02-empty-assignment.png differ diff --git a/25f2fc-homework-grader/Screenshots/03-question-feedback.png b/25f2fc-homework-grader/Screenshots/03-question-feedback.png new file mode 100644 index 00000000..5380c034 Binary files /dev/null and b/25f2fc-homework-grader/Screenshots/03-question-feedback.png differ diff --git a/25f2fc-homework-grader/Screenshots/04-grade-with-ai.png b/25f2fc-homework-grader/Screenshots/04-grade-with-ai.png new file mode 100644 index 00000000..5e443dd1 Binary files /dev/null and b/25f2fc-homework-grader/Screenshots/04-grade-with-ai.png differ diff --git a/25f2fc-homework-grader/Screenshots/homework-grader-screenshot.png b/25f2fc-homework-grader/Screenshots/homework-grader-screenshot.png deleted file mode 100644 index 4f3be55e..00000000 Binary files a/25f2fc-homework-grader/Screenshots/homework-grader-screenshot.png and /dev/null differ diff --git a/25f2fc-homework-grader/Skill/dc116967-432e-4864-93aa-d7ea3f335d24.json b/25f2fc-homework-grader/Skill/dc116967-432e-4864-93aa-d7ea3f335d24.json index 1e3ae90b..d8fce00a 100644 --- a/25f2fc-homework-grader/Skill/dc116967-432e-4864-93aa-d7ea3f335d24.json +++ b/25f2fc-homework-grader/Skill/dc116967-432e-4864-93aa-d7ea3f335d24.json @@ -17,7 +17,7 @@ }, "commands": [], "cardDescription": null, - "instructions": "THE USER ASKING IS THE STUDENT.\n\nGrade the student's homework assignment and provide an overall letter grade (A, B, C, D, E, F) along with detailed feedback. \n\nGrading Process:\n1. Examine each question and award points based on correctness (up to each question's maxPoints)\n2. Create a questionPoints array with the SAME LENGTH as the questions array\n3. Calculate overall letter grade from total points earned vs total possible\n4. Provide constructive feedback\n\nGRADING SCALE (MUST FOLLOW EXACTLY):\n- A: 90-100% (Excellent work)\n- B: 80-89% (Good work)\n- C: 70-79% (Average work)\n- D: 60-69% (Below average work)\n- E: 50-59% (Poor work)\n- F: 0-49% (Failing work)\n\nGRADE CALCULATION:\n1. Sum all questionPoints to get total earned points\n2. Sum all maxPoints from questions to get total possible points\n3. Calculate percentage: (total earned / total possible) \u00d7 100\n4. Apply the grading scale above to determine letter grade" + "instructions": "THE USER ASKING IS THE STUDENT.\n\nGrade the student's homework assignment and provide an overall letter grade (A, B, C, D, E, F) along with detailed feedback. \n\nGrading Process:\n1. Examine each question and award points based on correctness (up to each question's maxPoints)\n2. Create a questionPoints array with the SAME LENGTH as the questions array\n3. Create a questionFeedbacks array with the SAME LENGTH as the questions array — one short, specific feedback string per question (what was right, what was missing, how to improve). Write each entry for that question alone; do NOT repeat the per-question detail in the overall feedback.\n4. Calculate overall letter grade from total points earned vs total possible\n5. Provide overallFeedback as a brief summary of the whole assignment (strengths, main themes to work on) — the per-question detail belongs in questionFeedbacks\n\nGRADING SCALE (MUST FOLLOW EXACTLY):\n- A: 90-100% (Excellent work)\n- B: 80-89% (Good work)\n- C: 70-79% (Average work)\n- D: 60-69% (Below average work)\n- E: 50-59% (Poor work)\n- F: 0-49% (Failing work)\n\nGRADE CALCULATION:\n1. Sum all questionPoints to get total earned points\n2. Sum all maxPoints from questions to get total possible points\n3. Calculate percentage: (total earned / total possible) × 100\n4. Apply the grading scale above to determine letter grade" }, "relationships": { "cardInfo.theme": { diff --git a/25f2fc-homework-grader/Spec/290b04c0-7901-4332-bf42-698094a63226.json b/25f2fc-homework-grader/Spec/290b04c0-7901-4332-bf42-698094a63226.json index cbbbfb6c..36ee5e4a 100644 --- a/25f2fc-homework-grader/Spec/290b04c0-7901-4332-bf42-698094a63226.json +++ b/25f2fc-homework-grader/Spec/290b04c0-7901-4332-bf42-698094a63226.json @@ -22,7 +22,7 @@ "name": "GradeField", "module": "../homework-grader" }, - "readMe": null, + "readMe": "# GradeField\n\n## Summary\n\nGradeField holds the AI's grading result for an assignment: `overallGrade` (letter A–F), `overallFeedback` (a brief markdown summary of the whole assignment), `questionPoints` (containsMany numbers, one per question, same order as the questions array), `questionFeedbacks` (containsMany markdown, one focused feedback entry per question), and a computed `overallPoints` that sums the per-question points. The grading skill fills all of these in one act-mode patch; `isGradeConsistent` (exported from `../homework-grader`) checks the arrays line up with the question count.\n\n## Usage as a Field\n\n```ts\n@field grade = contains(GradeField);\n```\n\n## Template Usage\n\n```handlebars\n<@fields.grade />\n{{@model.grade.overallGrade}} · {{@model.grade.overallPoints}} pts\n```\n", "cardInfo": { "name": null, "notes": null, @@ -58,4 +58,4 @@ } } } -} \ No newline at end of file +} diff --git a/25f2fc-homework-grader/Spec/5455e5c1-1d62-41c9-ae39-f2ff09da9b83.json b/25f2fc-homework-grader/Spec/5455e5c1-1d62-41c9-ae39-f2ff09da9b83.json index 07d72f6d..9324b2b6 100644 --- a/25f2fc-homework-grader/Spec/5455e5c1-1d62-41c9-ae39-f2ff09da9b83.json +++ b/25f2fc-homework-grader/Spec/5455e5c1-1d62-41c9-ae39-f2ff09da9b83.json @@ -12,7 +12,7 @@ "name": "HomeworkGrader", "module": "../homework-grader" }, - "readMe": "## Summary\n\nThe `HomeworkGrader` card allows users to view, answer, and get feedback on homework assignments. It includes features such as an overview of the assignment, a detailed view of each question, and a feedback section with the overall grade and score breakdown.\n\n## Import\n\n```\nimport { HomeworkGrader } from '../homework-grader';\n```\n\n## Usage as a Field\n\nTo use the `HomeworkGrader` card as a field within a consuming card or field:\n\n```json\n{\n \"type\": \"card\",\n \"attributes\": {\n \"cardTitle\": \"Homework Assignment\",\n \"cardDescription\": \"Complete the homework and get feedback from the AI tutor.\"\n },\n \"relationships\": {\n \"homework\": {\n \"data\": {\n \"type\": \"card\",\n \"id\": \"../homework-grader\"\n }\n }\n }\n}\n```\n\n## Template Usage\n\nTo display the `HomeworkGrader` card within a template:\n\n```hbs\n<@fields.homework />\n```\n\nThis will render the `HomeworkGrader` card in the consuming card or field.", + "readMe": "## Summary\n\nThe `HomeworkGrader` card allows users to view, answer, and get feedback on homework assignments. It includes features such as an overview of the assignment, a detailed view of each question, and a feedback section with the overall grade and score breakdown.\n\n## Import\n\n```\nimport { HomeworkGrader } from '../homework-grader';\n```\n\n## Template Usage\n\nTo display the `HomeworkGrader` card within a template:\n\n```hbs\n<@fields.homework />\n```\n\nThis will render the `HomeworkGrader` card in the consuming card or field.", "cardInfo": { "name": null, "notes": null, @@ -42,4 +42,4 @@ } } } -} \ No newline at end of file +} diff --git a/25f2fc-homework-grader/Spec/5772d471-87be-488f-a7ee-00fbf0f6e206.json b/25f2fc-homework-grader/Spec/5772d471-87be-488f-a7ee-00fbf0f6e206.json index ab13b25f..70f8ef6a 100644 --- a/25f2fc-homework-grader/Spec/5772d471-87be-488f-a7ee-00fbf0f6e206.json +++ b/25f2fc-homework-grader/Spec/5772d471-87be-488f-a7ee-00fbf0f6e206.json @@ -2,7 +2,7 @@ "data": { "type": "card", "attributes": { - "readMe": null, + "readMe": "# QuestionField\n\n## Summary\n\nQuestionField is one assignment question: `cardTitle` (the question's short name), `questionText` (markdown prompt), `answer` (the student's markdown answer, edited inline from the isolated view), `maxPoints`, and a computed `isAnswered`. The grader holds questions in a `containsMany`, and the AI awards `questionPoints[i]` / writes `questionFeedbacks[i]` against the same index.\n\n## Usage as a Field\n\n```ts\n@field questions = containsMany(QuestionField);\n```\n\n## Template Usage\n\n```handlebars\n{{#each @model.questions as |q|}}{{q.cardTitle}}{{/each}}\n```\n\nEach question renders with its own embedded and fitted views; the fitted view embeds an editable answer field.\n", "ref": { "module": "../homework-grader", "name": "QuestionField" @@ -42,4 +42,4 @@ } } } -} \ No newline at end of file +} diff --git a/25f2fc-homework-grader/homework-grader.gts b/25f2fc-homework-grader/homework-grader.gts index c4544d0e..2a7b3027 100644 --- a/25f2fc-homework-grader/homework-grader.gts +++ b/25f2fc-homework-grader/homework-grader.gts @@ -15,7 +15,7 @@ import { IconButton, ProgressBar, } from '@cardstack/boxel-ui/components'; -import { add, eq } from '@cardstack/boxel-ui/helpers'; +import { add, and, bool, eq } from '@cardstack/boxel-ui/helpers'; import { CardDef, Component, @@ -26,16 +26,48 @@ import { linksTo, } from 'https://cardstack.com/base/card-api'; import BooleanField from 'https://cardstack.com/base/boolean'; +import enumField from 'https://cardstack.com/base/enum'; import MarkdownField from 'https://cardstack.com/base/markdown'; import NumberField from 'https://cardstack.com/base/number'; import { Skill } from 'https://cardstack.com/base/skill'; import StringField from 'https://cardstack.com/base/string'; import TextAreaField from 'https://cardstack.com/base/text-area'; +// True when a returned grade is structurally consistent with the assignment: +// a letter grade plus per-question points (and feedbacks, when present) +// matching the question count. Exported so live tests can hit it directly. +export function isGradeConsistent( + grade: + | { + overallGrade?: string | null; + questionPoints?: (number | null)[]; + questionFeedbacks?: (string | null)[]; + } + | null + | undefined, + questionCount: number, +): boolean { + if (!grade?.overallGrade) return false; + if ((grade.questionPoints?.length ?? 0) !== questionCount) return false; + let feedbacks = grade.questionFeedbacks; + if (feedbacks && feedbacks.length > 0 && feedbacks.length !== questionCount) { + return false; + } + return true; +} + +// letter grades the grading skill is allowed to award (see the skill's +// grading scale) — an enum so the edit UI is a picker, not free text +export const LetterGradeField = enumField(StringField, { + options: ['A', 'B', 'C', 'D', 'E', 'F'].map((g) => ({ value: g, label: g })), +}); + export class GradeField extends FieldDef { - @field overallGrade = contains(StringField); + @field overallGrade = contains(LetterGradeField); @field overallFeedback = contains(MarkdownField); @field questionPoints = containsMany(NumberField); + // one feedback entry per question, same order/length as questionPoints + @field questionFeedbacks = containsMany(MarkdownField); @field overallPoints = contains(NumberField, { computeVia: function (this: GradeField) { @@ -43,6 +75,59 @@ export class GradeField extends FieldDef { }, }); + static edit = class Edit extends Component { + + }; + static embedded = class Embedded extends Component { get gradeClass() { return `grade-${(this.args.model?.overallGrade ?? 'unknown').toUpperCase()}`; @@ -87,26 +172,26 @@ export class GradeField extends FieldDef { justify-content: center; font-size: 20px; font-weight: 800; - color: white; - background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%); + color: var(--c-on-blue, #ffffff); + background: #2563eb; } .grade-circle.grade-A { - background: linear-gradient(135deg, #10b981 0%, #059669 100%); + background: #10b981; } .grade-circle.grade-B { - background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); + background: #2563eb; } .grade-circle.grade-C { - background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); + background: #f59e0b; } .grade-circle.grade-D, .grade-circle.grade-E, .grade-circle.grade-F { - background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%); + background: #ef4444; } .details-column { @@ -221,6 +306,57 @@ export class QuestionField extends FieldDef { }, }); + static edit = class Edit extends Component { + + }; + static embedded = class Embedded extends Component {