From 485d75820b684b241b048e66274a0660b862d63a Mon Sep 17 00:00:00 2001 From: xiaomai Date: Wed, 22 Oct 2025 17:52:17 +0800 Subject: [PATCH] feat(ui): overhaul interface with Nuxt UI Integrate the Nuxt UI component library and completely revamp the application's user interface to improve usability, aesthetics, and maintainability. - Replace all custom components and native browser dialogs (`alert`, `prompt`, `confirm`) with Nuxt UI components like `UCard`, `UButton`, `UModal`, and `UNotifications`. - Refactor the main page by extracting the sidebar into dedicated panel components: `CategoryPanel`, `BoardSummaryPanel`, and `HistoryPanel`. - Redesign all major components (Toolbar, Board, Stage, Task) for a cleaner layout and improved information hierarchy. - Implement user-friendly modals for all creation, editing, and deletion flows, providing a more consistent user experience. - Add toast notifications to provide immediate feedback for user actions. --- app.config.ts | 24 ++ app.vue | 19 +- components/Board.vue | 105 +++++-- components/MergeModal.vue | 121 +++++--- components/StageColumn.vue | 246 ++++++++++++++-- components/TaskCard.vue | 96 ++++-- components/TaskModal.vue | 243 +++++++++++---- components/Toolbar.vue | 272 +++++++++++++---- components/dialogs/StageModal.vue | 76 +++++ components/panels/BoardSummaryPanel.vue | 73 +++++ components/panels/CategoryPanel.vue | 213 ++++++++++++++ components/panels/HistoryPanel.vue | 92 ++++++ layouts/default.vue | 5 + nuxt.config.ts | 8 +- package.json | 5 +- pages/index.vue | 143 +++++---- pnpm-lock.yaml | 373 ++++++++++++++++++++++++ stores/board.ts | 24 +- tailwind.config.ts | 3 +- 19 files changed, 1823 insertions(+), 318 deletions(-) create mode 100644 app.config.ts create mode 100644 components/dialogs/StageModal.vue create mode 100644 components/panels/BoardSummaryPanel.vue create mode 100644 components/panels/CategoryPanel.vue create mode 100644 components/panels/HistoryPanel.vue create mode 100644 layouts/default.vue diff --git a/app.config.ts b/app.config.ts new file mode 100644 index 0000000..dafe8ed --- /dev/null +++ b/app.config.ts @@ -0,0 +1,24 @@ +export default defineAppConfig({ + ui: { + primary: 'sky', + gray: 'slate', + notifications: { + position: 'bottom-right' + }, + button: { + default: { + color: 'neutral' + } + }, + card: { + default: { + header: { + padding: 'px-4 py-3' + }, + body: { + padding: 'px-4 py-4' + } + } + } + } +}) diff --git a/app.vue b/app.vue index 4799088..e08691d 100644 --- a/app.vue +++ b/app.vue @@ -1,11 +1,18 @@ - diff --git a/components/Board.vue b/components/Board.vue index 4aa0608..1c959b8 100644 --- a/components/Board.vue +++ b/components/Board.vue @@ -1,44 +1,95 @@ - diff --git a/components/MergeModal.vue b/components/MergeModal.vue index 524c7ee..6b7d804 100644 --- a/components/MergeModal.vue +++ b/components/MergeModal.vue @@ -1,55 +1,84 @@ - diff --git a/components/StageColumn.vue b/components/StageColumn.vue index 7ef010b..6c93c16 100644 --- a/components/StageColumn.vue +++ b/components/StageColumn.vue @@ -1,75 +1,261 @@ diff --git a/components/TaskCard.vue b/components/TaskCard.vue index b331959..5a0ded9 100644 --- a/components/TaskCard.vue +++ b/components/TaskCard.vue @@ -1,16 +1,54 @@ diff --git a/components/TaskModal.vue b/components/TaskModal.vue index 86c90d2..96d39d3 100644 --- a/components/TaskModal.vue +++ b/components/TaskModal.vue @@ -1,68 +1,211 @@ - diff --git a/components/Toolbar.vue b/components/Toolbar.vue index e658b06..071abf7 100644 --- a/components/Toolbar.vue +++ b/components/Toolbar.vue @@ -1,35 +1,106 @@ - diff --git a/components/dialogs/StageModal.vue b/components/dialogs/StageModal.vue new file mode 100644 index 0000000..c7406e6 --- /dev/null +++ b/components/dialogs/StageModal.vue @@ -0,0 +1,76 @@ + + + diff --git a/components/panels/BoardSummaryPanel.vue b/components/panels/BoardSummaryPanel.vue new file mode 100644 index 0000000..057fe50 --- /dev/null +++ b/components/panels/BoardSummaryPanel.vue @@ -0,0 +1,73 @@ + + + diff --git a/components/panels/CategoryPanel.vue b/components/panels/CategoryPanel.vue new file mode 100644 index 0000000..2566d04 --- /dev/null +++ b/components/panels/CategoryPanel.vue @@ -0,0 +1,213 @@ + + + diff --git a/components/panels/HistoryPanel.vue b/components/panels/HistoryPanel.vue new file mode 100644 index 0000000..f1eb59d --- /dev/null +++ b/components/panels/HistoryPanel.vue @@ -0,0 +1,92 @@ + + + diff --git a/layouts/default.vue b/layouts/default.vue new file mode 100644 index 0000000..88a1e66 --- /dev/null +++ b/layouts/default.vue @@ -0,0 +1,5 @@ + diff --git a/nuxt.config.ts b/nuxt.config.ts index 0af4f4b..c210f33 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,6 +1,6 @@ // Nuxt 4 configuration export default defineNuxtConfig({ - modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss'], + modules: ['@nuxt/ui', '@pinia/nuxt', '@nuxtjs/tailwindcss'], css: ['~/assets/css/tailwind.css'], typescript: { strict: true @@ -10,6 +10,11 @@ export default defineNuxtConfig({ title: 'Kanban' } }, + ui: { + global: true, + primary: 'sky', + gray: 'slate' + }, tailwindcss: { viewer: false }, @@ -22,4 +27,3 @@ export default defineNuxtConfig({ } } }); - diff --git a/package.json b/package.json index 9223af4..c2e8037 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "tailwindcss": "^3.4.13", "postcss": "^8.4.47", "autoprefixer": "^10.4.19", - "@types/node": "^20.11.30" + "@types/node": "^20.11.30", + "@nuxt/ui": "^2.15.1", + "@nuxt/icon": "^1.5.0" } } - diff --git a/pages/index.vue b/pages/index.vue index 0b9acdc..5a06761 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,106 +1,95 @@ - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 604c973..0f0901e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,12 @@ importers: specifier: ^3.23.8 version: 3.25.76 devDependencies: + '@nuxt/icon': + specifier: ^1.5.0 + version: 1.15.0(magicast@0.3.5)(vite@7.1.11(@types/node@20.19.23)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) + '@nuxt/ui': + specifier: ^2.15.1 + version: 2.22.3(magicast@0.3.5)(vite@7.1.11(@types/node@20.19.23)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)(zod@3.25.76) '@nuxtjs/tailwindcss': specifier: ^6.11.4 version: 6.14.0(magicast@0.3.5)(yaml@2.8.1) @@ -49,6 +55,12 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -347,6 +359,35 @@ packages: cpu: [x64] os: [win32] + '@headlessui/tailwindcss@0.2.2': + resolution: {integrity: sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==} + engines: {node: '>=10'} + peerDependencies: + tailwindcss: ^3.0 || ^4.0 + + '@headlessui/vue@1.7.23': + resolution: {integrity: sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==} + engines: {node: '>=10'} + peerDependencies: + vue: ^3.2.0 + + '@iconify-json/heroicons@1.2.3': + resolution: {integrity: sha512-n+vmCEgTesRsOpp5AB5ILB6srsgsYK+bieoQBNlafvoEhjVXLq8nIGN4B0v/s4DUfa0dOrjwE/cKJgIKdJXOEg==} + + '@iconify/collections@1.0.608': + resolution: {integrity: sha512-uMbaErE6TzDb04peWVFYjc9cweBD+j1nFBHi5EEcA1u1mXJAyePF01VzH6dimurrhivvU+nRmuYfiC8GPDyG6g==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + + '@iconify/vue@5.0.0': + resolution: {integrity: sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==} + peerDependencies: + vue: '>=3' + '@ioredis/commands@1.4.0': resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==} @@ -430,6 +471,9 @@ packages: peerDependencies: vite: '>=6.0' + '@nuxt/icon@1.15.0': + resolution: {integrity: sha512-kA0rxqr1B601zNJNcOXera8CyYcxUCEcT7dXEC7rwAz71PRCN5emf7G656eKEQgtqrD4JSj6NQqWDgrmFcf/GQ==} + '@nuxt/kit@3.19.3': resolution: {integrity: sha512-ze46EW5xW+UxDvinvPkYt2MzR355Az1lA3bpX8KDialgnCwr+IbkBij/udbUEC6ZFbidPkfK1eKl4ESN7gMY+w==} engines: {node: '>=18.12.0'} @@ -447,6 +491,26 @@ packages: engines: {node: '>=18.12.0'} hasBin: true + '@nuxt/ui@2.22.3': + resolution: {integrity: sha512-895SAzqCCT5JAc1JQ8nAmmpwdKCJqArY8ifL/PNtD681FKSdXiSPxODGnpqpovM/ws6bvoRwglA7BtwAJ5ySBg==} + peerDependencies: + joi: ^17.13.0 + superstruct: ^2.0.0 + valibot: ^1.0.0 + yup: ^1.6.0 + zod: ^3.24.0 + peerDependenciesMeta: + joi: + optional: true + superstruct: + optional: true + valibot: + optional: true + yup: + optional: true + zod: + optional: true + '@nuxt/vite-builder@4.1.3': resolution: {integrity: sha512-yrblLSpGW6h9k+sDZa+vtevQz/6JLrPAj3n97HrEmVa6qB+4sE4HWtkMNUtWsOPe60sAm9usRsjDUkkiHZ0DpA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -457,6 +521,9 @@ packages: rolldown: optional: true + '@nuxtjs/color-mode@3.5.2': + resolution: {integrity: sha512-cC6RfgZh3guHBMLLjrBB2Uti5eUoGM9KyauOaYS9ETmxNWBMTvpgjvSiSJp1OFljIXPIqVTJ3xtJpSNZiO3ZaA==} + '@nuxtjs/tailwindcss@6.14.0': resolution: {integrity: sha512-30RyDK++LrUVRgc2A85MktGWIZoRQgeQKjE4CjjD64OXNozyl+4ScHnnYgqVToMM6Ch2ZG2W4wV2J0EN6F0zkQ==} @@ -828,6 +895,9 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@poppinss/colors@4.1.5': resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==} @@ -1039,6 +1109,37 @@ packages: '@speed-highlight/core@1.2.7': resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@tailwindcss/aspect-ratio@0.4.2': + resolution: {integrity: sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==} + peerDependencies: + tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' + + '@tailwindcss/container-queries@0.1.1': + resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==} + peerDependencies: + tailwindcss: '>=3.2.0' + + '@tailwindcss/forms@0.5.10': + resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==} + peerDependencies: + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' + + '@tailwindcss/typography@0.5.19': + resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@tanstack/virtual-core@3.13.12': + resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==} + + '@tanstack/vue-virtual@3.13.12': + resolution: {integrity: sha512-vhF7kEU9EXWXh+HdAwKJ2m3xaOnTTmgcdXcF2pim8g4GvI7eRrk2YRuV5nUlZnd/NbCIX4/Ja2OZu5EjJL06Ww==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -1058,6 +1159,9 @@ packages: '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@unhead/vue@2.0.19': resolution: {integrity: sha512-7BYjHfOaoZ9+ARJkT10Q2TjnTUqDXmMpfakIAsD/hXiuff1oqWg1xeXT5+MomhNcC15HbiABpbbBmITLSHxdKg==} peerDependencies: @@ -1167,12 +1271,72 @@ packages: '@vueuse/core@11.3.0': resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==} + '@vueuse/core@13.9.0': + resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/integrations@13.9.0': + resolution: {integrity: sha512-SDobKBbPIOe0cVL7QxMzGkuUGHvWTdihi9zOrrWaWUgFKe15cwEcwfWmgrcNzjT6kHnNmWuTajPHoIzUjYNYYQ==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 || ^8 + vue: ^3.5.0 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/math@13.9.0': + resolution: {integrity: sha512-Qk2jqlaEGKwwe2/MBGtUd8nPpzoQPSQTfm2d30NPywjpYdpbI+WqOAE99MuSq9kIRoU7Xq3IYBtxMaLTy6lpsA==} + peerDependencies: + vue: ^3.5.0 + '@vueuse/metadata@11.3.0': resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==} + '@vueuse/metadata@13.9.0': + resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} + '@vueuse/shared@11.3.0': resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==} + '@vueuse/shared@13.9.0': + resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} + peerDependencies: + vue: ^3.5.0 + abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -1923,6 +2087,10 @@ packages: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + globby@15.0.0: resolution: {integrity: sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==} engines: {node: '>=20'} @@ -2211,6 +2379,9 @@ packages: resolution: {integrity: sha512-zPPuIt+ku1iCpFBRwseMcPYQ1cJL8l60rSmKeOuGfOXyE6YnTBmf2aEFNL2HQGrD0cPcLO/t+v9RTgC+fwEh/g==} engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4} + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + launch-editor@2.11.1: resolution: {integrity: sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==} @@ -2326,6 +2497,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mini-svg-data-uri@1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2818,6 +2993,10 @@ packages: peerDependencies: postcss: ^8.4.32 + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} @@ -3179,6 +3358,9 @@ packages: peerDependencies: tailwindcss: 1 || 2 || 2.0.1-compat || 3 + tailwind-merge@2.6.0: + resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + tailwindcss@3.4.18: resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==} engines: {node: '>=14.0.0'} @@ -3640,6 +3822,13 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.5.0 + tinyexec: 1.0.1 + + '@antfu/utils@8.1.1': {} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -3913,6 +4102,43 @@ snapshots: '@esbuild/win32-x64@0.25.11': optional: true + '@headlessui/tailwindcss@0.2.2(tailwindcss@3.4.18(yaml@2.8.1))': + dependencies: + tailwindcss: 3.4.18(yaml@2.8.1) + + '@headlessui/vue@1.7.23(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@tanstack/vue-virtual': 3.13.12(vue@3.5.22(typescript@5.9.3)) + vue: 3.5.22(typescript@5.9.3) + + '@iconify-json/heroicons@1.2.3': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/collections@1.0.608': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.3 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.2 + mlly: 1.8.0 + transitivePeerDependencies: + - supports-color + + '@iconify/vue@5.0.0(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@iconify/types': 2.0.0 + vue: 3.5.22(typescript@5.9.3) + '@ioredis/commands@1.4.0': {} '@isaacs/cliui@8.0.2': @@ -4096,6 +4322,28 @@ snapshots: - utf-8-validate - vue + '@nuxt/icon@1.15.0(magicast@0.3.5)(vite@7.1.11(@types/node@20.19.23)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@iconify/collections': 1.0.608 + '@iconify/types': 2.0.0 + '@iconify/utils': 2.3.0 + '@iconify/vue': 5.0.0(vue@3.5.22(typescript@5.9.3)) + '@nuxt/devtools-kit': 2.6.5(magicast@0.3.5)(vite@7.1.11(@types/node@20.19.23)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1)) + '@nuxt/kit': 3.19.3(magicast@0.3.5) + consola: 3.4.2 + local-pkg: 1.1.2 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - magicast + - supports-color + - vite + - vue + '@nuxt/kit@3.19.3(magicast@0.3.5)': dependencies: c12: 3.3.1(magicast@0.3.5) @@ -4178,6 +4426,52 @@ snapshots: transitivePeerDependencies: - magicast + '@nuxt/ui@2.22.3(magicast@0.3.5)(vite@7.1.11(@types/node@20.19.23)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)(zod@3.25.76)': + dependencies: + '@headlessui/tailwindcss': 0.2.2(tailwindcss@3.4.18(yaml@2.8.1)) + '@headlessui/vue': 1.7.23(vue@3.5.22(typescript@5.9.3)) + '@iconify-json/heroicons': 1.2.3 + '@nuxt/icon': 1.15.0(magicast@0.3.5)(vite@7.1.11(@types/node@20.19.23)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) + '@nuxt/kit': 4.1.3(magicast@0.3.5) + '@nuxtjs/color-mode': 3.5.2(magicast@0.3.5) + '@nuxtjs/tailwindcss': 6.14.0(magicast@0.3.5)(yaml@2.8.1) + '@popperjs/core': 2.11.8 + '@standard-schema/spec': 1.0.0 + '@tailwindcss/aspect-ratio': 0.4.2(tailwindcss@3.4.18(yaml@2.8.1)) + '@tailwindcss/container-queries': 0.1.1(tailwindcss@3.4.18(yaml@2.8.1)) + '@tailwindcss/forms': 0.5.10(tailwindcss@3.4.18(yaml@2.8.1)) + '@tailwindcss/typography': 0.5.19(tailwindcss@3.4.18(yaml@2.8.1)) + '@vueuse/core': 13.9.0(vue@3.5.22(typescript@5.9.3)) + '@vueuse/integrations': 13.9.0(fuse.js@7.1.0)(vue@3.5.22(typescript@5.9.3)) + '@vueuse/math': 13.9.0(vue@3.5.22(typescript@5.9.3)) + defu: 6.1.4 + fuse.js: 7.1.0 + ohash: 2.0.11 + pathe: 2.0.3 + scule: 1.3.0 + tailwind-merge: 2.6.0 + tailwindcss: 3.4.18(yaml@2.8.1) + optionalDependencies: + zod: 3.25.76 + transitivePeerDependencies: + - async-validator + - axios + - change-case + - drauu + - focus-trap + - idb-keyval + - jwt-decode + - magicast + - nprogress + - qrcode + - sortablejs + - supports-color + - tsx + - universal-cookie + - vite + - vue + - yaml + '@nuxt/vite-builder@4.1.3(@types/node@20.19.23)(magicast@0.3.5)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)': dependencies: '@nuxt/kit': 4.1.3(magicast@0.3.5) @@ -4235,6 +4529,15 @@ snapshots: - vue-tsc - yaml + '@nuxtjs/color-mode@3.5.2(magicast@0.3.5)': + dependencies: + '@nuxt/kit': 3.19.3(magicast@0.3.5) + pathe: 1.1.2 + pkg-types: 1.3.1 + semver: 7.7.3 + transitivePeerDependencies: + - magicast + '@nuxtjs/tailwindcss@6.14.0(magicast@0.3.5)(yaml@2.8.1)': dependencies: '@nuxt/kit': 3.19.3(magicast@0.3.5) @@ -4482,6 +4785,8 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@popperjs/core@2.11.8': {} + '@poppinss/colors@4.1.5': dependencies: kleur: 4.1.5 @@ -4635,6 +4940,33 @@ snapshots: '@speed-highlight/core@1.2.7': {} + '@standard-schema/spec@1.0.0': {} + + '@tailwindcss/aspect-ratio@0.4.2(tailwindcss@3.4.18(yaml@2.8.1))': + dependencies: + tailwindcss: 3.4.18(yaml@2.8.1) + + '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.18(yaml@2.8.1))': + dependencies: + tailwindcss: 3.4.18(yaml@2.8.1) + + '@tailwindcss/forms@0.5.10(tailwindcss@3.4.18(yaml@2.8.1))': + dependencies: + mini-svg-data-uri: 1.4.4 + tailwindcss: 3.4.18(yaml@2.8.1) + + '@tailwindcss/typography@0.5.19(tailwindcss@3.4.18(yaml@2.8.1))': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.18(yaml@2.8.1) + + '@tanstack/virtual-core@3.13.12': {} + + '@tanstack/vue-virtual@3.13.12(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@tanstack/virtual-core': 3.13.12 + vue: 3.5.22(typescript@5.9.3) + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -4654,6 +4986,8 @@ snapshots: '@types/web-bluetooth@0.0.20': {} + '@types/web-bluetooth@0.0.21': {} + '@unhead/vue@2.0.19(vue@3.5.22(typescript@5.9.3))': dependencies: hookable: 5.5.3 @@ -4846,8 +5180,30 @@ snapshots: - '@vue/composition-api' - vue + '@vueuse/core@13.9.0(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.9.0 + '@vueuse/shared': 13.9.0(vue@3.5.22(typescript@5.9.3)) + vue: 3.5.22(typescript@5.9.3) + + '@vueuse/integrations@13.9.0(fuse.js@7.1.0)(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@vueuse/core': 13.9.0(vue@3.5.22(typescript@5.9.3)) + '@vueuse/shared': 13.9.0(vue@3.5.22(typescript@5.9.3)) + vue: 3.5.22(typescript@5.9.3) + optionalDependencies: + fuse.js: 7.1.0 + + '@vueuse/math@13.9.0(vue@3.5.22(typescript@5.9.3))': + dependencies: + '@vueuse/shared': 13.9.0(vue@3.5.22(typescript@5.9.3)) + vue: 3.5.22(typescript@5.9.3) + '@vueuse/metadata@11.3.0': {} + '@vueuse/metadata@13.9.0': {} + '@vueuse/shared@11.3.0(vue@3.5.22(typescript@5.9.3))': dependencies: vue-demi: 0.14.10(vue@3.5.22(typescript@5.9.3)) @@ -4855,6 +5211,10 @@ snapshots: - '@vue/composition-api' - vue + '@vueuse/shared@13.9.0(vue@3.5.22(typescript@5.9.3))': + dependencies: + vue: 3.5.22(typescript@5.9.3) + abbrev@3.0.1: {} abort-controller@3.0.0: @@ -5586,6 +5946,8 @@ snapshots: dependencies: ini: 4.1.1 + globals@15.15.0: {} + globby@15.0.0: dependencies: '@sindresorhus/merge-streams': 4.0.0 @@ -5889,6 +6251,8 @@ snapshots: transitivePeerDependencies: - supports-color + kolorist@1.8.0: {} + launch-editor@2.11.1: dependencies: picocolors: 1.1.1 @@ -6006,6 +6370,8 @@ snapshots: mimic-fn@4.0.0: {} + mini-svg-data-uri@1.4.4: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -6688,6 +7054,11 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 @@ -7072,6 +7443,8 @@ snapshots: transitivePeerDependencies: - supports-color + tailwind-merge@2.6.0: {} + tailwindcss@3.4.18(yaml@2.8.1): dependencies: '@alloc/quick-lru': 5.2.0 diff --git a/stores/board.ts b/stores/board.ts index 5aac1ec..5fd2a89 100644 --- a/stores/board.ts +++ b/stores/board.ts @@ -113,6 +113,28 @@ export const useBoardStore = defineStore('board', () => { const stageById = (id: string) => board.value.stages.find(s => s.uuid === id) const categoryById = (id: string) => board.value.categories.find(c => c.uuid === id) + function addCategory(title: string, color: string) { + const c: Category = { uuid: uuid(), title, color } + board.value.categories.push(c) + log('category-add', { id: c.uuid, title, color }) + return c + } + function updateCategory(id: string, patch: Partial) { + const c = categoryById(id) + if (!c) return false + const before = JSON.parse(JSON.stringify(c)) + Object.assign(c, patch) + log('category-update', { id, before, after: c }) + return true + } + function removeCategory(id: string) { + const used = board.value.tasks.some(t => t.category === id) + if (used) return false + board.value.categories = board.value.categories.filter(c => c.uuid !== id) + log('category-delete', { id }) + return true + } + function addStage(title: string, colIndex = 0) { const s: Stage = { uuid: uuid(), title, tasks: [] } board.value.stages.push(s) @@ -188,8 +210,8 @@ export const useBoardStore = defineStore('board', () => { setBoard, setActor, log, saveToLocal, loadFromLocal, clearLocal, toJSON, downloadCurrent, applyMerge, addStage, renameStage, deleteStage, addTask, removeTask, editTask, moveTask, + addCategory, updateCategory, removeCategory, taskById, stageById, categoryById, diffBoards } }) - diff --git a/tailwind.config.ts b/tailwind.config.ts index 9cf19ea..7f64e91 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -19,6 +19,5 @@ export default { } } }, - plugins: [] + plugins: [], } satisfies Config -