From d0cbda7c0d80b64e4a73c2698f908146c8265c8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:00:32 +0000 Subject: [PATCH 1/7] chore(deps): update ckeditor5 config packages to v12.1.0 --- pnpm-lock.yaml | 247 ++++++++----------------------------------------- 1 file changed, 40 insertions(+), 207 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bf024c48..c7d51ae31 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -910,7 +910,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -922,7 +922,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -970,7 +970,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -982,7 +982,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -1030,7 +1030,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -1042,7 +1042,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -1097,7 +1097,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -1109,7 +1109,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -1164,7 +1164,7 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + version: 12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) http-server: specifier: ^14.1.0 version: 14.1.1 @@ -1176,7 +1176,7 @@ importers: version: 16.22.0(typescript@5.8.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + version: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) ts-node: specifier: ^10.9.1 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3) @@ -3151,6 +3151,10 @@ packages: resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.3.4': + resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@excalidraw/excalidraw@0.18.0': resolution: {integrity: sha512-QkIiS+5qdy8lmDWTKsuy0sK/fen/LRDtbhm2lc2xcFcqhv2/zdg95bYnl+wnwwXGHo7kEmP65BSiMHE7PJ3Zpw==} peerDependencies: @@ -5908,14 +5912,6 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.36.0': - resolution: {integrity: sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.36.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/eslint-plugin@8.38.0': resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5924,13 +5920,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.36.0': - resolution: {integrity: sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.38.0': resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5938,45 +5927,22 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/project-service@8.36.0': - resolution: {integrity: sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/project-service@8.38.0': resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/scope-manager@8.36.0': - resolution: {integrity: sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.38.0': resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.36.0': - resolution: {integrity: sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/tsconfig-utils@8.38.0': resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.36.0': - resolution: {integrity: sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.38.0': resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5984,33 +5950,16 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/types@8.36.0': - resolution: {integrity: sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.38.0': resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.36.0': - resolution: {integrity: sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/typescript-estree@8.38.0': resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.36.0': - resolution: {integrity: sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.38.0': resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6018,10 +5967,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/visitor-keys@8.36.0': - resolution: {integrity: sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.38.0': resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8441,8 +8386,8 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-ckeditor5@12.0.0: - resolution: {integrity: sha512-7slnS3fBU1Qv+CA+haTfFF09p/ShQWMWUysSuUdeIZrLKJ+AaQvWV8R0yx+bLVC5PBRA5q9utrTix916l+2PQg==} + eslint-config-ckeditor5@12.1.0: + resolution: {integrity: sha512-lbmgyvrIEIm7MhzlFkBkegeMPhpiJzJCHw5ZNu8zhxOxVisSron0+4+enjy2CSEXmsolWk4tl4vpB5dSwID7Fg==} peerDependencies: eslint: ^9.0.0 typescript: ^5.0.0 @@ -8456,8 +8401,8 @@ packages: eslint-linter-browserify@9.31.0: resolution: {integrity: sha512-Utv/GchpL5EkPK1FcYvPjdfcYl6nEr2SaJgY4cZHRt/IVGxvojhdZQLHSC9CTpWVWt1fQ7McrzyfCCD1QxB9ow==} - eslint-plugin-ckeditor5-rules@12.0.0: - resolution: {integrity: sha512-DGQa6rYuZhSq0I8zr8iD/l7PPl3owDLIdFsvOX36uJsykO0onNtKCSSNs6jhc55WJWchqdKPtKCxNSbEAQeT6w==} + eslint-plugin-ckeditor5-rules@12.1.0: + resolution: {integrity: sha512-tu8xYJkQ9CZzS+cDsBvnaKdADJVNzGNl/4a8i7A538y/YifyAiSMCSQOeefx5Ej27bBL+Wo9WlgeuLmjiyTP+A==} eslint-plugin-mocha@11.1.0: resolution: {integrity: sha512-rKntVWRsQFPbf8OkSgVNRVRrcVAPaGTyEgWCEyXaPDJkTl0v5/lwu1vTk5sWiUJU8l2sxwvGUZzSNrEKdVMeQw==} @@ -13823,8 +13768,8 @@ packages: peerDependencies: postcss: ^8.4.32 - stylelint-config-ckeditor5@12.0.0: - resolution: {integrity: sha512-PviRRAUJ2JpKhAO4UYw6dykAFpy/DHb58wRKDDwoVf9l/mup7l1Q3AFFVQO8zYVHxVlhQXqcWrAfYCPMhX3JjQ==} + stylelint-config-ckeditor5@12.1.0: + resolution: {integrity: sha512-6JDfp60U2XNba8xmXl4K4R5ix+YM/0ZoWUbdIhVl+WNVVJG0P21jRzQjIb1QbTVE8xjS3kdc9S7kErY3ch5zgw==} peerDependencies: stylelint: '>=16.0.0' @@ -13844,8 +13789,8 @@ packages: peerDependencies: stylelint: '>=10.1.0' - stylelint-plugin-ckeditor5-rules@12.0.0: - resolution: {integrity: sha512-DDs3+MKDh4SUO63AObc3jY9NJpTrAgtbLDpgiirxh49ib40OrlzAHZxy6quJeoPxmkS/ZFU7ocVBrycFGTGRfw==} + stylelint-plugin-ckeditor5-rules@12.1.0: + resolution: {integrity: sha512-RKTrDvmVOH4vb1oLjcuIql7sq/JzbFCmkd6St5S9eDo8mvquzbjIi0fq9DT+oAhdb3dM4G+eNpniF12L68VLmw==} peerDependencies: stylelint: '>=16.0.0' @@ -14327,13 +14272,6 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.36.0: - resolution: {integrity: sha512-fTCqxthY+h9QbEgSIBfL9iV6CvKDFuoxg6bHPNpJ9HIUzS+jy2lCEyCmGyZRWEBSaykqcDPf1SJ+BfCI8DRopA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - typescript-eslint@8.38.0: resolution: {integrity: sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -14603,10 +14541,6 @@ packages: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - validate-npm-package-name@6.0.1: - resolution: {integrity: sha512-OaI//3H0J7ZkR1OqlhGA8cA+Cbk/2xFOQpJOt5+s27/ta9eZwpeervh4Mxh4w0im/kdgktowaqVNR7QOrUd7Yg==} - engines: {node: ^18.17.0 || >=20.5.0} - validate-npm-package-name@6.0.2: resolution: {integrity: sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -16732,8 +16666,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-watchdog': 46.0.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-dev-build-tools@43.1.0(@swc/helpers@0.5.17)(tslib@2.8.1)(typescript@5.8.3)': dependencies: @@ -16925,6 +16857,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 46.0.0 ckeditor5: 46.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-multi-root@46.0.0': dependencies: @@ -17420,8 +17354,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-utils': 46.0.0 ckeditor5: 46.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@46.0.0': dependencies: @@ -18483,7 +18415,7 @@ snapshots: '@eslint/markdown@6.6.0': dependencies: '@eslint/core': 0.14.0 - '@eslint/plugin-kit': 0.3.3 + '@eslint/plugin-kit': 0.3.4 github-slugger: 2.0.0 mdast-util-from-markdown: 2.0.2 mdast-util-frontmatter: 2.0.1 @@ -18500,6 +18432,11 @@ snapshots: '@eslint/core': 0.15.1 levn: 0.4.1 + '@eslint/plugin-kit@0.3.4': + dependencies: + '@eslint/core': 0.15.1 + levn: 0.4.1 + '@excalidraw/excalidraw@0.18.0(@types/react-dom@19.1.6(@types/react@19.1.7))(@types/react@19.1.7)(react-dom@19.1.0(react@16.14.0))(react@16.14.0)': dependencies: '@braintree/sanitize-url': 6.0.2 @@ -20975,12 +20912,12 @@ snapshots: '@stylistic/eslint-plugin@4.4.1(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + '@typescript-eslint/utils': 8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) eslint: 9.31.0(jiti@2.5.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 - picomatch: 4.0.2 + picomatch: 4.0.3 transitivePeerDependencies: - supports-color - typescript @@ -21831,23 +21768,6 @@ snapshots: '@types/node': 22.16.5 optional: true - '@typescript-eslint/eslint-plugin@8.36.0(@typescript-eslint/parser@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.36.0 - '@typescript-eslint/type-utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.36.0 - eslint: 9.31.0(jiti@2.5.0) - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -21865,18 +21785,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.36.0 - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.36.0 - debug: 4.4.1(supports-color@6.0.0) - eslint: 9.31.0(jiti@2.5.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.38.0 @@ -21889,15 +21797,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.36.0(typescript@5.8.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3) - '@typescript-eslint/types': 8.36.0 - debug: 4.4.1(supports-color@6.0.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/project-service@8.38.0(typescript@5.8.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.8.3) @@ -21907,35 +21806,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.36.0': - dependencies: - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/visitor-keys': 8.36.0 - '@typescript-eslint/scope-manager@8.38.0': dependencies: '@typescript-eslint/types': 8.38.0 '@typescript-eslint/visitor-keys': 8.38.0 - '@typescript-eslint/tsconfig-utils@8.36.0(typescript@5.8.3)': - dependencies: - typescript: 5.8.3 - '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.8.3)': dependencies: typescript: 5.8.3 - '@typescript-eslint/type-utils@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - debug: 4.4.1(supports-color@6.0.0) - eslint: 9.31.0(jiti@2.5.0) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.38.0 @@ -21948,26 +21827,8 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.36.0': {} - '@typescript-eslint/types@8.38.0': {} - '@typescript-eslint/typescript-estree@8.36.0(typescript@5.8.3)': - dependencies: - '@typescript-eslint/project-service': 8.36.0(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.36.0(typescript@5.8.3) - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/visitor-keys': 8.36.0 - debug: 4.4.1(supports-color@6.0.0) - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.38.0(typescript@5.8.3)': dependencies: '@typescript-eslint/project-service': 8.38.0(typescript@5.8.3) @@ -21984,17 +21845,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.5.0)) - '@typescript-eslint/scope-manager': 8.36.0 - '@typescript-eslint/types': 8.36.0 - '@typescript-eslint/typescript-estree': 8.36.0(typescript@5.8.3) - eslint: 9.31.0(jiti@2.5.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/utils@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.5.0)) @@ -22006,11 +21856,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.36.0': - dependencies: - '@typescript-eslint/types': 8.36.0 - eslint-visitor-keys: 4.2.1 - '@typescript-eslint/visitor-keys@8.38.0': dependencies: '@typescript-eslint/types': 8.38.0 @@ -25081,17 +24926,17 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-ckeditor5@12.0.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): + eslint-config-ckeditor5@12.1.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): dependencies: '@eslint/js': 9.31.0 '@eslint/markdown': 6.6.0 '@stylistic/eslint-plugin': 4.4.1(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) eslint: 9.31.0(jiti@2.5.0) - eslint-plugin-ckeditor5-rules: 12.0.0 + eslint-plugin-ckeditor5-rules: 12.1.0 eslint-plugin-mocha: 11.1.0(eslint@9.31.0(jiti@2.5.0)) globals: 16.3.0 typescript: 5.8.3 - typescript-eslint: 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) + typescript-eslint: 8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) transitivePeerDependencies: - supports-color @@ -25101,14 +24946,14 @@ snapshots: eslint-linter-browserify@9.31.0: {} - eslint-plugin-ckeditor5-rules@12.0.0: + eslint-plugin-ckeditor5-rules@12.1.0: dependencies: '@es-joy/jsdoccomment': 0.50.2 enhanced-resolve: 5.18.2 fs-extra: 11.3.0 resolve.exports: 2.0.3 upath: 2.0.1 - validate-npm-package-name: 6.0.1 + validate-npm-package-name: 6.0.2 yaml: 2.8.0 eslint-plugin-mocha@11.1.0(eslint@9.31.0(jiti@2.5.0)): @@ -31562,12 +31407,12 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 7.1.0 - stylelint-config-ckeditor5@12.0.0(stylelint@16.22.0(typescript@5.8.3)): + stylelint-config-ckeditor5@12.1.0(stylelint@16.22.0(typescript@5.8.3)): dependencies: '@stylistic/stylelint-plugin': 3.1.3(stylelint@16.22.0(typescript@5.8.3)) stylelint: 16.22.0(typescript@5.8.3) stylelint-config-recommended: 16.0.0(stylelint@16.22.0(typescript@5.8.3)) - stylelint-plugin-ckeditor5-rules: 12.0.0(stylelint@16.22.0(typescript@5.8.3)) + stylelint-plugin-ckeditor5-rules: 12.1.0(stylelint@16.22.0(typescript@5.8.3)) stylelint-config-ckeditor5@2.0.1(stylelint@16.22.0(typescript@5.8.3)): dependencies: @@ -31582,7 +31427,7 @@ snapshots: dependencies: stylelint: 16.22.0(typescript@5.8.3) - stylelint-plugin-ckeditor5-rules@12.0.0(stylelint@16.22.0(typescript@5.8.3)): + stylelint-plugin-ckeditor5-rules@12.1.0(stylelint@16.22.0(typescript@5.8.3)): dependencies: stylelint: 16.22.0(typescript@5.8.3) @@ -32314,16 +32159,6 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.36.0(@typescript-eslint/parser@8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/parser': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - '@typescript-eslint/utils': 8.36.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) - eslint: 9.31.0(jiti@2.5.0) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - typescript-eslint@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3))(eslint@9.31.0(jiti@2.5.0))(typescript@5.8.3) @@ -32599,8 +32434,6 @@ snapshots: validate-npm-package-name@5.0.1: {} - validate-npm-package-name@6.0.1: {} - validate-npm-package-name@6.0.2: {} validator@13.15.0: {} From 88908934128c68eb45affbd256334775aecf4a51 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:01:27 +0000 Subject: [PATCH 2/7] chore(deps): update svelte monorepo --- pnpm-lock.yaml | 70 ++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bf024c48..4a770b55b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -807,13 +807,13 @@ importers: version: 9.31.0 '@sveltejs/adapter-auto': specifier: ^6.0.0 - version: 6.0.1(@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))) + version: 6.0.1(@sveltejs/kit@2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))) '@sveltejs/kit': specifier: ^2.16.0 - version: 2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + version: 2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) '@sveltejs/vite-plugin-svelte': specifier: ^6.0.0 - version: 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + version: 6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) '@tailwindcss/typography': specifier: ^0.5.15 version: 0.5.16(tailwindcss@4.1.11) @@ -825,19 +825,19 @@ importers: version: 9.31.0(jiti@2.5.0) eslint-plugin-svelte: specifier: ^3.0.0 - version: 3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.14)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)) + version: 3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.16)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)) globals: specifier: ^16.0.0 version: 16.3.0 mdsvex: specifier: ^0.12.3 - version: 0.12.6(svelte@5.36.14) + version: 0.12.6(svelte@5.36.16) svelte: specifier: ^5.0.0 - version: 5.36.14 + version: 5.36.16 svelte-check: specifier: ^4.0.0 - version: 4.3.0(picomatch@4.0.3)(svelte@5.36.14)(typescript@5.8.3) + version: 4.3.0(picomatch@4.0.3)(svelte@5.36.16)(typescript@5.8.3) tailwindcss: specifier: ^4.0.0 version: 4.1.11 @@ -5157,8 +5157,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.25.2': - resolution: {integrity: sha512-aKfj82vqEINedoH9Pw4Ip16jj3w8soNq9F3nJqc56kxXW74TcEu/gdTAuLUI+gsl8i+KXfetRqg1F+gG/AZRVQ==} + '@sveltejs/kit@2.26.0': + resolution: {integrity: sha512-TUxMYoK6Yim4uRIW0L7TXtlEtyLchy90PmInI7d1lPAPMchkBEvN3nVMkn5iTMUobxdLE5nR/YEU/4aYqezMuQ==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -13920,8 +13920,8 @@ packages: svelte: optional: true - svelte@5.36.14: - resolution: {integrity: sha512-okgNwfVa4FfDGOgd0ndooKjQz1LknUFDGfEJp6QNjYP6B4hDG0KktOP+Pta3ZtE8s+JELsYP+7nqMrJzQLkf5A==} + svelte@5.36.16: + resolution: {integrity: sha512-C7HnyISfvZEofs7T4p7+bmjrbQlhd6lZfgV2tLYg6Eb3nUFM/Zu9dGlSg+GWbUBU/WPw6zDPOFNZAx9qXsoCkg==} engines: {node: '>=18'} svg-pan-zoom@3.6.2: @@ -16732,8 +16732,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-watchdog': 46.0.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-dev-build-tools@43.1.0(@swc/helpers@0.5.17)(tslib@2.8.1)(typescript@5.8.3)': dependencies: @@ -16925,6 +16923,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 46.0.0 ckeditor5: 46.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-multi-root@46.0.0': dependencies: @@ -17420,8 +17420,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-utils': 46.0.0 ckeditor5: 46.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@46.0.0': dependencies: @@ -21001,14 +20999,14 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-auto@6.0.1(@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))': + '@sveltejs/adapter-auto@6.0.1(@sveltejs/kit@2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))': dependencies: - '@sveltejs/kit': 2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/kit': 2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) - '@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': + '@sveltejs/kit@2.26.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': dependencies: '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 1.0.2 @@ -21020,26 +21018,26 @@ snapshots: sade: 1.8.1 set-cookie-parser: 2.7.1 sirv: 3.0.1 - svelte: 5.36.14 + svelte: 5.36.16 vite: 7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0) - '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) debug: 4.4.1(supports-color@6.0.0) - svelte: 5.36.14 + svelte: 5.36.16 vite: 7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)))(svelte@5.36.16)(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) debug: 4.4.1(supports-color@6.0.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 - svelte: 5.36.14 + svelte: 5.36.16 vite: 7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0) vitefu: 1.1.1(vite@7.0.5(@types/node@24.1.0)(jiti@2.5.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)) transitivePeerDependencies: @@ -25122,7 +25120,7 @@ snapshots: eslint: 9.31.0(jiti@2.5.0) globals: 13.24.0 - eslint-plugin-svelte@3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.14)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)): + eslint-plugin-svelte@3.11.0(eslint@9.31.0(jiti@2.5.0))(svelte@5.36.16)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)): dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.5.0)) '@jridgewell/sourcemap-codec': 1.5.4 @@ -25134,9 +25132,9 @@ snapshots: postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.1.0)(typescript@5.8.3)) postcss-safe-parser: 7.0.1(postcss@8.5.6) semver: 7.7.2 - svelte-eslint-parser: 1.3.0(svelte@5.36.14) + svelte-eslint-parser: 1.3.0(svelte@5.36.16) optionalDependencies: - svelte: 5.36.14 + svelte: 5.36.16 transitivePeerDependencies: - ts-node @@ -27915,13 +27913,13 @@ snapshots: mdn-data@2.12.2: {} - mdsvex@0.12.6(svelte@5.36.14): + mdsvex@0.12.6(svelte@5.36.16): dependencies: '@types/mdast': 4.0.4 '@types/unist': 2.0.11 prism-svelte: 0.4.7 prismjs: 1.30.0 - svelte: 5.36.14 + svelte: 5.36.16 unist-util-visit: 2.0.3 vfile-message: 2.0.4 @@ -31736,19 +31734,19 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.3.0(picomatch@4.0.3)(svelte@5.36.14)(typescript@5.8.3): + svelte-check@4.3.0(picomatch@4.0.3)(svelte@5.36.16)(typescript@5.8.3): dependencies: '@jridgewell/trace-mapping': 0.3.29 chokidar: 4.0.3 fdir: 6.4.6(picomatch@4.0.3) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.36.14 + svelte: 5.36.16 typescript: 5.8.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.3.0(svelte@5.36.14): + svelte-eslint-parser@1.3.0(svelte@5.36.16): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -31757,9 +31755,9 @@ snapshots: postcss-scss: 4.0.9(postcss@8.5.6) postcss-selector-parser: 7.1.0 optionalDependencies: - svelte: 5.36.14 + svelte: 5.36.16 - svelte@5.36.14: + svelte@5.36.16: dependencies: '@ampproject/remapping': 2.3.0 '@jridgewell/sourcemap-codec': 1.5.4 From cb377248791ed98ebe745d8f340b293afb5dd1ae Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Wed, 23 Jul 2025 18:18:40 +0300 Subject: [PATCH 3/7] feat(views/board): basic column drag support --- .github/instructions/nx.instructions.md | 2 +- .../widgets/view_widgets/board_view/api.ts | 35 ++- .../board_view/differential_renderer.ts | 25 +- .../view_widgets/board_view/drag_handler.ts | 261 +++++++++++++++++- .../widgets/view_widgets/board_view/index.ts | 101 ++++++- 5 files changed, 397 insertions(+), 27 deletions(-) diff --git a/.github/instructions/nx.instructions.md b/.github/instructions/nx.instructions.md index 6c63651c8..c467932a2 100644 --- a/.github/instructions/nx.instructions.md +++ b/.github/instructions/nx.instructions.md @@ -4,7 +4,7 @@ applyTo: '**' // This file is automatically generated by Nx Console -You are in an nx workspace using Nx 21.3.1 and pnpm as the package manager. +You are in an nx workspace using Nx 21.3.2 and pnpm as the package manager. You have access to the Nx MCP server and the tools it provides. Use them. Follow these guidelines in order to best help the user: diff --git a/apps/client/src/widgets/view_widgets/board_view/api.ts b/apps/client/src/widgets/view_widgets/board_view/api.ts index 66bcc0f10..44dc2d6b2 100644 --- a/apps/client/src/widgets/view_widgets/board_view/api.ts +++ b/apps/client/src/widgets/view_widgets/board_view/api.ts @@ -110,12 +110,45 @@ export default class BoardApi { return columnValue; } + async reorderColumns(newColumnOrder: string[]) { + console.log("API: Reordering columns to:", newColumnOrder); + + // Update the column order in persisted data + if (!this.persistedData.columns) { + this.persistedData.columns = []; + } + + // Create a map of existing column data + const columnDataMap = new Map(); + this.persistedData.columns.forEach(col => { + columnDataMap.set(col.value, col); + }); + + // Reorder columns based on new order + this.persistedData.columns = newColumnOrder.map(columnValue => { + return columnDataMap.get(columnValue) || { value: columnValue }; + }); + + // Update internal columns array + this._columns = newColumnOrder; + + console.log("API: Updated internal columns to:", this._columns); + console.log("API: Updated persisted data:", this.persistedData.columns); + + await this.viewStorage.store(this.persistedData); + } + static async build(parentNote: FNote, viewStorage: ViewModeStorage) { const statusAttribute = parentNote.getLabelValue("board:groupBy") ?? "status"; let persistedData = await viewStorage.restore() ?? {}; const { byColumn, newPersistedData } = await getBoardData(parentNote, statusAttribute, persistedData); - const columns = Array.from(byColumn.keys()) || []; + + // Use the order from persistedData.columns, then add any new columns found + const orderedColumns = persistedData.columns?.map(col => col.value) || []; + const allColumns = Array.from(byColumn.keys()); + const newColumns = allColumns.filter(col => !orderedColumns.includes(col)); + const columns = [...orderedColumns, ...newColumns]; if (newPersistedData) { persistedData = newPersistedData; diff --git a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts index 797a525b5..7a2c682a7 100644 --- a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts +++ b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts @@ -241,15 +241,33 @@ export class DifferentialBoardRenderer { .addClass("board-column") .attr("data-column", column); - // Create header + // Create header with drag handle const $titleEl = $("

").attr("data-column-value", column); + + // Create drag handle + const $dragHandle = $("") + .addClass("column-drag-handle icon bx bx-menu") + .attr("title", "Drag to reorder column"); + + // Create title text const $titleText = $("").text(column); + + // Create title content container + const $titleContent = $("
") + .addClass("column-title-content") + .append($dragHandle, $titleText); + + // Create edit icon const $editIcon = $("") .addClass("edit-icon icon bx bx-edit-alt") .attr("title", "Click to edit column title"); - $titleEl.append($titleText, $editIcon); + + $titleEl.append($titleContent, $editIcon); $columnEl.append($titleEl); + // Setup column dragging + this.dragHandler.setupColumnDrag($columnEl, column); + // Handle wheel events for scrolling $columnEl.on("wheel", (event) => { const el = $columnEl[0]; @@ -259,7 +277,8 @@ export class DifferentialBoardRenderer { } }); - // Setup drop zone + // Setup drop zones for both notes and columns + this.dragHandler.setupNoteDropZone($columnEl, column); this.dragHandler.setupColumnDropZone($columnEl, column); // Add cards diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts index c11a68b8a..19653ce89 100644 --- a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts +++ b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts @@ -5,6 +5,8 @@ export interface DragContext { draggedNote: any; draggedBranch: any; draggedNoteElement: JQuery | null; + draggedColumn: string | null; + draggedColumnElement: JQuery | null; } export class BoardDragHandler { @@ -35,6 +37,54 @@ export class BoardDragHandler { this.setupTouchDrag($noteEl, note, branch); } + setupColumnDrag($columnEl: JQuery, columnValue: string) { + const $dragHandle = $columnEl.find('.column-drag-handle'); + + $dragHandle.attr("draggable", "true"); + + $dragHandle.on("dragstart", (e) => { + this.context.draggedColumn = columnValue; + this.context.draggedColumnElement = $columnEl; + $columnEl.addClass("column-dragging"); + + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.effectAllowed = "move"; + originalEvent.dataTransfer.setData("text/plain", columnValue); + } + + // Prevent note dragging when column is being dragged + e.stopPropagation(); + + // Setup global drag tracking for better drop indicator positioning + this.setupGlobalColumnDragTracking(); + }); + + $dragHandle.on("dragend", () => { + $columnEl.removeClass("column-dragging"); + this.$container.find('.board-column').removeClass('column-drag-over'); + this.context.draggedColumn = null; + this.context.draggedColumnElement = null; + this.cleanupColumnDropIndicators(); + this.cleanupGlobalColumnDragTracking(); + }); + } + + private setupGlobalColumnDragTracking() { + // Add container-level drag tracking for better indicator positioning + this.$container.on("dragover.columnDrag", (e) => { + if (this.context.draggedColumn) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + this.showColumnDropIndicator(originalEvent.clientX); + } + }); + } + + private cleanupGlobalColumnDragTracking() { + this.$container.off("dragover.columnDrag"); + } + updateApi(newApi: BoardApi) { this.api = newApi; } @@ -42,10 +92,16 @@ export class BoardDragHandler { private cleanupAllDropIndicators() { // Remove all drop indicators from the DOM to prevent layout issues this.$container.find(".board-drop-indicator").remove(); + this.$container.find(".column-drop-indicator").remove(); } - private cleanupColumnDropIndicators($columnEl: JQuery) { - // Remove drop indicators from a specific column + private cleanupColumnDropIndicators() { + // Remove column drop indicators + this.$container.find(".column-drop-indicator").remove(); + } + + private cleanupNoteDropIndicators($columnEl: JQuery) { + // Remove note drop indicators from a specific column $columnEl.find(".board-drop-indicator").remove(); } @@ -53,6 +109,10 @@ export class BoardDragHandler { cleanup() { this.cleanupAllDropIndicators(); this.$container.find('.board-column').removeClass('drag-over'); + this.$container.find('.board-column').removeClass('column-drag-over'); + this.context.draggedColumn = null; + this.context.draggedColumnElement = null; + this.cleanupGlobalColumnDragTracking(); } private setupMouseDrag($noteEl: JQuery, note: any, branch: any) { @@ -175,15 +235,16 @@ export class BoardDragHandler { }); } - setupColumnDropZone($columnEl: JQuery, column: string) { + setupNoteDropZone($columnEl: JQuery, column: string) { $columnEl.on("dragover", (e) => { - e.preventDefault(); - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.dropEffect = "move"; - } + // Only handle note drops when a note is being dragged + if (this.context.draggedNote && !this.context.draggedColumn) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.dropEffect = "move"; + } - if (this.context.draggedNote) { $columnEl.addClass("drag-over"); this.showDropIndicator($columnEl, e); } @@ -198,16 +259,59 @@ export class BoardDragHandler { if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { $columnEl.removeClass("drag-over"); - this.cleanupColumnDropIndicators($columnEl); + this.cleanupNoteDropIndicators($columnEl); } }); $columnEl.on("drop", async (e) => { - e.preventDefault(); - $columnEl.removeClass("drag-over"); + if (this.context.draggedNote && !this.context.draggedColumn) { + e.preventDefault(); + $columnEl.removeClass("drag-over"); - if (this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { - await this.handleNoteDrop($columnEl, column); + if (this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { + await this.handleNoteDrop($columnEl, column); + } + } + }); + } + + setupColumnDropZone($columnEl: JQuery, columnValue: string) { + $columnEl.on("dragover", (e) => { + // Only handle column drops when a column is being dragged + if (this.context.draggedColumn && !this.context.draggedNote) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.dropEffect = "move"; + } + + if (this.context.draggedColumn !== columnValue) { + $columnEl.addClass("column-drag-over"); + } + } + }); + + $columnEl.on("dragleave", (e) => { + if (this.context.draggedColumn && !this.context.draggedNote) { + const rect = $columnEl[0].getBoundingClientRect(); + const originalEvent = e.originalEvent as DragEvent; + const x = originalEvent.clientX; + const y = originalEvent.clientY; + + if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { + $columnEl.removeClass("column-drag-over"); + } + } + }); + + $columnEl.on("drop", async (e) => { + if (this.context.draggedColumn && !this.context.draggedNote) { + e.preventDefault(); + $columnEl.removeClass("column-drag-over"); + + if (this.context.draggedColumn !== columnValue) { + await this.handleColumnDrop($columnEl, columnValue); + } } }); } @@ -245,7 +349,7 @@ export class BoardDragHandler { const relativeY = y - columnRect.top; // Clean up any existing drop indicators in this column first - this.cleanupColumnDropIndicators($columnEl); + this.cleanupNoteDropIndicators($columnEl); // Create a new drop indicator const $dropIndicator = $("
").addClass("board-drop-indicator"); @@ -277,6 +381,63 @@ export class BoardDragHandler { $dropIndicator.addClass("show"); } + private showColumnDropIndicator(mouseX: number) { + // Clean up existing indicators + this.cleanupColumnDropIndicators(); + + // Get all columns (excluding the dragged one if it exists) + let $allColumns = this.$container.find('.board-column'); + if (this.context.draggedColumnElement) { + $allColumns = $allColumns.not(this.context.draggedColumnElement); + } + + let $targetColumn: JQuery = $(); + let insertBefore = false; + + // Find which column the mouse is closest to + $allColumns.each((_, columnEl) => { + const $column = $(columnEl); + const rect = columnEl.getBoundingClientRect(); + const columnMiddle = rect.left + rect.width / 2; + + if (mouseX >= rect.left && mouseX <= rect.right) { + // Mouse is over this column + $targetColumn = $column; + insertBefore = mouseX < columnMiddle; + return false; // Break the loop + } + }); + + // If no column found under mouse, find the closest one + if ($targetColumn.length === 0) { + let closestDistance = Infinity; + $allColumns.each((_, columnEl) => { + const $column = $(columnEl); + const rect = columnEl.getBoundingClientRect(); + const columnCenter = rect.left + rect.width / 2; + const distance = Math.abs(mouseX - columnCenter); + + if (distance < closestDistance) { + closestDistance = distance; + $targetColumn = $column; + insertBefore = mouseX < columnCenter; + } + }); + } + + if ($targetColumn.length > 0) { + const $dropIndicator = $("
").addClass("column-drop-indicator"); + + if (insertBefore) { + $targetColumn.before($dropIndicator); + } else { + $targetColumn.after($dropIndicator); + } + + $dropIndicator.addClass("show"); + } + } + private async handleNoteDrop($columnEl: JQuery, column: string) { const draggedNoteElement = this.context.draggedNoteElement; const draggedNote = this.context.draggedNote; @@ -337,4 +498,74 @@ export class BoardDragHandler { } } } + + private async handleColumnDrop($targetColumnEl: JQuery, targetColumnValue: string) { + if (!this.context.draggedColumn || !this.context.draggedColumnElement) { + return; + } + + try { + // Get current column order from the DOM + const currentOrder = Array.from(this.$container.find('.board-column')).map(el => + $(el).attr('data-column') + ).filter(col => col) as string[]; + + console.log("Current order:", currentOrder); + console.log("Dragged column:", this.context.draggedColumn); + console.log("Target column:", targetColumnValue); + + // Find the drop indicator to determine insert position + const $dropIndicator = this.$container.find(".column-drop-indicator.show"); + + if ($dropIndicator.length > 0) { + let newOrder = [...currentOrder]; + + // Remove dragged column from current position + newOrder = newOrder.filter(col => col !== this.context.draggedColumn); + + // Determine insertion position based on drop indicator + const $nextColumn = $dropIndicator.next('.board-column'); + const $prevColumn = $dropIndicator.prev('.board-column'); + + let insertIndex = -1; + + if ($nextColumn.length > 0) { + // Insert before the next column + const nextColumnValue = $nextColumn.attr('data-column'); + insertIndex = newOrder.indexOf(nextColumnValue!); + } else if ($prevColumn.length > 0) { + // Insert after the previous column + const prevColumnValue = $prevColumn.attr('data-column'); + insertIndex = newOrder.indexOf(prevColumnValue!) + 1; + } else { + // Insert at the beginning + insertIndex = 0; + } + + // Insert the dragged column at the determined position + if (insertIndex >= 0) { + newOrder.splice(insertIndex, 0, this.context.draggedColumn); + } else { + // Fallback: insert at the end + newOrder.push(this.context.draggedColumn); + } + + console.log("New order:", newOrder); + + // Update column order in API + await this.api.reorderColumns(newOrder); + + console.log(`Moved column "${this.context.draggedColumn}" to new position`); + + // Refresh the board to reflect the changes + await this.onBoardRefresh(); + } else { + console.warn("No drop indicator found for column drop"); + } + } catch (error) { + console.error("Failed to reorder columns:", error); + } finally { + this.cleanupColumnDropIndicators(); + } + } } diff --git a/apps/client/src/widgets/view_widgets/board_view/index.ts b/apps/client/src/widgets/view_widgets/board_view/index.ts index a438d6282..cadb3d38e 100644 --- a/apps/client/src/widgets/view_widgets/board_view/index.ts +++ b/apps/client/src/widgets/view_widgets/board_view/index.ts @@ -70,6 +70,47 @@ const TPL = /*html*/` border-radius: 4px; } + .board-view-container .board-column h3 .column-title-content { + display: flex; + align-items: center; + flex: 1; + min-width: 0; /* Allow text to truncate */ + } + + .board-view-container .board-column h3 .column-drag-handle { + margin-right: 0.5em; + color: var(--muted-text-color); + cursor: grab; + opacity: 0; + transition: opacity 0.2s ease; + padding: 0.25em; + border-radius: 3px; + } + + .board-view-container .board-column h3:hover .column-drag-handle { + opacity: 1; + } + + .board-view-container .board-column h3 .column-drag-handle:hover { + background-color: var(--main-background-color); + color: var(--main-text-color); + } + + .board-view-container .board-column h3 .column-drag-handle:active { + cursor: grabbing; + } + + .board-view-container .board-column.column-dragging { + opacity: 0.6; + transform: scale(0.98); + transition: opacity 0.2s ease, transform 0.2s ease; + } + + .board-view-container .board-column.column-drag-over { + border-color: var(--main-text-color); + background-color: var(--hover-item-background-color); + } + .board-view-container .board-column h3 input { background: transparent; border: none; @@ -172,6 +213,22 @@ const TPL = /*html*/` opacity: 1; } + .column-drop-indicator { + width: 4px; + background-color: var(--main-text-color); + border-radius: 2px; + opacity: 0; + transition: opacity 0.2s ease; + height: 100%; + z-index: 1000; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.3); + flex-shrink: 0; + } + + .column-drop-indicator.show { + opacity: 1; + } + .board-new-item { margin-top: 0.5em; padding: 0.5em; @@ -274,7 +331,9 @@ export default class BoardView extends ViewMode { this.dragContext = { draggedNote: null, draggedBranch: null, - draggedNoteElement: null + draggedNoteElement: null, + draggedColumn: null, + draggedColumnElement: null }; args.$parent.append(this.$root); @@ -320,10 +379,10 @@ export default class BoardView extends ViewMode { } private setupBoardInteractions() { - // Handle column title editing - this.$container.on('click', 'h3[data-column-value]', (e) => { + // Handle column title editing - listen for clicks on the title content, not the drag handle + this.$container.on('click', 'h3[data-column-value] .column-title-content span:not(.column-drag-handle)', (e) => { e.stopPropagation(); - const $titleEl = $(e.currentTarget); + const $titleEl = $(e.currentTarget).closest('h3[data-column-value]'); const columnValue = $titleEl.attr('data-column-value'); if (columnValue) { const columnItems = this.api?.getColumn(columnValue) || []; @@ -331,6 +390,24 @@ export default class BoardView extends ViewMode { } }); + // Also handle clicks on the h3 element itself (but not on the drag handle) + this.$container.on('click', 'h3[data-column-value]', (e) => { + // Only proceed if the click wasn't on the drag handle or edit icon + if (!$(e.target).hasClass('column-drag-handle') && + !$(e.target).hasClass('edit-icon') && + !$(e.target).hasClass('bx-menu') && + !$(e.target).hasClass('bx-edit-alt')) { + + e.stopPropagation(); + const $titleEl = $(e.currentTarget); + const columnValue = $titleEl.attr('data-column-value'); + if (columnValue) { + const columnItems = this.api?.getColumn(columnValue) || []; + this.startEditingColumnTitle($titleEl, columnValue, columnItems); + } + } + }); + // Handle add column button this.$container.on('click', '.board-add-column', (e) => { e.stopPropagation(); @@ -339,12 +416,21 @@ export default class BoardView extends ViewMode { } private createTitleStructure(title: string): { $titleText: JQuery; $editIcon: JQuery } { + const $dragHandle = $("") + .addClass("column-drag-handle icon bx bx-menu") + .attr("title", "Drag to reorder column"); + const $titleText = $("").text(title); + + const $titleContent = $("
") + .addClass("column-title-content") + .append($dragHandle, $titleText); + const $editIcon = $("") .addClass("edit-icon icon bx bx-edit-alt") .attr("title", "Click to edit column title"); - return { $titleText, $editIcon }; + return { $titleText: $titleContent, $editIcon }; } private startEditingColumnTitle($titleEl: JQuery, columnValue: string, columnItems: { branch: any; note: any; }[]) { @@ -352,8 +438,9 @@ export default class BoardView extends ViewMode { return; // Already editing } - const $titleText = $titleEl.find("span").first(); - const currentTitle = $titleText.text(); + const $titleContent = $titleEl.find(".column-title-content"); + const $titleSpan = $titleContent.find("span").last(); // Get the text span, not the drag handle + const currentTitle = $titleSpan.text(); $titleEl.addClass("editing"); const $input = $("") From 4047452b0f023bcd29deab1f2e3c94650a093f44 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Wed, 23 Jul 2025 18:26:20 +0300 Subject: [PATCH 4/7] feat(views/board): drag works in between columns --- .../view_widgets/board_view/drag_handler.ts | 52 +++++++------------ .../widgets/view_widgets/board_view/index.ts | 5 -- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts index 19653ce89..6116a147c 100644 --- a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts +++ b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts @@ -62,7 +62,6 @@ export class BoardDragHandler { $dragHandle.on("dragend", () => { $columnEl.removeClass("column-dragging"); - this.$container.find('.board-column').removeClass('column-drag-over'); this.context.draggedColumn = null; this.context.draggedColumnElement = null; this.cleanupColumnDropIndicators(); @@ -109,7 +108,6 @@ export class BoardDragHandler { cleanup() { this.cleanupAllDropIndicators(); this.$container.find('.board-column').removeClass('drag-over'); - this.$container.find('.board-column').removeClass('column-drag-over'); this.context.draggedColumn = null; this.context.draggedColumnElement = null; this.cleanupGlobalColumnDragTracking(); @@ -285,33 +283,16 @@ export class BoardDragHandler { originalEvent.dataTransfer.dropEffect = "move"; } - if (this.context.draggedColumn !== columnValue) { - $columnEl.addClass("column-drag-over"); - } - } - }); - - $columnEl.on("dragleave", (e) => { - if (this.context.draggedColumn && !this.context.draggedNote) { - const rect = $columnEl[0].getBoundingClientRect(); - const originalEvent = e.originalEvent as DragEvent; - const x = originalEvent.clientX; - const y = originalEvent.clientY; - - if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { - $columnEl.removeClass("column-drag-over"); - } + // Don't highlight columns - we only care about the drop indicator position } }); $columnEl.on("drop", async (e) => { if (this.context.draggedColumn && !this.context.draggedNote) { e.preventDefault(); - $columnEl.removeClass("column-drag-over"); - if (this.context.draggedColumn !== columnValue) { - await this.handleColumnDrop($columnEl, columnValue); - } + // Use the drop indicator position to determine where to place the column + await this.handleColumnDrop(); } }); } @@ -499,31 +480,30 @@ export class BoardDragHandler { } } - private async handleColumnDrop($targetColumnEl: JQuery, targetColumnValue: string) { + private async handleColumnDrop() { if (!this.context.draggedColumn || !this.context.draggedColumnElement) { return; } try { - // Get current column order from the DOM - const currentOrder = Array.from(this.$container.find('.board-column')).map(el => - $(el).attr('data-column') - ).filter(col => col) as string[]; - - console.log("Current order:", currentOrder); - console.log("Dragged column:", this.context.draggedColumn); - console.log("Target column:", targetColumnValue); - // Find the drop indicator to determine insert position const $dropIndicator = this.$container.find(".column-drop-indicator.show"); if ($dropIndicator.length > 0) { + // Get current column order from the DOM + const currentOrder = Array.from(this.$container.find('.board-column')).map(el => + $(el).attr('data-column') + ).filter(col => col) as string[]; + + console.log("Current order:", currentOrder); + console.log("Dragged column:", this.context.draggedColumn); + let newOrder = [...currentOrder]; // Remove dragged column from current position newOrder = newOrder.filter(col => col !== this.context.draggedColumn); - // Determine insertion position based on drop indicator + // Determine insertion position based on drop indicator position const $nextColumn = $dropIndicator.next('.board-column'); const $prevColumn = $dropIndicator.prev('.board-column'); @@ -533,21 +513,25 @@ export class BoardDragHandler { // Insert before the next column const nextColumnValue = $nextColumn.attr('data-column'); insertIndex = newOrder.indexOf(nextColumnValue!); + console.log("Inserting before column:", nextColumnValue, "at index:", insertIndex); } else if ($prevColumn.length > 0) { // Insert after the previous column const prevColumnValue = $prevColumn.attr('data-column'); insertIndex = newOrder.indexOf(prevColumnValue!) + 1; + console.log("Inserting after column:", prevColumnValue, "at index:", insertIndex); } else { // Insert at the beginning insertIndex = 0; + console.log("Inserting at the beginning"); } // Insert the dragged column at the determined position - if (insertIndex >= 0) { + if (insertIndex >= 0 && insertIndex <= newOrder.length) { newOrder.splice(insertIndex, 0, this.context.draggedColumn); } else { // Fallback: insert at the end newOrder.push(this.context.draggedColumn); + console.log("Fallback: inserting at the end"); } console.log("New order:", newOrder); diff --git a/apps/client/src/widgets/view_widgets/board_view/index.ts b/apps/client/src/widgets/view_widgets/board_view/index.ts index cadb3d38e..1bdf7d21e 100644 --- a/apps/client/src/widgets/view_widgets/board_view/index.ts +++ b/apps/client/src/widgets/view_widgets/board_view/index.ts @@ -106,11 +106,6 @@ const TPL = /*html*/` transition: opacity 0.2s ease, transform 0.2s ease; } - .board-view-container .board-column.column-drag-over { - border-color: var(--main-text-color); - background-color: var(--hover-item-background-color); - } - .board-view-container .board-column h3 input { background: transparent; border: none; From b277f4bf3f8ace9f3ccee45c47af8383d211ba01 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Wed, 23 Jul 2025 18:29:34 +0300 Subject: [PATCH 5/7] feat(views/board): basic refresh after column change --- .../widgets/view_widgets/board_view/api.ts | 5 -- .../board_view/differential_renderer.ts | 56 +++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/apps/client/src/widgets/view_widgets/board_view/api.ts b/apps/client/src/widgets/view_widgets/board_view/api.ts index 44dc2d6b2..4b6f55e3c 100644 --- a/apps/client/src/widgets/view_widgets/board_view/api.ts +++ b/apps/client/src/widgets/view_widgets/board_view/api.ts @@ -111,8 +111,6 @@ export default class BoardApi { } async reorderColumns(newColumnOrder: string[]) { - console.log("API: Reordering columns to:", newColumnOrder); - // Update the column order in persisted data if (!this.persistedData.columns) { this.persistedData.columns = []; @@ -132,9 +130,6 @@ export default class BoardApi { // Update internal columns array this._columns = newColumnOrder; - console.log("API: Updated internal columns to:", this._columns); - console.log("API: Updated persisted data:", this.persistedData.columns); - await this.viewStorage.store(this.persistedData); } diff --git a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts index 7a2c682a7..9d08b90b3 100644 --- a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts +++ b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts @@ -133,6 +133,15 @@ export class DifferentialBoardRenderer { } private updateColumns(oldState: BoardState, newState: BoardState): void { + // Check if column order has changed + const orderChanged = !this.arraysEqual(oldState.columnOrder, newState.columnOrder); + + if (orderChanged) { + console.log("Column order changed from", oldState.columnOrder, "to", newState.columnOrder); + // If order changed, we need to reorder the columns in the DOM + this.reorderColumns(newState.columnOrder); + } + // Remove columns that no longer exist for (const oldColumn of oldState.columnOrder) { if (!newState.columnOrder.includes(oldColumn)) { @@ -161,6 +170,53 @@ export class DifferentialBoardRenderer { } } + private arraysEqual(a: string[], b: string[]): boolean { + return a.length === b.length && a.every((val, index) => val === b[index]); + } + + private reorderColumns(newOrder: string[]): void { + console.log("Reordering columns to:", newOrder); + + // Get all existing column elements + const $columns = this.$container.find('.board-column'); + const $addColumnButton = this.$container.find('.board-add-column'); + + // Create a map of column elements by their data-column attribute + const columnElements = new Map>(); + $columns.each((_, el) => { + const $el = $(el); + const columnValue = $el.attr('data-column'); + if (columnValue) { + columnElements.set(columnValue, $el); + } + }); + + // Remove all columns from DOM (but keep references) + $columns.detach(); + + // Re-insert columns in the new order + let $insertAfter: JQuery | null = null; + for (const columnValue of newOrder) { + const $columnEl = columnElements.get(columnValue); + if ($columnEl) { + if ($insertAfter) { + $insertAfter.after($columnEl); + } else { + // Insert at the beginning + this.$container.prepend($columnEl); + } + $insertAfter = $columnEl; + } + } + + // Ensure add column button is at the end + if ($addColumnButton.length) { + this.$container.append($addColumnButton); + } + + console.log("Column reordering complete"); + } + private updateColumnCards(column: string, oldCards: { note: any; branch: any }[], newCards: { note: any; branch: any }[]): void { const $column = this.$container.find(`[data-column="${column}"]`); if (!$column.length) return; From e2157aab26fde43d8b1ba2621605d3a228614f17 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Wed, 23 Jul 2025 18:35:58 +0300 Subject: [PATCH 6/7] fix(views/board): reordering same column not working --- .../board_view/differential_renderer.ts | 5 ----- .../view_widgets/board_view/drag_handler.ts | 17 ++--------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts index 9d08b90b3..a5ab3c9a8 100644 --- a/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts +++ b/apps/client/src/widgets/view_widgets/board_view/differential_renderer.ts @@ -137,7 +137,6 @@ export class DifferentialBoardRenderer { const orderChanged = !this.arraysEqual(oldState.columnOrder, newState.columnOrder); if (orderChanged) { - console.log("Column order changed from", oldState.columnOrder, "to", newState.columnOrder); // If order changed, we need to reorder the columns in the DOM this.reorderColumns(newState.columnOrder); } @@ -175,8 +174,6 @@ export class DifferentialBoardRenderer { } private reorderColumns(newOrder: string[]): void { - console.log("Reordering columns to:", newOrder); - // Get all existing column elements const $columns = this.$container.find('.board-column'); const $addColumnButton = this.$container.find('.board-add-column'); @@ -213,8 +210,6 @@ export class DifferentialBoardRenderer { if ($addColumnButton.length) { this.$container.append($addColumnButton); } - - console.log("Column reordering complete"); } private updateColumnCards(column: string, oldCards: { note: any; branch: any }[], newCards: { note: any; branch: any }[]): void { diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts index 6116a147c..e8bd183e7 100644 --- a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts +++ b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts @@ -490,13 +490,8 @@ export class BoardDragHandler { const $dropIndicator = this.$container.find(".column-drop-indicator.show"); if ($dropIndicator.length > 0) { - // Get current column order from the DOM - const currentOrder = Array.from(this.$container.find('.board-column')).map(el => - $(el).attr('data-column') - ).filter(col => col) as string[]; - - console.log("Current order:", currentOrder); - console.log("Dragged column:", this.context.draggedColumn); + // Get current column order from the API (source of truth) + const currentOrder = [...this.api.columns]; let newOrder = [...currentOrder]; @@ -513,16 +508,13 @@ export class BoardDragHandler { // Insert before the next column const nextColumnValue = $nextColumn.attr('data-column'); insertIndex = newOrder.indexOf(nextColumnValue!); - console.log("Inserting before column:", nextColumnValue, "at index:", insertIndex); } else if ($prevColumn.length > 0) { // Insert after the previous column const prevColumnValue = $prevColumn.attr('data-column'); insertIndex = newOrder.indexOf(prevColumnValue!) + 1; - console.log("Inserting after column:", prevColumnValue, "at index:", insertIndex); } else { // Insert at the beginning insertIndex = 0; - console.log("Inserting at the beginning"); } // Insert the dragged column at the determined position @@ -531,16 +523,11 @@ export class BoardDragHandler { } else { // Fallback: insert at the end newOrder.push(this.context.draggedColumn); - console.log("Fallback: inserting at the end"); } - console.log("New order:", newOrder); - // Update column order in API await this.api.reorderColumns(newOrder); - console.log(`Moved column "${this.context.draggedColumn}" to new position`); - // Refresh the board to reflect the changes await this.onBoardRefresh(); } else { From 4d455650ba2b6d0bc56653dfda80eb8335147db1 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Wed, 23 Jul 2025 19:16:44 +0300 Subject: [PATCH 7/7] refactor(views/board): split row/column handling --- .../board_view/column_drag_handler.ts | 240 ++++++++ .../view_widgets/board_view/drag_handler.ts | 537 +----------------- .../view_widgets/board_view/drag_types.ts | 12 + .../board_view/note_drag_handler.ts | 332 +++++++++++ 4 files changed, 613 insertions(+), 508 deletions(-) create mode 100644 apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts create mode 100644 apps/client/src/widgets/view_widgets/board_view/drag_types.ts create mode 100644 apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts diff --git a/apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts new file mode 100644 index 000000000..18fd9a945 --- /dev/null +++ b/apps/client/src/widgets/view_widgets/board_view/column_drag_handler.ts @@ -0,0 +1,240 @@ +import BoardApi from "./api"; +import { DragContext, BaseDragHandler } from "./drag_types"; + +export class ColumnDragHandler implements BaseDragHandler { + private $container: JQuery; + private api: BoardApi; + private context: DragContext; + private onBoardRefresh: () => Promise; + + constructor( + $container: JQuery, + api: BoardApi, + context: DragContext, + onBoardRefresh: () => Promise + ) { + this.$container = $container; + this.api = api; + this.context = context; + this.onBoardRefresh = onBoardRefresh; + } + + setupColumnDrag($columnEl: JQuery, columnValue: string) { + const $dragHandle = $columnEl.find('.column-drag-handle'); + + $dragHandle.attr("draggable", "true"); + + $dragHandle.on("dragstart", (e) => { + this.context.draggedColumn = columnValue; + this.context.draggedColumnElement = $columnEl; + $columnEl.addClass("column-dragging"); + + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.effectAllowed = "move"; + originalEvent.dataTransfer.setData("text/plain", columnValue); + } + + // Prevent note dragging when column is being dragged + e.stopPropagation(); + + // Setup global drag tracking for better drop indicator positioning + this.setupGlobalColumnDragTracking(); + }); + + $dragHandle.on("dragend", () => { + $columnEl.removeClass("column-dragging"); + this.context.draggedColumn = null; + this.context.draggedColumnElement = null; + this.cleanupColumnDropIndicators(); + this.cleanupGlobalColumnDragTracking(); + }); + } + + setupColumnDropZone($columnEl: JQuery, columnValue: string) { + $columnEl.on("dragover", (e) => { + // Only handle column drops when a column is being dragged + if (this.context.draggedColumn && !this.context.draggedNote) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.dropEffect = "move"; + } + + // Don't highlight columns - we only care about the drop indicator position + } + }); + + $columnEl.on("drop", async (e) => { + if (this.context.draggedColumn && !this.context.draggedNote) { + e.preventDefault(); + console.log("Column drop event triggered for column:", this.context.draggedColumn); + + // Use the drop indicator position to determine where to place the column + await this.handleColumnDrop(); + } + }); + } + + updateApi(newApi: BoardApi) { + this.api = newApi; + } + + cleanup() { + this.cleanupColumnDropIndicators(); + this.context.draggedColumn = null; + this.context.draggedColumnElement = null; + this.cleanupGlobalColumnDragTracking(); + } + + private setupGlobalColumnDragTracking() { + // Add container-level drag tracking for better indicator positioning + this.$container.on("dragover.columnDrag", (e) => { + if (this.context.draggedColumn) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + this.showColumnDropIndicator(originalEvent.clientX); + } + }); + + // Add container-level drop handler for column reordering + this.$container.on("drop.columnDrag", async (e) => { + if (this.context.draggedColumn) { + e.preventDefault(); + console.log("Container drop event triggered for column:", this.context.draggedColumn); + await this.handleColumnDrop(); + } + }); + } + + private cleanupGlobalColumnDragTracking() { + this.$container.off("dragover.columnDrag"); + this.$container.off("drop.columnDrag"); + } + + private cleanupColumnDropIndicators() { + // Remove column drop indicators + this.$container.find(".column-drop-indicator").remove(); + } + + private showColumnDropIndicator(mouseX: number) { + // Clean up existing indicators + this.cleanupColumnDropIndicators(); + + // Get all columns (excluding the dragged one if it exists) + let $allColumns = this.$container.find('.board-column'); + if (this.context.draggedColumnElement) { + $allColumns = $allColumns.not(this.context.draggedColumnElement); + } + + let $targetColumn: JQuery = $(); + let insertBefore = false; + + // Find which column the mouse is closest to + $allColumns.each((_, columnEl) => { + const $column = $(columnEl); + const rect = columnEl.getBoundingClientRect(); + const columnMiddle = rect.left + rect.width / 2; + + if (mouseX >= rect.left && mouseX <= rect.right) { + // Mouse is over this column + $targetColumn = $column; + insertBefore = mouseX < columnMiddle; + return false; // Break the loop + } + }); + + // If no column found under mouse, find the closest one + if ($targetColumn.length === 0) { + let closestDistance = Infinity; + $allColumns.each((_, columnEl) => { + const $column = $(columnEl); + const rect = columnEl.getBoundingClientRect(); + const columnCenter = rect.left + rect.width / 2; + const distance = Math.abs(mouseX - columnCenter); + + if (distance < closestDistance) { + closestDistance = distance; + $targetColumn = $column; + insertBefore = mouseX < columnCenter; + } + }); + } + + if ($targetColumn.length > 0) { + const $dropIndicator = $("
").addClass("column-drop-indicator"); + + if (insertBefore) { + $targetColumn.before($dropIndicator); + } else { + $targetColumn.after($dropIndicator); + } + + $dropIndicator.addClass("show"); + } + } + + private async handleColumnDrop() { + console.log("handleColumnDrop called for:", this.context.draggedColumn); + + if (!this.context.draggedColumn || !this.context.draggedColumnElement) { + console.log("No dragged column or element found"); + return; + } + + try { + // Find the drop indicator to determine insert position + const $dropIndicator = this.$container.find(".column-drop-indicator.show"); + console.log("Drop indicator found:", $dropIndicator.length > 0); + + if ($dropIndicator.length > 0) { + // Get current column order from the API (source of truth) + const currentOrder = [...this.api.columns]; + + let newOrder = [...currentOrder]; + + // Remove dragged column from current position + newOrder = newOrder.filter(col => col !== this.context.draggedColumn); + + // Determine insertion position based on drop indicator position + const $nextColumn = $dropIndicator.next('.board-column'); + const $prevColumn = $dropIndicator.prev('.board-column'); + + let insertIndex = -1; + + if ($nextColumn.length > 0) { + // Insert before the next column + const nextColumnValue = $nextColumn.attr('data-column'); + insertIndex = newOrder.indexOf(nextColumnValue!); + } else if ($prevColumn.length > 0) { + // Insert after the previous column + const prevColumnValue = $prevColumn.attr('data-column'); + insertIndex = newOrder.indexOf(prevColumnValue!) + 1; + } else { + // Insert at the beginning + insertIndex = 0; + } + + // Insert the dragged column at the determined position + if (insertIndex >= 0 && insertIndex <= newOrder.length) { + newOrder.splice(insertIndex, 0, this.context.draggedColumn); + } else { + // Fallback: insert at the end + newOrder.push(this.context.draggedColumn); + } + + // Update column order in API + await this.api.reorderColumns(newOrder); + + // Refresh the board to reflect the changes + await this.onBoardRefresh(); + } else { + console.warn("No drop indicator found for column drop"); + } + } catch (error) { + console.error("Failed to reorder columns:", error); + } finally { + this.cleanupColumnDropIndicators(); + } + } +} diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts index e8bd183e7..4f8866cd2 100644 --- a/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts +++ b/apps/client/src/widgets/view_widgets/board_view/drag_handler.ts @@ -1,19 +1,16 @@ -import branchService from "../../../services/branches"; import BoardApi from "./api"; - -export interface DragContext { - draggedNote: any; - draggedBranch: any; - draggedNoteElement: JQuery | null; - draggedColumn: string | null; - draggedColumnElement: JQuery | null; -} +import { DragContext } from "./drag_types"; +import { NoteDragHandler } from "./note_drag_handler"; +import { ColumnDragHandler } from "./column_drag_handler"; export class BoardDragHandler { private $container: JQuery; private api: BoardApi; private context: DragContext; private onBoardRefresh: () => Promise; + + private noteDragHandler: NoteDragHandler; + private columnDragHandler: ColumnDragHandler; constructor( $container: JQuery, @@ -25,518 +22,42 @@ export class BoardDragHandler { this.api = api; this.context = context; this.onBoardRefresh = onBoardRefresh; + + // Initialize specialized drag handlers + this.noteDragHandler = new NoteDragHandler($container, api, context, onBoardRefresh); + this.columnDragHandler = new ColumnDragHandler($container, api, context, onBoardRefresh); } + // Note drag methods - delegate to NoteDragHandler setupNoteDrag($noteEl: JQuery, note: any, branch: any) { - $noteEl.attr("draggable", "true"); - - // Mouse drag events - this.setupMouseDrag($noteEl, note, branch); - - // Touch drag events - this.setupTouchDrag($noteEl, note, branch); - } - - setupColumnDrag($columnEl: JQuery, columnValue: string) { - const $dragHandle = $columnEl.find('.column-drag-handle'); - - $dragHandle.attr("draggable", "true"); - - $dragHandle.on("dragstart", (e) => { - this.context.draggedColumn = columnValue; - this.context.draggedColumnElement = $columnEl; - $columnEl.addClass("column-dragging"); - - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.effectAllowed = "move"; - originalEvent.dataTransfer.setData("text/plain", columnValue); - } - - // Prevent note dragging when column is being dragged - e.stopPropagation(); - - // Setup global drag tracking for better drop indicator positioning - this.setupGlobalColumnDragTracking(); - }); - - $dragHandle.on("dragend", () => { - $columnEl.removeClass("column-dragging"); - this.context.draggedColumn = null; - this.context.draggedColumnElement = null; - this.cleanupColumnDropIndicators(); - this.cleanupGlobalColumnDragTracking(); - }); - } - - private setupGlobalColumnDragTracking() { - // Add container-level drag tracking for better indicator positioning - this.$container.on("dragover.columnDrag", (e) => { - if (this.context.draggedColumn) { - e.preventDefault(); - const originalEvent = e.originalEvent as DragEvent; - this.showColumnDropIndicator(originalEvent.clientX); - } - }); - } - - private cleanupGlobalColumnDragTracking() { - this.$container.off("dragover.columnDrag"); - } - - updateApi(newApi: BoardApi) { - this.api = newApi; - } - - private cleanupAllDropIndicators() { - // Remove all drop indicators from the DOM to prevent layout issues - this.$container.find(".board-drop-indicator").remove(); - this.$container.find(".column-drop-indicator").remove(); - } - - private cleanupColumnDropIndicators() { - // Remove column drop indicators - this.$container.find(".column-drop-indicator").remove(); - } - - private cleanupNoteDropIndicators($columnEl: JQuery) { - // Remove note drop indicators from a specific column - $columnEl.find(".board-drop-indicator").remove(); - } - - // Public method to clean up any stray indicators - can be called externally - cleanup() { - this.cleanupAllDropIndicators(); - this.$container.find('.board-column').removeClass('drag-over'); - this.context.draggedColumn = null; - this.context.draggedColumnElement = null; - this.cleanupGlobalColumnDragTracking(); - } - - private setupMouseDrag($noteEl: JQuery, note: any, branch: any) { - $noteEl.on("dragstart", (e) => { - this.context.draggedNote = note; - this.context.draggedBranch = branch; - this.context.draggedNoteElement = $noteEl; - $noteEl.addClass("dragging"); - - // Set drag data - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.effectAllowed = "move"; - originalEvent.dataTransfer.setData("text/plain", note.noteId); - } - }); - - $noteEl.on("dragend", () => { - $noteEl.removeClass("dragging"); - this.context.draggedNote = null; - this.context.draggedBranch = null; - this.context.draggedNoteElement = null; - - // Clean up all drop indicators properly - this.cleanupAllDropIndicators(); - }); - } - - private setupTouchDrag($noteEl: JQuery, note: any, branch: any) { - let isDragging = false; - let startY = 0; - let startX = 0; - let dragThreshold = 10; // Minimum distance to start dragging - let $dragPreview: JQuery | null = null; - - $noteEl.on("touchstart", (e) => { - const touch = (e.originalEvent as TouchEvent).touches[0]; - startX = touch.clientX; - startY = touch.clientY; - isDragging = false; - $dragPreview = null; - }); - - $noteEl.on("touchmove", (e) => { - e.preventDefault(); // Prevent scrolling - const touch = (e.originalEvent as TouchEvent).touches[0]; - const deltaX = Math.abs(touch.clientX - startX); - const deltaY = Math.abs(touch.clientY - startY); - - // Start dragging if we've moved beyond threshold - if (!isDragging && (deltaX > dragThreshold || deltaY > dragThreshold)) { - isDragging = true; - this.context.draggedNote = note; - this.context.draggedBranch = branch; - this.context.draggedNoteElement = $noteEl; - $noteEl.addClass("dragging"); - - // Create drag preview - $dragPreview = this.createDragPreview($noteEl, touch.clientX, touch.clientY); - } - - if (isDragging && $dragPreview) { - // Update drag preview position - $dragPreview.css({ - left: touch.clientX - ($dragPreview.outerWidth() || 0) / 2, - top: touch.clientY - ($dragPreview.outerHeight() || 0) / 2 - }); - - // Find element under touch point - const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); - if (elementBelow) { - const $columnEl = $(elementBelow).closest('.board-column'); - - if ($columnEl.length > 0) { - // Remove drag-over from all columns - this.$container.find('.board-column').removeClass('drag-over'); - $columnEl.addClass('drag-over'); - - // Show drop indicator - this.showDropIndicatorAtPoint($columnEl, touch.clientY); - } else { - // Remove all drag indicators if not over a column - this.$container.find('.board-column').removeClass('drag-over'); - this.cleanupAllDropIndicators(); - } - } - } - }); - - $noteEl.on("touchend", async (e) => { - if (isDragging) { - const touch = (e.originalEvent as TouchEvent).changedTouches[0]; - const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); - if (elementBelow) { - const $columnEl = $(elementBelow).closest('.board-column'); - - if ($columnEl.length > 0) { - const column = $columnEl.attr('data-column'); - if (column && this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { - await this.handleNoteDrop($columnEl, column); - } - } - } - - // Clean up - $noteEl.removeClass("dragging"); - this.context.draggedNote = null; - this.context.draggedBranch = null; - this.context.draggedNoteElement = null; - this.$container.find('.board-column').removeClass('drag-over'); - this.cleanupAllDropIndicators(); - - // Remove drag preview - if ($dragPreview) { - $dragPreview.remove(); - $dragPreview = null; - } - } - isDragging = false; - }); + this.noteDragHandler.setupNoteDrag($noteEl, note, branch); } setupNoteDropZone($columnEl: JQuery, column: string) { - $columnEl.on("dragover", (e) => { - // Only handle note drops when a note is being dragged - if (this.context.draggedNote && !this.context.draggedColumn) { - e.preventDefault(); - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.dropEffect = "move"; - } + this.noteDragHandler.setupNoteDropZone($columnEl, column); + } - $columnEl.addClass("drag-over"); - this.showDropIndicator($columnEl, e); - } - }); - - $columnEl.on("dragleave", (e) => { - // Only remove drag-over if we're leaving the column entirely - const rect = $columnEl[0].getBoundingClientRect(); - const originalEvent = e.originalEvent as DragEvent; - const x = originalEvent.clientX; - const y = originalEvent.clientY; - - if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { - $columnEl.removeClass("drag-over"); - this.cleanupNoteDropIndicators($columnEl); - } - }); - - $columnEl.on("drop", async (e) => { - if (this.context.draggedNote && !this.context.draggedColumn) { - e.preventDefault(); - $columnEl.removeClass("drag-over"); - - if (this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { - await this.handleNoteDrop($columnEl, column); - } - } - }); + // Column drag methods - delegate to ColumnDragHandler + setupColumnDrag($columnEl: JQuery, columnValue: string) { + this.columnDragHandler.setupColumnDrag($columnEl, columnValue); } setupColumnDropZone($columnEl: JQuery, columnValue: string) { - $columnEl.on("dragover", (e) => { - // Only handle column drops when a column is being dragged - if (this.context.draggedColumn && !this.context.draggedNote) { - e.preventDefault(); - const originalEvent = e.originalEvent as DragEvent; - if (originalEvent.dataTransfer) { - originalEvent.dataTransfer.dropEffect = "move"; - } - - // Don't highlight columns - we only care about the drop indicator position - } - }); - - $columnEl.on("drop", async (e) => { - if (this.context.draggedColumn && !this.context.draggedNote) { - e.preventDefault(); - - // Use the drop indicator position to determine where to place the column - await this.handleColumnDrop(); - } - }); + this.columnDragHandler.setupColumnDropZone($columnEl, columnValue); } - private createDragPreview($noteEl: JQuery, x: number, y: number): JQuery { - // Clone the note element for the preview - const $preview = $noteEl.clone(); - - $preview - .addClass('board-drag-preview') - .css({ - position: 'fixed', - left: x - ($noteEl.outerWidth() || 0) / 2, - top: y - ($noteEl.outerHeight() || 0) / 2, - pointerEvents: 'none', - zIndex: 10000 - }) - .appendTo('body'); - - return $preview; + // Common methods + updateApi(newApi: BoardApi) { + this.api = newApi; + this.noteDragHandler.updateApi(newApi); + this.columnDragHandler.updateApi(newApi); } - private showDropIndicator($columnEl: JQuery, e: JQuery.DragOverEvent) { - const originalEvent = e.originalEvent as DragEvent; - const mouseY = originalEvent.clientY; - this.showDropIndicatorAtY($columnEl, mouseY); - } - - private showDropIndicatorAtPoint($columnEl: JQuery, touchY: number) { - this.showDropIndicatorAtY($columnEl, touchY); - } - - private showDropIndicatorAtY($columnEl: JQuery, y: number) { - const columnRect = $columnEl[0].getBoundingClientRect(); - const relativeY = y - columnRect.top; - - // Clean up any existing drop indicators in this column first - this.cleanupNoteDropIndicators($columnEl); - - // Create a new drop indicator - const $dropIndicator = $("
").addClass("board-drop-indicator"); - - // Find the best position to insert the note - const $notes = this.context.draggedNoteElement ? - $columnEl.find(".board-note").not(this.context.draggedNoteElement) : - $columnEl.find(".board-note"); - let insertAfterElement: HTMLElement | null = null; - - $notes.each((_, noteEl) => { - const noteRect = noteEl.getBoundingClientRect(); - const noteMiddle = noteRect.top + noteRect.height / 2 - columnRect.top; - - if (relativeY > noteMiddle) { - insertAfterElement = noteEl; - } - }); - - // Position the drop indicator - if (insertAfterElement) { - $(insertAfterElement).after($dropIndicator); - } else { - // Insert at the beginning (after the header) - const $header = $columnEl.find("h3"); - $header.after($dropIndicator); - } - - $dropIndicator.addClass("show"); - } - - private showColumnDropIndicator(mouseX: number) { - // Clean up existing indicators - this.cleanupColumnDropIndicators(); - - // Get all columns (excluding the dragged one if it exists) - let $allColumns = this.$container.find('.board-column'); - if (this.context.draggedColumnElement) { - $allColumns = $allColumns.not(this.context.draggedColumnElement); - } - - let $targetColumn: JQuery = $(); - let insertBefore = false; - - // Find which column the mouse is closest to - $allColumns.each((_, columnEl) => { - const $column = $(columnEl); - const rect = columnEl.getBoundingClientRect(); - const columnMiddle = rect.left + rect.width / 2; - - if (mouseX >= rect.left && mouseX <= rect.right) { - // Mouse is over this column - $targetColumn = $column; - insertBefore = mouseX < columnMiddle; - return false; // Break the loop - } - }); - - // If no column found under mouse, find the closest one - if ($targetColumn.length === 0) { - let closestDistance = Infinity; - $allColumns.each((_, columnEl) => { - const $column = $(columnEl); - const rect = columnEl.getBoundingClientRect(); - const columnCenter = rect.left + rect.width / 2; - const distance = Math.abs(mouseX - columnCenter); - - if (distance < closestDistance) { - closestDistance = distance; - $targetColumn = $column; - insertBefore = mouseX < columnCenter; - } - }); - } - - if ($targetColumn.length > 0) { - const $dropIndicator = $("
").addClass("column-drop-indicator"); - - if (insertBefore) { - $targetColumn.before($dropIndicator); - } else { - $targetColumn.after($dropIndicator); - } - - $dropIndicator.addClass("show"); - } - } - - private async handleNoteDrop($columnEl: JQuery, column: string) { - const draggedNoteElement = this.context.draggedNoteElement; - const draggedNote = this.context.draggedNote; - const draggedBranch = this.context.draggedBranch; - - if (draggedNote && draggedNoteElement && draggedBranch) { - const currentColumn = draggedNoteElement.attr("data-current-column"); - - // Capture drop indicator position BEFORE removing it - const dropIndicator = $columnEl.find(".board-drop-indicator.show"); - let targetBranchId: string | null = null; - let moveType: "before" | "after" | null = null; - - if (dropIndicator.length > 0) { - // Find the note element that the drop indicator is positioned relative to - const nextNote = dropIndicator.next(".board-note"); - const prevNote = dropIndicator.prev(".board-note"); - - if (nextNote.length > 0) { - targetBranchId = nextNote.attr("data-branch-id") || null; - moveType = "before"; - } else if (prevNote.length > 0) { - targetBranchId = prevNote.attr("data-branch-id") || null; - moveType = "after"; - } - } - - try { - // Handle column change - if (currentColumn !== column) { - await this.api.changeColumn(draggedNote.noteId, column); - } - - // Handle position change (works for both same column and different column moves) - if (targetBranchId && moveType) { - if (moveType === "before") { - console.log("Move before branch:", draggedBranch.branchId, "to", targetBranchId); - await branchService.moveBeforeBranch([draggedBranch.branchId], targetBranchId); - } else if (moveType === "after") { - console.log("Move after branch:", draggedBranch.branchId, "to", targetBranchId); - await branchService.moveAfterBranch([draggedBranch.branchId], targetBranchId); - } - } - - // Update the data attributes - draggedNoteElement.attr("data-current-column", column); - - // Show success feedback - console.log(`Moved note "${draggedNote.title}" from "${currentColumn}" to "${column}"`); - - // Refresh the board to reflect the changes - await this.onBoardRefresh(); - } catch (error) { - console.error("Failed to update note position:", error); - } finally { - // Always clean up drop indicators after drop operation - this.cleanupAllDropIndicators(); - } - } - } - - private async handleColumnDrop() { - if (!this.context.draggedColumn || !this.context.draggedColumnElement) { - return; - } - - try { - // Find the drop indicator to determine insert position - const $dropIndicator = this.$container.find(".column-drop-indicator.show"); - - if ($dropIndicator.length > 0) { - // Get current column order from the API (source of truth) - const currentOrder = [...this.api.columns]; - - let newOrder = [...currentOrder]; - - // Remove dragged column from current position - newOrder = newOrder.filter(col => col !== this.context.draggedColumn); - - // Determine insertion position based on drop indicator position - const $nextColumn = $dropIndicator.next('.board-column'); - const $prevColumn = $dropIndicator.prev('.board-column'); - - let insertIndex = -1; - - if ($nextColumn.length > 0) { - // Insert before the next column - const nextColumnValue = $nextColumn.attr('data-column'); - insertIndex = newOrder.indexOf(nextColumnValue!); - } else if ($prevColumn.length > 0) { - // Insert after the previous column - const prevColumnValue = $prevColumn.attr('data-column'); - insertIndex = newOrder.indexOf(prevColumnValue!) + 1; - } else { - // Insert at the beginning - insertIndex = 0; - } - - // Insert the dragged column at the determined position - if (insertIndex >= 0 && insertIndex <= newOrder.length) { - newOrder.splice(insertIndex, 0, this.context.draggedColumn); - } else { - // Fallback: insert at the end - newOrder.push(this.context.draggedColumn); - } - - // Update column order in API - await this.api.reorderColumns(newOrder); - - // Refresh the board to reflect the changes - await this.onBoardRefresh(); - } else { - console.warn("No drop indicator found for column drop"); - } - } catch (error) { - console.error("Failed to reorder columns:", error); - } finally { - this.cleanupColumnDropIndicators(); - } + cleanup() { + this.noteDragHandler.cleanup(); + this.columnDragHandler.cleanup(); } } + +// Export the drag context type for external use +export type { DragContext } from "./drag_types"; diff --git a/apps/client/src/widgets/view_widgets/board_view/drag_types.ts b/apps/client/src/widgets/view_widgets/board_view/drag_types.ts new file mode 100644 index 000000000..ff3cde8c7 --- /dev/null +++ b/apps/client/src/widgets/view_widgets/board_view/drag_types.ts @@ -0,0 +1,12 @@ +export interface DragContext { + draggedNote: any; + draggedBranch: any; + draggedNoteElement: JQuery | null; + draggedColumn: string | null; + draggedColumnElement: JQuery | null; +} + +export interface BaseDragHandler { + cleanup(): void; + updateApi(api: any): void; +} diff --git a/apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts b/apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts new file mode 100644 index 000000000..042f1a630 --- /dev/null +++ b/apps/client/src/widgets/view_widgets/board_view/note_drag_handler.ts @@ -0,0 +1,332 @@ +import branchService from "../../../services/branches"; +import BoardApi from "./api"; +import { DragContext, BaseDragHandler } from "./drag_types"; + +export class NoteDragHandler implements BaseDragHandler { + private $container: JQuery; + private api: BoardApi; + private context: DragContext; + private onBoardRefresh: () => Promise; + + constructor( + $container: JQuery, + api: BoardApi, + context: DragContext, + onBoardRefresh: () => Promise + ) { + this.$container = $container; + this.api = api; + this.context = context; + this.onBoardRefresh = onBoardRefresh; + } + + setupNoteDrag($noteEl: JQuery, note: any, branch: any) { + $noteEl.attr("draggable", "true"); + + // Mouse drag events + this.setupMouseDrag($noteEl, note, branch); + + // Touch drag events + this.setupTouchDrag($noteEl, note, branch); + } + + setupNoteDropZone($columnEl: JQuery, column: string) { + $columnEl.on("dragover", (e) => { + // Only handle note drops when a note is being dragged + if (this.context.draggedNote && !this.context.draggedColumn) { + e.preventDefault(); + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.dropEffect = "move"; + } + + $columnEl.addClass("drag-over"); + this.showDropIndicator($columnEl, e); + } + }); + + $columnEl.on("dragleave", (e) => { + // Only remove drag-over if we're leaving the column entirely + const rect = $columnEl[0].getBoundingClientRect(); + const originalEvent = e.originalEvent as DragEvent; + const x = originalEvent.clientX; + const y = originalEvent.clientY; + + if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) { + $columnEl.removeClass("drag-over"); + this.cleanupNoteDropIndicators($columnEl); + } + }); + + $columnEl.on("drop", async (e) => { + if (this.context.draggedNote && !this.context.draggedColumn) { + e.preventDefault(); + $columnEl.removeClass("drag-over"); + + if (this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { + await this.handleNoteDrop($columnEl, column); + } + } + }); + } + + updateApi(newApi: BoardApi) { + this.api = newApi; + } + + cleanup() { + this.cleanupAllDropIndicators(); + this.$container.find('.board-column').removeClass('drag-over'); + } + + private setupMouseDrag($noteEl: JQuery, note: any, branch: any) { + $noteEl.on("dragstart", (e) => { + this.context.draggedNote = note; + this.context.draggedBranch = branch; + this.context.draggedNoteElement = $noteEl; + $noteEl.addClass("dragging"); + + // Set drag data + const originalEvent = e.originalEvent as DragEvent; + if (originalEvent.dataTransfer) { + originalEvent.dataTransfer.effectAllowed = "move"; + originalEvent.dataTransfer.setData("text/plain", note.noteId); + } + }); + + $noteEl.on("dragend", () => { + $noteEl.removeClass("dragging"); + this.context.draggedNote = null; + this.context.draggedBranch = null; + this.context.draggedNoteElement = null; + + // Clean up all drop indicators properly + this.cleanupAllDropIndicators(); + }); + } + + private setupTouchDrag($noteEl: JQuery, note: any, branch: any) { + let isDragging = false; + let startY = 0; + let startX = 0; + let dragThreshold = 10; // Minimum distance to start dragging + let $dragPreview: JQuery | null = null; + + $noteEl.on("touchstart", (e) => { + const touch = (e.originalEvent as TouchEvent).touches[0]; + startX = touch.clientX; + startY = touch.clientY; + isDragging = false; + $dragPreview = null; + }); + + $noteEl.on("touchmove", (e) => { + e.preventDefault(); // Prevent scrolling + const touch = (e.originalEvent as TouchEvent).touches[0]; + const deltaX = Math.abs(touch.clientX - startX); + const deltaY = Math.abs(touch.clientY - startY); + + // Start dragging if we've moved beyond threshold + if (!isDragging && (deltaX > dragThreshold || deltaY > dragThreshold)) { + isDragging = true; + this.context.draggedNote = note; + this.context.draggedBranch = branch; + this.context.draggedNoteElement = $noteEl; + $noteEl.addClass("dragging"); + + // Create drag preview + $dragPreview = this.createDragPreview($noteEl, touch.clientX, touch.clientY); + } + + if (isDragging && $dragPreview) { + // Update drag preview position + $dragPreview.css({ + left: touch.clientX - ($dragPreview.outerWidth() || 0) / 2, + top: touch.clientY - ($dragPreview.outerHeight() || 0) / 2 + }); + + // Find element under touch point + const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); + if (elementBelow) { + const $columnEl = $(elementBelow).closest('.board-column'); + + if ($columnEl.length > 0) { + // Remove drag-over from all columns + this.$container.find('.board-column').removeClass('drag-over'); + $columnEl.addClass('drag-over'); + + // Show drop indicator + this.showDropIndicatorAtPoint($columnEl, touch.clientY); + } else { + // Remove all drag indicators if not over a column + this.$container.find('.board-column').removeClass('drag-over'); + this.cleanupAllDropIndicators(); + } + } + } + }); + + $noteEl.on("touchend", async (e) => { + if (isDragging) { + const touch = (e.originalEvent as TouchEvent).changedTouches[0]; + const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); + if (elementBelow) { + const $columnEl = $(elementBelow).closest('.board-column'); + + if ($columnEl.length > 0) { + const column = $columnEl.attr('data-column'); + if (column && this.context.draggedNote && this.context.draggedNoteElement && this.context.draggedBranch) { + await this.handleNoteDrop($columnEl, column); + } + } + } + + // Clean up + $noteEl.removeClass("dragging"); + this.context.draggedNote = null; + this.context.draggedBranch = null; + this.context.draggedNoteElement = null; + this.$container.find('.board-column').removeClass('drag-over'); + this.cleanupAllDropIndicators(); + + // Remove drag preview + if ($dragPreview) { + $dragPreview.remove(); + $dragPreview = null; + } + } + isDragging = false; + }); + } + + private createDragPreview($noteEl: JQuery, x: number, y: number): JQuery { + // Clone the note element for the preview + const $preview = $noteEl.clone(); + + $preview + .addClass('board-drag-preview') + .css({ + position: 'fixed', + left: x - ($noteEl.outerWidth() || 0) / 2, + top: y - ($noteEl.outerHeight() || 0) / 2, + pointerEvents: 'none', + zIndex: 10000 + }) + .appendTo('body'); + + return $preview; + } + + private showDropIndicator($columnEl: JQuery, e: JQuery.DragOverEvent) { + const originalEvent = e.originalEvent as DragEvent; + const mouseY = originalEvent.clientY; + this.showDropIndicatorAtY($columnEl, mouseY); + } + + private showDropIndicatorAtPoint($columnEl: JQuery, touchY: number) { + this.showDropIndicatorAtY($columnEl, touchY); + } + + private showDropIndicatorAtY($columnEl: JQuery, y: number) { + const columnRect = $columnEl[0].getBoundingClientRect(); + const relativeY = y - columnRect.top; + + // Clean up any existing drop indicators in this column first + this.cleanupNoteDropIndicators($columnEl); + + // Create a new drop indicator + const $dropIndicator = $("
").addClass("board-drop-indicator"); + + // Find the best position to insert the note + const $notes = this.context.draggedNoteElement ? + $columnEl.find(".board-note").not(this.context.draggedNoteElement) : + $columnEl.find(".board-note"); + let insertAfterElement: HTMLElement | null = null; + + $notes.each((_, noteEl) => { + const noteRect = noteEl.getBoundingClientRect(); + const noteMiddle = noteRect.top + noteRect.height / 2 - columnRect.top; + + if (relativeY > noteMiddle) { + insertAfterElement = noteEl; + } + }); + + // Position the drop indicator + if (insertAfterElement) { + $(insertAfterElement).after($dropIndicator); + } else { + // Insert at the beginning (after the header) + const $header = $columnEl.find("h3"); + $header.after($dropIndicator); + } + + $dropIndicator.addClass("show"); + } + + private async handleNoteDrop($columnEl: JQuery, column: string) { + const draggedNoteElement = this.context.draggedNoteElement; + const draggedNote = this.context.draggedNote; + const draggedBranch = this.context.draggedBranch; + + if (draggedNote && draggedNoteElement && draggedBranch) { + const currentColumn = draggedNoteElement.attr("data-current-column"); + + // Capture drop indicator position BEFORE removing it + const dropIndicator = $columnEl.find(".board-drop-indicator.show"); + let targetBranchId: string | null = null; + let moveType: "before" | "after" | null = null; + + if (dropIndicator.length > 0) { + // Find the note element that the drop indicator is positioned relative to + const nextNote = dropIndicator.next(".board-note"); + const prevNote = dropIndicator.prev(".board-note"); + + if (nextNote.length > 0) { + targetBranchId = nextNote.attr("data-branch-id") || null; + moveType = "before"; + } else if (prevNote.length > 0) { + targetBranchId = prevNote.attr("data-branch-id") || null; + moveType = "after"; + } + } + + try { + // Handle column change + if (currentColumn !== column) { + await this.api.changeColumn(draggedNote.noteId, column); + } + + // Handle position change (works for both same column and different column moves) + if (targetBranchId && moveType) { + if (moveType === "before") { + await branchService.moveBeforeBranch([draggedBranch.branchId], targetBranchId); + } else if (moveType === "after") { + await branchService.moveAfterBranch([draggedBranch.branchId], targetBranchId); + } + } + + // Update the data attributes + draggedNoteElement.attr("data-current-column", column); + + // Refresh the board to reflect the changes + await this.onBoardRefresh(); + } catch (error) { + console.error("Failed to update note position:", error); + } finally { + // Always clean up drop indicators after drop operation + this.cleanupAllDropIndicators(); + } + } + } + + private cleanupAllDropIndicators() { + // Remove all drop indicators from the DOM to prevent layout issues + this.$container.find(".board-drop-indicator").remove(); + } + + private cleanupNoteDropIndicators($columnEl: JQuery) { + // Remove note drop indicators from a specific column + $columnEl.find(".board-drop-indicator").remove(); + } +}