From 843b3411e43f4613cdb9b5abbd86f79545572369 Mon Sep 17 00:00:00 2001 From: mohamad Date: Sun, 1 Jun 2025 21:57:03 +0200 Subject: [PATCH 1/3] Update package dependencies and refactor ListDetailPage and ListsPage components - Added `motion` and `framer-motion` packages to `package.json` and `package-lock.json`. - Updated API base URL in `api-config.ts` to point to the local development environment. - Refactored `ListDetailPage.vue` to enhance item rendering and interaction, replacing `VListItem` with a custom list structure. - Improved `ListsPage.vue` to handle loading states and item addition more effectively, including better handling of temporary item IDs. These changes aim to improve the user experience and maintainability of the application. --- fe/package-lock.json | 93 +++-- fe/package.json | 1 + fe/src/config/api-config.ts | 2 +- fe/src/pages/ListDetailPage.vue | 404 +++------------------- fe/src/pages/ListsPage.vue | 595 ++++++++++++++++++++++++-------- 5 files changed, 577 insertions(+), 518 deletions(-) diff --git a/fe/package-lock.json b/fe/package-lock.json index 1266026..a49cb17 100644 --- a/fe/package-lock.json +++ b/fe/package-lock.json @@ -15,6 +15,7 @@ "@vueuse/core": "^13.1.0", "axios": "^1.9.0", "date-fns": "^4.1.0", + "motion": "^12.15.0", "pinia": "^3.0.2", "vue": "^3.5.13", "vue-i18n": "^12.0.0-alpha.2", @@ -4420,21 +4421,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/date-fns": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@types/date-fns/-/date-fns-2.5.3.tgz", - "integrity": "sha512-4KVPD3g5RjSgZtdOjvI/TDFkLNUHhdoWxmierdQbDeEg17Rov0hbBYtIzNaQA67ORpteOhvR9YEMTb6xeDCang==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -7685,6 +7671,33 @@ "node": ">= 0.6" } }, + "node_modules/framer-motion": { + "version": "12.15.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.15.0.tgz", + "integrity": "sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.15.0", + "motion-utils": "^12.12.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -9439,6 +9452,47 @@ "ufo": "^1.5.4" } }, + "node_modules/motion": { + "version": "12.15.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.15.0.tgz", + "integrity": "sha512-HLouXyIb1uQFiZgJTYGrtEzbatPc6vK+HP+Qt6afLQjaudiGiLLVsoy71CwzD/Stlh06FUd5OpyiXqn6XvqjqQ==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.15.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.15.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.15.0.tgz", + "integrity": "sha512-D2ldJgor+2vdcrDtKJw48k3OddXiZN1dDLLWrS8kiHzQdYVruh0IoTwbJBslrnTXIPgFED7PBN2Zbwl7rNqnhA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.12.1" + } + }, + "node_modules/motion-utils": { + "version": "12.12.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.12.1.tgz", + "integrity": "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w==", + "license": "MIT" + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -10524,7 +10578,7 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10534,7 +10588,7 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "scheduler": "^0.26.0" @@ -11005,7 +11059,7 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/semver": { @@ -12057,7 +12111,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/type-check": { @@ -13874,4 +13927,4 @@ } } } -} \ No newline at end of file +} diff --git a/fe/package.json b/fe/package.json index 47522ad..6f3f247 100644 --- a/fe/package.json +++ b/fe/package.json @@ -26,6 +26,7 @@ "@vueuse/core": "^13.1.0", "axios": "^1.9.0", "date-fns": "^4.1.0", + "motion": "^12.15.0", "pinia": "^3.0.2", "vue": "^3.5.13", "vue-i18n": "^12.0.0-alpha.2", diff --git a/fe/src/config/api-config.ts b/fe/src/config/api-config.ts index 052aade..19a3f4f 100644 --- a/fe/src/config/api-config.ts +++ b/fe/src/config/api-config.ts @@ -2,7 +2,7 @@ export const API_VERSION = 'v1' // API Base URL -export const API_BASE_URL = (window as any).ENV?.VITE_API_URL || 'https://mitlistbe.mohamad.dev' +export const API_BASE_URL = (window as any).ENV?.VITE_API_URL || 'http://localhost:8000' // API Endpoints export const API_ENDPOINTS = { diff --git a/fe/src/pages/ListDetailPage.vue b/fe/src/pages/ListDetailPage.vue index 1ddac86..0f2d1d4 100644 --- a/fe/src/pages/ListDetailPage.vue +++ b/fe/src/pages/ListDetailPage.vue @@ -30,39 +30,35 @@ - - - +
    +
  • - - - - + +
    + +
    +
  • +
