@energysage/es-ds-components 0.0.1 → 3.0.0-alpha.10
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/.eslintignore +9 -0
- package/.eslintrc.json +3 -0
- package/.prettierrc.json +10 -0
- package/README.md +0 -3
- package/components/es-accordion-list.vue +117 -0
- package/components/es-accordion.vue +7 -0
- package/components/es-badge.vue +20 -0
- package/components/es-breadcrumbs.vue +73 -0
- package/components/es-button.vue +122 -0
- package/components/es-card.vue +64 -0
- package/components/es-carousel.vue +316 -0
- package/components/es-col.vue +27 -0
- package/components/es-collapse.vue +83 -0
- package/components/es-container.vue +14 -0
- package/components/es-cta-banner.vue +95 -0
- package/components/es-cta-card.vue +60 -0
- package/components/es-data-table-simple.vue +73 -0
- package/components/es-data-table.vue +128 -0
- package/components/es-error-page.vue +120 -0
- package/components/es-file-input.vue +334 -0
- package/components/es-file-preview-modal.vue +61 -0
- package/components/es-footer.vue +163 -0
- package/components/es-form-checkbox.vue +40 -0
- package/components/es-form-input.vue +130 -0
- package/components/es-form-msg.vue +81 -0
- package/components/es-form-radio-card.vue +57 -0
- package/components/es-form-radio-cards.vue +78 -0
- package/components/es-form-textarea.vue +124 -0
- package/components/es-form.vue +16 -0
- package/components/es-modal.vue +103 -0
- package/components/es-nav-bar-account-menu.vue +70 -0
- package/components/es-nav-bar-featured-article.vue +60 -0
- package/components/es-nav-bar-link.vue +27 -0
- package/components/es-nav-bar-product-menu.vue +219 -0
- package/components/es-nav-bar-top-level-menu.vue +194 -0
- package/components/es-nav-bar-topic-menu.vue +197 -0
- package/components/es-nav-bar.vue +411 -0
- package/components/es-pagination.vue +67 -0
- package/components/es-popover.vue +113 -0
- package/components/es-progress-circle.vue +81 -0
- package/components/es-progress.vue +36 -0
- package/components/es-radio-button-group.vue +53 -0
- package/components/es-radio-button.vue +57 -0
- package/components/es-rating.vue +120 -0
- package/components/es-reviews-io-card-carousel.vue +279 -0
- package/components/es-row.vue +5 -0
- package/components/es-skeleton-img.vue +38 -0
- package/components/es-skeleton-wrapper.vue +17 -0
- package/components/es-skeleton.vue +97 -0
- package/components/es-slider.vue +218 -0
- package/components/es-spinner.vue +22 -0
- package/components/es-support-card.vue +150 -0
- package/components/es-support.vue +66 -0
- package/components/es-tab.vue +7 -0
- package/components/es-tabs.vue +70 -0
- package/components/es-verification-code.vue +94 -0
- package/components/es-video.vue +60 -0
- package/components/es-view-more.vue +64 -0
- package/components/es-zip-code-form.vue +204 -0
- package/components/icon/arrow-clockwise.vue +51 -0
- package/components/icon/arrow-counter-clockwise.vue +37 -0
- package/components/icon/arrow-cycle.vue +43 -0
- package/components/icon/arrow-left.vue +39 -0
- package/components/icon/arrow-right.vue +39 -0
- package/components/icon/arrow-up.vue +39 -0
- package/components/icon/arrow.vue +68 -0
- package/components/icon/bank.vue +38 -0
- package/components/icon/battery.vue +40 -0
- package/components/icon/bell.vue +42 -0
- package/components/icon/block.vue +46 -0
- package/components/icon/bolt.vue +38 -0
- package/components/icon/business.vue +42 -0
- package/components/icon/calculator.vue +37 -0
- package/components/icon/calendar.vue +46 -0
- package/components/icon/cart.vue +46 -0
- package/components/icon/chat-add.vue +44 -0
- package/components/icon/chat-approve.vue +42 -0
- package/components/icon/chat-bubble.vue +40 -0
- package/components/icon/chat-dots.vue +42 -0
- package/components/icon/check.vue +39 -0
- package/components/icon/chevron-down.vue +39 -0
- package/components/icon/chevron-horizontal.vue +39 -0
- package/components/icon/chevron-left.vue +39 -0
- package/components/icon/chevron-right.vue +39 -0
- package/components/icon/chevron-up.vue +39 -0
- package/components/icon/circle-alert.vue +46 -0
- package/components/icon/circle-check.vue +46 -0
- package/components/icon/circle-chevron-down.vue +47 -0
- package/components/icon/circle-chevron-left.vue +46 -0
- package/components/icon/circle-chevron-right.vue +46 -0
- package/components/icon/circle-chevron-up.vue +46 -0
- package/components/icon/circle-minus.vue +46 -0
- package/components/icon/circle-plus.vue +46 -0
- package/components/icon/circle-x.vue +46 -0
- package/components/icon/circle.vue +42 -0
- package/components/icon/clock.vue +46 -0
- package/components/icon/community-solar.vue +37 -0
- package/components/icon/companies.vue +43 -0
- package/components/icon/contact-us.vue +37 -0
- package/components/icon/copy.vue +45 -0
- package/components/icon/credit-card.vue +37 -0
- package/components/icon/document.vue +45 -0
- package/components/icon/electric-vehicle.vue +37 -0
- package/components/icon/electricity-circle.vue +39 -0
- package/components/icon/envelope.vue +45 -0
- package/components/icon/es-leaf.vue +39 -0
- package/components/icon/eye.vue +41 -0
- package/components/icon/facebook.vue +41 -0
- package/components/icon/file-doc.vue +72 -0
- package/components/icon/file-docx.vue +72 -0
- package/components/icon/file-pdf.vue +72 -0
- package/components/icon/flag.vue +37 -0
- package/components/icon/folder.vue +41 -0
- package/components/icon/gear.vue +37 -0
- package/components/icon/gift.vue +37 -0
- package/components/icon/hamburger.vue +38 -0
- package/components/icon/heart.vue +39 -0
- package/components/icon/heat-pump.vue +41 -0
- package/components/icon/image.vue +45 -0
- package/components/icon/info-blog-post.vue +47 -0
- package/components/icon/info.vue +45 -0
- package/components/icon/instagram.vue +49 -0
- package/components/icon/light-bulb.vue +36 -0
- package/components/icon/link-out.vue +38 -0
- package/components/icon/linkedin.vue +41 -0
- package/components/icon/location.vue +45 -0
- package/components/icon/lock-off.vue +45 -0
- package/components/icon/lock-on.vue +48 -0
- package/components/icon/marketplace.vue +43 -0
- package/components/icon/minus.vue +38 -0
- package/components/icon/money-bag.vue +37 -0
- package/components/icon/money.vue +35 -0
- package/components/icon/open-envelope.vue +45 -0
- package/components/icon/paper.vue +45 -0
- package/components/icon/payback.vue +37 -0
- package/components/icon/pencil.vue +45 -0
- package/components/icon/person-add.vue +41 -0
- package/components/icon/person-check.vue +41 -0
- package/components/icon/person-cross.vue +41 -0
- package/components/icon/person.vue +41 -0
- package/components/icon/phone.vue +41 -0
- package/components/icon/play.vue +41 -0
- package/components/icon/plus.vue +38 -0
- package/components/icon/roof.vue +37 -0
- package/components/icon/rooftop-solar.vue +37 -0
- package/components/icon/saving.vue +37 -0
- package/components/icon/search.vue +43 -0
- package/components/icon/settings-horizontal.vue +57 -0
- package/components/icon/settings-vertical.vue +57 -0
- package/components/icon/shield-with-check.vue +38 -0
- package/components/icon/shield.vue +41 -0
- package/components/icon/shopping-bag.vue +39 -0
- package/components/icon/solar.vue +37 -0
- package/components/icon/sound-down.vue +45 -0
- package/components/icon/sound-off.vue +41 -0
- package/components/icon/sound-on.vue +41 -0
- package/components/icon/sound-up.vue +41 -0
- package/components/icon/star-empty.vue +38 -0
- package/components/icon/star-full.vue +36 -0
- package/components/icon/star-half.vue +55 -0
- package/components/icon/state-ak.vue +53 -0
- package/components/icon/state-al.vue +38 -0
- package/components/icon/state-ar.vue +38 -0
- package/components/icon/state-az.vue +38 -0
- package/components/icon/state-ca.vue +38 -0
- package/components/icon/state-co.vue +38 -0
- package/components/icon/state-ct.vue +38 -0
- package/components/icon/state-dc.vue +52 -0
- package/components/icon/state-de.vue +38 -0
- package/components/icon/state-fl.vue +38 -0
- package/components/icon/state-ga.vue +38 -0
- package/components/icon/state-hi.vue +59 -0
- package/components/icon/state-ia.vue +38 -0
- package/components/icon/state-id.vue +38 -0
- package/components/icon/state-il.vue +38 -0
- package/components/icon/state-in.vue +38 -0
- package/components/icon/state-ks.vue +38 -0
- package/components/icon/state-ky.vue +38 -0
- package/components/icon/state-la.vue +38 -0
- package/components/icon/state-ma.vue +38 -0
- package/components/icon/state-md.vue +39 -0
- package/components/icon/state-me.vue +38 -0
- package/components/icon/state-mi.vue +38 -0
- package/components/icon/state-mn.vue +38 -0
- package/components/icon/state-mo.vue +38 -0
- package/components/icon/state-ms.vue +38 -0
- package/components/icon/state-mt.vue +38 -0
- package/components/icon/state-nc.vue +38 -0
- package/components/icon/state-nd.vue +38 -0
- package/components/icon/state-ne.vue +38 -0
- package/components/icon/state-nh.vue +38 -0
- package/components/icon/state-nj.vue +37 -0
- package/components/icon/state-nm.vue +38 -0
- package/components/icon/state-nv.vue +38 -0
- package/components/icon/state-ny.vue +41 -0
- package/components/icon/state-oh.vue +38 -0
- package/components/icon/state-ok.vue +38 -0
- package/components/icon/state-or.vue +38 -0
- package/components/icon/state-pa.vue +38 -0
- package/components/icon/state-ri.vue +38 -0
- package/components/icon/state-sc.vue +38 -0
- package/components/icon/state-sd.vue +38 -0
- package/components/icon/state-tn.vue +38 -0
- package/components/icon/state-tx.vue +38 -0
- package/components/icon/state-ut.vue +38 -0
- package/components/icon/state-va.vue +38 -0
- package/components/icon/state-vt.vue +38 -0
- package/components/icon/state-wa.vue +38 -0
- package/components/icon/state-wi.vue +38 -0
- package/components/icon/state-wv.vue +38 -0
- package/components/icon/state-wy.vue +38 -0
- package/components/icon/thumbs-up.vue +39 -0
- package/components/icon/trash-can.vue +41 -0
- package/components/icon/tree.vue +37 -0
- package/components/icon/twitter.vue +43 -0
- package/components/icon/upload.vue +41 -0
- package/components/icon/verified.vue +40 -0
- package/components/icon/video-play.vue +41 -0
- package/components/icon/wifi.vue +38 -0
- package/components/icon/x.vue +38 -0
- package/components/icon/youtube.vue +45 -0
- package/composables/forms.ts +124 -0
- package/nuxt.config.ts +83 -1
- package/package.json +47 -13
- package/tsconfig.json +4 -0
- package/types/es-carousel.ts +12 -0
- package/types/index.ts +1 -0
- package/utils/forms.ts +120 -0
- package/utils/get-es-footer-content.ts +90 -0
- package/utils/get-es-nav-bar-account-content.ts +55 -0
- package/utils/get-es-nav-bar-global-content.ts +482 -0
- package/utils/mime-type-finder.ts +48 -0
- package/utils/vuelidate-keys.ts +39 -0
- package/components/TestComponent.vue +0 -5
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
constrained: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false,
|
|
6
|
+
},
|
|
7
|
+
imageAltText: {
|
|
8
|
+
type: String,
|
|
9
|
+
default: '',
|
|
10
|
+
},
|
|
11
|
+
imageSrc: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: '',
|
|
14
|
+
},
|
|
15
|
+
primaryCtaTarget: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: '_blank',
|
|
18
|
+
},
|
|
19
|
+
primaryCtaText: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
primaryCtaUrl: {
|
|
24
|
+
type: String,
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
secondaryCtaTarget: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: '_blank',
|
|
30
|
+
},
|
|
31
|
+
secondaryCtaText: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: '',
|
|
34
|
+
},
|
|
35
|
+
secondaryCtaUrl: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: '',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const showSecondaryCta = computed(() => {
|
|
42
|
+
return !!props.secondaryCtaText && !!props.secondaryCtaUrl;
|
|
43
|
+
});
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<es-card
|
|
48
|
+
class="p-100 px-sm-200 text-center text-lg-left"
|
|
49
|
+
:class="{
|
|
50
|
+
'px-md-100 py-md-200': constrained,
|
|
51
|
+
'px-md-300': !constrained,
|
|
52
|
+
}">
|
|
53
|
+
<es-row class="align-items-lg-center justify-content-xl-between">
|
|
54
|
+
<es-col
|
|
55
|
+
class="EsSupportCard-contentColumn d-flex flex-column justify-content-lg-center position-relative"
|
|
56
|
+
:class="{ 'pr-lg-0': constrained }"
|
|
57
|
+
cols="12"
|
|
58
|
+
lg="8">
|
|
59
|
+
<!-- h2 is first in DOM order for semantics; using order utility classes to rearrange -->
|
|
60
|
+
<h2
|
|
61
|
+
class="align-items-center d-flex font-size-300 justify-content-center justify-content-lg-start mb-150 mb-lg-100 order-1"
|
|
62
|
+
:class="{
|
|
63
|
+
'pl-lg-100': constrained,
|
|
64
|
+
'pl-lg-200': !constrained,
|
|
65
|
+
}">
|
|
66
|
+
<slot name="headline" />
|
|
67
|
+
</h2>
|
|
68
|
+
<div class="EsSupportCard-imageContainer mb-150 mb-lg-0 order-0">
|
|
69
|
+
<slot name="image">
|
|
70
|
+
<nuxt-img
|
|
71
|
+
v-if="imageAltText && imageSrc"
|
|
72
|
+
:alt="imageAltText"
|
|
73
|
+
class="bg-teal-200 rounded-circle"
|
|
74
|
+
height="100px"
|
|
75
|
+
:src="imageSrc"
|
|
76
|
+
width="100px" />
|
|
77
|
+
</slot>
|
|
78
|
+
</div>
|
|
79
|
+
<!--
|
|
80
|
+
we are giving 'EsSupportCard-description' a unique class (that we don't use directly in this
|
|
81
|
+
component) for consuming applications to use in targeting ::v-deep styles on <p> tags to remove
|
|
82
|
+
the natural <p> bottom margin, for example.
|
|
83
|
+
|
|
84
|
+
e.g. a CMS rich text component may generate a <p> tag within this that automatically
|
|
85
|
+
gets a bottom margin, which throws off the vertical centering. we are intentionally leaving
|
|
86
|
+
the removal of that bottom margin up to consuming applications rather than removing it on all
|
|
87
|
+
<p> tags within this element, in case they may want two <p> tags or any other markup in here.
|
|
88
|
+
-->
|
|
89
|
+
<div
|
|
90
|
+
class="EsSupportCard-description font-size-75 font-size-lg-100 mb-150 mb-lg-0 order-2"
|
|
91
|
+
:class="{
|
|
92
|
+
'pl-lg-100': constrained,
|
|
93
|
+
'pl-lg-200': !constrained,
|
|
94
|
+
}">
|
|
95
|
+
<slot name="description" />
|
|
96
|
+
</div>
|
|
97
|
+
</es-col>
|
|
98
|
+
<es-col
|
|
99
|
+
cols="12"
|
|
100
|
+
lg="4"
|
|
101
|
+
xxl="3">
|
|
102
|
+
<es-button
|
|
103
|
+
class="w-100"
|
|
104
|
+
:class="{ 'mb-100': showSecondaryCta }"
|
|
105
|
+
:href="primaryCtaUrl"
|
|
106
|
+
:target="primaryCtaTarget"
|
|
107
|
+
variant="primary">
|
|
108
|
+
{{ primaryCtaText }}
|
|
109
|
+
</es-button>
|
|
110
|
+
<es-button
|
|
111
|
+
v-if="showSecondaryCta"
|
|
112
|
+
class="w-100"
|
|
113
|
+
:href="secondaryCtaUrl"
|
|
114
|
+
outline
|
|
115
|
+
:target="secondaryCtaTarget"
|
|
116
|
+
variant="primary">
|
|
117
|
+
{{ secondaryCtaText }}
|
|
118
|
+
</es-button>
|
|
119
|
+
</es-col>
|
|
120
|
+
</es-row>
|
|
121
|
+
</es-card>
|
|
122
|
+
</template>
|
|
123
|
+
|
|
124
|
+
<style lang="scss">
|
|
125
|
+
@use '@energysage/es-ds-styles/scss/mixins/breakpoints' as breakpoints;
|
|
126
|
+
|
|
127
|
+
@include breakpoints.media-breakpoint-up(lg) {
|
|
128
|
+
.EsSupportCard {
|
|
129
|
+
&-contentColumn {
|
|
130
|
+
/* account for the size of the image */
|
|
131
|
+
min-height: 100px;
|
|
132
|
+
/* 15px standard column padding + 100px image width */
|
|
133
|
+
padding-left: 115px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
&-description {
|
|
137
|
+
/* limit line length on larger breakpoints */
|
|
138
|
+
max-width: 450px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&-imageContainer {
|
|
142
|
+
/* account for 15px standard column padding */
|
|
143
|
+
left: 15px;
|
|
144
|
+
position: absolute;
|
|
145
|
+
top: 50%;
|
|
146
|
+
transform: translateY(-50%);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
</style>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps({
|
|
3
|
+
link: {
|
|
4
|
+
type: String,
|
|
5
|
+
required: true,
|
|
6
|
+
},
|
|
7
|
+
src: {
|
|
8
|
+
type: String,
|
|
9
|
+
required: true,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const slots = useSlots();
|
|
14
|
+
const hasTitle = computed(() => !!slots.title);
|
|
15
|
+
const hasLinkCopy = computed(() => !!slots.linkCopy);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div class="d-flex support-holder align-items-center">
|
|
20
|
+
<div class="mr-50">
|
|
21
|
+
<a
|
|
22
|
+
target="_blank"
|
|
23
|
+
aria-label="Support"
|
|
24
|
+
:href="link">
|
|
25
|
+
<img
|
|
26
|
+
class="image"
|
|
27
|
+
:src="src"
|
|
28
|
+
alt="EnergySage support" />
|
|
29
|
+
</a>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="d-flex flex-column">
|
|
32
|
+
<div>
|
|
33
|
+
<div class="h5 mb-25 font-size-base font-weight-bold">
|
|
34
|
+
<slot
|
|
35
|
+
v-if="hasTitle"
|
|
36
|
+
name="title" />
|
|
37
|
+
<template v-else> Need help signing up? </template>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div>
|
|
41
|
+
<a
|
|
42
|
+
target="_blank"
|
|
43
|
+
class="font-size-75"
|
|
44
|
+
:href="link">
|
|
45
|
+
<slot
|
|
46
|
+
v-if="hasLinkCopy"
|
|
47
|
+
name="linkCopy" />
|
|
48
|
+
<template v-else> Schedule a free call with your EnergySage Advisor. </template>
|
|
49
|
+
</a>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<style lang="scss" scoped>
|
|
56
|
+
.support-holder {
|
|
57
|
+
max-width: 325px;
|
|
58
|
+
|
|
59
|
+
.image {
|
|
60
|
+
height: 64px;
|
|
61
|
+
width: 64px;
|
|
62
|
+
border-radius: 2rem;
|
|
63
|
+
object-fit: contain;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import TabPanel from 'primevue/tabpanel';
|
|
3
|
+
import TabView from 'primevue/tabview';
|
|
4
|
+
|
|
5
|
+
// allow use of v-model on this component
|
|
6
|
+
const model = defineModel<number>();
|
|
7
|
+
|
|
8
|
+
// get the list of elements provided as children to the default slot
|
|
9
|
+
const panels = useSlots().default?.() || [];
|
|
10
|
+
|
|
11
|
+
// keep track of the active tab index
|
|
12
|
+
// - from above, if v-model is used
|
|
13
|
+
// - from below, if the tab component receives a click
|
|
14
|
+
const activeIndex: Ref<number> = ref(model.value || 0);
|
|
15
|
+
|
|
16
|
+
// watch the v-model for changes and update the active index if it does change
|
|
17
|
+
watch(model, (newVal) => {
|
|
18
|
+
// @ts-expect-error I don't know why
|
|
19
|
+
activeIndex.value = newVal;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// called from the TabView when the user clicks a tab to make it active
|
|
23
|
+
const updateActiveIndex = (index: number) => {
|
|
24
|
+
model.value = index;
|
|
25
|
+
};
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<tab-view
|
|
30
|
+
:active-index="activeIndex"
|
|
31
|
+
:pt="{
|
|
32
|
+
root: 'tabs es-tabs',
|
|
33
|
+
nav: 'list-unstyled nav position-relative',
|
|
34
|
+
tab: 'nav-link',
|
|
35
|
+
inkbar: 'inkbar position-absolute',
|
|
36
|
+
panelContainer: 'tab-content',
|
|
37
|
+
}"
|
|
38
|
+
@update:active-index="updateActiveIndex">
|
|
39
|
+
<!-- @vue-expect-error -->
|
|
40
|
+
<tab-panel
|
|
41
|
+
v-for="(panel, index) in panels"
|
|
42
|
+
:key="index"
|
|
43
|
+
:header="panel.props.title"
|
|
44
|
+
:pt="{
|
|
45
|
+
header: 'nav-item',
|
|
46
|
+
headerAction: ({ context }) => ({
|
|
47
|
+
class: [
|
|
48
|
+
'nav-link',
|
|
49
|
+
{
|
|
50
|
+
'active active-tab font-weight-bolder': context.active,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
}),
|
|
54
|
+
content: ({ context }) => ({
|
|
55
|
+
class: [
|
|
56
|
+
'tab-pane mt-100',
|
|
57
|
+
{
|
|
58
|
+
active: context.active,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
}),
|
|
62
|
+
}">
|
|
63
|
+
<!-- @vue-expect-error -->
|
|
64
|
+
<component
|
|
65
|
+
:is="item"
|
|
66
|
+
v-for="(item, idx) in panel.children.default()"
|
|
67
|
+
:key="idx" />
|
|
68
|
+
</tab-panel>
|
|
69
|
+
</tab-view>
|
|
70
|
+
</template>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import InputOtp from 'primevue/inputotp';
|
|
3
|
+
|
|
4
|
+
const model = defineModel<Array<string>>();
|
|
5
|
+
const verificationCode = ref<string>();
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
charCount: {
|
|
9
|
+
type: Number,
|
|
10
|
+
default: 5,
|
|
11
|
+
},
|
|
12
|
+
disabled: {
|
|
13
|
+
type: Boolean,
|
|
14
|
+
default: false,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const count = ref(props.charCount);
|
|
19
|
+
watch(model, (newVal) => {
|
|
20
|
+
verificationCode.value = newVal ? newVal.join('') : '';
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Note: @update:model-value is erroneously requiring a boolean function argument,
|
|
24
|
+
// workaround for error is to specify any
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
const updateCode = (newValue: any) => {
|
|
27
|
+
model.value = newValue.split('');
|
|
28
|
+
};
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div>
|
|
33
|
+
<input-otp
|
|
34
|
+
v-model="verificationCode"
|
|
35
|
+
class="custom-otp"
|
|
36
|
+
v-bind="$attrs"
|
|
37
|
+
:length="count"
|
|
38
|
+
integer-only
|
|
39
|
+
@update:model-value="updateCode">
|
|
40
|
+
<template #default="{ attrs, events, index }">
|
|
41
|
+
<input
|
|
42
|
+
:id="index.toString()"
|
|
43
|
+
type="text"
|
|
44
|
+
class="custom-otp-input form-control"
|
|
45
|
+
:disabled="props.disabled"
|
|
46
|
+
v-bind="attrs"
|
|
47
|
+
v-on="events" />
|
|
48
|
+
</template>
|
|
49
|
+
</input-otp>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<style lang="scss" scoped>
|
|
54
|
+
@use '@energysage/es-ds-styles/scss/variables' as variables;
|
|
55
|
+
@use '@energysage/es-ds-styles/scss/mixins/breakpoints' as breakpoints;
|
|
56
|
+
|
|
57
|
+
.custom-otp {
|
|
58
|
+
display: flex;
|
|
59
|
+
gap: 10px;
|
|
60
|
+
}
|
|
61
|
+
.custom-otp-input {
|
|
62
|
+
font-weight: 600 !important;
|
|
63
|
+
font-size: 1.875rem !important;
|
|
64
|
+
line-height: 2.25rem !important;
|
|
65
|
+
text-align: center;
|
|
66
|
+
height: 5rem;
|
|
67
|
+
width: 5rem;
|
|
68
|
+
appearance: textfield;
|
|
69
|
+
border: variables.$verification-code-border;
|
|
70
|
+
border-radius: variables.$verification-code-border-radius !important;
|
|
71
|
+
box-shadow: variables.$verification-code-shadow;
|
|
72
|
+
height: variables.$verification-code-dimension-lg;
|
|
73
|
+
width: variables.$verification-code-dimension-lg;
|
|
74
|
+
flex: 0 0 auto;
|
|
75
|
+
|
|
76
|
+
&:focus {
|
|
77
|
+
border-color: variables.$verification-code-focus-border-color;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@include breakpoints.media-breakpoint-down(md) {
|
|
81
|
+
height: variables.$verification-code-dimension-xs;
|
|
82
|
+
width: variables.$verification-code-dimension-xs;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&::-webkit-outer-spin-button,
|
|
86
|
+
&::-webkit-inner-spin-button {
|
|
87
|
+
appearance: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
&:last-child {
|
|
91
|
+
margin-right: 0 !important;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// Props
|
|
3
|
+
interface IProps {
|
|
4
|
+
altText: string;
|
|
5
|
+
coverImageUrl?: string;
|
|
6
|
+
embedUrl: string;
|
|
7
|
+
}
|
|
8
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
9
|
+
coverImageUrl: '',
|
|
10
|
+
});
|
|
11
|
+
const showVideo = ref(false);
|
|
12
|
+
|
|
13
|
+
// Methods
|
|
14
|
+
function getVideoIdFromUrl(url: string) {
|
|
15
|
+
const embedPattern = /https:\/\/www\.youtube\.com\/embed\/(?<videoId>[A-Za-z0-9-]+)/;
|
|
16
|
+
const parsedUrl = embedPattern.exec(url);
|
|
17
|
+
if (parsedUrl) {
|
|
18
|
+
return parsedUrl?.groups?.videoId;
|
|
19
|
+
}
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Computed
|
|
24
|
+
const videoId = computed(() => getVideoIdFromUrl(props.embedUrl));
|
|
25
|
+
const embedUrlWithParams = computed(
|
|
26
|
+
() => `https://www.youtube.com/embed/${videoId.value}?rel=0&autoplay=1&cc_load_policy=1&cc_lang_pref=en`,
|
|
27
|
+
);
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div>
|
|
32
|
+
<div
|
|
33
|
+
v-if="showVideo"
|
|
34
|
+
class="embed-responsive embed-responsive-16by9">
|
|
35
|
+
<iframe
|
|
36
|
+
:id="`youtube-video-${videoId}`"
|
|
37
|
+
:src="embedUrlWithParams"
|
|
38
|
+
class="embed-responsive-item"
|
|
39
|
+
frameborder="0"></iframe>
|
|
40
|
+
</div>
|
|
41
|
+
<es-card
|
|
42
|
+
v-else
|
|
43
|
+
:id="`youtube-placeholder-${videoId}`"
|
|
44
|
+
class="EsVideo-button bg-transparent overflow-hidden p-0 position-relative w-100"
|
|
45
|
+
variant="interactive"
|
|
46
|
+
@click="showVideo = true">
|
|
47
|
+
<slot v-if="$slots.default" />
|
|
48
|
+
<nuxt-img
|
|
49
|
+
v-else
|
|
50
|
+
class="EsVideo-image d-block w-100"
|
|
51
|
+
sizes="md:530px sm:275px"
|
|
52
|
+
:src="props.coverImageUrl"
|
|
53
|
+
:alt="props.altText" />
|
|
54
|
+
<icon-video-play
|
|
55
|
+
class="EsVideo-icon position-absolute abs-center"
|
|
56
|
+
width="74px"
|
|
57
|
+
height="54px" />
|
|
58
|
+
</es-card>
|
|
59
|
+
</div>
|
|
60
|
+
</template>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-expect-error module has no types
|
|
3
|
+
import truncate from 'html-truncate';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
/**
|
|
7
|
+
* Full text content
|
|
8
|
+
*/
|
|
9
|
+
content: {
|
|
10
|
+
type: String,
|
|
11
|
+
required: true,
|
|
12
|
+
},
|
|
13
|
+
/**
|
|
14
|
+
* Maximum character length of text before it is truncated
|
|
15
|
+
*/
|
|
16
|
+
length: {
|
|
17
|
+
type: Number,
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
/**
|
|
21
|
+
* Text for button to show more text
|
|
22
|
+
*/
|
|
23
|
+
clamp: {
|
|
24
|
+
type: String,
|
|
25
|
+
required: false,
|
|
26
|
+
default: 'Show more',
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* Text for button to hide text
|
|
30
|
+
*/
|
|
31
|
+
less: {
|
|
32
|
+
type: String,
|
|
33
|
+
required: false,
|
|
34
|
+
default: 'Show less',
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const isClamped = ref(true);
|
|
39
|
+
|
|
40
|
+
const truncatedContent = computed(() => truncate(props.content, props.length));
|
|
41
|
+
const isTruncated = computed(() => truncatedContent.value !== props.content);
|
|
42
|
+
const buttonText = computed(() => (isClamped.value ? props.clamp : props.less));
|
|
43
|
+
const bodyContent = computed(() => {
|
|
44
|
+
if (isClamped.value) {
|
|
45
|
+
return truncatedContent.value;
|
|
46
|
+
}
|
|
47
|
+
return props.content;
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<div>
|
|
53
|
+
<!-- eslint-disable-next-line vue/no-v-html -->
|
|
54
|
+
<span v-html="bodyContent" />
|
|
55
|
+
<es-button
|
|
56
|
+
v-if="isTruncated"
|
|
57
|
+
inline
|
|
58
|
+
variant="link"
|
|
59
|
+
class="ml-50 p-0"
|
|
60
|
+
@click="isClamped = !isClamped">
|
|
61
|
+
{{ buttonText }}
|
|
62
|
+
</es-button>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|