Fix Due dates to be color coded and have icons.

Thanks to xet7 !

Fixes #5950
This commit is contained in:
Lauri Ojansivu 2025-10-19 18:42:37 +03:00
parent 5d2bfab0f5
commit d965faa317
6 changed files with 126 additions and 32 deletions

View file

@ -94,7 +94,7 @@
/* Generic date badge and custom field date */
.card-date:not(.received-date):not(.start-date):not(.due-date):not(.end-date) time::before {
content: "📅"; /* Calendar - represents generic date */
/*content: "📅"; // Calendar - represents generic date */
}
.card-date time::before {
font-size: inherit;

View file

@ -24,14 +24,14 @@ template(name="dateCustomField")
template(name="minicardReceivedDate")
if canModifyCard
a.js-edit-date.card-date(title="{{_ 'card-received'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.js-edit-date.card-date.received-date(title="{{_ 'card-received'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
b
| {{showWeek}}
else
a.card-date(title="{{_ 'card-received'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.card-date.received-date(title="{{_ 'card-received'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
@ -40,14 +40,14 @@ template(name="minicardReceivedDate")
template(name="minicardStartDate")
if canModifyCard
a.js-edit-date.card-date(title="{{_ 'card-start'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.js-edit-date.card-date.start-date(title="{{_ 'card-start'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
b
| {{showWeek}}
else
a.card-date(title="{{_ 'card-start'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.card-date.start-date(title="{{_ 'card-start'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
@ -56,14 +56,14 @@ template(name="minicardStartDate")
template(name="minicardDueDate")
if canModifyCard
a.js-edit-date.card-date(title="{{_ 'card-due'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.js-edit-date.card-date.due-date(title="{{_ 'card-due'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
b
| {{showWeek}}
else
a.card-date(title="{{_ 'card-due'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.card-date.due-date(title="{{_ 'card-due'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
@ -72,14 +72,14 @@ template(name="minicardDueDate")
template(name="minicardEndDate")
if canModifyCard
a.js-edit-date.card-date(title="{{_ 'card-end'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.js-edit-date.card-date.end-date(title="{{_ 'card-end'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear
b
| {{showWeek}}
else
a.card-date(title="{{_ 'card-end'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
a.card-date.end-date(title="{{_ 'card-end'}} {{_ 'predicate-week'}} {{#if showWeekOfYear}}{{showWeek}}{{/if}}" class="{{classes}}")
time(datetime="{{showISODate}}")
| {{showDate}}
if showWeekOfYear

View file

@ -18,7 +18,8 @@ import {
now,
createDate,
fromNow,
calendar
calendar,
diff
} from '/imports/lib/dateUtils';
// editCardReceivedDatePopup
@ -169,9 +170,7 @@ class CardReceivedDate extends CardDate {
}
showTitle() {
return `${TAPi18n.__('card-received-on')} ${this.date
.get()
.format('LLLL')}`;
return `${TAPi18n.__('card-received-on')} ${format(this.date.get(), 'LLLL')}`;
}
events() {
@ -198,15 +197,15 @@ class CardStartDate extends CardDate {
const theDate = this.date.get();
const now = this.now.get();
// if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
if ((endAt && theDate.isAfter(endAt)) || (dueAt && theDate.isAfter(dueAt)))
if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt)))
classes += 'long-overdue';
else if (theDate.isAfter(now)) classes += '';
else if (isAfter(theDate, now)) classes += '';
else classes += 'current';
return classes;
}
showTitle() {
return `${TAPi18n.__('card-start-on')} ${this.date.get().format('LLLL')}`;
return `${TAPi18n.__('card-start-on')} ${format(this.date.get(), 'LLLL')}`;
}
events() {
@ -232,17 +231,17 @@ class CardDueDate extends CardDate {
const theDate = this.date.get();
const now = this.now.get();
// if the due date is after the end date, green - done early
if (endAt && theDate.isAfter(endAt)) classes += 'current';
if (endAt && isAfter(theDate, endAt)) classes += 'current';
// if there is an end date, don't need to flag the due date
else if (endAt) classes += '';
else if (now.diff(theDate, 'days') >= 2) classes += 'long-overdue';
else if (now.diff(theDate, 'minute') >= 0) classes += 'due';
else if (now.diff(theDate, 'days') >= -1) classes += 'almost-due';
else if (diff(now, theDate, 'days') >= 2) classes += 'long-overdue';
else if (diff(now, theDate, 'minute') >= 0) classes += 'due';
else if (diff(now, theDate, 'days') >= -1) classes += 'almost-due';
return classes;
}
showTitle() {
return `${TAPi18n.__('card-due-on')} ${this.date.get().format('LLLL')}`;
return `${TAPi18n.__('card-due-on')} ${format(this.date.get(), 'LLLL')}`;
}
events() {
@ -267,13 +266,13 @@ class CardEndDate extends CardDate {
const dueAt = this.data().getDue();
const theDate = this.date.get();
if (!dueAt) classes += '';
else if (theDate.isBefore(dueAt)) classes += 'current';
else if (theDate.isAfter(dueAt)) classes += 'due';
else if (isBefore(theDate, dueAt)) classes += 'current';
else if (isAfter(theDate, dueAt)) classes += 'due';
return classes;
}
showTitle() {
return `${TAPi18n.__('card-end-on')} ${this.date.get().format('LLLL')}`;
return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
}
events() {
@ -315,7 +314,7 @@ class CardCustomFieldDate extends CardDate {
}
showTitle() {
return `${this.date.get().format('LLLL')}`;
return `${format(this.date.get(), 'LLLL')}`;
}
classes() {
@ -418,10 +417,10 @@ class PokerEndDate extends CardDate {
return classes;
}
showDate() {
return this.date.get().format('l LT');
return format(this.date.get(), 'l LT');
}
showTitle() {
return `${TAPi18n.__('card-end-on')} ${this.date.get().format('LLLL')}`;
return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
}
events() {

View file

@ -169,6 +169,63 @@
margin-right: 0.4vw;
}
/* Unicode icons for minicard dates - matching cardDate.css */
.minicard .card-date.end-date time::before {
content: "🏁"; /* Finish flag - represents end/completion */
}
.minicard .card-date.due-date time::before {
content: "⏰"; /* Alarm clock - represents due/deadline */
}
.minicard .card-date.start-date time::before {
content: "🚀"; /* Rocket - represents start/launch */
}
.minicard .card-date.received-date time::before {
content: "📥"; /* Inbox tray - represents received/incoming */
}
.minicard .card-date time::before {
font-size: inherit;
margin-right: 0.3em;
display: inline-block;
}
/* Date type specific colors for minicards - matching cardDate.css */
.minicard .card-date.received-date {
background-color: #dbdbdb; /* Grey for received - same as base card-date */
}
.minicard .card-date.received-date:hover,
.minicard .card-date.received-date.is-active {
background-color: #b3b3b3;
}
.minicard .card-date.start-date {
background-color: #3cb500; /* Green for start */
}
.minicard .card-date.start-date:hover,
.minicard .card-date.start-date.is-active {
background-color: #2d8f00;
}
.minicard .card-date.due-date {
background-color: #ff9f19; /* Orange for due */
}
.minicard .card-date.due-date:hover,
.minicard .card-date.due-date.is-active {
background-color: #e68a00;
}
.minicard .card-date.end-date {
background-color: #a632db; /* Purple for end */
}
.minicard .card-date.end-date:hover,
.minicard .card-date.end-date.is-active {
background-color: #8a2bb8;
}
/* Font Awesome icons in minicard dates */
.minicard .card-date i.fa {
margin-right: 0.3vw;

View file

@ -12,11 +12,8 @@ template(name="minicard")
a.minicard-details-menu.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}") | ☰
.dates
if getReceived
unless getStart
unless getDue
unless getEnd
.date
+minicardReceivedDate
.date
+minicardReceivedDate
if getStart
.date
+minicardStartDate

View file

@ -304,6 +304,10 @@ export function format(date, format = 'L') {
return d.toLocaleString();
case 'llll':
return d.toLocaleString();
case 'LLLL':
return d.toLocaleString();
case 'l LT':
return `${month}/${day}/${year} ${hours}:${minutes}`;
case 'YYYY-MM-DD':
return `${year}-${month}-${day}`;
case 'YYYY-MM-DD HH:mm':
@ -490,3 +494,40 @@ export function calendar(date, now = new Date()) {
return format(d, 'L');
}
/**
* Calculate the difference between two dates in the specified unit
* @param {Date|string} date1 - First date
* @param {Date|string} date2 - Second date
* @param {string} unit - Unit of measurement ('millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'year')
* @returns {number} Difference in the specified unit
*/
export function diff(date1, date2, unit = 'millisecond') {
const d1 = new Date(date1);
const d2 = new Date(date2);
if (isNaN(d1.getTime()) || isNaN(d2.getTime())) return 0;
const diffMs = d1.getTime() - d2.getTime();
switch (unit) {
case 'millisecond':
return diffMs;
case 'second':
return Math.floor(diffMs / 1000);
case 'minute':
return Math.floor(diffMs / (1000 * 60));
case 'hour':
return Math.floor(diffMs / (1000 * 60 * 60));
case 'day':
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
case 'week':
return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 7));
case 'month':
return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 30));
case 'year':
return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 365));
default:
return diffMs;
}
}