Resolve merge conflicts by accepting PR #6131 changes

Co-authored-by: xet7 <15545+xet7@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-02-07 16:30:08 +00:00
parent dc0b68ee80
commit 97dd5d2064
257 changed files with 9483 additions and 14103 deletions

View file

@ -1,7 +1,7 @@
template(name="archivedBoards")
h2
span(title="{{_ 'archived-boards'}}")
i.fa.fa-archive
i.fa.fa-archive
| {{_ 'archived-boards'}}
ul.archived-lists

View file

@ -1,43 +1,25 @@
.swim-flex {
display: flex;
flex: 1;
flex-direction: column;
align-items: stretch;
padding-bottom: 40vw;
}
.board-wrapper {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow-x: hidden;
overflow-y: hidden;
width: 100%;
min-width: 100%;
display: flex;
flex: 1;
overflow: auto;
}
/* When zoom is 50% or lower, ensure full width like content */
.board-wrapper[style*="transform: scale(0.5)"] {
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
}
.board-wrapper[style*="transform: scale(0.4)"] {
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
}
.board-wrapper[style*="transform: scale(0.3)"] {
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
}
.board-wrapper .board-canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
transition: margin 0.1s;
overflow-y: auto;
width: 100%;
min-width: 100%;
overflow-x: hidden;
display: flex;
/* don't stretch vertically if not needed (e.g collapsed) */
align-self: start;
flex: 1;
}
/* Ensure horizontal scrollbar is visible for high zoom levels */
@ -97,172 +79,12 @@
position: relative;
}
#content[style*="overflow-x: auto"]::-webkit-scrollbar {
height: 12px;
width: 12px;
/* Force vertical scrollbar to always be visible */
#content[style*="overflow-y: auto"] {
overflow-y: scroll !important;
}
/* Force vertical scrollbar to always be visible */
#content[style*="overflow-y: auto"] {
overflow-y: scroll !important;
}
/* Mobile - make all text 2x bigger inside #content by default (icons stay same size) */
@media screen and (max-width: 800px),
screen and (max-device-width: 800px),
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
screen and (max-width: 800px) and (orientation: portrait),
screen and (max-width: 800px) and (orientation: landscape) {
#content {
font-size: 2em !important; /* 2x bigger base font size for content area */
}
/* Make all text elements 2x bigger */
#content h1, #content h2, #content h3, #content h4, #content h5, #content h6,
#content p, #content span, #content div, #content a, #content button,
#content .minicard, #content .list-header-name, #content .board-header-btn,
#content .card-title, #content .card-details, #content .card-description,
#content .swimlane-header, #content .list-title, #content .card-text,
#content .member, #content .member-name, #content .member-initials,
#content .checklist-item, #content .checklist-title, #content .comment,
#content .activity, #content .activity-text, #content .activity-time,
#content .board-title, #content .board-description, #content .list-name,
#content .card-text, #content .card-title, #content .card-description,
#content .swimlane-title, #content .swimlane-description,
#content .board-header-title, #content .board-header-description,
#content .card-detail-title, #content .card-detail-description,
#content .list-header-title, #content .list-header-description,
#content .swimlane-header-title, #content .swimlane-header-description,
#content .minicard-title, #content .minicard-description,
#content .card-comment, #content .card-comment-text,
#content .checklist-item-text, #content .checklist-item-title,
#content .activity-item, #content .activity-item-text,
#content .board-member, #content .board-member-name,
#content .team-member, #content .team-member-name,
#content .org-member, #content .org-member-name,
#content .template-member, #content .template-member-name,
#content .user-name, #content .user-email, #content .user-role,
#content .setting-title, #content .setting-description,
#content .popup-title, #content .popup-description,
#content .modal-title, #content .modal-description,
#content .notification-title, #content .notification-text,
#content .announcement-title, #content .announcement-text,
#content .offline-warning-title, #content .offline-warning-text,
#content .error-title, #content .error-text,
#content .success-title, #content .success-text,
#content .info-title, #content .info-text,
#content .warning-title, #content .warning-text {
font-size: 1em !important; /* Use inherited 2x scaling */
}
/* Keep icons the same size (don't scale them) */
#content .fa, #content .icon, #content i {
font-size: 1em !important; /* Keep original icon size */
}
/* Reset specific icon sizes to prevent double scaling */
#content .fa-home, #content .fa-bars, #content .fa-search,
#content .fa-bell, #content .fa-user, #content .fa-cog,
#content .fa-plus, #content .fa-minus, #content .fa-edit,
#content .fa-trash, #content .fa-save, #content .fa-cancel,
#content .fa-arrow-left, #content .fa-arrow-right,
#content .fa-arrow-up, #content .fa-arrow-down,
#content .fa-check, #content .fa-times, #content .fa-close,
#content .fa-star, #content .fa-heart, #content .fa-thumbs-up,
#content .fa-thumbs-down, #content .fa-comment, #content .fa-reply,
#content .fa-share, #content .fa-download, #content .fa-upload,
#content .fa-copy, #content .fa-paste, #content .fa-cut,
#content .fa-undo, #content .fa-redo, #content .fa-refresh,
#content .fa-sync, #content .fa-spinner, #content .fa-loading,
#content .fa-info, #content .fa-question, #content .fa-exclamation,
#content .fa-warning, #content .fa-error, #content .fa-success,
#content .fa-check-circle, #content .fa-times-circle,
#content .fa-exclamation-circle, #content .fa-question-circle,
#content .fa-info-circle, #content .fa-warning-circle,
#content .fa-error-circle, #content .fa-success-circle {
font-size: 1em !important; /* Keep original icon size */
}
}
/* Fallback for iPhone devices using JavaScript detection */
.iphone-device #content {
font-size: 2em !important; /* 2x bigger base font size for content area */
}
.iphone-device #content h1, .iphone-device #content h2, .iphone-device #content h3, .iphone-device #content h4, .iphone-device #content h5, .iphone-device #content h6,
.iphone-device #content p, .iphone-device #content span, .iphone-device #content div, .iphone-device #content a, .iphone-device #content button,
.iphone-device #content .minicard, .iphone-device #content .list-header-name, .iphone-device #content .board-header-btn,
.iphone-device #content .card-title, .iphone-device #content .card-details, .iphone-device #content .card-description,
.iphone-device #content .swimlane-header, .iphone-device #content .list-title, .iphone-device #content .card-text,
.iphone-device #content .member, .iphone-device #content .member-name, .iphone-device #content .member-initials,
.iphone-device #content .checklist-item, .iphone-device #content .checklist-title, .iphone-device #content .comment,
.iphone-device #content .activity, .iphone-device #content .activity-text, .iphone-device #content .activity-time,
.iphone-device #content .board-title, .iphone-device #content .board-description, .iphone-device #content .list-name,
.iphone-device #content .card-text, .iphone-device #content .card-title, .iphone-device #content .card-description,
.iphone-device #content .swimlane-title, .iphone-device #content .swimlane-description,
.iphone-device #content .board-header-title, .iphone-device #content .board-header-description,
.iphone-device #content .card-detail-title, .iphone-device #content .card-detail-description,
.iphone-device #content .list-header-title, .iphone-device #content .list-header-description,
.iphone-device #content .swimlane-header-title, .iphone-device #content .swimlane-header-description,
.iphone-device #content .minicard-title, .iphone-device #content .minicard-description,
.iphone-device #content .card-comment, .iphone-device #content .card-comment-text,
.iphone-device #content .checklist-item-text, .iphone-device #content .checklist-item-title,
.iphone-device #content .activity-item, .iphone-device #content .activity-item-text,
.iphone-device #content .board-member, .iphone-device #content .board-member-name,
.iphone-device #content .team-member, .iphone-device #content .team-member-name,
.iphone-device #content .org-member, .iphone-device #content .org-member-name,
.iphone-device #content .template-member, .iphone-device #content .template-member-name,
.iphone-device #content .user-name, .iphone-device #content .user-email, .iphone-device #content .user-role,
.iphone-device #content .setting-title, .iphone-device #content .setting-description,
.iphone-device #content .popup-title, .iphone-device #content .popup-description,
.iphone-device #content .modal-title, .iphone-device #content .modal-description,
.iphone-device #content .notification-title, .iphone-device #content .notification-text,
.iphone-device #content .announcement-title, .iphone-device #content .announcement-text,
.iphone-device #content .offline-warning-title, .iphone-device #content .offline-warning-text,
.iphone-device #content .error-title, .iphone-device #content .error-text,
.iphone-device #content .success-title, .iphone-device #content .success-text,
.iphone-device #content .info-title, .iphone-device #content .info-text,
.iphone-device #content .warning-title, .iphone-device #content .warning-text {
font-size: 1em !important; /* Use inherited 2x scaling */
}
/* Keep icons the same size for iPhone devices */
.iphone-device #content .fa, .iphone-device #content .icon, .iphone-device #content i {
font-size: 1em !important; /* Keep original icon size */
}
/* Mobile iPhone: scale card details text and icons to 2x */
body.mobile-mode.iphone-device .card-details {
font-size: 2em !important;
}
body.mobile-mode.iphone-device .card-details .fa,
body.mobile-mode.iphone-device .card-details .icon,
body.mobile-mode.iphone-device .card-details i,
body.mobile-mode.iphone-device .card-details .emoji-icon,
body.mobile-mode.iphone-device .card-details a,
body.mobile-mode.iphone-device .card-details p,
body.mobile-mode.iphone-device .card-details span,
body.mobile-mode.iphone-device .card-details div,
body.mobile-mode.iphone-device .card-details button,
body.mobile-mode.iphone-device .card-details input,
body.mobile-mode.iphone-device .card-details select,
body.mobile-mode.iphone-device .card-details textarea {
font-size: inherit !important;
}
/* Section titles slightly larger than content but not as big as card title */
body.mobile-mode.iphone-device .card-details .card-details-item-title {
font-size: 1.1em !important;
font-weight: bold;
}
/* Ensure scrollbars are positioned correctly */
#content[style*="overflow-x: auto"]::-webkit-scrollbar:vertical {
width: 12px;
}
#content[style*="overflow-x: auto"]::-webkit-scrollbar:horizontal {
height: 12px;
}
/* Force both scrollbars to always be visible for high zoom levels */
#content[style*="overflow-x: auto"][style*="overflow-y: auto"] {
@ -274,36 +96,6 @@ body.mobile-mode.iphone-device .card-details .card-details-item-title {
#content[style*="overflow-y: auto"] {
scrollbar-gutter: stable;
}
.board-wrapper .board-canvas .board-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
top: -100px;
right: -400px;
background: #000;
opacity: 0.33;
animation: fadeIn 0.2s;
z-index: 16;
}
/* Fix for mobile Safari: ensure overlay stays behind card details */
@media screen and (max-width: 800px) {
.board-wrapper .board-canvas .board-overlay {
z-index: 17 !important;
}
/* In desktop mode on small screens, still keep overlay behind card */
body.desktop-mode .board-wrapper .board-canvas .board-overlay {
z-index: 17 !important;
}
}
/* In mobile mode, lower the overlay z-index to stay behind card details */
body.mobile-mode .board-wrapper .board-canvas .board-overlay {
z-index: 17 !important;
}
/* iPhone in desktop mode: remove overlay to avoid blocking card */
body.desktop-mode.iphone-device .board-wrapper .board-canvas .board-overlay {
@ -320,73 +112,14 @@ body.desktop-mode .board-wrapper .board-canvas .board-overlay {
.board-wrapper .board-canvas.is-dragging-active .minicard-wrapper.is-checked {
display: none;
}
/* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */
.board-wrapper.mobile-view {
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important;
right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
}
.board-wrapper.mobile-view .board-canvas {
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important;
right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
}
.board-wrapper.mobile-view .board-canvas.mobile-view .swimlane {
border-bottom: 1px solid #ccc;
display: block !important;
flex-direction: column;
margin: 0;
padding: 0;
overflow-x: hidden !important;
overflow-y: auto;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
}
@media screen and (max-width: 800px),
screen and (max-device-width: 932px) and (-webkit-min-device-pixel-ratio: 3) {
.board-wrapper {
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important;
right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
}
.board-wrapper .board-canvas {
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important;
right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
}
.board-wrapper .board-canvas .swimlane {
border-bottom: 1px solid #ccc;
display: block !important;
flex-direction: column;
margin: 0;
padding: 0;
overflow-x: hidden !important;
overflow-y: auto;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
.board-wrapper .board-canvas .swimlane {
/* this effectively prevents board
to shrink */
min-width: 100vw;
}
}
.calendar-event-green {
@ -545,7 +278,6 @@ body.desktop-mode .board-wrapper .board-canvas .board-overlay {
justify-content: center;
align-items: center;
margin: 0;
font-size: 18px;
}
.modal-footer {
display: flex;
@ -558,10 +290,6 @@ body.desktop-mode .board-wrapper .board-canvas .board-overlay {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 5px;
right: 5px;
font-size: 25px;
cursor: pointer;
}

View file

@ -1,13 +1,9 @@
template(name="board")
if isConverting.get
+boardConversionProgress
else if isBoardReady.get
if currentBoard
if onlyShowCurrentCard
+cardDetails(currentCard)
else
+boardBody
+boardBody
else
//-- XXX We need a better error message in case the board has been archived
+message(label="board-not-found")
@ -17,32 +13,32 @@ template(name="board")
template(name="boardBody")
if notDisplayThisBoard
| {{_ 'tableVisibilityMode-allowPrivateOnly'}}
| {{_ 'tableVisibilityMode-allowPrivateOnly'}}
else
// Debug information (remove in production)
//- Debug information (remove in production)
if debugBoardState
//- Debug information (remove in production)
.debug-info(style="position: fixed; top: 0; left: 0; background: rgba(0,0,0,0.8); color: white; padding: 10px; z-index: 9999; font-size: 12px;")
| {{_ 'board'}}: {{currentBoard.title}} | {{_ 'view'}}: {{boardView}} | {{_ 'has-swimlanes'}}: {{hasSwimlanes}} | {{_ 'swimlanes'}}: {{currentBoard.swimlanes.length}}
.board-wrapper(class=currentBoard.colorClass class="{{#if isMiniScreen}}mobile-view{{/if}}")
.board-canvas.js-swimlanes(
class="{{#if hasSwimlanes}}dragscroll{{/if}}"
class="{{#if Sidebar.isOpen}}is-sibling-sidebar-open{{/if}}"
class="{{#if MultiSelection.isActive}}is-multiselection-active{{/if}}"
class="{{#if draggingActive.get}}is-dragging-active{{/if}}"
class="{{#unless isVerticalScrollbars}}no-scrollbars{{/unless}}"
class="{{#if isMiniScreen}}mobile-view{{/if}}")
if showOverlay.get
.board-overlay
if currentBoard.isTemplatesBoard
each currentBoard.swimlanes
+swimlane(this)
else if isViewSwimlanes
if hasSwimlanes
.swim-flex
each currentBoard.swimlanes
+swimlane(this)
else
// Fallback: If no swimlanes exist, show lists instead of empty message
+listsGroup(currentBoard)
else if isViewSwimlanes
.swim-flex
if hasSwimlanes
each currentBoard.swimlanes
+swimlane(this)
else
// Fallback: If no swimlanes exist, show lists instead of empty message
+listsGroup(currentBoard)
else if isViewLists
+listsGroup(currentBoard)
else if isViewCalendar
@ -56,10 +52,6 @@ template(name="boardBody")
+swimlane(this)
else
+listsGroup(currentBoard)
//- Render multiple open cards in desktop mode
unless isMiniScreen
each openCards
+cardDetails(this cardIndex=@index)
+sidebar
template(name="calendarView")

View file

@ -27,16 +27,16 @@ BlazeComponent.extendComponent({
this.autorun(() => {
const currentBoardId = Session.get('currentBoard');
if (!currentBoardId) return;
const handle = subManager.subscribe('board', currentBoardId, false);
// Use a separate autorun for subscription ready state to avoid reactive loops
this.subscriptionReadyAutorun = Tracker.autorun(() => {
if (handle.ready()) {
if (!this._boardProcessed || this._lastProcessedBoardId !== currentBoardId) {
this._boardProcessed = true;
this._lastProcessedBoardId = currentBoardId;
// Ensure default swimlane exists (only once per board)
this.ensureDefaultSwimlane(currentBoardId);
// Check if board needs conversion
@ -67,7 +67,7 @@ BlazeComponent.extendComponent({
if (!board) return;
const swimlanes = board.swimlanes();
if (swimlanes.length === 0) {
// Check if any swimlane exists in the database to avoid race conditions
const existingSwimlanes = ReactiveCache.getSwimlanes({ boardId });
@ -105,7 +105,6 @@ BlazeComponent.extendComponent({
this.isBoardReady.set(true); // Show board even if conversion check failed
}
},
onlyShowCurrentCard() {
const isMiniScreen = Utils.isMiniScreen();
const currentCardId = Utils.getCurrentCardId(true);
@ -114,7 +113,7 @@ BlazeComponent.extendComponent({
openCards() {
// In desktop mode, return array of all open cards
const isMobile = Utils.getMobileMode();
const isMobile = Utils.isMiniScreen();
if (!isMobile) {
const openCardIds = Session.get('openCards') || [];
return openCardIds.map(id => ReactiveCache.getCard(id)).filter(card => card);
@ -123,7 +122,7 @@ BlazeComponent.extendComponent({
},
goHome() {
FlowRouter.go('home');
FlowRouter.go('home')
},
isConverting() {
@ -195,7 +194,7 @@ BlazeComponent.extendComponent({
}
},
onRendered() {
// Initialize user settings (zoom and mobile mode)
// Initialize user settings (mobile mode)
Utils.initializeUserSettings();
// Detect iPhone devices and add class for better CSS targeting
@ -221,9 +220,9 @@ BlazeComponent.extendComponent({
const popupObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1 &&
if (node.nodeType === 1 &&
(node.classList.contains('popup') || node.classList.contains('modal') || node.classList.contains('menu')) &&
!node.closest('.js-swimlanes') &&
!node.closest('.js-swimlanes') &&
!node.closest('.swimlane') &&
!node.closest('.list') &&
!node.closest('.minicard')) {
@ -391,23 +390,24 @@ BlazeComponent.extendComponent({
helper(evt, item) {
const helper = $(`<div class="swimlane"
style="flex-direction: column;
height: ${swimlaneWhileSortingHeight}px;
width: $(boardComponent.width)px;
overflow: hidden;"/>`);
max-height: 30vh;
width: 100vw;
overflow: hidden; z-index: 100;"/>`);
helper.append(item.clone());
// Also grab the list of lists of cards
const list = item.next();
helper.append(list.clone());
return helper;
},
items: '.swimlane:not(.placeholder)',
items: '.swimlane-container',
placeholder: 'swimlane placeholder',
distance: 7,
start(evt, ui) {
const listDom = ui.placeholder.next('.js-swimlane');
const parentOffset = ui.item.parent().offset();
ui.placeholder.height(ui.helper.height());
height = ui.helper.height();
ui.placeholder[0].setAttribute('style', `height: ${height}px !important;`);
EscapeActions.executeUpTo('popup-close');
listDom.addClass('moving-swimlane');
boardComponent.setIsDragging(true);
@ -415,40 +415,19 @@ BlazeComponent.extendComponent({
ui.placeholder.insertAfter(ui.placeholder.next());
boardComponent.origPlaceholderIndex = ui.placeholder.index();
// resize all swimlanes + headers to be a total of 150 px per row
// this could be achieved by setIsDragging(true) but we want immediate
// result
ui.item
.siblings('.js-swimlane')
.css('height', `${swimlaneWhileSortingHeight - 26}px`);
// set the new scroll height after the resize and insertion of
// the placeholder. We want the element under the cursor to stay
// at the same place on the screen
ui.item.parent().get(0).scrollTop =
ui.placeholder.get(0).offsetTop + parentOffset.top - evt.pageY;
},
beforeStop(evt, ui) {
const parentOffset = ui.item.parent().offset();
const siblings = ui.item.siblings('.js-swimlane');
siblings.css('height', '');
// compute the new scroll height after the resize and removal of
// the placeholder
const scrollTop =
ui.placeholder.get(0).offsetTop + parentOffset.top - evt.pageY;
// then reset the original view of the swimlane
siblings.removeClass('moving-swimlane');
// and apply the computed scrollheight
ui.item.parent().get(0).scrollTop = scrollTop;
},
stop(evt, ui) {
// To attribute the new index number, we need to get the DOM element
// of the previous and the following card -- if any.
const prevSwimlaneDom = ui.item.prevAll('.js-swimlane').get(0);
const nextSwimlaneDom = ui.item.nextAll('.js-swimlane').get(0);
const prevSwimlaneDom = ui.item.prevAll('.swimlane-container').get(0);
const nextSwimlaneDom = ui.item.nextAll('.swimlane-container').get(0);
const sortIndex = calculateIndex(prevSwimlaneDom, nextSwimlaneDom, 1);
$swimlanesDom.sortable('cancel');
@ -464,39 +443,7 @@ BlazeComponent.extendComponent({
boardComponent.setIsDragging(false);
},
sort(evt, ui) {
// get the mouse position in the sortable
const parentOffset = ui.item.parent().offset();
const cursorY =
evt.pageY - parentOffset.top + ui.item.parent().scrollTop();
// compute the intended index of the placeholder (we need to skip the
// slots between the headers and the list of cards)
const newplaceholderIndex = Math.floor(
cursorY / swimlaneWhileSortingHeight,
);
let destPlaceholderIndex = (newplaceholderIndex + 1) * 2;
// if we are scrolling far away from the bottom of the list
if (destPlaceholderIndex >= ui.item.parent().get(0).childElementCount) {
destPlaceholderIndex = ui.item.parent().get(0).childElementCount - 1;
}
// update the placeholder position in the DOM tree
if (destPlaceholderIndex !== ui.placeholder.index()) {
if (destPlaceholderIndex < boardComponent.origPlaceholderIndex) {
ui.placeholder.insertBefore(
ui.placeholder
.siblings()
.slice(destPlaceholderIndex - 2, destPlaceholderIndex - 1),
);
} else {
ui.placeholder.insertAfter(
ui.placeholder
.siblings()
.slice(destPlaceholderIndex - 1, destPlaceholderIndex),
);
}
}
Utils.scrollIfNeeded(evt);
},
});
@ -505,10 +452,10 @@ BlazeComponent.extendComponent({
dragscroll.reset();
if ($swimlanesDom.data('uiSortable') || $swimlanesDom.data('sortable')) {
if (Utils.isTouchScreenOrShowDesktopDragHandles()) {
if (Utils.isMiniScreen()) {
$swimlanesDom.sortable('option', 'handle', '.js-swimlane-header-handle');
} else {
$swimlanesDom.sortable('option', 'handle', '.swimlane-header');
$swimlanesDom.sortable('option', 'handle', '.swimlane-header-wrap');
}
// Disable drag-dropping if the current user is not a board member
@ -540,57 +487,57 @@ BlazeComponent.extendComponent({
isViewSwimlanes() {
const currentUser = ReactiveCache.getCurrentUser();
let boardView;
if (currentUser) {
boardView = (currentUser.profile || {}).boardView;
} else {
boardView = window.localStorage.getItem('boardView');
}
// If no board view is set, default to swimlanes
if (!boardView) {
boardView = 'board-view-swimlanes';
}
return boardView === 'board-view-swimlanes';
},
isViewLists() {
const currentUser = ReactiveCache.getCurrentUser();
let boardView;
if (currentUser) {
boardView = (currentUser.profile || {}).boardView;
} else {
boardView = window.localStorage.getItem('boardView');
}
return boardView === 'board-view-lists';
},
isViewCalendar() {
const currentUser = ReactiveCache.getCurrentUser();
let boardView;
if (currentUser) {
boardView = (currentUser.profile || {}).boardView;
} else {
boardView = window.localStorage.getItem('boardView');
}
return boardView === 'board-view-cal';
},
isViewGantt() {
const currentUser = ReactiveCache.getCurrentUser();
let boardView;
if (currentUser) {
boardView = (currentUser.profile || {}).boardView;
} else {
boardView = window.localStorage.getItem('boardView');
}
return boardView === 'board-view-gantt';
},
@ -602,7 +549,7 @@ BlazeComponent.extendComponent({
}
return false;
}
try {
const swimlanes = currentBoard.swimlanes();
const hasSwimlanes = swimlanes && swimlanes.length > 0;
@ -638,7 +585,7 @@ BlazeComponent.extendComponent({
const isBoardReady = this.isBoardReady.get();
const isConverting = this.isConverting.get();
const boardView = Utils.boardView();
if (process.env.DEBUG === 'true') {
console.log('=== BOARD DEBUG STATE ===');
console.log('currentBoardId:', currentBoardId);
@ -648,7 +595,7 @@ BlazeComponent.extendComponent({
console.log('boardView:', boardView);
console.log('========================');
}
return {
currentBoardId,
hasCurrentBoard: !!currentBoard,
@ -1025,4 +972,3 @@ BlazeComponent.extendComponent({
* Gantt View Component
* Displays cards as a Gantt chart with start/due dates
*/

File diff suppressed because it is too large Load diff

View file

@ -22,918 +22,90 @@
padding: 0.7vh 0.7vw;
}
/* Zoom and Mobile Mode Controls */
.board-header-btns.center {
.board-header {
display: grid;
flex: 1;
gap: 0.3lh;
}
body {
&.mobile-mode {
.board-header {
flex-wrap: wrap;
}
}
&:not(.mobile-mode) {
.header-board-menu {
flex: 1;
}
.board-header {
justify-content: space-between;
grid-auto-flow: column;
}
.board-header-btns-left {
flex: 1;
justify-content: center;
}
.board-header-btns-right {
flex-grow: 0;
justify-content: end;
}
& .board-header-btns-right,
& .board-header-btns-left,
& .header-board-menu {
align-self: center;
align-items: center;
display: flex;
gap: 1.5ch;
overflow-wrap: normal;
}
}
}
/* Make some space on intermediate layouts */
@media screen and (max-width: 1200px) {
.board-header-btns-right span {
display: none !important;
}
}
.header-board-menu, .board-header-btns {
display: flex;
align-self: center;
align-items: center;
justify-content: center;
flex: 1;
gap: 1ch;
& p {
margin: 0;
}
}
.zoom-controls {
.board-header-btns-right > a {
flex-wrap: no-wrap;
}
body.mobile-mode {
header-board-menu h1 {
font-size: 2em;
}
.board-header-btn {
/* avoid wrapping if possible, at the cost of little icons */
font-size: 0.5em;
/* no much choice because the way FA icons are inserted */
padding-top: 0.1lh;
min-height: 0.8lh;
}
.board-header-btns-right {
display: grid;
grid-auto-flow: column;
grid-template-columns: repeat(auto-fit, 1fr);
flex: 1;
gap: 1ch;
justify-content: start;
align-items: center;
}
}
.board-header-btns-left {
display: flex;
align-items: center;
gap: 0.5vw;
background: rgba(255, 255, 255, 0.9);
padding: 0.5vh 1vw;
border-radius: 0.5vw;
box-shadow: 0 0.2vh 0.5vh rgba(0,0,0,0.1);
}
.zoom-controls .board-header-btn {
padding: 0.5vh 0.8vw !important;
border-radius: 0.3vw !important;
background: #fff !important;
border: 1px solid #000 !important;
transition: all 0.2s ease !important;
color: #000 !important;
height: auto !important;
line-height: normal !important;
margin: 0 !important;
float: none !important;
overflow: visible !important;
}
.zoom-controls .board-header-btn i {
color: #000 !important;
float: none !important;
display: inline !important;
line-height: normal !important;
margin: 0 !important;
}
.zoom-controls .board-header-btn:hover {
background: #000 !important;
border-color: #000 !important;
color: #fff !important;
}
.zoom-controls .board-header-btn:hover i {
color: #fff !important;
}
.zoom-controls .board-header-btn.is-active {
background: #0079bf;
color: white;
border-color: #005a8a;
}
.zoom-controls .board-header-btn.is-active i {
color: white;
}
.zoom-level {
font-weight: bold;
color: #333;
min-width: 3vw;
text-align: center;
font-size: clamp(12px, 2vw, 14px);
cursor: pointer;
padding: 0.3vh 0.5vw;
border-radius: 0.3vw;
transition: all 0.2s ease;
}
.zoom-level:hover {
background: #f0f0f0;
color: #000;
}
/* Mobile Mode Styles */
.mobile-mode .board-wrapper {
width: 100%;
height: 100%;
}
.mobile-mode .board-canvas {
height: 100%;
}
.mobile-mode .minicard {
font-size: clamp(16px, 4vw, 20px);
padding: 1.2vh 1.5vw 0.5vh;
min-height: 3vh;
}
.mobile-mode .list-header-name {
font-size: clamp(18px, 4.5vw, 24px);
}
.mobile-mode .board-header-btn {
padding: 1vh 1.5vw;
font-size: clamp(14px, 3.5vw, 18px);
}
.mobile-mode .zoom-controls {
padding: 1vh 1.5vw;
gap: 1vw;
}
.mobile-mode .zoom-controls .board-header-btn {
padding: 1vh 1.5vw !important;
font-size: clamp(14px, 3.5vw, 18px) !important;
background: #fff !important;
border: 1px solid #000 !important;
color: #000 !important;
height: auto !important;
line-height: normal !important;
margin: 0 !important;
float: none !important;
overflow: visible !important;
}
.mobile-mode .zoom-controls .board-header-btn i {
color: #000 !important;
float: none !important;
display: inline !important;
line-height: normal !important;
margin: 0 !important;
}
.mobile-mode .zoom-controls .board-header-btn:hover {
background: #000 !important;
border-color: #000 !important;
color: #fff !important;
}
.mobile-mode .zoom-controls .board-header-btn:hover i {
color: #fff !important;
}
.mobile-mode .zoom-level {
font-size: clamp(14px, 3.5vw, 18px);
min-width: 4vw;
}
/* Comprehensive Mobile Mode Styles - Works on all screen sizes */
.mobile-mode .board-wrapper {
width: 100% !important;
height: 100% !important;
transform: none !important;
transform-origin: initial !important;
max-width: 100% !important;
}
.mobile-mode .board-canvas {
height: 100% !important;
overflow-x: hidden !important;
overflow-y: auto !important;
width: 100% !important;
max-width: 100% !important;
}
.mobile-mode .swimlane {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
margin-bottom: 2rem !important;
display: block !important;
float: none !important;
}
.mobile-mode .swimlane-header {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
font-size: clamp(18px, 2.5vw, 32px) !important;
padding: 1rem !important;
margin-bottom: 1rem !important;
display: block !important;
}
.mobile-mode .list {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
display: block !important;
float: none !important;
margin-bottom: 2rem !important;
border-left: none !important;
border-bottom: 2px solid #ccc !important;
clear: both !important;
}
.mobile-mode .list-header {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
padding: 1rem !important;
font-size: clamp(18px, 2.5vw, 32px) !important;
display: grid !important;
grid-template-columns: 30px 1fr auto auto !important;
gap: 10px !important;
align-items: center !important;
position: relative !important;
}
.mobile-mode .list-header .list-header-name {
font-size: clamp(18px, 2.5vw, 32px) !important;
font-weight: bold !important;
grid-row: 1 !important;
grid-column: 2 !important;
align-self: end !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .list-header .cardCount {
font-size: clamp(14px, 2vw, 24px) !important;
grid-row: 2 !important;
grid-column: 2 !important;
align-self: start !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .list-header .list-header-menu-icon {
position: static !important;
right: auto !important;
top: auto !important;
transform: none !important;
grid-row: 1/3 !important;
grid-column: 3 !important;
padding: 14px !important;
font-size: clamp(24px, 3vw, 48px) !important;
text-align: center !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .list-header .list-header-handle {
position: static !important;
right: auto !important;
top: auto !important;
transform: none !important;
grid-row: 1/3 !important;
grid-column: 4 !important;
padding: 14px !important;
font-size: clamp(28px, 3.5vw, 56px) !important;
text-align: center !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .list-body {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
padding: 1rem !important;
display: block !important;
}
.mobile-mode .minicard {
width: 100% !important;
min-width: 100% !important;
max-width: 100% !important;
font-size: clamp(16px, 2vw, 24px) !important;
padding: 1.2vh 1.5vw 0.5vh !important;
min-height: 3vh !important;
margin-bottom: 0.5rem !important;
display: block !important;
float: none !important;
}
.mobile-mode .minicard .minicard-title {
font-size: clamp(16px, 2vw, 24px) !important;
font-weight: bold !important;
}
.mobile-mode .minicard .minicard-members {
font-size: clamp(12px, 1.5vw, 18px) !important;
}
.mobile-mode .minicard .minicard-lists {
font-size: clamp(12px, 1.5vw, 18px) !important;
}
/* Desktop Mode Styles */
.desktop-mode .board-wrapper {
width: auto !important;
height: auto !important;
}
.desktop-mode .swimlane {
width: auto !important;
min-width: auto !important;
}
.desktop-mode .list {
width: auto !important;
min-width: auto !important;
display: flex !important;
float: left !important;
margin-bottom: 0 !important;
border-left: 1px solid #ccc !important;
border-bottom: none !important;
}
.desktop-mode .list-header {
width: auto !important;
min-width: auto !important;
padding: 2.5vh 1.5vw 0.5vh !important;
font-size: clamp(14px, 3vw, 18px) !important;
display: block !important;
}
.desktop-mode .list-header .list-header-name {
font-size: clamp(14px, 3vw, 18px) !important;
display: inline !important;
grid-row: auto !important;
grid-column: auto !important;
align-self: auto !important;
}
.desktop-mode .list-header .cardCount {
font-size: 12px !important;
grid-row: auto !important;
grid-column: auto !important;
align-self: auto !important;
}
.desktop-mode .list-header .list-header-menu-icon {
position: absolute !important;
right: 60px !important;
top: 50% !important;
transform: translateY(-50%) !important;
grid-row: auto !important;
grid-column: auto !important;
padding: 14px !important;
font-size: 40px !important;
}
.desktop-mode .list-header .list-header-handle {
position: absolute !important;
right: 10px !important;
top: 50% !important;
transform: translateY(-50%) !important;
grid-row: auto !important;
grid-column: auto !important;
padding: 7px !important;
font-size: clamp(16px, 3vw, 20px) !important;
}
.desktop-mode .list-body {
width: auto !important;
min-width: auto !important;
padding: 5px 11px !important;
}
.desktop-mode .minicard {
width: auto !important;
min-width: auto !important;
font-size: clamp(12px, 2.5vw, 16px) !important;
padding: 0.5vh 0.8vw !important;
min-height: auto !important;
margin-bottom: 9px !important;
}
.desktop-mode .minicard .minicard-title {
font-size: clamp(12px, 2.5vw, 16px) !important;
}
.desktop-mode .minicard .minicard-members {
font-size: 10px !important;
}
.desktop-mode .minicard .minicard-lists {
font-size: 10px !important;
}
/* Additional Mobile Mode Styles for Other Elements - Works on all screen sizes */
.mobile-mode .swimlane-header .swimlane-title {
font-size: clamp(18px, 2.5vw, 32px) !important;
font-weight: bold !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .swimlane-header .swimlane-description {
font-size: clamp(14px, 2vw, 24px) !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .board-header {
font-size: clamp(18px, 2.5vw, 32px) !important;
padding: 1rem !important;
width: 100% !important;
max-width: 100% !important;
}
.mobile-mode .board-header .board-header-title {
font-size: clamp(18px, 2.5vw, 32px) !important;
font-weight: bold !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .board-header .board-header-description {
font-size: clamp(14px, 2vw, 24px) !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .board-header .board-header-btn {
font-size: clamp(14px, 2vw, 24px) !important;
padding: 1vh 1.5vw !important;
display: inline-block !important;
visibility: visible !important;
opacity: 1 !important;
}
.mobile-mode .board-header .board-header-btn i {
font-size: clamp(14px, 2vw, 24px) !important;
display: inline !important;
visibility: visible !important;
opacity: 1 !important;
}
/* Force mobile mode visibility on all screen sizes */
.mobile-mode .list-header .fa-angle-right,
.mobile-mode .list-header .fa-arrows {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
position: static !important;
right: auto !important;
top: auto !important;
transform: none !important;
}
.mobile-mode .list-header .fa-angle-right {
grid-row: 1/3 !important;
grid-column: 3 !important;
padding: 14px !important;
font-size: clamp(24px, 3vw, 48px) !important;
text-align: center !important;
}
.mobile-mode .list-header .fa-arrows {
grid-row: 1/3 !important;
grid-column: 4 !important;
padding: 14px !important;
font-size: clamp(28px, 3.5vw, 56px) !important;
text-align: center !important;
}
/* Override any media queries that might hide elements in mobile mode */
.mobile-mode * {
max-width: none !important;
}
.mobile-mode .list,
.mobile-mode .swimlane,
.mobile-mode .board-wrapper,
.mobile-mode .board-canvas {
max-width: 100% !important;
width: 100% !important;
min-width: 100% !important;
}
/* Force mobile mode list styling on all screen sizes - override desktop CSS */
.mobile-mode .board-canvas {
display: block !important;
flex-direction: column !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: flex-start !important;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
overflow-x: hidden !important;
overflow-y: auto !important;
}
.mobile-mode .swimlane {
display: block !important;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
}
.mobile-mode .swimlane .swimlane-header {
display: block !important;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
margin: 0 0 1rem 0 !important;
padding: 1rem !important;
font-size: clamp(18px, 2.5vw, 32px) !important;
font-weight: bold !important;
border-bottom: 2px solid #ccc !important;
}
.mobile-mode .swimlane .lists {
display: block !important;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
margin: 0 !important;
padding: 0 !important;
flex-direction: column !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: flex-start !important;
}
.mobile-mode .list {
display: block !important;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
border-left: none !important;
border-right: none !important;
border-top: none !important;
border-bottom: 2px solid #ccc !important;
flex: none !important;
flex-basis: auto !important;
flex-grow: 0 !important;
flex-shrink: 0 !important;
position: static !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
transform: none !important;
}
.mobile-mode .list:first-child {
margin-left: 0 !important;
margin-top: 0 !important;
}
.mobile-mode .list:last-child {
margin-right: 0 !important;
margin-bottom: 0 !important;
}
.mobile-mode .list.ui-sortable-helper {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
height: auto !important;
min-height: 60px !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
border-left: none !important;
border-right: none !important;
border-top: none !important;
border-bottom: 2px solid #ccc !important;
flex: none !important;
}
.mobile-mode .list.placeholder {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
height: auto !important;
min-height: 60px !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
border-left: none !important;
border-right: none !important;
border-top: none !important;
border-bottom: 2px solid #ccc !important;
flex: none !important;
}
/* Override any existing responsive CSS that might interfere with mobile mode */
.mobile-mode .board-canvas .swimlane .lists {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
margin: 0 !important;
padding: 0 !important;
flex-direction: column !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: flex-start !important;
overflow: visible !important;
}
.mobile-mode .board-canvas .swimlane .lists .list {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
border-left: none !important;
border-right: none !important;
border-top: none !important;
border-bottom: 2px solid #ccc !important;
flex: none !important;
flex-basis: auto !important;
flex-grow: 0 !important;
flex-shrink: 0 !important;
position: static !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
transform: none !important;
}
/* Force mobile mode to override any media query styles */
@media screen and (min-width: 801px) {
.mobile-mode .board-canvas {
display: block !important;
flex-direction: column !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: flex-start !important;
width: 100vw !important;
max-width: 100vw !important;
min-width: 100vw !important;
overflow-x: hidden !important;
overflow-y: auto !important;
}
.mobile-mode .swimlane {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
}
.mobile-mode .swimlane .lists {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
margin: 0 !important;
padding: 0 !important;
flex-direction: column !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
justify-content: flex-start !important;
}
.mobile-mode .list {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 100% !important;
margin: 0 0 2rem 0 !important;
padding: 0 !important;
float: none !important;
clear: both !important;
border-left: none !important;
border-right: none !important;
border-top: none !important;
border-bottom: 2px solid #ccc !important;
flex: none !important;
flex-basis: auto !important;
flex-grow: 0 !important;
flex-shrink: 0 !important;
position: static !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
transform: none !important;
}
}
/* Hide desktop-only elements in mobile mode (like mobile media queries do) */
.mobile-mode .board-header-btn i.fa + span {
display: none !important;
}
.mobile-mode .board-header-btn span {
display: none !important;
}
.mobile-mode .board-header-btn .fa + span {
display: none !important;
}
.mobile-mode .board-header-btn .fa + .board-header-btn-text {
display: none !important;
}
.mobile-mode .board-header-btn .fa + .board-header-btn-label {
display: none !important;
}
/* Show only icons in mobile mode */
.mobile-mode .board-header-btn {
width: auto !important;
min-width: auto !important;
padding: 8px !important;
text-align: center !important;
}
.mobile-mode .board-header-btn i {
display: inline-block !important;
margin: 0 !important;
}
/* Hide desktop-specific elements that shouldn't show in mobile mode */
.mobile-mode .desktop-only,
.mobile-mode .board-header .desktop-only {
display: none !important;
}
.mobile-mode .board-header .board-header-btn.desktop-only {
display: none !important;
}
/* Hide desktop-specific board header buttons in mobile mode */
.mobile-mode .board-header-btns.left {
display: none !important;
}
.mobile-mode .board-header-btns.center {
display: none !important;
}
/* Show only the right section buttons in mobile mode, but hide text labels */
.mobile-mode .board-header-btns.right {
display: block !important;
}
.mobile-mode .board-header-btns.right .board-header-btn span {
display: none !important;
}
.mobile-mode .board-header-btns.right .board-header-btn .fa + span {
display: none !important;
}
.mobile-mode .board-header-btns.right .board-header-btn .fa + .board-header-btn-text {
display: none !important;
}
.mobile-mode .board-header-btns.right .board-header-btn .fa + .board-header-btn-label {
display: none !important;
}
/* Hide specific desktop-only buttons that shouldn't show in mobile mode */
.mobile-mode .board-header-btn.js-star-board span,
.mobile-mode .board-header-btn.js-change-visibility span,
.mobile-mode .board-header-btn.js-watch-board span,
.mobile-mode .board-header-btn.js-sort-cards span {
display: none !important;
}
/* Show only icons for mobile mode buttons */
.mobile-mode .board-header-btns.right .board-header-btn {
width: auto !important;
min-width: auto !important;
padding: 8px !important;
text-align: center !important;
margin: 0 2px !important;
}
.mobile-mode .board-header-btns.right .board-header-btn i {
display: inline-block !important;
margin: 0 !important;
}
/* Ensure mobile mode looks like small screen mobile view */
.mobile-mode .board-header {
height: 40px !important;
}
.mobile-mode .board-header .board-header-btns {
margin-top: 0px !important;
}
.mobile-mode .board-header .board-header-btn {
height: 32px !important;
line-height: 32px !important;
font-size: 15px !important;
}
.mobile-mode .board-header .board-header-btn i.fa {
line-height: 32px !important;
}
/* Copy mobile media query styles to mobile mode for consistent appearance */
.mobile-mode .board-header {
height: 40px !important;
padding: 0 !important;
margin: 0 !important;
}
.mobile-mode .board-header .board-header-btns {
margin-top: 0px !important;
height: 40px !important;
display: flex !important;
align-items: center !important;
justify-content: flex-end !important;
}
.mobile-mode .board-header .board-header-btn {
height: 32px !important;
line-height: 32px !important;
font-size: 15px !important;
margin: 0 2px !important;
padding: 4px 8px !important;
border-radius: 4px !important;
background: rgba(255, 255, 255, 0.1) !important;
border: 1px solid rgba(255, 255, 255, 0.2) !important;
color: #fff !important;
text-decoration: none !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
min-width: 32px !important;
width: auto !important;
}
.mobile-mode .board-header .board-header-btn:hover {
background: rgba(255, 255, 255, 0.2) !important;
border-color: rgba(255, 255, 255, 0.3) !important;
}
.mobile-mode .board-header .board-header-btn i.fa {
line-height: 32px !important;
font-size: 15px !important;
margin: 0 !important;
padding: 0 !important;
}
.mobile-mode .board-header .board-header-btn i.fa + span {
display: none !important;
}
.mobile-mode .board-header .board-header-btn span {
display: none !important;
}
/* Hide the board title in mobile mode to match mobile view */
.mobile-mode .header-board-menu {
display: none !important;
}
/* Ensure the board header takes full width in mobile mode */
.mobile-mode .board-header {
width: 100% !important;
max-width: 100% !important;
display: flex !important;
align-items: center !important;
justify-content: space-between !important;
padding: 0 10px !important;
}
/* Additional Desktop Mode Styles for Other Elements */
.desktop-mode .swimlane-header .swimlane-title {
font-size: clamp(14px, 3vw, 18px) !important;
}
.desktop-mode .swimlane-header .swimlane-description {
font-size: 12px !important;
}
.desktop-mode .board-header {
font-size: clamp(14px, 3vw, 18px) !important;
padding: 2.5vh 1.5vw 0.5vh !important;
}
.desktop-mode .board-header .board-header-title {
font-size: clamp(14px, 3vw, 18px) !important;
}
.desktop-mode .board-header .board-header-description {
font-size: 12px !important;
}
.desktop-mode .board-header .board-header-btn {
font-size: clamp(12px, 2.5vw, 16px) !important;
padding: 0.5vh 0.8vw !important;
}
.desktop-mode .board-header .board-header-btn i {
font-size: clamp(12px, 2.5vw, 16px) !important;
flex: 1;
gap: 2ch;
padding: 0 0.5ch;
}

View file

@ -1,26 +1,67 @@
template(name="boardHeaderBar")
h1.header-board-menu
with currentBoard
if $eq title 'Templates'
| {{_ 'templates'}}
else
+viewer
= title
.board-header
.header-board-menu
with currentBoard
if $eq title 'Templates'
| {{_ 'templates'}}
else
+viewer
= title
if currentBoard
if currentUser
with currentBoard
if currentUser.isBoardAdmin
a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title)
i.fa.fa-pencil-square-o
unless isMiniScreen
.board-header-btns-left
if currentBoard
if currentUser
with currentBoard
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
span {{_ currentBoard.permission}}
.board-header-btns.left
unless isMiniScreen
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
if $eq watchLevel "watching"
i.fa.fa-eye
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}" title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
if showStarCounter
span.board-star-counter {{currentBoard.stars}}
a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}")
i.fa.fa-sort
span {{#if isSortActive }}{{_ 'sort-is-on'}}{{else}}{{_ 'sort-cards'}}{{/if}}
if isSortActive
a.board-header-btn-close.js-sort-reset(title="{{_ 'remove-sort'}}")
i.fa.fa-times-thin
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
.board-header-btns-right
.separator
if currentBoard
if currentUser
with currentBoard
if currentUser.isBoardAdmin
if isMiniScreen
if currentUser
with currentBoard
a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title)
i.fa.fa-pencil-square-o
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
span {{_ currentBoard.permission}}
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
@ -29,86 +70,43 @@ template(name="boardHeaderBar")
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
if showStarCounter
span.board-star-counter {{currentBoard.stars}}
a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}")
i.fa.fa-sort
span {{#if isSortActive }}{{_ 'sort-is-on'}}{{else}}{{_ 'sort-cards'}}{{/if}}
if isSortActive
a.board-header-btn-close.js-sort-reset(title="{{_ 'remove-sort'}}")
i.fa.fa-times-thin
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
.board-header-btns.center
.board-header-btns.right
if currentBoard
if isMiniScreen
if currentUser
with currentBoard
a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title)
i.fa.fa-pencil-square-o
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
if $eq watchLevel "watching"
i.fa.fa-eye
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}")
i.fa.fa-sort
span {{#if isSortActive }}{{_ 'sort-is-on'}}{{else}}{{_ 'sort-cards'}}{{/if}}
if isSortActive
a.board-header-btn-close.js-sort-reset(title="{{_ 'remove-sort'}}")
i.fa.fa-times-thin
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
if isSandstorm
if currentUser
a.board-header-btn.js-open-archived-board
i.fa.fa-archive
if isSandstorm
if currentUser
a.js-open-archived-board
i.fa.fa-archive
//if showSort
// a.board-header-btn.js-open-sort-view(title="{{_ 'sort-desc'}}")
// i.fa(class="{{directionClass}}")
// span {{_ 'sort'}}{{_ listSortShortDesc}}
//if showSort
// a.board-header-btn.js-open-sort-view(title="{{_ 'sort-desc'}}")
// i.fa(class="{{directionClass}}")
// span {{_ 'sort'}}{{_ listSortShortDesc}}
a.board-header-btn.js-open-filter-view(
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
class="{{#if Filter.isActive}}js-filter-active{{/if}}")
i.fa.fa-filter
span {{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}
if Filter.isActive
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
a.board-header-btn.js-open-filter-view(
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
class="{{#if Filter.isActive}}js-filter-active{{/if}}")
i.fa.fa-filter
span {{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}
if Filter.isActive
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
i.fa.fa-search
span {{_ 'search'}}
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
i.fa.fa-search
span {{_ 'search'}}
unless currentBoard.isTemplatesBoard
a.board-header-btn.js-toggle-board-view
@ -140,9 +138,9 @@ template(name="boardHeaderBar")
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
.separator
a.board-header-btn.js-toggle-sidebar(title="{{_ 'sidebar-open'}} {{_ 'or'}} {{_ 'sidebar-close'}}")
i.fa.fa-bars
.separator
a.board-header-btn.js-toggle-sidebar(title="{{_ 'sidebar-open'}} {{_ 'or'}} {{_ 'sidebar-close'}}")
i.fa.fa-bars
template(name="boardVisibilityList")
ul.pop-over-list
@ -172,26 +170,29 @@ template(name="boardChangeWatchPopup")
li
with "watching"
a.js-select-watch
i.fa.fa-eye
| {{_ 'watching'}}
if watchCheck
i.fa.fa-check
span
i.fa.fa-eye
| {{_ 'watching'}}
if watchCheck
i.fa.fa-check
span.sub-name {{_ 'watching-info'}}
li
with "tracking"
a.js-select-watch
i.fa.fa-bell
| {{_ 'tracking'}}
if watchCheck
i.fa.fa-check
span
i.fa.fa-bell
| {{_ 'tracking'}}
if watchCheck
i.fa.fa-check
span.sub-name {{_ 'tracking-info'}}
li
with "muted"
a.js-select-watch
i.fa.fa-bell-slash
| {{_ 'muted'}}
if watchCheck
i.fa.fa-check
span
i.fa.fa-bell-slash
| {{_ 'muted'}}
if watchCheck
i.fa.fa-check
span.sub-name {{_ 'muted-info'}}
template(name="boardChangeViewPopup")
@ -247,12 +248,13 @@ template(name="createBoard")
.materialCheckBox#add-template-container
span {{_ 'add-template-container'}}
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
.create-element-foooter
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
template(name="createBoardPopup")
form
@ -276,12 +278,13 @@ template(name="createBoardPopup")
.materialCheckBox#add-template-container
span {{_ 'add-template-container'}}
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
.create-element-foooter
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
// New popup for Template Container creation; shares the same form content
template(name="createTemplateContainerPopup")
@ -305,13 +308,14 @@ template(name="createTemplateContainerPopup")
a.flex.js-toggle-add-template-container
.materialCheckBox#add-template-container
span {{_ 'add-template-container'}}
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
.create-element-foooter
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
//template(name="listsortPopup")
// h2
@ -362,4 +366,3 @@ template(name="cardsSortPopup")
a.js-sort-created-asc
i.fa.fa-arrow-up
| {{_ 'created-at-oldest-first'}}

View file

@ -33,9 +33,6 @@ BlazeComponent.extendComponent({
const currentBoard = Utils.getCurrentBoard();
return currentBoard && currentBoard.getWatchLevel(Meteor.userId());
},
isStarred() {
const boardId = Session.get('currentBoard');
const user = ReactiveCache.getCurrentUser();
@ -182,7 +179,7 @@ Template.boardHeaderBar.helpers({
if (!sortBy) {
return '🃏'; // Card icon when nothing is selected
}
// Determine which sort option is active based on sortBy object
if (sortBy.dueAt) {
return '📅'; // Due date icon
@ -191,7 +188,7 @@ Template.boardHeaderBar.helpers({
} else if (sortBy.createdAt) {
return sortBy.createdAt === 1 ? '⬆️' : '⬇️'; // Up/down arrow based on direction
}
return '🃏'; // Default card icon
},
});

File diff suppressed because it is too large Load diff

View file

@ -67,81 +67,71 @@ template(name="boardList")
// Right boards grid
.boards-right-grid
.boards-path-header
.path-left
span.path-icon.emoji-icon {{currentMenuPath.icon}}
span.path-text {{currentMenuPath.text}}
if BoardMultiSelection.isActive
span.multiselection-hint
span.emoji-icon
i.fa.fa-thumb-tack
| {{_ 'multi-selection-active'}}
.path-right
if canModifyBoards
if hasBoardsSelected
button.js-archive-selected-boards.board-header-btn
.path-bottom
.path-left
span.path-icon.emoji-icon {{currentMenuPath.icon}}
span.path-text {{currentMenuPath.text}}
.path-right
unless isMiniScreen
+headerMultiSelection
if canModifyBoards
a.board-header-btn.js-multiselection-activate(
title="{{#if BoardMultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
class="{{#if BoardMultiSelection.isActive}}emphasis{{/if}}")
span.emoji-icon
i.fa.fa-archive
span {{_ 'archive-board'}}
button.js-duplicate-selected-boards.board-header-btn
span.emoji-icon
i.fa.fa-clipboard
span {{_ 'duplicate-board'}}
a.board-header-btn.js-multiselection-activate(
title="{{#if BoardMultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
class="{{#if BoardMultiSelection.isActive}}emphasis{{/if}}")
span.emoji-icon
i.fa.fa-check-square-o
if BoardMultiSelection.isActive
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
span.emoji-icon
i.fa.fa-times
i.fa.fa-check-square-o
if BoardMultiSelection.isActive
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
span.emoji-icon
i.fa.fa-times
ul.board-list.clearfix.js-boards(class="{{#if isMiniScreen}}mobile-view{{/if}} {{#if BoardMultiSelection.isActive}}is-multiselection-active{{/if}}")
li.js-add-board
if isSelectedMenu 'templates'
a.board-list-item.label(title="{{_ 'add-template-container'}}")
span.emoji-icon
i.fa.fa-plus
| &nbsp;{{_ 'add-template-container'}}
| {{_ 'add-template-container'}}
else
a.board-list-item.label(title="{{_ 'add-board'}}")
span.emoji-icon
i.fa.fa-plus
| &nbsp;{{_ 'add-board'}}
| {{_ 'add-board'}}
each boards
li.js-board(class="{{_id}} {{#if isStarred}}starred{{/if}} {{colorClass}} {{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}", draggable="true")
if isInvited
.board-list-item
if BoardMultiSelection.isActive
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
span.details
span.board-list-item-name= title
.board-card-header
span.js-star-board(
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
title="{{_ 'star-board-title'}}")
span.emoji-icon
| {{#if isStarred}}⭐{{else}}☆{{/if}}
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
.board-card-body
span.details
span.board-list-item-name= title
p.board-list-item-desc {{_ 'just-invited'}}
button.js-accept-invite.primary {{_ 'accept'}}
button.js-decline-invite {{_ 'decline'}}
.board-card-footer
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="{{#if BoardMultiSelection.isActive }}active{{/if}} {{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
else
if $eq type "template-container"
.template-container.board-list-item
if BoardMultiSelection.isActive
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
span.board-handle(title="{{_ 'drag-board'}}")
span.emoji-icon
i.fa.fa-arrows
a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
.template-container.board-list-item
if BoardMultiSelection.isActive
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
span.details
span.board-list-item-name(title="{{_ 'template-container'}}")
+viewer
= title
p.board-list-item-desc
+viewer
= description
//- #FIXME: is this obsolete ?
//- p.board-list-item-desc
//- +viewer
//- = description
if hasSpentTimeCards
span.js-has-spenttime-cards(
class="{{#if hasOvertimeCards}}has-overtime-card-active{{else}}no-overtime-card-active{{/if}}"
@ -154,19 +144,20 @@ template(name="boardList")
span.emoji-icon
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
else
.board-list-item
if BoardMultiSelection.isActive
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
span.board-handle(title="{{_ 'drag-board'}}")
span.emoji-icon
i.fa.fa-arrows
a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
.board-list-item
if BoardMultiSelection.isActive
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
span.details
span.board-list-item-name(title="{{_ 'board-drag-drop-reorder-or-click-open'}}")
+viewer
= title
//- p.board-list-item-desc
//- +viewer
//- = description
unless currentSetting.hideBoardMemberList
if allowsBoardMemberList
.minicard-members
@ -175,34 +166,24 @@ template(name="boardList")
+userAvatar(userId=member noRemove=true)
unless currentSetting.hideCardCounterList
if allowsCardCounterList
.minicard-lists.flex.flex-wrap
.minicard-lists
each list in boardLists _id
.item
| {{ list }}
p.board-list-item-desc
+viewer
= description
if hasSpentTimeCards
span.js-has-spenttime-cards(
class="{{#if hasOvertimeCards}}has-overtime-card-active{{else}}no-overtime-card-active{{/if}}"
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
span.emoji-icon
i.fa.fa-clock-o
a.js-star-board(
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
title="{{_ 'star-board-title'}}")
span.emoji-icon
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
a.js-star-board(
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
title="{{_ 'star-board-title'}}")
span.emoji-icon
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
template(name="boardListHeaderBar")
h1 {{_ title }}
//.board-header-btns.right
// a.board-header-btn.js-open-archived-board
// i.fa.fa-archive
// span {{_ 'archives'}}
// a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
// i.fa.fa-clone
// span {{_ 'templates'}}
// Recursive template for workspaces tree
template(name="workspaceTree")
@ -214,7 +195,7 @@ template(name="workspaceTree")
span.workspace-drag-handle
span.emoji-icon
i.fa.fa-arrows
a.js-select-workspace(data-id="{{id}}")
span.workspace-icon
if icon
@ -231,3 +212,16 @@ template(name="workspaceTree")
a.js-add-subworkspace(data-id="{{id}}" title="{{_ 'allboards.add-subworkspace'}}") +
if children
+workspaceTree(nodes=children selectedWorkspaceId=selectedWorkspaceId)
template(name="headerMultiSelection")
if BoardMultiSelection.isActive
if canModifyBoards
if hasBoardsSelected
button.negate.js-archive-selected-boards.board-header-btn
span.emoji-icon
i.fa.fa-archive
span {{_ 'archive-board'}}
button.negate.js-duplicate-selected-boards.board-header-btn
span.emoji-icon
i.fa.fa-clipboard
span {{_ 'duplicate-board'}}

View file

@ -108,10 +108,7 @@ BlazeComponent.extendComponent({
const newTree = EJSON.clone(tree);
// Remove the dragged space
const { tree: treeAfterRemoval, removed } = removeSpace(
newTree,
draggedSpaceId,
);
const { tree: treeAfterRemoval, removed } = removeSpace(newTree, draggedSpaceId);
if (removed) {
// Insert after target
@ -127,46 +124,39 @@ BlazeComponent.extendComponent({
onRendered() {
// jQuery sortable is disabled in favor of HTML5 drag-and-drop for space management
// The old sortable code has been removed to prevent conflicts
/* OLD SORTABLE CODE - DISABLED
const itemsSelector = '.js-board:not(.placeholder)';
const $boards = this.$('.js-boards');
$boards.sortable({
connectWith: '.js-boards',
tolerance: 'pointer',
appendTo: '.board-list',
helper: 'clone',
distance: 7,
items: itemsSelector,
placeholder: 'board-wrapper placeholder',
start(evt, ui) {
ui.helper.css('z-index', 1000);
ui.placeholder.height(ui.helper.height());
EscapeActions.executeUpTo('popup-close');
},
async stop(evt, ui) {
const prevBoardDom = ui.item.prev('.js-board').get(0);
const nextBoardDom = ui.item.next('.js-board').get(0);
const sortIndex = Utils.calculateIndex(prevBoardDom, nextBoardDom, 1);
// #FIXME OLD SORTABLE CODE - WILL BE DISABLED
//
// const itemsSelector = '.js-board';
const boardDomElement = ui.item.get(0);
const board = Blaze.getData(boardDomElement);
$boards.sortable('cancel');
const currentUser = ReactiveCache.getCurrentUser();
if (currentUser && typeof currentUser.setBoardSortIndex === 'function') {
await currentUser.setBoardSortIndex(board._id, sortIndex.base);
}
},
});
// const $boards = this.$('.js-boards');
// $boards.sortable({
// connectWith: '.js-boards',
// tolerance: 'pointer',
// appendTo: '.board-list',
// helper: 'clone',
// distance: 7,
// items: itemsSelector,
// placeholder: 'board-wrapper placeholder',
// start(evt, ui) {
// ui.helper.css('z-index', 1000);
// ui.placeholder.height(ui.helper.height());
// EscapeActions.executeUpTo('popup-close');
// },
// async stop(evt, ui) {
// const prevBoardDom = ui.item.prev('.js-board').get(0);
// const nextBoardDom = ui.item.next('.js-board').get(0);
// const sortIndex = Utils.calculateIndex(prevBoardDom, nextBoardDom, 1);
this.autorun(() => {
if (Utils.isTouchScreenOrShowDesktopDragHandles()) {
$boards.sortable({
handle: '.board-handle',
});
}
});
*/
// const boardDomElement = ui.item.get(0);
// const board = Blaze.getData(boardDomElement);
// $boards.sortable('cancel');
// const currentUser = ReactiveCache.getCurrentUser();
// if (currentUser && typeof currentUser.setBoardSortIndex === 'function') {
// await currentUser.setBoardSortIndex(board._id, sortIndex.base);
// }
// },
// });
},
userHasTeams() {
if (ReactiveCache.getCurrentUser()?.teams?.length > 0) return true;
@ -357,7 +347,7 @@ BlazeComponent.extendComponent({
const lists = ReactiveCache.getLists({ 'boardId': boardId, 'archived': false },{sort: ['sort','asc']});
const ret = lists.map(list => {
let cardCount = ReactiveCache.getCards({ 'boardId': boardId, 'listId': list._id }).length;
return `${list.title}: ${cardCount}`;
return `${list.title}: ${cardCountcardCount}`;
});
return ret;
*/
@ -535,6 +525,7 @@ BlazeComponent.extendComponent({
'click .js-multiselection-reset'(evt) {
evt.preventDefault();
BoardMultiSelection.disable();
Popup.close();
},
'click .js-toggle-board-multi-selection'(evt) {
evt.preventDefault();
@ -708,6 +699,7 @@ BlazeComponent.extendComponent({
icon: newIcon || '📁',
});
Meteor.call('setWorkspacesTree', updatedTree, (err) => {
if (err) console.error(err);
});
@ -808,6 +800,7 @@ BlazeComponent.extendComponent({
// Get the workspace ID directly from the dropped workspace-node's data-workspace-id attribute
const workspaceId = targetEl.getAttribute('data-workspace-id');
if (workspaceId) {
if (isMultiBoard) {
// Multi-board drag
@ -830,6 +823,7 @@ BlazeComponent.extendComponent({
evt.preventDefault();
evt.stopPropagation();
const menuType = evt.currentTarget.getAttribute('data-type');
// Only allow drop on "remaining" menu to unassign boards from spaces
if (menuType === 'remaining') {
@ -844,9 +838,11 @@ BlazeComponent.extendComponent({
evt.preventDefault();
evt.stopPropagation();
const menuType = evt.currentTarget.getAttribute('data-type');
evt.currentTarget.classList.remove('drag-over');
// Only handle drops on "remaining" menu
if (menuType !== 'remaining') return;
@ -908,6 +904,7 @@ BlazeComponent.extendComponent({
};
const allBoards = ReactiveCache.getBoards(query, {});
if (type === 'starred') {
return allBoards.filter(
(b) => currentUser && currentUser.hasStarred(b._id),

View file

@ -23,7 +23,7 @@
.original-positions-content {
background-color: white;
border: 1px solid #dee2e6;
border-radius: 4px;
border-radius: 0.4ch;
padding: 15px;
}
@ -65,7 +65,7 @@
.original-position-item {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
border-radius: 0.4ch;
margin-bottom: 10px;
padding: 12px;
transition: all 0.2s ease;
@ -100,7 +100,7 @@
color: white;
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
}
@ -112,7 +112,7 @@
.entity-id {
color: #6c757d;
font-size: 11px;
font-family: monospace;
}
@ -123,12 +123,12 @@
.original-position-description {
color: #495057;
margin-bottom: 6px;
font-size: 13px;
}
.original-title {
color: #6c757d;
font-size: 12px;
margin-bottom: 6px;
padding: 4px 6px;
background-color: #e9ecef;
@ -141,7 +141,7 @@
.original-position-date {
color: #6c757d;
font-size: 11px;
}
.no-original-positions {
@ -152,7 +152,7 @@
}
.no-original-positions i {
font-size: 24px;
margin-bottom: 10px;
display: block;
color: #adb5bd;
@ -164,32 +164,32 @@
margin: 5px 0;
padding: 10px;
}
.original-positions-header {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.original-positions-header .btn {
justify-content: center;
}
.original-positions-filters .btn-group {
justify-content: center;
}
.original-position-item-header {
flex-wrap: wrap;
gap: 6px;
}
.entity-name {
flex: 1;
min-width: 0;
word-break: break-word;
}
.original-position-item-details {
margin-left: 0;
margin-top: 8px;
@ -203,60 +203,60 @@
border-color: #4a5568;
color: #e2e8f0;
}
.original-positions-content {
background-color: #1a202c;
border-color: #4a5568;
}
.original-position-item {
background-color: #2d3748;
border-color: #4a5568;
color: #e2e8f0;
}
.original-position-item:hover {
background-color: #4a5568;
border-color: #718096;
}
.original-position-item-header {
color: #e2e8f0;
}
.original-position-item-header i {
color: #a0aec0;
}
.entity-name {
color: #e2e8f0;
}
.entity-id {
color: #a0aec0;
}
.original-position-description {
color: #e2e8f0;
}
.original-title {
background-color: #4a5568;
color: #a0aec0;
}
.original-title strong {
color: #e2e8f0;
}
.original-position-date {
color: #a0aec0;
}
.no-original-positions {
color: #a0aec0;
}
.no-original-positions i {
color: #718096;
}