cja-phoenix 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cja-phoenix.es.js +2707 -3358
- package/dist/style.css +1 -1
- package/dist/types/components/composite/CjaMenuBar.vue.d.ts +8 -5
- package/dist/types/components/composite/FunnelLayout.vue.d.ts +9 -9
- package/dist/types/components/composite/FunnelSubmit.vue.d.ts +2 -2
- package/dist/types/components/composite/FunnelSummary.vue.d.ts +9 -6
- package/dist/types/components/composite/FunnelTitle.vue.d.ts +1 -1
- package/dist/types/components/composite/JourneyMacroSteps.vue.d.ts +1 -1
- package/dist/types/components/composite/ProductDetails.vue.d.ts +4 -4
- package/dist/types/components/composite/ResultsLayout.vue.d.ts +11 -0
- package/dist/types/components/forms/CheckboxInput.vue.d.ts +8 -5
- package/dist/types/components/forms/FileInput.vue.d.ts +7 -4
- package/dist/types/components/forms/InputToggle.vue.d.ts +11 -7
- package/dist/types/components/forms/NumberInput.vue.d.ts +6 -3
- package/dist/types/components/forms/PhoneInput.vue.d.ts +16 -14
- package/dist/types/components/forms/RadioInput.vue.d.ts +41 -0
- package/dist/types/components/forms/SelectInput.vue.d.ts +18 -17
- package/dist/types/components/forms/SelectionTiles.vue.d.ts +7 -4
- package/dist/types/components/forms/TextInput.vue.d.ts +20 -18
- package/dist/types/components/forms/TileCheckboxInput.vue.d.ts +1 -1
- package/dist/types/components/forms/structure/InputContainer.vue.d.ts +2 -2
- package/dist/types/components/forms/structure/InputError.vue.d.ts +1 -1
- package/dist/types/components/forms/structure/InputTitle.vue.d.ts +1 -1
- package/dist/types/components/index.d.ts +6 -2
- package/dist/types/components/structural/CjaButton.vue.d.ts +8 -5
- package/dist/types/components/structural/CollapseContainer.vue.d.ts +3 -3
- package/dist/types/components/structural/ContentTabs.vue.d.ts +1 -1
- package/dist/types/components/structural/FixedContainer.vue.d.ts +63 -0
- package/dist/types/components/structural/GridContainer.vue.d.ts +9 -6
- package/dist/types/components/structural/GridItem.vue.d.ts +8 -8
- package/dist/types/components/structural/InfoMessage.vue.d.ts +30 -0
- package/dist/types/components/structural/LoadingSpinner.vue.d.ts +1 -1
- package/dist/types/components/structural/Modal.vue.d.ts +3 -3
- package/dist/types/components/structural/Scaffold.vue.d.ts +2 -2
- package/dist/types/stories/Modal.story.vue.d.ts +1 -1
- package/package.json +2 -2
- package/src/components/composite/ResultsLayout.vue +49 -0
- package/src/components/forms/InputToggle.vue +6 -1
- package/src/components/forms/RadioInput.vue +90 -0
- package/src/components/forms/SelectInput.vue +17 -7
- package/src/components/index.ts +9 -1
- package/src/components/structural/CjaButton.vue +1 -1
- package/src/components/structural/CollapseContainer.vue +35 -32
- package/src/components/structural/FixedContainer.vue +87 -0
- package/src/components/structural/InfoMessage.vue +97 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cja-phoenix",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build:dev": "rimraf dist && vue-tsc && vite build -m development",
|
|
6
6
|
"build:link": "rimraf dist && vue-tsc && vite build -m development && npm link",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"vee-validate": "^4.7.2",
|
|
34
34
|
"vite": "^3.0.0",
|
|
35
35
|
"vitepress": "^0.21.6",
|
|
36
|
-
"vue": "^3.
|
|
36
|
+
"vue": "^3.3.4",
|
|
37
37
|
"vue-router": "^4.1.6",
|
|
38
38
|
"vue-tippy": "^6.0.0",
|
|
39
39
|
"vue-tsc": "^1.0.24"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="results-container">
|
|
3
|
+
<slot name="mobile-controls" v-if="!activeViewport.lg"></slot>
|
|
4
|
+
<GridContainer class="results-grid">
|
|
5
|
+
<GridItem :size-lg="3" v-if="activeViewport.lg">
|
|
6
|
+
<div class="btn-container">
|
|
7
|
+
<button class="m-cgg-icon--arrow-back"></button>
|
|
8
|
+
</div>
|
|
9
|
+
<slot name="sidebar"></slot>
|
|
10
|
+
</GridItem>
|
|
11
|
+
<GridItem :size-sm="2" :size-md="4" :size-lg="9">
|
|
12
|
+
<slot name="content"></slot>
|
|
13
|
+
</GridItem>
|
|
14
|
+
</GridContainer>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script lang="ts" setup>
|
|
19
|
+
import { inject } from "vue";
|
|
20
|
+
import GridContainer from "../structural/GridContainer.vue";
|
|
21
|
+
import GridItem from "../structural/GridItem.vue";
|
|
22
|
+
|
|
23
|
+
const activeViewport: any = inject("activeViewport");
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<style lang="scss" scoped>
|
|
27
|
+
.results-container {
|
|
28
|
+
.results-grid {
|
|
29
|
+
padding-top: 24px;
|
|
30
|
+
padding-bottom: 24px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.btn-container {
|
|
34
|
+
button {
|
|
35
|
+
background: none;
|
|
36
|
+
padding: 0;
|
|
37
|
+
border: none;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
font-size: 26px;
|
|
40
|
+
line-height: 37px;
|
|
41
|
+
margin-bottom: 15px;
|
|
42
|
+
|
|
43
|
+
:focus {
|
|
44
|
+
outline: none;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="input-container">
|
|
3
3
|
<div
|
|
4
4
|
class="input-wrapper"
|
|
5
|
-
:class="[`size-${size}`, { active: modelValue }]"
|
|
5
|
+
:class="[`size-${size}`, { active: modelValue, 'full-width': fullWidth }]"
|
|
6
6
|
@click="$emit('update:modelValue', !modelValue)"
|
|
7
7
|
>
|
|
8
8
|
<div class="label">
|
|
@@ -25,6 +25,7 @@ const props = withDefaults(
|
|
|
25
25
|
validation?: any;
|
|
26
26
|
label: string;
|
|
27
27
|
modelValue: boolean;
|
|
28
|
+
fullWidth: boolean;
|
|
28
29
|
error?: string;
|
|
29
30
|
errorDisplay?: boolean;
|
|
30
31
|
}>(),
|
|
@@ -47,6 +48,10 @@ const emit = defineEmits(["update:modelValue"]);
|
|
|
47
48
|
align-items: center;
|
|
48
49
|
gap: 10px;
|
|
49
50
|
|
|
51
|
+
&.full-width {
|
|
52
|
+
justify-content: space-between;
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
.label {
|
|
51
56
|
@include input-title;
|
|
52
57
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="input-container">
|
|
3
|
+
<div class="input-container-radio">
|
|
4
|
+
<label>
|
|
5
|
+
<input
|
|
6
|
+
type="radio"
|
|
7
|
+
:name="name"
|
|
8
|
+
:checked="modelValue == value"
|
|
9
|
+
@change="handleChange"
|
|
10
|
+
/>
|
|
11
|
+
<div class="radio-icon"></div>
|
|
12
|
+
<div class="text-container" v-html="label"></div>
|
|
13
|
+
</label>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<InputError :error="error" v-if="error && errorDisplay" />
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import InputError from "./structure/InputError.vue";
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(
|
|
24
|
+
defineProps<{
|
|
25
|
+
name: string;
|
|
26
|
+
value: any;
|
|
27
|
+
label: string;
|
|
28
|
+
modelValue?: any;
|
|
29
|
+
error?: string;
|
|
30
|
+
errorDisplay?: boolean;
|
|
31
|
+
}>(),
|
|
32
|
+
{
|
|
33
|
+
errorDisplay: true,
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const handleChange = (event: any) => {
|
|
38
|
+
if (event.target.checked) {
|
|
39
|
+
emit("update:modelValue", props.value);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<style lang="scss" scoped>
|
|
47
|
+
.input-container-radio {
|
|
48
|
+
label {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: row;
|
|
51
|
+
align-items: center;
|
|
52
|
+
flex-wrap: nowrap;
|
|
53
|
+
gap: 15px;
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
margin: 0;
|
|
56
|
+
font-weight: 400;
|
|
57
|
+
|
|
58
|
+
input {
|
|
59
|
+
display: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.radio-icon {
|
|
63
|
+
width: 20px;
|
|
64
|
+
height: 20px;
|
|
65
|
+
border: 1px solid #64748b;
|
|
66
|
+
border-radius: 50%;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
input:checked + .radio-icon {
|
|
70
|
+
border: 6px solid #076b9c;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.text-container {
|
|
74
|
+
font-size: 16px;
|
|
75
|
+
line-height: 19px;
|
|
76
|
+
user-select: none;
|
|
77
|
+
|
|
78
|
+
a {
|
|
79
|
+
color: inherit;
|
|
80
|
+
font-weight: 700;
|
|
81
|
+
text-decoration: underline;
|
|
82
|
+
|
|
83
|
+
&:hover {
|
|
84
|
+
text-decoration: none;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
</style>
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
>
|
|
10
10
|
<div
|
|
11
11
|
class="select-toggle"
|
|
12
|
-
:class="[
|
|
12
|
+
:class="[
|
|
13
|
+
`size-${size}`,
|
|
14
|
+
collapsePosition,
|
|
15
|
+
{ open: open, disabled: disabled },
|
|
16
|
+
]"
|
|
13
17
|
@click="toggleCollapse()"
|
|
14
18
|
>
|
|
15
19
|
<span class="select-display">{{ displayValue || placeholder }}</span>
|
|
@@ -44,7 +48,7 @@
|
|
|
44
48
|
></span>
|
|
45
49
|
{{ option.label }}
|
|
46
50
|
</li>
|
|
47
|
-
<li v-if="searchFilter && filteredOptions
|
|
51
|
+
<li v-if="searchFilter && filteredOptions?.length == 0">
|
|
48
52
|
{{ searchFilter.noResults }}
|
|
49
53
|
</li>
|
|
50
54
|
</ul>
|
|
@@ -86,7 +90,7 @@ const props = withDefaults(
|
|
|
86
90
|
id?: InputHTMLAttributes["id"];
|
|
87
91
|
disabled?: InputHTMLAttributes["disabled"];
|
|
88
92
|
modelValue: SelectHTMLAttributes["value"];
|
|
89
|
-
options: SelectOption[];
|
|
93
|
+
options: SelectOption[] | null;
|
|
90
94
|
multiSelect?: boolean;
|
|
91
95
|
searchFilter?: {
|
|
92
96
|
placeholder: string;
|
|
@@ -108,7 +112,7 @@ const inputEl = ref();
|
|
|
108
112
|
const collapseEl = ref();
|
|
109
113
|
const collapsePosition = ref();
|
|
110
114
|
const filteredOptions = computed(() =>
|
|
111
|
-
search.value
|
|
115
|
+
search.value && props.options
|
|
112
116
|
? props.options.filter((opt) =>
|
|
113
117
|
opt.label.toLowerCase().includes(search.value.toLowerCase())
|
|
114
118
|
)
|
|
@@ -127,7 +131,7 @@ defineExpose({ errorMessage, meta, validate });
|
|
|
127
131
|
const emit = defineEmits(["update:modelValue"]);
|
|
128
132
|
|
|
129
133
|
const displayValue = computed(() =>
|
|
130
|
-
inputValue.value
|
|
134
|
+
inputValue.value && props.options
|
|
131
135
|
? props.multiSelect
|
|
132
136
|
? props.options
|
|
133
137
|
.filter((o) => inputValue.value.includes(o.value))
|
|
@@ -193,7 +197,7 @@ const toggleCollapse = () => {
|
|
|
193
197
|
}
|
|
194
198
|
};
|
|
195
199
|
|
|
196
|
-
const calcPosition = (el:
|
|
200
|
+
const calcPosition = (el: any) => {
|
|
197
201
|
const elRect = el.getBoundingClientRect();
|
|
198
202
|
const inputRect = inputEl.value.getBoundingClientRect();
|
|
199
203
|
const position =
|
|
@@ -252,7 +256,13 @@ const selectValue = (value: string) => {
|
|
|
252
256
|
}
|
|
253
257
|
|
|
254
258
|
&.open {
|
|
255
|
-
|
|
259
|
+
&.position-bottom {
|
|
260
|
+
border-radius: 5px 5px 0 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
&.position-top {
|
|
264
|
+
border-radius: 0 0 5px 5px;
|
|
265
|
+
}
|
|
256
266
|
|
|
257
267
|
em {
|
|
258
268
|
transform: rotate(180deg);
|
package/src/components/index.ts
CHANGED
|
@@ -2,19 +2,22 @@ import Modal from "./structural/Modal.vue";
|
|
|
2
2
|
import CjaButton from "./structural/CjaButton.vue";
|
|
3
3
|
import LoadingSpinner from "./structural/LoadingSpinner.vue";
|
|
4
4
|
import ContentTabs from "./structural/ContentTabs.vue";
|
|
5
|
+
import InfoMessage from "./structural/InfoMessage.vue";
|
|
5
6
|
import Scaffold from "./structural/Scaffold.vue";
|
|
6
7
|
import GridContainer from "./structural/GridContainer.vue";
|
|
7
8
|
import GridItem from "./structural/GridItem.vue";
|
|
9
|
+
import CollapseContainer from "./structural/CollapseContainer.vue";
|
|
10
|
+
import FixedContainer from "./structural/FixedContainer.vue";
|
|
8
11
|
|
|
9
12
|
import TextInput from "./forms/TextInput.vue";
|
|
10
13
|
import PhoneInput from "./forms/PhoneInput.vue";
|
|
11
14
|
import CheckboxInput from "./forms/CheckboxInput.vue";
|
|
15
|
+
import RadioInput from "./forms/RadioInput.vue";
|
|
12
16
|
import TileCheckboxInput from "./forms/TileCheckboxInput.vue";
|
|
13
17
|
import SelectInput from "./forms/SelectInput.vue";
|
|
14
18
|
import FileInput from "./forms/FileInput.vue";
|
|
15
19
|
import NumberInput from "./forms/NumberInput.vue";
|
|
16
20
|
import InputToggle from "./forms/InputToggle.vue";
|
|
17
|
-
import CollapseContainer from "./structural/CollapseContainer.vue";
|
|
18
21
|
import SelectionTiles from "./forms/SelectionTiles.vue";
|
|
19
22
|
|
|
20
23
|
import JourneyMacroSteps from "./composite/JourneyMacroSteps.vue";
|
|
@@ -22,6 +25,7 @@ import FunnelLayout from "./composite/FunnelLayout.vue";
|
|
|
22
25
|
import FunnelSubmit from "./composite/FunnelSubmit.vue";
|
|
23
26
|
import FunnelSummary from "./composite/FunnelSummary.vue";
|
|
24
27
|
import FunnelTitle from "./composite/FunnelTitle.vue";
|
|
28
|
+
import ResultsLayout from "./composite/ResultsLayout.vue";
|
|
25
29
|
import ProductDetails from "./composite/ProductDetails.vue";
|
|
26
30
|
import CjaMenuBar from "./composite/CjaMenuBar.vue";
|
|
27
31
|
|
|
@@ -30,6 +34,7 @@ export {
|
|
|
30
34
|
CjaButton,
|
|
31
35
|
TextInput,
|
|
32
36
|
PhoneInput,
|
|
37
|
+
RadioInput,
|
|
33
38
|
CheckboxInput,
|
|
34
39
|
TileCheckboxInput,
|
|
35
40
|
NumberInput,
|
|
@@ -50,4 +55,7 @@ export {
|
|
|
50
55
|
FunnelTitle,
|
|
51
56
|
JourneyMacroSteps,
|
|
52
57
|
CjaMenuBar,
|
|
58
|
+
FixedContainer,
|
|
59
|
+
ResultsLayout,
|
|
60
|
+
InfoMessage,
|
|
53
61
|
};
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="collapse-container">
|
|
3
|
-
<div
|
|
4
|
-
class="collapse-header"
|
|
5
|
-
@click="active = !active"
|
|
6
|
-
:class="{ active: active }"
|
|
7
|
-
>
|
|
2
|
+
<div class="collapse-container" :class="{ active: active }">
|
|
3
|
+
<div class="collapse-header" @click="active = !active">
|
|
8
4
|
<div class="header-wrapper">
|
|
9
5
|
<slot name="header"></slot>
|
|
10
6
|
</div>
|
|
@@ -14,13 +10,14 @@
|
|
|
14
10
|
name="slide"
|
|
15
11
|
@before-enter="setHeightZero"
|
|
16
12
|
@enter="setHeightSize"
|
|
13
|
+
@after-enter="clearHeight"
|
|
17
14
|
@leave="setHeightZero"
|
|
18
15
|
>
|
|
19
16
|
<div
|
|
20
17
|
v-show="active"
|
|
21
18
|
ref="contentContainer"
|
|
22
19
|
class="content-container"
|
|
23
|
-
:
|
|
20
|
+
:style="{ height: containerHeight, overflow: containerOverflow }"
|
|
24
21
|
>
|
|
25
22
|
<div ref="contentWrapper" class="content-wrapper">
|
|
26
23
|
<slot name="content"></slot>
|
|
@@ -43,11 +40,13 @@ const props = defineProps<{
|
|
|
43
40
|
const active = ref(props.defaultActive);
|
|
44
41
|
const contentContainer = ref();
|
|
45
42
|
const contentWrapper = ref();
|
|
43
|
+
const containerHeight = ref();
|
|
44
|
+
const containerOverflow = ref();
|
|
46
45
|
|
|
47
46
|
const setHeightSize = () => {
|
|
48
47
|
requestAnimationFrame(() => {
|
|
49
48
|
if (contentContainer.value && contentWrapper.value) {
|
|
50
|
-
|
|
49
|
+
containerHeight.value = `${contentWrapper.value.clientHeight}px`;
|
|
51
50
|
|
|
52
51
|
if (active.value && props.scrollToContent) {
|
|
53
52
|
setTimeout(() => {
|
|
@@ -58,24 +57,24 @@ const setHeightSize = () => {
|
|
|
58
57
|
});
|
|
59
58
|
}, 250);
|
|
60
59
|
}
|
|
61
|
-
|
|
62
|
-
setTimeout(() => {
|
|
63
|
-
contentContainer.value.style.height = "";
|
|
64
|
-
contentContainer.value.style.overflow = "visible";
|
|
65
|
-
}, 200);
|
|
66
60
|
}
|
|
67
61
|
});
|
|
68
62
|
};
|
|
69
63
|
|
|
70
64
|
const setHeightZero = () => {
|
|
71
|
-
|
|
65
|
+
containerHeight.value = `${contentWrapper.value.clientHeight}px`;
|
|
72
66
|
|
|
73
67
|
requestAnimationFrame(() => {
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
containerHeight.value = "0";
|
|
69
|
+
containerOverflow.value = "";
|
|
76
70
|
});
|
|
77
71
|
};
|
|
78
72
|
|
|
73
|
+
const clearHeight = () => {
|
|
74
|
+
containerHeight.value = "";
|
|
75
|
+
containerOverflow.value = "visible";
|
|
76
|
+
};
|
|
77
|
+
|
|
79
78
|
onMounted(() => {
|
|
80
79
|
if (props.defaultActive) {
|
|
81
80
|
setHeightSize();
|
|
@@ -90,26 +89,30 @@ onUnmounted(() => {
|
|
|
90
89
|
</script>
|
|
91
90
|
|
|
92
91
|
<style lang="scss" scoped>
|
|
93
|
-
.collapse-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
.collapse-container {
|
|
93
|
+
.collapse-header {
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: row;
|
|
96
|
+
align-items: center;
|
|
97
|
+
justify-content: space-between;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
user-select: none;
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
> span {
|
|
102
|
+
transition: all 0.2s linear;
|
|
103
|
+
}
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
.content-container {
|
|
107
|
+
box-sizing: border-box;
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
transition: all 0.2s linear;
|
|
107
110
|
}
|
|
108
|
-
}
|
|
109
111
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
&.active {
|
|
113
|
+
.collapse-header > span {
|
|
114
|
+
transform: rotate(180deg);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
114
117
|
}
|
|
115
118
|
</style>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="fixed-container"
|
|
4
|
+
:style="{ height: fixedContainerHeight }"
|
|
5
|
+
ref="fixedContainer"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
class="fixed-wrapper"
|
|
9
|
+
:class="{ 'position-fixed': positionFixed }"
|
|
10
|
+
:style="{ ...size, ...position }"
|
|
11
|
+
ref="fixedWrapper"
|
|
12
|
+
>
|
|
13
|
+
<slot></slot>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script lang="ts" setup>
|
|
19
|
+
import { onUnmounted, onMounted } from "vue";
|
|
20
|
+
import { ref } from "vue";
|
|
21
|
+
|
|
22
|
+
const props = withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
scrollThreshold?: number;
|
|
25
|
+
fixWidth?: boolean;
|
|
26
|
+
size?: {
|
|
27
|
+
height?: string;
|
|
28
|
+
width?: string;
|
|
29
|
+
};
|
|
30
|
+
position?: {
|
|
31
|
+
left?: string;
|
|
32
|
+
top?: string;
|
|
33
|
+
right?: string;
|
|
34
|
+
bottom?: string;
|
|
35
|
+
};
|
|
36
|
+
}>(),
|
|
37
|
+
{
|
|
38
|
+
scrollThreshold: 0,
|
|
39
|
+
fixWidth: true,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const positionFixed = ref(false);
|
|
44
|
+
const fixedContainer = ref();
|
|
45
|
+
const fixedContainerHeight = ref("");
|
|
46
|
+
const fixedWrapper = ref();
|
|
47
|
+
|
|
48
|
+
const fixPosition = () => {
|
|
49
|
+
if (fixedContainer.value) {
|
|
50
|
+
positionFixed.value =
|
|
51
|
+
window.scrollY > fixedContainer.value.offsetTop + props.scrollThreshold;
|
|
52
|
+
|
|
53
|
+
fixedContainerHeight.value = positionFixed.value
|
|
54
|
+
? `${fixedWrapper.value.clientHeight}px`
|
|
55
|
+
: "";
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const setWidth = () => {
|
|
60
|
+
fixedWrapper.value.style.maxWidth = `${fixedContainer.value.offsetWidth}px`;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
onMounted(() => {
|
|
64
|
+
window.addEventListener("scroll", fixPosition);
|
|
65
|
+
fixPosition();
|
|
66
|
+
|
|
67
|
+
if (props.fixWidth) {
|
|
68
|
+
window.addEventListener("resize", setWidth);
|
|
69
|
+
setWidth();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
onUnmounted(() => {
|
|
74
|
+
window.removeEventListener("scroll", fixPosition);
|
|
75
|
+
window.removeEventListener("resize", setWidth);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
defineExpose({ positionFixed });
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<style lang="scss" scoped>
|
|
82
|
+
.fixed-wrapper {
|
|
83
|
+
&.position-fixed {
|
|
84
|
+
position: fixed;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="info-message"
|
|
4
|
+
:class="[
|
|
5
|
+
`color-${color}`,
|
|
6
|
+
{ 'has-icon': $slots.icon, 'has-toggle': toggle },
|
|
7
|
+
]"
|
|
8
|
+
>
|
|
9
|
+
<div class="icon-container" v-if="$slots.icon">
|
|
10
|
+
<slot name="icon"></slot>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="text-container">
|
|
13
|
+
<h4 v-if="title">{{ title }}</h4>
|
|
14
|
+
<p v-if="description" v-html="description"></p>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="btn-container" v-if="toggle">
|
|
17
|
+
<button class="m-cgg-icon--cross2" @click="$emit('btn:close')"></button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script lang="ts" setup>
|
|
23
|
+
defineProps<{
|
|
24
|
+
title?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
toggle?: boolean;
|
|
27
|
+
color: "blue" | "green";
|
|
28
|
+
}>();
|
|
29
|
+
|
|
30
|
+
defineEmits(["btn:close"]);
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<style lang="scss" scoped>
|
|
34
|
+
.info-message {
|
|
35
|
+
display: grid;
|
|
36
|
+
grid-template-columns: 1fr;
|
|
37
|
+
gap: 16px;
|
|
38
|
+
padding: 16px 24px;
|
|
39
|
+
border: 2px solid #000;
|
|
40
|
+
border-radius: 16px;
|
|
41
|
+
|
|
42
|
+
&.has-icon {
|
|
43
|
+
grid-template-columns: auto 1fr;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&.has-toggle {
|
|
47
|
+
grid-template-columns: 1fr 18px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&.has-icon.has-toggle {
|
|
51
|
+
grid-template-columns: auto 1fr 18px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&.color-green {
|
|
55
|
+
background-color: #f8faf5;
|
|
56
|
+
border-color: #c4dab1;
|
|
57
|
+
color: #56924b;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&.color-blue {
|
|
61
|
+
background-color: #f4f9fc;
|
|
62
|
+
border-color: #076b9c;
|
|
63
|
+
color: #076b9c;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.text-container {
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: 15px;
|
|
70
|
+
|
|
71
|
+
h4 {
|
|
72
|
+
font-weight: 700;
|
|
73
|
+
font-size: 16px;
|
|
74
|
+
line-height: 20px;
|
|
75
|
+
margin: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
p {
|
|
79
|
+
font-size: 13px;
|
|
80
|
+
line-height: 17px;
|
|
81
|
+
margin: 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.btn-container {
|
|
86
|
+
button {
|
|
87
|
+
padding: 0;
|
|
88
|
+
border: none;
|
|
89
|
+
font-size: 18px;
|
|
90
|
+
line-height: 18px;
|
|
91
|
+
color: inherit;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
background: none;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
</style>
|