@sbc-connect/nuxt-base 0.0.0-test-ld-20260520212549
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +11 -0
- package/CHANGELOG.md +338 -0
- package/LICENSE +28 -0
- package/README.md +55 -0
- package/app/app.config.ts +441 -0
- package/app/app.vue +18 -0
- package/app/assets/css/connect-base-layout.css +13 -0
- package/app/assets/css/connect-base-tw.css +303 -0
- package/app/components/Connect/Address/Display.vue +84 -0
- package/app/components/Connect/BCGovLogo.vue +42 -0
- package/app/components/Connect/Breadcrumb.vue +68 -0
- package/app/components/Connect/ButtonControl/Buttons.vue +28 -0
- package/app/components/Connect/ButtonControl/Index.vue +66 -0
- package/app/components/Connect/ButtonControl/Wrapper.vue +18 -0
- package/app/components/Connect/Contact/Display.vue +65 -0
- package/app/components/Connect/FloatingLabel.vue +67 -0
- package/app/components/Connect/Footer.vue +99 -0
- package/app/components/Connect/Header/LogoHomeLink.vue +20 -0
- package/app/components/Connect/Header/WhatsNew.vue +36 -0
- package/app/components/Connect/Header/Wrapper.vue +14 -0
- package/app/components/Connect/Header/index.vue +17 -0
- package/app/components/Connect/I18n/Helper.vue +40 -0
- package/app/components/Connect/Input.vue +69 -0
- package/app/components/Connect/InputDate.vue +104 -0
- package/app/components/Connect/Layout/Index.vue +25 -0
- package/app/components/Connect/Layout/Sidebar.vue +38 -0
- package/app/components/Connect/LocaleSelect.vue +37 -0
- package/app/components/Connect/Modal/Error.vue +76 -0
- package/app/components/Connect/Modal/index.vue +51 -0
- package/app/components/Connect/PageSection.vue +57 -0
- package/app/components/Connect/Select.vue +28 -0
- package/app/components/Connect/Slideover/WhatsNew.vue +61 -0
- package/app/components/Connect/Spinner.vue +91 -0
- package/app/components/Connect/SystemBanner.vue +53 -0
- package/app/components/Connect/Textarea.vue +27 -0
- package/app/components/Connect/Tombstone/Item.vue +51 -0
- package/app/components/Connect/Tombstone/index.vue +123 -0
- package/app/components/Connect/Transition/Collapse.vue +39 -0
- package/app/components/Connect/Transition/Fade.vue +31 -0
- package/app/components/HelloWorld/Index.vue +14 -0
- package/app/composables/useConnectButtonControl.ts +146 -0
- package/app/composables/useConnectLaunchDarkly.ts +173 -0
- package/app/composables/useConnectModal.ts +13 -0
- package/app/composables/useConnectTombstone.ts +25 -0
- package/app/coverage/app/app.config.ts.html +1408 -0
- package/app/coverage/app/app.vue.html +139 -0
- package/app/coverage/app/components/Connect/Address/Display.vue.html +337 -0
- package/app/coverage/app/components/Connect/Address/index.html +116 -0
- package/app/coverage/app/components/Connect/BCGovLogo.vue.html +211 -0
- package/app/coverage/app/components/Connect/Breadcrumb.vue.html +289 -0
- package/app/coverage/app/components/Connect/ButtonControl/Buttons.vue.html +166 -0
- package/app/coverage/app/components/Connect/ButtonControl/Index.vue.html +283 -0
- package/app/coverage/app/components/Connect/ButtonControl/Wrapper.vue.html +139 -0
- package/app/coverage/app/components/Connect/ButtonControl/index.html +146 -0
- package/app/coverage/app/components/Connect/Contact/Display.vue.html +280 -0
- package/app/coverage/app/components/Connect/Contact/index.html +116 -0
- package/app/coverage/app/components/Connect/FloatingLabel.vue.html +286 -0
- package/app/coverage/app/components/Connect/Footer.vue.html +382 -0
- package/app/coverage/app/components/Connect/Header/LogoHomeLink.vue.html +145 -0
- package/app/coverage/app/components/Connect/Header/WhatsNew.vue.html +193 -0
- package/app/coverage/app/components/Connect/Header/Wrapper.vue.html +127 -0
- package/app/coverage/app/components/Connect/Header/index.html +161 -0
- package/app/coverage/app/components/Connect/Header/index.vue.html +136 -0
- package/app/coverage/app/components/Connect/I18n/Helper.vue.html +205 -0
- package/app/coverage/app/components/Connect/I18n/index.html +116 -0
- package/app/coverage/app/components/Connect/Input.vue.html +262 -0
- package/app/coverage/app/components/Connect/InputDate.vue.html +406 -0
- package/app/coverage/app/components/Connect/Layout/Index.vue.html +160 -0
- package/app/coverage/app/components/Connect/Layout/Sidebar.vue.html +199 -0
- package/app/coverage/app/components/Connect/Layout/index.html +131 -0
- package/app/coverage/app/components/Connect/LocaleSelect.vue.html +196 -0
- package/app/coverage/app/components/Connect/Modal/Error.vue.html +313 -0
- package/app/coverage/app/components/Connect/Modal/index.html +131 -0
- package/app/coverage/app/components/Connect/Modal/index.vue.html +238 -0
- package/app/coverage/app/components/Connect/PageSection.vue.html +256 -0
- package/app/coverage/app/components/Connect/Select.vue.html +169 -0
- package/app/coverage/app/components/Connect/Slideover/WhatsNew.vue.html +268 -0
- package/app/coverage/app/components/Connect/Slideover/index.html +116 -0
- package/app/coverage/app/components/Connect/Spinner.vue.html +358 -0
- package/app/coverage/app/components/Connect/SystemBanner.vue.html +244 -0
- package/app/coverage/app/components/Connect/Textarea.vue.html +160 -0
- package/app/coverage/app/components/Connect/Tombstone/Item.vue.html +238 -0
- package/app/coverage/app/components/Connect/Tombstone/index.html +131 -0
- package/app/coverage/app/components/Connect/Tombstone/index.vue.html +454 -0
- package/app/coverage/app/components/Connect/Transition/Collapse.vue.html +202 -0
- package/app/coverage/app/components/Connect/Transition/Fade.vue.html +178 -0
- package/app/coverage/app/components/Connect/Transition/index.html +131 -0
- package/app/coverage/app/components/Connect/index.html +281 -0
- package/app/coverage/app/components/HelloWorld/Index.vue.html +127 -0
- package/app/coverage/app/components/HelloWorld/index.html +116 -0
- package/app/coverage/app/composables/index.html +161 -0
- package/app/coverage/app/composables/useConnectButtonControl.ts.html +523 -0
- package/app/coverage/app/composables/useConnectLaunchDarkly.ts.html +595 -0
- package/app/coverage/app/composables/useConnectModal.ts.html +124 -0
- package/app/coverage/app/composables/useConnectTombstone.ts.html +160 -0
- package/app/coverage/app/error.vue.html +247 -0
- package/app/coverage/app/index.html +146 -0
- package/app/coverage/app/interfaces/connect-address.ts.html +121 -0
- package/app/coverage/app/interfaces/connect-breadcrumb.ts.html +100 -0
- package/app/coverage/app/interfaces/connect-button-control.ts.html +151 -0
- package/app/coverage/app/interfaces/connect-contact-item.ts.html +103 -0
- package/app/coverage/app/interfaces/connect-modal.ts.html +100 -0
- package/app/coverage/app/interfaces/connect-tombstone.ts.html +208 -0
- package/app/coverage/app/interfaces/connect-whatsnew.ts.html +127 -0
- package/app/coverage/app/interfaces/index.html +206 -0
- package/app/coverage/app/layouts/ConnectBase.vue.html +100 -0
- package/app/coverage/app/layouts/index.html +116 -0
- package/app/coverage/app/plugins/index.html +146 -0
- package/app/coverage/app/plugins/maska.client.ts.html +115 -0
- package/app/coverage/app/plugins/sanitize.client.ts.html +151 -0
- package/app/coverage/app/plugins/whats-new.client.ts.html +220 -0
- package/app/coverage/app/types/dates.ts.html +136 -0
- package/app/coverage/app/types/index.html +116 -0
- package/app/coverage/app/utils/appendUrlParam.ts.html +97 -0
- package/app/coverage/app/utils/getErrorMessage.ts.html +211 -0
- package/app/coverage/app/utils/getErrorStatus.ts.html +196 -0
- package/app/coverage/app/utils/index.html +191 -0
- package/app/coverage/app/utils/logFetchError.ts.html +193 -0
- package/app/coverage/app/utils/parseSpecialCharacters.ts.html +160 -0
- package/app/coverage/app/utils/setBreadcrumbs.ts.html +100 -0
- package/app/coverage/base.css +224 -0
- package/app/coverage/block-navigation.js +87 -0
- package/app/coverage/clover.xml +2094 -0
- package/app/coverage/coverage-final.json +58 -0
- package/app/coverage/favicon.png +0 -0
- package/app/coverage/index.html +386 -0
- package/app/coverage/prettify.css +1 -0
- package/app/coverage/prettify.js +2 -0
- package/app/coverage/sort-arrow-sprite.png +0 -0
- package/app/coverage/sorter.js +210 -0
- package/app/error.vue +54 -0
- package/app/interfaces/connect-address.ts +12 -0
- package/app/interfaces/connect-breadcrumb.ts +5 -0
- package/app/interfaces/connect-button-control.ts +23 -0
- package/app/interfaces/connect-contact-item.ts +6 -0
- package/app/interfaces/connect-modal.ts +5 -0
- package/app/interfaces/connect-tombstone.ts +41 -0
- package/app/interfaces/connect-whatsnew.ts +14 -0
- package/app/layouts/ConnectBase.vue +5 -0
- package/app/plugins/maska.client.ts +10 -0
- package/app/plugins/sanitize.client.ts +22 -0
- package/app/plugins/whats-new.client.ts +45 -0
- package/app/spa-loading-template.html +61 -0
- package/app/types/base-app-config.d.ts +15 -0
- package/app/types/base-directives.d.ts +7 -0
- package/app/types/base-page-meta.d.ts +8 -0
- package/app/types/dates.ts +17 -0
- package/app/utils/appendUrlParam.ts +4 -0
- package/app/utils/getErrorMessage.ts +42 -0
- package/app/utils/getErrorStatus.ts +37 -0
- package/app/utils/logFetchError.ts +36 -0
- package/app/utils/parseSpecialCharacters.ts +25 -0
- package/app/utils/setBreadcrumbs.ts +7 -0
- package/firebase.json +34 -0
- package/i18n/locales/en-CA.ts +70 -0
- package/i18n/locales/fr-CA.ts +96 -0
- package/nuxt.config.ts +147 -0
- package/package.json +49 -0
- package/public/BCGovLogo/gov_bc_logo_horiz_en.png +0 -0
- package/public/BCGovLogo/gov_bc_logo_horiz_fr.png +0 -0
- package/public/BCGovLogo/gov_bc_logo_vert_en.png +0 -0
- package/public/BCGovLogo/gov_bc_logo_vert_fr.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/fonts/BCSans/BCSans-Bold.woff +0 -0
- package/public/fonts/BCSans/BCSans-Bold.woff2 +0 -0
- package/public/fonts/BCSans/BCSans-BoldItalic.woff +0 -0
- package/public/fonts/BCSans/BCSans-BoldItalic.woff2 +0 -0
- package/public/fonts/BCSans/BCSans-Italic.woff +0 -0
- package/public/fonts/BCSans/BCSans-Italic.woff2 +0 -0
- package/public/fonts/BCSans/BCSans-Regular.woff +0 -0
- package/public/fonts/BCSans/BCSans-Regular.woff2 +0 -0
- package/public/fonts/BCSans/LICENSE_OFL.txt +94 -0
- package/test-results/.last-run.json +7 -0
- package/test-results/error-page-404-Error-vue-D-1eb51-cted-visuals-with-404-error-Desktop-Chrome/error-context.md +135 -0
- package/test-results/error-page-404-Error-vue-D-1eb51-cted-visuals-with-404-error-Desktop-Chrome/test-failed-1.png +0 -0
- package/test-results/error-page-404-Error-vue-D-1eb51-cted-visuals-with-404-error-Desktop-Chrome/trace.zip +0 -0
- package/test-results/error-page-500-Error-vue-D-8c2cf-cted-visuals-with-500-error-Desktop-Chrome/error-context.md +135 -0
- package/test-results/error-page-500-Error-vue-D-8c2cf-cted-visuals-with-500-error-Desktop-Chrome/test-failed-1.png +0 -0
- package/test-results/error-page-500-Error-vue-D-8c2cf-cted-visuals-with-500-error-Desktop-Chrome/trace.zip +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
type VariantOption = 'input' | 'textarea' | 'select' | 'selectmenu'
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
variant = 'input'
|
|
6
|
+
} = defineProps<{
|
|
7
|
+
label: string
|
|
8
|
+
variant?: VariantOption
|
|
9
|
+
id: string
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const variantClass: Record<VariantOption, string[]> = {
|
|
13
|
+
input: [
|
|
14
|
+
'-translate-y-1/2 top-1/2 group-focus-within:top-3 delay-50',
|
|
15
|
+
'group-has-[div>input:not(:placeholder-shown)]:top-3',
|
|
16
|
+
'group-has-[div>input:not(:placeholder-shown)]:text-xs',
|
|
17
|
+
'group-has-[div>input[aria-invalid=true]]:text-error'
|
|
18
|
+
],
|
|
19
|
+
textarea: [
|
|
20
|
+
'top-1 group-focus-within:top-1 delay-50',
|
|
21
|
+
'group-has-[div>textarea:not(:placeholder-shown)]:top-1',
|
|
22
|
+
'group-has-[div>textarea:not(:placeholder-shown)]:text-xs',
|
|
23
|
+
'group-has-[div>textarea[aria-invalid=true]]:text-error'
|
|
24
|
+
],
|
|
25
|
+
select: [
|
|
26
|
+
'delay-100',
|
|
27
|
+
'-translate-y-1/2 top-1/2 group-focus-within:top-3',
|
|
28
|
+
'group-has-[button[aria-invalid=true]]:text-error',
|
|
29
|
+
'group-has-[button[data-state=open]]:top-3',
|
|
30
|
+
'group-has-[button[data-state=open]]:text-xs',
|
|
31
|
+
'group-has-[button:not([data-placeholder])]:top-3',
|
|
32
|
+
'group-has-[button:not([data-placeholder])]:text-xs',
|
|
33
|
+
'group-has-[button[data-state=open]:not([aria-invalid=true])]:text-primary'
|
|
34
|
+
],
|
|
35
|
+
selectmenu: [
|
|
36
|
+
'delay-100',
|
|
37
|
+
'-translate-y-1/2 top-1/2 group-focus-within:top-3',
|
|
38
|
+
'group-has-[button[aria-invalid=true]]:text-error',
|
|
39
|
+
'group-has-[button[data-state=open]]:top-3',
|
|
40
|
+
'group-has-[button[data-state=open]]:text-xs',
|
|
41
|
+
'group-has-[button[data-placeholder=false]]:top-3',
|
|
42
|
+
'group-has-[button[data-placeholder=false]]:text-xs',
|
|
43
|
+
'group-has-[button[data-state=open]:not([aria-invalid=true])]:text-primary'
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<div class="relative group">
|
|
50
|
+
<span
|
|
51
|
+
:id
|
|
52
|
+
:class="[
|
|
53
|
+
variantClass[variant],
|
|
54
|
+
'line-clamp-1 px-2.5',
|
|
55
|
+
'absolute z-10 group-focus-within:text-primary',
|
|
56
|
+
'pointer-events-none text-neutral transition-all',
|
|
57
|
+
'motion-reduce:transition-none duration-200',
|
|
58
|
+
'group-focus-within:text-xs',
|
|
59
|
+
'group-focus-within:text-primary',
|
|
60
|
+
'w-fit',
|
|
61
|
+
]"
|
|
62
|
+
>
|
|
63
|
+
{{ label }}
|
|
64
|
+
</span>
|
|
65
|
+
<slot />
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const rtc = useRuntimeConfig().public
|
|
3
|
+
const uiVersion = rtc.version
|
|
4
|
+
const feesUrl = `${rtc.registryHomeUrl}product-fees`
|
|
5
|
+
const dependencyVersions: string[] = useAppConfig().connect?.footer?.versions || []
|
|
6
|
+
const localePath = useLocalePath()
|
|
7
|
+
const links = [
|
|
8
|
+
{
|
|
9
|
+
label: 'connect.label.home',
|
|
10
|
+
to: localePath('/')
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
label: 'connect.label.fees',
|
|
14
|
+
to: feesUrl,
|
|
15
|
+
target: '_blank'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: 'connect.label.disclaimer',
|
|
19
|
+
to: 'https://www2.gov.bc.ca/gov/content/home/disclaimer',
|
|
20
|
+
target: '_blank'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: 'connect.label.privacy',
|
|
24
|
+
to: 'https://www2.gov.bc.ca/gov/content/home/privacy',
|
|
25
|
+
target: '_blank'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'connect.label.accessibility',
|
|
29
|
+
to: 'https://www2.gov.bc.ca/gov/content/home/accessibility',
|
|
30
|
+
target: '_blank'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
label: 'connect.label.copyright',
|
|
34
|
+
to: 'https://www2.gov.bc.ca/gov/content/home/copyright',
|
|
35
|
+
target: '_blank'
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
const appVersions = computed<string[]>(() => {
|
|
40
|
+
const items = [...dependencyVersions]
|
|
41
|
+
if (uiVersion) {
|
|
42
|
+
items.unshift(uiVersion)
|
|
43
|
+
}
|
|
44
|
+
return items
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<footer
|
|
50
|
+
id="connect-main-footer"
|
|
51
|
+
data-testid="connect-main-footer"
|
|
52
|
+
class="border-t-2 border-brand-inverted bg-brand p-2 sm:px-4"
|
|
53
|
+
>
|
|
54
|
+
<div class="app-inner-container flex items-center justify-between">
|
|
55
|
+
<nav :aria-label="$t('connect.footer.navLabel')" class="flex grow">
|
|
56
|
+
<ul class="list-none flex-col gap-1 p-0 sm:-ml-2 sm:flex-row sm:flex-wrap">
|
|
57
|
+
<li
|
|
58
|
+
v-for="link in links"
|
|
59
|
+
:key="link.to"
|
|
60
|
+
:class="[
|
|
61
|
+
'flex-col gap-2 border-r-0 pr-2 last:mr-0',
|
|
62
|
+
'last:border-r-0 sm:mr-2 sm:inline-block sm:flex-none',
|
|
63
|
+
'sm:border-r sm:first:ml-2 border-line-muted',
|
|
64
|
+
]"
|
|
65
|
+
>
|
|
66
|
+
<NuxtLink
|
|
67
|
+
:to="link.to === '/' ? `/${$i18n.locale}` : link.to"
|
|
68
|
+
:target="link.target"
|
|
69
|
+
:class="[
|
|
70
|
+
'rounded p-1 text-sm text-secondary',
|
|
71
|
+
'hover:underline focus:outline-none',
|
|
72
|
+
'focus-visible:ring-2 focus-visible:ring-secondary',
|
|
73
|
+
]"
|
|
74
|
+
>
|
|
75
|
+
{{ $t(link.label) }}
|
|
76
|
+
</NuxtLink>
|
|
77
|
+
</li>
|
|
78
|
+
</ul>
|
|
79
|
+
</nav>
|
|
80
|
+
<div class="-mb-1 flex items-center">
|
|
81
|
+
<span class="italic text-brand-inverted">{{ $t('connect.label.bcApp') }}</span>
|
|
82
|
+
<UTooltip arrow :delay-duration="200">
|
|
83
|
+
<UButton
|
|
84
|
+
:aria-label="$t('connect.label.appVersion')"
|
|
85
|
+
color="secondary"
|
|
86
|
+
icon="i-mdi-info-outline"
|
|
87
|
+
variant="ghost"
|
|
88
|
+
/>
|
|
89
|
+
|
|
90
|
+
<template #content>
|
|
91
|
+
<div class="flex flex-col">
|
|
92
|
+
<span v-for="(item, i) in appVersions" :key="i">{{ item }}</span>
|
|
93
|
+
</div>
|
|
94
|
+
</template>
|
|
95
|
+
</UTooltip>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</footer>
|
|
99
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const localePath = useLocalePath()
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<NuxtLink
|
|
7
|
+
id="header-logo-home-link"
|
|
8
|
+
:to="localePath('/')"
|
|
9
|
+
:class="[
|
|
10
|
+
'flex items-center gap-4 rounded-md',
|
|
11
|
+
'px-2 transition-colors duration-300',
|
|
12
|
+
'ease-in-out hover:bg-secondary/[0.1]',
|
|
13
|
+
'focus:outline-none focus-visible:ring-2 focus-visible:ring-secondary',
|
|
14
|
+
]"
|
|
15
|
+
:aria-label="$t('connect.header.homeLink')"
|
|
16
|
+
>
|
|
17
|
+
<ConnectBCGovLogo />
|
|
18
|
+
<span class="text-base font-semibold text-secondary lg:text-lg"> {{ $t('connect.header.title') }} </span>
|
|
19
|
+
</NuxtLink>
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useStorage } from '@vueuse/core'
|
|
3
|
+
import { ConnectSlideoverWhatsNew } from '#components'
|
|
4
|
+
|
|
5
|
+
const state = useStorage<ConnectWhatsNewState>('connect-whats-new', { viewed: false, items: [] })
|
|
6
|
+
const overlay = useOverlay()
|
|
7
|
+
const slideover = overlay.create(ConnectSlideoverWhatsNew)
|
|
8
|
+
|
|
9
|
+
function open() {
|
|
10
|
+
slideover.open({
|
|
11
|
+
items: state.value.items
|
|
12
|
+
})
|
|
13
|
+
state.value.viewed = true
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<UChip
|
|
19
|
+
:show="!state.viewed && state.items.length > 0"
|
|
20
|
+
color="error"
|
|
21
|
+
position="top-left"
|
|
22
|
+
inset
|
|
23
|
+
:ui="{
|
|
24
|
+
base: 'ring-(--ui-error)',
|
|
25
|
+
}"
|
|
26
|
+
>
|
|
27
|
+
<UButton
|
|
28
|
+
variant="ghost"
|
|
29
|
+
color="secondary"
|
|
30
|
+
class="px-2 py-1 text-sm"
|
|
31
|
+
:label="$t('connect.label.whatsNew')"
|
|
32
|
+
:aria-label="$t('connect.label.whatsNewAria', { count: state.viewed ? 0 : state.items.length })"
|
|
33
|
+
@click="open"
|
|
34
|
+
/>
|
|
35
|
+
</UChip>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<header
|
|
3
|
+
id="connect-header-wrapper"
|
|
4
|
+
data-testid="connect-header-wrapper"
|
|
5
|
+
class="relative border-b-2 border-brand-inverted bg-brand p-2 sm:px-4"
|
|
6
|
+
>
|
|
7
|
+
<nav
|
|
8
|
+
class="app-inner-container"
|
|
9
|
+
:aria-label="$t('connect.header.navLabel')"
|
|
10
|
+
>
|
|
11
|
+
<slot />
|
|
12
|
+
</nav>
|
|
13
|
+
</header>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const headerConfig = useAppConfig().connect.header
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<ConnectHeaderWrapper>
|
|
7
|
+
<div class="flex items-center justify-between">
|
|
8
|
+
<ConnectHeaderLogoHomeLink />
|
|
9
|
+
<div class="flex gap-4">
|
|
10
|
+
<slot>
|
|
11
|
+
<ConnectHeaderWhatsNew v-if="headerConfig.whatsNew" />
|
|
12
|
+
<ConnectLocaleSelect v-if="headerConfig.localeSelect" />
|
|
13
|
+
</slot>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</ConnectHeaderWrapper>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const {
|
|
3
|
+
translationPath,
|
|
4
|
+
as = 'span'
|
|
5
|
+
} = defineProps<{
|
|
6
|
+
translationPath: string
|
|
7
|
+
as?: 'h1'
|
|
8
|
+
| 'h2'
|
|
9
|
+
| 'h3'
|
|
10
|
+
| 'h4'
|
|
11
|
+
| 'h5'
|
|
12
|
+
| 'h6'
|
|
13
|
+
| 'label'
|
|
14
|
+
| 'span'
|
|
15
|
+
| 'p'
|
|
16
|
+
| 'div'
|
|
17
|
+
| 'li'
|
|
18
|
+
| 'legend'
|
|
19
|
+
| 'strong'
|
|
20
|
+
| 'em'
|
|
21
|
+
}>()
|
|
22
|
+
|
|
23
|
+
const attrs = useAttrs()
|
|
24
|
+
const { t } = useI18n()
|
|
25
|
+
|
|
26
|
+
const textToDisplay = computed(() => {
|
|
27
|
+
const translationProps = {
|
|
28
|
+
...attrs,
|
|
29
|
+
boldStart: '<strong>',
|
|
30
|
+
boldEnd: '</strong>',
|
|
31
|
+
italicStart: '<em>',
|
|
32
|
+
italicEnd: '</em>'
|
|
33
|
+
}
|
|
34
|
+
return t(translationPath, translationProps)
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<component :is="as" v-sanitize="textToDisplay" />
|
|
40
|
+
</template>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { InputProps } from '@nuxt/ui'
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
id,
|
|
6
|
+
autoFocus = false
|
|
7
|
+
} = defineProps<{
|
|
8
|
+
id: string
|
|
9
|
+
label: string
|
|
10
|
+
mask?: string
|
|
11
|
+
disabled?: boolean
|
|
12
|
+
autoFocus?: boolean
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const model = defineModel<InputProps['modelValue']>({ required: true })
|
|
16
|
+
const inputRef = useTemplateRef('input-ref')
|
|
17
|
+
|
|
18
|
+
// Inject props
|
|
19
|
+
const injectedProps = inject<InputProps>(
|
|
20
|
+
`UInput-props${id ? `-${id}` : ''}`,
|
|
21
|
+
{} as InputProps
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// Inject slots
|
|
25
|
+
const injectedSlots = inject<{ [key: string]: VNode }>(
|
|
26
|
+
`UInput-slots${id ? `-${id}` : ''}`,
|
|
27
|
+
{}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
defineExpose({ input: inputRef })
|
|
31
|
+
|
|
32
|
+
// vue ignore reason - type mismatch between model and defaultValue prop caused by strict generics
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<!-- @vue-ignore -->
|
|
37
|
+
<UInput
|
|
38
|
+
ref="input-ref"
|
|
39
|
+
v-bind="{
|
|
40
|
+
id,
|
|
41
|
+
disabled,
|
|
42
|
+
autofocus: autoFocus,
|
|
43
|
+
...injectedProps, // injected props will default when provided
|
|
44
|
+
}"
|
|
45
|
+
v-model.trim="model"
|
|
46
|
+
v-maska="mask"
|
|
47
|
+
class="w-full grow"
|
|
48
|
+
:data-testid="id"
|
|
49
|
+
placeholder=" "
|
|
50
|
+
>
|
|
51
|
+
<label
|
|
52
|
+
:for="id"
|
|
53
|
+
class="floating-label-input"
|
|
54
|
+
>
|
|
55
|
+
{{ label }}
|
|
56
|
+
</label>
|
|
57
|
+
|
|
58
|
+
<!-- Render injected slots -->
|
|
59
|
+
<template
|
|
60
|
+
v-for="(comp, name) in injectedSlots"
|
|
61
|
+
#[name]
|
|
62
|
+
:key="name"
|
|
63
|
+
>
|
|
64
|
+
<component
|
|
65
|
+
:is="comp"
|
|
66
|
+
/>
|
|
67
|
+
</template>
|
|
68
|
+
</UInput>
|
|
69
|
+
</template>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
// https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/
|
|
4
|
+
// https://whatsock.com/Templates/Datepickers/Basic,%20Auto%20Open/index.htm
|
|
5
|
+
import type { ConnectInput, UCalendar } from '#components'
|
|
6
|
+
import { CalendarDate } from '@internationalized/date'
|
|
7
|
+
import { DateTime } from 'luxon'
|
|
8
|
+
|
|
9
|
+
// FUTURE: update props as needed (min/max/disabled days)
|
|
10
|
+
defineProps<{
|
|
11
|
+
label: string
|
|
12
|
+
id: string
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits<{
|
|
16
|
+
blur: []
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const externalModel = defineModel<string | null | undefined>({ required: true })
|
|
20
|
+
|
|
21
|
+
const localModel = computed({
|
|
22
|
+
get() {
|
|
23
|
+
if (externalModel.value) {
|
|
24
|
+
const dt = DateTime.fromISO(externalModel.value, { zone: 'America/Vancouver' })
|
|
25
|
+
if (dt.isValid) {
|
|
26
|
+
return new CalendarDate(dt.year, dt.month, dt.day)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined
|
|
30
|
+
},
|
|
31
|
+
set(v) {
|
|
32
|
+
if (v) {
|
|
33
|
+
externalModel.value = DateTime.fromObject({
|
|
34
|
+
year: v.year,
|
|
35
|
+
month: v.month,
|
|
36
|
+
day: v.day
|
|
37
|
+
}).toISODate()
|
|
38
|
+
} else {
|
|
39
|
+
externalModel.value = null
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const open = ref(false)
|
|
45
|
+
const calendarRef = useTemplateRef('calendar-ref')
|
|
46
|
+
const inputRef = useTemplateRef<InstanceType<typeof ConnectInput>>('input-ref')
|
|
47
|
+
|
|
48
|
+
function focusCalendar() {
|
|
49
|
+
const button = (calendarRef.value as any)?.$el?.querySelector('button')
|
|
50
|
+
if (button) {
|
|
51
|
+
(button as HTMLButtonElement).focus()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function focusInput() {
|
|
56
|
+
inputRef.value?.input?.inputRef?.focus()
|
|
57
|
+
open.value = false
|
|
58
|
+
emit('blur')
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<UPopover
|
|
64
|
+
v-model:open="open"
|
|
65
|
+
:content="{
|
|
66
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
67
|
+
onEscapeKeyDown: () => {
|
|
68
|
+
focusInput()
|
|
69
|
+
},
|
|
70
|
+
side: 'bottom',
|
|
71
|
+
align: 'start',
|
|
72
|
+
}"
|
|
73
|
+
@update:open="(v) => {
|
|
74
|
+
if (!v) {
|
|
75
|
+
$emit('blur')
|
|
76
|
+
}
|
|
77
|
+
}"
|
|
78
|
+
>
|
|
79
|
+
<template #default>
|
|
80
|
+
<div class="w-full group">
|
|
81
|
+
<ConnectInput
|
|
82
|
+
:id
|
|
83
|
+
ref="input-ref"
|
|
84
|
+
v-model="externalModel"
|
|
85
|
+
:label
|
|
86
|
+
mask="####-##-##"
|
|
87
|
+
trailing-icon="i-mdi-calendar"
|
|
88
|
+
@focus="open = true"
|
|
89
|
+
@click.stop="open = true"
|
|
90
|
+
@keydown.down.prevent="focusCalendar"
|
|
91
|
+
/>
|
|
92
|
+
</div>
|
|
93
|
+
</template>
|
|
94
|
+
|
|
95
|
+
<template #content>
|
|
96
|
+
<UCalendar
|
|
97
|
+
ref="calendar-ref"
|
|
98
|
+
v-model="localModel"
|
|
99
|
+
class="p-2"
|
|
100
|
+
@update:model-value="focusInput"
|
|
101
|
+
/>
|
|
102
|
+
</template>
|
|
103
|
+
</UPopover>
|
|
104
|
+
</template>
|
|
@@ -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
|
+
<slot name="bottomHeaders" />
|
|
13
|
+
<main class="app-body px-2 sm:px-4">
|
|
14
|
+
<slot name="body">
|
|
15
|
+
<div class="app-inner-container grow flex flex-col overflow-clip">
|
|
16
|
+
<slot />
|
|
17
|
+
</div>
|
|
18
|
+
</slot>
|
|
19
|
+
</main>
|
|
20
|
+
<slot name="topFooters" />
|
|
21
|
+
<slot name="footer">
|
|
22
|
+
<ConnectFooter />
|
|
23
|
+
</slot>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { NavigationMenuItem } from '@nuxt/ui'
|
|
3
|
+
|
|
4
|
+
defineProps<{ items: NavigationMenuItem[] }>()
|
|
5
|
+
|
|
6
|
+
const showSideMenu = ref(true)
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<div class="flex gap-4 my-10 relative">
|
|
11
|
+
<UButton
|
|
12
|
+
class="absolute z-1 -top-8"
|
|
13
|
+
color="neutral"
|
|
14
|
+
size="xs"
|
|
15
|
+
:icon="showSideMenu ? 'i-mdi-minus' : 'i-mdi-plus'"
|
|
16
|
+
data-testid="connect-sidebar-toggle-btn"
|
|
17
|
+
@click="showSideMenu = !showSideMenu"
|
|
18
|
+
/>
|
|
19
|
+
<ConnectTransitionCollapse>
|
|
20
|
+
<div v-if="showSideMenu">
|
|
21
|
+
<UNavigationMenu
|
|
22
|
+
collapsible
|
|
23
|
+
:items
|
|
24
|
+
orientation="vertical"
|
|
25
|
+
class="text-neutral-highlighted"
|
|
26
|
+
variant="pill"
|
|
27
|
+
:ui="{
|
|
28
|
+
label: 'text-base',
|
|
29
|
+
link: 'cursor-pointer',
|
|
30
|
+
linkLabel: 'text-neutral-highlighted',
|
|
31
|
+
root: 'bg-white rounded p-3',
|
|
32
|
+
}"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</ConnectTransitionCollapse>
|
|
36
|
+
<slot />
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DropdownMenuItem } from '@nuxt/ui'
|
|
3
|
+
import type { LocaleObject } from '@nuxtjs/i18n'
|
|
4
|
+
|
|
5
|
+
const { locale, locales, setLocale } = useI18n()
|
|
6
|
+
|
|
7
|
+
const items = computed((): DropdownMenuItem[][] => {
|
|
8
|
+
const options = locales.value.map((loc: LocaleObject) => {
|
|
9
|
+
const isCurrentLocal = loc.code === locale.value
|
|
10
|
+
return {
|
|
11
|
+
label: loc.name || 'N/A',
|
|
12
|
+
icon: isCurrentLocal ? 'i-mdi-check' : '',
|
|
13
|
+
onSelect: () => setLocale(loc.code),
|
|
14
|
+
class: isCurrentLocal ? 'bg-gray-100' : 'pl-8',
|
|
15
|
+
color: isCurrentLocal ? 'primary' as const : 'neutral' as const
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
return [options]
|
|
19
|
+
})
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<UDropdownMenu
|
|
24
|
+
v-if="items[0] && items[0].length > 1"
|
|
25
|
+
:items
|
|
26
|
+
color="secondary"
|
|
27
|
+
>
|
|
28
|
+
<UButton
|
|
29
|
+
data-testid="locale-select-dropdown"
|
|
30
|
+
icon="i-mdi-web"
|
|
31
|
+
:aria-label="$t('connect.label.localeSelect')"
|
|
32
|
+
size="lg"
|
|
33
|
+
variant="ghost"
|
|
34
|
+
color="secondary"
|
|
35
|
+
/>
|
|
36
|
+
</UDropdownMenu>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { VNode } from 'vue'
|
|
3
|
+
// https://vue-i18n.intlify.dev/api/composition.html#te-key-locale
|
|
4
|
+
const { t, te } = useI18n()
|
|
5
|
+
|
|
6
|
+
interface ErrorModalProps {
|
|
7
|
+
error: unknown
|
|
8
|
+
i18nPrefix: string
|
|
9
|
+
buttons?: ConnectModalButton[]
|
|
10
|
+
contactInfo?: VNode
|
|
11
|
+
preferErrorMessage?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
error,
|
|
16
|
+
i18nPrefix,
|
|
17
|
+
buttons = [
|
|
18
|
+
{ label: useNuxtApp().$i18n.t('label.close'), shouldClose: true }
|
|
19
|
+
],
|
|
20
|
+
preferErrorMessage = false
|
|
21
|
+
} = defineProps<ErrorModalProps>()
|
|
22
|
+
defineEmits<{ close: [] }>()
|
|
23
|
+
|
|
24
|
+
const status = getErrorStatus(error)
|
|
25
|
+
const message = getErrorMessage(error)
|
|
26
|
+
|
|
27
|
+
const titleKey = `${i18nPrefix}.${status}.title`
|
|
28
|
+
const descKey = `${i18nPrefix}.${status}.description`
|
|
29
|
+
|
|
30
|
+
const title = te(titleKey) ? t(titleKey) : t(`${i18nPrefix}.undefined.title`)
|
|
31
|
+
const i18nDescription = te(descKey) ? t(descKey) : t(`${i18nPrefix}.undefined.description`)
|
|
32
|
+
|
|
33
|
+
const description = (preferErrorMessage && message)
|
|
34
|
+
? message
|
|
35
|
+
: i18nDescription
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<UModal
|
|
40
|
+
id="connect-error-modal"
|
|
41
|
+
overlay
|
|
42
|
+
:title
|
|
43
|
+
:description
|
|
44
|
+
:dismissible="false"
|
|
45
|
+
>
|
|
46
|
+
<template #content>
|
|
47
|
+
<div class="p-10 flex flex-col gap-6">
|
|
48
|
+
<h2 class="text-2xl font-semibold text-neutral-highlighted">
|
|
49
|
+
{{ title }}
|
|
50
|
+
</h2>
|
|
51
|
+
<p>{{ description }}</p>
|
|
52
|
+
<component :is="contactInfo" v-if="contactInfo" />
|
|
53
|
+
<div class="flex flex-wrap items-center justify-center gap-4">
|
|
54
|
+
<template
|
|
55
|
+
v-for="button in buttons"
|
|
56
|
+
:key="button.label"
|
|
57
|
+
>
|
|
58
|
+
<UButton
|
|
59
|
+
v-if="button.shouldClose"
|
|
60
|
+
v-bind="button"
|
|
61
|
+
size="xl"
|
|
62
|
+
class="w-full justify-center sm:w-min sm:justify-normal"
|
|
63
|
+
@click="$emit('close')"
|
|
64
|
+
/>
|
|
65
|
+
<UButton
|
|
66
|
+
v-else
|
|
67
|
+
v-bind="button"
|
|
68
|
+
size="xl"
|
|
69
|
+
class="w-full justify-center sm:w-min sm:justify-normal"
|
|
70
|
+
/>
|
|
71
|
+
</template>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</template>
|
|
75
|
+
</UModal>
|
|
76
|
+
</template>
|