@kiva/kv-components 3.106.0 → 3.107.1

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 (179) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/CHANGELOG.md +22 -0
  3. package/dist/components/.storybook/main.js +85 -0
  4. package/dist/components/.storybook/package.json +3 -0
  5. package/dist/components/.storybook/preview.js +61 -0
  6. package/dist/components/.storybook/tailwind.css +5 -0
  7. package/dist/components/KvAccordionItem.vue +130 -0
  8. package/dist/components/KvActivityRow.vue +33 -0
  9. package/dist/components/KvBorrowerImage.vue +179 -0
  10. package/dist/components/KvButton.vue +287 -0
  11. package/dist/components/KvCarousel.vue +297 -0
  12. package/dist/components/KvCartModal.vue +365 -0
  13. package/dist/components/KvCheckbox.vue +203 -0
  14. package/dist/components/KvChip.vue +54 -0
  15. package/dist/components/KvClassicLoanCard.vue +527 -0
  16. package/dist/components/KvCommentsAdd.vue +135 -0
  17. package/dist/components/KvCommentsContainer.vue +84 -0
  18. package/dist/components/KvCommentsHeartButton.vue +70 -0
  19. package/dist/components/KvCommentsList.vue +68 -0
  20. package/dist/components/KvCommentsListItem.vue +241 -0
  21. package/dist/components/KvCommentsReplyButton.vue +52 -0
  22. package/dist/components/KvContentfulImg.vue +273 -0
  23. package/dist/components/KvCountdownTimer.vue +59 -0
  24. package/dist/components/KvExpandable.vue +84 -0
  25. package/dist/components/KvExpandableQuestion.vue +120 -0
  26. package/dist/components/KvFlag.vue +120 -0
  27. package/dist/components/KvGrid.vue +28 -0
  28. package/dist/components/KvImpactDashboardHeader.vue +40 -0
  29. package/dist/components/KvInlineActivityCard.vue +55 -0
  30. package/dist/components/KvInlineActivityFeed.vue +38 -0
  31. package/dist/components/KvIntroductionLoanCard.vue +446 -0
  32. package/dist/components/KvLendAmountButton.vue +65 -0
  33. package/dist/components/KvLendCta.vue +451 -0
  34. package/dist/components/KvLightbox.vue +334 -0
  35. package/dist/components/KvLineGraph.vue +128 -0
  36. package/dist/components/KvLoadingPlaceholder.vue +38 -0
  37. package/dist/components/KvLoadingSpinner.vue +81 -0
  38. package/dist/components/KvLoanActivities.vue +268 -0
  39. package/dist/components/KvLoanBookmark.vue +39 -0
  40. package/dist/components/KvLoanCallouts.vue +53 -0
  41. package/dist/components/KvLoanProgressGroup.vue +76 -0
  42. package/dist/components/KvLoanTag.vue +88 -0
  43. package/dist/components/KvLoanTeamPick.vue +44 -0
  44. package/dist/components/KvLoanUse.vue +92 -0
  45. package/dist/components/KvMap.vue +599 -0
  46. package/dist/components/KvMaterialIcon.vue +47 -0
  47. package/dist/components/KvPageContainer.vue +15 -0
  48. package/dist/components/KvPagination.vue +198 -0
  49. package/dist/components/KvPieChart.vue +257 -0
  50. package/dist/components/KvPopper.vue +178 -0
  51. package/dist/components/KvProgressBar.vue +149 -0
  52. package/dist/components/KvRadio.vue +198 -0
  53. package/dist/components/KvSelect.vue +114 -0
  54. package/dist/components/KvSideSheet.vue +134 -0
  55. package/dist/components/KvSwitch.vue +143 -0
  56. package/dist/components/KvTab.vue +90 -0
  57. package/dist/components/KvTabPanel.vue +64 -0
  58. package/dist/components/KvTabs.vue +182 -0
  59. package/dist/components/KvTextInput.vue +247 -0
  60. package/dist/components/KvTextLink.vue +138 -0
  61. package/dist/components/KvThemeProvider.vue +122 -0
  62. package/dist/components/KvToast.vue +221 -0
  63. package/dist/components/KvTooltip.vue +168 -0
  64. package/dist/components/KvTreeMapChart.vue +229 -0
  65. package/dist/components/KvUserAvatar.vue +132 -0
  66. package/dist/components/KvVerticalCarousel.vue +156 -0
  67. package/dist/components/KvVotingCard.vue +160 -0
  68. package/dist/components/KvVotingCardV2.vue +154 -0
  69. package/dist/components/KvWideLoanCard.vue +432 -0
  70. package/dist/components/stories/Forms.stories.js +62 -0
  71. package/dist/components/stories/KvAccordionItem.stories.js +24 -0
  72. package/dist/components/stories/KvActivityRow.stories.js +25 -0
  73. package/dist/components/stories/KvBorrowerImage.stories.js +68 -0
  74. package/dist/components/stories/KvButton.stories.js +144 -0
  75. package/dist/components/stories/KvCarousel.stories.js +426 -0
  76. package/dist/components/stories/KvCartModal.stories.js +54 -0
  77. package/dist/components/stories/KvCheckbox.stories.js +163 -0
  78. package/dist/components/stories/KvChip.stories.js +43 -0
  79. package/dist/components/stories/KvClassicLoanCard.stories.js +480 -0
  80. package/dist/components/stories/KvCommentsAdd.stories.js +32 -0
  81. package/dist/components/stories/KvCommentsContainer.stories.js +42 -0
  82. package/dist/components/stories/KvCommentsHeartButton.stories.js +25 -0
  83. package/dist/components/stories/KvCommentsList.stories.js +39 -0
  84. package/dist/components/stories/KvCommentsListItem.stories.js +45 -0
  85. package/dist/components/stories/KvCommentsReplyButton.stories.js +21 -0
  86. package/dist/components/stories/KvContentfulImg.stories.js +196 -0
  87. package/dist/components/stories/KvCountdownTimer.stories.js +30 -0
  88. package/dist/components/stories/KvExpandableQuestion.stories.js +129 -0
  89. package/dist/components/stories/KvFlag.stories.js +36 -0
  90. package/dist/components/stories/KvGrid.stories.js +97 -0
  91. package/dist/components/stories/KvImpactDashboardHeader.stories.js +22 -0
  92. package/dist/components/stories/KvInlineActivityCard.stories.js +69 -0
  93. package/dist/components/stories/KvInlineActivityFeed.stories.js +76 -0
  94. package/dist/components/stories/KvIntroductionLoanCard.stories.js +208 -0
  95. package/dist/components/stories/KvLendAmountButton.stories.js +31 -0
  96. package/dist/components/stories/KvLendCta.stories.js +177 -0
  97. package/dist/components/stories/KvLightbox.stories.js +304 -0
  98. package/dist/components/stories/KvLineGraph.stories.js +52 -0
  99. package/dist/components/stories/KvLoadingPlaceholder.stories.js +17 -0
  100. package/dist/components/stories/KvLoadingSpinner.stories.js +52 -0
  101. package/dist/components/stories/KvLoanActivities.stories.js +104 -0
  102. package/dist/components/stories/KvLoanBookmark.stories.js +22 -0
  103. package/dist/components/stories/KvLoanCallouts.stories.js +22 -0
  104. package/dist/components/stories/KvLoanProgressGroup.stories.js +29 -0
  105. package/dist/components/stories/KvLoanTag.stories.js +61 -0
  106. package/dist/components/stories/KvLoanTeamPick.stories.js +20 -0
  107. package/dist/components/stories/KvLoanUse.stories.js +60 -0
  108. package/dist/components/stories/KvMap.stories.js +121 -0
  109. package/dist/components/stories/KvMaterialIcon.stories.js +201 -0
  110. package/dist/components/stories/KvPageContainer.stories.js +50 -0
  111. package/dist/components/stories/KvPagination.stories.js +70 -0
  112. package/dist/components/stories/KvPieChart.stories.js +47 -0
  113. package/dist/components/stories/KvProgressBar.stories.js +53 -0
  114. package/dist/components/stories/KvRadio.stories.js +140 -0
  115. package/dist/components/stories/KvSelect.stories.js +125 -0
  116. package/dist/components/stories/KvSideSheet.stories.js +50 -0
  117. package/dist/components/stories/KvSwitch.stories.js +66 -0
  118. package/dist/components/stories/KvTabs.stories.js +106 -0
  119. package/dist/components/stories/KvTextInput.stories.js +194 -0
  120. package/dist/components/stories/KvTextLink.stories.js +55 -0
  121. package/dist/components/stories/KvThemeProvider.stories.js +178 -0
  122. package/dist/components/stories/KvToast.stories.js +117 -0
  123. package/dist/components/stories/KvTooltip.stories.js +26 -0
  124. package/dist/components/stories/KvTreeMapChart.stories.js +42 -0
  125. package/dist/components/stories/KvUserAvatar.stories.js +47 -0
  126. package/dist/components/stories/KvVerticalCarousel.stories.js +168 -0
  127. package/dist/components/stories/KvVotingCard.stories.js +33 -0
  128. package/dist/components/stories/KvVotingCardV2.stories.js +89 -0
  129. package/dist/components/stories/KvWideLoanCard.stories.js +292 -0
  130. package/dist/components/stories/StyleguidePrimitives.stories.js +499 -0
  131. package/dist/components/stories/StyleguideProse.stories.js +215 -0
  132. package/dist/data/countries-borders.json +1 -0
  133. package/dist/data/ne_110m_admin_0_countries.json +1 -0
  134. package/dist/utils/Alea.cjs +87 -0
  135. package/dist/utils/Alea.js +9 -0
  136. package/dist/utils/attrs.cjs +50 -0
  137. package/dist/utils/attrs.js +7 -0
  138. package/dist/utils/carousels.cjs +184 -0
  139. package/dist/utils/carousels.js +8 -0
  140. package/dist/utils/chunk-3HK4G4NT.js +27 -0
  141. package/dist/utils/chunk-55HF2ORX.js +201 -0
  142. package/dist/utils/chunk-AY3PR5S4.js +54 -0
  143. package/dist/utils/chunk-AZPWOFD5.js +148 -0
  144. package/dist/utils/chunk-B5J5WLAH.js +18 -0
  145. package/dist/utils/chunk-GPSH6OPA.js +64 -0
  146. package/dist/utils/chunk-HIY5IW65.js +28 -0
  147. package/dist/utils/chunk-HV3AUBFT.js +15 -0
  148. package/dist/utils/chunk-MSMZIN54.js +110 -0
  149. package/dist/utils/chunk-OXJCCNNW.js +30 -0
  150. package/dist/utils/chunk-S3MABILA.js +22 -0
  151. package/dist/utils/chunk-VIGEMAKO.js +249 -0
  152. package/dist/utils/chunk-YCNMJ4YV.js +37 -0
  153. package/dist/utils/chunk-YFEC5ODJ.js +129 -0
  154. package/dist/utils/expander.cjs +78 -0
  155. package/dist/utils/expander.js +9 -0
  156. package/dist/utils/imageUtils.cjs +54 -0
  157. package/dist/utils/imageUtils.js +9 -0
  158. package/dist/utils/index.cjs +1118 -0
  159. package/dist/utils/index.js +166 -0
  160. package/dist/utils/loanCard.cjs +222 -0
  161. package/dist/utils/loanCard.js +9 -0
  162. package/dist/utils/loanUtils.cjs +170 -0
  163. package/dist/utils/loanUtils.js +23 -0
  164. package/dist/utils/mapUtils.cjs +276 -0
  165. package/dist/utils/mapUtils.js +15 -0
  166. package/dist/utils/printing.cjs +42 -0
  167. package/dist/utils/printing.js +9 -0
  168. package/dist/utils/scrollLock.cjs +54 -0
  169. package/dist/utils/scrollLock.js +13 -0
  170. package/dist/utils/throttle.cjs +38 -0
  171. package/dist/utils/throttle.js +7 -0
  172. package/dist/utils/touchEvents.cjs +47 -0
  173. package/dist/utils/touchEvents.js +11 -0
  174. package/dist/utils/treemap.cjs +133 -0
  175. package/dist/utils/treemap.js +7 -0
  176. package/package.json +12 -4
  177. package/utils/index.js +14 -0
  178. package/vue/KvVerticalCarousel.vue +1 -1
  179. package/index.js +0 -3
