diff --git a/odex30_base/expert_theme/__manifest__.py b/odex30_base/expert_theme/__manifest__.py
index dca6dbc..c64bbad 100644
--- a/odex30_base/expert_theme/__manifest__.py
+++ b/odex30_base/expert_theme/__manifest__.py
@@ -33,6 +33,7 @@
'expert_theme/static/src/scss/expert_login.scss',
'expert_theme/static/src/scss/login_minimal.scss',
'expert_theme/static/src/js/expert_login_template.js',
+ 'expert_theme/static/src/scss/frontend.scss',
],
'web.assets_backend': [
'expert_theme/static/src/fonts/en_fonts.scss',
diff --git a/odex30_base/expert_theme/controllers/main.py b/odex30_base/expert_theme/controllers/main.py
index fc6cbac..d8ac941 100644
--- a/odex30_base/expert_theme/controllers/main.py
+++ b/odex30_base/expert_theme/controllers/main.py
@@ -10,8 +10,7 @@ class IntroLoaderController(http.Controller):
img_b64 = request.env['ir.config_parameter'].sudo().get_param('intro_loader.image_data')
if not img_b64:
- # Return a 1x1 transparent pixel or default Odoo logo if none set
- return request.redirect('/web/static/img/logo2.png')
+ return request.redirect('/expert_theme/static/src/img/logo.webp')
image_data = base64.b64decode(img_b64)
headers = [('Content-Type', 'image/png')]
diff --git a/odex30_base/expert_theme/models/res_config_settings.py b/odex30_base/expert_theme/models/res_config_settings.py
index d6023cc..e9dd3e0 100644
--- a/odex30_base/expert_theme/models/res_config_settings.py
+++ b/odex30_base/expert_theme/models/res_config_settings.py
@@ -8,6 +8,17 @@ class ResConfigSettings(models.TransientModel):
# Text Configuration
intro_loader_text = fields.Char(string="Loader Text", config_parameter='intro_loader.text', default="Loading...")
intro_loader_show_text = fields.Boolean(string="Show Text", config_parameter='intro_loader.show_text')
+ # Text Styling
+ intro_loader_text_color = fields.Char(
+ string="Text Color",
+ config_parameter='intro_loader.text_color',
+ default="#6c757d" # Standard Bootstrap muted gray
+ )
+ intro_loader_text_size = fields.Integer(
+ string="Text Size (px)",
+ config_parameter='intro_loader.text_size',
+ default=24
+ )
# Spinner Configuration
intro_loader_show_spinner = fields.Boolean(string="Show Spinner", config_parameter='intro_loader.show_spinner')
@@ -21,6 +32,20 @@ class ResConfigSettings(models.TransientModel):
('none', 'Static')
], string="Image Animation", config_parameter='intro_loader.animation', default='pulse')
+ # Exit Animation Configuration
+ intro_loader_exit_type = fields.Selection([
+ ('fade', 'Fade Out'),
+ ('slide_up', 'Slide Up (Curtain)'),
+ ('zoom_out', 'Zoom Out'),
+ ('circle_mask', 'Circle Mask')
+ ], string="Exit Animation", config_parameter='intro_loader.exit_type', default='fade')
+
+ intro_loader_exit_duration = fields.Float(
+ string="Exit Duration (Seconds)",
+ config_parameter='intro_loader.exit_duration',
+ default=0.8
+ )
+
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
diff --git a/odex30_base/expert_theme/static/src/img/logo.webp b/odex30_base/expert_theme/static/src/img/logo.webp
new file mode 100644
index 0000000..f737c38
Binary files /dev/null and b/odex30_base/expert_theme/static/src/img/logo.webp differ
diff --git a/odex30_base/expert_theme/static/src/js/intro_loader.js b/odex30_base/expert_theme/static/src/js/intro_loader.js
index 9996b41..93adc27 100644
--- a/odex30_base/expert_theme/static/src/js/intro_loader.js
+++ b/odex30_base/expert_theme/static/src/js/intro_loader.js
@@ -9,26 +9,23 @@ patch(WebClient.prototype, {
super.setup();
onMounted(() => {
- // Select the loader element
const loader = document.getElementById("o_intro_loader");
if (loader) {
- // Optional: Check sessionStorage if you want it ONCE per browser session
- // const hasLoaded = sessionStorage.getItem('odoo_intro_shown');
-
- // Add the hidden class to trigger CSS transition
- // We add a small delay (e.g., 500ms) to ensure the UI is visually stable behind it
+ // Read duration from HTML attribute (default to 800ms if missing)
+ const duration = parseInt(loader.dataset.durationMs) || 800;
+
+ // Add delay for visual stability (optional 500ms)
setTimeout(() => {
- loader.classList.add("o_hidden");
+ // Trigger CSS animation
+ loader.classList.add("o_hiddens");
- // Cleanup DOM after animation finishes (optional but cleaner)
+ // Remove from DOM exactly when animation finishes
setTimeout(() => {
loader.remove();
- }, 1000);
+ }, duration + 100); // +100ms buffer
}, 500);
-
- // sessionStorage.setItem('odoo_intro_shown', 'true');
}
});
}
diff --git a/odex30_base/expert_theme/static/src/scss/expert_theme.scss b/odex30_base/expert_theme/static/src/scss/expert_theme.scss
index 026ff27..e86df56 100644
--- a/odex30_base/expert_theme/static/src/scss/expert_theme.scss
+++ b/odex30_base/expert_theme/static/src/scss/expert_theme.scss
@@ -376,4 +376,4 @@ body {
.expert-home-container {
padding: 15px;
}
-}
\ No newline at end of file
+}
diff --git a/odex30_base/expert_theme/static/src/scss/frontend.scss b/odex30_base/expert_theme/static/src/scss/frontend.scss
new file mode 100644
index 0000000..5c35e8a
--- /dev/null
+++ b/odex30_base/expert_theme/static/src/scss/frontend.scss
@@ -0,0 +1,3 @@
+.o_loader_content{
+ display: none !important;
+}
\ No newline at end of file
diff --git a/odex30_base/expert_theme/static/src/scss/intro_loader.scss b/odex30_base/expert_theme/static/src/scss/intro_loader.scss
index f416be7..59e63ff 100644
--- a/odex30_base/expert_theme/static/src/scss/intro_loader.scss
+++ b/odex30_base/expert_theme/static/src/scss/intro_loader.scss
@@ -6,7 +6,10 @@
display: flex;
align-items: center;
justify-content: center;
- transition: opacity 0.8s ease-out, visibility 0.8s;
+
+ /* Default Transition Base */
+ transition-timing-function: ease-in-out;
+ transition-duration: var(--exit-duration, 0.8s); /* Use dynamic var */
.o_loader_content {
display: flex;
@@ -33,10 +36,45 @@
animation: loader-spin 1s linear infinite;
}
- &.o_hidden {
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
+ // &.o_hiddens {
+ // opacity: 0;
+ // visibility: hidden;
+ // pointer-events: none;
+ // }
+
+ /* 1. Fade Out */
+ &.exit-fade {
+ transition-property: opacity, visibility;
+ &.o_hiddens {
+ opacity: 0;
+ // visibility: hidden;
+ }
+ }
+
+ /* 2. Slide Up (Curtain) */
+ &.exit-slide_up {
+ transition-property: transform;
+ &.o_hiddens {
+ transform: translateY(-100%);
+ }
+ }
+
+ /* 3. Zoom Out */
+ &.exit-zoom_out {
+ transition-property: opacity, transform;
+ &.o_hiddens {
+ opacity: 0;
+ transform: scale(1.5); /* Expands out while fading */
+ }
+ }
+
+ /* 4. Circle Mask (Advanced CSS Clip Path) */
+ &.exit-circle_mask {
+ transition-property: clip-path;
+ clip-path: circle(150% at 50% 50%);
+ &.o_hiddens {
+ clip-path: circle(0% at 50% 50%);
+ }
}
}
diff --git a/odex30_base/expert_theme/views/res_config_settings_views.xml b/odex30_base/expert_theme/views/res_config_settings_views.xml
index b7c294d..0bff925 100644
--- a/odex30_base/expert_theme/views/res_config_settings_views.xml
+++ b/odex30_base/expert_theme/views/res_config_settings_views.xml
@@ -6,24 +6,38 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/odex30_base/expert_theme/views/web_layout.xml b/odex30_base/expert_theme/views/web_layout.xml
index 3f26ec8..f2184a8 100644
--- a/odex30_base/expert_theme/views/web_layout.xml
+++ b/odex30_base/expert_theme/views/web_layout.xml
@@ -2,25 +2,43 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-

-
+
-
-
+