From c31055f61c55fd86649e28e64fde10cc4e1be8f1 Mon Sep 17 00:00:00 2001 From: Boxel Submission Bot Date: Wed, 8 Apr 2026 14:18:27 +0800 Subject: [PATCH] add To-Do Item Card Definition changes [boxel-content-hash:9a4ae49a295a] --- .../bd26e4b9-b0e0-409b-9b90-efc2d116151e.json | 74 ++ .../c41b4e4c-f364-4677-a461-80f0c2bb105f.json | 40 + Todo/design-review.json | 32 + Todo/fix-login-bug.json | 32 + Todo/update-readme.json | 32 + todo.gts | 715 ++++++++++++++++++ 6 files changed, 925 insertions(+) create mode 100644 CardListing/bd26e4b9-b0e0-409b-9b90-efc2d116151e.json create mode 100644 Spec/c41b4e4c-f364-4677-a461-80f0c2bb105f.json create mode 100644 Todo/design-review.json create mode 100644 Todo/fix-login-bug.json create mode 100644 Todo/update-readme.json create mode 100644 todo.gts diff --git a/CardListing/bd26e4b9-b0e0-409b-9b90-efc2d116151e.json b/CardListing/bd26e4b9-b0e0-409b-9b90-efc2d116151e.json new file mode 100644 index 0000000..882989e --- /dev/null +++ b/CardListing/bd26e4b9-b0e0-409b-9b90-efc2d116151e.json @@ -0,0 +1,74 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "CardListing", + "module": "https://realms-staging.stack.cards/catalog/catalog-app/listing/listing" + } + }, + "type": "card", + "attributes": { + "name": "To-Do Item Card Definition", + "images": [], + "summary": "The Todo component provides a structured representation for task management within a card-based system. It captures essential task attributes such as title, description, status, priority, due date, and completion status. The component supports multiple display formats—including embedded, fitted, tile, and card views—to adapt to various UI contexts and responsive layouts. It emphasizes visual cues through labels and icons for status, priority, and completion, facilitating quick comprehension of task states. The primary purpose of this definition is to enable flexible, visually organized task tracking within customizable card interfaces.", + "cardInfo": { + "name": null, + "notes": null, + "summary": null, + "cardThumbnailURL": null + } + }, + "relationships": { + "tags": { + "links": { + "self": null + } + }, + "specs.0": { + "links": { + "self": "../Spec/c41b4e4c-f364-4677-a461-80f0c2bb105f" + } + }, + "skills": { + "links": { + "self": null + } + }, + "license": { + "links": { + "self": null + } + }, + "publisher": { + "links": { + "self": null + } + }, + "categories": { + "links": { + "self": null + } + }, + "examples.0": { + "links": { + "self": "../Todo/design-review" + } + }, + "examples.1": { + "links": { + "self": "../Todo/fix-login-bug" + } + }, + "examples.2": { + "links": { + "self": "../Todo/update-readme" + } + }, + "cardInfo.theme": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/Spec/c41b4e4c-f364-4677-a461-80f0c2bb105f.json b/Spec/c41b4e4c-f364-4677-a461-80f0c2bb105f.json new file mode 100644 index 0000000..659577c --- /dev/null +++ b/Spec/c41b4e4c-f364-4677-a461-80f0c2bb105f.json @@ -0,0 +1,40 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "Spec", + "module": "https://cardstack.com/base/spec" + } + }, + "type": "card", + "attributes": { + "ref": { + "name": "Todo", + "module": "../todo" + }, + "readMe": "Here is the usage documentation for the Todo card spec:\n\n## Todo\n\n**Summary**:\nThe Todo card spec defines a card for tracking tasks, including fields for title, description, status, priority, due date, and completion status.\n\n**Import**:\n```gts\nimport { Todo } from 'https://realms-staging.stack.cards/richard.tan/deep-whippet-89/todo';\n```\n\n**Usage as a Field**:\nTo use the Todo card as a field, import the spec and include it as a `linksTo` field:\n\n```gts\n@field todo = linksTo(Todo);\n```\n\n**Template Usage**:\nTo display a Todo card in a template, use the field name and specify the desired format:\n\n```hbs\n<@fields.todo @format=\"isolated\" />\n```\n\nThis will render the Todo card in the isolated format, which provides a detailed view of the task.", + "cardInfo": { + "name": null, + "notes": null, + "summary": null, + "cardThumbnailURL": null + }, + "specType": "card", + "cardTitle": "Todo", + "cardDescription": null, + "containedExamples": [] + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + }, + "linkedExamples": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/Todo/design-review.json b/Todo/design-review.json new file mode 100644 index 0000000..f74aad8 --- /dev/null +++ b/Todo/design-review.json @@ -0,0 +1,32 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "Todo", + "module": "../todo" + } + }, + "type": "card", + "attributes": { + "title": "Conduct Q2 design review", + "status": "done", + "dueDate": "2026-04-05", + "cardInfo": { + "name": "Conduct Q2 design review", + "notes": null, + "summary": "Review and finalize Q2 dashboard mockups with the team", + "cardThumbnailURL": null + }, + "priority": "medium", + "completed": true, + "description": "Schedule and run a design review session with the team to evaluate the new dashboard mockups. Collect feedback, document action items, and align on the final direction before handoff to engineering." + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/Todo/fix-login-bug.json b/Todo/fix-login-bug.json new file mode 100644 index 0000000..c9eb9fd --- /dev/null +++ b/Todo/fix-login-bug.json @@ -0,0 +1,32 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "Todo", + "module": "../todo" + } + }, + "type": "card", + "attributes": { + "title": "Fix login authentication bug", + "status": "in-progress", + "dueDate": "2026-04-10", + "cardInfo": { + "name": "Fix login authentication bug", + "notes": null, + "summary": "Investigate and fix JWT token refresh causing unexpected logouts", + "cardThumbnailURL": null + }, + "priority": "high", + "completed": false, + "description": "Users are being logged out unexpectedly after 5 minutes due to a token refresh issue. Investigate the JWT expiry logic and ensure the refresh token flow is working correctly." + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/Todo/update-readme.json b/Todo/update-readme.json new file mode 100644 index 0000000..78c8b7a --- /dev/null +++ b/Todo/update-readme.json @@ -0,0 +1,32 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "Todo", + "module": "../todo" + } + }, + "type": "card", + "attributes": { + "title": "Update project README", + "status": "todo", + "dueDate": "2026-04-18", + "cardInfo": { + "name": "Update project README", + "notes": null, + "summary": "Add Docker setup instructions and contribution guidelines to the README", + "cardThumbnailURL": null + }, + "priority": "low", + "completed": false, + "description": "The README is outdated and missing setup instructions for the new Docker-based development environment. Add installation steps, environment variable documentation, and contribution guidelines." + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/todo.gts b/todo.gts new file mode 100644 index 0000000..a53b2e8 --- /dev/null +++ b/todo.gts @@ -0,0 +1,715 @@ +// ═══ [EDIT TRACKING: ON] Mark all changes with ⁿ ═══ +import { + // ¹ Core imports + CardDef, + Component, + field, + contains, +} from 'https://cardstack.com/base/card-api'; +import StringField from 'https://cardstack.com/base/string'; // ² +import BooleanField from 'https://cardstack.com/base/boolean'; // ³ +import DateField from 'https://cardstack.com/base/date'; // ⁴ +import TextAreaField from 'https://cardstack.com/base/text-area'; // ⁵ +import enumField from 'https://cardstack.com/base/enum'; // ⁶ +import { formatDateTime } from '@cardstack/boxel-ui/helpers'; // ⁷ +import { eq } from '@cardstack/boxel-ui/helpers'; // ⁸ +import CheckSquareIcon from '@cardstack/boxel-icons/square-check'; // ⁹ + +// ¹⁰ Priority enum field +const PriorityField = enumField(StringField, { + options: [ + { value: 'low', label: 'Low' }, + { value: 'medium', label: 'Medium' }, + { value: 'high', label: 'High' }, + ], +}); + +// ¹¹ Status enum field +const StatusField = enumField(StringField, { + options: [ + { value: 'todo', label: 'To Do' }, + { value: 'in-progress', label: 'In Progress' }, + { value: 'done', label: 'Done' }, + ], +}); + +export class Todo extends CardDef { + // ¹² + static displayName = 'Todo'; + static icon = CheckSquareIcon; + + @field title = contains(StringField); // ¹³ + @field description = contains(TextAreaField); // ¹⁴ + @field status = contains(StatusField); // ¹⁵ + @field priority = contains(PriorityField); // ¹⁶ + @field dueDate = contains(DateField); // ¹⁷ + @field completed = contains(BooleanField); // ¹⁸ + + @field cardTitle = contains(StringField, { + // ¹⁹ + computeVia: function (this: Todo) { + return this.cardInfo?.name ?? this.title ?? 'Untitled Todo'; + }, + }); + + static isolated = class Isolated extends Component { + // ²⁰ + get statusLabel() { + const s = this.args.model?.status; + if (s === 'done') return 'Done'; + if (s === 'in-progress') return 'In Progress'; + return 'To Do'; + } + + get priorityLabel() { + const p = this.args.model?.priority; + if (p === 'high') return 'High'; + if (p === 'medium') return 'Medium'; + return 'Low'; + } + + get priorityClass() { + const p = this.args.model?.priority; + if (p === 'high') return 'priority-high'; + if (p === 'medium') return 'priority-medium'; + return 'priority-low'; + } + + get statusClass() { + const s = this.args.model?.status; + if (s === 'done') return 'status-done'; + if (s === 'in-progress') return 'status-in-progress'; + return 'status-todo'; + } + + + }; + + static embedded = class Embedded extends Component { + // ²² + get statusClass() { + const s = this.args.model?.status; + if (s === 'done') return 'status-done'; + if (s === 'in-progress') return 'status-in-progress'; + return 'status-todo'; + } + + get statusLabel() { + const s = this.args.model?.status; + if (s === 'done') return 'Done'; + if (s === 'in-progress') return 'In Progress'; + return 'To Do'; + } + + get priorityClass() { + const p = this.args.model?.priority; + if (p === 'high') return 'priority-high'; + if (p === 'medium') return 'priority-medium'; + return 'priority-low'; + } + + get priorityLabel() { + const p = this.args.model?.priority; + if (p === 'high') return 'High'; + if (p === 'medium') return 'Medium'; + return 'Low'; + } + + + }; + + static fitted = class Fitted extends Component { + // ²⁴ + get statusClass() { + const s = this.args.model?.status; + if (s === 'done') return 'status-done'; + if (s === 'in-progress') return 'status-in-progress'; + return 'status-todo'; + } + + get statusLabel() { + const s = this.args.model?.status; + if (s === 'done') return 'Done'; + if (s === 'in-progress') return 'In Progress'; + return 'To Do'; + } + + get priorityClass() { + const p = this.args.model?.priority; + if (p === 'high') return 'priority-high'; + if (p === 'medium') return 'priority-medium'; + return 'priority-low'; + } + + get priorityDot() { + const p = this.args.model?.priority; + if (p === 'high') return '🔴'; + if (p === 'medium') return '🟡'; + return '🟢'; + } + + + }; +}