Skip to content

Commit 6f50d3e

Browse files
committed
fix: fixed manually adding time where datetime picker would overlap at the top, feat: added shortcut to the exact time tracking logger in the add time buttton from card back section + adjusted UI to have hours and minutes next to each other and auto focus hours input
1 parent f723384 commit 6f50d3e

File tree

2 files changed

+223
-43
lines changed

2 files changed

+223
-43
lines changed
Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,57 @@
11
<template>
22
<div class="flex flex-column align-items-start pt-4 add-time-container">
3-
<!-- Help button -->
4-
<div class="w-full flex justify-content-end">
3+
<!-- Header with button and help -->
4+
<div class="w-full flex justify-content-between align-items-center">
5+
<Button
6+
label="Log Exact Times"
7+
icon="pi pi-calendar-clock"
8+
outlined
9+
size="small"
10+
@click="openAddTimeRange"
11+
/>
512
<HelpButton
613
feature="manualTime"
714
title="Learn about adding time manually"
815
/>
916
</div>
1017

11-
<span class="p-float-label w-full">
12-
<InputNumber
13-
id="f-hours"
14-
v-model="hours"
15-
placeholder="0"
16-
class="w-full"
17-
:format="false"
18-
:use-grouping="false"
19-
:min-fraction-digits="0"
20-
:max-fraction-digits="2"
21-
:min="0"
22-
thousand-separator=""
23-
locale="en-GB"
24-
/>
25-
<label for="f-hours">Hours</label>
26-
</span>
27-
28-
<span class="p-float-label w-full">
29-
<InputNumber
30-
id="f-minutes"
31-
v-model="minutes"
32-
placeholder="0"
33-
class="w-full"
34-
:format="false"
35-
:use-grouping="false"
36-
:min-fraction-digits="0"
37-
:max-fraction-digits="0"
38-
:min="0"
39-
:max="59"
40-
thousand-separator=""
41-
locale="en-GB"
42-
/>
43-
<label for="f-minutes">Minutes</label>
44-
</span>
18+
<!-- Hours and Minutes inputs side by side -->
19+
<div class="w-full flex flex-row input-row">
20+
<span class="p-float-label input-half">
21+
<InputNumber
22+
id="f-hours"
23+
v-model="hours"
24+
placeholder="0"
25+
class="w-full"
26+
:format="false"
27+
:use-grouping="false"
28+
:min-fraction-digits="0"
29+
:max-fraction-digits="2"
30+
:min="0"
31+
thousand-separator=""
32+
locale="en-GB"
33+
/>
34+
<label for="f-hours">Hours</label>
35+
</span>
36+
37+
<span class="p-float-label input-half">
38+
<InputNumber
39+
id="f-minutes"
40+
v-model="minutes"
41+
placeholder="0"
42+
class="w-full"
43+
:format="false"
44+
:use-grouping="false"
45+
:min-fraction-digits="0"
46+
:max-fraction-digits="0"
47+
:min="0"
48+
:max="59"
49+
thousand-separator=""
50+
locale="en-GB"
51+
/>
52+
<label for="f-minutes">Minutes</label>
53+
</span>
54+
</div>
4555

4656
<Button label="Add time" class="w-full" @click="save" />
4757
</div>
@@ -63,12 +73,31 @@ const minutes = ref<number>(0);
6373
6474
onMounted(() => {
6575
// Auto-focus the hours input field
66-
const hoursInput = document.getElementById('f-hours');
67-
if (hoursInput) {
68-
hoursInput.focus();
69-
}
76+
setTimeout(() => {
77+
const hoursInput = document.querySelector('#f-hours input');
78+
if (hoursInput) {
79+
(hoursInput as HTMLInputElement).focus();
80+
}
81+
}, 100);
7082
});
7183
84+
const openAddTimeRange = async () => {
85+
const trello = getTrelloCard();
86+
const memberId = await getMemberId();
87+
const card = await trello.card('id');
88+
89+
await trello.modal({
90+
title: 'Add Time Range',
91+
url: `./index.html?page=add-time-range&memberId=${memberId}&cardId=${card.id}`,
92+
fullscreen: false,
93+
height: 650
94+
});
95+
96+
// Close the popup after the modal is closed
97+
// This refreshes the data in the parent view
98+
await trello.closePopup();
99+
};
100+
72101
const save = async () => {
73102
if (!hours.value && !minutes.value) {
74103
await getTrelloCard().alert({
@@ -98,6 +127,30 @@ setTimeout(resizeTrelloFrame);
98127

99128
<style scoped>
100129
.add-time-container {
101-
gap: 2rem;
130+
gap: 1.5rem;
131+
}
132+
133+
/* Ensure button has proper spacing */
134+
.add-time-container > div:first-child {
135+
margin-bottom: 0.5rem;
136+
}
137+
138+
/* Input row with gap */
139+
.input-row {
140+
gap: 1rem;
141+
}
142+
143+
/* Input fields at 50% width each with gap accounted for */
144+
.input-half {
145+
flex: 1;
146+
min-width: 0;
147+
}
148+
149+
.input-half :deep(.p-inputnumber) {
150+
width: 100%;
151+
}
152+
153+
.input-half :deep(.p-inputtext) {
154+
width: 100%;
102155
}
103156
</style>

src/pages/ManageMemberTime.vue

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363

6464
<div v-else class="entries-list">
6565
<div
66-
v-for="range in sortedRanges"
66+
v-for="range in visibleRanges"
6767
:key="range.rangeId"
6868
class="entry-card"
6969
>
@@ -96,6 +96,35 @@
9696
/>
9797
</div>
9898
</div>
99+
100+
<!-- Collapsed entries summary -->
101+
<div
102+
v-if="hasCollapsedEntries"
103+
class="collapsed-entry-card"
104+
@click="toggleShowAll"
105+
>
106+
<div class="collapsed-main">
107+
<div class="collapsed-icon">
108+
<i
109+
:class="
110+
showAllEntries ? 'pi pi-chevron-up' : 'pi pi-chevron-down'
111+
"
112+
></i>
113+
</div>
114+
<div class="collapsed-details">
115+
<span class="collapsed-label">
116+
{{
117+
showAllEntries
118+
? 'Show Less'
119+
: `${collapsedRanges.length} More Entries`
120+
}}
121+
</span>
122+
<span v-if="!showAllEntries" class="collapsed-duration">
123+
{{ formatTime(collapsedTotalTime, false) }}
124+
</span>
125+
</div>
126+
</div>
127+
</div>
99128
</div>
100129
</div>
101130

@@ -142,6 +171,8 @@ const memberId = ref('');
142171
const memberName = ref('');
143172
const timeRanges = ref<Range[]>([]);
144173
const activeTimer = ref<any>(null);
174+
const showAllEntries = ref(false);
175+
const MAX_VISIBLE_ENTRIES = 5;
145176
let cardId = '';
146177
147178
const hasAnyTime = computed(() => {
@@ -152,6 +183,34 @@ const sortedRanges = computed(() => {
152183
return [...timeRanges.value].sort((a, b) => b.start - a.start);
153184
});
154185
186+
const visibleRanges = computed(() => {
187+
if (
188+
showAllEntries.value ||
189+
sortedRanges.value.length <= MAX_VISIBLE_ENTRIES
190+
) {
191+
return sortedRanges.value;
192+
}
193+
return sortedRanges.value.slice(0, MAX_VISIBLE_ENTRIES);
194+
});
195+
196+
const collapsedRanges = computed(() => {
197+
if (
198+
showAllEntries.value ||
199+
sortedRanges.value.length <= MAX_VISIBLE_ENTRIES
200+
) {
201+
return [];
202+
}
203+
return sortedRanges.value.slice(MAX_VISIBLE_ENTRIES);
204+
});
205+
206+
const collapsedTotalTime = computed(() => {
207+
return collapsedRanges.value.reduce((sum, range) => sum + range.diff, 0);
208+
});
209+
210+
const hasCollapsedEntries = computed(() => {
211+
return sortedRanges.value.length > MAX_VISIBLE_ENTRIES;
212+
});
213+
155214
const totalTime = computed(() => {
156215
const rangesTime = timeRanges.value.reduce(
157216
(sum, range) => sum + range.diff,
@@ -161,6 +220,11 @@ const totalTime = computed(() => {
161220
return rangesTime + timerTime;
162221
});
163222
223+
const toggleShowAll = () => {
224+
showAllEntries.value = !showAllEntries.value;
225+
setTimeout(resizeTrelloFrame, 100);
226+
};
227+
164228
onMounted(async () => {
165229
const params = new URLSearchParams(window.location.search);
166230
memberId.value = params.get('memberId') || '';
@@ -363,7 +427,7 @@ const openAddManualTime = async () => {
363427
title: 'Add Time Manually',
364428
url: `./index.html?page=add-time-range&memberId=${memberId.value}&cardId=${cardId}`,
365429
fullscreen: false,
366-
height: 600
430+
height: 650
367431
});
368432
369433
// Reload data after modal closes
@@ -598,6 +662,69 @@ html[data-color-mode='dark'] .entry-duration {
598662
gap: 0.25rem;
599663
}
600664
665+
/* Collapsed Entry Card */
666+
.collapsed-entry-card {
667+
display: flex;
668+
justify-content: center;
669+
align-items: center;
670+
padding: 1rem;
671+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
672+
border-radius: 6px;
673+
border: 1px solid rgba(255, 255, 255, 0.2);
674+
cursor: pointer;
675+
transition: transform 0.2s, box-shadow 0.2s;
676+
user-select: none;
677+
}
678+
679+
.collapsed-entry-card:hover {
680+
transform: translateY(-2px);
681+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
682+
}
683+
684+
.collapsed-entry-card:active {
685+
transform: translateY(0);
686+
}
687+
688+
html[data-color-mode='dark'] .collapsed-entry-card {
689+
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
690+
}
691+
692+
html[data-color-mode='dark'] .collapsed-entry-card:hover {
693+
box-shadow: 0 4px 12px rgba(90, 103, 216, 0.4);
694+
}
695+
696+
.collapsed-main {
697+
display: flex;
698+
align-items: center;
699+
gap: 1rem;
700+
}
701+
702+
.collapsed-icon {
703+
font-size: 1.25rem;
704+
color: white;
705+
display: flex;
706+
align-items: center;
707+
}
708+
709+
.collapsed-details {
710+
display: flex;
711+
flex-direction: column;
712+
gap: 0.25rem;
713+
align-items: center;
714+
}
715+
716+
.collapsed-label {
717+
font-size: 0.9375rem;
718+
color: white;
719+
font-weight: 600;
720+
}
721+
722+
.collapsed-duration {
723+
font-size: 0.875rem;
724+
color: rgba(255, 255, 255, 0.9);
725+
font-weight: 500;
726+
}
727+
601728
/* Total Section */
602729
.total-section {
603730
margin-top: 0.5rem;

0 commit comments

Comments
 (0)