@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.
- package/CHANGELOG.md +38 -0
- package/README.md +1 -1
- package/app/app.config.ts +167 -16
- package/app/components/Connect/Address/Display.vue +77 -0
- package/app/components/Connect/Breadcrumb.vue +2 -2
- package/app/components/Connect/Footer.vue +3 -3
- package/app/components/Connect/Header/Wrapper.vue +2 -2
- package/app/components/Connect/Header/index.vue +4 -5
- package/app/components/Connect/I18n/Helper.vue +24 -0
- package/app/components/Connect/Input.vue +32 -0
- package/app/components/Connect/Layout/Index.vue +23 -0
- package/app/components/Connect/Modal/index.vue +51 -0
- package/app/components/Connect/PageSection.vue +57 -0
- package/app/components/Connect/Slideover/WhatsNew.vue +4 -4
- package/app/components/Connect/Spinner.vue +94 -0
- package/app/components/Connect/SystemBanner.vue +8 -8
- package/app/components/Connect/Textarea.vue +30 -0
- package/app/components/Connect/Transition/Collapse.vue +39 -0
- package/app/composables/useConnectModal.ts +11 -0
- package/app/interfaces/connect-address.ts +12 -0
- package/app/interfaces/connect-modal.ts +5 -0
- package/app/layouts/ConnectBase.vue +3 -13
- package/app/plugins/maska.client.ts +10 -0
- package/app/plugins/whats-new.client.ts +1 -1
- package/app/spa-loading-template.html +60 -38
- package/app/types/base-app-config.d.ts +15 -0
- package/app/types/base-page-meta.d.ts +8 -0
- package/app/utils/logFetchError.ts +36 -0
- package/app/utils/parseSpecialCharacters.ts +25 -0
- package/app/utils/setBreadcrumbs.ts +5 -0
- package/i18n/locales/en-CA.ts +3 -2
- package/modules/base-assets/index.ts +30 -0
- package/modules/{assets/runtime/assets/core-tw.css → base-assets/runtime/assets/connect-base-tw.css} +48 -46
- package/nuxt.config.ts +43 -17
- package/package.json +9 -9
- package/app/plugins/launchdarkly.client.ts +0 -9
- package/modules/assets/index.ts +0 -24
- package/modules/assets/runtime/assets/core-main.css +0 -6
- /package/modules/{assets/runtime/assets/core-layout.css → base-assets/runtime/assets/connect-base-layout.css} +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Bold.woff +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Bold.woff2 +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-BoldItalic.woff +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-BoldItalic.woff2 +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Italic.woff +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Italic.woff2 +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Regular.woff +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/BCSans-Regular.woff2 +0 -0
- /package/{public → modules/base-assets/runtime/public}/fonts/BCSans/LICENSE_OFL.txt +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
fullscreen: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false
|
|
6
|
+
},
|
|
7
|
+
size: {
|
|
8
|
+
type: Number,
|
|
9
|
+
default: 75
|
|
10
|
+
}
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const spinnerStyle = computed(() => ({
|
|
14
|
+
'--spinner-size': `${props.size}px`,
|
|
15
|
+
'--spinner-margin': `${props.size / -2}px`
|
|
16
|
+
}))
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<!-- eslint-disable tailwindcss/no-custom-classname -->
|
|
21
|
+
<Teleport v-if="fullscreen" to="body">
|
|
22
|
+
<div class="fixed inset-0 z-[999] h-screen w-screen bg-gray-100 opacity-50" />
|
|
23
|
+
<svg
|
|
24
|
+
class="spinner fixed"
|
|
25
|
+
viewBox="0 0 50 50"
|
|
26
|
+
:style="spinnerStyle"
|
|
27
|
+
>
|
|
28
|
+
<circle
|
|
29
|
+
class="path"
|
|
30
|
+
cx="25"
|
|
31
|
+
cy="25"
|
|
32
|
+
r="20"
|
|
33
|
+
fill="none"
|
|
34
|
+
stroke-width="5"
|
|
35
|
+
/>
|
|
36
|
+
</svg>
|
|
37
|
+
</Teleport>
|
|
38
|
+
<svg
|
|
39
|
+
v-else
|
|
40
|
+
class="spinner absolute"
|
|
41
|
+
viewBox="0 0 50 50"
|
|
42
|
+
:style="spinnerStyle"
|
|
43
|
+
>
|
|
44
|
+
<circle
|
|
45
|
+
class="path"
|
|
46
|
+
cx="25"
|
|
47
|
+
cy="25"
|
|
48
|
+
r="20"
|
|
49
|
+
fill="none"
|
|
50
|
+
stroke-width="5"
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<style scoped>
|
|
56
|
+
.spinner {
|
|
57
|
+
animation: rotate 1.5s linear infinite;
|
|
58
|
+
z-index: 10000;
|
|
59
|
+
top: 50%;
|
|
60
|
+
left: 50%;
|
|
61
|
+
margin-top: var(--spinner-margin, -37.5px);
|
|
62
|
+
margin-left: var(--spinner-margin, -37.5px);
|
|
63
|
+
width: var(--spinner-size, 75px);
|
|
64
|
+
height: var(--spinner-size, 75px);
|
|
65
|
+
transform-origin: 50% 50%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.spinner .path {
|
|
69
|
+
stroke: #1669bb;
|
|
70
|
+
stroke-linecap: round;
|
|
71
|
+
animation: dash 1.25s ease-in-out infinite;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@keyframes rotate {
|
|
75
|
+
100% {
|
|
76
|
+
transform: rotate(360deg);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@keyframes dash {
|
|
81
|
+
0% {
|
|
82
|
+
stroke-dasharray: 1, 150;
|
|
83
|
+
stroke-dashoffset: 0;
|
|
84
|
+
}
|
|
85
|
+
50% {
|
|
86
|
+
stroke-dasharray: 90, 150;
|
|
87
|
+
stroke-dashoffset: -35;
|
|
88
|
+
}
|
|
89
|
+
100% {
|
|
90
|
+
stroke-dasharray: 90, 150;
|
|
91
|
+
stroke-dashoffset: -124;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -15,7 +15,7 @@ onMounted(async () => {
|
|
|
15
15
|
</script>
|
|
16
16
|
|
|
17
17
|
<template>
|
|
18
|
-
<div class="bg-
|
|
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-
|
|
27
|
-
wrapper: 'bg-
|
|
28
|
-
close: 'mt-2 text-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
47
|
+
color: var(--ui-neutral-highlighted);
|
|
48
48
|
text-decoration: underline;
|
|
49
49
|
}
|
|
50
50
|
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const model = defineModel<string>({ required: true })
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
id: string
|
|
6
|
+
label: string
|
|
7
|
+
invalid?: boolean
|
|
8
|
+
}>()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<UTextarea
|
|
13
|
+
:id
|
|
14
|
+
v-model.trim="model"
|
|
15
|
+
:data-testid="id"
|
|
16
|
+
placeholder=" "
|
|
17
|
+
class="w-full grow"
|
|
18
|
+
:ui="{
|
|
19
|
+
base: invalid ? 'ring-0 shadow-input-error focus:shadow-input-error resize-none' : 'resize-none',
|
|
20
|
+
}"
|
|
21
|
+
>
|
|
22
|
+
<label
|
|
23
|
+
class="floating-label-textarea bg-shade w-[96%] flex-1 pt-1 -mt-1"
|
|
24
|
+
:class="invalid ? 'text-error' : ''"
|
|
25
|
+
:for="id"
|
|
26
|
+
>
|
|
27
|
+
{{ label }}
|
|
28
|
+
</label>
|
|
29
|
+
</UTextarea>
|
|
30
|
+
</template>
|
|
@@ -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>
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
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,39 +1,61 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
border: solid 5px transparent;
|
|
14
|
-
border-top-color: #1669bb;
|
|
15
|
-
border-left-color: #1669bb;
|
|
16
|
-
border-bottom-color: #efefef;
|
|
17
|
-
border-right-color: #efefef;
|
|
18
|
-
border-radius: 50%;
|
|
19
|
-
-webkit-animation: loader 400ms linear infinite;
|
|
20
|
-
animation: loader 400ms linear infinite;
|
|
21
|
-
}
|
|
1
|
+
<head>
|
|
2
|
+
<title>Loading...</title>
|
|
3
|
+
<style>
|
|
4
|
+
.loading-container {
|
|
5
|
+
position: fixed;
|
|
6
|
+
inset: 0;
|
|
7
|
+
z-index: 9999;
|
|
8
|
+
background-color: rgba(241, 243, 245, 0.8);
|
|
9
|
+
display: flex;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
align-items: center;
|
|
12
|
+
}
|
|
22
13
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
14
|
+
.loader {
|
|
15
|
+
display: block;
|
|
16
|
+
width: 75px;
|
|
17
|
+
height: 75px;
|
|
18
|
+
animation: rotate 1.5s linear infinite;
|
|
19
|
+
transform-origin: 50% 50%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.loader .path {
|
|
23
|
+
stroke: #1669bb;
|
|
24
|
+
stroke-linecap: round;
|
|
25
|
+
animation: dash 1.25s ease-in-out infinite;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@keyframes rotate {
|
|
29
|
+
100% {
|
|
30
|
+
transform: rotate(360deg);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@keyframes dash {
|
|
35
|
+
0% {
|
|
36
|
+
stroke-dasharray: 1, 150;
|
|
37
|
+
stroke-dashoffset: 0;
|
|
38
|
+
}
|
|
39
|
+
50% {
|
|
40
|
+
stroke-dasharray: 90, 150;
|
|
41
|
+
stroke-dashoffset: -35;
|
|
42
|
+
}
|
|
43
|
+
100% {
|
|
44
|
+
stroke-dasharray: 90, 150;
|
|
45
|
+
stroke-dashoffset: -124;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
49
|
+
</head>
|
|
50
|
+
<div class="loading-container">
|
|
51
|
+
<svg class="loader" viewBox="0 0 50 50">
|
|
52
|
+
<circle
|
|
53
|
+
class="path"
|
|
54
|
+
cx="25"
|
|
55
|
+
cy="25"
|
|
56
|
+
r="20"
|
|
57
|
+
fill="none"
|
|
58
|
+
stroke-width="5"
|
|
59
|
+
/>
|
|
60
|
+
</svg>
|
|
61
|
+
</div>
|
|
@@ -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,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a string to decode HTML entities and remove HTML tags.
|
|
3
|
+
*
|
|
4
|
+
* @param text The string to parse.
|
|
5
|
+
* @param fallback The fallback text to return if the input is null or undefined.
|
|
6
|
+
* @returns The sanitized string.
|
|
7
|
+
*/
|
|
8
|
+
export function parseSpecialCharacters(text: string | undefined | null, fallback = 'N/A'): string {
|
|
9
|
+
// Return fallback text if the input is null or undefined.
|
|
10
|
+
if (text === null || text === undefined) {
|
|
11
|
+
return fallback
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const inputText = String(text)
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const parser = new DOMParser()
|
|
18
|
+
const doc = parser.parseFromString(inputText, 'text/html')
|
|
19
|
+
|
|
20
|
+
return doc.body.textContent || fallback
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(`Error parsing special characters in: ${inputText}`, error)
|
|
23
|
+
return fallback
|
|
24
|
+
}
|
|
25
|
+
}
|
package/i18n/locales/en-CA.ts
CHANGED
|
@@ -54,10 +54,11 @@ export default {
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
test: {
|
|
57
|
-
|
|
57
|
+
i18n: {
|
|
58
58
|
strong: 'This should have {boldStart} bold {boldEnd} text',
|
|
59
59
|
strongWithProps: 'This should have {boldStart} bold {boldEnd} text and allow a {prop}',
|
|
60
|
-
italic: 'Italic test {italicStart} goes here {italicEnd}.'
|
|
60
|
+
italic: 'Italic test {italicStart} goes here {italicEnd}.',
|
|
61
|
+
computed: 'This text will be updated. Updated {boldStart}{count}{boldEnd} times.'
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
}
|
|
@@ -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
|
+
})
|