feat: Enhance intro loader with customizable text and exit animations
This commit is contained in:
parent
c747afc842
commit
3a4691d3be
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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')]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
|
|
@ -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');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,4 +376,4 @@ body {
|
|||
.expert-home-container {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
.o_loader_content{
|
||||
display: none !important;
|
||||
}
|
||||
|
|
@ -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%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,24 +6,38 @@
|
|||
<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 Intro Loader" string="Odex Intro Loader"
|
||||
<app data-string="Odex Theme" string="Odex Theme"
|
||||
name="expert_theme">
|
||||
<block title="Intro Loader" id="intro_loader_settings">
|
||||
<setting id="loader_global_enable"
|
||||
help="Show a full screen loader on page load.">
|
||||
<field name="intro_loader_active" />
|
||||
</setting>
|
||||
|
||||
<setting invisible="not intro_loader_active">
|
||||
<setting string="Exit Animation" invisible="not intro_loader_active"
|
||||
help="Customize how the loader disappears when Odoo is ready.">
|
||||
<group>
|
||||
<field name="intro_loader_exit_type" />
|
||||
<field name="intro_loader_exit_duration" />
|
||||
</group>
|
||||
</setting>
|
||||
<setting string="Visuals" invisible="not intro_loader_active"
|
||||
help="Customize the appearance of the intro loader.">
|
||||
<group>
|
||||
<field name="intro_loader_image" widget="image" class="oe_avatar" />
|
||||
<field name="intro_loader_animation" />
|
||||
</group>
|
||||
</setting>
|
||||
<setting string="Content" invisible="not intro_loader_active"
|
||||
help="Customize the content of the intro loader.">
|
||||
<group>
|
||||
<field name="intro_loader_show_spinner" />
|
||||
<field name="intro_loader_show_text" />
|
||||
<field name="intro_loader_text"
|
||||
invisible="not intro_loader_show_text" />
|
||||
<field name="intro_loader_text_color" widget="color"
|
||||
invisible="not intro_loader_show_text" />
|
||||
<field name="intro_loader_text_size"
|
||||
invisible="not intro_loader_show_text" />
|
||||
</group>
|
||||
</setting>
|
||||
</block>
|
||||
|
|
|
|||
|
|
@ -2,25 +2,43 @@
|
|||
<odoo>
|
||||
<template id="layout_intro_loader" inherit_id="web.layout">
|
||||
<xpath expr="//body" position="before">
|
||||
<t t-set="loader_active" t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.active')"/>
|
||||
|
||||
<t t-if="loader_active">
|
||||
<t t-set="anim_type" t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.animation') or 'pulse'"/>
|
||||
<t t-set="show_text" t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.show_text')"/>
|
||||
<t t-set="loader_text" t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.text')"/>
|
||||
<t t-set="show_spinner" t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.show_spinner')"/>
|
||||
<t t-set="loader_active"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.active')" />
|
||||
|
||||
<t t-if="loader_active">
|
||||
<t t-set="text_color"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.text_color') or '#6c757d'" />
|
||||
<t t-set="text_size"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.text_size') or '24'" />
|
||||
|
||||
<t t-set="anim_type"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.animation') or 'pulse'" />
|
||||
<t t-set="show_text"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.show_text')" />
|
||||
<t t-set="loader_text"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.text')" />
|
||||
<t t-set="show_spinner"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.show_spinner')" />
|
||||
|
||||
<t t-set="exit_type"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.exit_type') or 'fade'" />
|
||||
<t t-set="exit_duration"
|
||||
t-value="request.env['ir.config_parameter'].sudo().get_param('intro_loader.exit_duration') or 0.8" />
|
||||
|
||||
<div id="o_intro_loader"
|
||||
t-attf-class="o_intro_loader exit-#{exit_type}"
|
||||
t-attf-style="--exit-duration: #{exit_duration}s;"
|
||||
t-att-data-duration-ms="float(exit_duration) * 1000">
|
||||
|
||||
<div id="o_intro_loader" class="o_intro_loader">
|
||||
<div class="o_loader_content">
|
||||
<img src="/intro_loader/image"
|
||||
t-attf-class="o_loader_logo mb-4 anim-#{anim_type}"/>
|
||||
|
||||
<img src="/intro_loader/image"
|
||||
t-attf-class="o_loader_logo mb-4 anim-#{anim_type}" />
|
||||
<t t-if="show_spinner">
|
||||
<div class="o_loader_spinner"></div>
|
||||
</t>
|
||||
|
||||
<t t-if="show_text">
|
||||
<h3 class="text-muted mt-3" t-esc="loader_text"/>
|
||||
<h3 class="text-muted mt-3" t-esc="loader_text"
|
||||
t-attf-style="color: #{text_color}; font-size: #{text_size}px; font-weight: 500;" />
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue