Skip to content

Commit d02e94c

Browse files
vittoriaThinkstwleightond
authored andcommitted
Add animation Download button, fix base-select, fix validation
1 parent 23be5a2 commit d02e94c

File tree

5 files changed

+107
-15
lines changed

5 files changed

+107
-15
lines changed

frontend_vue/src/components/base/BaseDownloadIconButton.vue

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,94 @@
1515
:disabled="props.disabled"
1616
download
1717
:href="props.url"
18+
@click="downloadContent"
1819
>
1920
<span class="sr-only">{{ props.alt }} Download</span>
21+
2022
<span
23+
v-tooltip="{
24+
content: tooltipText,
25+
shown: isTriggered,
26+
triggers: tooltipTriggers,
27+
}"
2128
:class="{ hidden: props.disabled }"
2229
class="absolute w-[2rem] rounded-full h-[2rem] bg-green top-[-.5rem] right-[-.5rem] flex items-center justify-center text-white"
23-
><font-awesome-icon icon="arrow-down"></font-awesome-icon
24-
></span>
30+
>
31+
<Transition
32+
name="fade"
33+
mode="out-in"
34+
>
35+
<font-awesome-icon
36+
v-if="!isTriggered"
37+
icon="arrow-down"
38+
></font-awesome-icon>
39+
<font-awesome-icon
40+
v-else
41+
aria-hidden="true"
42+
icon="check"
43+
></font-awesome-icon>
44+
</Transition>
45+
</span>
2546
</a>
2647
</div>
2748
</template>
2849

2950
<script lang="ts" setup>
51+
import { ref } from 'vue';
52+
3053
const props = defineProps<{
3154
url?: string;
3255
alt?: string;
3356
disabled?: boolean;
3457
}>();
58+
59+
const tooltipText = ref('Download');
60+
const isTriggered = ref(false);
61+
const tooltipTriggers = ref(['hover', 'focus']);
62+
63+
function delay(ms: number) {
64+
return new Promise((resolve) => setTimeout(resolve, ms));
65+
}
66+
67+
// 1. prevents UI from jumping when tooltip content changes
68+
// 2. shows tooltip when content is downloaded
69+
async function showTooltip() {
70+
await delay(150);
71+
tooltipTriggers.value = [];
72+
isTriggered.value = true;
73+
tooltipText.value = 'Download started!';
74+
// vTooltip sets a default delay of 1.5s
75+
await delay(1500);
76+
isTriggered.value = false;
77+
tooltipTriggers.value = ['hover', 'focus'];
78+
await delay(150);
79+
tooltipText.value = 'Download';
80+
}
81+
82+
function downloadContent() {
83+
showTooltip();
84+
}
3585
</script>
86+
87+
<style scoped>
88+
@keyframes bounce {
89+
40% {
90+
transform: scale(1.2);
91+
}
92+
80% {
93+
transform: scale(0.8);
94+
}
95+
100% {
96+
transform: scale(1);
97+
}
98+
}
99+
100+
.fade-enter-active,
101+
.fade-leave-active {
102+
animation: bounce 350ms;
103+
}
104+
.fade-enter,
105+
.fade-leave-to {
106+
transform: scale(1);
107+
}
108+
</style>

frontend_vue/src/components/base/BaseFormSelect.vue

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
<template>
22
<label
33
:for="id"
4-
class="mt-8 ml-4 mb-8 font-semibold leading-3"
4+
class="mt-8 ml-4 font-semibold"
55
>{{ label }}</label
66
>
7-
<p
8-
v-if="errorMessage"
9-
class="text-xs text-red ml-[4px] leading-[0px]"
10-
>
11-
{{ errorMessage }}
12-
</p>
7+
138
<v-select
149
:id="id"
1510
class="v-select"
11+
:class="{ 'invalid': errorMessage }"
12+
:style="`--vs-dropdown-height: ${props.height}`"
1613
:options="options"
17-
:searchable="(searchable == null) ? false : searchable"
14+
:searchable="searchable"
1815
:placeholder="placeholder"
1916
@input="handleSelectOption"
2017
@blur="handleBlur"
@@ -43,6 +40,14 @@
4340
></slot>
4441
</template>
4542
</v-select>
43+
<div class="h-8 mt-4 ml-16">
44+
<p
45+
v-if="errorMessage"
46+
class="text-xs text-red leading-[0px]"
47+
>
48+
{{ errorMessage }}
49+
</p>
50+
</div>
4651
</template>
4752

