Add Field component system and migrate UI

This commit is contained in:
Gregor Vostrak
2026-02-10 12:22:53 +01:00
parent 1ecb332458
commit fd012e7c69
71 changed files with 1023 additions and 741 deletions

View File

@@ -14,7 +14,7 @@ import {
ComboboxViewport,
} from 'radix-vue';
import Dropdown from '@/packages/ui/src/Input/Dropdown.vue';
import { Button } from '@/Components/ui/button';
import { Button } from '@/packages/ui/src/Buttons';
const { members } = useMembersQuery();
@@ -77,7 +77,6 @@ function selectMember(member: Member) {
:disabled="disabled"
type="button"
variant="input"
size="input"
class="w-full justify-between text-start font-normal">
<div class="flex items-center gap-3 truncate">
<UserIcon class="w-4 text-text-secondary shrink-0" />
@@ -92,7 +91,7 @@ function selectMember(member: Member) {
<template #content>
<ComboboxRoot
v-model:search-term="searchValue"
:open="open"
v-model:open="open"
class="relative"
:filter-function="(val: string[]) => val">
<ComboboxAnchor>

View File

@@ -9,8 +9,7 @@ import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import Checkbox from '@/packages/ui/src/Input/Checkbox.vue';
import { useNotificationsStore } from '@/utils/notification';
import { getCurrentOrganizationId } from '@/utils/useUser';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import { Field, FieldLabel, FieldError } from '@/packages/ui/src/field';
const props = defineProps<{
show: boolean;
@@ -113,25 +112,21 @@ const close = () => {
},
}">
<template #default="{ field }">
<div class="flex flex-col">
<div class="flex items-center space-x-3 text-sm">
<Checkbox
:id="field.name"
:name="field.name"
:checked="field.state.value"
@update:checked="field.handleChange"
@blur="field.handleBlur" />
<InputLabel
:for="field.name"
class="font-medium text-text-primary">
I understand that this will permanently delete all data
related to this member
</InputLabel>
</div>
<InputError
class="pl-7 pt-2"
:message="field.state.meta.errors[0]" />
</div>
<Field orientation="horizontal">
<Checkbox
:id="field.name"
:name="field.name"
:checked="field.state.value"
@update:checked="field.handleChange"
@blur="field.handleBlur" />
<FieldLabel :for="field.name" class="font-medium text-text-primary">
I understand that this will permanently delete all data related
to this member
</FieldLabel>
<FieldError v-if="field.state.meta.errors[0]" class="pl-7 pt-2">
{{ field.state.meta.errors[0] }}
</FieldError>
</Field>
</template>
</form.Field>
</div>

View File

@@ -6,7 +6,7 @@ import type { Member, UpdateMemberBody } from '@/packages/api/src';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { type MemberBillableKey, useMembersStore } from '@/utils/useMembers';
import BillableRateInput from '@/packages/ui/src/Input/BillableRateInput.vue';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import { Field, FieldLabel } from '@/packages/ui/src/field';
import MemberBillableRateModal from '@/Components/Common/Member/MemberBillableRateModal.vue';
import MemberBillableSelect from '@/Components/Common/Member/MemberBillableSelect.vue';
import { onMounted, watch } from 'vue';
@@ -121,28 +121,24 @@ const roleDescription = computed(() => {
<template #content>
<div class="pb-5 pt-2 divide-y divide-border-secondary">
<div class="pb-5 flex space-x-6">
<div>
<InputLabel for="role" value="Role" />
<MemberRoleSelect
v-model="memberBody.role"
class="mt-2"
name="role"></MemberRoleSelect>
</div>
<Field>
<FieldLabel for="role">Role</FieldLabel>
<MemberRoleSelect v-model="memberBody.role" name="role"></MemberRoleSelect>
</Field>
<div class="flex-1 text-xs flex items-center pt-6">
<p>{{ roleDescription }}</p>
</div>
</div>
<div class="flex items-center space-x-4 pt-5">
<div class="col-span-6 sm:col-span-4 flex-1 flex space-x-5">
<div>
<InputLabel for="billableType" value="Billable" />
<Field>
<FieldLabel for="billableType">Billable</FieldLabel>
<MemberBillableSelect
v-model="billableRateSelect"
class="mt-2"
name="billableType"></MemberBillableSelect>
</div>
<div v-if="billableRateSelect === 'custom-rate'" class="flex-1">
<InputLabel for="memberBillableRate" value="Billable Rate" />
</Field>
<Field v-if="billableRateSelect === 'custom-rate'" class="flex-1">
<FieldLabel for="memberBillableRate">Billable Rate</FieldLabel>
<BillableRateInput
v-model="memberBody.billable_rate"
focus
@@ -150,7 +146,7 @@ const roleDescription = computed(() => {
:currency="getOrganizationCurrencyString()"
name="memberBillableRate"
@keydown.enter="saveWithChecks()"></BillableRateInput>
</div>
</Field>
</div>
</div>
</div>

View File

@@ -5,8 +5,7 @@ import DialogModal from '@/packages/ui/src/DialogModal.vue';
import { ref } from 'vue';
import PrimaryButton from '@/packages/ui/src/Buttons/PrimaryButton.vue';
import { useFocus } from '@vueuse/core';
import InputLabel from '@/packages/ui/src/Input/InputLabel.vue';
import InputError from '@/packages/ui/src/Input/InputError.vue';
import { Field, FieldLabel, FieldError } from '@/packages/ui/src/field';
import type { Role } from '@/types/jetstream';
import { Link, useForm } from '@inertiajs/vue3';
import { getCurrentOrganizationId } from '@/utils/useUser';
@@ -111,8 +110,8 @@ useFocus(clientNameInput, { initialValue: true });
</div>
</div>
<div v-else class="space-y-4">
<div class="col-span-6 sm:col-span-4 flex-1">
<InputLabel for="email" value="Email" />
<Field class="col-span-6 sm:col-span-4 flex-1">
<FieldLabel for="email">Email</FieldLabel>
<TextInput
id="email"
ref="memberEmailInput"
@@ -120,16 +119,16 @@ useFocus(clientNameInput, { initialValue: true });
name="email"
type="text"
placeholder="Member Email"
class="mt-1 block w-full"
class="block w-full"
required
autocomplete="memberName"
@keydown.enter="submit" />
<InputError :message="errors.email" class="mt-2" />
</div>
<FieldError v-if="errors.email">{{ errors.email }}</FieldError>
</Field>
<div v-if="availableRoles.length > 0">
<InputLabel for="roles" value="Role" />
<InputError :message="errors.role" class="mt-2" />
<Field v-if="availableRoles.length > 0">
<FieldLabel for="roles">Role</FieldLabel>
<FieldError v-if="errors.role">{{ errors.role }}</FieldError>
<div
class="relative z-0 mt-1 border border-card-border rounded-lg bg-card-background cursor-pointer">
@@ -182,7 +181,7 @@ useFocus(clientNameInput, { initialValue: true });
</div>
</button>
</div>
</div>
</Field>
</div>
</template>
<template #footer>