diff --git a/src/components/Modal.vue b/src/components/Modal.vue new file mode 100644 index 0000000..be7185a --- /dev/null +++ b/src/components/Modal.vue @@ -0,0 +1,96 @@ + + + diff --git a/src/components/form/Form.vue b/src/components/form/Form.vue new file mode 100644 index 0000000..6fcb6c0 --- /dev/null +++ b/src/components/form/Form.vue @@ -0,0 +1,102 @@ + + + diff --git a/src/components/form/FormField.vue b/src/components/form/FormField.vue new file mode 100644 index 0000000..425bc9b --- /dev/null +++ b/src/components/form/FormField.vue @@ -0,0 +1,103 @@ + + + diff --git a/src/components/form/form.types.ts b/src/components/form/form.types.ts new file mode 100644 index 0000000..4715499 --- /dev/null +++ b/src/components/form/form.types.ts @@ -0,0 +1,7 @@ +export type FormData = Record; +export type FormErrors = Record; +export interface FormSubmit { + isValid: boolean; + formData: FormData; + fieldErrors: FormErrors; +} diff --git a/src/components/form/validator.types.ts b/src/components/form/validator.types.ts new file mode 100644 index 0000000..3691c63 --- /dev/null +++ b/src/components/form/validator.types.ts @@ -0,0 +1,15 @@ +export interface ValidState { + isValid: boolean; + message: string; +} + +export type FormValidatorFn = ( + field: string, + value: unknown, + formData: Record +) => ValidState | Promise; + +export interface FormValidator { + field: string; + validators: FormValidatorFn[]; +} diff --git a/src/components/form/validators.ts b/src/components/form/validators.ts new file mode 100644 index 0000000..003ec99 --- /dev/null +++ b/src/components/form/validators.ts @@ -0,0 +1,44 @@ +import { FormValidatorFn } from './validator.types'; + +export function MinLength(length: number, message?: string): FormValidatorFn { + return (_: string, value: unknown) => { + let isValid = true; + if (value != null && typeof value === 'string' && value.length < length) + isValid = false; + return { + isValid, + message: message || `Must be at least ${length} characters long`, + }; + }; +} + +export function MaxLength(length: number, message?: string): FormValidatorFn { + return (_: string, value: unknown) => { + let isValid = true; + if (value != null && typeof value === 'string' && value.length >= length) + isValid = false; + return { + isValid, + message: message || `Must be less than ${length} characters long`, + }; + }; +} + +export function IsRequired(message?: string): FormValidatorFn { + return (_: string, value: unknown) => { + return { + isValid: !!value, + message: message || `Field is required`, + }; + }; +} + +export function IsEmail(message?: string): FormValidatorFn { + return (_: string, value: unknown) => { + let isValid = value != null && /\S+@\S+\.\S+/.test(value as string); + return { + isValid, + message: message || `Must be a valid email address`, + }; + }; +} diff --git a/src/components/item/NewStorageModal.vue b/src/components/item/NewStorageModal.vue new file mode 100644 index 0000000..be75727 --- /dev/null +++ b/src/components/item/NewStorageModal.vue @@ -0,0 +1,61 @@ + + + diff --git a/src/components/item/StoredItemCard.vue b/src/components/item/StoredItemCard.vue new file mode 100644 index 0000000..c13a02a --- /dev/null +++ b/src/components/item/StoredItemCard.vue @@ -0,0 +1,129 @@ + + + diff --git a/src/views/building/floors/FloorView.vue b/src/views/building/floors/FloorView.vue index 22b0033..9d9e661 100644 --- a/src/views/building/floors/FloorView.vue +++ b/src/views/building/floors/FloorView.vue @@ -70,7 +70,10 @@ v-if="!movingBubble || storage.id === movingBubble?.id" :storage="storage" :class="{ - 'z-20': storage.id === hoveredBubble?.id, + 'z-20': + storage.id === hoveredBubble?.id || + storage.id === selectedStorage?.id || + (isSet(storage) && storage.id === selectedSet?.id), 'pointer-events-none': !!movingBubble, }" @mouseenter="() => (hoveredBubble = storage)" @@ -107,9 +110,19 @@ :storages="storages" :selected-room="selectedRoom" :selected-storage="selectedStorage" + :selected-set="selectedSet" @select-room="(room) => selectRoomFromList(room)" @select-storage="(storage) => selectStorage(storage)" + @new-storage="(set) => addNewStorage(set)" /> + + + +