@sbc-connect/nuxt-base 0.1.5 → 0.1.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 (39) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +1 -1
  3. package/app/app.config.ts +98 -5
  4. package/app/components/Connect/Address/Display.vue +77 -0
  5. package/app/components/Connect/Breadcrumb.vue +1 -1
  6. package/app/components/Connect/Footer.vue +3 -3
  7. package/app/components/Connect/Header/Wrapper.vue +1 -1
  8. package/app/components/Connect/Header/index.vue +4 -5
  9. package/app/components/Connect/Input.vue +1 -1
  10. package/app/components/Connect/Layout/Index.vue +25 -0
  11. package/app/components/Connect/Modal/index.vue +51 -0
  12. package/app/components/Connect/PageSection.vue +2 -2
  13. package/app/components/Connect/Slideover/WhatsNew.vue +3 -3
  14. package/app/components/Connect/SystemBanner.vue +8 -8
  15. package/app/components/Connect/Textarea.vue +2 -2
  16. package/app/components/Connect/Transition/Collapse.vue +39 -0
  17. package/app/composables/useConnectModal.ts +11 -0
  18. package/app/interfaces/connect-address.ts +12 -0
  19. package/app/interfaces/connect-modal.ts +5 -0
  20. package/app/layouts/ConnectBase.vue +3 -13
  21. package/app/plugins/whats-new.client.ts +1 -1
  22. package/app/utils/logFetchError.ts +36 -0
  23. package/modules/base-assets/index.ts +30 -0
  24. package/modules/{assets/runtime/assets/core-tw.css → base-assets/runtime/assets/connect-base-tw.css} +44 -44
  25. package/nuxt.config.ts +26 -18
  26. package/package.json +12 -13
  27. package/app/plugins/launchdarkly.client.ts +0 -9
  28. package/modules/assets/index.ts +0 -24
  29. package/modules/assets/runtime/assets/core-main.css +0 -6
  30. /package/modules/{assets/runtime/assets/core-layout.css → base-assets/runtime/assets/connect-base-layout.css} +0 -0
  31. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Bold.woff +0 -0
  32. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Bold.woff2 +0 -0
  33. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-BoldItalic.woff +0 -0
  34. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-BoldItalic.woff2 +0 -0
  35. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Italic.woff +0 -0
  36. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Italic.woff2 +0 -0
  37. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Regular.woff +0 -0
  38. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Regular.woff2 +0 -0
  39. /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/LICENSE_OFL.txt +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @sbc-connect/nuxt-base
2
2
 
