Add Odex Sidebar Backend Theme 2 with collapsible menu and configuration options
This commit is contained in:
parent
575bb504ee
commit
144fffbb1a
|
|
@ -1 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
========================
|
||||
Odex Sidebar Backend Theme v2
|
||||
========================
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This module provides a modern, collapsible sidebar menu system that replaces the default Odex app menu bar with an enhanced navigation experience. It delivers an improved user interface with better space management and responsive design.
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
* **Collapsible/Expandable Sidebar Menu**: Toggle the sidebar to maximize screen space for your work
|
||||
* **Smooth Navigation**: Seamlessly navigate across all Odex applications and menus
|
||||
* **Responsive Design**: Adapts beautifully to different screen sizes (desktop, tablet, mobile)
|
||||
* **Persistent State**: Sidebar collapse/expand state is saved and persists across user sessions
|
||||
* **Enable/Disable Toggle**: Control the sidebar feature through the Settings panel
|
||||
* **Optimized Performance**: Minimal performance impact with efficient menu rendering
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
1. Download or clone this module into your Odex addons directory
|
||||
2. Restart the Odex server
|
||||
3. Navigate to **Apps** and search for "Odex Sidebar Backend Theme 2"
|
||||
4. Click **Install**
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
This module requires:
|
||||
|
||||
* Odex 18.0 (or compatible version)
|
||||
* web module
|
||||
* base module
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
After installation, you can configure the sidebar menu feature:
|
||||
|
||||
1. Navigate to **Settings > General Settings** (or **Settings > Sidebar Menu** if available)
|
||||
2. Find the **Sidebar Menu** section
|
||||
3. Enable or disable the sidebar menu feature as needed
|
||||
4. Click **Save**
|
||||
|
||||
The setting is automatically saved and persists across all user sessions.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Once enabled:
|
||||
|
||||
* Click the **menu icon** (≡) at the top of the sidebar to collapse/expand it
|
||||
* The sidebar state is automatically saved for your next session
|
||||
* All applications and menu items are accessible through the sidebar
|
||||
* The responsive design automatically adjusts on smaller screens
|
||||
|
||||
Module Structure
|
||||
================
|
||||
|
||||
::
|
||||
|
||||
odex_sidebar_backend_theme2/
|
||||
├── __init__.py # Python initialization
|
||||
├── __manifest__.py # Module metadata
|
||||
├── views/
|
||||
│ └── res_config_settings.xml # Settings configuration
|
||||
├── static/
|
||||
│ └── src/
|
||||
│ ├── scss/
|
||||
│ │ └── sidebar_menu.scss # Sidebar styling
|
||||
│ ├── js/
|
||||
│ │ ├── sidebar_menu.js # Main sidebar logic
|
||||
│ │ ├── sidebar_css_loader.js # CSS loading functionality
|
||||
│ │ ├── menu_item.js # Menu item handling
|
||||
│ │ └── navbar_patch.js # Navigation bar customizations
|
||||
│ └── xml/
|
||||
│ ├── sidebar_menu_template.xml # Sidebar template
|
||||
│ ├── menu_item_template.xml # Menu item template
|
||||
│ └── navbar_patch.xml # Navbar patches
|
||||
└── README.rst # This file
|
||||
|
||||
Technologies
|
||||
=============
|
||||
|
||||
* JavaScript (ES6+)
|
||||
* SCSS/CSS
|
||||
* XML (Odex QWeb templates)
|
||||
* Python
|
||||
|
||||
Browser Support
|
||||
===============
|
||||
|
||||
* Chrome/Edge 90+
|
||||
* Firefox 88+
|
||||
* Safari 14+
|
||||
* Mobile browsers (iOS Safari, Chrome Mobile)
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
**Sidebar not appearing:**
|
||||
- Clear your browser cache
|
||||
- Log out and log back in
|
||||
- Check that the module is enabled in Settings
|
||||
|
||||
**Sidebar not saving state:**
|
||||
- Ensure cookies are enabled in your browser
|
||||
- Check browser console for JavaScript errors (F12)
|
||||
|
||||
**Performance issues:**
|
||||
- Clear browser cache and local storage
|
||||
- Try disabling and re-enabling the module
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
For issues, questions, or feature requests, please contact Epxert Ltd.
|
||||
|
||||
* Website: https://www.exp-sa.com
|
||||
* Email: support@exp-sa.com
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This module is licensed under the LGPL-3 License. See the LICENSE file for details.
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
* Epxert Ltd. (https://www.exp-sa.com)
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
**Version 1.0.0** (Initial Release)
|
||||
- Initial release of Odex Sidebar Backend Theme 2
|
||||
- Collapsible sidebar menu functionality
|
||||
- Persistent state management
|
||||
- Responsive design support
|
||||
- Enable/disable toggle in settings
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
|
|
@ -1,26 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Odex Sidebar Backend Theme2',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'Web',
|
||||
'summary': 'Custom menu for navigating all Odoo apps and menus smoothly',
|
||||
'name': 'Odex Sidebar Backend Theme 2',
|
||||
'version': '1.0.0',
|
||||
'category': 'Web/Themes',
|
||||
'summary': 'Enhanced collapsible sidebar menu for Odex backend navigation',
|
||||
'description': """
|
||||
Replace the default Odoo app menu bar with a collapsible sidebar menu.
|
||||
Odex Sidebar Backend Theme 2
|
||||
=============================
|
||||
|
||||
This module provides a modern, collapsible sidebar menu system that replaces
|
||||
the default Odex app menu bar with an enhanced navigation experience.
|
||||
|
||||
Key Features:
|
||||
- Collapsible/expandable sidebar menu for better space management
|
||||
- Smooth navigation across all Odex applications and menus
|
||||
- Responsive design that adapts to different screen sizes
|
||||
- Persistent sidebar state (collapse/expand) across sessions
|
||||
- Enable/disable sidebar via Settings panel
|
||||
- Minimal performance impact with optimized menu rendering
|
||||
|
||||
Configuration:
|
||||
Navigate to Settings > Sidebar Menu to enable or disable the sidebar menu feature.
|
||||
The setting is automatically saved and persists across all user sessions.
|
||||
""",
|
||||
'author': 'Your Company',
|
||||
'website': 'https://www.yourcompany.com',
|
||||
'depends': ['web'],
|
||||
'data': [],
|
||||
'author': 'Epxert Ltd.',
|
||||
'website': 'https://www.exp-sa.com',
|
||||
'license': 'LGPL-3',
|
||||
'depends': [
|
||||
'web',
|
||||
'base',
|
||||
],
|
||||
'data': [
|
||||
'views/res_config_settings.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'odex_sidebar_backend_theme2/static/src/scss/sidebar_menu.scss',
|
||||
|
||||
'odex_sidebar_backend_theme2/static/src/xml/sidebar_menu_template.xml',
|
||||
'odex_sidebar_backend_theme2/static/src/xml/menu_item_template.xml',
|
||||
|
||||
'odex_sidebar_backend_theme2/static/src/js/sidebar_menu.js',
|
||||
'odex_sidebar_backend_theme2/static/src/js/sidebar_css_loader.js',
|
||||
'odex_sidebar_backend_theme2/static/src/js/menu_item.js',
|
||||
|
||||
'odex_sidebar_backend_theme2/static/src/xml/navbar_patch.xml',
|
||||
'odex_sidebar_backend_theme2/static/src/js/navbar_patch.js',
|
||||
],
|
||||
|
|
@ -28,5 +48,4 @@
|
|||
'installable': True,
|
||||
'application': False,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import res_config_settings
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import fields,api, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
sidebar_menu_enable = fields.Boolean(
|
||||
config_parameter='odex_sidebar_backend_theme2.sidebar_menu_enable',
|
||||
string='Enable Sidebar Menu',
|
||||
help='Enable or disable the sidebar menu in the backend'
|
||||
)
|
||||
|
||||
disable_nav_menu_section = fields.Boolean(
|
||||
config_parameter='odex_sidebar_backend_theme2.disable_nav_menu_section',
|
||||
string='Disable Navigation Menu Section',
|
||||
help='Enable or disable the top navigation bar menu section in the backend interface'
|
||||
)
|
||||
|
||||
sidebar_menu_icon = fields.Binary(
|
||||
string="Sidebar Icon",
|
||||
help="Upload an icon for the sidebar menu.",
|
||||
)
|
||||
|
||||
# set default value for the setting
|
||||
def get_values(self):
|
||||
res = super(ResConfigSettings, self).get_values()
|
||||
IrConfigParam = self.env['ir.config_parameter'].sudo()
|
||||
sidebar_menu_enable = IrConfigParam.get_param('odex_sidebar_backend_theme2.sidebar_menu_enable')
|
||||
disable_nav_menu_section = IrConfigParam.get_param('odex_sidebar_backend_theme2.disable_nav_menu_section')
|
||||
res.update(
|
||||
sidebar_menu_enable=sidebar_menu_enable == 'True',
|
||||
disable_nav_menu_section=disable_nav_menu_section == 'True',
|
||||
sidebar_menu_icon=IrConfigParam.get_param('odex_sidebar_backend_theme2.sidebar_menu_icon')
|
||||
)
|
||||
return res
|
||||
|
||||
def _generate_sidebar_css(self):
|
||||
"""Generate CSS rules for sidebar menu state"""
|
||||
if self.disable_nav_menu_section:
|
||||
return """
|
||||
/* Sidebar Menu Disabled - Hide Top Menu Sections */
|
||||
.o_main_navbar .o_menu_sections {
|
||||
{
|
||||
display: none !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
"""
|
||||
return ""
|
||||
|
||||
# save the setting value
|
||||
def set_values(self):
|
||||
super(ResConfigSettings, self).set_values()
|
||||
IrConfigParam = self.env['ir.config_parameter'].sudo()
|
||||
IrConfigParam.set_param(
|
||||
'odex_sidebar_backend_theme2.sidebar_menu_enable',
|
||||
str(self.sidebar_menu_enable)
|
||||
)
|
||||
IrConfigParam.set_param(
|
||||
'odex_sidebar_backend_theme2.disable_nav_menu_section',
|
||||
str(self.disable_nav_menu_section)
|
||||
)
|
||||
IrConfigParam.set_param(
|
||||
'odex_sidebar_backend_theme2.sidebar_menu_icon',
|
||||
self.sidebar_menu_icon or ''
|
||||
)
|
||||
|
||||
if self.sidebar_menu_icon:
|
||||
# Store the image URL in config parameter
|
||||
image_url = f"/web/image/res.config.settings/{self.id}/sidebar_menu_icon"
|
||||
self.env['ir.config_parameter'].sudo().set_param('odex_sidebar_backend_theme2.sidebar_menu_icon_url', image_url)
|
||||
else:
|
||||
self.env['ir.config_parameter'].sudo().set_param('odex_sidebar_backend_theme2.sidebar_menu_icon_url', '')
|
||||
|
||||
# Generate and store CSS for sidebar state
|
||||
css_code = self._generate_sidebar_css()
|
||||
IrConfigParam.set_param(
|
||||
'odex_sidebar_backend_theme2.sidebar_css',
|
||||
css_code
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def get_sidebar_setting(self):
|
||||
IrConfigParam = self.env['ir.config_parameter'].sudo()
|
||||
sidebar_enabled = IrConfigParam.get_param('odex_sidebar_backend_theme2.sidebar_menu_enable') == 'True'
|
||||
sidebar_icon_url = IrConfigParam.get_param('odex_sidebar_backend_theme2.sidebar_menu_icon_url')
|
||||
return {'sidebar_enabled': sidebar_enabled, 'sidebar_icon_url': sidebar_icon_url}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
/**
|
||||
* Load and inject sidebar CSS rules based on configuration
|
||||
*/
|
||||
export function loadSidebarCSS() {
|
||||
// Get the RPC service
|
||||
const rpc = useService("rpc");
|
||||
|
||||
const loadCSS = async () => {
|
||||
try {
|
||||
// Fetch the stored CSS from config parameter
|
||||
const css = await rpc(
|
||||
'/web/dataset/call_kw/ir.config_parameter/get_param',
|
||||
{
|
||||
model: 'ir.config_parameter',
|
||||
method: 'get_param',
|
||||
args: ['odex_sidebar_backend_theme2.sidebar_css'],
|
||||
kwargs: {},
|
||||
}
|
||||
);
|
||||
|
||||
if (css && css.trim()) {
|
||||
// Create a style element and inject the CSS
|
||||
const style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
style.id = 'sidebar-dynamic-css';
|
||||
style.innerHTML = css;
|
||||
document.head.appendChild(style);
|
||||
console.log('Sidebar CSS injected successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading sidebar CSS:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Load CSS when DOM is ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', loadCSS);
|
||||
} else {
|
||||
loadCSS();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on module load
|
||||
registry.category("web_tour.tours").add("sidebar_css_loader", {
|
||||
steps: [],
|
||||
});
|
||||
|
||||
// Auto-load CSS on page load
|
||||
// loadSidebarCSS();
|
||||
|
|
@ -4,6 +4,7 @@ import { Component, onMounted, useEffect, useState } from "@odoo/owl";
|
|||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { MenuItem } from "./menu_item";
|
||||
import { rpc } from "@web/core/network/rpc"
|
||||
|
||||
export class SidebarMenu extends Component {
|
||||
static template = "odex_sidebar_backend_theme2.SidebarMenu"
|
||||
|
|
@ -14,13 +15,18 @@ export class SidebarMenu extends Component {
|
|||
this.menuService = useService("menu");
|
||||
this.busService = useService("bus_service");
|
||||
this.actionService = useService("action");
|
||||
this.rpc = rpc;
|
||||
|
||||
this.state = useState({
|
||||
menus: [],
|
||||
isOpen: true,
|
||||
isCollapsed: false
|
||||
isCollapsed: false,
|
||||
sidebarEnabled: false,
|
||||
sidebarMenuIconUrl: null,
|
||||
});
|
||||
|
||||
this.loadSidebarSetting()
|
||||
|
||||
// =================== JavaScript Control Starts Here ===================
|
||||
|
||||
const applyLayoutChanges = (isOpen) => {
|
||||
|
|
@ -92,6 +98,33 @@ export class SidebarMenu extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
async loadSidebarSetting() {
|
||||
try {
|
||||
const result = await this.rpc('/web/dataset/call_kw', {
|
||||
model: 'res.config.settings',
|
||||
method: 'get_sidebar_setting',
|
||||
args: [],
|
||||
kwargs: {},
|
||||
});
|
||||
|
||||
// Convert string result to boolean
|
||||
this.state.sidebarEnabled = result.sidebar_enabled !== 'False' && result.sidebar_enabled !== false && result.sidebar_enabled !== '';
|
||||
|
||||
// If sidebar is disabled, close it
|
||||
if (!this.state.sidebarEnabled) {
|
||||
this.state.isOpen = false;
|
||||
}
|
||||
|
||||
// Load sidebar menu icon URL
|
||||
this.state.sidebarMenuIconUrl = result.sidebar_icon_url || '/odex_sidebar_backend_theme2/static/src/img/logo1.png';
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading sidebar setting:', error);
|
||||
// Default to enabled if setting cannot be loaded
|
||||
this.state.sidebarEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
loadMenus() {
|
||||
const allMenus = this.menuService.getAll();
|
||||
const clonedMenus = structuredClone(allMenus);
|
||||
|
|
|
|||
|
|
@ -461,11 +461,6 @@
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide submenus inside the top bar */
|
||||
.o_main_navbar .o_menu_sections {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.o_web_client {
|
||||
margin-left: 0 !important;
|
||||
transition: all 0.3s ease-in-out;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="odex_sidebar_backend_theme2.SidebarMenu" owl="1">
|
||||
<div class="custom_sidebar" t-att-class="{ 'is-open': state.isOpen, 'is-collapsed': state.isCollapsed }">
|
||||
<div class="custom_sidebar" t-att-class="{ 'is-open': state.isOpen, 'is-collapsed': state.isCollapsed, 'is-disabled': !state.sidebarEnabled }" t-if="state.sidebarEnabled">
|
||||
<!-- Sidebar Header -->
|
||||
<header class="sidebar-header">
|
||||
<a href="/" class="header-logo" t-att-title="state.isCollapsed ? 'Home' : ''">
|
||||
<img src="/odex_sidebar_backend_theme2/static/src/img/logo1.png" alt="CodingNepal" />
|
||||
<img t-att-src="state.sidebarMenuIconUrl" alt="CodingNepal" />
|
||||
</a>
|
||||
<button class="sidebar-toggler" t-on-click="() => this.toggleCollapse()">
|
||||
<span class="material-symbols-rounded">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form_inherit_sidebar" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.form.inherit.sidebar</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base.res_config_settings_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="inside">
|
||||
<app data-string="Odex Sidebar Menu" string="Odex Sidebar Menu"
|
||||
name="odex_sidebar_backend_theme2">
|
||||
<block title="Odex Sidebar Menu" name="odex_sidebar_settings_block">
|
||||
<setting>
|
||||
<div class="content-group">
|
||||
<div class="row mt16">
|
||||
<label for="sidebar_menu_enable" />
|
||||
<div class="text-muted">
|
||||
Enable or disable the sidebar menu in the backend
|
||||
interface
|
||||
</div>
|
||||
<field name="sidebar_menu_enable" />
|
||||
</div>
|
||||
<div class="row mt16">
|
||||
<label for="disable_nav_menu_section" />
|
||||
<div class="text-muted">
|
||||
Enable or disable the top navigation bar menu section
|
||||
in the backend interface
|
||||
</div>
|
||||
<field name="disable_nav_menu_section" />
|
||||
</div>
|
||||
|
||||
<div class="row mt16">
|
||||
<label for="sidebar_menu_icon" />
|
||||
<field name="sidebar_menu_icon" widget="image"
|
||||
options="{'size': [128, 128]}"/>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue