@sbc-connect/nuxt-base 0.1.4 → 0.1.6

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 (48) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +1 -1
  3. package/app/app.config.ts +167 -16
  4. package/app/components/Connect/Address/Display.vue +77 -0
  5. package/app/components/Connect/Breadcrumb.vue +2 -2
  6. package/app/components/Connect/Footer.vue +3 -3
  7. package/app/components/Connect/Header/Wrapper.vue +2 -2
  8. package/app/components/Connect/Header/index.vue +4 -5
  9. package/app/components/Connect/I18n/Helper.vue +24 -0
  10. package/app/components/Connect/Input.vue +32 -0
  11. package/app/components/Connect/Layout/Index.vue +23 -0
  12. package/app/components/Connect/Modal/index.vue +51 -0
  13. package/app/components/Connect/PageSection.vue +57 -0
  14. package/app/components/Connect/Slideover/WhatsNew.vue +4 -4
  15. package/app/components/Connect/Spinner.vue +94 -0
  16. package/app/components/Connect/SystemBanner.vue +8 -8
  17. package/app/components/Connect/Textarea.vue +30 -0
  18. package/app/components/Connect/Transition/Collapse.vue +39 -0
  19. package/app/composables/useConnectModal.ts +11 -0
  20. package/app/interfaces/connect-address.ts +12 -0
  21. package/app/interfaces/connect-modal.ts +5 -0
  22. package/app/layouts/ConnectBase.vue +3 -13
  23. package/app/plugins/maska.client.ts +10 -0
  24. package/app/plugins/whats-new.client.ts +1 -1
  25. package/app/spa-loading-template.html +60 -38
  26. package/app/types/base-app-config.d.ts +15 -0
  27. package/app/types/base-page-meta.d.ts +8 -0
  28. package/app/utils/logFetchError.ts +36 -0
  29. package/app/utils/parseSpecialCharacters.ts +25 -0
  30. package/app/utils/setBreadcrumbs.ts +5 -0
  31. package/i18n/locales/en-CA.ts +3 -2
  32. package/modules/base-assets/index.ts +30 -0
  33. package/modules/{assets/runtime/assets/core-tw.css → base-assets/runtime/assets/connect-base-tw.css} +48 -46
  34. package/nuxt.config.ts +43 -17
  35. package/package.json +9 -9
  36. package/app/plugins/launchdarkly.client.ts +0 -9
  37. package/modules/assets/index.ts +0 -24
  38. package/modules/assets/runtime/assets/core-main.css +0 -6
  39. /package/modules/{assets/runtime/assets/core-layout.css → base-assets/runtime/assets/connect-base-layout.css} +0 -0
  40. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Bold.woff +0 -0
  41. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Bold.woff2 +0 -0
  42. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-BoldItalic.woff +0 -0
  43. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-BoldItalic.woff2 +0 -0
  44. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Italic.woff +0 -0
  45. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Italic.woff2 +0 -0
  46. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Regular.woff +0 -0
  47. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Regular.woff2 +0 -0
  48. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/LICENSE_OFL.txt +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # @sbc-connect/nuxt-base
2
2
 