+
@@ -1295,18 +1291,21 @@ const handleExpenseCreated = (expense: any) => { overflow: hidden; } +.neo-item-list-container { + border: 3px solid #111; + border-radius: 18px; + background: var(--light); + box-shadow: 6px 6px 0 #111; + overflow: hidden; +} + .neo-item-list { list-style: none; padding: 0; - margin: 0 0 2rem 0; - break-inside: avoid; - width: 100%; - background: var(--light); - display: flex; - flex-direction: column; + margin: 0; } -.neo-item { +.neo-list-item { padding: 1.2rem; margin-bottom: 0; border-bottom: 1px solid #eee; @@ -1314,21 +1313,19 @@ const handleExpenseCreated = (expense: any) => { transition: background-color 0.1s ease-in-out; } -.neo-item:last-child { +.neo-list-item:last-child { border-bottom: none; } -.neo-item:hover { +.neo-list-item:hover { background-color: #f9f9f9; } -.neo-item-complete { - background: #f9f9f9; -} - .neo-item-content { display: flex; align-items: center; + justify-content: space-between; + gap: 1rem; } .neo-checkbox-label { @@ -1336,6 +1333,7 @@ const handleExpenseCreated = (expense: any) => { align-items: center; gap: 0.7em; cursor: pointer; + flex-grow: 1; } .neo-checkbox-label input[type="checkbox"] { @@ -1346,35 +1344,11 @@ const handleExpenseCreated = (expense: any) => { border-radius: 4px; } -.neo-item-details { - flex-grow: 1; - display: flex; - flex-direction: column; -} - .item-name { - /* Added for VListItem content */ font-size: 1.1rem; font-weight: 700; } -.neo-item-complete .item-name { - /* Adjusted for VListItem */ - text-decoration: line-through; - /* opacity: 0.6; Combined with bg-gray-100 opacity-70 on VListItem */ -} - - -.neo-item-quantity { - font-size: 0.9rem; - color: #555; - margin-top: 0.2rem; -} - -.neo-price-input { - margin-top: 0.5rem; -} - .neo-item-actions { display: flex; gap: 0.5rem; @@ -1389,6 +1363,13 @@ const handleExpenseCreated = (expense: any) => { display: flex; align-items: center; justify-content: center; + transition: transform 0.1s ease-out, opacity 0.1s ease-out; + -webkit-tap-highlight-color: transparent; +} + +.neo-icon-button:active { + transform: scale(0.98); + opacity: 0.9; } .neo-edit-button { @@ -1400,308 +1381,35 @@ const handleExpenseCreated = (expense: any) => { } .neo-delete-button { - background: none; - border: none; - cursor: pointer; color: #e74c3c; - padding: 0.5rem; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin-left: 0; } .neo-delete-button:hover { background: #fee; } -.neo-actions { - display: flex; - gap: 1rem; - margin-bottom: 2rem; -} - -.neo-action-button { - /* General button, mostly replaced by VButton */ - background: #111; - color: white; - border: none; - border-radius: 8px; - padding: 0.6rem 1rem; - font-weight: 700; - cursor: pointer; -} - -.neo-action-button:hover { - transform: translateY(-2px); - box-shadow: 3px 5px 0 #111; -} - -.neo-action-button .icon { - width: 1.2rem; - height: 1.2rem; -} - -.neo-disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.add-item-form { - /* Added for new form styling */ - /* display: flex; (already on class) */ - /* gap: 0.5rem; (already on class) */ - /* margin-top: 1rem; (original was 2rem, now mt-4) */ - /* padding: 1rem; (original was 1rem) */ - /* border: 3px solid #111; (original was 3px) */ - /* border-radius: 12px; (original was 12px) */ - /* background: #f9f9f9; (original was #f9f9f9) */ - /* box-shadow: 4px 4px 0 #111; (original was 4px) */ -} - - -.neo-new-item-form { - /* Kept for reference, but form tag itself is now styled */ - width: 100%; - gap: 10px; -} - -.neo-text-input { - /* Not directly used by VInput, but kept for reference */ - flex-grow: 1; - border: 2px solid #111; - border-radius: 8px; - padding: 0.8rem; - font-size: 1.1rem; - font-weight: 500; -} - -.neo-new-item-input { - /* Not directly used by VInput, but kept for reference */ - background: transparent; - border: none; - outline: none; - all: unset; - width: 100%; - font-size: 1.1rem; - font-weight: 500; - color: #444; - flex-grow: 1; -} - -.neo-new-item-input::placeholder { - /* VInput handles its own placeholder styling */ - color: #999; - font-weight: 500; -} - -.neo-quantity-input { - /* Not directly used by VInput, but kept for reference */ - width: 80px; - /* This specific width is now on VFormField for quantity */ - border: 2px solid #111; - border-radius: 8px; - padding: 0.4rem; - font-size: 1rem; - font-weight: 500; -} - -.neo-number-input { - /* For price input, now VInput with class="w-24" */ - border: 2px solid #111; - border-radius: 6px; - padding: 0.5rem; - font-size: 1rem; - width: 100px; -} - -.neo-add-button { - /* Replaced by VButton */ - background: #111; - color: white; - border: none; - border-radius: 8px; - padding: 0 1rem; - font-weight: 700; - cursor: pointer; - min-width: 60px; - height: 2rem; -} - -.neo-button { - /* General button, mostly replaced by VButton */ - background: #111; - color: white; - border: none; - border-radius: 8px; - padding: 0.8rem 1.5rem; - font-weight: 700; - margin-top: 1rem; - cursor: pointer; -} - -.new-item-input { - /* Styling for the old li wrapper of add item form, can be removed */ +.neo-price-input { margin-top: 0.5rem; - padding: 0.5rem; -} - -/* Responsive adjustments */ -@media (max-width: 900px) { - .neo-container { - padding: 0.8rem; - } - - .neo-title { - font-size: 1.8rem; - } - - /* .neo-item { // VListItem might have its own padding - padding: 1rem; - } */ + padding-left: 2.2em; } @media (max-width: 600px) { - .neo-container { - padding: 0.5rem; - } - - .neo-list-header { - flex-direction: column; - align-items: flex-start; - gap: 0.8rem; - } - - .neo-title { - font-size: 1.5rem; - margin-bottom: 0.5rem; - } - - .neo-header-actions { - flex-wrap: wrap; - gap: 0.5rem; - } - - .neo-action-button { - /* VButton has its own sizing */ - padding: 0.8rem; - font-size: 0.9rem; - } - - .neo-description { - font-size: 1rem; - margin-bottom: 1.5rem; - } - - /* .neo-item { // VListItem + .neo-list-item { padding: 1rem; - } */ - - .item-name { - /* Adjusted for VListItem */ - font-size: 1rem; } - .neo-item-quantity { - font-size: 0.85rem; - } - - /* .neo-checkbox-label input[type="checkbox"] { // VCheckbox has its own styling + .neo-checkbox-label input[type="checkbox"] { width: 1.4em; height: 1.4em; - } */ + } + + .item-name { + font-size: 1rem; + } .neo-icon-button { - /* VButton icon-only replaces this */ padding: 0.6rem; } - - .add-item-form { - /* Adjusted form class */ - flex-wrap: wrap; - gap: 0.5rem; - } - - /* VInput placeholder styling is internal to VInput */ - /* .neo-new-item-input { - width: 100%; - font-size: 1rem; - } */ - - /* VInput type number styling is internal or via props */ - /* .neo-quantity-input { - width: 80px; - font-size: 0.9rem; - } */ - - /* VButton styling replaces this */ - /* .neo-add-button { - width: 100%; - margin-top: 0.5rem; - padding: 0.8rem; - } */ - - /* Optimize modals for mobile */ - .modal-container { - /* VModal has its own responsive sizing via props/CSS */ - width: 95%; - max-height: 85vh; - margin: 1rem; - } - - .modal-header { - /* VModal slot */ - padding: 1rem; - } - - .modal-body { - /* VModal slot */ - padding: 1rem; - } - - .modal-footer { - /* VModal slot */ - padding: 1rem; - } - - /* Improve touch targets - general principle, components should handle this */ - /* button, - input[type="checkbox"], - .neo-checkbox-label { - min-height: 44px; - } */ - - /* Optimize loading states for mobile */ - .neo-loading-state { - /* VSpinner used instead */ - padding: 2rem 1rem; - } - - .spinner-dots span { - /* VSpinner has its own dot styling */ - width: 10px; - height: 10px; - } - - /* Improve scrolling performance */ - .item-list-tight { - /* Assuming VList with this class */ - -webkit-overflow-scrolling: touch; - } - - /* Optimize expense cards for mobile */ - .neo-expense-card { - padding: 0.8rem; - } - - .neo-expense-header { - font-size: 1.1rem; - } - - .neo-split-item { - padding: 0.8rem 0; - } } /* Add smooth transitions for all interactive elements - VComponents have their own */ diff --git a/fe/src/pages/ListsPage.vue b/fe/src/pages/ListsPage.vue index e325e10..ac5f252 100644 --- a/fe/src/pages/ListsPage.vue +++ b/fe/src/pages/ListsPage.vue @@ -8,11 +8,8 @@ - + +
+ Loading lists... +
+
{{ list.name }}
{{ list.description || 'No description' }}
    -
  • +
  • -
  • +
-
+
+ Create a new list
@@ -59,15 +65,15 @@ \ No newline at end of file From 5cb13862ef0cf908e37808bfbcda5722a6686757 Mon Sep 17 00:00:00 2001 From: mohamad Date: Sun, 1 Jun 2025 22:00:11 +0200 Subject: [PATCH 2/3] Enhance ChoresPage accessibility and functionality - Added ARIA roles and attributes to buttons and modals for improved accessibility. - Updated chore types and properties in the Chore interface to allow for null values. - Refactored chore loading and filtering logic to handle edge cases and improve performance. - Enhanced calendar and list views with better user feedback for empty states and loading indicators. - Improved styling for mobile responsiveness and dark mode support. These changes aim to enhance user experience, accessibility, and maintainability of the ChoresPage component. --- fe/src/pages/ChoresPage.vue | 1513 +++++++++++++++++++++++++---------- fe/src/types/chore.ts | 37 +- 2 files changed, 1085 insertions(+), 465 deletions(-) diff --git a/fe/src/pages/ChoresPage.vue b/fe/src/pages/ChoresPage.vue index c4603db..8019483 100644 --- a/fe/src/pages/ChoresPage.vue +++ b/fe/src/pages/ChoresPage.vue @@ -3,31 +3,31 @@

Chores

-
+
@@ -36,19 +36,20 @@
-
@@ -62,43 +63,56 @@
-

{{ currentMonthYear }}

-
-
-
-
{{ day }}
-
-
-
-
- {{ day.date.getDate() }} -
+
-
-
-
-
- {{ chore.name }} +
+
+
+
{{ day }}
+
+
+
+
+ {{ day.date.getDate() }} + +
+
+
+
+ {{ chore.name }} +
+
+ +
+
+ calendar_today +

No chores to display for this period.

+
-
+
@@ -139,24 +153,35 @@ title="Mark as Not Done"> undo Undo - -
+
+ Rtask_alt +

No chores in this view. Well done!

+ +
-