4853
<script setup lang="ts">
@@ -58,12 +63,13 @@ const props = defineProps<{
5863
options: string[] | SelectOption[];
5964
placeholder?: string;
6065
searchable?: boolean;
66+
height?: string;
6167
}>();
6268
6369
const id = toRef(props, 'id');
6470
const emits = defineEmits(['selectOption']);
6571
66-
const { value, errorMessage, handleChange, handleBlur } = useField(id);
72+
const { errorMessage, handleChange, handleBlur } = useField(id);
6773
6874
onMounted(() => {
6975
// When selecting the v-select, focus is set on the inner search input
@@ -87,7 +93,8 @@ function handleSelectOption(value: string | SelectOption) {
8793
}
8894
</script>
8995

90-
<style>
96+
<style lang="scss">
97+
9198
.focus-visible {
9299
outline: 2px solid;
93100
outline-color: hsl(191, 96%, 36%);
@@ -97,11 +104,12 @@ function handleSelectOption(value: string | SelectOption) {
97104
@apply text-grey-400;
98105
}
99106
.v-select .vs__dropdown-toggle {
100-
@apply px-16 py-8 border resize-none shadow-inner-shadow-grey rounded-3xl border-grey-400 bg-white outline-offset-1;
107+
@apply px-16 py-[0.4rem] border resize-none shadow-inner-shadow-grey rounded-3xl border-grey-400 bg-white outline-offset-1;
101108
}
102109
103110
.v-select .vs__dropdown-menu {
104-
@apply mt-[8px] bg-white shadow-none border-grey-100 rounded-xl;
111+
@apply mt-[8px] bg-white shadow-none border-grey-300 rounded-xl;
112+
height: var(--vs-dropdown-height);
105113
}
106114
107115
.v-select .vs__clear {
@@ -118,4 +126,8 @@ function handleSelectOption(value: string | SelectOption) {
118126
.v-select .vs__dropdown-option--highlight {
119127
@apply bg-green-500 text-white;
120128
}
129+
130+
.v-select.invalid > .vs__dropdown-toggle {
131+
@apply border border-red;
132+
}
121133
</style>

frontend_vue/src/components/tokens/idp_app/GenerateTokenForm.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<BaseGenerateTokenSettings setting-type="Canarytoken">
3+
<div class="flex flex-col gap-8">
34
<div class="flex flex-col gap-8 mb-8">
45
<BaseFormSelect
56
id="app_type"
@@ -8,6 +9,7 @@
89
required
910
:options="IDP_OPTIONS"
1011
:searchable="true"
12+
height="220px"
1113
@select-option="handleSelectedApp"
1214
>
1315
<template #option="{ option }">
@@ -40,6 +42,7 @@
4042
placeholder="https://www.example.com"
4143
full-width
4244
/>
45+
</div>
4346
</BaseGenerateTokenSettings>
4447
<GenerateTokenSettingsNotifications
4548
memo-helper-example="Fake Salesforce app in Okta"

frontend_vue/src/utils/formValidators.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ export const formValidators: ValidateSchemaType = {
212212
schema: Yup.object().shape({
213213
...validationNotificationSettings,
214214
redirect_url: Yup.string(),
215+
app_type: Yup.string().required('App type is required'),
215216
}),
216217
},
217218
};

frontend_vue/src/views/ComponentPreview.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,10 @@
239239
<hr class="my-24" />
240240
<h1 class="pb-16">Incident details</h1>
241241
<div class="flex flex-col gap-16 px-16 py-16 mb-32 bg-grey-100">
242-
<IncidentDetails :hit-alert="alertSample" :showingMap="true" />
242+
<IncidentDetails
243+
:hit-alert="alertSample"
244+
:showingMap="true"
245+
/>
243246
</div>
244247
<div class="flex flex-col gap-16 mb-32">
245248
<h1>Upload File</h1>

0 commit comments

Comments
 (0)