3
+ ## 0.1.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#26](https://github.com/bcgov/connect-nuxt/pull/26) [`65ae301`](https://github.com/bcgov/connect-nuxt/commit/65ae301972b39cfed8550e49c1209133674528a4) Thanks [@deetz99](https://github.com/deetz99)! - Update CSS variables to match Nuxt UI naming convention. Issue: bcgov/entity#29335
8
+
9
+ - [#27](https://github.com/bcgov/connect-nuxt/pull/27) [`09fa4f1`](https://github.com/bcgov/connect-nuxt/commit/09fa4f1b4b2c65d189a6477c9c5f2d44607b543d) Thanks [@deetz99](https://github.com/deetz99)! - - ConnectModal component
10
+
11
+ - ConnectAddressDisplay component
12
+ - logFetchError util
13
+ - tests
14
+ - switch lodash for es-toolkit
15
+
16
+ issue: bcgov/entity#29335
17
+
18
+ - [#25](https://github.com/bcgov/connect-nuxt/pull/25) [`aba11d1`](https://github.com/bcgov/connect-nuxt/commit/aba11d1303ab1b19b3a51c27959766c4ee0cd5d8) Thanks [@deetz99](https://github.com/deetz99)! - - create auth header components
19
+
20
+ - connect-auth layout
21
+
22
+ issue: bcgov/entity#29335
23
+
24
+ ## 0.1.5
25
+
26
+ ### Patch Changes
27
+
28
+ - [#19](https://github.com/bcgov/connect-nuxt/pull/19) [`4231254`](https://github.com/bcgov/connect-nuxt/commit/42312540f5eec65f5d3979d5492bdfaa9bb0b079) Thanks [@deetz99](https://github.com/deetz99)! - Several components and utils
29
+
30
+ - ConnectInput
31
+ - ConnectTextarea
32
+ - ConnectI18nHelper
33
+ - ConnectSpinner
34
+ - ConnectPageSection
35
+ - parseSpecialCharacters util
36
+ - setBreadcrumbs util
37
+ - set nuxt ui default icons to use mdi instead of lucide icons
38
+
39
+ issue: bcgov/entity#29334
40
+
3
41
  ## 0.1.4
4
42
 
5
43
  ### Patch Changes
package/README.md CHANGED
@@ -48,7 +48,7 @@ For local development, the following variables are required. The default values
48
48
 
49
49
  ```
50
50
  # .env
51
- NUXT_BASE_URL="http://localhost:3000/"
51
+ NUXT_PUBLIC_BASE_URL="http://localhost:3000/"
52
52
  ```
53
53
 
54
54
  #### Production Environments
package/app/app.config.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  export default defineAppConfig({
2
3
  connect: {
3
4
  header: {
@@ -37,12 +38,176 @@ export default defineAppConfig({
37
38
  button: {
38
39
  slots: {
39
40
  base: 'cursor-pointer'
41
+ },
42
+ compoundVariants: [
43
+ {
44
+ color: 'primary',
45
+ variant: 'solid',
46
+ class: 'font-bold text-(--ui-bg) bg-(--ui-primary) hover:bg-(--ui-primary)/75 disabled:bg-(--ui-primary) aria-disabled:bg-(--ui-primary) focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-(--ui-primary)'
47
+ },
48
+ {
49
+ color: 'primary',
50
+ variant: 'ghost',
51
+ class: 'text-(--ui-primary) hover:bg-(--ui-primary)/10 active:bg-(--ui-primary)/25 focus:outline-none focus-visible:bg-(--ui-primary)/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent'
52
+ },
53
+ {
54
+ color: 'primary',
55
+ variant: 'outline',
56
+ class: 'ring ring-inset ring-primary text-primary hover:bg-primary/10 active:bg-primary/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus:outline-none focus-visible:ring-2 focus-visible:ring-primary'
57
+ }
58
+ ],
59
+ variants: {
60
+ size: {
61
+ sm: {
62
+ base: 'px-7 py-0.5 text-sm gap-2.5',
63
+ leadingIcon: 'size-4',
64
+ leadingAvatarSize: '3xs',
65
+ trailingIcon: 'size-4'
66
+ },
67
+ md: {
68
+ base: 'px-7 py-1.5 text-sm gap-2.5',
69
+ leadingIcon: 'size-5',
70
+ leadingAvatarSize: '2xs',
71
+ trailingIcon: 'size-5'
72
+ },
73
+ lg: {
74
+ base: 'px-7 py-2.25 text-sm gap-2.5',
75
+ leadingIcon: 'size-5',
76
+ leadingAvatarSize: '2xs',
77
+ trailingIcon: 'size-5'
78
+ },
79
+ xl: {
80
+ base: 'px-7 py-2.5 text-base gap-2.5',
81
+ leadingIcon: 'size-5',
82
+ leadingAvatarSize: '2xs',
83
+ trailingIcon: 'size-5'
84
+ }
85
+ }
86
+ },
87
+ defaultVariants: {
88
+ color: 'primary',
89
+ variant: 'solid',
90
+ size: 'lg'
91
+ }
92
+ },
93
+ card: {
94
+ slots: {
95
+ root: 'rounded-md'
40
96
  }
41
97
  },
42
98
  dropdownMenu: {
43
99
  slots: {
44
- content: 'bg-secondary ring-0',
45
- group: 'p-0'
100
+ content: 'min-w-32 max-h-[75dvh] shadow-lg rounded-sm',
101
+ group: 'p-0 isolate',
102
+ item: 'group relative w-full flex items-center select-none outline-none before:inset-px before:rounded-none cursor-pointer',
103
+ separator: '-mx-0 my-0 h-px bg-(--ui-border)'
104
+ },
105
+ variants: {
106
+ active: {
107
+ true: {
108
+ item: 'text-primary before:bg-shade',
109
+ itemLeadingIcon: 'text-(--ui-text)'
110
+ },
111
+ false: {
112
+ item: 'text-(--ui-text) data-highlighted:text-primary data-[state=open]:text-(--ui-text-highlighted) data-highlighted:before:bg-shade data-[state=open]:before:bg-(--ui-bg-elevated)/50 transition-colors before:transition-colors',
113
+ itemLeadingIcon: 'text-neutral group-data-highlighted:text-primary group-data-[state=open]:text-(--ui-text) transition-colors'
114
+ }
115
+ },
116
+ size: {
117
+ md: {
118
+ label: 'px-4 py-3 text-sm gap-1.5',
119
+ item: 'px-4 py-3 text-sm gap-1.5',
120
+ itemLeadingIcon: 'size-5',
121
+ itemLeadingAvatarSize: '2xs',
122
+ itemTrailingIcon: 'size-5',
123
+ itemTrailingKbds: 'gap-0.5',
124
+ itemTrailingKbdsSize: 'md'
125
+ }
126
+ }
127
+ },
128
+ compoundVariants: [
129
+ {
130
+ color: 'primary',
131
+ active: false,
132
+ class: {
133
+ item: 'text-(--ui-primary) data-highlighted:text-(--ui-primary) data-highlighted:before:bg-(--ui-primary)/10 data-[state=open]:before:bg-(--ui-primary)/10',
134
+ itemLeadingIcon: 'text-(--ui-primary) group-data-highlighted:text-(--ui-primary) group-data-[state=open]:text-(--ui-primary)'
135
+ }
136
+ },
137
+ {
138
+ color: 'primary',
139
+ active: true,
140
+ class: {
141
+ item: 'text-(--ui-primary) before:bg-(--ui-primary)/10',
142
+ itemLeadingIcon: 'text-(--ui-primary)'
143
+ }
144
+ }
145
+ ]
146
+ },
147
+ icons: {
148
+ arrowLeft: 'i-mdi-arrow-left',
149
+ arrowRight: 'i-mdi-arrow-right',
150
+ check: 'i-mdi-check',
151
+ chevronDoubleLeft: 'i-mdi-chevron-double-left',
152
+ chevronDoubleRight: 'i-mdi-chevron-double-right',
153
+ chevronDown: 'i-mdi-menu-down',
154
+ chevronLeft: 'i-mdi-menu-left',
155
+ chevronRight: 'i-mdi-menu-right',
156
+ chevronUp: 'i-mdi-menu-up',
157
+ close: 'i-mdi-close',
158
+ ellipsis: 'i-mdi-dots-horizontal',
159
+ external: 'i-mdi-open-in-new',
160
+ file: 'i-mdi-file',
161
+ folder: 'i-mdi-folder',
162
+ folderOpen: 'i-mdi-folder-open',
163
+ loading: 'i-mdi-loading',
164
+ minus: 'i-mdi-minus',
165
+ plus: 'i-mdi-plus',
166
+ search: 'i-mdi-magnify',
167
+ upload: 'i-mdi-upload'
168
+ },
169
+ input: {
170
+ variants: {
171
+ size: {
172
+ bcGovLg: {
173
+ base: 'px-2.5 pb-2 pt-6 text-base gap-1.5',
174
+ leading: 'ps-2.5',
175
+ trailing: 'pe-2.5',
176
+ leadingIcon: 'size-5',
177
+ leadingAvatarSize: '2xs',
178
+ trailingIcon: 'size-5'
179
+ }
180
+ },
181
+ variant: {
182
+ bcGov: 'ring-0 ring-transparent peer rounded-t-sm rounded-b-none bg-shade shadow-input focus:ring-0 focus:outline-none focus:shadow-input-focus text-neutral-highlighted'
183
+ }
184
+ },
185
+ defaultVariants: {
186
+ size: 'bcGovLg',
187
+ color: 'primary',
188
+ variant: 'bcGov'
189
+ }
190
+ },
191
+ textarea: {
192
+ variants: {
193
+ size: {
194
+ bcGovLg: {
195
+ base: 'px-2.5 pb-1.5 pt-5 text-base gap-1.5',
196
+ leading: 'ps-2.5',
197
+ trailing: 'pe-2.5',
198
+ leadingIcon: 'size-5',
199
+ leadingAvatarSize: '2xs',
200
+ trailingIcon: 'size-5'
201
+ }
202
+ },
203
+ variant: {
204
+ bcGov: 'peer rounded-t-sm rounded-b-none bg-shade focus:ring-0 focus:outline-none shadow-input focus:shadow-input-focus text-neutral-highlighted'
205
+ }
206
+ },
207
+ defaultVariants: {
208
+ size: 'bcGovLg',
209
+ color: 'primary',
210
+ variant: 'bcGov'
46
211
  }
47
212
  },
48
213
  tooltip: {
@@ -53,17 +218,3 @@ export default defineAppConfig({
53
218
  }
54
219
  }
55
220
  })
56
-
57
- declare module '@nuxt/schema' {
58
- interface AppConfigInput {
59
- connect?: {
60
- header?: {
61
- localeSelect?: boolean
62
- whatsNew?: boolean
63
- }
64
- footer?: {
65
- versions?: string[]
66
- }
67
- }
68
- }
69
- }
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps<{
3
+ address: Partial<ConnectAddress>
4
+ omitCountry?: boolean
5
+ }>()
6
+
7
+ const getAddressDisplayParts = (
8
+ address: Partial<ConnectAddress>,
9
+ separateCity = false,
10
+ addTextDecor = false,
11
+ omitCountry = false
12
+ ): string[] => {
13
+ const regionNamesInEnglish = new Intl.DisplayNames(['en'], { type: 'region' })
14
+ const textDecor = addTextDecor ? ',' : ''
15
+
16
+ const getLine1 = () => {
17
+ return (
18
+ address.street || [
19
+ [address.unitNumber, address.streetNumber].filter(val => !!val).join('-'),
20
+ address.streetName
21
+ ].filter(val => !!val).join(' ') || ''
22
+ ) + textDecor
23
+ }
24
+
25
+ const getLine2 = () => {
26
+ return (address.streetAdditional || '') + textDecor
27
+ }
28
+
29
+ const getCity = () => {
30
+ return (address.city || '') + textDecor
31
+ }
32
+
33
+ const getRegion = () => {
34
+ return address.region
35
+ ? address.region + (addTextDecor ? '\u00A0' : '')
36
+ : ''
37
+ }
38
+
39
+ const getCountry = () => {
40
+ return address.country && !omitCountry ? (regionNamesInEnglish.of(address.country) || address.country) : ''
41
+ }
42
+
43
+ return [
44
+ getLine1(),
45
+ getLine2(),
46
+ separateCity ? getCity() : '',
47
+ [!separateCity ? getCity() : '', getRegion(), address.postalCode].filter(val => !!val).join(' ') || '',
48
+ getCountry()
49
+ ].filter(val => !!val && val !== ',')
50
+ }
51
+
52
+ const addressDisplay = getAddressDisplayParts(props.address, false, true, props.omitCountry)
53
+ </script>
54
+
55
+ <template>
56
+ <div
57
+ data-testid="address-display"
58
+ class="flex flex-col gap-2"
59
+ >
60
+ <div>
61
+ <div
62
+ v-for="addressLine, i in addressDisplay"
63
+ :key="addressLine + i"
64
+ data-testid="address-line"
65
+ >
66
+ {{ addressLine }}
67
+ </div>
68
+ </div>
69
+ <span
70
+ v-if="address.locationDescription"
71
+ data-testid="location-description"
72
+ class="italic"
73
+ >
74
+ {{ address.locationDescription }}
75
+ </span>
76
+ </div>
77
+ </template>
@@ -38,7 +38,7 @@ function resolveBackHref() {
38
38
  v-if="$route.meta.hideBreadcrumbs !== true"
39
39
  class="bg-blue-350"
40
40
  >
41
- <div class="app-inner-container flex items-center px-4 py-2 gap-3">
41
+ <div class="app-inner-container flex items-center p-2 sm:px-4 py-2 gap-3">
42
42
  <UButton
43
43
  class="size-[28px] rounded-full px-1 bg-secondary hover:bg-secondary/75"
44
44
  :disabled="breadcrumbs.length < 2"
@@ -50,7 +50,7 @@ function resolveBackHref() {
50
50
  leadingIcon: 'text-blue-500',
51
51
  }"
52
52
  />
53
- <div class="w-[1px] bg-shadePrimary h-[24px]" />
53
+ <div class="w-[1px] bg-shade h-[24px]" />
54
54
  <UBreadcrumb
55
55
  :items="breadcrumbs"
56
56
  :aria-label="$t('connect.breadcrumb.arialabel')"
@@ -54,7 +54,7 @@ const appVersions = computed<string[]>(() => {
54
54
  <footer
55
55
  id="connect-main-footer"
56
56
  data-testid="connect-main-footer"
57
- class="border-t-2 border-brandLight bg-brandDark"
57
+ class="border-t-2 border-brand-inverted bg-brand"
58
58
  >
59
59
  <div class="app-inner-container flex items-center justify-between p-2">
60
60
  <nav :aria-label="$t('connect.footer.navLabel')" class="flex grow">
@@ -65,7 +65,7 @@ const appVersions = computed<string[]>(() => {
65
65
  :class="[
66
66
  'flex-col gap-2 border-r-0 pr-2 last:mr-0',
67
67
  'last:border-r-0 sm:mr-2 sm:inline-block sm:flex-none',
68
- 'sm:border-r sm:first:ml-2 border-lineLight',
68
+ 'sm:border-r sm:first:ml-2 border-line',
69
69
  ]"
70
70
  >
71
71
  <NuxtLink
@@ -83,7 +83,7 @@ const appVersions = computed<string[]>(() => {
83
83
  </ul>
84
84
  </nav>
85
85
  <div class="-mb-1 flex items-center">
86
- <span class="italic text-brandLight">{{ $t('connect.label.bcApp') }}</span>
86
+ <span class="italic text-brand-inverted">{{ $t('connect.label.bcApp') }}</span>
87
87
  <UTooltip arrow :delay-duration="200">
88
88
  <UButton
89
89
  :aria-label="$t('connect.label.appVersion')"
@@ -2,10 +2,10 @@
2
2
  <header
3
3
  id="connect-header-wrapper"
4
4
  data-testid="connect-header-wrapper"
5
- class="relative border-b-2 border-brandLight bg-brandDark"
5
+ class="relative border-b-2 border-brand-inverted bg-brand p-2 sm:px-4"
6
6
  >
7
7
  <nav
8
- class="app-inner-container px-2"
8
+ class="app-inner-container"
9
9
  :aria-label="$t('connect.header.navLabel')"
10
10
  >
11
11
  <slot />
@@ -6,13 +6,12 @@ const headerConfig = useAppConfig().connect.header
6
6
  <ConnectHeaderWrapper>
7
7
  <div class="flex items-center justify-between">
8
8
  <ConnectHeaderLogoHomeLink />
9
- <ClientOnly>
10
- <div class="flex gap-4">
11
- <slot />
9
+ <div class="flex gap-4">
10
+ <slot>
12
11
  <ConnectHeaderWhatsNew v-if="headerConfig.whatsNew" />
13
12
  <ConnectLocaleSelect v-if="headerConfig.localeSelect" />
14
- </div>
15
- </ClientOnly>
13
+ </slot>
14
+ </div>
16
15
  </div>
17
16
  </ConnectHeaderWrapper>
18
17
  </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps({
3
+ translationPath: { type: String, required: true }
4
+ })
5
+
6
+ const attrs = useAttrs()
7
+ const { t } = useI18n()
8
+
9
+ const textToDisplay = computed(() => {
10
+ const translationProps = {
11
+ ...attrs,
12
+ boldStart: '<strong>',
13
+ boldEnd: '</strong>',
14
+ italicStart: '<em>',
15
+ italicEnd: '</em>'
16
+ }
17
+ return t(props.translationPath, translationProps)
18
+ })
19
+ </script>
20
+
21
+ <template>
22
+ <!-- eslint-disable-next-line vue/no-v-html -->
23
+ <span v-html="textToDisplay" />
24
+ </template>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ const model = defineModel<string>({ required: true })
3
+
4
+ defineProps<{
5
+ id: string
6
+ label: string
7
+ mask?: string
8
+ invalid?: boolean
9
+ }>()
10
+ </script>
11
+
12
+ <template>
13
+ <UInput
14
+ :id
15
+ v-model.trim="model"
16
+ v-maska="mask"
17
+ :data-testid="id"
18
+ placeholder="&nbsp;"
19
+ class="w-full grow"
20
+ :ui="{
21
+ base: invalid ? 'ring-0 shadow-input-error focus:shadow-input-error' : '',
22
+ }"
23
+ >
24
+ <label
25
+ :for="id"
26
+ class="floating-label-input"
27
+ :class="invalid ? 'text-error' : ''"
28
+ >
29
+ {{ label }}
30
+ </label>
31
+ </UInput>
32
+ </template>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div class="app-container">
3
+ <slot name="header">
4
+ <ConnectHeader />
5
+ </slot>
6
+ <slot name="banner">
7
+ <ConnectSystemBanner />
8
+ </slot>
9
+ <slot name="breadcrumb">
10
+ <ConnectBreadcrumb />
11
+ </slot>
12
+ <div class="app-inner-container app-body">
13
+ <div class="flex flex-col lg:flex-row lg:gap-6 grow">
14
+ <div class="grow max-w-full overflow-hidden">
15
+ <slot />
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <slot name="footer">
20
+ <ConnectFooter />
21
+ </slot>
22
+ </div>
23
+ </template>
@@ -0,0 +1,51 @@
1
+ <script setup lang="ts">
2
+ const isSmallScreen = useMediaQuery('(max-width: 640px)')
3
+
4
+ defineProps<{
5
+ title: string
6
+ description: string
7
+ dismissible: boolean
8
+ buttons?: ConnectModalButton[]
9
+ }>()
10
+ defineEmits<{ close: [] }>()
11
+ </script>
12
+
13
+ <template>
14
+ <UModal
15
+ overlay
16
+ :title
17
+ :description
18
+ :dismissible
19
+ >
20
+ <template #content>
21
+ <div class="p-10 flex flex-col gap-6">
22
+ <div class="flex flex-col gap-6 text-left">
23
+ <h2>
24
+ {{ title }}
25
+ </h2>
26
+ <p class="-mt-2">
27
+ {{ description }}
28
+ </p>
29
+ </div>
30
+ <div v-if="buttons && buttons.length" class="flex flex-wrap items-center justify-center gap-4">
31
+ <template
32
+ v-for="button in buttons"
33
+ :key="button.label"
34
+ >
35
+ <UButton
36
+ v-if="button.shouldClose"
37
+ v-bind="button"
38
+ :block="isSmallScreen"
39
+ @click="$emit('close')"
40
+ />
41
+ <UButton
42
+ v-else
43
+ v-bind="button"
44
+ :block="isSmallScreen"
45
+ />
46
+ </template>
47
+ </div>
48
+ </div>
49
+ </template>
50
+ </UModal>
51
+ </template>
@@ -0,0 +1,57 @@
1
+ <script setup lang="ts">
2
+ import type { ButtonProps } from '#ui/types'
3
+
4
+ defineProps<{
5
+ heading?: {
6
+ label?: string
7
+ labelClass?: string
8
+ level?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
9
+ icon?: string
10
+ iconClass?: string
11
+ ui?: string
12
+ }
13
+ uiBody?: string
14
+ actions?: ButtonProps[]
15
+ }>()
16
+ </script>
17
+
18
+ <template>
19
+ <UCard
20
+ as="section"
21
+ class="w-full"
22
+ variant="outline"
23
+ :ui="{
24
+ header: heading?.ui ?? 'bg-shade-secondary px-4 py-4 sm:px-4 rounded-t-md',
25
+ body: uiBody ?? 'p-0 sm:p-0',
26
+ footer: 'p-0 sm:p-0',
27
+ }"
28
+ >
29
+ <template v-if="heading?.label || $slots.header" #header>
30
+ <slot name="header">
31
+ <div class="flex items-center justify-between gap-2.5">
32
+ <component :is="heading?.level || 'h2'">
33
+ <div class="flex items-center gap-2.5">
34
+ <UIcon
35
+ v-if="heading?.icon"
36
+ :name="heading.icon"
37
+ :class="heading?.iconClass || 'size-6 shrink-0 text-primary'"
38
+ />
39
+ <span :class="heading?.labelClass || 'font-semibold text-neutral-highlighted text-base'">
40
+ {{ heading?.label }}
41
+ </span>
42
+ </div>
43
+ </component>
44
+
45
+ <div class="flex items-center gap-2.5">
46
+ <UButton
47
+ v-for="(action, i) in actions"
48
+ :key="i"
49
+ v-bind="action"
50
+ />
51
+ </div>
52
+ </div>
53
+ </slot>
54
+ </template>
55
+ <slot />
56
+ </UCard>
57
+ </template>
@@ -14,11 +14,11 @@ defineProps<{
14
14
  :close="{
15
15
  color: 'neutral',
16
16
  variant: 'ghost',
17
- class: 'cursor-pointer hover:bg-gray-100/50 focus-visible:bg-transparent focus-visible:ring-2 rounded-full',
17
+ class: 'cursor-pointer hover:bg-shade/50 focus-visible:bg-transparent focus-visible:ring-2 rounded-full',
18
18
  }"
19
19
  :ui="{
20
- header: 'bg-brandLight',
21
- title: 'text-brandDark',
20
+ header: 'bg-brand-inverted',
21
+ title: 'text-brand',
22
22
  body: 'flex-1 overflow-y-auto p-0 sm:p-0',
23
23
  description: 'sr-only',
24
24
  }"
@@ -55,7 +55,7 @@ defineProps<{
55
55
  <!-- must style globally for vhtml style to work -->
56
56
  <style>
57
57
  .vhtml a {
58
- color: var(--ui-markBlue);
58
+ color: var(--ui-mark);
59
59
  text-decoration: underline;
60
60
  }
61
61
  </style>