ओडू थीम डेवलपमेंट गाइड: ओडू 17/18 के लिए कस्टम थीम बनाएं
Odoo थीम इकोसिस्टम, Odoo ऐप स्टोर पर सालाना 12 मिलियन डॉलर से अधिक की कमाई करता है, फिर भी 8% से कम थीम को 5-स्टार रेटिंग प्राप्त होती है। भूलने योग्य थीम और बेस्ट-सेलर के बीच का अंतर ओडू की रेंडरिंग पाइपलाइन, क्यूवेब टेम्पलेट इनहेरिटेंस और वेबसाइट बिल्डर के ड्रैग-एंड-ड्रॉप आर्किटेक्चर को समझने के लिए आता है।
यह मार्गदर्शिका ओडू थीम विकास की हर परत को कवर करती है - प्रोजेक्ट मचान से लेकर उन्नत एससीएसएस आर्किटेक्चर तक, कस्टम स्निपेट बनाने से लेकर आपकी थीम को ओडू के वेबसाइट बिल्डर के साथ निर्बाध रूप से काम करने तक।
मुख्य बातें
- ओडू थीम मानक मॉड्यूल हैं एक विशिष्ट निर्देशिका संरचना के साथ - वे
websiteमॉड्यूल का विस्तार करते हैं और एसेट बंडलिंग सिस्टम के माध्यम से टेम्पलेट, एससीएसएस और जावास्क्रिप्ट पंजीकृत करते हैं। - QWeb Odoo का सर्वर-साइड टेम्प्लेट इंजन है - यह XML निर्देशों (t-if, t-foreach, t-call, t-inherit) का उपयोग करता है जो HTML में संकलित होता है। वेबसाइट के किसी भी हिस्से को अनुकूलित करने के लिए XPath के साथ टेम्पलेट इनहेरिटेंस को समझना आवश्यक है।
- एससीएसएस पाइपलाइन ओडू के एसेट मैनेजर के माध्यम से संकलित होती है - कस्टम वैरिएबल बूटस्ट्रैप 5 डिफ़ॉल्ट को ओवरराइड करते हैं, और
_variables.scssको फ्रेमवर्क से पहले लोड किया जाना चाहिए। - वेबसाइट बिल्डर एकीकरण के लिए स्निपेट विकल्प, कस्टम बिल्डिंग ब्लॉक और गतिशील सामग्री ब्लॉक को परिभाषित करने की आवश्यकता होती है, जिसे गैर-तकनीकी उपयोगकर्ता ड्रैग-एंड-ड्रॉप संपादक के माध्यम से कॉन्फ़िगर कर सकते हैं।
- Odoo में रिस्पॉन्सिव डिज़ाइन Odoo-विशिष्ट उपयोगिताओं के साथ बूटस्ट्रैप 5 के ग्रिड सिस्टम का लाभ उठाता है - सभी ब्रेकप्वाइंट पर परीक्षण करें और अंतर्राष्ट्रीय तैनाती के लिए RTL भाषाओं पर विचार करें।
1. थीम मॉड्यूल संरचना
एक ओडू थीम वेबसाइट-विशिष्ट परिवर्धन के साथ मानक मॉड्यूल संरचना का अनुसरण करती है:
theme_ecosire/
├── __init__.py
├── __manifest__.py
├── data/
│ ├── theme_data.xml # Default pages, menus
│ └── images.xml # Pre-loaded image library
├── static/
│ ├── description/
│ │ ├── icon.png # Module icon (128x128)
│ │ └── icon.svg # SVG version
│ ├── src/
│ │ ├── img/ # Theme images
│ │ ├── fonts/ # Custom fonts
│ │ ├── scss/
│ │ │ ├── _variables.scss # Bootstrap variable overrides
│ │ │ ├── _mixins.scss # Custom SCSS mixins
│ │ │ ├── _typography.scss # Font stacks, sizes
│ │ │ ├── _header.scss # Header styles
│ │ │ ├── _footer.scss # Footer styles
│ │ │ ├── _snippets.scss # Snippet-specific styles
│ │ │ └── primary.scss # Main entry point
│ │ ├── js/
│ │ │ ├── snippets/ # Snippet JS (animations, interactions)
│ │ │ └── theme.js # Theme-wide JS
│ │ └── xml/
│ │ └── snippets.xml # OWL snippet templates
│ └── img/ # Public images (backgrounds, icons)
├── views/
│ ├── assets.xml # Asset bundle registration
│ ├── layout.xml # Header/footer templates
│ ├── pages.xml # Pre-built page templates
│ └── snippets/
│ ├── options.xml # Snippet options (color pickers, etc.)
│ └── s_custom_block.xml # Custom snippet definitions
└── tests/
└── test_theme.py # Theme installation tests
थीम प्रकट
# __manifest__.py
{
'name': 'Theme Ecosire',
'description': 'Modern, performance-optimized theme for Odoo Website',
'category': 'Theme',
'version': '18.0.1.0.0',
'author': 'ECOSIRE Private Limited',
'website': 'https://ecosire.com',
'license': 'LGPL-3',
'depends': ['website'],
'data': [
'views/assets.xml',
'views/layout.xml',
'views/pages.xml',
'views/snippets/options.xml',
'views/snippets/s_custom_block.xml',
],
'assets': {
'web.assets_frontend': [
# Variables MUST come before Bootstrap
('prepend', 'theme_ecosire/static/src/scss/_variables.scss'),
'theme_ecosire/static/src/scss/primary.scss',
'theme_ecosire/static/src/js/theme.js',
],
'website.assets_wysiwyg': [
'theme_ecosire/static/src/js/snippets/*.js',
],
},
'images': [
'static/description/banner.png',
'static/description/theme_screenshot.jpg',
],
'snippet_lists': {
'website.snippets': [
('replace', 'theme_ecosire.s_custom_hero'),
],
},
'installable': True,
'application': False,
'auto_install': False,
}
assets कुंजी के बारे में महत्वपूर्ण नोट: Odoo 17+ में, __manifest__.py में assets शब्दकोश स्थिर फ़ाइलों को पंजीकृत करने का पसंदीदा तरीका है। <template inherit_id="web.assets_frontend"> का उपयोग करने वाला पुराना views/assets.xml दृष्टिकोण अभी भी काम करता है लेकिन इसे चरणबद्ध तरीके से समाप्त किया जा रहा है। अधिकतम अनुकूलता के लिए दोनों का उपयोग करें.
2. क्यूवेब टेम्प्लेटिंग डीप डाइव
QWeb Odoo का XML-आधारित टेम्पलेट इंजन है। यह t- से पहले लगे निर्देशों को संसाधित करता है और HTML आउटपुट करता है। थीम विकास के लिए QWeb को समझना गैर-परक्राम्य है।
मुख्य निर्देश
<!-- Conditional rendering -->
<div t-if="website.is_publisher()">
<span>Edit mode controls here</span>
</div>
<div t-elif="request.env.user._is_internal()">
<span>Internal user view</span>
</div>
<div t-else="">
<span>Public visitor view</span>
</div>
<!-- Loops -->
<ul>
<t t-foreach="website.menu_id.child_id" t-as="menu_item">
<li t-attf-class="nav-item #{('active' if menu_item.is_active else '')}">
<a t-att-href="menu_item.url" t-out="menu_item.name"/>
</li>
</t>
</ul>
<!-- Variable setting -->
<t t-set="company" t-value="res_company"/>
<t t-set="primary_color" t-value="'#FF6B00'"/>
<!-- Output (auto-escaped) -->
<span t-out="partner.name"/>
<!-- Raw HTML output (use with caution) -->
<div t-raw="sanitized_html_content"/>
<!-- Dynamic attributes -->
<div t-att-id="'section-' + str(section.id)"
t-attf-class="container #{extra_class}"
t-att-data-section="section.sequence"/>
<!-- Template calling -->
<t t-call="theme_ecosire.hero_section">
<t t-set="title">Welcome to Our Store</t>
<t t-set="subtitle">Premium Odoo Themes</t>
</t>
XPath के साथ टेम्पलेट इनहेरिटेंस
यहीं से थीम विकास को बल मिलता है। आप किसी भी मौजूदा टेम्पलेट को बदले बिना उसे संशोधित कर सकते हैं:
<!-- views/layout.xml -->
<template id="custom_header" inherit_id="website.layout" name="Custom Header">
<!-- Replace the entire header -->
<xpath expr="//header" position="replace">
<header id="top" class="ecosire-header">
<nav class="navbar navbar-expand-lg">
<div class="container">
<a class="navbar-brand" t-att-href="'/'">
<img t-if="website.logo"
t-att-src="website.image_url(website, 'logo')"
alt="Logo" class="img-fluid" style="max-height: 50px;"/>
</a>
<!-- Custom mega menu -->
<t t-call="theme_ecosire.mega_menu"/>
<!-- CTA button -->
<a href="/contactus" class="btn btn-primary ms-3">
Get Started
</a>
</div>
</nav>
</header>
</xpath>
<!-- Add a top bar before the header -->
<xpath expr="//header[@id='top']" position="before">
<div class="ecosire-topbar bg-dark text-white py-1">
<div class="container d-flex justify-content-between">
<span t-out="res_company.phone"/>
<span t-out="res_company.email"/>
</div>
</div>
</xpath>
<!-- Modify footer: add a newsletter section -->
<xpath expr="//footer" position="inside">
<div class="ecosire-newsletter bg-primary text-white py-5">
<div class="container text-center">
<h3>Stay Updated</h3>
<t t-call="website.s_newsletter_block"/>
</div>
</div>
</xpath>
</template>
XPath स्थिति संदर्भ
| स्थिति | प्रभाव |
|---|---|
replace | मिलान किए गए तत्व को पूरी तरह से बदलें |
inside | मिलान किए गए तत्व के अंदर जोड़ें |
before | मिलान किए गए तत्व से पहले डालें |
after | मिलान किए गए तत्व के बाद डालें |
attributes | मिलान किए गए तत्व की विशेषताओं को संशोधित करें |
<!-- Modify attributes example -->
<xpath expr="//div[@id='wrapwrap']" position="attributes">
<attribute name="class" add="ecosire-theme" separator=" "/>
</xpath>
<!-- Remove an element -->
<xpath expr="//div[hasclass('o_not_editable')]" position="replace"/>
3. एससीएसएस वास्तुकला
Odoo की SCSS पाइपलाइन अपने एसेट मैनेजर के माध्यम से संकलित होती है, जिसका अर्थ है कि आपके वेरिएबल ओवरराइड को बूटस्ट्रैप के डिफॉल्ट से पहले लोड किया जाना चाहिए। यह सुनिश्चित करने के लिए कि आपकी _variables.scss फ़ाइल प्राथमिकता लेती है, अपने मेनिफेस्ट के एसेट डिक्शनरी में 'प्रीपेन्ड' निर्देश का उपयोग करें। यह एकल फ़ाइल आपके थीम में रंग, फ़ॉन्ट, रिक्ति, सीमा त्रिज्या और हर दूसरे बूटस्ट्रैप डिज़ाइन टोकन को नियंत्रित करती है।
वेरिएबल ओवरराइड्स (_variables.scss)
// _variables.scss — loaded BEFORE Bootstrap
// Override Bootstrap 5 defaults
// Brand Colors
$o-brand-primary: #FF6B00;
$o-brand-secondary: #1A1F36;
// Bootstrap color overrides
$primary: $o-brand-primary;
$secondary: $o-brand-secondary;
$success: #00C853;
$info: #2196F3;
$warning: #FFB300;
$danger: #FF1744;
// Typography
$font-family-sans-serif: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
$font-family-monospace: 'JetBrains Mono', 'Fira Code', monospace;
$font-size-base: 1rem;
$headings-font-weight: 700;
$headings-line-height: 1.2;
// Spacing
$spacer: 1rem;
// Border radius
$border-radius: 0.5rem;
$border-radius-lg: 1rem;
$border-radius-pill: 50rem;
// Shadows
$box-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.05);
$box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
$box-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12);
// Navbar
$navbar-padding-y: 1rem;
$navbar-brand-font-size: 1.5rem;
// Cards
$card-border-radius: $border-radius-lg;
$card-border-color: transparent;
$card-box-shadow: $box-shadow;
मुख्य स्टाइलशीट (प्राथमिक.एससीएसएस)
// primary.scss — Main entry point
@import 'variables'; // Already prepended, but import for IDE support
@import 'mixins';
@import 'typography';
@import 'header';
@import 'footer';
@import 'snippets';
// ============================================
// Global Overrides
// ============================================
#wrapwrap.ecosire-theme {
// Smooth scrolling
scroll-behavior: smooth;
// Better text rendering
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// ============================================
// Section Spacing
// ============================================
.s_section {
padding: 5rem 0;
@media (max-width: 768px) {
padding: 3rem 0;
}
}
// ============================================
// Button Styles
// ============================================
.btn-primary {
background: linear-gradient(135deg, $primary, darken($primary, 10%));
border: none;
padding: 0.75rem 2rem;
font-weight: 600;
letter-spacing: 0.02em;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba($primary, 0.4);
}
}
// ============================================
// Card Component
// ============================================
.ecosire-card {
background: white;
border-radius: $border-radius-lg;
overflow: hidden;
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow: $box-shadow-lg;
}
&__image {
aspect-ratio: 16 / 9;
object-fit: cover;
width: 100%;
}
&__body {
padding: 1.5rem;
}
}
कस्टम फ़ॉन्ट लोड हो रहा है
// _typography.scss
@font-face {
font-family: 'Inter';
src: url('/theme_ecosire/static/src/fonts/Inter-Variable.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
font-style: normal;
}
@font-face {
font-family: 'Inter';
src: url('/theme_ecosire/static/src/fonts/Inter-Variable-Italic.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
font-style: italic;
}
// Heading hierarchy
h1, .h1 { font-size: 2.5rem; font-weight: 800; }
h2, .h2 { font-size: 2rem; font-weight: 700; }
h3, .h3 { font-size: 1.5rem; font-weight: 600; }
h4, .h4 { font-size: 1.25rem; font-weight: 600; }
4. कस्टम स्निपेट्स (बिल्डिंग ब्लॉक्स)
स्निपेट्स ओडू के वेबसाइट बिल्डर में ड्रैग-एंड-ड्रॉप बिल्डिंग ब्लॉक हैं। कस्टम स्निपेट बनाना किसी थीम को वास्तव में मूल्यवान बनाता है।
स्निपेट टेम्पलेट को परिभाषित करना
<!-- views/snippets/s_custom_block.xml -->
<odoo>
<!-- The snippet template -->
<template id="s_ecosire_hero" name="Ecosire Hero Section">
<section class="s_ecosire_hero pt-5 pb-5 o_cc o_cc1">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-6">
<h1 class="display-4 fw-bold">
Transform Your Business
</h1>
<p class="lead text-muted mt-3">
Enterprise solutions that scale with your ambitions.
</p>
<div class="mt-4">
<a href="/contactus" class="btn btn-primary btn-lg me-3">
Get Started
</a>
<a href="/about" class="btn btn-outline-secondary btn-lg">
Learn More
</a>
</div>
</div>
<div class="col-lg-6">
<img src="/theme_ecosire/static/src/img/hero-illustration.svg"
alt="Hero" class="img-fluid" loading="lazy"/>
</div>
</div>
</div>
</section>
</template>
<!-- Register snippet in the builder panel -->
<template id="snippets" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_structure']//t[@t-snippet]/.."
position="inside">
<t t-snippet="theme_ecosire.s_ecosire_hero"
t-thumbnail="/theme_ecosire/static/src/img/snippets/hero_thumb.png"/>
</xpath>
</template>
</odoo>
स्निपेट विकल्प (उपयोगकर्ता अनुकूलन)
<!-- views/snippets/options.xml -->
<odoo>
<template id="s_ecosire_hero_options" inherit_id="website.snippet_options">
<xpath expr="." position="inside">
<div data-js="EcosireHeroOptions"
data-selector=".s_ecosire_hero">
<!-- Layout selector -->
<we-select string="Layout">
<we-button data-select-class="s_hero_left">Text Left</we-button>
<we-button data-select-class="s_hero_center">Centered</we-button>
<we-button data-select-class="s_hero_right">Text Right</we-button>
</we-select>
<!-- Background style -->
<we-select string="Background">
<we-button data-select-class="bg-white">White</we-button>
<we-button data-select-class="bg-dark text-white">Dark</we-button>
<we-button data-select-class="bg-gradient">Gradient</we-button>
</we-select>
<!-- Animation toggle -->
<we-checkbox string="Enable Animation"
data-toggle-class="s_hero_animated"/>
</div>
</xpath>
</template>
</odoo>
स्निपेट जावास्क्रिप्ट (एनिमेशन)
// static/src/js/snippets/s_ecosire_hero.js
/** @odoo-module */
import publicWidget from '@web/legacy/js/public/public_widget';
const EcosireHero = publicWidget.Widget.extend({
selector: '.s_ecosire_hero.s_hero_animated',
disabledInEditableMode: true,
start() {
this._super(...arguments);
this._initAnimation();
return Promise.resolve();
},
_initAnimation() {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.2 }
);
this.el.querySelectorAll('.animate-target').forEach(el => {
observer.observe(el);
});
},
destroy() {
this._super(...arguments);
},
});
publicWidget.registry.EcosireHero = EcosireHero;
export default EcosireHero;
5. रिस्पॉन्सिव डिज़ाइन सर्वोत्तम अभ्यास
मोबाइल-फर्स्ट एससीएसएस
// _responsive.scss
// Mobile-first breakpoints (Bootstrap 5)
// xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px
.ecosire-header {
// Mobile default
padding: 0.5rem 0;
.navbar-brand img {
max-height: 35px;
}
.nav-link {
padding: 0.75rem 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
// Tablet and up
@include media-breakpoint-up(md) {
padding: 0.75rem 0;
.nav-link {
padding: 0.5rem 1rem;
border-bottom: none;
}
}
// Desktop
@include media-breakpoint-up(lg) {
padding: 1rem 0;
.navbar-brand img {
max-height: 50px;
}
}
}
// Touch-friendly elements
@media (hover: none) {
.btn {
min-height: 44px;
min-width: 44px;
}
.nav-link {
min-height: 44px;
display: flex;
align-items: center;
}
}
आरटीएल समर्थन
// _rtl.scss — Critical for Arabic, Hebrew, Urdu markets
html[dir="rtl"] {
.ecosire-header {
.navbar-brand {
margin-left: 1rem;
margin-right: 0;
}
.btn + .btn {
margin-right: 0.75rem;
margin-left: 0;
}
}
.ecosire-card__body {
text-align: right;
}
// Use logical properties where possible
.ms-3 { margin-inline-start: 1rem; }
.me-3 { margin-inline-end: 1rem; }
}
6. प्रदर्शन अनुकूलन
छवि अनुकूलन
<!-- Use responsive images with srcset -->
<img t-att-src="'/web/image/ir.attachment/%s/datas/800x400' % image.id"
t-att-srcset="'/web/image/ir.attachment/%s/datas/400x200 400w, /web/image/ir.attachment/%s/datas/800x400 800w, /web/image/ir.attachment/%s/datas/1200x600 1200w' % (image.id, image.id, image.id)"
sizes="(max-width: 576px) 400px, (max-width: 992px) 800px, 1200px"
loading="lazy"
decoding="async"
alt="Descriptive alt text"/>
क्रिटिकल सीएसएस इनलाइनिंग
<!-- views/layout.xml -->
<template id="critical_css" inherit_id="website.layout">
<xpath expr="//head" position="inside">
<style type="text/css">
/* Inline critical above-the-fold CSS */
.ecosire-header { min-height: 72px; }
.s_ecosire_hero { min-height: 60vh; }
.navbar-brand img { max-height: 50px; }
</style>
</xpath>
</template>
एसेट लोडिंग रणनीति
# __manifest__.py
'assets': {
# Critical CSS — loaded in head
'web.assets_frontend': [
('prepend', 'theme_ecosire/static/src/scss/_variables.scss'),
'theme_ecosire/static/src/scss/primary.scss',
],
# Non-critical JS — deferred
'web.assets_frontend_lazy': [
'theme_ecosire/static/src/js/animations.js',
'theme_ecosire/static/src/js/parallax.js',
],
# Editor-only assets
'website.assets_wysiwyg': [
'theme_ecosire/static/src/js/snippets/*.js',
'theme_ecosire/static/src/scss/_editor.scss',
],
},
7. वेबसाइट बिल्डर एकीकरण
गतिशील सामग्री ब्लॉक
<!-- A snippet that fetches products dynamically -->
<template id="s_featured_products" name="Featured Products Grid">
<section class="s_featured_products pt-5 pb-5">
<div class="container">
<h2 class="text-center mb-5">Featured Products</h2>
<div class="row" t-if="products">
<t t-foreach="products[:8]" t-as="product">
<div class="col-md-3 mb-4">
<div class="ecosire-card h-100">
<img t-att-src="product.image_url"
t-att-alt="product.name"
class="ecosire-card__image" loading="lazy"/>
<div class="ecosire-card__body">
<h5 t-out="product.name"/>
<p class="text-primary fw-bold"
t-out="product.list_price"
t-options='{"widget": "monetary"}'/>
<a t-att-href="product.website_url"
class="btn btn-outline-primary btn-sm">
View Details
</a>
</div>
</div>
</div>
</t>
</div>
</div>
</section>
</template>
पेज टेम्पलेट्स
<!-- Pre-built page templates that users can select -->
<template id="landing_page_template" name="Landing Page">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<t t-call="theme_ecosire.s_ecosire_hero"/>
<t t-call="theme_ecosire.s_features_grid"/>
<t t-call="theme_ecosire.s_testimonials"/>
<t t-call="theme_ecosire.s_cta_banner"/>
</div>
</t>
</template>
8. अपनी थीम का परीक्षण करना
# tests/test_theme.py
from odoo.tests.common import HttpCase, tagged
@tagged('post_install', '-at_install')
class TestThemeEcosire(HttpCase):
def test_01_theme_installation(self):
"""Theme installs without errors."""
module = self.env['ir.module.module'].search([
('name', '=', 'theme_ecosire')
])
self.assertEqual(module.state, 'installed')
def test_02_homepage_loads(self):
"""Homepage renders with theme applied."""
response = self.url_open('/')
self.assertEqual(response.status_code, 200)
self.assertIn('ecosire-theme', response.text)
def test_03_snippets_available(self):
"""Custom snippets appear in the builder."""
self.start_tour('/web#action=website.action_website',
'theme_ecosire_snippet_tour', login='admin')
def test_04_responsive_meta(self):
"""Viewport meta tag is present."""
response = self.url_open('/')
self.assertIn('viewport', response.text)
9. ओडू ऐप स्टोर पर प्रकाशन
| आवश्यकता | विवरण |
|---|---|
| स्क्रीनशॉट | 3-5 उच्च गुणवत्ता वाले स्क्रीनशॉट (1920x1080) |
| चिह्न | static/description/ में 128x128 पीएनजी |
| विवरण | static/description/index.html में HTML विवरण |
| लाइसेंस | थीम के लिए LGPL-3 (मानक अभ्यास) |
| संस्करण | मैच ओडू सीरीज (18.0.x.y.z) |
| परीक्षण | ओडू की स्वचालित लिंटिंग जांच पास करें |
| डेमो डेटा | खरीदने से पहले प्रयास करने के लिए डेमो डेटा शामिल करें |
अक्सर पूछे जाने वाले प्रश्न
क्या मैं ओडू थीम में टेलविंड सीएसएस का उपयोग कर सकता हूं?
हालांकि तकनीकी रूप से संभव है, Odoo के अंतर्निहित बूटस्ट्रैप 5 के साथ टेलविंड सीएसएस का उपयोग करने से टकराव पैदा होता है और बंडल का आकार काफी बढ़ जाता है। अनुशंसित दृष्टिकोण बूटस्ट्रैप 5 उपयोगिताओं और एससीएसएस कस्टम गुणों का उपयोग करना है, जो मूल रूप से ओडू की संपत्ति पाइपलाइन और वेबसाइट बिल्डर के साथ एकीकृत होते हैं। यदि आपको उपयोगिता वर्गों की आवश्यकता है जो बूटस्ट्रैप प्रदान नहीं करता है, तो इसके बजाय कस्टम SCSS उपयोगिताएँ बनाएँ।
मैं अपनी थीम को ओडू 17 और 18 दोनों के साथ कैसे संगत बनाऊं?
प्रत्येक Odoo संस्करण के लिए अलग शाखाएँ बनाएँ। Odoo 17 बूटस्ट्रैप 5.1 का उपयोग करता है जबकि Odoo 18 CSS वेरिएबल समर्थन के साथ बूटस्ट्रैप 5.3 का उपयोग करता है। परिसंपत्ति पंजीकरण भी बदल गया - Odoo 18 मैनिफ़ेस्ट संपत्ति कुंजी को प्राथमिकता देता है जबकि Odoo 17 XML टेम्पलेट इनहेरिटेंस का उपयोग करता है। साझा एससीएसएस आंशिक और संस्करण-विशिष्ट एकीकरण फ़ाइलें बनाए रखें।
मेरे एससीएसएस वैरिएबल ओवरराइड क्यों काम नहीं कर रहे हैं?
सबसे आम कारण लोड ऑर्डर है। बूटस्ट्रैप संकलित होने से पहले आपका _variables.scss लोड होना चाहिए। अपने मेनिफेस्ट में 'प्रीपेंड' निर्देश का उपयोग करें: ('प्रीपेंड', 'थीम_नाम/स्टैटिक/src/scss/_variables.scss')। यह भी सुनिश्चित करें कि आप सही वेरिएबल नामों को ओवरराइड कर रहे हैं - ओडू कुछ बूटस्ट्रैप वेरिएबल्स को $o-ब्रांड-प्राइमरी जैसे ओ-पूर्वलग्न संस्करणों के साथ लपेटता है।
कस्टम स्निपेट वेबसाइट बिल्डर के साथ कैसे काम करते हैं?
कस्टम स्निपेट QWeb टेम्प्लेट हैं जो वेबसाइट.स्निपेट्स के टेम्प्लेट इनहेरिटेंस के माध्यम से स्निपेट पैनल में पंजीकृत होते हैं। प्रत्येक स्निपेट को अपनी HTML संरचना के लिए एक टेम्पलेट की आवश्यकता होती है, अनुकूलन पैनल के लिए वेबसाइट.snippet_options में परिभाषित वैकल्पिक विकल्प, और इंटरएक्टिविटी के लिए वैकल्पिक जावास्क्रिप्ट publicWidget.Widget का विस्तार होता है। वेबसाइट बिल्डर स्वचालित रूप से ड्रैग-एंड-ड्रॉप, इनलाइन संपादन और पंजीकृत स्निपेट्स के लिए पूर्ववत/पुनः करने का प्रबंधन करता है।
ओडू थीम में कस्टम फ़ॉन्ट जोड़ने का सबसे अच्छा तरीका क्या है?
WOFF2 फ़ॉन्ट फ़ाइलों को static/src/fonts/ में रखें और अपने SCSS में @font-face नियम परिभाषित करें। प्रदर्शन के लिए फ़ॉन्ट-डिस्प्ले: स्वैप का उपयोग करें। फिर अपने _variables.scss में $font-family-sans-serif बूटस्ट्रैप वेरिएबल को ओवरराइड करें। बाहरी सीडीएन से फ़ॉन्ट लोड करने से बचें क्योंकि यह डीएनएस लुकअप जोड़ता है और प्रतिबंधित नेटवर्क में विफल हो सकता है। सबसेट फ़ॉन्ट में केवल आवश्यक वर्ण श्रेणियां शामिल हों।
मैं अपनी ओडू थीम में डार्क मोड का समर्थन कैसे करूं?
Odoo 18 ने CSS कस्टम प्रॉपर्टी के माध्यम से नेटिव डार्क मोड सपोर्ट पेश किया। [data-bs-theme='dark'] चयनकर्ता का उपयोग करके अपनी थीम में डार्क मोड वेरिएबल्स को ओवरराइड करें। अपने कस्टम रंग, पृष्ठभूमि और छाया के हल्के और गहरे दोनों प्रकार को परिभाषित करें। वेबसाइट बिल्डर टॉगल स्विचिंग को संभालता है - आपकी थीम को बस दोनों मोड के लिए सही सीएसएस वैरिएबल मान प्रदान करने की आवश्यकता है।
अगले चरण
थीम विकास वह है जहां डिज़ाइन इंजीनियरिंग से मिलता है। एक अच्छी तरह से निर्मित ओडू थीम सैकड़ों ग्राहकों को सेवा प्रदान कर सकती है और ओडू ऐप स्टोर पर महत्वपूर्ण आवर्ती राजस्व उत्पन्न कर सकती है।
संबंधित गाइड के लिए:
- ओडू पायथन डेवलपमेंट गाइड - बैकएंड डेवलपमेंट फंडामेंटल
- ओडू कस्टम मॉड्यूल डेवलपमेंट - मॉड्यूल आर्किटेक्चर अवलोकन
- ओडू रेस्ट एपीआई ट्यूटोरियल - एपीआई एकीकरण पैटर्न
एक कस्टम Odoo थीम या वेबसाइट रीडिज़ाइन की आवश्यकता है? ECOSIRE की Odoo अनुकूलन टीम पूर्ण वेबसाइट बिल्डर एकीकरण, सभी ब्रेकप्वाइंट पर प्रतिक्रियाशील डिज़ाइन और अंतर्राष्ट्रीय तैनाती के लिए RTL समर्थन के साथ एंटरप्राइज़-ग्रेड थीम डिज़ाइन और बनाती है। हमने 40 से अधिक देशों में ग्राहकों के लिए कस्टम थीम वितरित की हैं। निःशुल्क डिज़ाइन परामर्श के लिए हमसे संपर्क करें।
लेखक
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
संबंधित लेख
blog.posts.ai-powered-customer-segmentation-guide.title
blog.posts.ai-powered-customer-segmentation-guide.description
blog.posts.ai-supply-chain-optimization-2026.title
blog.posts.ai-supply-chain-optimization-2026.description
blog.posts.b2b-ecommerce-strategy-wholesale-guide.title
blog.posts.b2b-ecommerce-strategy-wholesale-guide.description