Skip to content

Commit fca7d24

Browse files
Blackshadow8910tankerkiller125tonyaellie
authored
Creation modal quality of life changes (sysadminsmedia#467)
Co-authored-by: Matt Kilgore <[email protected]> Co-authored-by: Tonya <[email protected]>
1 parent 96d88c5 commit fca7d24

File tree

8 files changed

+140
-56
lines changed

8 files changed

+140
-56
lines changed

frontend/components/Base/Modal.vue

+38-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
<template>
22
<div class="z-[999]">
33
<input :id="modalId" v-model="modal" type="checkbox" class="modal-toggle" />
4-
<div class="modal modal-bottom overflow-visible sm:modal-middle">
4+
<div
5+
class="modal overflow-visible sm:modal-middle"
6+
:class="{ 'modal-bottom': !props.modalTop }"
7+
:modal-top="props.modalTop"
8+
>
59
<div ref="modalBox" class="modal-box relative overflow-visible">
610
<button
711
v-if="props.showCloseButton"
@@ -41,6 +45,14 @@
4145
type: Boolean,
4246
default: true,
4347
},
48+
clickOutsideToClose: {
49+
type: Boolean,
50+
default: false,
51+
},
52+
modalTop: {
53+
type: Boolean,
54+
default: false,
55+
},
4456
});
4557
4658
const modalBox = ref();
@@ -51,9 +63,11 @@
5163
}
5264
}
5365
54-
onClickOutside(modalBox, () => {
55-
close();
56-
});
66+
if (props.clickOutsideToClose) {
67+
onClickOutside(modalBox, () => {
68+
close();
69+
});
70+
}
5771
5872
function close() {
5973
if (props.readonly) {
@@ -74,3 +88,23 @@
7488
}
7589
});
7690
</script>
91+
92+
<style lang="css" scoped>
93+
@media (max-width: 640px) {
94+
.modal[modal-top=true] {
95+
align-items: start;
96+
}
97+
98+
.modal[modal-top=true] :where(.modal-box) {
99+
max-width: none;
100+
--tw-translate-y: 2.5rem /* 40px */;
101+
--tw-scale-x: 1;
102+
--tw-scale-y: 1;
103+
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate))
104+
skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
105+
width: 100%;
106+
border-top-left-radius: 0px;
107+
border-top-right-radius: 0px;
108+
}
109+
}
110+
</style>

frontend/components/Form/Multiselect.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<span class="label-text">{{ label }}</span>
55
</label>
66
<div class="dropdown dropdown-top sm:dropdown-end">
7-
<div tabindex="0" class="flex min-h-[48px] w-full flex-wrap gap-2 rounded-lg border border-gray-400 p-4">
7+
<div tabindex="0" class="flex min-h-[48px] w-full flex-wrap gap-2 rounded-lg border border-base-content/20 p-4">
88
<span v-for="itm in value" :key="itm.id" class="badge">
99
{{ itm.name }}
1010
</span>
@@ -20,7 +20,7 @@
2020
<div
2121
tabindex="0"
2222
style="display: inline"
23-
class="dropdown-content menu z-[9999] mb-1 w-full rounded border border-gray-400 bg-base-100 shadow"
23+
class="dropdown-content menu z-[9999] mb-1 w-full rounded border border-base-content/20 bg-base-100 shadow"
2424
>
2525
<div class="m-2">
2626
<input v-model="search" placeholder="Search…" class="input input-bordered input-sm w-full" />

frontend/components/Item/CreateModal.vue

