mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-13 18:52:14 +01:00
Add Field component system and migrate UI
This commit is contained in:
@@ -5,7 +5,7 @@ import DialogModal from '@/packages/ui/src/DialogModal.vue';
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
|
||||
import TimeTrackerProjectTaskDropdown from '@/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue';
|
||||
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
|
||||
import { Field, FieldLabel } from '../field';
|
||||
import { TagIcon } from '@heroicons/vue/20/solid';
|
||||
import { getDayJsInstance, getLocalizedDayJs } from '@/packages/ui/src/utils/time';
|
||||
import type {
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/Components/ui/select';
|
||||
import { Button } from '@/Components/ui/button';
|
||||
import { Button } from '@/packages/ui/src/Buttons';
|
||||
import DatePicker from '@/packages/ui/src/Input/DatePicker.vue';
|
||||
import DurationHumanInput from '@/packages/ui/src/Input/DurationHumanInput.vue';
|
||||
|
||||
@@ -165,6 +165,7 @@ const billableProxy = computed({
|
||||
v-model:project="timeEntry.project_id"
|
||||
v-model:task="timeEntry.task_id"
|
||||
variant="input"
|
||||
size="default"
|
||||
:clients
|
||||
:create-project
|
||||
:create-client
|
||||
@@ -181,7 +182,7 @@ const billableProxy = computed({
|
||||
:tags="tags"
|
||||
:show-no-tag-option="false">
|
||||
<template #trigger>
|
||||
<Button variant="input" size="sm">
|
||||
<Button variant="input">
|
||||
<TagIcon class="h-4 text-icon-default" />
|
||||
<span>{{
|
||||
timeEntry.tags.length === 0
|
||||
@@ -192,7 +193,7 @@ const billableProxy = computed({
|
||||
</template>
|
||||
</TagDropdown>
|
||||
<Select v-model="billableProxy">
|
||||
<SelectTrigger size="small" :show-chevron="false">
|
||||
<SelectTrigger :show-chevron="false">
|
||||
<SelectValue class="flex items-center gap-2">
|
||||
<BillableIcon class="h-4 text-icon-default" />
|
||||
<span>{{ timeEntry.billable ? 'Billable' : 'Non-Billable' }}</span>
|
||||
@@ -206,9 +207,9 @@ const billableProxy = computed({
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-4 pt-4">
|
||||
<div class="flex-1">
|
||||
<InputLabel>Duration</InputLabel>
|
||||
<div class="space-y-2 mt-1 flex flex-col">
|
||||
<Field class="flex-1">
|
||||
<FieldLabel>Duration</FieldLabel>
|
||||
<div class="space-y-2 flex flex-col">
|
||||
<DurationHumanInput
|
||||
v-model:start="localStart"
|
||||
v-model:end="localEnd"
|
||||
@@ -222,31 +223,27 @@ const billableProxy = computed({
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
<div class="grid grid-cols-2 sm:flex gap-4">
|
||||
<div>
|
||||
<InputLabel>Start</InputLabel>
|
||||
<div class="flex flex-col gap-2 mt-1 sm:w-28">
|
||||
<Field>
|
||||
<FieldLabel>Start</FieldLabel>
|
||||
<div class="flex flex-col gap-2 sm:w-28">
|
||||
<TimePickerSimple
|
||||
v-model="localStart"
|
||||
class="w-full"
|
||||
size="large"></TimePickerSimple>
|
||||
class="w-full"></TimePickerSimple>
|
||||
<DatePicker
|
||||
v-model="localStart"
|
||||
class="w-full"
|
||||
tabindex="1"></DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<InputLabel>End</InputLabel>
|
||||
<div class="flex flex-col gap-2 mt-1 sm:w-28">
|
||||
<TimePickerSimple
|
||||
v-model="localEnd"
|
||||
class="w-full"
|
||||
size="large"></TimePickerSimple>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>End</FieldLabel>
|
||||
<div class="flex flex-col gap-2 sm:w-28">
|
||||
<TimePickerSimple v-model="localEnd" class="w-full"></TimePickerSimple>
|
||||
<DatePicker v-model="localEnd" class="w-full" tabindex="1"></DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,7 +5,7 @@ import DialogModal from '@/packages/ui/src/DialogModal.vue';
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
|
||||
import TimeTrackerProjectTaskDropdown from '@/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue';
|
||||
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
|
||||
import { Field, FieldLabel } from '../field';
|
||||
import { TagIcon } from '@heroicons/vue/20/solid';
|
||||
import { getLocalizedDayJs } from '@/packages/ui/src/utils/time';
|
||||
import type {
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/Components/ui/select';
|
||||
import { Button } from '@/Components/ui/button';
|
||||
import { Button } from '@/packages/ui/src/Buttons';
|
||||
import DatePicker from '@/packages/ui/src/Input/DatePicker.vue';
|
||||
import DurationHumanInput from '@/packages/ui/src/Input/DurationHumanInput.vue';
|
||||
|
||||
@@ -199,7 +199,7 @@ const billableProxy = computed({
|
||||
</template>
|
||||
</TagDropdown>
|
||||
<Select v-model="billableProxy">
|
||||
<SelectTrigger size="small" :show-chevron="false">
|
||||
<SelectTrigger size="sm" :show-chevron="false">
|
||||
<SelectValue class="flex items-center gap-2">
|
||||
<BillableIcon class="h-4 text-icon-default" />
|
||||
<span>{{
|
||||
@@ -215,9 +215,9 @@ const billableProxy = computed({
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-4 pt-4">
|
||||
<div class="flex-1">
|
||||
<InputLabel>Duration</InputLabel>
|
||||
<div class="space-y-2 mt-1 flex flex-col">
|
||||
<Field class="flex-1">
|
||||
<FieldLabel>Duration</FieldLabel>
|
||||
<div class="space-y-2 flex flex-col">
|
||||
<DurationHumanInput
|
||||
v-model:start="localStart"
|
||||
v-model:end="localEnd"
|
||||
@@ -231,34 +231,32 @@ const billableProxy = computed({
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
<div class="grid grid-cols-2 sm:flex gap-4">
|
||||
<div>
|
||||
<InputLabel>Start</InputLabel>
|
||||
<div class="flex flex-col gap-2 mt-1 sm:w-28">
|
||||
<Field>
|
||||
<FieldLabel>Start</FieldLabel>
|
||||
<div class="flex flex-col gap-2 sm:w-28">
|
||||
<TimePickerSimple
|
||||
v-model="localStart"
|
||||
class="w-full"
|
||||
size="large"></TimePickerSimple>
|
||||
class="w-full"></TimePickerSimple>
|
||||
<DatePicker
|
||||
v-model="localStart"
|
||||
class="w-full"
|
||||
tabindex="1"></DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<InputLabel>End</InputLabel>
|
||||
<div class="flex flex-col gap-2 mt-1 sm:w-28">
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>End</FieldLabel>
|
||||
<div class="flex flex-col gap-2 sm:w-28">
|
||||
<TimePickerSimple
|
||||
v-model="localEnd"
|
||||
class="w-full"
|
||||
size="large"></TimePickerSimple>
|
||||
class="w-full"></TimePickerSimple>
|
||||
<DatePicker
|
||||
v-model="localEnd"
|
||||
class="w-full"
|
||||
tabindex="1"></DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,8 @@ import type {
|
||||
} from '@/packages/api/src';
|
||||
import { ref } from 'vue';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { Checkbox, InputLabel } from '@/packages/ui/src';
|
||||
import { Checkbox } from '@/packages/ui/src';
|
||||
import { FieldLabel } from '../field';
|
||||
|
||||
const props = defineProps<{
|
||||
selectedTimeEntries: TimeEntry[];
|
||||
@@ -71,14 +72,14 @@ const showMassUpdateModal = ref(false);
|
||||
:checked="allSelected"
|
||||
@update:checked="allSelected ? emit('unselectAll') : emit('selectAll')">
|
||||
</Checkbox>
|
||||
<InputLabel
|
||||
<FieldLabel
|
||||
v-if="selectedTimeEntries.length > 0"
|
||||
for="selectAll"
|
||||
class="select-none text-text-secondary">
|
||||
{{ selectedTimeEntries.length }} selected
|
||||
</InputLabel>
|
||||
<InputLabel v-else for="selectAll" class="text-text-secondary select-none"
|
||||
>Select All</InputLabel
|
||||
</FieldLabel>
|
||||
<FieldLabel v-else for="selectAll" class="text-text-secondary select-none"
|
||||
>Select All</FieldLabel
|
||||
>
|
||||
<button
|
||||
v-if="selectedTimeEntries.length"
|
||||
|
||||
@@ -5,7 +5,7 @@ import DialogModal from '@/packages/ui/src/DialogModal.vue';
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import PrimaryButton from '../Buttons/PrimaryButton.vue';
|
||||
import TimeTrackerProjectTaskDropdown from '@/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue';
|
||||
import InputLabel from '../Input/InputLabel.vue';
|
||||
import { Field, FieldLabel } from '../field';
|
||||
import {
|
||||
type CreateClientBody,
|
||||
type CreateProjectBody,
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/Components/ui/select';
|
||||
import { Button } from '@/Components/ui/button';
|
||||
import { Button } from '@/packages/ui/src/Buttons';
|
||||
import TagDropdown from '@/packages/ui/src/Tag/TagDropdown.vue';
|
||||
import type { Tag, Task } from '@/packages/api/src';
|
||||
|
||||
@@ -146,18 +146,18 @@ watch(removeAllTags, () => {
|
||||
|
||||
<template #content>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<InputLabel for="description" value="Description" />
|
||||
<Field>
|
||||
<FieldLabel for="description">Description</FieldLabel>
|
||||
<TextInput
|
||||
id="description"
|
||||
ref="descriptionInput"
|
||||
v-model="description"
|
||||
type="text"
|
||||
class="mt-1 block w-full"
|
||||
class="block w-full"
|
||||
@keydown.enter="submit" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<InputLabel for="project" value="Project" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="project">Project</FieldLabel>
|
||||
<TimeTrackerProjectTaskDropdown
|
||||
v-model:project="projectId"
|
||||
v-model:task="taskId"
|
||||
@@ -169,15 +169,14 @@ watch(removeAllTags, () => {
|
||||
:create-client
|
||||
:currency="currency"
|
||||
:can-create-project
|
||||
class="mt-1"
|
||||
empty-placeholder="Select project..."
|
||||
allow-reset
|
||||
:enable-estimated-time
|
||||
:projects="projects"
|
||||
:tasks="tasks"></TimeTrackerProjectTaskDropdown>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<InputLabel for="project" value="Tag" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>Tag</FieldLabel>
|
||||
<div class="flex space-x-5">
|
||||
<TagDropdown
|
||||
v-model="selectedTags"
|
||||
@@ -194,33 +193,31 @@ watch(removeAllTags, () => {
|
||||
</Button>
|
||||
</template>
|
||||
</TagDropdown>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="no_tags" v-model:checked="removeAllTags"></Checkbox>
|
||||
<InputLabel for="no_tags" value="Remove all tags" />
|
||||
</div>
|
||||
<FieldLabel for="no_tags">Remove all tags</FieldLabel>
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<InputLabel for="project" value="Billable" />
|
||||
<div class="flex">
|
||||
<Select v-model="timeEntryBillable">
|
||||
<SelectTrigger>
|
||||
<SelectValue>
|
||||
<span v-if="billable === undefined">Set billable status</span>
|
||||
<span v-else-if="billable === true">Billable</span>
|
||||
<span v-else>Non Billable</span>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="do-not-update">
|
||||
Keep current billable status
|
||||
</SelectItem>
|
||||
<SelectItem value="billable">Billable</SelectItem>
|
||||
<SelectItem value="non-billable">Non Billable</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>Billable</FieldLabel>
|
||||
<Select v-model="timeEntryBillable">
|
||||
<SelectTrigger>
|
||||
<SelectValue>
|
||||
<span v-if="billable === undefined">Set billable status</span>
|
||||
<span v-else-if="billable === true">Billable</span>
|
||||
<span v-else>Non Billable</span>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="do-not-update">
|
||||
Keep current billable status
|
||||
</SelectItem>
|
||||
<SelectItem value="billable">Billable</SelectItem>
|
||||
<SelectItem value="non-billable">Non Billable</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
|
||||
Reference in New Issue
Block a user