@@ -0,0 +1,40 @@
1
+ <!-- eslint-disable max-len -->
2
+ <template>
3
+ <nav class="tw-bg-primary">
4
+ <div
5
+ class="header__full tw-h-9 tw-grid xl:tw-gap-x-4 tw-items-center tw-mx-auto tw-px-2.5 md:tw-px-4 lg:tw-px-8"
6
+ style="max-width: 1200px;"
7
+ >
8
+ <div class="header__full__logo tw-w-6 tw-text-brand">
9
+ <svg
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ viewBox="0 0 57 23"
12
+ >
13
+ <path
14
+ d="M4.695.391H0v22.141h4.695V.391zm12.899 22.141h4.695V7.011h-4.695v15.521zm12.159 0h5.413l5.413-15.521h-4.662s-2.544 8.445-3.293 11.119h-.066c-.75-2.674-3.326-11.119-3.326-11.119h-4.956l5.477 15.521zm-23.537-8.31c7.37 0 9.092-6.158 9.092-7.21h-.637c-7.372 0-9.094 6.157-9.094 7.21h.639zm-.639.969c0 1.117 1.276 7.403 9.222 7.403h.638c0-1.119-1.277-7.403-9.221-7.403h-.639zM22.746 2.739C22.746 1.272 21.671 0 19.941 0c-1.727 0-2.804 1.272-2.804 2.739 0 1.468 1.077 2.739 2.804 2.739 1.73 0 2.805-1.271 2.805-2.739M57 7.011h-4.532V9.13c-.783-1.631-2.608-2.543-4.729-2.543-3.848 0-6.88 3.129-6.88 8.184 0 5.087 2.935 8.185 6.652 8.185 2.608 0 4.173-1.272 4.956-2.675v2.25H57V7.011zm-4.663 8.151c0 2.871-1.76 4.208-3.522 4.208-1.924 0-3.163-1.956-3.163-4.598 0-2.608 1.305-4.598 3.326-4.598 1.663 0 3.359 1.37 3.359 4.206v.782z"
15
+ fill="currentColor"
16
+ />
17
+ </svg>
18
+ </div>
19
+
20
+ <div class="header__full__right">
21
+ <slot></slot>
22
+ </div>
23
+ </div>
24
+ </nav>
25
+ </template>
26
+
27
+ <style scoped>
28
+ .header__full {
29
+ grid-template-areas: 'logo right';
30
+ grid-template-columns: 1fr auto;
31
+ }
32
+
33
+ .header__full__logo {
34
+ grid-area: logo;
35
+ }
36
+
37
+ .header__full__right {
38
+ grid-area: right;
39
+ }
40
+ </style>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div
3
+ class="tw-flex tw-items-center tw-gap-1 tw-py-0.5 tw-px-1 tw-shadow-lg tw-rounded-sm tw-bg-white"
4
+ >
5
+ <KvUserAvatar
6
+ :lender-image-url="lenderImageUrl"
7
+ :lender-name="lenderName"
8
+ is-small
9
+ class="activity-avatar"
10
+ />
11
+ <p class="tw-text-base tw-whitespace-nowrap">
12
+ <span class="data-hj-suppress">{{ lenderName }}</span> contributed
13
+ </p>
14
+ </div>
15
+ </template>
16
+
17
+ <script>
18
+ import { computed, toRefs } from 'vue-demi';
19
+ import KvUserAvatar from './KvUserAvatar.vue';
20
+
21
+ export default {
22
+ name: 'KvInlineActivityCard',
23
+ components: {
24
+ KvUserAvatar,
25
+ },
26
+ props: {
27
+ /**
28
+ * Activity data object
29
+ */
30
+ activity: {
31
+ type: Object,
32
+ default: () => ({}),
33
+ },
34
+ },
35
+ setup(props) {
36
+ const {
37
+ activity,
38
+ } = toRefs(props);
39
+
40
+ const lenderName = computed(() => activity?.value?.lender?.name ?? '');
41
+ const lenderImageUrl = computed(() => activity?.value?.lender?.image?.url ?? '');
42
+
43
+ return {
44
+ lenderImageUrl,
45
+ lenderName,
46
+ };
47
+ },
48
+ };
49
+ </script>
50
+
51
+ <style scoped lang="postcss">
52
+ .activity-avatar, .activity-avatar >>> img, .activity-avatar >>> div {
53
+ @apply tw-w-4 tw-h-4;
54
+ }
55
+ </style>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div class="tw-flex tw-gap-x-0.5 tw-overflow-x-auto tw-py-2 tw-px-1 hide-scrollbar">
3
+ <KvInlineActivityCard
4
+ v-for="(activity, index) in activities"
5
+ :key="index"
6
+ :activity="activity"
7
+ />
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ import KvInlineActivityCard from './KvInlineActivityCard.vue';
13
+
14
+ export default {
15
+ name: 'KvInlineActivityFeed',
16
+ components: { KvInlineActivityCard },
17
+ props: {
18
+ /**
19
+ * Activities data array
20
+ */
21
+ activities: {
22
+ type: Array,
23
+ default: () => ([]),
24
+ },
25
+ },
26
+ };
27
+ </script>
28
+
29
+ <style scoped lang="postcss">
30
+ .hide-scrollbar {
31
+ -ms-overflow-style: none; /* IE and Edge */
32
+ scrollbar-width: none; /* Firefox */
33
+ }
34
+
35
+ .hide-scrollbar::-webkit-scrollbar {
36
+ @apply tw-hidden;
37
+ }
38
+ </style>
@@ -0,0 +1,446 @@
1
+ <template>
2
+ <div
3
+ class="tw-flex tw-flex-col tw-bg-white tw-rounded tw-w-full tw-pb-2"
4
+ :class="{ 'tw-pointer-events-none' : isLoading }"
5
+ data-testid="loan-card"
6
+ style="box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.38);"
7
+ :style="{ minWidth: '230px', maxWidth: cardWidth }"
8
+ >
9
+ <div class="tw-grow">
10
+ <div class="loan-card-active-hover">
11
+ <!-- Borrower image -->
12
+ <kv-loading-placeholder
13
+ v-if="isLoading"
14
+ class="tw-w-full tw-rounded-t"
15
+ :style="{ height: '11rem' }"
16
+ />
17
+ <div
18
+ v-else
19
+ :style="{ height: '11rem' }"
20
+ class="tw-relative tw-overflow-hidden"
21
+ >
22
+ <component
23
+ :is="tag"
24
+ :to="readMorePath"
25
+ :href="readMorePath"
26
+ class="tw-flex"
27
+ aria-label="Borrower image"
28
+ @click.native="clickReadMore('Photo', $event)"
29
+ >
30
+ <kv-borrower-image
31
+ class="
32
+ tw-relative
33
+ tw-w-full
34
+ tw-bg-black
35
+ tw-rounded-t
36
+ borrower-image
37
+ "
38
+ :alt="`Photo of ${borrowerName}`"
39
+ :aspect-ratio="imageAspectRatio"
40
+ :default-image="{ width: imageDefaultWidth }"
41
+ :hash="imageHash"
42
+ :images="imageSizes"
43
+ :photo-path="photoPath"
44
+ />
45
+
46
+ <div v-if="countryName">
47
+ <p
48
+ class="
49
+ tw-absolute
50
+ tw-bottom-1
51
+ tw-left-1
52
+ tw-text-primary
53
+ tw-bg-white
54
+ tw-rounded
55
+ tw-p-1
56
+ tw-mb-0
57
+ tw-mr-2
58
+ tw-text-h4
59
+ tw-inline-flex
60
+ tw-items-center
61
+ !tw-capitalize
62
+ "
63
+ style="padding: 2px 6px;"
64
+ >
65
+ <kv-flag
66
+ class="tw-ml-0.5 tw-mr-1"
67
+ :country="countryCode"
68
+ width-override="16px"
69
+ hide-border
70
+ />
71
+ {{ formattedLocation }}
72
+ </p>
73
+ </div>
74
+ </component>
75
+
76
+ <kv-loan-bookmark
77
+ v-if="!isVisitor"
78
+ :loan-id="loanId"
79
+ :is-bookmarked="isBookmarked"
80
+ class="loan-bookmark tw-absolute tw-right-1.5 tw-top-0"
81
+ data-testid="loan-card-bookmark"
82
+ @toggle-bookmark="$emit('toggle-bookmark')"
83
+ />
84
+ </div>
85
+
86
+ <!-- Loan name -->
87
+
88
+ <kv-loading-placeholder
89
+ v-if="isLoading || typeof loanCallouts === 'undefined'"
90
+ class="tw-mt-1 tw-mx-auto"
91
+ :style="{ width: '60%', height: '1.75rem', 'border-radius': '500rem' }"
92
+ />
93
+
94
+ <component
95
+ :is="tag"
96
+ :to="readMorePath"
97
+ :href="readMorePath"
98
+ aria-label="Borrower name"
99
+ class="!tw-text-primary"
100
+ @click.native="clickReadMore('Name', $event)"
101
+ >
102
+ <h3
103
+ class="loan-card-name"
104
+ :class="{ 'tw-text-center': borrowerName.length < 20 }"
105
+ style="font-size: 28px;"
106
+ >
107
+ {{ borrowerName }}
108
+ </h3>
109
+ </component>
110
+
111
+ <!-- Loan tag -->
112
+
113
+ <div
114
+ v-if="isLoading"
115
+ class="tw-flex tw-justify-center tw-gap-2"
116
+ >
117
+ <kv-loading-placeholder
118
+ v-if="isLoading || typeof loanCallouts === 'undefined'"
119
+ class="tw-mt-0.5 tw-mb-1"
120
+ :style="{ width: '20%', height: '1.65rem', 'border-radius': '500rem' }"
121
+ />
122
+ <kv-loading-placeholder
123
+ v-if="isLoading || typeof loanCallouts === 'undefined'"
124
+ class="tw-mt-0.5 tw-mb-1"
125
+ :style="{ width: '20%', height: '1.65rem', 'border-radius': '500rem' }"
126
+ />
127
+ <kv-loading-placeholder
128
+ v-if="isLoading || typeof loanCallouts === 'undefined'"
129
+ class="tw-mt-0.5 tw-mb-1"
130
+ :style="{ width: '20%', height: '1.65rem', 'border-radius': '500rem' }"
131
+ />
132
+ </div>
133
+
134
+ <component
135
+ :is="tag"
136
+ v-else
137
+ :to="readMorePath"
138
+ :href="readMorePath"
139
+ class="tw-flex hover:tw-no-underline focus:tw-no-underline tw-justify-center"
140
+ aria-label="Loan tag"
141
+ @click.native="clickReadMore('Tag', $event)"
142
+ >
143
+ <kv-loan-callouts
144
+ :callouts="loanCallouts"
145
+ :add-bg-color="false"
146
+ class="loan-callouts"
147
+ />
148
+ </component>
149
+
150
+ <component
151
+ :is="tag"
152
+ :to="readMorePath"
153
+ :href="readMorePath"
154
+ class="loan-card-use tw-text-primary"
155
+ aria-label="Loan use"
156
+ @click.native="clickReadMore('Use', $event)"
157
+ >
158
+ <!-- Loan use -->
159
+ <div
160
+ class="tw-pt-0.5 tw-px-2"
161
+ :class="{'tw-mb-1.5': !isLoading}"
162
+ >
163
+ <div
164
+ v-if="isLoading"
165
+ class="tw-w-full"
166
+ style="height: 5.5rem;"
167
+ >
168
+ <div
169
+ v-for="(_n, i) in [...Array(3)]"
170
+ :key="i"
171
+ class="tw-h-2 tw-mb-1"
172
+ >
173
+ <kv-loading-placeholder />
174
+ </div>
175
+ </div>
176
+ <div v-else>
177
+ <kv-loan-use
178
+ :use="loanUse"
179
+ :loan-amount="loanAmount"
180
+ :status="loanStatus"
181
+ :borrower-count="loanBorrowerCount"
182
+ :name="borrowerName"
183
+ :distribution-model="distributionModel"
184
+ hide-loan-amount
185
+ class="!tw-line-clamp-3"
186
+ />
187
+ </div>
188
+ </div>
189
+ </component>
190
+ </div>
191
+ </div>
192
+
193
+ <div class="tw-px-2">
194
+ <!-- Fundraising -->
195
+ <div
196
+ v-if="!hasProgressData"
197
+ class="tw-w-full tw-pr-1"
198
+ >
199
+ <div class="tw-flex tw-justify-between">
200
+ <kv-loading-placeholder
201
+ class="tw-mb-0.5"
202
+ :style="{ width: '20%', height: '1.3rem' }"
203
+ />
204
+ <kv-loading-placeholder
205
+ class="tw-mb-0.5"
206
+ :style="{ width: '20%', height: '1.3rem' }"
207
+ />
208
+ </div>
209
+
210
+ <kv-loading-placeholder
211
+ class="tw-rounded"
212
+ :style="{ width: '100%', height: '0.5rem' }"
213
+ />
214
+ </div>
215
+
216
+ <div>
217
+ <component
218
+ :is="tag"
219
+ v-if="unreservedAmount > 0"
220
+ :to="readMorePath"
221
+ :href="readMorePath"
222
+ class="loan-card-progress tw-mt-1"
223
+ aria-label="Loan progress"
224
+ @click.native="clickReadMore('Progress', $event)"
225
+ >
226
+ <kv-loan-progress-group
227
+ id="loanProgress"
228
+ :money-left="`${unreservedAmount}`"
229
+ :amount-goal="`${loanAmount}`"
230
+ :progress-percent="fundraisingPercent"
231
+ class="tw-text-secondary"
232
+ />
233
+ </component>
234
+ </div>
235
+
236
+ <!-- Loan Tag -->
237
+ <kv-loading-placeholder
238
+ v-if="isLoading"
239
+ class="tw-rounded tw-mx-auto tw-mt-2"
240
+ :style="{ width: '9rem', height: '1rem' }"
241
+ />
242
+
243
+ <div
244
+ v-else-if="isFunded"
245
+ class="tw-bg-eco-green-1 tw-text-action tw-text-center tw-py-1.5"
246
+ style="font-weight: bold; font-size: 13px; border-radius: 8px;"
247
+ >
248
+ 🎉 Fully funded!
249
+ </div>
250
+
251
+ <kv-loan-tag
252
+ v-else
253
+ :loan="loan"
254
+ :use-expanded-styles="true"
255
+ style="font-size: 15px;"
256
+ class="tw-text-center tw-pt-2"
257
+ />
258
+ </div>
259
+ </div>
260
+ </template>
261
+
262
+ <script>
263
+ import numeral from 'numeral';
264
+ import { loanCardComputedProperties, loanCardMethods } from '../utils/loanCard';
265
+ import KvLoanBookmark from './KvLoanBookmark.vue';
266
+ import KvLoanUse from './KvLoanUse.vue';
267
+ import KvBorrowerImage from './KvBorrowerImage.vue';
268
+ import KvLoanProgressGroup from './KvLoanProgressGroup.vue';
269
+ import KvLoanCallouts from './KvLoanCallouts.vue';
270
+ import KvLoanTag from './KvLoanTag.vue';
271
+ import KvMaterialIcon from './KvMaterialIcon.vue';
272
+ import KvLoadingPlaceholder from './KvLoadingPlaceholder.vue';
273
+ import KvFlag from './KvFlag.vue';
274
+
275
+ export default {
276
+ name: 'KvIntroductionLoanCard',
277
+ components: {
278
+ KvBorrowerImage,
279
+ KvLoadingPlaceholder,
280
+ KvLoanUse,
281
+ KvLoanProgressGroup,
282
+ KvMaterialIcon,
283
+ KvLoanTag,
284
+ KvLoanCallouts,
285
+ KvFlag,
286
+ KvLoanBookmark,
287
+ },
288
+ props: {
289
+ loanId: {
290
+ type: Number,
291
+ default: undefined,
292
+ },
293
+ loan: {
294
+ type: Object,
295
+ default: null,
296
+ },
297
+ customLoanDetails: {
298
+ type: Boolean,
299
+ default: false,
300
+ },
301
+ categoryPageName: {
302
+ type: String,
303
+ default: '',
304
+ },
305
+ customCallouts: {
306
+ type: Array,
307
+ default: () => ([]),
308
+ },
309
+ kvTrackFunction: {
310
+ type: Function,
311
+ required: true,
312
+ },
313
+ photoPath: {
314
+ type: String,
315
+ required: true,
316
+ },
317
+ errorMsg: {
318
+ type: String,
319
+ default: '',
320
+ },
321
+ externalLinks: {
322
+ type: Boolean,
323
+ default: false,
324
+ },
325
+ route: {
326
+ type: Object,
327
+ default: undefined,
328
+ },
329
+ useFullWidth: {
330
+ type: Boolean,
331
+ default: false,
332
+ },
333
+ isVisitor: {
334
+ type: Boolean,
335
+ default: true,
336
+ },
337
+ isBookmarked: {
338
+ type: Boolean,
339
+ default: false,
340
+ },
341
+ },
342
+ setup(props, { emit }) {
343
+ const {
344
+ allDataLoaded,
345
+ borrowerName,
346
+ city,
347
+ countryName,
348
+ countryCode,
349
+ distributionModel,
350
+ formattedLocation,
351
+ fundraisingPercent,
352
+ hasProgressData,
353
+ imageHash,
354
+ isLoading,
355
+ loanAmount,
356
+ loanBorrowerCount,
357
+ loanCallouts,
358
+ loanStatus,
359
+ loanUse,
360
+ mdiMapMarker,
361
+ readMorePath,
362
+ state,
363
+ tag,
364
+ unreservedAmount,
365
+ } = loanCardComputedProperties(props, true);
366
+
367
+ const {
368
+ clickReadMore,
369
+ } = loanCardMethods(props, emit);
370
+
371
+ return {
372
+ allDataLoaded,
373
+ borrowerName,
374
+ city,
375
+ countryName,
376
+ countryCode,
377
+ distributionModel,
378
+ formattedLocation,
379
+ fundraisingPercent,
380
+ hasProgressData,
381
+ imageHash,
382
+ isLoading,
383
+ loanAmount,
384
+ loanBorrowerCount,
385
+ loanCallouts,
386
+ loanStatus,
387
+ loanUse,
388
+ mdiMapMarker,
389
+ readMorePath,
390
+ state,
391
+ tag,
392
+ unreservedAmount,
393
+ clickReadMore,
394
+ };
395
+ },
396
+ computed: {
397
+ cardWidth() {
398
+ return this.useFullWidth ? '100%' : '20.5rem';
399
+ },
400
+ imageAspectRatio() {
401
+ return 5 / 8;
402
+ },
403
+ imageDefaultWidth() {
404
+ return 480;
405
+ },
406
+ imageSizes() {
407
+ return [
408
+ { width: this.imageDefaultWidth, viewSize: 375 },
409
+ ];
410
+ },
411
+ lendersNumber() {
412
+ return this.loan?.lenders?.totalCount ?? 0;
413
+ },
414
+ amountLent() {
415
+ const amount = this.loan?.loanFundraisingInfo?.fundedAmount ?? 0;
416
+ return numeral(parseFloat(amount)).format('$0,0');
417
+ },
418
+ isFunded() {
419
+ return this.loan?.status === 'funded' || parseFloat(this.unreservedAmount) === 0;
420
+ },
421
+ },
422
+ };
423
+ </script>
424
+
425
+ <style lang="postcss" scoped>
426
+ .loan-callouts >>> span {
427
+ @apply !tw-bg-transparent tw-text-action;
428
+ }
429
+ .loan-card-use:hover,
430
+ .loan-card-use:focus {
431
+ @apply tw-text-primary;
432
+ }
433
+ .loan-card-active-hover:hover .loan-card-use, .loan-card-active-hover:hover .loan-card-name {
434
+ @apply tw-underline;
435
+ }
436
+ .loan-card-progress:hover,
437
+ .loan-card-progress:focus {
438
+ @apply tw-no-underline;
439
+ }
440
+ .loan-card-name {
441
+ @apply tw-pt-1 tw-px-3 tw-text-ellipsis tw-overflow-hidden tw-line-clamp-1 tw-cursor-pointer;
442
+ }
443
+ .loan-bookmark >>> button {
444
+ @apply !tw-rounded-t-none;
445
+ }
446
+ </style>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <kv-button @click="addToBasket">
3
+ {{ buttonText }}
4
+ </kv-button>
5
+ </template>
6
+
7
+ <script>
8
+ import KvButton from './KvButton.vue';
9
+
10
+ export default {
11
+ name: 'KvLendAmountButton',
12
+ components: {
13
+ KvButton,
14
+ },
15
+ props: {
16
+ loanId: {
17
+ type: Number,
18
+ default: null,
19
+ },
20
+ showNow: {
21
+ type: Boolean,
22
+ default: false,
23
+ },
24
+ amountLeft: {
25
+ type: [Number, String],
26
+ default: 20,
27
+ },
28
+ completeLoan: {
29
+ type: Boolean,
30
+ default: false,
31
+ },
32
+ },
33
+ computed: {
34
+ amountValue() {
35
+ return parseFloat(this.amountLeft).toFixed();
36
+ },
37
+ buttonText() {
38
+ let str = '';
39
+
40
+ if (this.completeLoan) {
41
+ str = `Complete loan for $${this.amountValue}`;
42
+ } else {
43
+ str = `Lend $${this.amountValue}`;
44
+ if (this.showNow) {
45
+ str += ' now';
46
+ }
47
+ }
48
+
49
+ return str;
50
+ },
51
+ },
52
+ methods: {
53
+ addToBasket(event) {
54
+ this.$kvTrackEvent(
55
+ 'Lending',
56
+ 'Add to basket (Partial Share)',
57
+ 'lend-button-click',
58
+ this.loanId,
59
+ this.amountLeft,
60
+ );
61
+ this.$emit('add-to-basket', event);
62
+ },
63
+ },
64
+ };
65
+ </script>