3
+ ## 0.1.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [#28](https://github.com/bcgov/connect-nuxt/pull/28) [`68af125`](https://github.com/bcgov/connect-nuxt/commit/68af1259b87846f42010026977411481e53ca8fb) Thanks [@kialj876](https://github.com/kialj876)! - Filling out the pay layer. Ticket bcgov/entity#29337
8
+
9
+ ## 0.1.6
10
+
11
+ ### Patch Changes
12
+
13
+ - [#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
14
+
15
+ - [#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
16
+
17
+ - ConnectAddressDisplay component
18
+ - logFetchError util
19
+ - tests
20
+ - switch lodash for es-toolkit
21
+
22
+ issue: bcgov/entity#29335
23
+
24
+ - [#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
25
+
26
+ - connect-auth layout
27
+
28
+ issue: bcgov/entity#29335
29
+
3
30
  ## 0.1.5
4
31
 
5
32
  ### 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
@@ -38,6 +38,56 @@ export default defineAppConfig({
38
38
  button: {
39
39
  slots: {
40
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'
41
91
  }
42
92
  },
43
93
  card: {
@@ -47,9 +97,52 @@ export default defineAppConfig({
47
97
  },
48
98
  dropdownMenu: {
49
99
  slots: {
50
- content: 'bg-secondary ring-0',
51
- group: 'p-0'
52
- }
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
+ ]
53
146
  },
54
147
  icons: {
55
148
  arrowLeft: 'i-mdi-arrow-left',
@@ -86,7 +179,7 @@ export default defineAppConfig({
86
179
  }
87
180
  },
88
181
  variant: {
89
- bcGov: 'ring-0 ring-transparent peer rounded-t-sm rounded-b-none bg-shadePrimary shadow-input focus:ring-0 focus:outline-none focus:shadow-inputFocus text-neutralDark'
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'
90
183
  }
91
184
  },
92
185
  defaultVariants: {
@@ -108,7 +201,7 @@ export default defineAppConfig({
108
201
  }
109
202
  },
110
203
  variant: {
111
- bcGov: 'peer rounded-t-sm rounded-b-none bg-shadePrimary focus:ring-0 focus:outline-none shadow-input focus:shadow-inputFocus text-neutralDark'
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'
112
205
  }
113
206
  },
114
207
  defaultVariants: {
@@ -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>
@@ -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,7 +2,7 @@
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 p-2 sm:px-4"
5
+ class="relative border-b-2 border-brand-inverted bg-brand p-2 sm:px-4"
6
6
  >
7
7
  <nav
8
8
  class="app-inner-container"
@@ -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>
@@ -18,7 +18,7 @@ defineProps<{
18
18
  placeholder="&nbsp;"
19
19
  class="w-full grow"
20
20
  :ui="{
21
- base: invalid ? 'ring-0 shadow-inputError focus:shadow-inputError' : '',
21
+ base: invalid ? 'ring-0 shadow-input-error focus:shadow-input-error' : '',
22
22
  }"
23
23
  >
24
24
  <label
@@ -0,0 +1,25 @@
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
+ <slot name="body">
15
+ <div class="grow max-w-full overflow-hidden">
16
+ <slot />
17
+ </div>
18
+ </slot>
19
+ </div>
20
+ </div>
21
+ <slot name="footer">
22
+ <ConnectFooter />
23
+ </slot>
24
+ </div>
25
+ </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>
@@ -21,7 +21,7 @@ defineProps<{
21
21
  class="w-full"
22
22
  variant="outline"
23
23
  :ui="{
24
- header: heading?.ui ?? 'bg-shadeSecondary px-4 py-4 sm:px-4 rounded-t-md',
24
+ header: heading?.ui ?? 'bg-shade-secondary px-4 py-4 sm:px-4 rounded-t-md',
25
25
  body: uiBody ?? 'p-0 sm:p-0',
26
26
  footer: 'p-0 sm:p-0',
27
27
  }"
@@ -36,7 +36,7 @@ defineProps<{
36
36
  :name="heading.icon"
37
37
  :class="heading?.iconClass || 'size-6 shrink-0 text-primary'"
38
38
  />
39
- <span :class="heading?.labelClass || 'font-semibold text-neutralDark text-base'">
39
+ <span :class="heading?.labelClass || 'font-semibold text-neutral-highlighted text-base'">
40
40
  {{ heading?.label }}
41
41
  </span>
42
42
  </div>
@@ -14,11 +14,11 @@ defineProps<{
14
14
  :close="{
15
15
  color: 'neutral',
16
16
  variant: 'ghost',
17
- class: 'cursor-pointer hover:bg-shadePrimary/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
  }"
@@ -15,7 +15,7 @@ onMounted(async () => {
15
15
  </script>
16
16
 
17
17
  <template>
18
- <div class="bg-brandLight">
18
+ <div class="bg-brand-inverted">
19
19
  <UAlert
20
20
  v-show="!!message && !close"
21
21
  class="py-0"
@@ -23,18 +23,18 @@ onMounted(async () => {
23
23
  :close="dismissible"
24
24
  close-icon="i-mdi-close"
25
25
  :ui="{
26
- root: 'rounded-none bg-brandLight p-2 sm:px-4 app-inner-container',
27
- wrapper: 'bg-brandLight',
28
- close: 'mt-2 text-neutralDark',
26
+ root: 'rounded-none bg-brand-inverted p-2 sm:px-4 app-inner-container',
27
+ wrapper: 'bg-brand-inverted',
28
+ close: 'mt-2 text-neutral-highlighted',
29
29
  }"
30
30
  @update:open="close = true"
31
31
  >
32
- <!-- dismissible ? { class: 'pr-2 text-neutralDark' } : null -->
32
+ <!-- dismissible ? { class: 'pr-2 text-neutral-highlighted' } : null -->
33
33
  <template #description>
34
34
  <div class="flex gap-2 items-center py-2">
35
- <UIcon class="size-7 shrink-0 text-neutralDark self-start" :name="icon" />
35
+ <UIcon class="size-7 shrink-0 text-neutral-highlighted self-start" :name="icon" />
36
36
  <!-- eslint-disable vue/no-v-html tailwindcss/no-custom-classname -->
37
- <p class="vhtml text-neutralDark" v-html="message" />
37
+ <p class="vhtml text-neutral-highlighted" v-html="message" />
38
38
  </div>
39
39
  </template>
40
40
  </UAlert>
@@ -44,7 +44,7 @@ onMounted(async () => {
44
44
  <!-- must style globally for vhtml style to work -->
45
45
  <style>
46
46
  .vhtml > a {
47
- color: var(--ui-neutralDark);
47
+ color: var(--ui-neutral-highlighted);
48
48
  text-decoration: underline;
49
49
  }
50
50
  </style>
@@ -16,11 +16,11 @@ defineProps<{
16
16
  placeholder="&nbsp;"
17
17
  class="w-full grow"
18
18
  :ui="{
19
- base: invalid ? 'ring-0 shadow-inputError focus:shadow-inputError resize-none' : 'resize-none',
19
+ base: invalid ? 'ring-0 shadow-input-error focus:shadow-input-error resize-none' : 'resize-none',
20
20
  }"
21
21
  >
22
22
  <label
23
- class="floating-label-textarea bg-shadePrimary w-[96%] flex-1 pt-1 -mt-1"
23
+ class="floating-label-textarea bg-shade w-[96%] flex-1 pt-1 -mt-1"
24
24
  :class="invalid ? 'text-error' : ''"
25
25
  :for="id"
26
26
  >
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <Transition name="collapse">
3
+ <slot />
4
+ </Transition>
5
+ </template>
6
+
7
+ <style>
8
+ .collapse-enter-active,
9
+ .collapse-leave-active {
10
+ transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out;
11
+ }
12
+ .collapse-enter-from,
13
+ .collapse-leave-to {
14
+ max-height: 0;
15
+ opacity: 0;
16
+ }
17
+ .collapse-enter-to,
18
+ .collapse-leave-from {
19
+ max-height: 1000px;
20
+ opacity: 1;
21
+ }
22
+
23
+ @media (prefers-reduced-motion) {
24
+ .collapse-enter-active,
25
+ .collapse-leave-active {
26
+ transition: max-height 0s ease-out, opacity 0s ease-out;
27
+ }
28
+ .collapse-enter-from,
29
+ .collapse-leave-to {
30
+ max-height: 0;
31
+ opacity: 0;
32
+ }
33
+ .collapse-enter-to,
34
+ .collapse-leave-from {
35
+ max-height: 1000px;
36
+ opacity: 1;
37
+ }
38
+ }
39
+ </style>
@@ -0,0 +1,11 @@
1
+ import { ConnectModal } from '#components'
2
+
3
+ export const useConnectModal = () => {
4
+ const overlay = useOverlay()
5
+
6
+ const baseModal = overlay.create(ConnectModal)
7
+
8
+ return {
9
+ baseModal
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ export interface ConnectAddress {
2
+ street: string
3
+ streetAdditional: string
4
+ city: string
5
+ region: string
6
+ postalCode: string
7
+ country: string
8
+ locationDescription: string
9
+ streetName?: string
10
+ streetNumber?: string
11
+ unitNumber?: string
12
+ }
@@ -0,0 +1,5 @@
1
+ import type { ButtonProps } from '@nuxt/ui'
2
+
3
+ export interface ConnectModalButton extends ButtonProps {
4
+ shouldClose?: boolean
5
+ }
@@ -1,15 +1,5 @@
1
1
  <template>
2
- <div class="app-container">
3
- <ConnectHeader />
4
- <ConnectSystemBanner />
5
- <ConnectBreadcrumb />
6
- <div class="app-inner-container app-body">
7
- <div class="flex flex-col lg:flex-row lg:gap-6 grow">
8
- <div class="grow max-w-full overflow-hidden">
9
- <slot />
10
- </div>
11
- </div>
12
- </div>
13
- <ConnectFooter />
14
- </div>
2
+ <ConnectLayout>
3
+ <slot />
4
+ </ConnectLayout>
15
5
  </template>
@@ -1,5 +1,5 @@
1
1
  import { useStorage } from '@vueuse/core'
2
- import isEqual from 'lodash-es/isEqual'
2
+ import { isEqual } from 'es-toolkit'
3
3
 
4
4
  export default defineNuxtPlugin({
5
5
  name: 'connect-whats-new-plugin',
@@ -0,0 +1,36 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ export function logFetchError(error: unknown, message: string) {
3
+ let status = 'Unknown Status'
4
+ let statusText = 'Unknown Status Text'
5
+ let hasMessage = false
6
+
7
+ if (error && typeof error === 'object' && 'response' in error && typeof (error as any).response === 'object') {
8
+ const response = (error as any).response
9
+
10
+ if ('status' in response && typeof response.status === 'number') {
11
+ status = response.status
12
+ }
13
+
14
+ if ('statusText' in response && typeof response.statusText === 'string') {
15
+ statusText = response.statusText
16
+ }
17
+
18
+ if (
19
+ 'data' in error
20
+ && (error as any).data
21
+ && typeof (error as any).data === 'object'
22
+ && 'message' in (error as any).data
23
+ ) {
24
+ statusText = statusText || (error as any).data.message
25
+ hasMessage = (error as any).data.message !== undefined
26
+ }
27
+
28
+ console.error(
29
+ `${message}: ${status} - ${statusText} ${
30
+ hasMessage ? `--- ${JSON.stringify((error as any).data)}` : ''
31
+ }`
32
+ )
33
+ } else {
34
+ console.error(message)
35
+ }
36
+ }
@@ -0,0 +1,30 @@
1
+ import { defineNuxtModule, createResolver, installModule } from 'nuxt/kit'
2
+
3
+ export default defineNuxtModule({
4
+ meta: {
5
+ name: 'base-assets',
6
+ configKey: 'baseAssets'
7
+ },
8
+ defaults: {},
9
+ async setup(_options, _nuxt) {
10
+ console.info('Setting up **base** assets module')
11
+ const resolver = createResolver(import.meta.url)
12
+
13
+ _nuxt.hook('nitro:config', async (nitroConfig) => {
14
+ nitroConfig.publicAssets ||= []
15
+ nitroConfig.publicAssets.push({
16
+ dir: resolver.resolve('./runtime/public'),
17
+ maxAge: 60 * 60 * 24 * 365
18
+ })
19
+ })
20
+
21
+ _nuxt.options.css.push(resolver.resolve('./runtime/assets/connect-base-tw.css'))
22
+ _nuxt.options.css.push(resolver.resolve('./runtime/assets/connect-base-layout.css'))
23
+ await installModule('@nuxt/ui')
24
+
25
+ _nuxt.options.alias = {
26
+ ..._nuxt.options.alias,
27
+ '#connect-theme': resolver.resolve('./runtime/assets/connect-base-tw.css')
28
+ }
29
+ }
30
+ })
@@ -12,23 +12,23 @@
12
12
  --ui-success: var(--color-green-600);
13
13
  --ui-warning: #F8661A;
14
14
  /* Custom themes */
15
- --ui-brandDark: var(--color-midnightBlue-900);
16
- --ui-brandLight: var(--color-yellow-400);
17
- --ui-lineDark: #6F7780;
18
- --ui-lineLight: var(--color-gray-300);
19
- --ui-lineSpecial: #899EB2;
15
+ --ui-brand: var(--color-midnightBlue-900);
16
+ --ui-brand-inverted: var(--color-yellow-400);
17
+ --ui-line: #6F7780;
18
+ --ui-line-muted: var(--color-gray-300);
19
+ --ui-line-highlighted: #899EB2;
20
20
  --ui-mark: #1A5A96;
21
- --ui-markHover: #0000EE;
21
+ --ui-mark-highlighted: #0000EE;
22
22
  --ui-neutral: var(--color-gray-700);
23
- --ui-neutralDark: var(--color-gray-900);
24
- --ui-neutralLight: #757575;
25
- --ui-shadeCaution: #FFF7E3;
26
- --ui-shadeLight: white;
27
- --ui-shadeNew: #E8F5E9;
28
- --ui-shadePrimary: var(--color-gray-100);
29
- --ui-shadeSecondary: #E2E8EE;
30
- --ui-shadeSpecial: var(--color-blue-50);
31
- --ui-shadeWarning: #FAE9E9;
23
+ --ui-neutral-highlighted: var(--color-gray-900);
24
+ --ui-neutral-toned: #757575;
25
+ --ui-shade-caution: #FFF7E3;
26
+ --ui-shade-inverted: white;
27
+ --ui-shade-new: #E8F5E9;
28
+ --ui-shade: var(--color-gray-100);
29
+ --ui-shade-secondary: #E2E8EE;
30
+ --ui-shade-highlighted: var(--color-blue-50);
31
+ --ui-shade-warning: #FAE9E9;
32
32
  --ui-radius: 0.1667rem;
33
33
  }
34
34
 
@@ -40,23 +40,23 @@
40
40
  --ui-success: var(--color-green-600);
41
41
  --ui-warning: #F8661A;
42
42
  /* Custom themes */
43
- --ui-brandDark: var(--color-midnightBlue-900);
44
- --ui-brandLight: var(--color-yellow-400);
45
- --ui-lineDark: #6F7780;
46
- --ui-lineLight: var(--color-gray-300);
47
- --ui-lineSpecial: #899EB2;
43
+ --ui-brand: var(--color-midnightBlue-900);
44
+ --ui-brand-inverted: var(--color-yellow-400);
45
+ --ui-line: #6F7780;
46
+ --ui-line-muted: var(--color-gray-300);
47
+ --ui-line-highlighted: #899EB2;
48
48
  --ui-mark: #1A5A96;
49
- --ui-markHover: #0000EE;
49
+ --ui-mark-highlighted: #0000EE;
50
50
  --ui-neutral: var(--color-gray-700);
51
- --ui-neutralDark: var(--color-gray-900);
52
- --ui-neutralLight: #757575;
53
- --ui-shadeCaution: #FFF7E3;
54
- --ui-shadeLight: white;
55
- --ui-shadeNew: #E8F5E9;
56
- --ui-shadePrimary: var(--color-gray-100);
57
- --ui-shadeSecondary: #E2E8EE;
58
- --ui-shadeSpecial: var(--color-blue-50);
59
- --ui-shadeWarning: #FAE9E9;
51
+ --ui-neutral-highlighted: var(--color-gray-900);
52
+ --ui-neutral-toned: #757575;
53
+ --ui-shade-caution: #FFF7E3;
54
+ --ui-shade-inverted: white;
55
+ --ui-shade-new: #E8F5E9;
56
+ --ui-shade: var(--color-gray-100);
57
+ --ui-shade-secondary: #E2E8EE;
58
+ --ui-shade-highlighted: var(--color-blue-50);
59
+ --ui-shade-warning: #FAE9E9;
60
60
  --ui-radius: 0.1667rem;
61
61
  }
62
62
 
@@ -75,8 +75,8 @@
75
75
 
76
76
  /* box shadow */
77
77
  --shadow-input: inset 0 -1px 0 0px var(--ui-neutral);
78
- --shadow-inputFocus: inset 0 -2px 0 0px var(--ui-primary);
79
- --shadow-inputError: inset 0 -2px 0 0px var(--ui-error);
78
+ --shadow-input-focus: inset 0 -2px 0 0px var(--ui-primary);
79
+ --shadow-input-error: inset 0 -2px 0 0px var(--ui-error);
80
80
 
81
81
  /* GRAY */
82
82
  --color-gray-50: #f8f9fa;
@@ -163,8 +163,8 @@
163
163
  font-family: "BCSans";
164
164
  font-style: normal;
165
165
  font-weight: 400;
166
- src: url("BCGovFonts/BCSans-Regular.woff2") format("woff2"),
167
- url("BCGovFonts/BCSans-Regular.woff") format("woff"); /* Optimized for very modern browsers */
166
+ src: url("/fonts/BCSans/BCSans-Regular.woff2") format("woff2"),
167
+ url("/fonts/BCSans/BCSans-Regular.woff") format("woff"); /* Optimized for very modern browsers */
168
168
  font-display: swap;
169
169
  }
170
170
 
@@ -172,15 +172,15 @@
172
172
  font-family: "BCSans";
173
173
  font-style: italic;
174
174
  font-weight: 400;
175
- src: url("BCGovFonts/BCSans-Italic.woff2") format("woff2"),
176
- url("BCGovFonts/BCSans-Italic.woff") format("woff"); /* Optimized for very modern browsers */
175
+ src: url("/fonts/BCSans/BCSans-Italic.woff2") format("woff2"),
176
+ url("/fonts/BCSans/BCSans-Italic.woff") format("woff"); /* Optimized for very modern browsers */
177
177
  font-display: swap;
178
178
  }
179
179
  @font-face {
180
180
  font-family: "BCSans";
181
181
  font-weight: 700;
182
- src: url("BCGovFonts/BCSans-Bold.woff2") format("woff2"),
183
- url("BCGovFonts/BCSans-Bold.woff") format("woff"); /* Optimized for very modern browsers */
182
+ src: url("/fonts/BCSans/BCSans-Bold.woff2") format("woff2"),
183
+ url("/fonts/BCSans/BCSans-Bold.woff") format("woff"); /* Optimized for very modern browsers */
184
184
  font-display: swap;
185
185
  }
186
186
 
@@ -188,8 +188,8 @@
188
188
  font-family: "BCSans";
189
189
  font-style: italic;
190
190
  font-weight: 700;
191
- src: url("BCGovFonts/BCSans-BoldItalic.woff2") format("woff2"),
192
- url("BCGovFonts/BCSans-BoldItalic.woff") format("woff"); /* Optimized for very modern browsers */
191
+ src: url("/fonts/BCSans/BCSans-BoldItalic.woff2") format("woff2"),
192
+ url("/fonts/BCSans/BCSans-BoldItalic.woff") format("woff"); /* Optimized for very modern browsers */
193
193
  font-display: swap;
194
194
  }
195
195
 
@@ -215,7 +215,7 @@ body {
215
215
  h2,
216
216
  h3,
217
217
  h4 {
218
- @apply text-neutralDark;
218
+ @apply text-neutral-highlighted;
219
219
  }
220
220
 
221
221
  h1,
@@ -247,15 +247,15 @@ body {
247
247
 
248
248
  td,
249
249
  th {
250
- @apply text-neutralDark text-sm;
250
+ @apply text-neutral-highlighted text-sm;
251
251
  }
252
252
 
253
253
  /* floating labels */
254
254
  .floating-label-input {
255
- @apply pointer-events-none absolute left-0 top-3 text-neutralDark transition-all motion-reduce:transition-none duration-200 text-xs font-medium px-2.5 peer-focus:top-3 peer-focus:text-xs peer-placeholder-shown:text-sm peer-placeholder-shown:top-1/2 -translate-y-1/2 peer-focus:text-primary;
255
+ @apply pointer-events-none absolute left-0 top-3 text-neutral-highlighted transition-all motion-reduce:transition-none duration-200 text-xs font-medium px-2.5 peer-focus:top-3 peer-focus:text-xs peer-placeholder-shown:text-sm peer-placeholder-shown:top-1/2 -translate-y-1/2 peer-focus:text-primary;
256
256
  }
257
257
 
258
258
  .floating-label-textarea {
259
- @apply pointer-events-none absolute left-0 top-1 text-neutralDark text-xs font-medium px-2.5 transition-all duration-200 peer-focus:top-1 peer-focus:text-xs peer-placeholder-shown:text-sm peer-placeholder-shown:top-2.5 peer-focus:translate-none peer-focus:text-primary;
259
+ @apply pointer-events-none absolute left-0 top-1 text-neutral-highlighted text-xs font-medium px-2.5 transition-all duration-200 peer-focus:top-1 peer-focus:text-xs peer-placeholder-shown:text-sm peer-placeholder-shown:top-2.5 peer-focus:translate-none peer-focus:text-primary;
260
260
  }
261
261
  }
package/nuxt.config.ts CHANGED
@@ -8,7 +8,6 @@ export default defineNuxtConfig({
8
8
  devtools: { enabled: false },
9
9
 
10
10
  alias: {
11
- 'BCGovFonts': resolve('./public/fonts/BCSans'),
12
11
  'BCGovLogoSmEn': resolve('./public/BCGovLogo/gov_bc_logo_vert_en.png'),
13
12
  'BCGovLogoSmFr': resolve('./public/BCGovLogo/gov_bc_logo_vert_fr.png'),
14
13
  'BCGovLogoLgEn': resolve('./public/BCGovLogo/gov_bc_logo_horiz_en.png'),
@@ -19,7 +18,7 @@ export default defineNuxtConfig({
19
18
  compatibilityDate: '2025-07-10',
20
19
 
21
20
  imports: {
22
- dirs: ['interfaces', 'types']
21
+ dirs: ['interfaces', 'types', 'enums']
23
22
  },
24
23
 
25
24
  modules: [
@@ -62,21 +61,23 @@ export default defineNuxtConfig({
62
61
  'info',
63
62
  'warning',
64
63
  'error',
65
- 'brandDark',
66
- 'brandLight',
67
- 'lineDark',
68
- 'lineLight',
69
- 'lineSpecial',
64
+ 'brand',
65
+ 'brand-inverted',
66
+ 'line',
67
+ 'line-muted',
68
+ 'line-highlighted',
69
+ 'mark',
70
+ 'mark-highlighted',
70
71
  'neutral',
71
- 'neutralDark',
72
- 'neutralLight',
73
- 'shadeCaution',
74
- 'shadeLight',
75
- 'shadeNew',
76
- 'shadePrimary',
77
- 'shadeSecondary',
78
- 'shadeSpecial',
79
- 'shadeWarning'
72
+ 'neutral-highlighted',
73
+ 'neutral-toned',
74
+ 'shade-caution',
75
+ 'shade-inverted',
76
+ 'shade-new',
77
+ 'shade',
78
+ 'shade-secondary',
79
+ 'shade-highlighted',
80
+ 'shade-warning'
80
81
  ]
81
82
  }
82
83
  },
@@ -92,6 +93,8 @@ export default defineNuxtConfig({
92
93
  'mdi:check',
93
94
  'mdi:chevron-double-left',
94
95
  'mdi:chevron-double-right',
96
+ 'mdi:chevron-left',
97
+ 'mdi:chevron-right',
95
98
  'mdi:menu-down',
96
99
  'mdi:menu-left',
97
100
  'mdi:menu-right',
@@ -106,7 +109,12 @@ export default defineNuxtConfig({
106
109
  'mdi:minus',
107
110
  'mdi:plus',
108
111
  'mdi:magnify',
109
- 'mdi:upload'
112
+ 'mdi:upload',
113
+ 'mdi:caret-down',
114
+ 'mdi:menu',
115
+ 'mdi:file-document-outline',
116
+ 'mdi:home',
117
+ 'mdi:web'
110
118
  ]
111
119
  }
112
120
  },
@@ -115,7 +123,7 @@ export default defineNuxtConfig({
115
123
  public: {
116
124
  // Should in alphabetical order
117
125
  appName: process.env.npm_package_name || '',
118
- version: `Connect Base Layer v${process.env.npm_package_version || ''}`,
126
+ version: `${process.env.npm_package_name} v${process.env.npm_package_version || ''}`,
119
127
  baseUrl: '',
120
128
  registryHomeUrl: '',
121
129
  ldClientId: '',
package/package.json CHANGED
@@ -1,32 +1,31 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-base",
3
3
  "type": "module",
4
- "version": "0.1.5",
4
+ "version": "0.1.7",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
8
8
  "dependencies": {
9
9
  "@iconify-json/mdi": "^1.2.3",
10
10
  "@nuxt/ui": "^3.3.0",
11
- "@nuxtjs/i18n": "^10.0.2",
11
+ "@nuxtjs/i18n": "^10.0.3",
12
+ "@vueuse/core": "^13.6.0",
13
+ "@vueuse/nuxt": "^13.6.0",
12
14
  "dompurify": "^3.2.6",
15
+ "es-toolkit": "^1.39.8",
13
16
  "launchdarkly-vue-client-sdk": "^2.4.1",
14
- "@vueuse/nuxt": "^13.5.0",
15
- "@vueuse/core": "^13.5.0",
16
- "lodash-es": "^4.17.21",
17
- "maska": "^3.1.1"
17
+ "maska": "^3.2.0"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@axe-core/playwright": "^4.10.2",
21
21
  "@vitest/coverage-v8": "^3.2.4",
22
- "dotenv": "^17.2.0",
23
- "nuxt": "^4.0.0",
22
+ "dotenv": "^17.2.1",
23
+ "nuxt": "^4.0.2",
24
24
  "typescript": "^5.8.3",
25
- "vue-tsc": "^3.0.3",
26
- "@types/lodash-es": "^4.17.12",
27
- "@sbc-connect/playwright-config": "0.0.4",
28
- "@sbc-connect/vitest-config": "0.0.5",
29
- "@sbc-connect/eslint-config": "0.0.5"
25
+ "vue-tsc": "^3.0.4",
26
+ "@sbc-connect/playwright-config": "0.0.5",
27
+ "@sbc-connect/eslint-config": "0.0.6",
28
+ "@sbc-connect/vitest-config": "0.0.6"
30
29
  },
31
30
  "scripts": {
32
31
  "preinstall": "npx only-allow pnpm",
@@ -1,9 +0,0 @@
1
- // import { LDPlugin } from 'launchdarkly-vue-client-sdk'
2
-
3
- // export default defineNuxtPlugin({
4
- // name: 'connect-launchdarkly-plugin',
5
- // parallel: true,
6
- // setup(nuxtApp) {
7
- // nuxtApp.vueApp.use(LDPlugin, { deferInitialization: true })
8
- // }
9
- // })
@@ -1,24 +0,0 @@
1
- import { defineNuxtModule, createResolver, installModule } from 'nuxt/kit'
2
-
3
- // Module options TypeScript interface definition
4
- export interface ModuleOptions {
5
- someconfig: boolean
6
- }
7
-
8
- export default defineNuxtModule<ModuleOptions>({
9
- meta: {
10
- name: 'assets',
11
- configKey: 'assets'
12
- },
13
- // Default configuration options of the Nuxt module
14
- defaults: {},
15
- async setup(_options, _nuxt) {
16
- console.info('Setting up assets module')
17
- const resolver = createResolver(import.meta.url)
18
-
19
- _nuxt.options.css.push(resolver.resolve('./runtime/assets/core-tw.css'))
20
- _nuxt.options.css.push(resolver.resolve('./runtime/assets/core-layout.css'))
21
- // _nuxt.options.css.push(resolver.resolve('./runtime/assets/core-main.css'))
22
- await installModule('@nuxt/ui')
23
- }
24
- })
@@ -1,6 +0,0 @@
1
- @import "tailwindcss";
2
- @import "@nuxt/ui";
3
- @import "./core-tw.css";
4
- @import "./core-layout.css";
5
-
6
- @source "../../../../app/";