@energysage/es-ds-components 3.0.0-alpha.6 → 3.0.0-alpha.7
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/components/es-accordion-list.vue +112 -0
- package/components/es-accordion.vue +7 -0
- package/components/es-badge.vue +20 -0
- package/components/es-breadcrumbs.vue +43 -32
- package/components/es-button.vue +112 -0
- package/components/es-card.vue +64 -0
- package/components/es-carousel.vue +160 -0
- package/components/{b-col.vue → es-col.vue} +11 -11
- package/components/es-collapse.vue +38 -36
- 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 +126 -0
- package/components/es-error-page.vue +120 -0
- package/components/es-file-input.vue +331 -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 +67 -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 +215 -0
- package/components/es-nav-bar-top-level-menu.vue +193 -0
- package/components/es-nav-bar-topic-menu.vue +194 -0
- package/components/es-nav-bar.vue +396 -0
- package/components/es-pagination.vue +66 -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 +50 -57
- package/components/es-rating.vue +120 -0
- package/components/es-reviews-io-card-carousel.vue +275 -0
- package/components/es-slider.vue +147 -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 +67 -0
- package/components/es-verification-code.vue +94 -0
- package/components/es-view-more.vue +63 -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 → icon/chevron-down.vue} +16 -16
- package/components/icon/chevron-horizontal.vue +39 -0
- package/components/icon/chevron-left.vue +39 -0
- package/components/{icon-chevron-right.vue → icon/chevron-right.vue} +16 -16
- 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/lib-utils/mime-type-finder.js +48 -0
- package/nuxt.config.ts +40 -9
- package/package.json +29 -5
- package/tsconfig.json +2 -2
- package/utils/get-es-footer-content.js +90 -0
- package/utils/get-es-nav-bar-account-content.js +55 -0
- package/utils/get-es-nav-bar-global-content.js +474 -0
- /package/components/{b-container.vue → es-container.vue} +0 -0
- /package/components/{b-row.vue → es-row.vue} +0 -0
|
@@ -1,40 +1,9 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<panel
|
|
3
|
-
:collapsed="!expanded"
|
|
4
|
-
:pt="{
|
|
5
|
-
header: 'align-items-center d-flex justify-content-between position-relative py-100',
|
|
6
|
-
icons: 'h-100 position-absolute w-100',
|
|
7
|
-
root: border ? 'border-bottom border-top' : '',
|
|
8
|
-
toggler: {
|
|
9
|
-
class: 'es-collapse-toggler align-items-center btn btn-link d-flex h-100 inline justify-content-end rounded-0 p-0 position-absolute text-body w-100',
|
|
10
|
-
},
|
|
11
|
-
// https://vuejs.org/guide/built-ins/transition
|
|
12
|
-
transition: {
|
|
13
|
-
enterActiveClass: 'es-collapse-enter-active',
|
|
14
|
-
enterFromClass: 'es-collapse-enter-from',
|
|
15
|
-
enterToClass: 'es-collapse-enter-to',
|
|
16
|
-
leaveActiveClass: 'es-collapse-leave-active',
|
|
17
|
-
leaveFromClass: 'es-collapse-leave-from',
|
|
18
|
-
leaveToClass: 'es-collapse-leave-to'
|
|
19
|
-
},
|
|
20
|
-
}"
|
|
21
|
-
toggleable
|
|
22
|
-
@toggle="onClick">
|
|
23
|
-
<template #header>
|
|
24
|
-
<slot name="title" />
|
|
25
|
-
</template>
|
|
26
|
-
<template #togglericon>
|
|
27
|
-
<icon-chevron-down />
|
|
28
|
-
</template>
|
|
29
|
-
<slot />
|
|
30
|
-
</panel>
|
|
31
|
-
</template>
|
|
32
|
-
|
|
33
1
|
<script setup lang="ts">
|
|
34
2
|
import Panel from 'primevue/panel';
|
|
35
3
|
|
|
36
4
|
const emit = defineEmits(['toggled', 'userClick']);
|
|
37
|
-
|
|
5
|
+
|
|
6
|
+
const model = defineModel<boolean>();
|
|
38
7
|
const props = defineProps({
|
|
39
8
|
border: {
|
|
40
9
|
type: Boolean,
|
|
@@ -42,12 +11,12 @@ const props = defineProps({
|
|
|
42
11
|
},
|
|
43
12
|
isProgrammaticUntilUserInput: {
|
|
44
13
|
type: Boolean,
|
|
45
|
-
default: true
|
|
14
|
+
default: true,
|
|
46
15
|
},
|
|
47
16
|
visible: {
|
|
48
17
|
type: Boolean,
|
|
49
|
-
default: false
|
|
50
|
-
}
|
|
18
|
+
default: false,
|
|
19
|
+
},
|
|
51
20
|
});
|
|
52
21
|
|
|
53
22
|
const userDeterminedState = ref(null);
|
|
@@ -79,3 +48,36 @@ const onClick = ({ value }) => {
|
|
|
79
48
|
emit('userClick', !value);
|
|
80
49
|
};
|
|
81
50
|
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<panel
|
|
54
|
+
:collapsed="!expanded"
|
|
55
|
+
:pt="{
|
|
56
|
+
header: 'align-items-center d-flex justify-content-between position-relative py-100',
|
|
57
|
+
icons: 'h-100 position-absolute w-100',
|
|
58
|
+
root: border ? 'border-bottom border-top' : '',
|
|
59
|
+
toggler: {
|
|
60
|
+
// eslint-disable-next-line max-len
|
|
61
|
+
class: 'es-collapse-toggler align-items-center btn btn-link d-flex h-100 inline justify-content-end rounded-0 p-0 position-absolute text-body w-100',
|
|
62
|
+
},
|
|
63
|
+
// https://vuejs.org/guide/built-ins/transition
|
|
64
|
+
transition: {
|
|
65
|
+
enterActiveClass: 'es-collapse-enter-active',
|
|
66
|
+
enterFromClass: 'es-collapse-enter-from',
|
|
67
|
+
enterToClass: 'es-collapse-enter-to',
|
|
68
|
+
leaveActiveClass: 'es-collapse-leave-active',
|
|
69
|
+
leaveFromClass: 'es-collapse-leave-from',
|
|
70
|
+
leaveToClass: 'es-collapse-leave-to',
|
|
71
|
+
},
|
|
72
|
+
}"
|
|
73
|
+
toggleable
|
|
74
|
+
@toggle="onClick">
|
|
75
|
+
<template #header>
|
|
76
|
+
<slot name="title" />
|
|
77
|
+
</template>
|
|
78
|
+
<template #togglericon>
|
|
79
|
+
<icon-chevron-down />
|
|
80
|
+
</template>
|
|
81
|
+
<slot />
|
|
82
|
+
</panel>
|
|
83
|
+
</template>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
dark: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false,
|
|
6
|
+
},
|
|
7
|
+
hasButton: {
|
|
8
|
+
type: Boolean,
|
|
9
|
+
default: false,
|
|
10
|
+
},
|
|
11
|
+
// default or wide
|
|
12
|
+
variant: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: 'default',
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const lgFirst = computed(() => {
|
|
19
|
+
if (props.variant === 'wide') {
|
|
20
|
+
return props.hasButton ? '8' : '6';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return props.hasButton ? '7' : '4';
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const lgSecond = computed(() => {
|
|
27
|
+
if (props.variant === 'wide') {
|
|
28
|
+
return props.hasButton ? '4' : '6';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return props.hasButton ? '5' : '8';
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const xxlFirst = computed(() => {
|
|
35
|
+
if (props.variant === 'wide') {
|
|
36
|
+
return props.hasButton ? '8' : '6';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return props.hasButton ? '8' : '5';
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const xxlSecond = computed(() => {
|
|
43
|
+
if (props.variant === 'wide') {
|
|
44
|
+
return props.hasButton ? '4' : '6';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return props.hasButton ? '4' : '7';
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<es-card
|
|
53
|
+
:class="[
|
|
54
|
+
{
|
|
55
|
+
'bg-dark-blue border-dark-blue text-white': dark,
|
|
56
|
+
'px-100 px-lg-200': variant === 'default',
|
|
57
|
+
'px-100 px-lg-300': variant === 'wide',
|
|
58
|
+
},
|
|
59
|
+
]"
|
|
60
|
+
v-bind="$attrs">
|
|
61
|
+
<es-row>
|
|
62
|
+
<es-col
|
|
63
|
+
class="mb-200 my-lg-auto text-center text-lg-left"
|
|
64
|
+
:lg="lgFirst"
|
|
65
|
+
:xxl="xxlFirst">
|
|
66
|
+
<!-- avoiding use of an <h2> tag here for long-form content SEO reasons,
|
|
67
|
+
but preserving heading semantics for screen readers -->
|
|
68
|
+
<div
|
|
69
|
+
role="heading"
|
|
70
|
+
aria-level="2"
|
|
71
|
+
class="font-weight-semibold"
|
|
72
|
+
:class="{
|
|
73
|
+
'font-size-300': variant === 'default',
|
|
74
|
+
'mb-50': $slots.subtitle,
|
|
75
|
+
'mb-0': !$slots.subtitle,
|
|
76
|
+
'text-white': dark,
|
|
77
|
+
h2: variant === 'wide',
|
|
78
|
+
}">
|
|
79
|
+
<slot name="heading"> Easily find what solar costs in your area </slot>
|
|
80
|
+
</div>
|
|
81
|
+
<p
|
|
82
|
+
v-if="$slots.subtitle"
|
|
83
|
+
class="mb-0">
|
|
84
|
+
<slot name="subtitle" />
|
|
85
|
+
</p>
|
|
86
|
+
</es-col>
|
|
87
|
+
<es-col
|
|
88
|
+
class="d-flex justify-content-center justify-content-lg-end my-auto"
|
|
89
|
+
:lg="lgSecond"
|
|
90
|
+
:xxl="xxlSecond">
|
|
91
|
+
<slot name="cta" />
|
|
92
|
+
</es-col>
|
|
93
|
+
</es-row>
|
|
94
|
+
</es-card>
|
|
95
|
+
</template>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
imageFirst: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false,
|
|
6
|
+
},
|
|
7
|
+
horizontalPadding: {
|
|
8
|
+
type: String,
|
|
9
|
+
default: 'px-100',
|
|
10
|
+
},
|
|
11
|
+
verticalSpacing: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: 'mb-150',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<es-card
|
|
20
|
+
class="align-items-center d-flex flex-column py-200 text-center"
|
|
21
|
+
:class="props.horizontalPadding"
|
|
22
|
+
v-bind="$attrs">
|
|
23
|
+
<!-- avoiding use of an <h2> tag here for long-form content SEO reasons,
|
|
24
|
+
but preserving heading semantics for screen readers -->
|
|
25
|
+
<div
|
|
26
|
+
role="heading"
|
|
27
|
+
aria-level="2"
|
|
28
|
+
class="font-weight-semibold font-size-300"
|
|
29
|
+
:class="[{ 'order-1': props.imageFirst }, props.verticalSpacing]">
|
|
30
|
+
<slot name="heading"> Easily find what solar costs in your area </slot>
|
|
31
|
+
</div>
|
|
32
|
+
<div
|
|
33
|
+
v-if="$slots.image"
|
|
34
|
+
class="mx-auto w-100"
|
|
35
|
+
:class="props.verticalSpacing">
|
|
36
|
+
<slot name="image" />
|
|
37
|
+
</div>
|
|
38
|
+
<div
|
|
39
|
+
class="w-100"
|
|
40
|
+
:class="{ 'order-2': props.imageFirst }">
|
|
41
|
+
<div
|
|
42
|
+
v-if="$slots.subtitle"
|
|
43
|
+
class="es-cta-card-subtitle"
|
|
44
|
+
:class="props.verticalSpacing">
|
|
45
|
+
<slot name="subtitle" />
|
|
46
|
+
</div>
|
|
47
|
+
<slot name="cta" />
|
|
48
|
+
</div>
|
|
49
|
+
</es-card>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<style lang="scss" scoped>
|
|
53
|
+
.es-cta-card {
|
|
54
|
+
&-subtitle {
|
|
55
|
+
:deep(p:last-child) {
|
|
56
|
+
margin-bottom: 0;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
fields: {
|
|
4
|
+
type: Array,
|
|
5
|
+
default: null,
|
|
6
|
+
},
|
|
7
|
+
items: {
|
|
8
|
+
type: Array,
|
|
9
|
+
default: () => [],
|
|
10
|
+
},
|
|
11
|
+
tableClass: {
|
|
12
|
+
type: [Array, String],
|
|
13
|
+
default: null,
|
|
14
|
+
},
|
|
15
|
+
striped: {
|
|
16
|
+
type: Boolean,
|
|
17
|
+
default: false,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const isSingleCol = computed(() => !props.fields);
|
|
22
|
+
const computedItems = computed(() => {
|
|
23
|
+
if (!props.items.length && !useSlots().default) {
|
|
24
|
+
throw new Error('Neither items prop nor slot content is defined.');
|
|
25
|
+
}
|
|
26
|
+
// If there are no fields, just return the items as a single-column array
|
|
27
|
+
if (!props.fields) {
|
|
28
|
+
return props.items;
|
|
29
|
+
}
|
|
30
|
+
if (props.fields.length !== props.items.length) {
|
|
31
|
+
throw new Error('The number of fields and items must be the same.');
|
|
32
|
+
}
|
|
33
|
+
// If fields and items are both present, map them together
|
|
34
|
+
return props.fields.map((field, index) => [field, props.items[index]]);
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
<template>
|
|
38
|
+
<div
|
|
39
|
+
:class="tableClass"
|
|
40
|
+
class="table-responsive">
|
|
41
|
+
<table
|
|
42
|
+
v-if="$slots.default || items.length"
|
|
43
|
+
class="table table-borderless"
|
|
44
|
+
:class="{ 'table-striped': striped }">
|
|
45
|
+
<template v-if="$slots.default">
|
|
46
|
+
<slot />
|
|
47
|
+
</template>
|
|
48
|
+
<tbody v-else>
|
|
49
|
+
<template v-if="isSingleCol">
|
|
50
|
+
<tr
|
|
51
|
+
v-for="(item, index) in computedItems"
|
|
52
|
+
:key="`${index}${item}`">
|
|
53
|
+
<td>
|
|
54
|
+
{{ item }}
|
|
55
|
+
</td>
|
|
56
|
+
</tr>
|
|
57
|
+
</template>
|
|
58
|
+
<template v-else>
|
|
59
|
+
<tr
|
|
60
|
+
v-for="(item, index) in computedItems"
|
|
61
|
+
:key="`${index}${item[0]}`">
|
|
62
|
+
<td class="col-sm-7">
|
|
63
|
+
{{ item[0] }}
|
|
64
|
+
</td>
|
|
65
|
+
<td class="col-sm-4">
|
|
66
|
+
<b>{{ item[1] }}</b>
|
|
67
|
+
</td>
|
|
68
|
+
</tr>
|
|
69
|
+
</template>
|
|
70
|
+
</tbody>
|
|
71
|
+
</table>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import DataTable from 'primevue/datatable';
|
|
3
|
+
import Column from 'primevue/column';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
fields: {
|
|
7
|
+
type: Array,
|
|
8
|
+
default: null,
|
|
9
|
+
},
|
|
10
|
+
items: {
|
|
11
|
+
type: Array,
|
|
12
|
+
required: true,
|
|
13
|
+
},
|
|
14
|
+
stickyFirstCol: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
default: false,
|
|
17
|
+
},
|
|
18
|
+
stickyHeader: {
|
|
19
|
+
type: [Boolean, String],
|
|
20
|
+
default: false,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const checkFrozenRow = (index) => {
|
|
25
|
+
if (index === 0 && props.stickyFirstCol) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Code is taken from BootStrap Vue to implemnt <b-table> feature that automatically
|
|
32
|
+
// samples the first row to extract field name and "humanize" by converting kebab-case,
|
|
33
|
+
// snake_case, and camelCase to individual words and capitalizes each word.
|
|
34
|
+
// Doc: https://bootstrap-vue.org/docs/components/table
|
|
35
|
+
// Source Code: https://github.com/bootstrap-vue/bootstrap-vue/blob/5173dd19f6f46dc9d125cd7233fb59ccd2ef9296/src/utils/string.js#L30
|
|
36
|
+
const startCase = (str: string) =>
|
|
37
|
+
str
|
|
38
|
+
.replace(/_/g, ' ')
|
|
39
|
+
.replace(/([a-z])([A-Z])/g, (_, $1, $2) => `${$1} ${$2}`)
|
|
40
|
+
.replace(/(\s|^)(\w)/g, (_, $1, $2) => $1 + $2.toUpperCase());
|
|
41
|
+
|
|
42
|
+
const label = (col) => {
|
|
43
|
+
if (typeof col === 'string') {
|
|
44
|
+
return startCase(col);
|
|
45
|
+
}
|
|
46
|
+
return col?.label ? col.label : startCase(col?.key);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const columns = computed(() => {
|
|
50
|
+
if (props.fields) {
|
|
51
|
+
return props.fields;
|
|
52
|
+
}
|
|
53
|
+
return Object.keys(props.items[0]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const scrollHeight = computed(() => {
|
|
57
|
+
if (props.stickyHeader) {
|
|
58
|
+
if (typeof props.stickyHeader === 'string') {
|
|
59
|
+
return props.stickyHeader;
|
|
60
|
+
}
|
|
61
|
+
return '300px';
|
|
62
|
+
}
|
|
63
|
+
return '';
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
<template>
|
|
67
|
+
<data-table
|
|
68
|
+
scrollable
|
|
69
|
+
:pt="{
|
|
70
|
+
table: {
|
|
71
|
+
class: 'font-size-75 font-size-md-100',
|
|
72
|
+
style: 'border-collapse: separate; border-spacing: 0;',
|
|
73
|
+
},
|
|
74
|
+
wrapper: {
|
|
75
|
+
style: 'border-radius: inherit',
|
|
76
|
+
},
|
|
77
|
+
thead: {
|
|
78
|
+
style: 'top: 0px; z-index: 2',
|
|
79
|
+
},
|
|
80
|
+
}"
|
|
81
|
+
:value="props.items"
|
|
82
|
+
class="border table__data-table table-spacing table"
|
|
83
|
+
:scroll-height="scrollHeight">
|
|
84
|
+
<column
|
|
85
|
+
v-for="(col, index) of columns"
|
|
86
|
+
:key="col?.key ? col.key : col"
|
|
87
|
+
:field="col?.key ? col.key : col"
|
|
88
|
+
:header="label(col)"
|
|
89
|
+
:sortable="col?.sortable"
|
|
90
|
+
:frozen="checkFrozenRow(index)"
|
|
91
|
+
align-frozen="left"
|
|
92
|
+
:pt="{
|
|
93
|
+
sortIcon: {
|
|
94
|
+
style: 'display: none',
|
|
95
|
+
},
|
|
96
|
+
headerCell: (options) => ({
|
|
97
|
+
class: [
|
|
98
|
+
{
|
|
99
|
+
sortable: options.props.sortable,
|
|
100
|
+
stickyFirstColHeader: options.props.frozen,
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
}),
|
|
104
|
+
bodyCell: (options) => ({
|
|
105
|
+
class: [
|
|
106
|
+
{
|
|
107
|
+
stickyFirstCol: options.props.frozen,
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
}),
|
|
111
|
+
}">
|
|
112
|
+
</column>
|
|
113
|
+
</data-table>
|
|
114
|
+
</template>
|
|
115
|
+
<style scoped lang="scss">
|
|
116
|
+
:deep(.stickyFirstColHeader) {
|
|
117
|
+
position: sticky !important;
|
|
118
|
+
}
|
|
119
|
+
:deep(.stickyFirstCol) {
|
|
120
|
+
position: sticky !important;
|
|
121
|
+
background: inherit;
|
|
122
|
+
}
|
|
123
|
+
:deep(.sortable) {
|
|
124
|
+
cursor: pointer !important;
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import IconContactUs from './icon/contact-us.vue';
|
|
3
|
+
import IconCommunitySolar from './icon/community-solar.vue';
|
|
4
|
+
import IconInfoBlogPost from './icon/info-blog-post.vue';
|
|
5
|
+
import IconMarketplace from './icon/marketplace.vue';
|
|
6
|
+
|
|
7
|
+
const ES_DOMAIN = process.env.ES_DOMAIN || 'https://www.energysage.com';
|
|
8
|
+
const linkItems = [
|
|
9
|
+
{
|
|
10
|
+
icon: IconContactUs,
|
|
11
|
+
link: 'mailto:hello@energysage.com',
|
|
12
|
+
label: 'Contact us',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
icon: IconCommunitySolar,
|
|
16
|
+
link: `${ES_DOMAIN}/solar/`,
|
|
17
|
+
label: 'Learn about solar',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
icon: IconInfoBlogPost,
|
|
21
|
+
link: `${ES_DOMAIN}/blog/`,
|
|
22
|
+
label: 'EnergySage blog',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
icon: IconMarketplace,
|
|
26
|
+
link: `${ES_DOMAIN}/shop/home-solar/`,
|
|
27
|
+
label: 'EnergySage marketplace',
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const props = defineProps({
|
|
32
|
+
errorType: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
interface ErrorCode {
|
|
39
|
+
shortMessage?: string;
|
|
40
|
+
longMessage: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ErrorCodeMap {
|
|
44
|
+
[key: string]: ErrorCode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const errorCodeToMessages: ErrorCodeMap = {
|
|
48
|
+
403: {
|
|
49
|
+
shortMessage: 'Access denied',
|
|
50
|
+
longMessage:
|
|
51
|
+
"Oops! If you're seeing this message, there's a good chance you have cookies or " +
|
|
52
|
+
'referrers turned off in your browser.',
|
|
53
|
+
},
|
|
54
|
+
404: {
|
|
55
|
+
shortMessage: 'Page not found',
|
|
56
|
+
longMessage: 'Oops! We are terribly sorry, but there is nothing bright to see here.',
|
|
57
|
+
},
|
|
58
|
+
500: {
|
|
59
|
+
shortMessage: 'Internal server error',
|
|
60
|
+
longMessage: 'Oops! We are terribly sorry, but our server is not so bright today. Please try again.',
|
|
61
|
+
},
|
|
62
|
+
503: {
|
|
63
|
+
shortMessage: 'Service unavailable',
|
|
64
|
+
longMessage: 'The page you are requesting is temporarily unavailable.',
|
|
65
|
+
},
|
|
66
|
+
default: {
|
|
67
|
+
longMessage: 'Oops! Something went wrong!',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const messages: ErrorCode = errorCodeToMessages[props.errorType];
|
|
72
|
+
|
|
73
|
+
const errorShortMessage = messages?.shortMessage || props.errorType;
|
|
74
|
+
|
|
75
|
+
const errorLongMessage = messages?.longMessage || errorCodeToMessages.default.longMessage;
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<template>
|
|
79
|
+
<div class="bg-gray-50">
|
|
80
|
+
<es-container class="py-500 py-lg-800">
|
|
81
|
+
<es-row>
|
|
82
|
+
<es-col
|
|
83
|
+
md="7"
|
|
84
|
+
class="my-500 mx-auto text-center">
|
|
85
|
+
<h1 class="post1 text-gray-600">
|
|
86
|
+
{{ errorShortMessage }}
|
|
87
|
+
</h1>
|
|
88
|
+
<p
|
|
89
|
+
id="msgError"
|
|
90
|
+
class="font-size-lg text-gray-600">
|
|
91
|
+
{{ errorLongMessage }}
|
|
92
|
+
</p>
|
|
93
|
+
</es-col>
|
|
94
|
+
</es-row>
|
|
95
|
+
<es-row>
|
|
96
|
+
<es-col
|
|
97
|
+
v-for="(item, index) in linkItems"
|
|
98
|
+
:key="index"
|
|
99
|
+
cols="6"
|
|
100
|
+
md="3">
|
|
101
|
+
<a
|
|
102
|
+
class="align-items-center d-flex flex-column justify-content-center text-center"
|
|
103
|
+
:href="item.link">
|
|
104
|
+
<div
|
|
105
|
+
class="bg-white d-flex justify-content-center mb-50 rounded-circle"
|
|
106
|
+
align-v="center">
|
|
107
|
+
<div class="m-100 text-orange">
|
|
108
|
+
<component
|
|
109
|
+
:is="item.icon"
|
|
110
|
+
height="53px"
|
|
111
|
+
width="53px" />
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<p class="mb-200 mb-md-0">{{ item.label }}</p>
|
|
115
|
+
</a>
|
|
116
|
+
</es-col>
|
|
117
|
+
</es-row>
|
|
118
|
+
</es-container>
|
|
119
|
+
</div>
|
|
120
|
+
</template>
|