diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9487932..98d61b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.0.15] - 2025-07-30
+### Added
+- Menu bar compoenent
+
## [1.0.14] - 2025-07-29
### fixed
- Package publication error fixed
diff --git a/README.md b/README.md
index 9ba20ca..d8e7297 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
# visua-vue
-**Current version: v1.0.14**
\ No newline at end of file
+**Current version: v1.0.15**
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 3f85de8..a793179 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@cellule-financiere-pmo/visua-vue",
- "version": "1.0.14",
+ "version": "1.0.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@cellule-financiere-pmo/visua-vue",
- "version": "1.0.14",
+ "version": "1.0.15",
"license": "ISC",
"dependencies": {
"@cellule-financiere-pmo/visua": "1.1.3",
diff --git a/package.json b/package.json
index 8fe7545..a44bfb1 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,25 @@
{
"name": "@cellule-financiere-pmo/visua-vue",
- "version": "1.0.14",
+ "version": "1.0.15",
"type": "module",
"description": "Composants Vue.js du Design System Visua.",
"main": "dist/visua-vue.umd.js",
"module": "dist/visua-vue.es.js",
"types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "require": "./dist/visua-vue.umd.js",
+ "import": "./dist/visua-vue.es.js",
+ "types": "./dist/index.d.ts"
+ }
+ },
+ "sideEffects": false,
"files": [
- "dist"
+ "dist",
+ "src/components/*.vue",
+ "src/components/**/*.ts",
+ "src/components/**/*.type.ts",
+ "src/composables/*"
],
"scripts": {
"dev": "vite",
diff --git a/src/App.vue b/src/App.vue
index 6abd524..94c5e86 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -13,7 +13,8 @@
// import VAlertView from '../template/VAlertView.vue';
// import VModalView from '../template/VModalView.vue';
// import VConfirmModalView from '../template/VConfirmModalView.vue';
-import VDataTableView from '../template/VDataTableView.vue';
+// import VDataTableView from '../template/VDataTableView.vue';
+import VMenuBarView from '../template/VMenuBarView.vue'
@@ -32,5 +33,14 @@ import VDataTableView from '../template/VDataTableView.vue';
-
+
+
+
+
diff --git a/src/assets/base.css b/src/assets/base.css
index 5df8f7f..6800f62 100644
--- a/src/assets/base.css
+++ b/src/assets/base.css
@@ -8,4 +8,6 @@ html {
font-size: 16px;
font-family: var(--font-family-primary);
font-style: normal;
+ padding: 0px;
+ margin: 0px;
}
diff --git a/src/assets/style/global.css b/src/assets/style/global.css
index b326de8..fd714b6 100644
--- a/src/assets/style/global.css
+++ b/src/assets/style/global.css
@@ -31,7 +31,7 @@
/* menu */
--menu-container-border-color: var(--border-default-grey);
--menu-border-width: 0px 0px 0px var(--large-border-width);
- --menu-default-background: var(--background-transparent);
+ --menu-default-background: var(--background-default-grey);
--menu-default-color: var(--text-default-grey);
--menu-active-color: var(--text-active-blue-france);
--menu-hover-background: var(--background-transparent-active);
@@ -41,4 +41,5 @@
--menu-indent: 1rem;
--menu-border-color: transparent;
--menu-border-color-active: var(--border-active-blue-france);
+ --menu-border-radius: 0px;
}
diff --git a/src/assets/style/primevue-configuration.css b/src/assets/style/primevue-configuration.css
index 1a1ca2e..f07817d 100644
--- a/src/assets/style/primevue-configuration.css
+++ b/src/assets/style/primevue-configuration.css
@@ -21,3 +21,5 @@
@import './primevue-style/datatable.css';
@import './primevue-style/paginator.css';
@import './primevue-style/list.css';
+@import './primevue-style/menubar.css';
+@import './primevue-style/navigation.css';
diff --git a/src/assets/style/primevue-style/menubar.css b/src/assets/style/primevue-style/menubar.css
new file mode 100644
index 0000000..ec3e09c
--- /dev/null
+++ b/src/assets/style/primevue-style/menubar.css
@@ -0,0 +1,44 @@
+:root {
+ --p-menubar-mobile-button-border-radius: var(--menu-border-radius);
+ --p-menubar-mobile-button-size: 1.75rem;
+ --p-menubar-mobile-button-color: var(--text-active-blue-france);
+ --p-menubar-mobile-button-hover-color: var(--text-active-blue-france);
+ --p-menubar-mobile-button-hover-background: var(--background-transparent-active);
+ --p-menubar-mobile-button-focus-ring-width: var(--focus-width);
+ --p-menubar-mobile-button-focus-ring-style: var(--focus-style);
+ --p-menubar-mobile-button-focus-ring-color: var(--focus-color);
+ --p-menubar-mobile-button-focus-ring-offset: var(--focus-offset);
+ /* --p-menubar-mobile-button-focus-ring-shadow: */
+ --p-menubar-separator-border-color: var(--border-default-grey);
+ --p-menubar-submenu-padding: var(--p-navigation-list-padding);
+ --p-menubar-submenu-gap: var(--p-navigation-list-gap);
+ --p-menubar-submenu-background: var(--background-transparent);
+ --p-menubar-submenu-border-color: var(--border-default-grey);
+ --p-menubar-submenu-border-radius: var(--menu-border-radius);
+ --p-menubar-submenu-shadow: var(--shadow);
+ --p-menubar-submenu-mobile-indent: 1rem;
+ --p-menubar-submenu-icon-size: var(--p-navigation-submenu-icon-size);
+ --p-menubar-submenu-icon-color: var(--p-navigation-submenu-icon-color);
+ --p-menubar-submenu-icon-focus-color: var(--p-navigation-submenu-icon-focus-color);
+ --p-menubar-submenu-icon-active-color: var(--p-navigation-submenu-icon-active-color);
+ --p-menubar-item-focus-background: var(--p-navigation-item-focus-background);
+ --p-menubar-item-active-background: var(--p-navigation-item-active-background);
+ --p-menubar-item-color: var(--p-navigation-item-color);
+ --p-menubar-item-focus-color: var(--p-navigation-item-focus-color);
+ --p-menubar-item-active-color: var(--p-navigation-item-active-color);
+ --p-menubar-item-padding: var(--p-navigation-item-padding);
+ --p-menubar-item-border-radius: var(--p-navigation-item-border-radius);
+ --p-menubar-item-gap: var(--p-navigation-item-gap);
+ --p-menubar-item-icon-color: var(--p-navigation-item-icon-color);
+ --p-menubar-item-icon-focus-color: var(--p-navigation-item-icon-focus-color);
+ --p-menubar-item-icon-active-color: var(--p-navigation-item-icon-active-color);
+ --p-menubar-base-item-border-radius: var(--menu-border-radius);
+ --p-menubar-base-item-padding: var(--p-navigation-item-padding);
+ --p-menubar-background: var(--background-transparent);
+ --p-menubar-border-color: var(--border-default-grey);
+ --p-menubar-border-radius: var(--menu-border-radius);
+ --p-menubar-color: var(--menu-default-color);
+ --p-menubar-gap: 0.5rem;
+ --p-menubar-padding: var(--menu-padding);
+ --p-menubar-transition-duration: var(--transition-duration);
+}
diff --git a/src/assets/style/primevue-style/navigation.css b/src/assets/style/primevue-style/navigation.css
new file mode 100644
index 0000000..732ec93
--- /dev/null
+++ b/src/assets/style/primevue-style/navigation.css
@@ -0,0 +1,23 @@
+:root{
+ --p-navigation-submenu-icon-size: 0.875rem;
+ --p-navigation-submenu-label-padding: var(--menu-padding);
+ --p-navigation-submenu-label-font-weight: var( --titles-H4-SM-weight);
+ --p-navigation-item-padding: calc(var(--menu-padding) * 3);
+ --p-navigation-item-border-radius: var(--p-border-radius-sm);
+ --p-navigation-item-gap: var(--menu-item-gap);
+ --p-navigation-list-padding: var(--menu-padding);
+ --p-navigation-list-gap: var(--menu-gap);
+ --p-navigation-submenu-icon-color: var(--menu-default-color);
+ --p-navigation-submenu-icon-focus-color: var(--menu-active-color);
+ --p-navigation-submenu-icon-active-color: var(--menu-active-color);
+ --p-navigation-submenu-label-background: var(--menu-default-background);
+ --p-navigation-submenu-label-color: var(--menu-default-color);
+ --p-navigation-item-focus-background: var(--menu-default-background);
+ --p-navigation-item-active-background: var(--menu-default-background);
+ --p-navigation-item-color: var(--menu-default-color);
+ --p-navigation-item-focus-color: var(--menu-active-color);
+ --p-navigation-item-active-color: var(--menu-active-color);
+ --p-navigation-item-icon-color: var(--menu-default-color);
+ --p-navigation-item-icon-focus-color: var(--menu-active-color);
+ --p-navigation-item-icon-active-color: var(--menu-active-color);
+}
diff --git a/src/components/interface/index.ts b/src/components/interface/index.ts
index 2054a82..4c1f4a6 100644
--- a/src/components/interface/index.ts
+++ b/src/components/interface/index.ts
@@ -14,3 +14,5 @@ export type { default as IVMessage } from '../message/IVMessage.type';
export type { default as IVModal } from '../modal/IVModal.type';
export type { default as IVProgressBar } from '../progressbar/IVProgressBar.type';
export type { default as IVSelect } from '../select/IVSelect.type';
+export type { default as IVMenuBar } from '../menu/IVMenuBar.type';
+export type { default as IVMenuBarItem } from '../menu/IVMenuBar.type';
diff --git a/src/components/menu/IVMenuBar.type.ts b/src/components/menu/IVMenuBar.type.ts
new file mode 100644
index 0000000..3ab604e
--- /dev/null
+++ b/src/components/menu/IVMenuBar.type.ts
@@ -0,0 +1,91 @@
+import type { HTMLAttributes } from "vue"
+import type { RouteLocationRaw } from "vue-router"
+import type { MenuItem } from "primevue/menuitem"
+/**
+ * Describes a link or button item in a menu bar.
+ */
+export interface IVMenuBarLinks {
+ /** Whether the item should be rendered as a button */
+ button?: boolean;
+
+ /** Name of the icon to display on the left */
+ icon?: string;
+
+ /** Whether the icon appears on the right side */
+ iconRight?: boolean;
+
+ /** Text label for the item */
+ label?: string;
+
+ /** Target URL if rendered as an anchor () */
+ target?: string;
+
+ /** Callback executed when the item is clicked */
+ onClick?: ($event: MouseEvent) => void;
+
+ /** Navigation route */
+ to?: RouteLocationRaw;
+}
+
+/**
+ * Extends PrimeVue's MenuItem with optional routing capabilities.
+ * Excludes 'style' and 'class' to avoid conflicts with Vue attributes.
+ */
+export interface IVMenuBarItem
+ extends Partial>,
+ Partial> {}
+
+/**
+ * Interface for configuring a customizable menu bar component.
+ */
+export default interface IVMenuBar {
+ /** HTML id for the searchbar input */
+ searchbarId?: string;
+
+ /** Title of the service or application */
+ serviceTitle?: string;
+
+ /** Description of the service */
+ serviceDescription?: string;
+
+ /** Text displayed beside the logo (can be multiline) */
+ logoText?: string | string[];
+
+ /** Whether to show the logo */
+ logo?: boolean;
+
+ /** Bound model value for the search input */
+ modelValue?: string;
+
+ /** Placeholder text for the search input */
+ placeholder?: string;
+
+ /** List of quick link items with additional HTML attributes */
+ quickLinks?: (IVMenuBarItem & HTMLAttributes)[];
+
+ /** Label for the search input (accessibility) */
+ searchLabel?: string;
+
+ /** ARIA label for the quick links section */
+ quickLinksAriaLabel?: string;
+
+ /** Whether to display the search bar */
+ showSearch?: boolean;
+
+ /** Label describing the search bar visibility */
+ showSearchLabel?: string;
+
+ /** Label for the main menu toggle button */
+ menuLabel?: string;
+
+ /** Label used in modal menus */
+ menuModalLabel?: string;
+
+ /** Label for closing the modal menu */
+ closeMenuModalLabel?: string;
+
+ /** Responsive breakpoints (e.g. Tailwind-style classes) */
+ breakpoints?: string;
+}
+
+
diff --git a/src/components/menu/VMenuBar.vue b/src/components/menu/VMenuBar.vue
new file mode 100644
index 0000000..96a7c39
--- /dev/null
+++ b/src/components/menu/VMenuBar.vue
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
diff --git a/src/components/scrollpanel/VScrollpanel.vue b/src/components/scrollpanel/VScrollPanel.vue
similarity index 100%
rename from src/components/scrollpanel/VScrollpanel.vue
rename to src/components/scrollpanel/VScrollPanel.vue
diff --git a/src/index.ts b/src/index.ts
index ce643a7..a2fa461 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -14,6 +14,7 @@ export { default as VGroup } from './components/group/VGroup.vue';
export { default as VHint } from './components/hint/VHint.vue';
export { default as VInput } from './components/input/VInput.vue';
export { default as VLabel } from './components/label/VLabel.vue';
+export { default as VMenuBar } from './components/menu/VMenuBar.vue';
export { default as VMessage } from './components/message/VMessage.vue';
export { default as VModal } from './components/modal/VModal.vue';
export { default as VConfirmModal } from './components/modal/VConfirmModal.vue';
diff --git a/src/main.ts b/src/main.ts
index 590d577..7a6c56e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,11 +4,13 @@ import App from './App.vue'
import primeVue from 'primevue/config'
import ToastService from 'primevue/toastservice'
import ConfirmationService from 'primevue/confirmationservice'
+import router from '../template/router'
const app = createApp(App)
app.use(primeVue)
app.use(ToastService)
app.use(ConfirmationService)
+app.use(router)
app.mount('#app')
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 3bb66f6..88049a0 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -1,6 +1,6 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
- "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "test/VButton.spec.ts"],
+ "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "test/VButton.spec.ts", "template/router.ts"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
diff --git a/vitest.config.ts b/vitest.config.ts
index a2705ef..a13a13a 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -2,8 +2,10 @@
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vitest/config';
import path from 'path';
+import vue from '@vitejs/plugin-vue';
export default defineConfig({
+ plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),