@sbc-connect/nuxt-base 0.1.2 → 0.1.4

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 (35) hide show
  1. package/.env.example +11 -1
  2. package/CHANGELOG.md +45 -0
  3. package/LICENSE +28 -0
  4. package/README.md +36 -47
  5. package/app/app.config.ts +60 -5
  6. package/app/app.vue +16 -3
  7. package/app/components/Connect/BCGovLogo.vue +42 -0
  8. package/app/components/Connect/Breadcrumb.vue +61 -0
  9. package/app/components/Connect/Footer.vue +104 -0
  10. package/app/components/Connect/Header/LogoHomeLink.vue +20 -0
  11. package/app/components/Connect/Header/WhatsNew.vue +36 -0
  12. package/app/components/Connect/Header/Wrapper.vue +14 -0
  13. package/app/components/Connect/Header/index.vue +18 -0
  14. package/app/components/Connect/LocaleSelect.vue +37 -0
  15. package/app/components/Connect/Slideover/WhatsNew.vue +61 -0
  16. package/app/components/Connect/SystemBanner.vue +50 -0
  17. package/app/components/HelloWorld/Index.vue +2 -2
  18. package/app/composables/useConnectLaunchDarkly.ts +177 -0
  19. package/app/error.vue +53 -0
  20. package/app/interfaces/connect-breadcrumb.ts +5 -0
  21. package/app/interfaces/connect-whatsnew.ts +14 -0
  22. package/app/layouts/{default.vue → ConnectBase.vue} +4 -0
  23. package/app/plugins/launchdarkly.client.ts +9 -0
  24. package/app/plugins/sanitize.client.ts +13 -0
  25. package/app/plugins/whats-new.client.ts +45 -0
  26. package/app/spa-loading-template.html +39 -0
  27. package/app/utils/appendUrlParam.ts +4 -0
  28. package/i18n/locales/en-CA.ts +63 -0
  29. package/i18n/locales/fr-CA.ts +91 -0
  30. package/modules/assets/index.ts +2 -2
  31. package/modules/assets/runtime/assets/core-layout.css +3 -3
  32. package/modules/assets/runtime/assets/core-tw.css +71 -52
  33. package/nuxt.config.ts +89 -1
  34. package/package.json +19 -10
  35. package/eslint.config.ts +0 -3
package/.env.example CHANGED
@@ -1 +1,11 @@
1
- NUXT_BASE_URL="http://localhost:3000/"
1
+ # Web Urls
2
+ NUXT_PUBLIC_BASE_URL="http://localhost:3000/"
3
+ NUXT_PUBLIC_REGISTRY_HOME_URL="https://dev.bcregistry.gov.bc.ca/"
4
+
5
+ # API Urls
6
+ # Status API
7
+ NUXT_PUBLIC_STATUS_API_URL="https://status-api-dev.apps.gold.devops.gov.bc.ca"
8
+ NUXT_PUBLIC_STATUS_API_VERSION="/api/v1"
9
+
10
+ # LaunchDarkly
11
+ NUXT_PUBLIC_LD_CLIENT_ID=""
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @sbc-connect/nuxt-base
2
2
 
3
+ ## 0.1.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#18](https://github.com/bcgov/connect-nuxt/pull/18) [`90f240f`](https://github.com/bcgov/connect-nuxt/commit/90f240fd789a5286ded5df710bddd6dc953bcba5) Thanks [@deetz99](https://github.com/deetz99)! - **Feat: Whats New**
8
+
9
+ - fetch whats new inside a plugin
10
+ - whats new header button
11
+ - whats new slideover component
12
+ - whats new plugin tests
13
+ - fix eslint to ignore playwright reports
14
+ - whats new items tracked in local storage to display button chip or not
15
+
16
+ issue: bcgov/entity#29334
17
+
18
+ - [#15](https://github.com/bcgov/connect-nuxt/pull/15) [`0fb8c54`](https://github.com/bcgov/connect-nuxt/commit/0fb8c54e059d78b246b80a03f049d075b7bbcf72) Thanks [@deetz99](https://github.com/deetz99)! - - add spa-loading-template
19
+
20
+ - add error.vue
21
+ - add html attrs to app.vue
22
+ - add launch darkly composable & start tests
23
+ - add Banner component
24
+ - add iconify dep and icons to client bundle
25
+ - add test:unit:watch command to run vitest in watch mode
26
+ - update vitest config to search nested folders
27
+ - update --ui-radius var so rounded-md is 0.25rem
28
+ - remove core main css file causing duplicate fonts
29
+ - add html sanitizer plugin
30
+
31
+ issue: bcgov/entity#29334
32
+
33
+ - [#16](https://github.com/bcgov/connect-nuxt/pull/16) [`9b8c225`](https://github.com/bcgov/connect-nuxt/commit/9b8c225a011e3c89c9b490e93a554f55a4e29b78) Thanks [@kialj876](https://github.com/kialj876)! - - add base header components (logo, localeSelect, wrapper)
34
+
35
+ - add footer component
36
+ - appendUrlParam util
37
+
38
+ issue: bcgov/entity#29334
39
+
40
+ ## 0.1.3
41
+
42
+ ### Patch Changes
43
+
44
+ - [#9](https://github.com/bcgov/connect-nuxt/pull/9) [`e841fde`](https://github.com/bcgov/connect-nuxt/commit/e841fde27630d63efb2c152cd78d92b1193d1d5e) Thanks [@kialj876](https://github.com/kialj876)! - Add Nuxt back as a dev dependency
45
+
46
+ - [#8](https://github.com/bcgov/connect-nuxt/pull/8) [`c85ebfc`](https://github.com/bcgov/connect-nuxt/commit/c85ebfc879e19cce307b109c9d38044f71f482d2) Thanks [@kialj876](https://github.com/kialj876)! - Added in i18n, added base header components, added in styles for nuxt ui
47
+
3
48
  ## 0.1.2
4
49
 
5
50
  ### Patch Changes
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, bcgov
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,73 +1,62 @@
1
- # Nuxt Layer Starter
1
+ [![License](https://img.shields.io/badge/License-BSD%203%20Clause-blue.svg)](LICENSE) [![pkg.pr.new](https://pkg.pr.new/badge/OWNER/REPO)](https://pkg.pr.new/~/bcgov/connect-nuxt)
2
2
 
3
- Create Nuxt extendable layer with this GitHub template.
3
+ # @sbc-connect/nuxt-base
4
+ The foundational Nuxt layer for all Connect applications.
4
5
 
5
- ## Setup
6
+ This package contains the core UI components, styling, and utilities for the Connect ecosystem. Extend this layer in your Nuxt project to get a consistent, on-brand starting point with zero configuration.
6
7
 
7
- Make sure to install the dependencies:
8
+ ## Features
8
9
 
9
- ```bash
10
- pnpm install
11
- ```
12
-
13
- ## Working on your layer
14
-
15
- Your layer is at the root of this repository, it is exactly like a regular Nuxt project, except you can publish it on NPM.
16
-
17
- The `.playground` directory should help you on trying your layer during development.
10
+ ### BC Government Branding
11
+ - Official color theme and design tokens
12
+ - BCSans font family with pre-configured @font-face rules
13
+ - BC Government logos and favicon assets
18
14
 
19
- Running `pnpm dev` will prepare and boot `.playground` directory, which imports your layer itself.
15
+ ### Core Development Assets
16
+ - A library of reusable base components
17
+ - Essential composables for common application logic
18
+ - Standard utility functions
19
+ - Pre-configured for Internationalization (i18n)
20
20
 
21
- ## Distributing your layer
22
-
23
- Your Nuxt layer is shaped exactly the same as any other Nuxt project, except you can publish it on NPM.
24
-
25
- To do so, you only have to check if `files` in `package.json` are valid, then run:
26
-
27
- ```bash
28
- npm publish --access public
29
- ```
21
+ For detailed usage and documentation, please see the [Base Layer Docs](../../../docs/packages/layers/base/intro.md)
30
22
 
31
- Once done, your users will only have to run:
23
+ ## Usage
32
24
 
25
+ ### Install
33
26
  ```bash
34
- npm install --save your-layer
27
+ pnpm install @sbc-connect/nuxt-base
35
28
  ```
36
29
 
37
- Then add the dependency to their `extends` in `nuxt.config`:
30
+ ### Configure
31
+ Then add the dependency to `extends` in `nuxt.config`:
38
32
 
39
33
  ```ts
40
34
  defineNuxtConfig({
41
- extends: 'your-layer'
35
+ extends: '@sbc-connect/nuxt-base'
42
36
  })
43
37
  ```
44
38
 
45
- ## Development Server
39
+ ### Environment Variables
40
+ This project requires certain environment variables to be set to run correctly.
46
41
 
47
- Start the development server on http://localhost:3000
42
+ Create a file named .env in the root of the project.
48
43
 
49
- ```bash
50
- pnpm dev
51
- ```
52
-
53
- ## Production
44
+ Copy the contents of the .env.example file into your new .env file.
54
45
 
55
- Build the application for production:
46
+ #### Local Development
47
+ For local development, the following variables are required. The default values are suitable for running the application on your local machine:
56
48
 
57
- ```bash
58
- pnpm build
59
49
  ```
60
-
61
- Or statically generate it with:
62
-
63
- ```bash
64
- pnpm generate
50
+ # .env
51
+ NUXT_BASE_URL="http://localhost:3000/"
65
52
  ```
66
53
 
67
- Locally preview production build:
54
+ #### Production Environments
55
+ > [!IMPORTANT]
56
+ > The values for staging and production environments are managed securely and should not be stored in this file.
68
57
 
69
- ```bash
70
- pnpm preview
71
- ```
58
+ To obtain the correct values for a production build or deployment, please contact the Connect Platform Team.
59
+
60
+ ## Contributing
72
61
 
73
- Checkout the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
62
+ We welcome contributions to this package! Please see the main [Contribution Guidelines](../../../CONTRIBUTING.md) for information on our branching strategy, commit conventions, and pull request process.
package/app/app.config.ts CHANGED
@@ -1,14 +1,69 @@
1
1
  export default defineAppConfig({
2
- myLayer: {
3
- name: 'Hello from Nuxt layer NEW AGAIN x 24!!'
2
+ connect: {
3
+ header: {
4
+ localeSelect: true,
5
+ whatsNew: true
6
+ },
7
+ footer: {
8
+ versions: []
9
+ }
10
+ },
11
+ ui: {
12
+ breadcrumb: {
13
+ slots: {
14
+ separatorIcon: 'text-secondary'
15
+ },
16
+ variants: {
17
+ active: {
18
+ true: {
19
+ link: 'text-secondary font-medium'
20
+ },
21
+ false: {
22
+ link: 'text-secondary underline font-medium'
23
+ }
24
+ }
25
+ },
26
+ compoundVariants: [
27
+ {
28
+ disabled: false,
29
+ active: false,
30
+ to: true,
31
+ class: {
32
+ link: 'hover:text-secondary hover:underline transition-colors'
33
+ }
34
+ }
35
+ ]
36
+ },
37
+ button: {
38
+ slots: {
39
+ base: 'cursor-pointer'
40
+ }
41
+ },
42
+ dropdownMenu: {
43
+ slots: {
44
+ content: 'bg-secondary ring-0',
45
+ group: 'p-0'
46
+ }
47
+ },
48
+ tooltip: {
49
+ slots: {
50
+ content: 'bg-neutral ring-neutral text-secondary p-4',
51
+ arrow: 'fill-neutral'
52
+ }
53
+ }
4
54
  }
5
55
  })
6
56
 
7
57
  declare module '@nuxt/schema' {
8
58
  interface AppConfigInput {
9
- myLayer?: {
10
- /** Project name */
11
- name?: string
59
+ connect?: {
60
+ header?: {
61
+ localeSelect?: boolean
62
+ whatsNew?: boolean
63
+ }
64
+ footer?: {
65
+ versions?: string[]
66
+ }
12
67
  }
13
68
  }
14
69
  }
package/app/app.vue CHANGED
@@ -1,5 +1,18 @@
1
+ <script setup lang="ts">
2
+ const { localeProperties } = useI18n()
3
+
4
+ useHead({
5
+ htmlAttrs: {
6
+ lang: () => localeProperties.value.code,
7
+ dir: () => localeProperties.value.dir
8
+ }
9
+ })
10
+ </script>
11
+
1
12
  <template>
2
- <nuxt-layout>
3
- <nuxt-page />
4
- </nuxt-layout>
13
+ <UApp :toaster="{ position: 'bottom-center' }">
14
+ <NuxtLayout>
15
+ <NuxtPage />
16
+ </NuxtLayout>
17
+ </UApp>
5
18
  </template>
@@ -0,0 +1,42 @@
1
+ <script setup lang="ts">
2
+ // must explicitly import or will fail when publishing layer // TODO: find better way to handle image aliases
3
+ // @ts-expect-error - Cannot find module 'BCGovLogoLgFr' or its corresponding type declarations.ts(2307)
4
+ import frLargeLogo from 'BCGovLogoLgFr'
5
+ // @ts-expect-error - Cannot find module 'BCGovLogoSmFr' or its corresponding type declarations.ts(2307)
6
+ import frSmallLogo from 'BCGovLogoSmFr'
7
+ // @ts-expect-error - Cannot find module 'BCGovLogoLgEn' or its corresponding type declarations.ts(2307)
8
+ import enLargeLogo from 'BCGovLogoLgEn'
9
+ // @ts-expect-error - Cannot find module 'BCGovLogoSmEn' or its corresponding type declarations.ts(2307)
10
+ import enSmallLogo from 'BCGovLogoSmEn'
11
+ </script>
12
+
13
+ <template>
14
+ <!-- use french logo for french locale, any other locale uses english logo -->
15
+ <div v-if="$i18n.locale === 'fr-CA'" class="shrink-0">
16
+ <!-- Using scale because it will increase the size of the image without affecting the container size -->
17
+ <!-- there is a lot of padding on the images, if only the height gets increased, -->
18
+ <!-- the padding makes the header too tall -->
19
+ <img
20
+ class="hidden h-[60px] scale-125 sm:block"
21
+ :src="frLargeLogo"
22
+ :alt="$t('connect.label.bcGovLogo')"
23
+ >
24
+ <img
25
+ class="block h-[64px] scale-125 sm:hidden"
26
+ :src="frSmallLogo"
27
+ :alt="$t('connect.label.bcGovLogo')"
28
+ >
29
+ </div>
30
+ <div v-else class="shrink-0">
31
+ <img
32
+ class="hidden h-[60px] scale-125 sm:block"
33
+ :src="enLargeLogo"
34
+ :alt="$t('connect.label.bcGovLogo')"
35
+ >
36
+ <img
37
+ class="block h-[64px] scale-150 sm:hidden"
38
+ :src="enSmallLogo"
39
+ :alt="$t('connect.label.bcGovLogo')"
40
+ >
41
+ </div>
42
+ </template>
@@ -0,0 +1,61 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps({ accountId: { type: String, required: false } })
3
+
4
+ const { t } = useI18n()
5
+
6
+ const breadcrumbs = computed<ConnectBreadcrumb[]>(() => {
7
+ const metaCrumbs = useRoute().meta.breadcrumbs as ConnectBreadcrumb[] | undefined
8
+
9
+ if (metaCrumbs) {
10
+ return metaCrumbs.map((bc) => {
11
+ if (bc.appendAccountId && props.accountId) {
12
+ return {
13
+ ...bc,
14
+ to: appendUrlParam(bc.to as string, 'accountid', props.accountId)
15
+ }
16
+ }
17
+ return bc
18
+ })
19
+ } else {
20
+ return [{ label: t('connect.breadcrumb.default') }]
21
+ }
22
+ })
23
+
24
+ function resolveBackHref() {
25
+ const bcLength = breadcrumbs.value.length
26
+
27
+ if (bcLength > 1) {
28
+ // return the second to last breadcrumb link
29
+ return breadcrumbs.value[bcLength - 2]?.to ?? breadcrumbs.value[bcLength - 2]?.href
30
+ } else {
31
+ return ''
32
+ }
33
+ }
34
+ </script>
35
+
36
+ <template>
37
+ <div
38
+ v-if="$route.meta.hideBreadcrumbs !== true"
39
+ class="bg-blue-350"
40
+ >
41
+ <div class="app-inner-container flex items-center px-4 py-2 gap-3">
42
+ <UButton
43
+ class="size-[28px] rounded-full px-1 bg-secondary hover:bg-secondary/75"
44
+ :disabled="breadcrumbs.length < 2"
45
+ color="secondary"
46
+ icon="i-mdi-arrow-left"
47
+ :aria-label="$t('connect.label.goBack')"
48
+ :to="resolveBackHref()"
49
+ :ui="{
50
+ leadingIcon: 'text-blue-500',
51
+ }"
52
+ />
53
+ <div class="w-[1px] bg-shadePrimary h-[24px]" />
54
+ <UBreadcrumb
55
+ :items="breadcrumbs"
56
+ :aria-label="$t('connect.breadcrumb.arialabel')"
57
+ separator-icon="i-mdi-chevron-right"
58
+ />
59
+ </div>
60
+ </div>
61
+ </template>
@@ -0,0 +1,104 @@
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.releaseNotes',
14
+ to: 'https://www.release-notes.bcregistry.gov.bc.ca',
15
+ target: '_blank'
16
+ },
17
+ {
18
+ label: 'connect.label.fees',
19
+ to: feesUrl,
20
+ target: '_blank'
21
+ },
22
+ {
23
+ label: 'connect.label.disclaimer',
24
+ to: 'https://www2.gov.bc.ca/gov/content/home/disclaimer',
25
+ target: '_blank'
26
+ },
27
+ {
28
+ label: 'connect.label.privacy',
29
+ to: 'https://www2.gov.bc.ca/gov/content/home/privacy',
30
+ target: '_blank'
31
+ },
32
+ {
33
+ label: 'connect.label.accessibility',
34
+ to: 'https://www2.gov.bc.ca/gov/content/home/accessibility',
35
+ target: '_blank'
36
+ },
37
+ {
38
+ label: 'connect.label.copyright',
39
+ to: 'https://www2.gov.bc.ca/gov/content/home/copyright',
40
+ target: '_blank'
41
+ }
42
+ ]
43
+
44
+ const appVersions = computed<string[]>(() => {
45
+ const items = [...dependencyVersions]
46
+ if (uiVersion) {
47
+ items.unshift(uiVersion)
48
+ }
49
+ return items
50
+ })
51
+ </script>
52
+
53
+ <template>
54
+ <footer
55
+ id="connect-main-footer"
56
+ data-testid="connect-main-footer"
57
+ class="border-t-2 border-brandLight bg-brandDark"
58
+ >
59
+ <div class="app-inner-container flex items-center justify-between p-2">
60
+ <nav :aria-label="$t('connect.footer.navLabel')" class="flex grow">
61
+ <ul class="list-none flex-col gap-1 p-0 sm:-ml-2 sm:flex-row sm:flex-wrap">
62
+ <li
63
+ v-for="link in links"
64
+ :key="link.to"
65
+ :class="[
66
+ 'flex-col gap-2 border-r-0 pr-2 last:mr-0',
67
+ 'last:border-r-0 sm:mr-2 sm:inline-block sm:flex-none',
68
+ 'sm:border-r sm:first:ml-2 border-lineLight',
69
+ ]"
70
+ >
71
+ <NuxtLink
72
+ :to="link.to === '/' ? `/${$i18n.locale}` : link.to"
73
+ :target="link.target"
74
+ :class="[
75
+ 'rounded p-1 text-sm text-secondary',
76
+ 'hover:underline focus:outline-none',
77
+ 'focus-visible:ring-2 focus-visible:ring-secondary',
78
+ ]"
79
+ >
80
+ {{ $t(link.label) }}
81
+ </NuxtLink>
82
+ </li>
83
+ </ul>
84
+ </nav>
85
+ <div class="-mb-1 flex items-center">
86
+ <span class="italic text-brandLight">{{ $t('connect.label.bcApp') }}</span>
87
+ <UTooltip arrow :delay-duration="200">
88
+ <UButton
89
+ :aria-label="$t('connect.label.appVersion')"
90
+ color="secondary"
91
+ icon="i-mdi-info-outline"
92
+ variant="ghost"
93
+ />
94
+
95
+ <template #content>
96
+ <div class="flex flex-col">
97
+ <span v-for="(item, i) in appVersions" :key="i">{{ item }}</span>
98
+ </div>
99
+ </template>
100
+ </UTooltip>
101
+ </div>
102
+ </div>
103
+ </footer>
104
+ </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-brandLight bg-brandDark"
6
+ >
7
+ <nav
8
+ class="app-inner-container px-2"
9
+ :aria-label="$t('connect.header.navLabel')"
10
+ >
11
+ <slot />
12
+ </nav>
13
+ </header>
14
+ </template>
@@ -0,0 +1,18 @@
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
+ <ClientOnly>
10
+ <div class="flex gap-4">
11
+ <slot />
12
+ <ConnectHeaderWhatsNew v-if="headerConfig.whatsNew" />
13
+ <ConnectLocaleSelect v-if="headerConfig.localeSelect" />
14
+ </div>
15
+ </ClientOnly>
16
+ </div>
17
+ </ConnectHeaderWrapper>
18
+ </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' : 'neutral'
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>