diff --git a/odex30_base/odex_sidebar_backend_theme/ __init__.py b/odex30_base/odex_sidebar_backend_theme/ __init__.py
new file mode 100644
index 0000000..7c68785
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/ __init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
\ No newline at end of file
diff --git a/odex30_base/odex_sidebar_backend_theme/__manifest__.py b/odex30_base/odex_sidebar_backend_theme/__manifest__.py
new file mode 100644
index 0000000..f117350
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/__manifest__.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': 'Custom sidebar',
+ 'version': '18.0.1.0.0',
+ 'category': 'Web',
+ 'summary': 'Custom menu for navigating all Odoo apps and menus smoothly',
+ 'description': """
+ Replace the default Odoo app menu bar with a collapsible sidebar menu.
+ """,
+ 'author': 'Your Company',
+ 'website': 'https://www.yourcompany.com',
+ 'depends': ['web'],
+ 'data': [],
+ 'assets': {
+ 'web.assets_backend': [
+ 'odex_sidebar_backend_theme/static/src/scss/sidebar_menu.scss',
+
+ # 'odex_sidebar_backend_theme/static/src/xml/sidebar_menu_template.xml',
+ # 'odex_sidebar_backend_theme/static/src/xml/menu_item_template.xml',
+
+ 'odex_sidebar_backend_theme/static/src/js/sidebar_menu.js',
+ 'odex_sidebar_backend_theme/static/src/js/menu_item.js',
+
+ 'odex_sidebar_backend_theme/static/src/xml/navbar_patch.xml',
+ 'odex_sidebar_backend_theme/static/src/js/navbar_patch.js',
+ ],
+ },
+ 'installable': True,
+ 'application': False,
+ 'auto_install': False,
+ 'license': 'LGPL-3',
+}
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/js/menu_item.js b/odex30_base/odex_sidebar_backend_theme/static/src/js/menu_item.js
new file mode 100644
index 0000000..b84f5eb
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/js/menu_item.js
@@ -0,0 +1,56 @@
+/** @odoo-module **/
+
+import { Component, xml } from "@odoo/owl";
+import { useService } from "@web/core/utils/hooks";
+
+export class MenuItem extends Component {
+ static template = xml`
+
+
+
+
+ `
+
+ static components = { MenuItem };
+
+ // 2. نحدد الـ props التي يستقبلها المكون
+ static props = {
+ menu: { type: Object },
+ siblings: { type: Array },
+ };
+
+ setup() {
+ this.menuService = useService("menu");
+ }
+
+ // 3. تعديل دالة toggleMenu لتتعامل مع الأشقاء
+ toggleMenu(menu, siblings) {
+ const wasOpen = menu.isOpen; // نحفظ الحالة القديمة
+
+ // الخطوة أ: إغلاق جميع القوائم الشقيقة
+ for (const sibling of siblings) {
+ sibling.isOpen = false;
+ }
+
+ // الخطوة ب: فتح القائمة الحالية فقط إذا كانت مغلقة في الأصل
+ // هذا يمنعها من إعادة الفتح فورًا ويسمح بسلوك الإغلاق عند النقر عليها مرة أخرى
+ if (!wasOpen) {
+ menu.isOpen = true;
+ }
+ }
+
+ selectMenu(menu) {
+ this.menuService.selectMenu(menu);
+ }
+}
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/js/navbar_patch.js b/odex30_base/odex_sidebar_backend_theme/static/src/js/navbar_patch.js
new file mode 100644
index 0000000..32436bb
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/js/navbar_patch.js
@@ -0,0 +1,25 @@
+/** @odoo-module **/
+
+// **العودة إلى استيراد NavBar**
+import { NavBar } from "@web/webclient/navbar/navbar";
+import { patch } from "@web/core/utils/patch";
+import { useService } from "@web/core/utils/hooks";
+
+
+// **العودة إلى عمل patch لمكون NavBar**
+patch(NavBar.prototype, {
+ setup() {
+ super.setup(...arguments); // مهم جدًا
+ // استدعاء خدمة dialog
+ this.busService = useService("bus_service");
+ },
+
+ // 3. إضافة دالة لإرسال الحدث
+ toggleSidebar() {
+ this.busService.trigger("toggle-sidebar");
+ },
+});
+
+
+
+
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/js/sidebar_menu.js b/odex30_base/odex_sidebar_backend_theme/static/src/js/sidebar_menu.js
new file mode 100644
index 0000000..d90d079
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/js/sidebar_menu.js
@@ -0,0 +1,103 @@
+/** @odoo-module **/
+
+import { Component, onMounted, useEffect, useState, xml } from "@odoo/owl";
+import { registry } from "@web/core/registry";
+import { useService } from "@web/core/utils/hooks";
+import { MenuItem } from "./menu_item";
+
+export class SidebarMenu extends Component {
+ static template = xml`
+ `
+ ;
+
+ static components = { MenuItem };
+
+ setup() {
+ this.menuService = useService("menu");
+ this.busService = useService("bus_service");
+
+ this.state = useState({
+ menus: [],
+ isOpen: false
+ });
+
+ // =================== التحكم عبر JavaScript يبدأ هنا ===================
+
+ // const applyLayoutChanges = (isOpen) => {
+ // const actionManager = document.querySelector('.o_action_manager');
+ // const mainNavbar = document.querySelector('.o_navbar');
+ // const sidebarWidth = "250px";
+
+ // if (isOpen) {
+ // if (actionManager) actionManager.style.marginLeft = sidebarWidth;
+ // if (mainNavbar) mainNavbar.style.marginLeft = sidebarWidth;
+ // } else {
+ // if (actionManager) actionManager.style.marginLeft = '0';
+ // if (mainNavbar) mainNavbar.style.marginLeft = '0';
+ // }
+ // };
+
+ // // 2. استخدام useEffect لمراقبة التغييرات في state.isOpen
+ // useEffect(
+ // (isOpen) => {
+ // // هذا الكود سيعمل في كل مرة تتغير فيها قيمة isOpen
+ // applyLayoutChanges(isOpen);
+ // },
+ // () => [this.state.isOpen] // <-- هذا هو الجزء الحاسم: نطلب من useEffect مراقبة هذه القيمة
+ // );
+
+ // ====================================================================
+
+ // 1. عرّف الدالة كمتغير داخل setup
+ const toggleSidebar = () => {
+ // الآن `this` مضمون أنه يشير إلى نسخة المكون التي تم إنشاؤها بواسطة setup
+ this.state.isOpen = !this.state.isOpen;
+ // this.busService.trigger("sidebar-state-changed", this.state.isOpen);
+ };
+
+ // 2. اربطها بـ this حتى يمكن الوصول إليها من أماكن أخرى إذا لزم الأمر
+ this.toggleSidebar = toggleSidebar;
+ // ===============================================
+
+ onMounted(() => {
+ this.loadMenus();
+ this.busService.addEventListener("toggle-sidebar", this.toggleSidebar);
+ });
+ }
+
+ loadMenus() {
+ const allMenus = this.menuService.getAll();
+ const clonedMenus = structuredClone(allMenus);
+ const menuMap = new Map(clonedMenus.map(menu => [menu.id, menu]));
+ let finalMenuTree = [];
+
+ for (const menu of clonedMenus) {
+ if (menu.children) {
+ menu.children = menu.children.map(childId => menuMap.get(childId)).filter(Boolean);
+ } else {
+ menu.children = [];
+ }
+ menu.isOpen = false;
+ }
+
+ const rootMenu = clonedMenus.find(menu => menu.id === "root");
+ if (rootMenu && rootMenu.children) {
+ finalMenuTree = rootMenu.children;
+ }
+
+ this.state.menus.splice(0, this.state.menus.length, ...finalMenuTree);
+ }
+ }
+
+registry.category("main_components").add("sidebar_menu_component", {
+ Component: SidebarMenu,
+});
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/scss/sidebar_menu.scss b/odex30_base/odex_sidebar_backend_theme/static/src/scss/sidebar_menu.scss
new file mode 100644
index 0000000..1917c4e
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/scss/sidebar_menu.scss
@@ -0,0 +1,173 @@
+/* ===================================
+ 1. تصميم الـ Sidebar الرئيسي
+ =================================== */
+.custom_sidebar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 250px;
+ height: 100%;
+ background-color: #2f3542 !important;
+ overflow-y: auto;
+ z-index: 999;
+ padding-top: 60px;
+ transform: translateX(-100%);
+ transition: transform 0.3s ease-in-out;
+}
+
+.custom_sidebar .custom_icon_close {
+color: #fff;
+ position: absolute;
+ top: 8px;
+ right: 30px;
+ font-size: 1.2rem;
+ cursor: pointer;
+}
+
+/* عند إضافة كلاس is-open، تظهر القائمة */
+.custom_sidebar.is-open {
+ transform: translateX(0);
+}
+
+// اخقاء الايقون الافتراضية للابلكيشن من الشريط العلوي
+.o_navbar .o_main_navbar .o_navbar_apps_menu .o-dropdown {
+ display: none !important;
+}
+
+/* ===================================
+ 2. إخفاء الشريط العلوي وتعديل المحتوى الرئيسي
+ =================================== */
+.o_web_client {
+ margin-left: 0 !important;
+ transition: all 0.3s ease-in-out;
+}
+
+/* تعديل عرض الشريط العلوي والمحتوى الرئيسي */
+.o_navbar,
+.o_action_manager {
+ transition: all 0.3s ease-in-out;
+}
+
+/* إخفاء القوائم داخل الشريط العلوي */
+.o_main_navbar .o_menu_sections {
+ display: none !important;
+}
+
+/* ===================================
+ 3. تصميم عناصر القائمة (Accordion)
+ =================================== */
+
+/* تصميم حاوية عنصر القائمة الرئيسي */
+.custom_sidebar .menu-item-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ cursor: pointer;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.18);
+ transition: background-color 0.3s;
+}
+
+.custom_sidebar .sidebar_menu_list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+/* تصميم رابط القائمة الرئيسي */
+.custom_sidebar .menu-item-container .menu-item-link {
+ flex-grow: 1;
+ padding: 13px 9px;
+ color: #b9d0ec;
+ font-size: 15px;
+ text-decoration: none;
+}
+
+/* تغيير اللون عند الفتح (عندما يكون للعنصر li كلاس 'open') */
+.custom_sidebar li.open > .menu-item-container {
+ background: #45ae54;
+}
+
+.custom_sidebar li.open > .menu-item-container .menu-item-link {
+ color: #fff;
+}
+
+/* تصميم أيقونة الفتح/الإغلاق (السهم) */
+.custom_sidebar .toggle-icon {
+ width: 20px;
+ height: 20px;
+ margin-right: 10px;
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23b9d0ec' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e" );
+ background-repeat: no-repeat;
+ background-position: center;
+ transition: transform 0.2s ease-in-out;
+}
+
+/* تغيير لون السهم عند الفتح */
+.custom_sidebar li.open > .menu-item-container .toggle-icon {
+ transform: rotate(90deg);
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e" );
+}
+
+/* ===================================
+ 4. تصميم القوائم الفرعية
+ =================================== */
+.custom_sidebar .submenu_list {
+ list-style: none;
+ padding: 5px 0;
+ margin: 0;
+ background-color: rgba(0, 0, 0, 0.2); /* خلفية داكنة قليلاً للقوائم الفرعية */
+}
+
+.custom_sidebar .submenu_list li .menu-item-link {
+ font-size: 14px;
+ padding-left: 25px; /* مسافة بادئة أكبر لتمييز المستوى */
+}
+
+/* تصميم خاص بعناصر المستوى الأخير (التي لا تفتح قوائم أخرى) */
+.custom_sidebar .submenu_list li:not(.has-children) .menu-item-link {
+ color: #fff;
+ transition: all 0.3s;
+}
+
+.custom_sidebar .submenu_list li:not(.has-children) .menu-item-link:hover {
+ background-color: #193658;
+ color: #fff;
+}
+
+/* ===================================
+ 5. تصميم شريط التمرير (Scrollbar)
+ =================================== */
+.custom_sidebar::-webkit-scrollbar {
+ width: 8px;
+}
+
+.custom_sidebar::-webkit-scrollbar-track {
+ background: #2f3542; /* خلفية شريط التمرير بنفس لون الـ Sidebar */
+}
+
+.custom_sidebar::-webkit-scrollbar-thumb {
+ background-color: #45ae54;
+ border-radius: 4px;
+}
+
+.custom_sidebar::-webkit-scrollbar-thumb:hover {
+ background-color: #5bc569; /* لون أفتح قليلاً عند المرور */
+}
+
+/* ===================================
+ 6. تصميم أيقونة الفتح (جديد)
+ =================================== */
+.sidebar_toggle_icon {
+ position: relative;
+ display: flex;
+ align-items: center;
+ width: auto;
+ height: calc(var(--o-navbar-height) - 0px);
+ border-radius: 0;
+ user-select: none;
+ background: transparent;
+ color: var(--NavBar-entry-color, rgba(255, 255, 255, 0.9));
+ font-size: 1.2em;
+ padding: 0 15px;
+ border: none;
+}
\ No newline at end of file
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/xml/menu_item_template.xml b/odex30_base/odex_sidebar_backend_theme/static/src/xml/menu_item_template.xml
new file mode 100644
index 0000000..b408df6
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/xml/menu_item_template.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/xml/navbar_patch.xml b/odex30_base/odex_sidebar_backend_theme/static/src/xml/navbar_patch.xml
new file mode 100644
index 0000000..9f4bf58
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/xml/navbar_patch.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/odex30_base/odex_sidebar_backend_theme/static/src/xml/sidebar_menu_template.xml b/odex30_base/odex_sidebar_backend_theme/static/src/xml/sidebar_menu_template.xml
new file mode 100644
index 0000000..c3c5016
--- /dev/null
+++ b/odex30_base/odex_sidebar_backend_theme/static/src/xml/sidebar_menu_template.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+