@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.
Files changed (224) hide show
  1. package/.eslintignore +9 -0
  2. package/.eslintrc.json +3 -0
  3. package/.prettierrc.json +10 -0
  4. package/components/es-accordion-list.vue +112 -0
  5. package/components/es-accordion.vue +7 -0
  6. package/components/es-badge.vue +20 -0
  7. package/components/es-breadcrumbs.vue +43 -32
  8. package/components/es-button.vue +112 -0
  9. package/components/es-card.vue +64 -0
  10. package/components/es-carousel.vue +160 -0
  11. package/components/{b-col.vue → es-col.vue} +11 -11
  12. package/components/es-collapse.vue +38 -36
  13. package/components/es-cta-banner.vue +95 -0
  14. package/components/es-cta-card.vue +60 -0
  15. package/components/es-data-table-simple.vue +73 -0
  16. package/components/es-data-table.vue +126 -0
  17. package/components/es-error-page.vue +120 -0
  18. package/components/es-file-input.vue +331 -0
  19. package/components/es-file-preview-modal.vue +61 -0
  20. package/components/es-footer.vue +163 -0
  21. package/components/es-form-checkbox.vue +40 -0
  22. package/components/es-form-input.vue +130 -0
  23. package/components/es-form-msg.vue +81 -0
  24. package/components/es-form-radio-card.vue +57 -0
  25. package/components/es-form-radio-cards.vue +78 -0
  26. package/components/es-form-textarea.vue +124 -0
  27. package/components/es-form.vue +16 -0
  28. package/components/es-modal.vue +103 -0
  29. package/components/es-nav-bar-account-menu.vue +67 -0
  30. package/components/es-nav-bar-featured-article.vue +60 -0
  31. package/components/es-nav-bar-link.vue +27 -0
  32. package/components/es-nav-bar-product-menu.vue +215 -0
  33. package/components/es-nav-bar-top-level-menu.vue +193 -0
  34. package/components/es-nav-bar-topic-menu.vue +194 -0
  35. package/components/es-nav-bar.vue +396 -0
  36. package/components/es-pagination.vue +66 -0
  37. package/components/es-popover.vue +113 -0
  38. package/components/es-progress-circle.vue +81 -0
  39. package/components/es-progress.vue +36 -0
  40. package/components/es-radio-button-group.vue +53 -0
  41. package/components/es-radio-button.vue +50 -57
  42. package/components/es-rating.vue +120 -0
  43. package/components/es-reviews-io-card-carousel.vue +275 -0
  44. package/components/es-slider.vue +147 -0
  45. package/components/es-spinner.vue +22 -0
  46. package/components/es-support-card.vue +150 -0
  47. package/components/es-support.vue +66 -0
  48. package/components/es-tab.vue +7 -0
  49. package/components/es-tabs.vue +67 -0
  50. package/components/es-verification-code.vue +94 -0
  51. package/components/es-view-more.vue +63 -0
  52. package/components/es-zip-code-form.vue +204 -0
  53. package/components/icon/arrow-clockwise.vue +51 -0
  54. package/components/icon/arrow-counter-clockwise.vue +37 -0
  55. package/components/icon/arrow-cycle.vue +43 -0
  56. package/components/icon/arrow-left.vue +39 -0
  57. package/components/icon/arrow-right.vue +39 -0
  58. package/components/icon/arrow-up.vue +39 -0
  59. package/components/icon/arrow.vue +68 -0
  60. package/components/icon/bank.vue +38 -0
  61. package/components/icon/battery.vue +40 -0
  62. package/components/icon/bell.vue +42 -0
  63. package/components/icon/block.vue +46 -0
  64. package/components/icon/bolt.vue +38 -0
  65. package/components/icon/business.vue +42 -0
  66. package/components/icon/calculator.vue +37 -0
  67. package/components/icon/calendar.vue +46 -0
  68. package/components/icon/cart.vue +46 -0
  69. package/components/icon/chat-add.vue +44 -0
  70. package/components/icon/chat-approve.vue +42 -0
  71. package/components/icon/chat-bubble.vue +40 -0
  72. package/components/icon/chat-dots.vue +42 -0
  73. package/components/icon/check.vue +39 -0
  74. package/components/{icon-chevron-down.vue → icon/chevron-down.vue} +16 -16
  75. package/components/icon/chevron-horizontal.vue +39 -0
  76. package/components/icon/chevron-left.vue +39 -0
  77. package/components/{icon-chevron-right.vue → icon/chevron-right.vue} +16 -16
  78. package/components/icon/chevron-up.vue +39 -0
  79. package/components/icon/circle-alert.vue +46 -0
  80. package/components/icon/circle-check.vue +46 -0
  81. package/components/icon/circle-chevron-down.vue +47 -0
  82. package/components/icon/circle-chevron-left.vue +46 -0
  83. package/components/icon/circle-chevron-right.vue +46 -0
  84. package/components/icon/circle-chevron-up.vue +46 -0
  85. package/components/icon/circle-minus.vue +46 -0
  86. package/components/icon/circle-plus.vue +46 -0
  87. package/components/icon/circle-x.vue +46 -0
  88. package/components/icon/circle.vue +42 -0
  89. package/components/icon/clock.vue +46 -0
  90. package/components/icon/community-solar.vue +37 -0
  91. package/components/icon/companies.vue +43 -0
  92. package/components/icon/contact-us.vue +37 -0
  93. package/components/icon/copy.vue +45 -0
  94. package/components/icon/credit-card.vue +37 -0
  95. package/components/icon/document.vue +45 -0
  96. package/components/icon/electric-vehicle.vue +37 -0
  97. package/components/icon/electricity-circle.vue +39 -0
  98. package/components/icon/envelope.vue +45 -0
  99. package/components/icon/es-leaf.vue +39 -0
  100. package/components/icon/eye.vue +41 -0
  101. package/components/icon/facebook.vue +41 -0
  102. package/components/icon/file-doc.vue +72 -0
  103. package/components/icon/file-docx.vue +72 -0
  104. package/components/icon/file-pdf.vue +72 -0
  105. package/components/icon/flag.vue +37 -0
  106. package/components/icon/folder.vue +41 -0
  107. package/components/icon/gear.vue +37 -0
  108. package/components/icon/gift.vue +37 -0
  109. package/components/icon/hamburger.vue +38 -0
  110. package/components/icon/heart.vue +39 -0
  111. package/components/icon/heat-pump.vue +41 -0
  112. package/components/icon/image.vue +45 -0
  113. package/components/icon/info-blog-post.vue +47 -0
  114. package/components/icon/info.vue +45 -0
  115. package/components/icon/instagram.vue +49 -0
  116. package/components/icon/light-bulb.vue +36 -0
  117. package/components/icon/link-out.vue +38 -0
  118. package/components/icon/linkedin.vue +41 -0
  119. package/components/icon/location.vue +45 -0
  120. package/components/icon/lock-off.vue +45 -0
  121. package/components/icon/lock-on.vue +48 -0
  122. package/components/icon/marketplace.vue +43 -0
  123. package/components/icon/minus.vue +38 -0
  124. package/components/icon/money-bag.vue +37 -0
  125. package/components/icon/money.vue +35 -0
  126. package/components/icon/open-envelope.vue +45 -0
  127. package/components/icon/paper.vue +45 -0
  128. package/components/icon/payback.vue +37 -0
  129. package/components/icon/pencil.vue +45 -0
  130. package/components/icon/person-add.vue +41 -0
  131. package/components/icon/person-check.vue +41 -0
  132. package/components/icon/person-cross.vue +41 -0
  133. package/components/icon/person.vue +41 -0
  134. package/components/icon/phone.vue +41 -0
  135. package/components/icon/play.vue +41 -0
  136. package/components/icon/plus.vue +38 -0
  137. package/components/icon/roof.vue +37 -0
  138. package/components/icon/rooftop-solar.vue +37 -0
  139. package/components/icon/saving.vue +37 -0
  140. package/components/icon/search.vue +43 -0
  141. package/components/icon/settings-horizontal.vue +57 -0
  142. package/components/icon/settings-vertical.vue +57 -0
  143. package/components/icon/shield-with-check.vue +38 -0
  144. package/components/icon/shield.vue +41 -0
  145. package/components/icon/shopping-bag.vue +39 -0
  146. package/components/icon/solar.vue +37 -0
  147. package/components/icon/sound-down.vue +45 -0
  148. package/components/icon/sound-off.vue +41 -0
  149. package/components/icon/sound-on.vue +41 -0
  150. package/components/icon/sound-up.vue +41 -0
  151. package/components/icon/star-empty.vue +38 -0
  152. package/components/icon/star-full.vue +36 -0
  153. package/components/icon/star-half.vue +55 -0
  154. package/components/icon/state-ak.vue +53 -0
  155. package/components/icon/state-al.vue +38 -0
  156. package/components/icon/state-ar.vue +38 -0
  157. package/components/icon/state-az.vue +38 -0
  158. package/components/icon/state-ca.vue +38 -0
  159. package/components/icon/state-co.vue +38 -0
  160. package/components/icon/state-ct.vue +38 -0
  161. package/components/icon/state-dc.vue +52 -0
  162. package/components/icon/state-de.vue +38 -0
  163. package/components/icon/state-fl.vue +38 -0
  164. package/components/icon/state-ga.vue +38 -0
  165. package/components/icon/state-hi.vue +59 -0
  166. package/components/icon/state-ia.vue +38 -0
  167. package/components/icon/state-id.vue +38 -0
  168. package/components/icon/state-il.vue +38 -0
  169. package/components/icon/state-in.vue +38 -0
  170. package/components/icon/state-ks.vue +38 -0
  171. package/components/icon/state-ky.vue +38 -0
  172. package/components/icon/state-la.vue +38 -0
  173. package/components/icon/state-ma.vue +38 -0
  174. package/components/icon/state-md.vue +39 -0
  175. package/components/icon/state-me.vue +38 -0
  176. package/components/icon/state-mi.vue +38 -0
  177. package/components/icon/state-mn.vue +38 -0
  178. package/components/icon/state-mo.vue +38 -0
  179. package/components/icon/state-ms.vue +38 -0
  180. package/components/icon/state-mt.vue +38 -0
  181. package/components/icon/state-nc.vue +38 -0
  182. package/components/icon/state-nd.vue +38 -0
  183. package/components/icon/state-ne.vue +38 -0
  184. package/components/icon/state-nh.vue +38 -0
  185. package/components/icon/state-nj.vue +37 -0
  186. package/components/icon/state-nm.vue +38 -0
  187. package/components/icon/state-nv.vue +38 -0
  188. package/components/icon/state-ny.vue +41 -0
  189. package/components/icon/state-oh.vue +38 -0
  190. package/components/icon/state-ok.vue +38 -0
  191. package/components/icon/state-or.vue +38 -0
  192. package/components/icon/state-pa.vue +38 -0
  193. package/components/icon/state-ri.vue +38 -0
  194. package/components/icon/state-sc.vue +38 -0
  195. package/components/icon/state-sd.vue +38 -0
  196. package/components/icon/state-tn.vue +38 -0
  197. package/components/icon/state-tx.vue +38 -0
  198. package/components/icon/state-ut.vue +38 -0
  199. package/components/icon/state-va.vue +38 -0
  200. package/components/icon/state-vt.vue +38 -0
  201. package/components/icon/state-wa.vue +38 -0
  202. package/components/icon/state-wi.vue +38 -0
  203. package/components/icon/state-wv.vue +38 -0
  204. package/components/icon/state-wy.vue +38 -0
  205. package/components/icon/thumbs-up.vue +39 -0
  206. package/components/icon/trash-can.vue +41 -0
  207. package/components/icon/tree.vue +37 -0
  208. package/components/icon/twitter.vue +43 -0
  209. package/components/icon/upload.vue +41 -0
  210. package/components/icon/verified.vue +40 -0
  211. package/components/icon/video-play.vue +41 -0
  212. package/components/icon/wifi.vue +38 -0
  213. package/components/icon/x.vue +38 -0
  214. package/components/icon/youtube.vue +45 -0
  215. package/composables/forms.ts +124 -0
  216. package/lib-utils/mime-type-finder.js +48 -0
  217. package/nuxt.config.ts +40 -9
  218. package/package.json +29 -5
  219. package/tsconfig.json +2 -2
  220. package/utils/get-es-footer-content.js +90 -0
  221. package/utils/get-es-nav-bar-account-content.js +55 -0
  222. package/utils/get-es-nav-bar-global-content.js +474 -0
  223. /package/components/{b-container.vue → es-container.vue} +0 -0
  224. /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
- const model = defineModel();
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>