mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 23:40:13 +01:00
Resize height of swimlane by dragging. Font Awesome to Unicode icons.
Thanks to xet7 !
This commit is contained in:
parent
2947238a02
commit
09631d6b0c
16 changed files with 832 additions and 146 deletions
|
|
@ -192,7 +192,7 @@ and adds the following new features:
|
||||||
|
|
||||||
- [Mobile one board per row. Board zoom size percent. Board toggle mobile/desktop mode. In Progress](https://github.com/wekan/wekan/commit/752699d1c2fb8ea9ff0f3ec9ae0b2b776443d826).
|
- [Mobile one board per row. Board zoom size percent. Board toggle mobile/desktop mode. In Progress](https://github.com/wekan/wekan/commit/752699d1c2fb8ea9ff0f3ec9ae0b2b776443d826).
|
||||||
Thanks to xet7.
|
Thanks to xet7.
|
||||||
- [Drag any files from file manager to minicard or opened card.
|
- Drag any files from file manager to minicard or opened card.
|
||||||
[Part 1](https://github.com/wekan/wekan/commit/3e9481c5bd2c02ba501bd0a6ef1d1e6ce82bb1d9),
|
[Part 1](https://github.com/wekan/wekan/commit/3e9481c5bd2c02ba501bd0a6ef1d1e6ce82bb1d9),
|
||||||
[Part 2](https://github.com/wekan/wekan/commit/cdd7d69c660d0b6ac06b7b75d4f59985b8a9322a).
|
[Part 2](https://github.com/wekan/wekan/commit/cdd7d69c660d0b6ac06b7b75d4f59985b8a9322a).
|
||||||
Thanks to xet7.
|
Thanks to xet7.
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ template(name="minicard")
|
||||||
class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}")
|
class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}")
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
if isTouchScreenOrShowDesktopDragHandles
|
if isTouchScreenOrShowDesktopDragHandles
|
||||||
a.fa.fa-navicon.minicard-details-menu-with-handle.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}")
|
a.minicard-details-menu-with-handle.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}") | ☰
|
||||||
.handle
|
.handle
|
||||||
.fa.fa-arrows
|
| ↔️
|
||||||
else
|
else
|
||||||
a.fa.fa-navicon.minicard-details-menu.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}")
|
a.minicard-details-menu.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}") | ☰
|
||||||
.dates
|
.dates
|
||||||
if getReceived
|
if getReceived
|
||||||
unless getStart
|
unless getStart
|
||||||
|
|
@ -36,7 +36,7 @@ template(name="minicard")
|
||||||
if hasActiveUploads
|
if hasActiveUploads
|
||||||
.minicard-upload-progress
|
.minicard-upload-progress
|
||||||
.upload-progress-header
|
.upload-progress-header
|
||||||
i.fa.fa-upload
|
| 📤
|
||||||
span {{_ 'uploading-files'}} ({{uploadCount}})
|
span {{_ 'uploading-files'}} ({{uploadCount}})
|
||||||
each uploads
|
each uploads
|
||||||
.upload-progress-item(class="{{#if $eq status 'error'}}upload-error{{/if}}")
|
.upload-progress-item(class="{{#if $eq status 'error'}}upload-error{{/if}}")
|
||||||
|
|
@ -45,11 +45,11 @@ template(name="minicard")
|
||||||
.upload-progress-fill(style="width: {{progress}}%")
|
.upload-progress-fill(style="width: {{progress}}%")
|
||||||
if $eq status 'error'
|
if $eq status 'error'
|
||||||
.upload-progress-error
|
.upload-progress-error
|
||||||
i.fa.fa-exclamation-triangle
|
| ⚠️
|
||||||
span {{_ 'upload-failed'}}
|
span {{_ 'upload-failed'}}
|
||||||
else if $eq status 'completed'
|
else if $eq status 'completed'
|
||||||
.upload-progress-success
|
.upload-progress-success
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
span {{_ 'upload-completed'}}
|
span {{_ 'upload-completed'}}
|
||||||
|
|
||||||
.minicard-title
|
.minicard-title
|
||||||
|
|
@ -61,12 +61,12 @@ template(name="minicard")
|
||||||
| {{ parentCardName }}
|
| {{ parentCardName }}
|
||||||
if isLinkedBoard
|
if isLinkedBoard
|
||||||
a.js-linked-link
|
a.js-linked-link
|
||||||
span.linked-icon.fa.fa-folder
|
span.linked-icon | 📁
|
||||||
else if isLinkedCard
|
else if isLinkedCard
|
||||||
a.js-linked-link
|
a.js-linked-link
|
||||||
span.linked-icon.fa.fa-id-card
|
span.linked-icon | 🃏
|
||||||
if getArchived
|
if getArchived
|
||||||
span.linked-icon.linked-archived.fa.fa-archive
|
span.linked-icon.linked-archived | 📦
|
||||||
+viewer
|
+viewer
|
||||||
if currentBoard.allowsCardNumber
|
if currentBoard.allowsCardNumber
|
||||||
span.card-number
|
span.card-number
|
||||||
|
|
@ -147,7 +147,7 @@ template(name="minicard")
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
if comments.length
|
if comments.length
|
||||||
.badge(title="{{_ 'card-comments-title' comments.length }}")
|
.badge(title="{{_ 'card-comments-title' comments.length }}")
|
||||||
span.badge-icon.fa.fa-comment-o.badge-comment.badge-text
|
span.badge-icon.badge-comment.badge-text | 💬
|
||||||
= ' '
|
= ' '
|
||||||
= comments.length
|
= comments.length
|
||||||
//span.badge-comment.badge-text
|
//span.badge-comment.badge-text
|
||||||
|
|
@ -155,36 +155,36 @@ template(name="minicard")
|
||||||
if getDescription
|
if getDescription
|
||||||
unless currentBoard.allowsDescriptionTextOnMinicard
|
unless currentBoard.allowsDescriptionTextOnMinicard
|
||||||
.badge.badge-state-image-only(title=getDescription)
|
.badge.badge-state-image-only(title=getDescription)
|
||||||
span.badge-icon.fa.fa-align-left
|
span.badge-icon | 📝
|
||||||
if getVoteQuestion
|
if getVoteQuestion
|
||||||
.badge.badge-state-image-only(title=getVoteQuestion)
|
.badge.badge-state-image-only(title=getVoteQuestion)
|
||||||
span.badge-icon.fa.fa-thumbs-up(class="{{#if voteState}}text-green{{/if}}")
|
span.badge-icon(class="{{#if voteState}}text-green{{/if}}") | 👍
|
||||||
span.badge-text {{ voteCountPositive }}
|
span.badge-text {{ voteCountPositive }}
|
||||||
span.badge-icon.fa.fa-thumbs-down(class="{{#if $eq voteState false}}text-red{{/if}}")
|
span.badge-icon(class="{{#if $eq voteState false}}text-red{{/if}}") | 👎
|
||||||
span.badge-text {{ voteCountNegative }}
|
span.badge-text {{ voteCountNegative }}
|
||||||
if getPokerQuestion
|
if getPokerQuestion
|
||||||
.badge.badge-state-image-only(title=getPokerQuestion)
|
.badge.badge-state-image-only(title=getPokerQuestion)
|
||||||
span.badge-icon.fa.fa-check(class="{{#if pokerState}}text-green{{/if}}")
|
span.badge-icon(class="{{#if pokerState}}text-green{{/if}}") | ✅
|
||||||
if expiredPoker
|
if expiredPoker
|
||||||
span.badge-text {{ getPokerEstimation }}
|
span.badge-text {{ getPokerEstimation }}
|
||||||
if attachments.length
|
if attachments.length
|
||||||
if currentBoard.allowsBadgeAttachmentOnMinicard
|
if currentBoard.allowsBadgeAttachmentOnMinicard
|
||||||
.badge
|
.badge
|
||||||
span.badge-icon.fa.fa-paperclip
|
span.badge-icon | 📎
|
||||||
span.badge-text= attachments.length
|
span.badge-text= attachments.length
|
||||||
if checklists.length
|
if checklists.length
|
||||||
.badge(class="{{#if checklistFinished}}is-finished{{/if}}")
|
.badge(class="{{#if checklistFinished}}is-finished{{/if}}")
|
||||||
span.badge-icon.fa.fa-check-square-o
|
span.badge-icon | ☑️
|
||||||
span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
|
span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
|
||||||
if allSubtasks.count
|
if allSubtasks.count
|
||||||
.badge
|
.badge
|
||||||
span.badge-icon.fa.fa-sitemap
|
span.badge-icon | 🌐
|
||||||
span.badge-text.check-list-text {{subtasksFinishedCount}}/{{allSubtasksCount}}
|
span.badge-text.check-list-text {{subtasksFinishedCount}}/{{allSubtasksCount}}
|
||||||
//{{subtasksFinishedCount}}/{{subtasksCount}} does not work because when a subtaks is archived, the count goes down
|
//{{subtasksFinishedCount}}/{{subtasksCount}} does not work because when a subtaks is archived, the count goes down
|
||||||
if currentBoard.allowsCardSortingByNumber
|
if currentBoard.allowsCardSortingByNumber
|
||||||
if currentBoard.allowsCardSortingByNumberOnMinicard
|
if currentBoard.allowsCardSortingByNumberOnMinicard
|
||||||
.badge
|
.badge
|
||||||
span.badge-icon.fa.fa-sort
|
span.badge-icon | 🔢
|
||||||
span.badge-text.check-list-sort {{ sort }}
|
span.badge-text.check-list-sort {{ sort }}
|
||||||
if currentBoard.allowsDescriptionTextOnMinicard
|
if currentBoard.allowsDescriptionTextOnMinicard
|
||||||
if getDescription
|
if getDescription
|
||||||
|
|
@ -193,7 +193,7 @@ template(name="minicard")
|
||||||
| {{ getDescription }}
|
| {{ getDescription }}
|
||||||
if shouldShowListOnMinicard
|
if shouldShowListOnMinicard
|
||||||
.minicard-list-name
|
.minicard-list-name
|
||||||
i.fa.fa-list
|
| 📋
|
||||||
| {{ listName }}
|
| {{ listName }}
|
||||||
if $eq 'subtext-with-full-path' currentBoard.presentParentTask
|
if $eq 'subtext-with-full-path' currentBoard.presentParentTask
|
||||||
.parent-subtext
|
.parent-subtext
|
||||||
|
|
@ -212,50 +212,50 @@ template(name="minicardDetailsActionsPopup")
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
li
|
li
|
||||||
a.js-move-card
|
a.js-move-card
|
||||||
i.fa.fa-arrow-right
|
| ➡️
|
||||||
| {{_ 'moveCardPopup-title'}}
|
| {{_ 'moveCardPopup-title'}}
|
||||||
li
|
li
|
||||||
a.js-copy-card
|
a.js-copy-card
|
||||||
i.fa.fa-copy
|
| 📋
|
||||||
| {{_ 'copyCardPopup-title'}}
|
| {{_ 'copyCardPopup-title'}}
|
||||||
hr
|
hr
|
||||||
li
|
li
|
||||||
a.js-archive
|
a.js-archive
|
||||||
i.fa.fa-arrow-right
|
| ➡️
|
||||||
i.fa.fa-archive
|
| 📦
|
||||||
| {{_ 'archive-card'}}
|
| {{_ 'archive-card'}}
|
||||||
hr
|
hr
|
||||||
li
|
li
|
||||||
a.js-move-card-to-top
|
a.js-move-card-to-top
|
||||||
i.fa.fa-arrow-up
|
| ⬆️
|
||||||
| {{_ 'moveCardToTop-title'}}
|
| {{_ 'moveCardToTop-title'}}
|
||||||
li
|
li
|
||||||
a.js-move-card-to-bottom
|
a.js-move-card-to-bottom
|
||||||
i.fa.fa-arrow-down
|
| ⬇️
|
||||||
| {{_ 'moveCardToBottom-title'}}
|
| {{_ 'moveCardToBottom-title'}}
|
||||||
hr
|
hr
|
||||||
li
|
li
|
||||||
a.js-add-labels
|
a.js-add-labels
|
||||||
i.fa.fa-tags
|
| 🏷️
|
||||||
| {{_ 'card-edit-labels'}}
|
| {{_ 'card-edit-labels'}}
|
||||||
li
|
li
|
||||||
a.js-due-date
|
a.js-due-date
|
||||||
i.fa.fa-sign-in
|
| 📥
|
||||||
| {{_ 'editCardDueDatePopup-title'}}
|
| {{_ 'editCardDueDatePopup-title'}}
|
||||||
li
|
li
|
||||||
a.js-set-card-color
|
a.js-set-card-color
|
||||||
i.fa.fa-paint-brush
|
| 🎨
|
||||||
| {{_ 'setCardColorPopup-title'}}
|
| {{_ 'setCardColorPopup-title'}}
|
||||||
li
|
li
|
||||||
a.js-link
|
a.js-link
|
||||||
i.fa.fa-link
|
| 🔗
|
||||||
| {{_ 'link-card'}}
|
| {{_ 'link-card'}}
|
||||||
li
|
li
|
||||||
a.js-toggle-watch-card
|
a.js-toggle-watch-card
|
||||||
if isWatching
|
if isWatching
|
||||||
i.fa.fa-eye
|
| 👁️
|
||||||
| {{_ 'unwatch'}}
|
| {{_ 'unwatch'}}
|
||||||
else
|
else
|
||||||
i.fa.fa-eye-slash
|
| 👁️-slash
|
||||||
| {{_ 'watch'}}
|
| {{_ 'watch'}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
background: transparent;
|
background: transparent;
|
||||||
transition: background-color 0.2s ease;
|
transition: background-color 0.2s ease;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
/* Ensure the handle is clickable */
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-resize-handle:hover {
|
.list-resize-handle:hover {
|
||||||
|
|
@ -90,6 +92,8 @@
|
||||||
width: var(--list-width, auto) !important;
|
width: var(--list-width, auto) !important;
|
||||||
min-width: var(--list-width, auto) !important;
|
min-width: var(--list-width, auto) !important;
|
||||||
max-width: var(--list-width, auto) !important;
|
max-width: var(--list-width, auto) !important;
|
||||||
|
/* Ensure the width is applied immediately */
|
||||||
|
overflow: visible !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.list-resizing-active {
|
body.list-resizing-active {
|
||||||
|
|
@ -250,7 +254,70 @@ body.list-resizing-active * {
|
||||||
}
|
}
|
||||||
.list.list-collapsed {
|
.list.list-collapsed {
|
||||||
flex: none;
|
flex: none;
|
||||||
|
min-width: 60px;
|
||||||
|
max-width: 80px;
|
||||||
|
width: 60px;
|
||||||
|
min-height: 60vh;
|
||||||
|
height: 60vh;
|
||||||
|
overflow: visible;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.list.list-collapsed .list-header {
|
||||||
|
padding: 1vh 1.5vw 0.5vh;
|
||||||
|
min-height: 2.5vh !important;
|
||||||
|
height: auto !important;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible !important;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 60px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .js-collapse {
|
||||||
|
margin: 0 auto 20px auto;
|
||||||
|
z-index: 10;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: block;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated {
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
margin: 20px 0 0 0 !important;
|
||||||
|
position: relative !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list.list-collapsed .list-header .list-rotated h2.list-header-name {
|
||||||
|
text-align: left;
|
||||||
|
overflow: visible;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: block !important;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.2;
|
||||||
|
color: #333;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 25vh;
|
||||||
|
height: 60vh;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(calc(-50% + 50px), -50%) rotate(0deg);
|
||||||
|
z-index: 10;
|
||||||
|
visibility: visible !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.list.list-composer .open-list-composer,
|
.list.list-composer .open-list-composer,
|
||||||
.list .list-composer .open-list-composer {
|
.list .list-composer .open-list-composer {
|
||||||
color: #8c8c8c;
|
color: #8c8c8c;
|
||||||
|
|
@ -334,11 +401,152 @@ body.list-resizing-active * {
|
||||||
color: #a6a6a6;
|
color: #a6a6a6;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
.list-header .list-header-uncollapse-left {
|
.list-header .js-collapse {
|
||||||
color: #a6a6a6;
|
color: #a6a6a6;
|
||||||
|
margin-right: 15px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 5px 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.list-header .list-header-uncollapse-right {
|
.list-header .js-collapse:hover {
|
||||||
color: #a6a6a6;
|
background-color: #e0e0e0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .js-collapse {
|
||||||
|
display: inline-block !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments for collapsed lists */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.list.list-collapsed {
|
||||||
|
min-width: 60px;
|
||||||
|
max-width: 80px;
|
||||||
|
width: 60px;
|
||||||
|
min-height: 60vh;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header {
|
||||||
|
max-width: 60px;
|
||||||
|
margin: 0 auto;
|
||||||
|
min-height: 2.5vh !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated {
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
margin: 20px 0 0 0 !important;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated h2.list-header-name {
|
||||||
|
width: 15vh;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 1.2;
|
||||||
|
padding: 8px 4px;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(calc(-50% + 50px), -50%) rotate(0deg);
|
||||||
|
text-align: left;
|
||||||
|
visibility: visible !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
display: block !important;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
color: #333;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .js-collapse {
|
||||||
|
margin: 0 auto 20px auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.list.list-collapsed {
|
||||||
|
min-height: 60vh;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header {
|
||||||
|
min-height: 2.5vh !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated {
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
margin: 20px 0 0 0 !important;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated h2.list-header-name {
|
||||||
|
width: 15vh;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 1.2;
|
||||||
|
padding: 8px 4px;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(calc(-50% + 50px), -50%) rotate(0deg);
|
||||||
|
text-align: left;
|
||||||
|
visibility: visible !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
display: block !important;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
color: #333;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .js-collapse {
|
||||||
|
margin: 0 auto 20px auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.list.list-collapsed {
|
||||||
|
min-height: 60vh;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header {
|
||||||
|
min-height: 2.5vh !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated {
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
margin: 20px 0 0 0 !important;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .list-rotated h2.list-header-name {
|
||||||
|
width: 15vh;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 1.2;
|
||||||
|
padding: 8px 4px;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(calc(-50% + 50px), -50%) rotate(0deg);
|
||||||
|
text-align: left;
|
||||||
|
visibility: visible !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
display: block !important;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
color: #333;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.list.list-collapsed .list-header .js-collapse {
|
||||||
|
margin: 0 auto 20px auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.list-header .list-header-collapse {
|
.list-header .list-header-collapse {
|
||||||
color: #a6a6a6;
|
color: #a6a6a6;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ template(name='list')
|
||||||
class="{{#if collapsed}}list-collapsed{{/if}} {{#if autoWidth}}list-auto-width{{/if}} {{#if isMiniScreen}}mobile-view{{/if}}")
|
class="{{#if collapsed}}list-collapsed{{/if}} {{#if autoWidth}}list-auto-width{{/if}} {{#if isMiniScreen}}mobile-view{{/if}}")
|
||||||
+listHeader
|
+listHeader
|
||||||
+listBody
|
+listBody
|
||||||
.list-resize-handle.js-list-resize-handle
|
.list-resize-handle.js-list-resize-handle.nodragscroll
|
||||||
|
|
||||||
template(name='miniList')
|
template(name='miniList')
|
||||||
a.mini-list.js-select-list.js-list(id="js-list-{{_id}}" class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
a.mini-list.js-select-list.js-list(id="js-list-{{_id}}" class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ BlazeComponent.extendComponent({
|
||||||
onRendered() {
|
onRendered() {
|
||||||
const boardComponent = this.parentComponent().parentComponent();
|
const boardComponent = this.parentComponent().parentComponent();
|
||||||
|
|
||||||
// Initialize list resize functionality
|
// Initialize list resize functionality immediately
|
||||||
this.initializeListResize();
|
this.initializeListResize();
|
||||||
|
|
||||||
const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)';
|
const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)';
|
||||||
|
|
@ -201,13 +201,15 @@ BlazeComponent.extendComponent({
|
||||||
listWidth() {
|
listWidth() {
|
||||||
const user = ReactiveCache.getCurrentUser();
|
const user = ReactiveCache.getCurrentUser();
|
||||||
const list = Template.currentData();
|
const list = Template.currentData();
|
||||||
return user.getListWidth(list.boardId, list._id);
|
if (!user || !list) return 270; // Return default width if user or list is not available
|
||||||
|
return user.getListWidthFromStorage(list.boardId, list._id);
|
||||||
},
|
},
|
||||||
|
|
||||||
listConstraint() {
|
listConstraint() {
|
||||||
const user = ReactiveCache.getCurrentUser();
|
const user = ReactiveCache.getCurrentUser();
|
||||||
const list = Template.currentData();
|
const list = Template.currentData();
|
||||||
return user.getListConstraint(list.boardId, list._id);
|
if (!user || !list) return 550; // Return default constraint if user or list is not available
|
||||||
|
return user.getListConstraintFromStorage(list.boardId, list._id);
|
||||||
},
|
},
|
||||||
|
|
||||||
autoWidth() {
|
autoWidth() {
|
||||||
|
|
@ -217,12 +219,31 @@ BlazeComponent.extendComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeListResize() {
|
initializeListResize() {
|
||||||
|
// Check if we're still in a valid template context
|
||||||
|
if (!Template.currentData()) {
|
||||||
|
console.warn('No current template data available for list resize initialization');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const list = Template.currentData();
|
const list = Template.currentData();
|
||||||
const $list = this.$('.js-list');
|
const $list = this.$('.js-list');
|
||||||
const $resizeHandle = this.$('.js-list-resize-handle');
|
const $resizeHandle = this.$('.js-list-resize-handle');
|
||||||
|
|
||||||
|
// Check if elements exist
|
||||||
|
if (!$list.length || !$resizeHandle.length) {
|
||||||
|
console.warn('List or resize handle not found, retrying in 100ms');
|
||||||
|
Meteor.setTimeout(() => {
|
||||||
|
if (!this.isDestroyed) {
|
||||||
|
this.initializeListResize();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Only enable resize for non-collapsed, non-auto-width lists
|
// Only enable resize for non-collapsed, non-auto-width lists
|
||||||
if (list.collapsed || this.autoWidth()) {
|
const isAutoWidth = this.autoWidth();
|
||||||
|
if (list.collapsed || isAutoWidth) {
|
||||||
$resizeHandle.hide();
|
$resizeHandle.hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -240,41 +261,41 @@ BlazeComponent.extendComponent({
|
||||||
startX = e.pageX || e.originalEvent.touches[0].pageX;
|
startX = e.pageX || e.originalEvent.touches[0].pageX;
|
||||||
startWidth = $list.outerWidth();
|
startWidth = $list.outerWidth();
|
||||||
|
|
||||||
|
|
||||||
// Add visual feedback
|
// Add visual feedback
|
||||||
$list.addClass('list-resizing');
|
$list.addClass('list-resizing');
|
||||||
$('body').addClass('list-resizing-active');
|
$('body').addClass('list-resizing-active');
|
||||||
|
|
||||||
|
|
||||||
// Prevent text selection during resize
|
// Prevent text selection during resize
|
||||||
$('body').css('user-select', 'none');
|
$('body').css('user-select', 'none');
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
const doResize = (e) => {
|
const doResize = (e) => {
|
||||||
if (!isResizing) return;
|
if (!isResizing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentX = e.pageX || e.originalEvent.touches[0].pageX;
|
const currentX = e.pageX || e.originalEvent.touches[0].pageX;
|
||||||
const deltaX = currentX - startX;
|
const deltaX = currentX - startX;
|
||||||
const newWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + deltaX));
|
const newWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + deltaX));
|
||||||
|
|
||||||
// Apply the new width immediately for real-time feedback using CSS custom properties
|
// Apply the new width immediately for real-time feedback
|
||||||
$list[0].style.setProperty('--list-width', `${newWidth}px`);
|
$list[0].style.setProperty('--list-width', `${newWidth}px`);
|
||||||
$list.css({
|
$list[0].style.setProperty('width', `${newWidth}px`);
|
||||||
'width': `${newWidth}px`,
|
$list[0].style.setProperty('min-width', `${newWidth}px`);
|
||||||
'min-width': `${newWidth}px`,
|
$list[0].style.setProperty('max-width', `${newWidth}px`);
|
||||||
'max-width': `${newWidth}px`,
|
$list[0].style.setProperty('flex', 'none');
|
||||||
'flex': 'none',
|
$list[0].style.setProperty('flex-basis', 'auto');
|
||||||
'flex-basis': 'auto',
|
$list[0].style.setProperty('flex-grow', '0');
|
||||||
'flex-grow': '0',
|
$list[0].style.setProperty('flex-shrink', '0');
|
||||||
'flex-shrink': '0'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Debug: log the width change
|
|
||||||
if (process.env.DEBUG === 'true') {
|
|
||||||
console.log(`Resizing list to ${newWidth}px`);
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopResize = (e) => {
|
const stopResize = (e) => {
|
||||||
|
|
@ -287,17 +308,15 @@ BlazeComponent.extendComponent({
|
||||||
const deltaX = currentX - startX;
|
const deltaX = currentX - startX;
|
||||||
const finalWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + deltaX));
|
const finalWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + deltaX));
|
||||||
|
|
||||||
// Ensure the final width is applied using CSS custom properties
|
// Ensure the final width is applied
|
||||||
$list[0].style.setProperty('--list-width', `${finalWidth}px`);
|
$list[0].style.setProperty('--list-width', `${finalWidth}px`);
|
||||||
$list.css({
|
$list[0].style.setProperty('width', `${finalWidth}px`);
|
||||||
'width': `${finalWidth}px`,
|
$list[0].style.setProperty('min-width', `${finalWidth}px`);
|
||||||
'min-width': `${finalWidth}px`,
|
$list[0].style.setProperty('max-width', `${finalWidth}px`);
|
||||||
'max-width': `${finalWidth}px`,
|
$list[0].style.setProperty('flex', 'none');
|
||||||
'flex': 'none',
|
$list[0].style.setProperty('flex-basis', 'auto');
|
||||||
'flex-basis': 'auto',
|
$list[0].style.setProperty('flex-grow', '0');
|
||||||
'flex-grow': '0',
|
$list[0].style.setProperty('flex-shrink', '0');
|
||||||
'flex-shrink': '0'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove visual feedback but keep the width
|
// Remove visual feedback but keep the width
|
||||||
$list.removeClass('list-resizing');
|
$list.removeClass('list-resizing');
|
||||||
|
|
@ -311,16 +330,14 @@ BlazeComponent.extendComponent({
|
||||||
const boardId = list.boardId;
|
const boardId = list.boardId;
|
||||||
const listId = list._id;
|
const listId = list._id;
|
||||||
|
|
||||||
// Use the same method as the hamburger menu
|
// Use the new storage method that handles both logged-in and non-logged-in users
|
||||||
if (process.env.DEBUG === 'true') {
|
if (process.env.DEBUG === 'true') {
|
||||||
console.log(`Saving list width: ${finalWidth}px for list ${listId}`);
|
|
||||||
}
|
}
|
||||||
Meteor.call('applyListWidth', boardId, listId, finalWidth, listConstraint, (error, result) => {
|
Meteor.call('applyListWidthToStorage', boardId, listId, finalWidth, listConstraint, (error, result) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Error saving list width:', error);
|
console.error('Error saving list width:', error);
|
||||||
} else {
|
} else {
|
||||||
if (process.env.DEBUG === 'true') {
|
if (process.env.DEBUG === 'true') {
|
||||||
console.log('List width saved successfully:', result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -334,9 +351,16 @@ BlazeComponent.extendComponent({
|
||||||
$(document).on('mouseup', stopResize);
|
$(document).on('mouseup', stopResize);
|
||||||
|
|
||||||
// Touch events for mobile
|
// Touch events for mobile
|
||||||
$resizeHandle.on('touchstart', startResize);
|
$resizeHandle.on('touchstart', startResize, { passive: false });
|
||||||
$(document).on('touchmove', doResize);
|
$(document).on('touchmove', doResize, { passive: false });
|
||||||
$(document).on('touchend', stopResize);
|
$(document).on('touchend', stopResize, { passive: false });
|
||||||
|
|
||||||
|
|
||||||
|
// Prevent dragscroll interference
|
||||||
|
$resizeHandle.on('mousedown', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Reactively update resize handle visibility when auto-width changes
|
// Reactively update resize handle visibility when auto-width changes
|
||||||
component.autorun(() => {
|
component.autorun(() => {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ template(name="listBody")
|
||||||
+addCardForm(listId=_id position="bottom")
|
+addCardForm(listId=_id position="bottom")
|
||||||
else
|
else
|
||||||
a.open-minicard-composer.js-card-composer.js-open-inlined-form(title="{{_ 'add-card-to-bottom-of-list'}}")
|
a.open-minicard-composer.js-card-composer.js-open-inlined-form(title="{{_ 'add-card-to-bottom-of-list'}}")
|
||||||
i.fa.fa-plus
|
| ➕
|
||||||
|
|
||||||
template(name="spinnerList")
|
template(name="spinnerList")
|
||||||
.sk-spinner.sk-spinner-list(
|
.sk-spinner.sk-spinner-list(
|
||||||
|
|
@ -54,7 +54,7 @@ template(name="addCardForm")
|
||||||
|
|
||||||
.add-controls.clearfix
|
.add-controls.clearfix
|
||||||
button.primary.confirm(type="submit") {{_ 'add'}}
|
button.primary.confirm(type="submit") {{_ 'add'}}
|
||||||
a.fa.fa-times-thin.js-close-inlined-form
|
a.js-close-inlined-form | ❌
|
||||||
.add-controls.clearfix
|
.add-controls.clearfix
|
||||||
unless currentBoard.isTemplatesBoard
|
unless currentBoard.isTemplatesBoard
|
||||||
unless currentBoard.isTemplateBoard
|
unless currentBoard.isTemplateBoard
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,6 @@ template(name="listHeader")
|
||||||
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
|
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
|
||||||
else
|
else
|
||||||
if collapsed
|
if collapsed
|
||||||
a.js-collapse(title="{{_ 'uncollapse'}}")
|
|
||||||
i.fa.fa-arrow-left.list-header-uncollapse-left
|
|
||||||
i.fa.fa-arrow-right.list-header-uncollapse-right
|
|
||||||
if showCardsCountForList cards.length
|
if showCardsCountForList cards.length
|
||||||
br
|
br
|
||||||
span.cardCount {{cardsCount}}
|
span.cardCount {{cardsCount}}
|
||||||
|
|
@ -29,6 +26,10 @@ template(name="listHeader")
|
||||||
if showCardsCountForList cards.length
|
if showCardsCountForList cards.length
|
||||||
span.cardCount {{cardsCount}} {{cardsCountForListIsOne cards.length}}
|
span.cardCount {{cardsCount}} {{cardsCountForListIsOne cards.length}}
|
||||||
else
|
else
|
||||||
|
if collapsed
|
||||||
|
a.js-collapse(title="{{_ 'uncollapse'}}")
|
||||||
|
| ⬅️
|
||||||
|
| ➡️
|
||||||
div(class="{{#if collapsed}}list-rotated{{/if}}")
|
div(class="{{#if collapsed}}list-rotated{{/if}}")
|
||||||
h2.list-header-name(
|
h2.list-header-name(
|
||||||
title="{{ moment modifiedAt 'LLL' }}"
|
title="{{ moment modifiedAt 'LLL' }}"
|
||||||
|
|
@ -45,32 +46,32 @@ template(name="listHeader")
|
||||||
if isMiniScreen
|
if isMiniScreen
|
||||||
if currentList
|
if currentList
|
||||||
if isWatching
|
if isWatching
|
||||||
i.list-header-watch-icon.fa.fa-eye
|
i.list-header-watch-icon | 👁️
|
||||||
div.list-header-menu
|
div.list-header-menu
|
||||||
unless currentUser.isCommentOnly
|
unless currentUser.isCommentOnly
|
||||||
if canSeeAddCard
|
if canSeeAddCard
|
||||||
a.js-add-card.fa.fa-plus.list-header-plus-top(title="{{_ 'add-card-to-top-of-list'}}")
|
a.js-add-card.list-header-plus-top(title="{{_ 'add-card-to-top-of-list'}}") | ➕
|
||||||
a.fa.fa-navicon.js-open-list-menu(title="{{_ 'listActionPopup-title'}}")
|
a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") | ☰
|
||||||
else
|
else
|
||||||
a.list-header-menu-icon.fa.fa-angle-right.js-select-list
|
a.list-header-menu-icon.js-select-list | ▶️
|
||||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
a.list-header-handle.handle.js-list-handle | ↔️
|
||||||
else if currentUser.isBoardMember
|
else if currentUser.isBoardMember
|
||||||
if isWatching
|
if isWatching
|
||||||
i.list-header-watch-icon.fa.fa-eye
|
i.list-header-watch-icon | 👁️
|
||||||
unless collapsed
|
unless collapsed
|
||||||
div.list-header-menu
|
div.list-header-menu
|
||||||
unless currentUser.isCommentOnly
|
unless currentUser.isCommentOnly
|
||||||
//if isBoardAdmin
|
//if isBoardAdmin
|
||||||
// a.fa.js-list-star.list-header-plus-top(class="fa-star{{#unless starred}}-o{{/unless}}")
|
// a.fa.js-list-star.list-header-plus-top(class="fa-star{{#unless starred}}-o{{/unless}}")
|
||||||
if canSeeAddCard
|
if canSeeAddCard
|
||||||
a.js-add-card.fa.fa-plus.list-header-plus-top(title="{{_ 'add-card-to-top-of-list'}}")
|
a.js-add-card.list-header-plus-top(title="{{_ 'add-card-to-top-of-list'}}") | ➕
|
||||||
a.js-collapse(title="{{_ 'collapse'}}")
|
a.js-collapse(title="{{_ 'collapse'}}")
|
||||||
i.fa.fa-arrow-right.list-header-collapse-right
|
| ⬅️
|
||||||
i.fa.fa-arrow-left.list-header-collapse-left
|
| ➡️
|
||||||
a.fa.fa-navicon.js-open-list-menu(title="{{_ 'listActionPopup-title'}}")
|
a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") | ☰
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
if isTouchScreenOrShowDesktopDragHandles
|
if isTouchScreenOrShowDesktopDragHandles
|
||||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
a.list-header-handle.handle.js-list-handle | ↔️
|
||||||
|
|
||||||
template(name="editListTitleForm")
|
template(name="editListTitleForm")
|
||||||
.list-composer
|
.list-composer
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@ template(name="sidebar")
|
||||||
.sidebar-actions
|
.sidebar-actions
|
||||||
.sidebar-shortcuts
|
.sidebar-shortcuts
|
||||||
a.sidebar-btn.js-shortcuts(title="{{_ 'keyboard-shortcuts' }}")
|
a.sidebar-btn.js-shortcuts(title="{{_ 'keyboard-shortcuts' }}")
|
||||||
i.fa.fa-keyboard-o
|
| ⌨️
|
||||||
span {{_ 'keyboard-shortcuts' }}
|
span {{_ 'keyboard-shortcuts' }}
|
||||||
a.sidebar-btn.js-keyboard-shortcuts-toggle(
|
a.sidebar-btn.js-keyboard-shortcuts-toggle(
|
||||||
title="{{#if isKeyboardShortcuts}}{{_ 'keyboard-shortcuts-enabled'}}{{else}}{{_ 'keyboard-shortcuts-disabled'}}{{/if}}")
|
title="{{#if isKeyboardShortcuts}}{{_ 'keyboard-shortcuts-enabled'}}{{else}}{{_ 'keyboard-shortcuts-disabled'}}{{/if}}")
|
||||||
i.fa(class="fa-solid fa-{{#if isKeyboardShortcuts}}check-square-o{{else}}ban{{/if}}")
|
| {{#if isKeyboardShortcuts}}✅{{else}}🚫{{/if}}
|
||||||
if isAccessibilityEnabled
|
if isAccessibilityEnabled
|
||||||
a.sidebar-accessibility
|
a.sidebar-accessibility
|
||||||
i.fa.fa-universal-access
|
| ♿
|
||||||
span {{_ 'accessibility'}}
|
span {{_ 'accessibility'}}
|
||||||
a.sidebar-xmark.js-close-sidebar ✕
|
a.sidebar-xmark.js-close-sidebar ✕
|
||||||
.sidebar-content.js-board-sidebar-content
|
.sidebar-content.js-board-sidebar-content
|
||||||
|
|
@ -22,7 +22,7 @@ template(name="sidebar")
|
||||||
// i.fa.fa-navicon
|
// i.fa.fa-navicon
|
||||||
unless isDefaultView
|
unless isDefaultView
|
||||||
h2
|
h2
|
||||||
a.fa.fa-chevron-left.js-back-home
|
a.js-back-home | ⬅️
|
||||||
= getViewTitle
|
= getViewTitle
|
||||||
if isOpen
|
if isOpen
|
||||||
+Template.dynamic(template=getViewTemplate)
|
+Template.dynamic(template=getViewTemplate)
|
||||||
|
|
@ -51,7 +51,7 @@ template(name='homeSidebar')
|
||||||
hr
|
hr
|
||||||
unless currentUser.isNoComments
|
unless currentUser.isNoComments
|
||||||
h3.activity-title
|
h3.activity-title
|
||||||
i.fa.fa-comments-o
|
| 💬
|
||||||
| {{_ 'activities'}}
|
| {{_ 'activities'}}
|
||||||
|
|
||||||
.material-toggle-switch(title="{{_ 'show-activities'}}")
|
.material-toggle-switch(title="{{_ 'show-activities'}}")
|
||||||
|
|
@ -67,11 +67,11 @@ template(name="membersWidget")
|
||||||
unless currentUser.isWorker
|
unless currentUser.isWorker
|
||||||
h3
|
h3
|
||||||
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}")
|
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}")
|
||||||
i.board-header-btn-icon.fa.fa-cog
|
| ⚙️
|
||||||
| {{_ 'boardMenuPopup-title'}}
|
| {{_ 'boardMenuPopup-title'}}
|
||||||
hr
|
hr
|
||||||
h3
|
h3
|
||||||
i.fa.fa-users
|
| 👥
|
||||||
| {{_ 'members'}}
|
| {{_ 'members'}}
|
||||||
+basicTabs(tabs=tabs)
|
+basicTabs(tabs=tabs)
|
||||||
+tabContent(slug="people")
|
+tabContent(slug="people")
|
||||||
|
|
@ -83,15 +83,15 @@ template(name="membersWidget")
|
||||||
if isSandstorm
|
if isSandstorm
|
||||||
if currentUser.isBoardMember
|
if currentUser.isBoardMember
|
||||||
a.member.add-member.sandstorm-powerbox-request-identity(title="{{_ 'add-members'}}")
|
a.member.add-member.sandstorm-powerbox-request-identity(title="{{_ 'add-members'}}")
|
||||||
i.fa.fa-plus
|
| ➕
|
||||||
else if currentUser.isBoardAdmin
|
else if currentUser.isBoardAdmin
|
||||||
a.member.add-member.js-manage-board-members(title="{{_ 'add-members'}}")
|
a.member.add-member.js-manage-board-members(title="{{_ 'add-members'}}")
|
||||||
i.fa.fa-plus
|
| ➕
|
||||||
.clearfix
|
.clearfix
|
||||||
if isInvited
|
if isInvited
|
||||||
hr
|
hr
|
||||||
p
|
p
|
||||||
i.fa.fa-exclamation-circle
|
| ⚠️
|
||||||
| {{_ 'just-invited'}}
|
| {{_ 'just-invited'}}
|
||||||
button.js-member-invite-accept.primary {{_ 'accept'}}
|
button.js-member-invite-accept.primary {{_ 'accept'}}
|
||||||
button.js-member-invite-decline {{_ 'decline'}}
|
button.js-member-invite-decline {{_ 'decline'}}
|
||||||
|
|
@ -127,7 +127,7 @@ template(name="boardOrgGeneral")
|
||||||
th
|
th
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
a.member.orgOrTeamMember.add-member.js-manage-board-addOrg(title="{{_ 'add-members'}}")
|
a.member.orgOrTeamMember.add-member.js-manage-board-addOrg(title="{{_ 'add-members'}}")
|
||||||
i.addTeamFaPlus.fa.fa-plus
|
| ➕
|
||||||
.divaddfaplusminus
|
.divaddfaplusminus
|
||||||
| {{_ 'add'}}
|
| {{_ 'add'}}
|
||||||
each org in currentBoard.activeOrgs
|
each org in currentBoard.activeOrgs
|
||||||
|
|
@ -148,7 +148,7 @@ template(name="boardTeamGeneral")
|
||||||
th
|
th
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
a.member.orgOrTeamMember.add-member.js-manage-board-addTeam(title="{{_ 'add-members'}}")
|
a.member.orgOrTeamMember.add-member.js-manage-board-addTeam(title="{{_ 'add-members'}}")
|
||||||
i.addTeamFaPlus.fa.fa-plus
|
| ➕
|
||||||
.divaddfaplusminus
|
.divaddfaplusminus
|
||||||
| {{_ 'add'}}
|
| {{_ 'add'}}
|
||||||
each currentBoard.activeTeams
|
each currentBoard.activeTeams
|
||||||
|
|
@ -161,7 +161,7 @@ template(name="boardChangeColorPopup")
|
||||||
span.background-box(class="board-color-{{this}}")
|
span.background-box(class="board-color-{{this}}")
|
||||||
span {{this}}
|
span {{this}}
|
||||||
if isSelected
|
if isSelected
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
|
|
||||||
template(name="boardChangeBackgroundImagePopup")
|
template(name="boardChangeBackgroundImagePopup")
|
||||||
form
|
form
|
||||||
|
|
@ -423,7 +423,7 @@ template(name="chooseBoardSource")
|
||||||
template(name="archiveBoardPopup")
|
template(name="archiveBoardPopup")
|
||||||
p {{_ 'close-board-pop'}}
|
p {{_ 'close-board-pop'}}
|
||||||
button.js-confirm.negate.full(type="submit")
|
button.js-confirm.negate.full(type="submit")
|
||||||
i.fa.fa-archive
|
| 📦
|
||||||
| {{_ 'archive'}}
|
| {{_ 'archive'}}
|
||||||
|
|
||||||
template(name="outgoingWebhooksPopup")
|
template(name="outgoingWebhooksPopup")
|
||||||
|
|
@ -459,25 +459,25 @@ template(name="boardMenuPopup")
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
li
|
li
|
||||||
a.js-open-rules-view(title="{{_ 'rules'}}")
|
a.js-open-rules-view(title="{{_ 'rules'}}")
|
||||||
i.fa.fa-magic
|
| ✨
|
||||||
| {{_ 'rules'}}
|
| {{_ 'rules'}}
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
li
|
li
|
||||||
a.js-custom-fields
|
a.js-custom-fields
|
||||||
i.fa.fa-list-alt
|
| 📝
|
||||||
| {{_ 'custom-fields'}}
|
| {{_ 'custom-fields'}}
|
||||||
li
|
li
|
||||||
a.js-open-archives
|
a.js-open-archives
|
||||||
i.fa.fa-archive
|
| 📦
|
||||||
| {{_ 'archived-items'}}
|
| {{_ 'archived-items'}}
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
li
|
li
|
||||||
a.js-change-board-color
|
a.js-change-board-color
|
||||||
i.fa.fa-paint-brush
|
| 🎨
|
||||||
| {{_ 'board-change-color'}}
|
| {{_ 'board-change-color'}}
|
||||||
li
|
li
|
||||||
a.js-change-background-image
|
a.js-change-background-image
|
||||||
i.fa.fa-picture-o
|
| 🖼️
|
||||||
| {{_ 'board-change-background-image'}}
|
| {{_ 'board-change-background-image'}}
|
||||||
//Bug Board icons random dance https://github.com/wekan/wekan/issues/4214
|
//Bug Board icons random dance https://github.com/wekan/wekan/issues/4214
|
||||||
//if currentUser.isBoardAdmin
|
//if currentUser.isBoardAdmin
|
||||||
|
|
@ -492,20 +492,20 @@ template(name="boardMenuPopup")
|
||||||
if withApi
|
if withApi
|
||||||
li
|
li
|
||||||
a.js-export-board
|
a.js-export-board
|
||||||
i.fa.fa-share-alt
|
| 📤
|
||||||
| {{_ 'export-board'}}
|
| {{_ 'export-board'}}
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
li
|
li
|
||||||
a.js-outgoing-webhooks
|
a.js-outgoing-webhooks
|
||||||
i.fa.fa-globe
|
| 🌐
|
||||||
| {{_ 'outgoing-webhooks'}}
|
| {{_ 'outgoing-webhooks'}}
|
||||||
li
|
li
|
||||||
a.js-card-settings
|
a.js-card-settings
|
||||||
i.fa.fa-id-card-o
|
| 🃏
|
||||||
| {{_ 'card-settings'}}
|
| {{_ 'card-settings'}}
|
||||||
li
|
li
|
||||||
a.js-subtask-settings
|
a.js-subtask-settings
|
||||||
i.fa.fa-sitemap
|
| 🌐
|
||||||
| {{_ 'subtask-settings'}}
|
| {{_ 'subtask-settings'}}
|
||||||
unless currentBoard.isTemplatesBoard
|
unless currentBoard.isTemplatesBoard
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
|
|
@ -513,41 +513,40 @@ template(name="boardMenuPopup")
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
li
|
li
|
||||||
a.js-archive-board
|
a.js-archive-board
|
||||||
i.fa.fa-arrow-right
|
| ➡️📦
|
||||||
i.fa.fa-archive
|
|
||||||
| {{_ 'archive-board'}}
|
| {{_ 'archive-board'}}
|
||||||
|
|
||||||
template(name="exportBoard")
|
template(name="exportBoard")
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
li
|
li
|
||||||
a.download-json-link(href="{{exportUrl}}", download="{{exportJsonFilename}}")
|
a.download-json-link(href="{{exportUrl}}", download="{{exportJsonFilename}}")
|
||||||
i.fa.fa-share-alt
|
| 📤
|
||||||
| {{_ 'export-board-json'}}
|
| {{_ 'export-board-json'}}
|
||||||
li
|
li
|
||||||
a(href="{{exportUrlExcel}}", download="{{exportFilenameExcel}}")
|
a(href="{{exportUrlExcel}}", download="{{exportFilenameExcel}}")
|
||||||
i.fa.fa-share-alt
|
| 📤
|
||||||
| {{_ 'export-board-excel'}}
|
| {{_ 'export-board-excel'}}
|
||||||
li
|
li
|
||||||
a(href="{{exportCsvUrl}}", download="{{exportCsvFilename}}")
|
a(href="{{exportCsvUrl}}", download="{{exportCsvFilename}}")
|
||||||
i.fa.fa-share-alt
|
| 📤
|
||||||
| {{_ 'export-board-csv'}} ,
|
| {{_ 'export-board-csv'}} ,
|
||||||
li
|
li
|
||||||
a(href="{{exportScsvUrl}}", download="{{exportCsvFilename}}")
|
a(href="{{exportScsvUrl}}", download="{{exportCsvFilename}}")
|
||||||
i.fa.fa-share-alt
|
| 📤
|
||||||
| {{_ 'export-board-csv'}} ;
|
| {{_ 'export-board-csv'}} ;
|
||||||
li
|
li
|
||||||
a(href="{{exportTsvUrl}}", download="{{exportTsvFilename}}")
|
a(href="{{exportTsvUrl}}", download="{{exportTsvFilename}}")
|
||||||
i.fa.fa-share-alt
|
| 📤
|
||||||
| {{_ 'export-board-tsv'}}
|
| {{_ 'export-board-tsv'}}
|
||||||
li
|
li
|
||||||
a.html-export-board
|
a.html-export-board
|
||||||
i.fa.fa-archive
|
| 📦
|
||||||
| {{_ 'export-board-html'}}
|
| {{_ 'export-board-html'}}
|
||||||
|
|
||||||
template(name="labelsWidget")
|
template(name="labelsWidget")
|
||||||
.board-widget.board-widget-labels
|
.board-widget.board-widget-labels
|
||||||
h3
|
h3
|
||||||
i.fa.fa-tags
|
| 🏷️
|
||||||
| {{_ 'labels'}}
|
| {{_ 'labels'}}
|
||||||
.board-widget-content
|
.board-widget-content
|
||||||
each currentBoard.labels
|
each currentBoard.labels
|
||||||
|
|
@ -558,7 +557,7 @@ template(name="labelsWidget")
|
||||||
= name
|
= name
|
||||||
if currentUser.isBoardAdmin
|
if currentUser.isBoardAdmin
|
||||||
a.card-label.add-label.js-add-label(title="{{_ 'label-create'}}")
|
a.card-label.add-label.js-add-label(title="{{_ 'label-create'}}")
|
||||||
i.fa.fa-plus
|
| ➕
|
||||||
|
|
||||||
template(name="memberPopup")
|
template(name="memberPopup")
|
||||||
.board-member-menu
|
.board-member-menu
|
||||||
|
|
@ -570,7 +569,7 @@ template(name="memberPopup")
|
||||||
p.quiet @#{user.username}
|
p.quiet @#{user.username}
|
||||||
if isInvited
|
if isInvited
|
||||||
p
|
p
|
||||||
i.fa.fa-exclamation-circle
|
| ⚠️
|
||||||
| {{_ 'not-accepted-yet'}}
|
| {{_ 'not-accepted-yet'}}
|
||||||
|
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
|
|
@ -665,31 +664,31 @@ template(name="changePermissionsPopup")
|
||||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-admin{{/if}}")
|
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-admin{{/if}}")
|
||||||
| {{_ 'admin'}}
|
| {{_ 'admin'}}
|
||||||
if isAdmin
|
if isAdmin
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
span.sub-name {{_ 'admin-desc'}}
|
span.sub-name {{_ 'admin-desc'}}
|
||||||
li
|
li
|
||||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-normal{{/if}}")
|
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-normal{{/if}}")
|
||||||
| {{_ 'normal'}}
|
| {{_ 'normal'}}
|
||||||
if isNormal
|
if isNormal
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
span.sub-name {{_ 'normal-desc'}}
|
span.sub-name {{_ 'normal-desc'}}
|
||||||
li
|
li
|
||||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-no-comments{{/if}}")
|
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-no-comments{{/if}}")
|
||||||
| {{_ 'no-comments'}}
|
| {{_ 'no-comments'}}
|
||||||
if isNoComments
|
if isNoComments
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
span.sub-name {{_ 'no-comments-desc'}}
|
span.sub-name {{_ 'no-comments-desc'}}
|
||||||
li
|
li
|
||||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-comment-only{{/if}}")
|
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-comment-only{{/if}}")
|
||||||
| {{_ 'comment-only'}}
|
| {{_ 'comment-only'}}
|
||||||
if isCommentOnly
|
if isCommentOnly
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
span.sub-name {{_ 'comment-only-desc'}}
|
span.sub-name {{_ 'comment-only-desc'}}
|
||||||
li
|
li
|
||||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-worker{{/if}}")
|
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-worker{{/if}}")
|
||||||
| {{_ 'worker'}}
|
| {{_ 'worker'}}
|
||||||
if isWorker
|
if isWorker
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
span.sub-name {{_ 'worker-desc'}}
|
span.sub-name {{_ 'worker-desc'}}
|
||||||
if isLastAdmin
|
if isLastAdmin
|
||||||
hr
|
hr
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ template(name="swimlaneFixedHeader")
|
||||||
| {{isTitleDefault title}}
|
| {{isTitleDefault title}}
|
||||||
.swimlane-header-menu
|
.swimlane-header-menu
|
||||||
unless currentUser.isCommentOnly
|
unless currentUser.isCommentOnly
|
||||||
a.js-open-add-swimlane-menu.swimlane-header-plus-icon
|
a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}")
|
||||||
| ➕(title="{{_ 'add-swimlane'}}")
|
| ➕
|
||||||
a.js-open-swimlane-menu
|
a.js-open-swimlane-menu(title="{{_ 'swimlaneActionPopup-title'}}")
|
||||||
| ☰(title="{{_ 'swimlaneActionPopup-title'}}")
|
| ☰
|
||||||
//// TODO: Collapse Swimlane: make button working, etc.
|
//// TODO: Collapse Swimlane: make button working, etc.
|
||||||
//unless collapsed
|
//unless collapsed
|
||||||
// a.js-collapse-swimlane(title="{{_ 'collapse'}}")
|
// a.js-collapse-swimlane(title="{{_ 'collapse'}}")
|
||||||
|
|
@ -99,7 +99,7 @@ template(name="setSwimlaneColorPopup")
|
||||||
each colors
|
each colors
|
||||||
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
|
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
|
||||||
if(isSelected color)
|
if(isSelected color)
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
// Buttons aligned left too
|
// Buttons aligned left too
|
||||||
.flush-left
|
.flush-left
|
||||||
button.primary.confirm.js-submit(style="margin-left:0") {{_ 'save'}}
|
button.primary.confirm.js-submit(style="margin-left:0") {{_ 'save'}}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.swimlane-header-menu .swimlane-header-collapse-down {
|
.swimlane-header-menu .swimlane-header-collapse-down {
|
||||||
font-size: 50%;
|
font-size: 50%;
|
||||||
|
|
@ -234,3 +235,106 @@
|
||||||
background: #4b0082 !important;
|
background: #4b0082 !important;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Swimlane resize handle */
|
||||||
|
.swimlane-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 8px;
|
||||||
|
background: transparent;
|
||||||
|
cursor: row-resize;
|
||||||
|
z-index: 20;
|
||||||
|
border-top: 2px solid transparent;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-radius: 2px;
|
||||||
|
/* Ensure the handle is clickable */
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show resize handle only on hover */
|
||||||
|
.swimlane:hover .swimlane-resize-handle {
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
border-top-color: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a subtle resize indicator line at the bottom of swimlane on hover */
|
||||||
|
.swimlane:hover .swimlane-resize-handle::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: rgba(0, 123, 255, 0.3);
|
||||||
|
z-index: 21;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the indicator line more prominent when hovering over the resize handle */
|
||||||
|
.swimlane-resize-handle:hover::after {
|
||||||
|
background: rgba(0, 123, 255, 0.6) !important;
|
||||||
|
height: 3px !important;
|
||||||
|
box-shadow: 0 0 4px rgba(0, 123, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.swimlane-resize-handle:hover {
|
||||||
|
background: rgba(0, 123, 255, 0.4) !important;
|
||||||
|
border-top-color: #0079bf !important;
|
||||||
|
box-shadow: 0 0 4px rgba(0, 123, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.swimlane-resize-handle:active {
|
||||||
|
background: rgba(0, 123, 255, 0.6) !important;
|
||||||
|
border-top-color: #0079bf !important;
|
||||||
|
box-shadow: 0 0 6px rgba(0, 123, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a subtle indicator line */
|
||||||
|
.swimlane-resize-handle::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 20px;
|
||||||
|
height: 2px;
|
||||||
|
background: rgba(0, 123, 255, 0.6);
|
||||||
|
border-radius: 1px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swimlane-resize-handle:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Visual feedback during resize */
|
||||||
|
.swimlane.swimlane-resizing {
|
||||||
|
transition: none !important;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 123, 255, 0.3);
|
||||||
|
/* Ensure the swimlane maintains its new height during resize */
|
||||||
|
flex: none !important;
|
||||||
|
flex-basis: auto !important;
|
||||||
|
flex-grow: 0 !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
/* Override any conflicting layout properties */
|
||||||
|
display: flex !important;
|
||||||
|
position: relative !important;
|
||||||
|
/* Force height to be respected */
|
||||||
|
height: var(--swimlane-height, auto) !important;
|
||||||
|
min-height: var(--swimlane-height, auto) !important;
|
||||||
|
max-height: var(--swimlane-height, auto) !important;
|
||||||
|
/* Ensure the height is applied immediately */
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.swimlane-resizing-active {
|
||||||
|
cursor: row-resize !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.swimlane-resizing-active * {
|
||||||
|
cursor: row-resize !important;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ template(name="swimlane")
|
||||||
unless collapseSwimlane
|
unless collapseSwimlane
|
||||||
.swimlane.js-lists.js-swimlane.dragscroll(id="swimlane-{{_id}}"
|
.swimlane.js-lists.js-swimlane.dragscroll(id="swimlane-{{_id}}"
|
||||||
style="height:{{swimlaneHeight}};")
|
style="height:{{swimlaneHeight}};")
|
||||||
|
.swimlane-resize-handle.js-swimlane-resize-handle.nodragscroll
|
||||||
if isMiniScreen
|
if isMiniScreen
|
||||||
if currentListIsInThisSwimlane _id
|
if currentListIsInThisSwimlane _id
|
||||||
+list(currentList)
|
+list(currentList)
|
||||||
|
|
@ -67,7 +68,7 @@ template(name="addListForm")
|
||||||
a.js-list-template {{_ 'template'}}
|
a.js-list-template {{_ 'template'}}
|
||||||
else
|
else
|
||||||
a.open-list-composer.js-open-inlined-form(title="{{_ 'add-list'}}")
|
a.open-list-composer.js-open-inlined-form(title="{{_ 'add-list'}}")
|
||||||
i.fa.fa-plus
|
| ➕
|
||||||
|
|
||||||
template(name="moveSwimlanePopup")
|
template(name="moveSwimlanePopup")
|
||||||
unless currentUser.isWorker
|
unless currentUser.isWorker
|
||||||
|
|
|
||||||
|
|
@ -247,10 +247,21 @@ BlazeComponent.extendComponent({
|
||||||
Utils.isTouchScreenOrShowDesktopDragHandles()
|
Utils.isTouchScreenOrShowDesktopDragHandles()
|
||||||
? ['.js-list-handle', '.js-swimlane-header-handle']
|
? ['.js-list-handle', '.js-swimlane-header-handle']
|
||||||
: ['.js-list-header'],
|
: ['.js-list-header'],
|
||||||
);
|
).concat([
|
||||||
|
'.js-list-resize-handle',
|
||||||
|
'.js-swimlane-resize-handle'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const isResizeHandle = $(evt.target).closest('.js-list-resize-handle, .js-swimlane-resize-handle').length > 0;
|
||||||
|
const isInNoDragArea = $(evt.target).closest(noDragInside.join(',')).length > 0;
|
||||||
|
|
||||||
|
if (isResizeHandle) {
|
||||||
|
console.log('Board drag prevented - resize handle clicked');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$(evt.target).closest(noDragInside.join(',')).length === 0 &&
|
!isInNoDragArea &&
|
||||||
this.$('.swimlane').prop('clientHeight') > evt.offsetY
|
this.$('.swimlane').prop('clientHeight') > evt.offsetY
|
||||||
) {
|
) {
|
||||||
this._isDragging = true;
|
this._isDragging = true;
|
||||||
|
|
@ -283,9 +294,150 @@ BlazeComponent.extendComponent({
|
||||||
swimlaneHeight() {
|
swimlaneHeight() {
|
||||||
const user = ReactiveCache.getCurrentUser();
|
const user = ReactiveCache.getCurrentUser();
|
||||||
const swimlane = Template.currentData();
|
const swimlane = Template.currentData();
|
||||||
const height = user.getSwimlaneHeight(swimlane.boardId, swimlane._id);
|
const height = user.getSwimlaneHeightFromStorage(swimlane.boardId, swimlane._id);
|
||||||
return height == -1 ? "auto" : (height + 5 + "px");
|
return height == -1 ? "auto" : (height + 5 + "px");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRendered() {
|
||||||
|
// Initialize swimlane resize functionality immediately
|
||||||
|
this.initializeSwimlaneResize();
|
||||||
|
},
|
||||||
|
|
||||||
|
initializeSwimlaneResize() {
|
||||||
|
// Check if we're still in a valid template context
|
||||||
|
if (!Template.currentData()) {
|
||||||
|
console.warn('No current template data available for swimlane resize initialization');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const swimlane = Template.currentData();
|
||||||
|
const $swimlane = $(`#swimlane-${swimlane._id}`);
|
||||||
|
const $resizeHandle = $swimlane.find('.js-swimlane-resize-handle');
|
||||||
|
|
||||||
|
// Check if elements exist
|
||||||
|
if (!$swimlane.length || !$resizeHandle.length) {
|
||||||
|
console.warn('Swimlane or resize handle not found, retrying in 100ms');
|
||||||
|
Meteor.setTimeout(() => {
|
||||||
|
if (!this.isDestroyed) {
|
||||||
|
this.initializeSwimlaneResize();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($resizeHandle.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isResizing = false;
|
||||||
|
let startY = 0;
|
||||||
|
let startHeight = 0;
|
||||||
|
const minHeight = 100;
|
||||||
|
const maxHeight = 2000;
|
||||||
|
|
||||||
|
const startResize = (e) => {
|
||||||
|
isResizing = true;
|
||||||
|
startY = e.pageY || e.originalEvent.touches[0].pageY;
|
||||||
|
startHeight = parseInt($swimlane.css('height')) || 300;
|
||||||
|
|
||||||
|
|
||||||
|
$swimlane.addClass('swimlane-resizing');
|
||||||
|
$('body').addClass('swimlane-resizing-active');
|
||||||
|
$('body').css('user-select', 'none');
|
||||||
|
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
const doResize = (e) => {
|
||||||
|
if (!isResizing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentY = e.pageY || e.originalEvent.touches[0].pageY;
|
||||||
|
const deltaY = currentY - startY;
|
||||||
|
const newHeight = Math.max(minHeight, Math.min(maxHeight, startHeight + deltaY));
|
||||||
|
|
||||||
|
|
||||||
|
// Apply the new height immediately for real-time feedback
|
||||||
|
$swimlane[0].style.setProperty('--swimlane-height', `${newHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('height', `${newHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('min-height', `${newHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('max-height', `${newHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('flex', 'none');
|
||||||
|
$swimlane[0].style.setProperty('flex-basis', 'auto');
|
||||||
|
$swimlane[0].style.setProperty('flex-grow', '0');
|
||||||
|
$swimlane[0].style.setProperty('flex-shrink', '0');
|
||||||
|
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopResize = (e) => {
|
||||||
|
if (!isResizing) return;
|
||||||
|
|
||||||
|
isResizing = false;
|
||||||
|
|
||||||
|
// Calculate final height
|
||||||
|
const currentY = e.pageY || e.originalEvent.touches[0].pageY;
|
||||||
|
const deltaY = currentY - startY;
|
||||||
|
const finalHeight = Math.max(minHeight, Math.min(maxHeight, startHeight + deltaY));
|
||||||
|
|
||||||
|
// Ensure the final height is applied
|
||||||
|
$swimlane[0].style.setProperty('--swimlane-height', `${finalHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('height', `${finalHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('min-height', `${finalHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('max-height', `${finalHeight}px`);
|
||||||
|
$swimlane[0].style.setProperty('flex', 'none');
|
||||||
|
$swimlane[0].style.setProperty('flex-basis', 'auto');
|
||||||
|
$swimlane[0].style.setProperty('flex-grow', '0');
|
||||||
|
$swimlane[0].style.setProperty('flex-shrink', '0');
|
||||||
|
|
||||||
|
// Remove visual feedback but keep the height
|
||||||
|
$swimlane.removeClass('swimlane-resizing');
|
||||||
|
$('body').removeClass('swimlane-resizing-active');
|
||||||
|
$('body').css('user-select', '');
|
||||||
|
|
||||||
|
// Save the new height using the existing system
|
||||||
|
const boardId = swimlane.boardId;
|
||||||
|
const swimlaneId = swimlane._id;
|
||||||
|
|
||||||
|
if (process.env.DEBUG === 'true') {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the new storage method that handles both logged-in and non-logged-in users
|
||||||
|
Meteor.call('applySwimlaneHeightToStorage', boardId, swimlaneId, finalHeight, (error, result) => {
|
||||||
|
if (error) {
|
||||||
|
console.error('Error saving swimlane height:', error);
|
||||||
|
} else {
|
||||||
|
if (process.env.DEBUG === 'true') {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mouse events
|
||||||
|
$resizeHandle.on('mousedown', startResize);
|
||||||
|
$(document).on('mousemove', doResize);
|
||||||
|
$(document).on('mouseup', stopResize);
|
||||||
|
|
||||||
|
// Touch events for mobile
|
||||||
|
$resizeHandle.on('touchstart', startResize, { passive: false });
|
||||||
|
$(document).on('touchmove', doResize, { passive: false });
|
||||||
|
$(document).on('touchend', stopResize, { passive: false });
|
||||||
|
|
||||||
|
|
||||||
|
// Prevent dragscroll interference
|
||||||
|
$resizeHandle.on('mousedown', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
}).register('swimlane');
|
}).register('swimlane');
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
BlazeComponent.extendComponent({
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ template(name="changeLanguagePopup")
|
||||||
a.js-set-language
|
a.js-set-language
|
||||||
= name
|
= name
|
||||||
if isCurrentLanguage
|
if isCurrentLanguage
|
||||||
i.fa.fa-check
|
| ✅
|
||||||
|
|
||||||
template(name="changeSettingsPopup")
|
template(name="changeSettingsPopup")
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
|
|
@ -186,7 +186,7 @@ template(name="changeSettingsPopup")
|
||||||
unless currentUser.isWorker
|
unless currentUser.isWorker
|
||||||
li
|
li
|
||||||
label.bold.clear
|
label.bold.clear
|
||||||
i.fa.fa-sort-numeric-asc
|
| 🔢
|
||||||
| {{_ 'show-cards-minimum-count'}}
|
| {{_ 'show-cards-minimum-count'}}
|
||||||
input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="-1")
|
input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="-1")
|
||||||
label.bold.clear
|
label.bold.clear
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,8 @@ Blaze.registerHelper('isTouchScreenOrShowDesktopDragHandles', () =>
|
||||||
|
|
||||||
Blaze.registerHelper('moment', (...args) => {
|
Blaze.registerHelper('moment', (...args) => {
|
||||||
args.pop(); // hash
|
args.pop(); // hash
|
||||||
const [date, format] = args;
|
const [date, formatStr] = args;
|
||||||
return format(new Date(date), format ?? 'LLLL');
|
return format(new Date(date), formatStr ?? 'LLLL');
|
||||||
});
|
});
|
||||||
|
|
||||||
Blaze.registerHelper('canModifyCard', () =>
|
Blaze.registerHelper('canModifyCard', () =>
|
||||||
|
|
|
||||||
202
models/users.js
202
models/users.js
|
|
@ -875,6 +875,52 @@ Users.helpers({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSwimlaneHeightFromStorage(boardId, swimlaneId) {
|
||||||
|
// For logged-in users, get from profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.getSwimlaneHeight(boardId, swimlaneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, get from localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-swimlane-heights');
|
||||||
|
if (stored) {
|
||||||
|
const heights = JSON.parse(stored);
|
||||||
|
if (heights[boardId] && heights[boardId][swimlaneId]) {
|
||||||
|
return heights[boardId][swimlaneId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error reading swimlane heights from localStorage:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
setSwimlaneHeightToStorage(boardId, swimlaneId, height) {
|
||||||
|
// For logged-in users, save to profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.setSwimlaneHeight(boardId, swimlaneId, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, save to localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-swimlane-heights');
|
||||||
|
let heights = stored ? JSON.parse(stored) : {};
|
||||||
|
|
||||||
|
if (!heights[boardId]) {
|
||||||
|
heights[boardId] = {};
|
||||||
|
}
|
||||||
|
heights[boardId][swimlaneId] = height;
|
||||||
|
|
||||||
|
localStorage.setItem('wekan-swimlane-heights', JSON.stringify(heights));
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error saving swimlane height to localStorage:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** returns all confirmed move and copy dialog field values
|
/** returns all confirmed move and copy dialog field values
|
||||||
* <li> the board, swimlane and list id is stored for each board
|
* <li> the board, swimlane and list id is stored for each board
|
||||||
*/
|
*/
|
||||||
|
|
@ -1032,6 +1078,144 @@ Users.helpers({
|
||||||
_id: this._id,
|
_id: this._id,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getListWidthFromStorage(boardId, listId) {
|
||||||
|
// For logged-in users, get from profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.getListWidth(boardId, listId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, get from localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-list-widths');
|
||||||
|
if (stored) {
|
||||||
|
const widths = JSON.parse(stored);
|
||||||
|
if (widths[boardId] && widths[boardId][listId]) {
|
||||||
|
return widths[boardId][listId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error reading list widths from localStorage:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 270; // Return default width instead of -1
|
||||||
|
},
|
||||||
|
|
||||||
|
setListWidthToStorage(boardId, listId, width) {
|
||||||
|
// For logged-in users, save to profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.setListWidth(boardId, listId, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, save to localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-list-widths');
|
||||||
|
let widths = stored ? JSON.parse(stored) : {};
|
||||||
|
|
||||||
|
if (!widths[boardId]) {
|
||||||
|
widths[boardId] = {};
|
||||||
|
}
|
||||||
|
widths[boardId][listId] = width;
|
||||||
|
|
||||||
|
localStorage.setItem('wekan-list-widths', JSON.stringify(widths));
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error saving list width to localStorage:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getListConstraintFromStorage(boardId, listId) {
|
||||||
|
// For logged-in users, get from profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.getListConstraint(boardId, listId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, get from localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-list-constraints');
|
||||||
|
if (stored) {
|
||||||
|
const constraints = JSON.parse(stored);
|
||||||
|
if (constraints[boardId] && constraints[boardId][listId]) {
|
||||||
|
return constraints[boardId][listId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error reading list constraints from localStorage:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 550; // Return default constraint instead of -1
|
||||||
|
},
|
||||||
|
|
||||||
|
setListConstraintToStorage(boardId, listId, constraint) {
|
||||||
|
// For logged-in users, save to profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.setListConstraint(boardId, listId, constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, save to localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-list-constraints');
|
||||||
|
let constraints = stored ? JSON.parse(stored) : {};
|
||||||
|
|
||||||
|
if (!constraints[boardId]) {
|
||||||
|
constraints[boardId] = {};
|
||||||
|
}
|
||||||
|
constraints[boardId][listId] = constraint;
|
||||||
|
|
||||||
|
localStorage.setItem('wekan-list-constraints', JSON.stringify(constraints));
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error saving list constraint to localStorage:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSwimlaneHeightFromStorage(boardId, swimlaneId) {
|
||||||
|
// For logged-in users, get from profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.getSwimlaneHeight(boardId, swimlaneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, get from localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-swimlane-heights');
|
||||||
|
if (stored) {
|
||||||
|
const heights = JSON.parse(stored);
|
||||||
|
if (heights[boardId] && heights[boardId][swimlaneId]) {
|
||||||
|
return heights[boardId][swimlaneId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error reading swimlane heights from localStorage:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; // Return -1 if not found
|
||||||
|
},
|
||||||
|
|
||||||
|
setSwimlaneHeightToStorage(boardId, swimlaneId, height) {
|
||||||
|
// For logged-in users, save to profile
|
||||||
|
if (this._id) {
|
||||||
|
return this.setSwimlaneHeight(boardId, swimlaneId, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-logged-in users, save to localStorage
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('wekan-swimlane-heights');
|
||||||
|
let heights = stored ? JSON.parse(stored) : {};
|
||||||
|
|
||||||
|
if (!heights[boardId]) {
|
||||||
|
heights[boardId] = {};
|
||||||
|
}
|
||||||
|
heights[boardId][swimlaneId] = height;
|
||||||
|
|
||||||
|
localStorage.setItem('wekan-swimlane-heights', JSON.stringify(heights));
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error saving swimlane height to localStorage:', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Users.mutations({
|
Users.mutations({
|
||||||
|
|
@ -1429,6 +1613,24 @@ Meteor.methods({
|
||||||
const user = ReactiveCache.getCurrentUser();
|
const user = ReactiveCache.getCurrentUser();
|
||||||
user.setSwimlaneHeight(boardId, swimlaneId, height);
|
user.setSwimlaneHeight(boardId, swimlaneId, height);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
applySwimlaneHeightToStorage(boardId, swimlaneId, height) {
|
||||||
|
check(boardId, String);
|
||||||
|
check(swimlaneId, String);
|
||||||
|
check(height, Number);
|
||||||
|
const user = ReactiveCache.getCurrentUser();
|
||||||
|
user.setSwimlaneHeightToStorage(boardId, swimlaneId, height);
|
||||||
|
},
|
||||||
|
|
||||||
|
applyListWidthToStorage(boardId, listId, width, constraint) {
|
||||||
|
check(boardId, String);
|
||||||
|
check(listId, String);
|
||||||
|
check(width, Number);
|
||||||
|
check(constraint, Number);
|
||||||
|
const user = ReactiveCache.getCurrentUser();
|
||||||
|
user.setListWidthToStorage(boardId, listId, width);
|
||||||
|
user.setListConstraintToStorage(boardId, listId, constraint);
|
||||||
|
},
|
||||||
setZoomLevel(level) {
|
setZoomLevel(level) {
|
||||||
check(level, Number);
|
check(level, Number);
|
||||||
const user = ReactiveCache.getCurrentUser();
|
const user = ReactiveCache.getCurrentUser();
|
||||||
|
|
|
||||||
7
package-lock.json
generated
7
package-lock.json
generated
|
|
@ -137,7 +137,7 @@
|
||||||
"from": "git+https://github.com/wekan/dragscroll.git"
|
"from": "git+https://github.com/wekan/dragscroll.git"
|
||||||
},
|
},
|
||||||
"@wekanteam/exceljs": {
|
"@wekanteam/exceljs": {
|
||||||
"version": "git+https://github.com/wekan/exceljs.git#7d182abf83ddfb1a8f5a9592a0fdf60ef72f6686",
|
"version": "git+https://github.com/wekan/exceljs.git#e0229907e7a81bc3fe6daf4e42b1fdfbecdcb7cb",
|
||||||
"from": "git+https://github.com/wekan/exceljs.git",
|
"from": "git+https://github.com/wekan/exceljs.git",
|
||||||
"requires": {
|
"requires": {
|
||||||
"archiver": "^5.0.0",
|
"archiver": "^5.0.0",
|
||||||
|
|
@ -2517,11 +2517,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
|
||||||
},
|
},
|
||||||
"moment": {
|
|
||||||
"version": "2.30.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
|
||||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="
|
|
||||||
},
|
|
||||||
"mongo-object": {
|
"mongo-object": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mongo-object/-/mongo-object-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/mongo-object/-/mongo-object-3.0.1.tgz",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue