mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 00:02:15 +01:00
design fixes, improve component encapsulation
This commit is contained in:
@@ -158,6 +158,7 @@ async function discardCurrentTimeEntry() {
|
||||
}
|
||||
|
||||
const { tags } = storeToRefs(useTagsStore());
|
||||
const { timeEntries } = storeToRefs(useTimeEntriesStore());
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -196,6 +197,7 @@ const { tags } = storeToRefs(useTagsStore());
|
||||
:tags
|
||||
:tasks
|
||||
:projects
|
||||
:time-entries
|
||||
:create-tag
|
||||
:is-active
|
||||
:currency="getOrganizationCurrencyString()"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build && vue-tsc --emitDeclarationOnly",
|
||||
"watch": "vite build --watch",
|
||||
"types": "vue-tsc ",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
|
||||
@@ -318,7 +318,9 @@ watch(showEditTimeEntryModal, (value) => {
|
||||
:tags="tags as any"
|
||||
:projects="projects"
|
||||
:tasks="tasks"
|
||||
:clients="clients" />
|
||||
:clients="clients"
|
||||
:currency="currency"
|
||||
:can-create-project="canCreateProject" />
|
||||
<FullCalendar ref="calendarRef" class="fullcalendar" :options="calendarOptions">
|
||||
<template #eventContent="arg">
|
||||
<FullCalendarEventContent
|
||||
|
||||
@@ -102,7 +102,7 @@ function onSelectChange(checked: boolean) {
|
||||
)
|
||||
"
|
||||
@update:checked="onSelectChange" />
|
||||
<div class="flex items-center min-w-0">
|
||||
<div class="flex items-center min-w-0 space-x-1 lg:space-x-2">
|
||||
<GroupedItemsCountButton :expanded="expanded" @click="expanded = !expanded">
|
||||
{{ timeEntry?.timeEntries?.length }}
|
||||
</GroupedItemsCountButton>
|
||||
@@ -125,7 +125,7 @@ function onSelectChange(checked: boolean) {
|
||||
@changed="updateProjectAndTask"></TimeTrackerProjectTaskDropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center font-medium lg:space-x-2">
|
||||
<div class="flex items-center font-medium space-x-1 lg:space-x-2">
|
||||
<TimeEntryRowTagDropdown
|
||||
:create-tag
|
||||
:tags="tags"
|
||||
@@ -142,8 +142,8 @@ function onSelectChange(checked: boolean) {
|
||||
twMerge(
|
||||
'text-text-secondary px-1 py-1.5 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-medium focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:bg-tertiary',
|
||||
organization?.time_format === '12-hours'
|
||||
? 'w-[170px]'
|
||||
: 'w-[120px]'
|
||||
? 'w-[150px]'
|
||||
: 'w-[90px]'
|
||||
)
|
||||
"
|
||||
@click="expanded = !expanded">
|
||||
@@ -157,7 +157,7 @@ function onSelectChange(checked: boolean) {
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="text-text-primary min-w-[90px] px-2.5 py-1.5 bg-transparent text-right hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-medium focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:bg-tertiary"
|
||||
class="text-text-primary !mr-2 min-w-[70px] px-1.5 py-1.5 bg-transparent text-right hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-medium focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:bg-tertiary"
|
||||
@click="expanded = !expanded">
|
||||
{{
|
||||
formatHumanReadableDuration(
|
||||
|
||||
@@ -15,8 +15,6 @@ import type {
|
||||
Client,
|
||||
TimeEntry,
|
||||
} from '@/packages/api/src';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import { canCreateProjects } from '@/utils/permissions';
|
||||
import TagDropdown from '@/packages/ui/src/Tag/TagDropdown.vue';
|
||||
import { Badge } from '@/packages/ui/src';
|
||||
import BillableIcon from '@/packages/ui/src/Icons/BillableIcon.vue';
|
||||
@@ -44,6 +42,8 @@ const props = defineProps<{
|
||||
projects: Project[];
|
||||
tasks: Task[];
|
||||
clients: Client[];
|
||||
currency: string;
|
||||
canCreateProject: boolean;
|
||||
}>();
|
||||
|
||||
const description = ref<HTMLInputElement | null>(null);
|
||||
@@ -163,8 +163,8 @@ type BillableOption = {
|
||||
:clients
|
||||
:create-project
|
||||
:create-client
|
||||
:can-create-project="canCreateProjects()"
|
||||
:currency="getOrganizationCurrencyString()"
|
||||
:can-create-project="canCreateProject"
|
||||
:currency="currency"
|
||||
size="xlarge"
|
||||
class="bg-input-background"
|
||||
:projects="projects"
|
||||
|
||||
@@ -35,11 +35,11 @@ const organization = inject<ComputedRef<Organization>>('organization');
|
||||
data-testid="time_entry_range_selector"
|
||||
:class="
|
||||
twMerge(
|
||||
'text-text-secondary px-2 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:text-text-primary focus-visible:ring-ring focus-visible:bg-tertiary',
|
||||
'text-text-secondary px-1 bg-transparent text-center hover:bg-card-background rounded-lg border border-transparent hover:border-card-border focus-visible:outline-none focus:outline-none focus-visible:ring-2 focus-visible:text-text-primary focus-visible:ring-ring focus-visible:bg-tertiary',
|
||||
showDate
|
||||
? 'text-xs py-1.5 font-semibold'
|
||||
: 'text-sm py-1.5 font-medium',
|
||||
organization?.time_format === '12-hours' ? 'w-[170px]' : 'w-[120px]',
|
||||
organization?.time_format === '12-hours' ? 'w-[150px]' : 'w-[90px]',
|
||||
open && 'border-card-border bg-card-background'
|
||||
)
|
||||
">
|
||||
|
||||
@@ -186,7 +186,9 @@ async function handleDeleteTimeEntry() {
|
||||
:tags="tags"
|
||||
:projects="projects"
|
||||
:tasks="tasks"
|
||||
:clients="clients" />
|
||||
:clients="clients"
|
||||
:currency="currency"
|
||||
:can-create-project="canCreateProject" />
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -77,7 +77,7 @@ function selectInput(event: Event) {
|
||||
v-model="currentTime"
|
||||
data-testid="time_entry_duration_input"
|
||||
name="Duration"
|
||||
class="text-text-primary w-[90px] px-2.5 py-1.5 bg-transparent text-right hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-medium focus-visible:bg-tertiary focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring"
|
||||
class="text-text-primary w-[70px] !mr-2 px-1.5 py-1.5 bg-transparent text-right hover:bg-card-background rounded-lg border border-transparent hover:border-card-border text-sm font-medium focus-visible:bg-tertiary focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring"
|
||||
@focus="selectInput"
|
||||
@keydown.tab="open = false"
|
||||
@blur="updateTimerAndStartLiveTimerUpdate"
|
||||
|
||||
@@ -61,7 +61,7 @@ function selectUnselectAll(value: boolean) {
|
||||
{{ formatDate(date, organization?.date_format) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-text-secondary pr-[90px] lg:pr-[92px]">
|
||||
<div class="text-text-secondary pr-[87px] lg:pr-[92px]">
|
||||
<span class="font-medium">
|
||||
{{
|
||||
formatHumanReadableDuration(
|
||||
|
||||
@@ -15,8 +15,6 @@ import type {
|
||||
} from '@/packages/api/src';
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFocus } from '@vueuse/core';
|
||||
import { autoUpdate, flip, limitShift, offset, shift, useFloating } from '@floating-ui/vue';
|
||||
import TimeTrackerRecentlyTrackedEntry from '@/packages/ui/src/TimeTracker/TimeTrackerRecentlyTrackedEntry.vue';
|
||||
@@ -34,6 +32,7 @@ const props = defineProps<{
|
||||
tasks: Task[];
|
||||
tags: Tag[];
|
||||
clients: Client[];
|
||||
timeEntries: TimeEntry[];
|
||||
createTag: (name: string) => Promise<Tag | undefined>;
|
||||
createProject: (project: CreateProjectBody) => Promise<Project | undefined>;
|
||||
createClient: (client: CreateClientBody) => Promise<Client | undefined>;
|
||||
@@ -131,10 +130,9 @@ function updateTimeEntryDescription() {
|
||||
}
|
||||
}
|
||||
|
||||
const { timeEntries } = storeToRefs(useTimeEntriesStore());
|
||||
const filteredRecentlyTrackedTimeEntries = computed(() => {
|
||||
// do not include running time entries
|
||||
const finishedTimeEntries = timeEntries.value.filter((item) => item.end !== null);
|
||||
const finishedTimeEntries = props.timeEntries.filter((item) => item.end !== null);
|
||||
|
||||
// filter out duplicates based on description, task, project, tags and billable
|
||||
const nonDuplicateTimeEntries = finishedTimeEntries.filter((item, index, self) => {
|
||||
|
||||
@@ -20,6 +20,7 @@ import TextInput from './Input/TextInput.vue';
|
||||
import InputLabel from './Input/InputLabel.vue';
|
||||
import TimeTrackerRunningInDifferentOrganizationOverlay from './TimeTracker/TimeTrackerRunningInDifferentOrganizationOverlay.vue';
|
||||
import TimeTrackerControls from './TimeTracker/TimeTrackerControls.vue';
|
||||
import TimeTrackerMoreOptionsDropdown from './TimeTracker/TimeTrackerMoreOptionsDropdown.vue';
|
||||
import CardTitle from './CardTitle.vue';
|
||||
import SelectDropdown from './Input/SelectDropdown.vue';
|
||||
import Badge from './Badge.vue';
|
||||
@@ -48,6 +49,7 @@ export {
|
||||
InputLabel,
|
||||
TimeTrackerRunningInDifferentOrganizationOverlay,
|
||||
TimeTrackerControls,
|
||||
TimeTrackerMoreOptionsDropdown,
|
||||
CardTitle,
|
||||
SelectDropdown,
|
||||
Badge,
|
||||
|
||||
Reference in New Issue
Block a user