+17-11
Original file line numberDiff line numberDiff line change
@@ -141,20 +141,26 @@
141141
}
142142
}
143143
144-
whenever(
144+
watch(
145145
() => modal.value,
146-
() => {
147-
focused.value = true;
148-
149-
if (locationId.value) {
150-
const found = locations.value.find(l => l.id === locationId.value);
151-
if (found) {
152-
form.location = found;
146+
open => {
147+
if (open) {
148+
useTimeoutFn(() => {
149+
focused.value = true;
150+
}, 50);
151+
152+
if (locationId.value) {
153+
const found = locations.value.find(l => l.id === locationId.value);
154+
if (found) {
155+
form.location = found;
156+
}
153157
}
154-
}
155158
156-
if (labelId.value) {
157-
form.labels = labels.value.filter(l => l.id === labelId.value);
159+
if (labelId.value) {
160+
form.labels = labels.value.filter(l => l.id === labelId.value);
161+
}
162+
} else {
163+
focused.value = false;
158164
}
159165
}
160166
);

frontend/components/Label/CreateModal.vue

+7-3
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,14 @@
6464
loading.value = false;
6565
}
6666
67-
whenever(
67+
watch(
6868
() => modal.value,
69-
() => {
70-
focused.value = true;
69+
open => {
70+
if (open)
71+
useTimeoutFn(() => {
72+
focused.value = true;
73+
}, 50);
74+
else focused.value = false;
7175
}
7276
);
7377

frontend/components/Location/CreateModal.vue

+29-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<BaseModal v-model="modal">
33
<template #title>{{ $t("components.location.create_modal.title") }}</template>
44
<form @submit.prevent="create()">
5+
<LocationSelector v-model="form.parent" />
56
<FormTextField
67
ref="locationNameRef"
78
v-model="form.name"
@@ -17,7 +18,6 @@
1718
:label="$t('components.location.create_modal.location_description')"
1819
:max-length="1000"
1920
/>
20-
<LocationSelector v-model="form.parent" />
2121
<div class="modal-action">
2222
<div class="flex justify-center">
2323
<BaseButton class="rounded-r-none" type="submit" :loading="loading">{{ $t("global.create") }}</BaseButton>
@@ -59,10 +59,23 @@
5959
parent: null as LocationSummary | null,
6060
});
6161
62-
whenever(
62+
watch(
6363
() => modal.value,
64-
() => {
65-
focused.value = true;
64+
open => {
65+
if (open) {
66+
useTimeoutFn(() => {
67+
focused.value = true;
68+
}, 50);
69+
70+
if (locationId.value) {
71+
const found = locations.value.find(l => l.id === locationId.value);
72+
if (found) {
73+
form.parent = found;
74+
}
75+
}
76+
} else {
77+
focused.value = false;
78+
}
6679
}
6780
);
6881
@@ -77,8 +90,20 @@
7790
const api = useUserApi();
7891
const toast = useNotifier();
7992
93+
const locationsStore = useLocationStore();
94+
const locations = computed(() => locationsStore.allLocations);
95+
96+
const route = useRoute();
97+
8098
const { shift } = useMagicKeys();
8199
100+
const locationId = computed(() => {
101+
if (route.fullPath.includes("/location/")) {
102+
return route.params.id;
103+
}
104+
return null;
105+
});
106+
82107
async function create(close = true) {
83108
if (loading.value) {
84109
toast.error("Already creating a location");

frontend/components/global/QuickMenu/Input.vue

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<template>
2-
<Combobox v-model="selectedAction">
2+
<Combobox v-model="selectedAction" :nullable="true">
33
<ComboboxInput
44
ref="inputBox"
55
class="input input-bordered mt-2 w-full"
66
@input="inputValue = $event.target.value"
77
></ComboboxInput>
88
<ComboboxOptions
99
class="card dropdown-content absolute max-h-48 w-full overflow-y-scroll rounded-lg border border-base-300 bg-base-100"
10+
:unmount="false"
1011
>
1112
<ComboboxOption
1213
v-for="(action, idx) in filteredActions"
@@ -68,33 +69,40 @@
6869
},
6970
});
7071
71-
const selectedAction = useVModel(props, "modelValue");
72+
const emit = defineEmits(["update:modelValue", "actionSelected"]);
73+
const selectedAction = ref(null);
7274
7375
const inputValue = ref("");
7476
const inputBox = ref();
7577
const inputBoxButton = ref();
7678
const { focused: inputBoxFocused } = useFocus(inputBox);
7779
78-
const emit = defineEmits(["update:modelValue", "quickSelect"]);
79-
8080
const revealActions = () => {
8181
unrefElement(inputBoxButton).click();
8282
};
8383
84-
watch(inputBoxFocused, () => {
85-
if (inputBoxFocused.value) revealActions();
84+
watch(inputBoxFocused, val => {
85+
if (val) revealActions();
8686
else inputValue.value = "";
8787
});
8888
8989
watch(inputValue, (val, oldVal) => {
9090
if (!oldVal) {
9191
const action = props.actions?.find(v => v.shortcut === val);
9292
if (action) {
93-
emit("quickSelect", action);
93+
emit("actionSelected", action);
94+
inputBoxFocused.value = false;
9495
}
9596
}
9697
});
9798
99+
watch(selectedAction, val => {
100+
if (val) {
101+
emit("actionSelected", val);
102+
selectedAction.value = null;
103+
}
104+
});
105+
98106
const filteredActions = computed(() => {
99107
const searchTerm = inputValue.value.toLowerCase();
100108
return (props.actions || []).filter(action => {

frontend/components/global/QuickMenu/Modal.vue

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<template>
2-
<BaseModal v-model="modal" :show-close-button="false">
2+
<BaseModal
3+
v-model="modal"
4+
:show-close-button="false"
5+
:click-outside-to-close="true"
6+
:modal-top="true"
7+
:class="{ 'self-start': true }"
8+
>
39
<div class="relative">
410
<span class="text-neutral-400">{{ $t("components.quick_menu.shortcut_hint") }}</span>
5-
<QuickMenuInput
6-
ref="inputBox"
7-
v-model="selectedAction"
8-
:actions="props.actions || []"
9-
@quick-select="invokeAction"
10-
></QuickMenuInput>
11+
<QuickMenuInput ref="inputBox" :actions="props.actions || []" @action-selected="invokeAction"></QuickMenuInput>
1112
</div>
1213
</BaseModal>
1314
</template>
@@ -28,7 +29,6 @@
2829
});
2930
3031
const modal = useVModel(props, "modelValue");
31-
const selectedAction = ref<QuickMenuAction>();
3232
3333
const inputBox = ref<QuickMenuInputData>({ focused: false, revealActions: () => {} });
3434
@@ -37,7 +37,6 @@
3737
}, 50).start;
3838
3939
const onModalClose = () => {
40-
selectedAction.value = undefined;
4140
inputBox.value.focused = false;
4241
};
4342
@@ -51,8 +50,4 @@
5150
modal.value = false;
5251
useTimeoutFn(action.action, 100).start();
5352
}
54-
55-
watch(selectedAction, action => {
56-
if (action) invokeAction(action);
57-
});
5853
</script>

0 commit comments

Comments
 (0)