Compare commits
8 Commits
e470d730ed
...
5d7f7267e7
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d7f7267e7 | |||
|
|
4b6ed3781d | ||
|
|
bdb23b923f | ||
| ae8973ba11 | |||
|
|
fbf20b1fa2 | ||
|
|
49500e41df | ||
| 640fae8be8 | |||
| 3d8621e6ab |
3
addons/theme_aakriti_v2/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
28
addons/theme_aakriti_v2/__manifest__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': 'Aakriti Events - Premium Theme V2',
|
||||||
|
'version': '17.0.1.0.0',
|
||||||
|
'category': 'Theme/Creative',
|
||||||
|
'summary': 'Premium dark-gold events theme for Aakriti Events website',
|
||||||
|
'description': """
|
||||||
|
Aakriti Events Premium Theme V2.
|
||||||
|
A fully standalone, luxurious dark-gold events theme featuring:
|
||||||
|
- Dramatic hero section with event photography
|
||||||
|
- Services grid (Wedding, Corporate, Birthday, Cultural, Stage, Brand Launch, Private Parties, Event Coordination)
|
||||||
|
- Gallery carousel, process steps, testimonials, stats and contact form
|
||||||
|
- Sticky header with gold CTA button and mobile-responsive drawer nav
|
||||||
|
- Dark footer with 4-column grid
|
||||||
|
Can be switched to from Website > Theme settings.
|
||||||
|
""",
|
||||||
|
'author': 'Antigravity',
|
||||||
|
'depends': ['website', 'event_rental'],
|
||||||
|
'data': [
|
||||||
|
'views/website_v2_templates.xml',
|
||||||
|
'views/portfolio_templates.xml',
|
||||||
|
'views/blog_templates.xml',
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
'auto_install': False,
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
||||||
BIN
addons/theme_aakriti_v2/__pycache__/__init__.cpython-310.pyc
Normal file
2
addons/theme_aakriti_v2/controllers/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import blog_controller
|
||||||
30
addons/theme_aakriti_v2/controllers/blog_controller.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
||||||
|
from ..utils.blog_data import get_all_posts, get_post_by_slug, get_recent_posts
|
||||||
|
|
||||||
|
|
||||||
|
class V2BlogController(http.Controller):
|
||||||
|
|
||||||
|
@http.route('/blog', type='http', auth='public', website=True)
|
||||||
|
def blog_list(self, **kwargs):
|
||||||
|
"""Render the blog listing page with all posts."""
|
||||||
|
posts = get_all_posts()
|
||||||
|
return request.render('theme_aakriti_v2.v2_blog_list', {
|
||||||
|
'posts': posts,
|
||||||
|
'page_title': 'Blog — Aakriti Events',
|
||||||
|
})
|
||||||
|
|
||||||
|
@http.route('/blog/<string:slug>', type='http', auth='public', website=True)
|
||||||
|
def blog_detail(self, slug, **kwargs):
|
||||||
|
"""Render a single blog post by slug."""
|
||||||
|
post = get_post_by_slug(slug)
|
||||||
|
if not post:
|
||||||
|
return request.not_found()
|
||||||
|
|
||||||
|
recent = get_recent_posts(exclude_slug=slug, limit=3)
|
||||||
|
return request.render('theme_aakriti_v2.v2_blog_detail', {
|
||||||
|
'post': post,
|
||||||
|
'recent_posts': recent,
|
||||||
|
'page_title': post['title'] + ' — Aakriti Events',
|
||||||
|
})
|
||||||
2868
addons/theme_aakriti_v2/static/src/css/theme_v2.css
Normal file
BIN
addons/theme_aakriti_v2/static/src/img/about.webp
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/about/cta.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 57 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/birthday.png
Normal file
|
After Width: | Height: | Size: 998 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/corporate.png
Normal file
|
After Width: | Height: | Size: 743 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/cta-img.png
Normal file
|
After Width: | Height: | Size: 237 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/cultural.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
addons/theme_aakriti_v2/static/src/img/decorative-line.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/decorative-line.webp
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/gallery1.webp
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/hero-banner.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
addons/theme_aakriti_v2/static/src/img/hero_bg.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/home-banner.webp
Normal file
|
After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/process/design.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/process/discover.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/process/execute.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/process/plan.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 14 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/1.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/2.webp
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/3.webp
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/4.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/5.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/6.webp
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/7.webp
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/home/works/8.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/inner-banner/1.webp
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/inner-banner/2.webp
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/inner-banner/3.webp
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/inner-banner/4.webp
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/inner-banner/5.webp
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/logo.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/all.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/corporate.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/cultural.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/engagements.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/festivals.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/pre-wedding.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/portfolio/wedding.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
addons/theme_aakriti_v2/static/src/img/stage_decor.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
addons/theme_aakriti_v2/static/src/img/wedding.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
345
addons/theme_aakriti_v2/static/src/js/theme_v2.js
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
/**
|
||||||
|
* Aakriti Events – Premium Theme V2 JS
|
||||||
|
* Handles: sticky header, mobile drawer, gallery carousel, scroll reveal, counter animation
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* ── Helpers ──────────────────────────────────────────── */
|
||||||
|
function qs(sel, ctx) { return (ctx || document).querySelector(sel); }
|
||||||
|
function qsa(sel, ctx) { return (ctx || document).querySelectorAll(sel); }
|
||||||
|
function onReady(fn) {
|
||||||
|
if (document.readyState !== 'loading') { fn(); }
|
||||||
|
else { document.addEventListener('DOMContentLoaded', fn); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Sticky Header ────────────────────────────────────── */
|
||||||
|
function initHeader() {
|
||||||
|
var header = qs('#v2-header');
|
||||||
|
if (!header) return;
|
||||||
|
|
||||||
|
function updateHeader() {
|
||||||
|
if (window.scrollY > 40) {
|
||||||
|
header.classList.add('scrolled');
|
||||||
|
} else {
|
||||||
|
header.classList.remove('scrolled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', updateHeader, { passive: true });
|
||||||
|
updateHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Mobile Drawer ────────────────────────────────────── */
|
||||||
|
function initMobileDrawer() {
|
||||||
|
var toggle = qs('#v2-mobile-toggle');
|
||||||
|
var drawer = qs('#v2-mobile-drawer');
|
||||||
|
var overlay = qs('#v2-drawer-overlay');
|
||||||
|
var closeBtn = qs('#v2-drawer-close');
|
||||||
|
if (!toggle || !drawer) return;
|
||||||
|
|
||||||
|
function openDrawer() {
|
||||||
|
drawer.classList.add('open');
|
||||||
|
if (overlay) { overlay.classList.add('active'); }
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
function closeDrawer() {
|
||||||
|
drawer.classList.remove('open');
|
||||||
|
if (overlay) { overlay.classList.remove('active'); }
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle.addEventListener('click', openDrawer);
|
||||||
|
if (closeBtn) { closeBtn.addEventListener('click', closeDrawer); }
|
||||||
|
if (overlay) { overlay.addEventListener('click', closeDrawer); }
|
||||||
|
|
||||||
|
qsa('#v2-mobile-drawer a').forEach(function (a) {
|
||||||
|
a.addEventListener('click', closeDrawer);
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
if (window.innerWidth > 991) { closeDrawer(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Gallery Carousel ─────────────────────────────────── */
|
||||||
|
function initGallery() {
|
||||||
|
var track = qs('#v2-gallery-track');
|
||||||
|
var prevBtn = qs('#v2-gallery-prev');
|
||||||
|
var nextBtn = qs('#v2-gallery-next');
|
||||||
|
if (!track) return;
|
||||||
|
|
||||||
|
var current = 0;
|
||||||
|
var itemWidth = 0;
|
||||||
|
var visibleItems = 4;
|
||||||
|
|
||||||
|
function updateLayout() {
|
||||||
|
var ww = window.innerWidth;
|
||||||
|
if (ww > 991) {
|
||||||
|
visibleItems = 4;
|
||||||
|
} else if (ww > 576) {
|
||||||
|
visibleItems = 3;
|
||||||
|
} else {
|
||||||
|
visibleItems = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var containerWidth = track.parentElement.offsetWidth;
|
||||||
|
var gap = 12; // White gap between slanted items in pixels
|
||||||
|
|
||||||
|
var items = qsa('.v2-gallery-item-slant', track);
|
||||||
|
|
||||||
|
// Calculate width 'w' so that 'visibleItems' fit exactly in containerWidth
|
||||||
|
var w = (containerWidth - (visibleItems - 1) * gap) / (0.75 * visibleItems + 0.25);
|
||||||
|
var mr = (-0.25 * w) + gap;
|
||||||
|
|
||||||
|
items.forEach(function (item, idx) {
|
||||||
|
item.style.width = w + 'px';
|
||||||
|
if (idx === items.length - 1) {
|
||||||
|
item.style.marginRight = '0px';
|
||||||
|
} else {
|
||||||
|
item.style.marginRight = mr + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
itemWidth = (w * 0.75) + gap; // The effective step width to slide
|
||||||
|
|
||||||
|
current = clamp(current, 0, getMax());
|
||||||
|
goTo(current, false);
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); }
|
||||||
|
|
||||||
|
function getMax() {
|
||||||
|
var itemsCount = track.children.length;
|
||||||
|
return Math.max(0, itemsCount - visibleItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateButtons() {
|
||||||
|
if (prevBtn) {
|
||||||
|
if (current <= 0) {
|
||||||
|
prevBtn.style.opacity = '0.5';
|
||||||
|
prevBtn.style.pointerEvents = 'none';
|
||||||
|
} else {
|
||||||
|
prevBtn.style.opacity = '1';
|
||||||
|
prevBtn.style.pointerEvents = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextBtn) {
|
||||||
|
if (current >= getMax()) {
|
||||||
|
nextBtn.style.opacity = '0.5';
|
||||||
|
nextBtn.style.pointerEvents = 'none';
|
||||||
|
} else {
|
||||||
|
nextBtn.style.opacity = '1';
|
||||||
|
nextBtn.style.pointerEvents = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goTo(index, animate) {
|
||||||
|
if (animate === undefined) animate = true;
|
||||||
|
current = clamp(index, 0, getMax());
|
||||||
|
track.style.transition = animate ? 'transform 0.4s ease' : 'none';
|
||||||
|
track.style.transform = 'translateX(-' + (current * itemWidth) + 'px)';
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevBtn) { prevBtn.addEventListener('click', function () { goTo(current - 1); resetAutoSlide(); }); }
|
||||||
|
if (nextBtn) { nextBtn.addEventListener('click', function () { goTo(current + 1); resetAutoSlide(); }); }
|
||||||
|
|
||||||
|
// Touch/swipe support
|
||||||
|
var startX = 0;
|
||||||
|
track.addEventListener('touchstart', function (e) { startX = e.touches[0].clientX; }, { passive: true });
|
||||||
|
track.addEventListener('touchend', function (e) {
|
||||||
|
var diff = startX - e.changedTouches[0].clientX;
|
||||||
|
if (Math.abs(diff) > 50) {
|
||||||
|
goTo(current + (diff > 0 ? 1 : -1));
|
||||||
|
resetAutoSlide();
|
||||||
|
}
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
// Auto slide
|
||||||
|
var autoSlideInterval;
|
||||||
|
function startAutoSlide() {
|
||||||
|
autoSlideInterval = setInterval(function () {
|
||||||
|
if (current >= getMax()) {
|
||||||
|
goTo(0);
|
||||||
|
} else {
|
||||||
|
goTo(current + 1);
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
function resetAutoSlide() {
|
||||||
|
clearInterval(autoSlideInterval);
|
||||||
|
startAutoSlide();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', updateLayout);
|
||||||
|
updateLayout();
|
||||||
|
startAutoSlide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Scroll Reveal ────────────────────────────────────── */
|
||||||
|
function initReveal() {
|
||||||
|
var els = qsa('.v2-reveal');
|
||||||
|
if (!els.length) return;
|
||||||
|
|
||||||
|
if ('IntersectionObserver' in window) {
|
||||||
|
var io = new IntersectionObserver(function (entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.classList.add('visible');
|
||||||
|
io.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { threshold: 0.12 });
|
||||||
|
els.forEach(function (el) { io.observe(el); });
|
||||||
|
} else {
|
||||||
|
els.forEach(function (el) { el.classList.add('visible'); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Counter Animation ────────────────────────────────── */
|
||||||
|
function animateCounter(el, target, suffix) {
|
||||||
|
var start = 0;
|
||||||
|
var duration = 1800;
|
||||||
|
var startTime = null;
|
||||||
|
|
||||||
|
function step(ts) {
|
||||||
|
if (!startTime) startTime = ts;
|
||||||
|
var progress = Math.min((ts - startTime) / duration, 1);
|
||||||
|
var eased = 1 - Math.pow(1 - progress, 3); // ease out cubic
|
||||||
|
var val = Math.round(eased * target);
|
||||||
|
el.textContent = val + suffix;
|
||||||
|
if (progress < 1) { requestAnimationFrame(step); }
|
||||||
|
}
|
||||||
|
requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initCounters() {
|
||||||
|
var counters = qsa('[data-v2-counter]');
|
||||||
|
if (!counters.length) return;
|
||||||
|
|
||||||
|
var observed = false;
|
||||||
|
|
||||||
|
if ('IntersectionObserver' in window) {
|
||||||
|
var io = new IntersectionObserver(function (entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
if (entry.isIntersecting && !observed) {
|
||||||
|
observed = true;
|
||||||
|
counters.forEach(function (el) {
|
||||||
|
var target = parseInt(el.getAttribute('data-v2-counter'), 10);
|
||||||
|
var suffix = el.getAttribute('data-v2-suffix') || '';
|
||||||
|
animateCounter(el, target, suffix);
|
||||||
|
});
|
||||||
|
io.disconnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { threshold: 0.3 });
|
||||||
|
|
||||||
|
var statsSection = qs('#v2-stats');
|
||||||
|
if (statsSection) { io.observe(statsSection); }
|
||||||
|
} else {
|
||||||
|
counters.forEach(function (el) {
|
||||||
|
el.textContent = el.getAttribute('data-v2-counter') + (el.getAttribute('data-v2-suffix') || '');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Active nav link ──────────────────────────────────── */
|
||||||
|
function initActiveNav() {
|
||||||
|
var path = window.location.pathname;
|
||||||
|
qsa('.v2-nav a, .v2-drawer-nav a').forEach(function (a) {
|
||||||
|
var href = a.getAttribute('href') || '';
|
||||||
|
if (href === path || (href !== '/' && path.startsWith(href))) {
|
||||||
|
a.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Bootstrap ────────────────────────────────────────── */
|
||||||
|
function initPortfolio() {
|
||||||
|
const grid = document.getElementById('v2-portfolio-grid');
|
||||||
|
const tabs = document.querySelectorAll('.v2-portfolio-tab');
|
||||||
|
if (!grid || !tabs.length) return;
|
||||||
|
|
||||||
|
// Dynamic portfolio data
|
||||||
|
const portfolioData = [
|
||||||
|
{ category: 'weddings', img: '/theme_aakriti_v2/static/src/img/wedding.png', title: 'Romantic Garden Wedding', location: 'Bangalore, India' },
|
||||||
|
{ category: 'corporate', img: '/theme_aakriti_v2/static/src/img/corporate.png', title: 'Annual Corporate Summit', location: 'Hyderabad, India' },
|
||||||
|
{ category: 'birthday', img: '/theme_aakriti_v2/static/src/img/birthday.png', title: 'Milestone Birthday Bash', location: 'Bangalore, India' },
|
||||||
|
{ category: 'cultural', img: '/theme_aakriti_v2/static/src/img/cultural.png', title: 'Royal Cultural Night', location: 'Mysore, India' },
|
||||||
|
{ category: 'private', img: '/theme_aakriti_v2/static/src/img/gallery1.webp', title: 'Private Celebration', location: 'Goa, India' },
|
||||||
|
{ category: 'weddings', img: '/theme_aakriti_v2/static/src/img/about.webp', title: 'Classic Wedding', location: 'Bangalore, India' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Function to render items
|
||||||
|
function renderItems(filter) {
|
||||||
|
grid.innerHTML = ''; // Clear current
|
||||||
|
|
||||||
|
portfolioData.forEach(item => {
|
||||||
|
if (filter === 'all' || filter === item.category) {
|
||||||
|
const itemHTML = `
|
||||||
|
<div class="v2-portfolio-item" data-category="${item.category}" style="opacity: 0; transform: scale(0.9); transition: opacity 0.4s ease, transform 0.4s ease;">
|
||||||
|
<div class="v2-portfolio-item-inner">
|
||||||
|
<img src="${item.img}" alt="${item.title}"/>
|
||||||
|
<div class="v2-portfolio-info">
|
||||||
|
<h3>${item.title}</h3>
|
||||||
|
<p><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 12-9 12s-9-5-9-12a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg> ${item.location}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
// Parse and append to trigger animation
|
||||||
|
const temp = document.createElement('div');
|
||||||
|
temp.innerHTML = itemHTML.trim();
|
||||||
|
const element = temp.firstChild;
|
||||||
|
grid.appendChild(element);
|
||||||
|
|
||||||
|
// Trigger animation after append
|
||||||
|
setTimeout(() => {
|
||||||
|
element.style.opacity = '1';
|
||||||
|
element.style.transform = 'scale(1)';
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial render
|
||||||
|
renderItems('all');
|
||||||
|
|
||||||
|
// Tab click handlers
|
||||||
|
tabs.forEach(tab => {
|
||||||
|
tab.addEventListener('click', function () {
|
||||||
|
tabs.forEach(t => t.classList.remove('active'));
|
||||||
|
this.classList.add('active');
|
||||||
|
|
||||||
|
const filter = this.getAttribute('data-filter');
|
||||||
|
|
||||||
|
// Fade out existing items
|
||||||
|
const currentItems = grid.querySelectorAll('.v2-portfolio-item');
|
||||||
|
currentItems.forEach(item => {
|
||||||
|
item.style.opacity = '0';
|
||||||
|
item.style.transform = 'scale(0.9)';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for fade out, then render new filtered list
|
||||||
|
setTimeout(() => {
|
||||||
|
renderItems(filter);
|
||||||
|
}, 400); // Wait for transition
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onReady(function () {
|
||||||
|
initHeader();
|
||||||
|
initMobileDrawer();
|
||||||
|
initGallery();
|
||||||
|
initReveal();
|
||||||
|
initCounters();
|
||||||
|
initActiveNav();
|
||||||
|
initPortfolio();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
1
addons/theme_aakriti_v2/utils/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
330
addons/theme_aakriti_v2/utils/blog_data.py
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Aakriti Events V2 — Blog Data Utility
|
||||||
|
All blog post data lives here. Each post is a dict with a unique `slug`
|
||||||
|
field used for URL routing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
BLOG_POSTS = [
|
||||||
|
{
|
||||||
|
"slug": "how-to-plan-a-luxury-wedding",
|
||||||
|
"title": "How to Plan a Luxury Wedding Without the Stress",
|
||||||
|
"category": "Wedding Tips",
|
||||||
|
"date": "June 15, 2025",
|
||||||
|
"read_time": "6 min read",
|
||||||
|
"image": "/theme_aakriti_v2/static/src/img/wedding.png",
|
||||||
|
"excerpt": (
|
||||||
|
"Planning a luxury wedding can feel overwhelming, but with the right team "
|
||||||
|
"and timeline in place, your dream celebration becomes effortlessly achievable."
|
||||||
|
),
|
||||||
|
"content": """
|
||||||
|
<p>A luxury wedding is more than just a big budget — it's about creating an experience
|
||||||
|
that feels personal, intentional, and effortlessly beautiful for every single guest.
|
||||||
|
The secret to pulling this off without stress lies in three core principles:
|
||||||
|
<strong>early planning, the right vendor network, and clear communication.</strong></p>
|
||||||
|
|
||||||
|
<h3>Start at Least 12 Months Out</h3>
|
||||||
|
<p>The most sought-after venues, photographers, and floral designers book up quickly.
|
||||||
|
Starting your planning journey 12–18 months before your date ensures you have access
|
||||||
|
to the very best. Begin with a clear vision board and a realistic budget conversation
|
||||||
|
before you book anything.</p>
|
||||||
|
|
||||||
|
<h3>Build Your Dream Team First</h3>
|
||||||
|
<p>Your wedding planner and creative director are your most important hires.
|
||||||
|
A great planner will have an established vendor network, negotiate on your behalf,
|
||||||
|
and manage your timeline so you never have to worry. At Aakriti Design, we handle
|
||||||
|
every detail — from mandap construction to guest flow logistics — so you can
|
||||||
|
simply be present on your day.</p>
|
||||||
|
|
||||||
|
<h3>Design Around Your Story</h3>
|
||||||
|
<p>Luxury isn't about excess — it's about meaning. Every floral arrangement,
|
||||||
|
every lighting choice, every table setting should reflect who you are as a couple.
|
||||||
|
We begin every wedding design consultation by listening. Your cultural background,
|
||||||
|
your favourite memories, the mood you want guests to feel walking in — all of this
|
||||||
|
shapes our creative direction.</p>
|
||||||
|
|
||||||
|
<h3>Plan for the Guest Experience</h3>
|
||||||
|
<p>The difference between a good wedding and an unforgettable one is how guests
|
||||||
|
<em>feel</em> as they move through the day. Think about arrival moments, cocktail
|
||||||
|
hour flow, the reveal of the main reception space, and the energy of the dance floor.
|
||||||
|
Every transition is an opportunity to create a memory.</p>
|
||||||
|
|
||||||
|
<p>Ready to start planning your dream wedding? <a href="/contactus">Reach out to our
|
||||||
|
team</a> for a complimentary consultation.</p>
|
||||||
|
""",
|
||||||
|
"author": "Paarul Ladd",
|
||||||
|
"author_title": "Founder & Creative Director",
|
||||||
|
"tags": ["Wedding", "Planning", "Luxury"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slug": "multicultural-wedding-design-tips",
|
||||||
|
"title": "Multicultural Wedding Design: Blending Traditions Beautifully",
|
||||||
|
"category": "Design Inspiration",
|
||||||
|
"date": "May 28, 2025",
|
||||||
|
"read_time": "5 min read",
|
||||||
|
"image": "/theme_aakriti_v2/static/src/img/cultural.png",
|
||||||
|
"excerpt": (
|
||||||
|
"Designing a fusion wedding that honours two cultures with equal beauty and "
|
||||||
|
"respect requires deep creativity and cultural sensitivity. Here's how we do it."
|
||||||
|
),
|
||||||
|
"content": """
|
||||||
|
<p>Multicultural weddings are among the most beautiful and complex celebrations
|
||||||
|
to design. When two families bring different traditions, colour palettes, rituals,
|
||||||
|
and aesthetic expectations to the same event, the challenge is to honour them
|
||||||
|
all — without making the event feel like a compromise.</p>
|
||||||
|
|
||||||
|
<h3>Start with a Cultural Discovery Session</h3>
|
||||||
|
<p>Before we pick a single flower or choose a fabric, we sit down with both
|
||||||
|
families separately and together. We ask about rituals that matter most, colours
|
||||||
|
that hold significance, and moments they want guests to witness and remember.
|
||||||
|
This forms the emotional foundation of the entire design.</p>
|
||||||
|
|
||||||
|
<h3>Find the Visual Thread</h3>
|
||||||
|
<p>Every beautiful fusion design has a unifying visual language — a colour, a
|
||||||
|
texture, or a motif that bridges both traditions. For an Indo-Western wedding,
|
||||||
|
this might be ivory and gold paired with lush greenery. For an African-South Asian
|
||||||
|
celebration, it could be rich jewel tones with intricate pattern work. The thread
|
||||||
|
makes the event feel cohesive rather than divided.</p>
|
||||||
|
|
||||||
|
<h3>Zone the Ceremony Thoughtfully</h3>
|
||||||
|
<p>When a celebration includes two ceremony types — a Hindu ceremony and a Christian
|
||||||
|
blessing, for example — how you transition between zones matters enormously. Lighting,
|
||||||
|
floral drops, or even a simple walk through a beautifully designed corridor can create
|
||||||
|
a meaningful moment of transition between rituals.</p>
|
||||||
|
|
||||||
|
<h3>Communicate with Vendors Early</h3>
|
||||||
|
<p>Caterers, musicians, officiants — every vendor needs to understand the cultural
|
||||||
|
context of what they're contributing to. We brief each vendor thoroughly and ensure
|
||||||
|
all timelines account for the natural pace of different ritual formats.</p>
|
||||||
|
|
||||||
|
<p>We've had the privilege of designing some of the most extraordinary fusion
|
||||||
|
celebrations in the region. <a href="/contactus">Let's talk about yours.</a></p>
|
||||||
|
""",
|
||||||
|
"author": "Paarul Ladd",
|
||||||
|
"author_title": "Founder & Creative Director",
|
||||||
|
"tags": ["Multicultural", "Wedding", "Design"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slug": "stage-decoration-trends-2025",
|
||||||
|
"title": "Stage Decoration Trends Dominating 2025 Events",
|
||||||
|
"category": "Trends",
|
||||||
|
"date": "May 10, 2025",
|
||||||
|
"read_time": "4 min read",
|
||||||
|
"image": "/theme_aakriti_v2/static/src/img/stage_decor.png",
|
||||||
|
"excerpt": (
|
||||||
|
"From dramatic floral backdrops to architectural LED installations, "
|
||||||
|
"stage design in 2025 is bolder, more immersive, and deeply personal."
|
||||||
|
),
|
||||||
|
"content": """
|
||||||
|
<p>The stage is the centrepiece of any celebration — the place where memories are
|
||||||
|
made, photographs are taken, and families gather. In 2025, stage decoration has
|
||||||
|
evolved dramatically, moving beyond standard floral arches toward fully immersive,
|
||||||
|
architectural experiences.</p>
|
||||||
|
|
||||||
|
<h3>1. Organic Floral Cascades</h3>
|
||||||
|
<p>Tightly packed, symmetrical floral walls are giving way to organic, cascading
|
||||||
|
arrangements that feel wild and lush. Think trailing jasmine, oversized garden roses,
|
||||||
|
and dramatic foliage draping from asymmetric frames. The effect is romantic without
|
||||||
|
feeling rigid.</p>
|
||||||
|
|
||||||
|
<h3>2. Mixed Material Backdrops</h3>
|
||||||
|
<p>Combining fabric draping with metallic accents, geometric frames, and live
|
||||||
|
botanicals creates stages with depth and texture. The interplay of softness and
|
||||||
|
structure creates a visually rich backdrop that photographs beautifully from
|
||||||
|
every angle.</p>
|
||||||
|
|
||||||
|
<h3>3. LED and Projection Mapping</h3>
|
||||||
|
<p>For evening events and corporate galas, projection mapping onto stage structures
|
||||||
|
allows dynamic, programmable visuals that transform throughout the event. From a
|
||||||
|
soft warm glow during dinner to an energetic light show for the reception, the
|
||||||
|
technology adds theatrical impact.</p>
|
||||||
|
|
||||||
|
<h3>4. Custom Monogram and Typography</h3>
|
||||||
|
<p>Couples and brands are increasingly requesting custom typographic elements
|
||||||
|
integrated into stage design — neon or acrylic lettering, laser-cut name panels,
|
||||||
|
and illuminated monograms that serve as both decor and branding.</p>
|
||||||
|
|
||||||
|
<h3>5. Sustainability-Forward Design</h3>
|
||||||
|
<p>2025 is also the year event design gets more sustainable. Rental flower walls,
|
||||||
|
reusable structural elements, and seasonal, locally sourced florals are becoming
|
||||||
|
standard practice for conscious couples.</p>
|
||||||
|
|
||||||
|
<p>Want to see how these trends could work for your event?
|
||||||
|
<a href="/contactus">Book a design consultation with us.</a></p>
|
||||||
|
""",
|
||||||
|
"author": "Paarul Ladd",
|
||||||
|
"author_title": "Founder & Creative Director",
|
||||||
|
"tags": ["Stage Design", "Trends", "Decor"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slug": "corporate-event-design-essentials",
|
||||||
|
"title": "Corporate Event Design: Making Brand Moments Unforgettable",
|
||||||
|
"category": "Corporate Events",
|
||||||
|
"date": "April 22, 2025",
|
||||||
|
"read_time": "5 min read",
|
||||||
|
"image": "/theme_aakriti_v2/static/src/img/corporate.png",
|
||||||
|
"excerpt": (
|
||||||
|
"A corporate event is a brand experience. Every design decision — from "
|
||||||
|
"the entrance to the stage — should reflect your company's identity and values."
|
||||||
|
),
|
||||||
|
"content": """
|
||||||
|
<p>Corporate events are often treated as purely logistical exercises — a venue,
|
||||||
|
some food, a speaker. But the most impactful brand moments happen when design
|
||||||
|
is treated with the same care as content. When a space feels right, guests
|
||||||
|
pay attention, they engage, they remember.</p>
|
||||||
|
|
||||||
|
<h3>Design That Communicates Brand Identity</h3>
|
||||||
|
<p>The moment a guest enters your event, they should feel your brand. This means
|
||||||
|
your colour palette, typography, and visual language need to carry through from
|
||||||
|
the signage at the entrance to the centrepieces on the tables. We work closely
|
||||||
|
with your marketing team to ensure design coherence at every touchpoint.</p>
|
||||||
|
|
||||||
|
<h3>Entrance Design Matters Most</h3>
|
||||||
|
<p>The entrance moment sets the emotional tone for everything that follows. A
|
||||||
|
dramatic brand-installed entrance arch, a branded photo wall, or a thoughtfully
|
||||||
|
lit arrival corridor creates a sense of occasion and signals to guests that this
|
||||||
|
event is special.</p>
|
||||||
|
|
||||||
|
<h3>Stage and AV Integration</h3>
|
||||||
|
<p>For conferences and product launches, the stage design and audio-visual
|
||||||
|
production need to work as one unified system. Screens, lighting rigs, speaker
|
||||||
|
positions, and branding elements should be designed together, not assembled
|
||||||
|
separately. We coordinate closely with AV teams to ensure a seamless result.</p>
|
||||||
|
|
||||||
|
<h3>Networking Spaces Deserve Design Attention</h3>
|
||||||
|
<p>Breakout rooms and networking areas are where conversations — and deals —
|
||||||
|
happen. Comfortable, well-designed networking zones with good lighting and
|
||||||
|
thoughtful furniture arrangements significantly increase guest engagement and
|
||||||
|
event ROI.</p>
|
||||||
|
|
||||||
|
<p>Planning a corporate event or brand activation?
|
||||||
|
<a href="/contactus">Let's create something exceptional together.</a></p>
|
||||||
|
""",
|
||||||
|
"author": "Paarul Ladd",
|
||||||
|
"author_title": "Founder & Creative Director",
|
||||||
|
"tags": ["Corporate", "Brand", "Events"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slug": "birthday-celebration-ideas-adults",
|
||||||
|
"title": "Elevated Birthday Celebrations: Beyond the Ordinary",
|
||||||
|
"category": "Birthday Events",
|
||||||
|
"date": "April 5, 2025",
|
||||||
|
"read_time": "4 min read",
|
||||||
|
"image": "/theme_aakriti_v2/static/src/img/birthday.png",
|
||||||
|
"excerpt": (
|
||||||
|
"Adult birthday celebrations deserve the same creative attention as weddings. "
|
||||||
|
"Here's how to design a milestone birthday that guests will talk about for years."
|
||||||
|
),
|
||||||
|
"content": """
|
||||||
|
<p>A milestone birthday — a 30th, 50th, or 60th — is a significant life moment.
|
||||||
|
It deserves to be celebrated with intention, beauty, and personal meaning.
|
||||||
|
Gone are the days of a standard restaurant booking. Today's elevated birthday
|
||||||
|
events are intimate, immersive, and deeply personal.</p>
|
||||||
|
|
||||||
|
<h3>Choose a Theme That Reflects the Guest of Honour</h3>
|
||||||
|
<p>The best birthday events tell the story of the person being celebrated.
|
||||||
|
Are they a lover of travel? A fashion devotee? A nature enthusiast? Let their
|
||||||
|
passions and personality drive every design decision — from the colour palette
|
||||||
|
and centrepieces to the entertainment and menu.</p>
|
||||||
|
|
||||||
|
<h3>The Importance of the Reveal Moment</h3>
|
||||||
|
<p>One of the most powerful design tools for a birthday celebration is the
|
||||||
|
reveal moment — when the guest of honour first sees the decorated space.
|
||||||
|
A well-designed reveal, with controlled lighting and a dramatic entrance, creates
|
||||||
|
an emotional peak that guests carry with them forever.</p>
|
||||||
|
|
||||||
|
<h3>Intimate vs. Grand — Both Can Be Extraordinary</h3>
|
||||||
|
<p>An intimate dinner for 20 can be just as visually stunning as a party for 200.
|
||||||
|
In fact, smaller gatherings allow for more intricate, personal design details —
|
||||||
|
custom place cards, hand-written menus, personalised table settings, and curated
|
||||||
|
sensory experiences that wouldn't be practical at scale.</p>
|
||||||
|
|
||||||
|
<h3>Commission a Signature Cake</h3>
|
||||||
|
<p>A custom birthday cake that reflects the guest of honour's aesthetic is one
|
||||||
|
of the most photographed moments of any celebration. Work with an artist-baker
|
||||||
|
to create something that becomes a conversation piece — and the centrepiece of
|
||||||
|
the dessert table.</p>
|
||||||
|
|
||||||
|
<p>Ready to design a birthday celebration as special as the person it honours?
|
||||||
|
<a href="/contactus">Let's begin the conversation.</a></p>
|
||||||
|
""",
|
||||||
|
"author": "Paarul Ladd",
|
||||||
|
"author_title": "Founder & Creative Director",
|
||||||
|
"tags": ["Birthday", "Celebration", "Design"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slug": "event-decor-colour-palette-guide",
|
||||||
|
"title": "The Art of Choosing Your Event Colour Palette",
|
||||||
|
"category": "Design Guide",
|
||||||
|
"date": "March 18, 2025",
|
||||||
|
"read_time": "7 min read",
|
||||||
|
"image": "/theme_aakriti_v2/static/src/img/gallery1.webp",
|
||||||
|
"excerpt": (
|
||||||
|
"Your event colour palette sets the emotional tone before a single guest "
|
||||||
|
"arrives. Learn how to choose a palette that feels intentional and cohesive."
|
||||||
|
),
|
||||||
|
"content": """
|
||||||
|
<p>Colour is the most powerful emotional tool in event design. Before a guest
|
||||||
|
reads a single word of signage or takes their first bite of food, the colour
|
||||||
|
palette of a space has already communicated the mood, the personality, and the
|
||||||
|
intention of the event. Choosing thoughtfully matters enormously.</p>
|
||||||
|
|
||||||
|
<h3>Start with the Emotional Goal</h3>
|
||||||
|
<p>Ask yourself: how do you want guests to feel when they walk in? Romantic and
|
||||||
|
intimate? Celebratory and energetic? Sophisticated and calm? Different colour
|
||||||
|
families evoke different emotional responses. Warm terracottas and earthy tones
|
||||||
|
feel grounded and welcoming. Cool blues and silvers feel refined and elegant.
|
||||||
|
Jewel tones feel festive and rich.</p>
|
||||||
|
|
||||||
|
<h3>Choose a Dominant, Secondary, and Accent</h3>
|
||||||
|
<p>The most successful event palettes use three layers of colour. A dominant
|
||||||
|
colour (60% of the visual space), a secondary colour (30%), and an accent
|
||||||
|
(10%). This structure creates visual harmony without monotony. For a luxury
|
||||||
|
wedding, this might look like: soft ivory (dominant), dusty sage (secondary),
|
||||||
|
and burnished gold (accent).</p>
|
||||||
|
|
||||||
|
<h3>Consider How Colour Behaves in Different Lighting</h3>
|
||||||
|
<p>A colour that looks perfect in a mood board can behave completely differently
|
||||||
|
under warm uplighting, natural daylight, or cool LED wash. We always review
|
||||||
|
fabric and floral samples under the actual event lighting conditions before
|
||||||
|
finalising any palette decision.</p>
|
||||||
|
|
||||||
|
<h3>Cultural Significance of Colour</h3>
|
||||||
|
<p>In multicultural events, colour choices carry symbolic weight. Red is auspicious
|
||||||
|
in South Asian traditions; white is associated with mourning in some East Asian
|
||||||
|
cultures. Understanding the cultural context of your guest list ensures colour
|
||||||
|
choices feel respectful and celebratory.</p>
|
||||||
|
|
||||||
|
<h3>Test Before You Commit</h3>
|
||||||
|
<p>We always recommend a mock-up table setting or a small test arrangement before
|
||||||
|
finalising large orders. Seeing colours together in a real-world setting — with
|
||||||
|
real fabrics, real florals, and real lighting — often reveals refinements that
|
||||||
|
digital mood boards miss.</p>
|
||||||
|
|
||||||
|
<p>Working on an event and unsure about your palette?
|
||||||
|
<a href="/contactus">Book a design session with our team.</a></p>
|
||||||
|
""",
|
||||||
|
"author": "Paarul Ladd",
|
||||||
|
"author_title": "Founder & Creative Director",
|
||||||
|
"tags": ["Design", "Colour", "Tips"],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_posts():
|
||||||
|
"""Return all blog posts."""
|
||||||
|
return BLOG_POSTS
|
||||||
|
|
||||||
|
|
||||||
|
def get_post_by_slug(slug):
|
||||||
|
"""Return a single blog post dict by its slug, or None if not found."""
|
||||||
|
for post in BLOG_POSTS:
|
||||||
|
if post["slug"] == slug:
|
||||||
|
return post
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_recent_posts(exclude_slug=None, limit=3):
|
||||||
|
"""Return recent posts, optionally excluding one by slug."""
|
||||||
|
posts = [p for p in BLOG_POSTS if p["slug"] != exclude_slug]
|
||||||
|
return posts[:limit]
|
||||||
615
addons/theme_aakriti_v2/views/blog_templates.xml
Normal file
@ -0,0 +1,615 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- ══════════════════════════════════════════════════════
|
||||||
|
BLOG LIST PAGE
|
||||||
|
Route: /v2/blog
|
||||||
|
══════════════════════════════════════════════════════ -->
|
||||||
|
<template id="v2_blog_list" name="V2 Blog List">
|
||||||
|
<t t-call="website.layout">
|
||||||
|
<t t-set="head">
|
||||||
|
<title t-out="page_title"/>
|
||||||
|
<meta name="description" content="Read the latest insights on luxury weddings, event design, multicultural celebrations, and creative inspiration from the Aakriti Events team."/>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<div id="wrap" class="oe_structure" style="background-color: var(--v2-cream); font-family: var(--v2-font-body);">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* ── Blog List Page ── */
|
||||||
|
.v2-blog-banner {
|
||||||
|
position: relative;
|
||||||
|
height: 340px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.v2-blog-banner::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(to bottom, rgba(30, 18, 8, 0.55) 0%, rgba(30, 18, 8, 0.65) 100%);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.v2-blog-banner-bg {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.v2-blog-banner-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.v2-blog-banner-title {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: clamp(2.8rem, 5vw, 4.5rem);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--v2-white);
|
||||||
|
line-height: 1.1;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.v2-blog-breadcrumb {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: rgba(255,255,255,0.75);
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.v2-blog-breadcrumb a {
|
||||||
|
color: rgba(255,255,255,0.75);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.v2-blog-breadcrumb .v2-active {
|
||||||
|
color: var(--v2-gold);
|
||||||
|
}
|
||||||
|
/* Blog Grid */
|
||||||
|
.v2-blog-section {
|
||||||
|
max-width: 1320px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 80px 24px;
|
||||||
|
}
|
||||||
|
.v2-blog-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 32px;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.v2-blog-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.v2-blog-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Blog Card */
|
||||||
|
.v2-blog-card {
|
||||||
|
background: var(--v2-white);
|
||||||
|
border-radius: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 40px rgba(30,18,8,0.06);
|
||||||
|
border: 1px solid var(--v2-border);
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.v2-blog-card:hover {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
box-shadow: 0 20px 50px rgba(30,18,8,0.12);
|
||||||
|
}
|
||||||
|
.v2-blog-card-img-wrap {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
.v2-blog-card-img-wrap img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.6s ease;
|
||||||
|
}
|
||||||
|
.v2-blog-card:hover .v2-blog-card-img-wrap img {
|
||||||
|
transform: scale(1.06);
|
||||||
|
}
|
||||||
|
.v2-blog-card-category {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
left: 16px;
|
||||||
|
background: var(--v2-gold);
|
||||||
|
color: var(--v2-white);
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.v2-blog-card-body {
|
||||||
|
padding: 28px 24px 24px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.v2-blog-card-meta {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: var(--v2-muted);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.v2-blog-card-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.v2-blog-card-title {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--v2-text);
|
||||||
|
line-height: 1.25;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.v2-blog-card-title:hover {
|
||||||
|
color: var(--v2-gold);
|
||||||
|
}
|
||||||
|
.v2-blog-card-excerpt {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: var(--v2-muted);
|
||||||
|
line-height: 1.7;
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.v2-blog-card-link {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--v2-gold);
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
transition: gap 0.2s ease;
|
||||||
|
}
|
||||||
|
.v2-blog-card-link:hover {
|
||||||
|
gap: 10px;
|
||||||
|
color: var(--v2-gold-dark);
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.v2-blog-section {
|
||||||
|
padding: 48px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Inner Banner -->
|
||||||
|
<div class="v2-blog-banner">
|
||||||
|
<img class="v2-blog-banner-bg"
|
||||||
|
src="/theme_aakriti_v2/static/src/img/hero_bg.png"
|
||||||
|
alt="Blog banner"/>
|
||||||
|
<div class="v2-blog-banner-content">
|
||||||
|
<h1 class="v2-blog-banner-title">Our Blog</h1>
|
||||||
|
<div class="v2-blog-breadcrumb">
|
||||||
|
<a href="/">Home</a> / <span class="v2-active">Blog</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Blog Grid -->
|
||||||
|
<div class="v2-blog-section">
|
||||||
|
<div style="text-align:center; margin-bottom:56px;">
|
||||||
|
<div style="font-size:0.75rem; font-weight:700; color:#C9973A; text-transform:uppercase; letter-spacing:0.15em; margin-bottom:12px; display:flex; align-items:center; justify-content:center; gap:12px;">
|
||||||
|
<span style="height:1px; width:40px; background:#C9973A; display:inline-block;"></span>
|
||||||
|
INSIGHTS & INSPIRATION
|
||||||
|
<span style="height:1px; width:40px; background:#C9973A; display:inline-block;"></span>
|
||||||
|
</div>
|
||||||
|
<h2 style="font-family:'Cormorant Garamond',Georgia,serif; font-size:clamp(2rem,3.5vw,3rem); color:#1a1206; font-weight:600; margin:0;">
|
||||||
|
Stories from the Studio
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="v2-blog-grid">
|
||||||
|
<t t-foreach="posts" t-as="post">
|
||||||
|
<article class="v2-blog-card">
|
||||||
|
<div class="v2-blog-card-img-wrap">
|
||||||
|
<img t-att-src="post['image']" t-att-alt="post['title']"/>
|
||||||
|
<span class="v2-blog-card-category" t-out="post['category']"/>
|
||||||
|
</div>
|
||||||
|
<div class="v2-blog-card-body">
|
||||||
|
<div class="v2-blog-card-meta">
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/></svg>
|
||||||
|
<t t-out="post['date']"/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
||||||
|
<t t-out="post['read_time']"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<a t-attf-href="/blog/#{post['slug']}" class="v2-blog-card-title" t-out="post['title']"/>
|
||||||
|
<p class="v2-blog-card-excerpt" t-out="post['excerpt']"/>
|
||||||
|
<a t-attf-href="/blog/#{post['slug']}" class="v2-blog-card-link">
|
||||||
|
Read Article
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ══════════════════════════════════════════════════════
|
||||||
|
BLOG DETAIL PAGE
|
||||||
|
Route: /v2/blog/<slug>
|
||||||
|
══════════════════════════════════════════════════════ -->
|
||||||
|
<template id="v2_blog_detail" name="V2 Blog Detail">
|
||||||
|
<t t-call="website.layout">
|
||||||
|
<t t-set="head">
|
||||||
|
<title t-out="page_title"/>
|
||||||
|
<meta t-att-name="'description'" t-att-content="post['excerpt']"/>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<div id="wrap" class="oe_structure" style="background-color: var(--v2-cream); font-family: var(--v2-font-body);">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* ── Blog Detail Page ── */
|
||||||
|
.v2-detail-banner {
|
||||||
|
position: relative;
|
||||||
|
height: 460px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.v2-detail-banner::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(to top, rgba(30,18,8,0.85) 0%, rgba(30,18,8,0.25) 60%, transparent 100%);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.v2-detail-banner img {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.v2-detail-banner-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
max-width: 1320px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 24px 48px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.v2-detail-category-badge {
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--v2-gold);
|
||||||
|
color: var(--v2-white);
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
padding: 5px 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.v2-detail-banner-title {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: clamp(2rem, 4vw, 3.5rem);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--v2-white);
|
||||||
|
line-height: 1.15;
|
||||||
|
max-width: 800px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.v2-detail-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: rgba(255,255,255,0.8);
|
||||||
|
}
|
||||||
|
.v2-detail-meta span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
/* Article Layout */
|
||||||
|
.v2-detail-layout {
|
||||||
|
max-width: 1320px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 64px 24px;
|
||||||
|
display: grid;
|
||||||
|
gap: 60px;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.v2-detail-layout {
|
||||||
|
grid-template-columns: 1fr 340px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Article Body */
|
||||||
|
.v2-article-body {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--v2-text);
|
||||||
|
line-height: 1.85;
|
||||||
|
}
|
||||||
|
.v2-article-body h3 {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--v2-text);
|
||||||
|
margin: 40px 0 16px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.v2-article-body p {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.v2-article-body strong {
|
||||||
|
color: var(--v2-text);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.v2-article-body a {
|
||||||
|
color: var(--v2-gold);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.v2-article-body a:hover {
|
||||||
|
color: var(--v2-gold-dark);
|
||||||
|
}
|
||||||
|
.v2-article-body em {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
/* Author Card */
|
||||||
|
.v2-author-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
background: var(--v2-white);
|
||||||
|
border: 1px solid var(--v2-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
margin-top: 48px;
|
||||||
|
}
|
||||||
|
.v2-author-avatar {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--v2-gold);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: 1.6rem;
|
||||||
|
color: var(--v2-white);
|
||||||
|
font-weight: 600;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.v2-author-info h4 {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: var(--v2-text);
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 4px;
|
||||||
|
}
|
||||||
|
.v2-author-info p {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--v2-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
/* Tags */
|
||||||
|
.v2-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
.v2-tag {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--v2-gold);
|
||||||
|
border: 1px solid var(--v2-gold);
|
||||||
|
padding: 4px 14px;
|
||||||
|
border-radius: 100px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
/* Sidebar */
|
||||||
|
.v2-sidebar {}
|
||||||
|
.v2-sidebar-card {
|
||||||
|
background: var(--v2-white);
|
||||||
|
border: 1px solid var(--v2-border);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 32px 28px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
.v2-sidebar-title {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--v2-text);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid var(--v2-border);
|
||||||
|
}
|
||||||
|
.v2-recent-post {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 14px 0;
|
||||||
|
border-bottom: 1px solid var(--v2-border);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.v2-recent-post:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
.v2-recent-post-img {
|
||||||
|
width: 72px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 8px;
|
||||||
|
object-fit: cover;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.v2-recent-post-info h5 {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--v2-text);
|
||||||
|
line-height: 1.35;
|
||||||
|
margin: 0 0 4px;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
.v2-recent-post:hover .v2-recent-post-info h5 {
|
||||||
|
color: var(--v2-gold);
|
||||||
|
}
|
||||||
|
.v2-recent-post-info span {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--v2-muted);
|
||||||
|
}
|
||||||
|
.v2-cta-sidebar {
|
||||||
|
background: linear-gradient(135deg, var(--v2-dark) 0%, var(--v2-dark2) 100%);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 36px 28px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.v2-cta-sidebar h3 {
|
||||||
|
font-family: var(--v2-font-display);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--v2-white);
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
.v2-cta-sidebar p {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: rgba(255,255,255,0.7);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.v2-detail-layout {
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
.v2-detail-banner {
|
||||||
|
height: 320px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Hero Banner -->
|
||||||
|
<div class="v2-detail-banner">
|
||||||
|
<img t-att-src="post['image']" t-att-alt="post['title']"/>
|
||||||
|
<div class="v2-detail-banner-content">
|
||||||
|
<span class="v2-detail-category-badge" t-out="post['category']"/>
|
||||||
|
<h1 class="v2-detail-banner-title" t-out="post['title']"/>
|
||||||
|
<div class="v2-detail-meta">
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/></svg>
|
||||||
|
<t t-out="post['date']"/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
||||||
|
<t t-out="post['read_time']"/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
||||||
|
<t t-out="post['author']"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Article Layout -->
|
||||||
|
<div class="v2-detail-layout">
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div>
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<div style="font-size:0.78rem; color: var(--v2-muted); margin-bottom:32px; text-transform:uppercase; letter-spacing:0.06em;">
|
||||||
|
<a href="/" style="color: var(--v2-muted); text-decoration:none;">Home</a>
|
||||||
|
<span style="margin:0 8px;">·</span>
|
||||||
|
<a href="/blog" style="color: var(--v2-muted); text-decoration:none;">Blog</a>
|
||||||
|
<span style="margin:0 8px;">·</span>
|
||||||
|
<span style="color: var(--v2-gold);" t-out="post['category']"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Article Body -->
|
||||||
|
<div class="v2-article-body">
|
||||||
|
<t t-out="post['content']"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tags -->
|
||||||
|
<div class="v2-tags">
|
||||||
|
<t t-foreach="post.get('tags', [])" t-as="tag">
|
||||||
|
<span class="v2-tag" t-out="tag"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Author Card -->
|
||||||
|
<div class="v2-author-card">
|
||||||
|
<div class="v2-author-avatar">
|
||||||
|
<t t-out="post['author'][0]"/>
|
||||||
|
</div>
|
||||||
|
<div class="v2-author-info">
|
||||||
|
<h4 t-out="post['author']"/>
|
||||||
|
<p t-out="post['author_title']"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Back Link -->
|
||||||
|
<div style="margin-top:48px;">
|
||||||
|
<a href="/blog" style="display:inline-flex; align-items:center; gap:8px; font-size:0.82rem; font-weight:700; color: var(--v2-gold); text-transform:uppercase; letter-spacing:0.08em; text-decoration:none;">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5"/><path d="m12 19-7-7 7-7"/></svg>
|
||||||
|
Back to All Articles
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside class="v2-sidebar">
|
||||||
|
<!-- Recent Posts -->
|
||||||
|
<div class="v2-sidebar-card">
|
||||||
|
<div class="v2-sidebar-title">More Articles</div>
|
||||||
|
<t t-foreach="recent_posts" t-as="rp">
|
||||||
|
<a t-attf-href="/blog/#{rp['slug']}" class="v2-recent-post">
|
||||||
|
<img t-att-src="rp['image']" t-att-alt="rp['title']" class="v2-recent-post-img"/>
|
||||||
|
<div class="v2-recent-post-info">
|
||||||
|
<h5 t-out="rp['title']"/>
|
||||||
|
<span t-out="rp['date']"/>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA Card -->
|
||||||
|
<div class="v2-cta-sidebar">
|
||||||
|
<h3>Ready to Create Your Dream Event?</h3>
|
||||||
|
<p>Let's talk about your vision. We'd love to bring it to life.</p>
|
||||||
|
<a href="/contactus" style="display:inline-flex; align-items:center; gap:8px; background: var(--v2-gold); color: var(--v2-white); padding:12px 24px; border-radius:4px; font-size:0.8rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; text-decoration:none; transition:background 0.3s;">
|
||||||
|
Book a Consultation
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
105
addons/theme_aakriti_v2/views/portfolio_templates.xml
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<!-- Page Record -->
|
||||||
|
<record id="portfolio_page" model="website.page">
|
||||||
|
<field name="name">Portfolio</field>
|
||||||
|
<field name="type">qweb</field>
|
||||||
|
<field name="url">/portfolio</field>
|
||||||
|
<field name="website_published">True</field>
|
||||||
|
<field name="key">theme_aakriti_v2.portfolio_page_template</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<t name="Portfolio" t-name="theme_aakriti_v2.portfolio_page_template">
|
||||||
|
<t t-call="website.layout">
|
||||||
|
<div id="wrap" class="oe_structure oe_empty" style="background-color: var(--v2-cream); font-family: 'Jost', sans-serif;">
|
||||||
|
<!-- Inner Banner -->
|
||||||
|
<section class="v2-inner-banner" style="background-image: url('/theme_aakriti_v2/static/src/img/inner-banner/1.webp');">
|
||||||
|
<div class="v2-inner-banner-content">
|
||||||
|
<h1 class="v2-inner-banner-title" style="font-family: var(--v2-font-display);">Portfolio</h1>
|
||||||
|
<div class="v2-inner-banner-breadcrumb">
|
||||||
|
<a href="/">Home</a> / <span class="v2-active">Portfolio</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Portfolio Section -->
|
||||||
|
<section class="v2-portfolio-section">
|
||||||
|
|
||||||
|
<div class="v2-portfolio-tabs">
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab active" data-filter="all">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/all.png"
|
||||||
|
alt="All Events"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
ALL
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="weddings">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/wedding.png"
|
||||||
|
alt="Weddings"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
WEDDINGS
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="pre-wedding">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/pre-wedding.png"
|
||||||
|
alt="Pre Wedding"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
PRE-WEDDING
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="engagements">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/engagements.png"
|
||||||
|
alt="Engagements"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
ENGAGEMENTS
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="celebrations">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/celebrations.png"
|
||||||
|
alt="Celebrations"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
CELEBRATIONS
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="corporate">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/corporate.png"
|
||||||
|
alt="Corporate"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
CORPORATE
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="cultural">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/cultural.png"
|
||||||
|
alt="Cultural"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
CULTURAL
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="v2-portfolio-tab" data-filter="festivals">
|
||||||
|
<img src="/theme_aakriti_v2/static/src/img/portfolio/festivals.png"
|
||||||
|
alt="Festivals"
|
||||||
|
width="40"
|
||||||
|
height="40"/>
|
||||||
|
FESTIVALS
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="v2-masonry-grid" id="v2-portfolio-grid">
|
||||||
|
<!-- Portfolio items injected by theme_v2.js -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||