Merge remote master before deployment
This commit is contained in:
68
docs/DEVPI_RELEASE_FLOW.md
Normal file
68
docs/DEVPI_RELEASE_FLOW.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
## Devpi Release Flow
|
||||||
|
|
||||||
|
### Current state
|
||||||
|
|
||||||
|
- `mandel/testing` is the active package source for MandelBlog project builds.
|
||||||
|
- `ocyan.plugin.template_engine==0.2.12` is published there and is the current production-safe version.
|
||||||
|
- `mandel/stable` is not available yet.
|
||||||
|
|
||||||
|
This means production is intentionally running from the testing index for now, to avoid breaking installs while the stable index is not provisioned.
|
||||||
|
|
||||||
|
### Index roles
|
||||||
|
|
||||||
|
- `mandel/testing`
|
||||||
|
- pre-production and current fallback source
|
||||||
|
- currently also the active production source until stable exists
|
||||||
|
- `mandel/stable`
|
||||||
|
- intended production index
|
||||||
|
- not yet provisioned
|
||||||
|
|
||||||
|
### Promotion flow
|
||||||
|
|
||||||
|
When `mandel/stable` exists, promote existing artifacts without rebuilding:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
devpi use https://pypi.mandelblog.com/mandel/testing
|
||||||
|
devpi login mandel
|
||||||
|
devpi push ocyan-plugin-template-engine==0.2.12 mandel/stable
|
||||||
|
```
|
||||||
|
|
||||||
|
### Admin prerequisite
|
||||||
|
|
||||||
|
Promotion requires a devpi admin to create the production index and grant upload or push permissions.
|
||||||
|
|
||||||
|
Recommended admin setup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
devpi index -c mandel/stable bases=root/pypi volatile=False acl_upload=mandel,Mandel-publish
|
||||||
|
```
|
||||||
|
|
||||||
|
### Planned stable-first install order
|
||||||
|
|
||||||
|
Do not enable this until `mandel/stable` exists:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PIP_INDEX_URL=https://pypi.mandelblog.com/mandel/stable/+simple/
|
||||||
|
PIP_EXTRA_INDEX_URL=https://pypi.mandelblog.com/mandel/testing/+simple/
|
||||||
|
```
|
||||||
|
|
||||||
|
### CI behavior
|
||||||
|
|
||||||
|
- If the stable index is missing, Jenkins logs:
|
||||||
|
- `devpi stable index not available, using testing as production source`
|
||||||
|
- The build does not fail because of the missing stable index.
|
||||||
|
- Installs continue from `mandel/testing`.
|
||||||
|
|
||||||
|
### Validation checklist
|
||||||
|
|
||||||
|
After stable becomes available and promotion is done:
|
||||||
|
|
||||||
|
1. confirm both wheel and sdist are visible in the stable simple index
|
||||||
|
2. switch MandelStudio to stable-first
|
||||||
|
3. run Jenkins build and deploy
|
||||||
|
4. verify installed version is still `0.2.12`
|
||||||
|
5. recheck editor validation for:
|
||||||
|
- `/contact/`
|
||||||
|
- `/diensten/`
|
||||||
|
- `#demo`
|
||||||
|
- absolute URLs
|
||||||
@@ -31,7 +31,8 @@
|
|||||||
"ocyan.plugin.wagtail_content_page",
|
"ocyan.plugin.wagtail_content_page",
|
||||||
"ocyan.plugin.wagtail_forms",
|
"ocyan.plugin.wagtail_forms",
|
||||||
"ocyan.plugin.wagtail_oscar_integration",
|
"ocyan.plugin.wagtail_oscar_integration",
|
||||||
"ocyan.plugin.roadrunner_highlight_slider"
|
"ocyan.plugin.roadrunner_highlight_slider",
|
||||||
|
"ocyan.plugin.wordspinner"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"cookie_jar": {
|
"cookie_jar": {
|
||||||
|
|||||||
40
mandelstudio/templates/carbasa/headers/header.html
Normal file
40
mandelstudio/templates/carbasa/headers/header.html
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load agency_navigation %}
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light header-inner">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" title="{% trans 'Website logo en home pagina navigatie' %}" href="/">
|
||||||
|
{% include "partials/brand.html" with big=True %}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#carbasaHeaderNav" aria-controls="carbasaHeaderNav" aria-expanded="false" aria-label="{% trans 'Toggle navigation' %}">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{% block nav %}
|
||||||
|
<div class="collapse navbar-collapse menu-bar page-menu-bar" id="carbasaHeaderNav">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item dropdown agency-nav-dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="/diensten/" id="carbasaHeaderDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{% trans "Our Collection" %}
|
||||||
|
</a>
|
||||||
|
{% agency_nav_pages as nav_pages %}
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="carbasaHeaderDropdown">
|
||||||
|
{% for nav_page in nav_pages %}
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{{ nav_page.url }}">{{ nav_page.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block user_bar %}
|
||||||
|
{% include "oxyan/headers/partials/carbasa-user-bar.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
45
mandelstudio/templates/engine/blocks/core/richtext.html
Normal file
45
mandelstudio/templates/engine/blocks/core/richtext.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<section class="container py-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-lg-10 col-xl-9">
|
||||||
|
<div class="te-richtext card border-0 shadow-sm rounded-4">
|
||||||
|
<div class="card-body p-4 p-md-5">
|
||||||
|
{{ value.content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.te-modern-saas .te-richtext {
|
||||||
|
color: var(--te-color-text-base);
|
||||||
|
background: color-mix(in srgb, var(--te-color-surface-soft) 18%, white 82%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.te-modern-saas .te-richtext .card-body > * + * {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.te-modern-saas .te-richtext h2,
|
||||||
|
.te-modern-saas .te-richtext h3,
|
||||||
|
.te-modern-saas .te-richtext h4 {
|
||||||
|
color: var(--te-color-surface-strong);
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.te-modern-saas .te-richtext p,
|
||||||
|
.te-modern-saas .te-richtext li {
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.te-modern-saas .te-richtext ul,
|
||||||
|
.te-modern-saas .te-richtext ol {
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.te-modern-saas .te-richtext a {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -15,13 +15,26 @@
|
|||||||
{% include "engine/partials/tech_theme_overrides.html" %}
|
{% include "engine/partials/tech_theme_overrides.html" %}
|
||||||
{% include "engine/partials/travel_theme_overrides.html" %}
|
{% include "engine/partials/travel_theme_overrides.html" %}
|
||||||
{% include "engine/partials/saas_theme_overrides.html" %}
|
{% include "engine/partials/saas_theme_overrides.html" %}
|
||||||
|
<style>
|
||||||
|
:root { --mb-site-header-height: 88px; }
|
||||||
|
header.mega_header {
|
||||||
|
z-index: 1200;
|
||||||
|
}
|
||||||
|
.te-modern-saas .te-block--saas-testimonials .saas-testimonials__header {
|
||||||
|
top: calc(var(--mb-site-header-height) + 8px);
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
:root { --mb-site-header-height: 72px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block layout %}
|
{% block layout %}
|
||||||
<a class="btn btn-secondary hidelink" id="main_content_link" href="#skip_header" tabindex="2">
|
<a class="btn btn-secondary hidelink" id="main_content_link" href="#skip_header" tabindex="2">
|
||||||
{% skip_to_content_text %}
|
{% skip_to_content_text %}
|
||||||
</a>
|
</a>
|
||||||
{% include_header header_template|default:"engine/partials/header.html" %}
|
{% include "carbasa/headers/header.html" %}
|
||||||
<div id="main_content" tabindex="-1">
|
<div id="main_content" tabindex="-1">
|
||||||
<div class="te-modern-saas">
|
<div class="te-modern-saas">
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -15,13 +15,26 @@
|
|||||||
{% include "engine/partials/tech_theme_overrides.html" %}
|
{% include "engine/partials/tech_theme_overrides.html" %}
|
||||||
{% include "engine/partials/travel_theme_overrides.html" %}
|
{% include "engine/partials/travel_theme_overrides.html" %}
|
||||||
{% include "engine/partials/saas_theme_overrides.html" %}
|
{% include "engine/partials/saas_theme_overrides.html" %}
|
||||||
|
<style>
|
||||||
|
:root { --mb-site-header-height: 88px; }
|
||||||
|
header.mega_header {
|
||||||
|
z-index: 1200;
|
||||||
|
}
|
||||||
|
.te-modern-saas .te-block--saas-testimonials .saas-testimonials__header {
|
||||||
|
top: calc(var(--mb-site-header-height) + 8px);
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
:root { --mb-site-header-height: 72px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block layout %}
|
{% block layout %}
|
||||||
<a class="btn btn-secondary hidelink" id="main_content_link" href="#skip_header" tabindex="2">
|
<a class="btn btn-secondary hidelink" id="main_content_link" href="#skip_header" tabindex="2">
|
||||||
{% skip_to_content_text %}
|
{% skip_to_content_text %}
|
||||||
</a>
|
</a>
|
||||||
{% include_header header_template|default:"engine/partials/header.html" %}
|
{% include "carbasa/headers/header.html" %}
|
||||||
<div id="main_content" tabindex="-1">
|
<div id="main_content" tabindex="-1">
|
||||||
<div class="te-modern-saas">
|
<div class="te-modern-saas">
|
||||||
<main class="te-section">
|
<main class="te-section">
|
||||||
|
|||||||
@@ -15,13 +15,26 @@
|
|||||||
{% include "engine/partials/tech_theme_overrides.html" %}
|
{% include "engine/partials/tech_theme_overrides.html" %}
|
||||||
{% include "engine/partials/travel_theme_overrides.html" %}
|
{% include "engine/partials/travel_theme_overrides.html" %}
|
||||||
{% include "engine/partials/saas_theme_overrides.html" %}
|
{% include "engine/partials/saas_theme_overrides.html" %}
|
||||||
|
<style>
|
||||||
|
:root { --mb-site-header-height: 88px; }
|
||||||
|
header.mega_header {
|
||||||
|
z-index: 1200;
|
||||||
|
}
|
||||||
|
.te-modern-saas .te-block--saas-testimonials .saas-testimonials__header {
|
||||||
|
top: calc(var(--mb-site-header-height) + 8px);
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
:root { --mb-site-header-height: 72px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block layout %}
|
{% block layout %}
|
||||||
<a class="btn btn-secondary hidelink" id="main_content_link" href="#skip_header" tabindex="2">
|
<a class="btn btn-secondary hidelink" id="main_content_link" href="#skip_header" tabindex="2">
|
||||||
{% skip_to_content_text %}
|
{% skip_to_content_text %}
|
||||||
</a>
|
</a>
|
||||||
{% include_header header_template|default:"engine/partials/header.html" %}
|
{% include "carbasa/headers/header.html" %}
|
||||||
<div id="main_content" tabindex="-1">
|
<div id="main_content" tabindex="-1">
|
||||||
<div class="te-modern-saas">
|
<div class="te-modern-saas">
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
{% load wagtailimages_tags %}
|
||||||
|
<section class="saas-demo saas-demo--inline saas-demo--{{ self.background_style }}"
|
||||||
|
data-width="{{ self.layout_width }}">
|
||||||
|
<div class="saas-demo__container">
|
||||||
|
<header class="saas-demo__header">
|
||||||
|
<h2 class="saas-demo__title">{{ self.section_title }}</h2>
|
||||||
|
{% if self.section_subtitle %}
|
||||||
|
<div class="saas-demo__subtitle">{{ self.section_subtitle }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form class="saas-demo__form" action="{% url "contact_form:contact-form-handler" %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="saas-demo__fields">
|
||||||
|
{% for field in self.form_fields %}
|
||||||
|
<div class="saas-demo__field">
|
||||||
|
<label class="saas-demo__label" for="demo-{{ field.field_type }}">
|
||||||
|
{{ field.label }}
|
||||||
|
{% if field.required %}<span class="saas-demo__required">*</span>{% endif %}
|
||||||
|
</label>
|
||||||
|
{% if field.field_type == 'message' %}
|
||||||
|
<textarea class="saas-demo__textarea"
|
||||||
|
id="demo-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
placeholder="{{ field.placeholder }}"
|
||||||
|
{% if field.required %}required{% endif %}></textarea>
|
||||||
|
{% elif field.field_type == 'company_size' %}
|
||||||
|
<select class="saas-demo__select"
|
||||||
|
id="demo-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
{% if field.required %}required{% endif %}>
|
||||||
|
<option value="">{{ field.placeholder|default:"Select company size" }}</option>
|
||||||
|
<option value="1-10">1-10 employees</option>
|
||||||
|
<option value="11-50">11-50 employees</option>
|
||||||
|
<option value="51-200">51-200 employees</option>
|
||||||
|
<option value="201-500">201-500 employees</option>
|
||||||
|
<option value="500+">500+ employees</option>
|
||||||
|
</select>
|
||||||
|
{% else %}
|
||||||
|
<input class="saas-demo__input"
|
||||||
|
type="{% if field.field_type == 'email' %}email{% elif field.field_type == 'phone' %}tel{% else %}text{% endif %}"
|
||||||
|
id="demo-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
placeholder="{{ field.placeholder }}"
|
||||||
|
{% if field.required %}required{% endif %}>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="saas-demo__submit">{{ self.submit_button_text }}</button>
|
||||||
|
|
||||||
|
{% if self.privacy_text %}
|
||||||
|
<div class="saas-demo__privacy">{{ self.privacy_text }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
{% load wagtailimages_tags %}
|
||||||
|
<section class="saas-demo saas-demo--modal-trigger saas-demo--{{ self.background_style }}"
|
||||||
|
data-width="{{ self.layout_width }}"
|
||||||
|
data-demo-modal-root>
|
||||||
|
<div class="saas-demo__container">
|
||||||
|
<div class="saas-demo__content">
|
||||||
|
<h2 class="saas-demo__title">{{ self.section_title }}</h2>
|
||||||
|
{% if self.section_subtitle %}
|
||||||
|
<div class="saas-demo__subtitle">{{ self.section_subtitle }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<button type="button" class="saas-demo__trigger" data-demo-modal-open>
|
||||||
|
{{ self.submit_button_text }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="saas-demo__modal" data-demo-modal hidden>
|
||||||
|
<div class="saas-demo__modal-backdrop" data-demo-modal-close></div>
|
||||||
|
<div class="saas-demo__modal-content">
|
||||||
|
<button type="button" class="saas-demo__modal-close" data-demo-modal-close aria-label="Close">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h3 class="saas-demo__modal-title">{{ self.section_title }}</h3>
|
||||||
|
|
||||||
|
<form class="saas-demo__form" action="{% url "contact_form:contact-form-handler" %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="saas-demo__fields">
|
||||||
|
{% for field in self.form_fields %}
|
||||||
|
<div class="saas-demo__field">
|
||||||
|
<label class="saas-demo__label" for="modal-{{ field.field_type }}">
|
||||||
|
{{ field.label }}
|
||||||
|
{% if field.required %}<span class="saas-demo__required">*</span>{% endif %}
|
||||||
|
</label>
|
||||||
|
{% if field.field_type == 'message' %}
|
||||||
|
<textarea class="saas-demo__textarea"
|
||||||
|
id="modal-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
placeholder="{{ field.placeholder }}"
|
||||||
|
{% if field.required %}required{% endif %}></textarea>
|
||||||
|
{% else %}
|
||||||
|
<input class="saas-demo__input"
|
||||||
|
type="{% if field.field_type == 'email' %}email{% elif field.field_type == 'phone' %}tel{% else %}text{% endif %}"
|
||||||
|
id="modal-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
placeholder="{{ field.placeholder }}"
|
||||||
|
{% if field.required %}required{% endif %}>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="saas-demo__submit">{{ self.submit_button_text }}</button>
|
||||||
|
|
||||||
|
{% if self.privacy_text %}
|
||||||
|
<div class="saas-demo__privacy">{{ self.privacy_text }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const roots = document.querySelectorAll('[data-demo-modal-root]');
|
||||||
|
roots.forEach((root) => {
|
||||||
|
if (root.dataset.modalBound === "1") return;
|
||||||
|
root.dataset.modalBound = "1";
|
||||||
|
|
||||||
|
const modal = root.querySelector('[data-demo-modal]');
|
||||||
|
const openBtn = root.querySelector('[data-demo-modal-open]');
|
||||||
|
const closeBtns = root.querySelectorAll('[data-demo-modal-close]');
|
||||||
|
if (!modal || !openBtn) return;
|
||||||
|
|
||||||
|
const openModal = () => {
|
||||||
|
modal.hidden = false;
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
modal.hidden = true;
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
openBtn.addEventListener('click', openModal);
|
||||||
|
closeBtns.forEach((btn) => btn.addEventListener('click', closeModal));
|
||||||
|
|
||||||
|
root.addEventListener('keydown', (event) => {
|
||||||
|
if (event.key === 'Escape' && !modal.hidden) closeModal();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
{% load wagtailimages_tags %}
|
||||||
|
<section class="saas-demo saas-demo--split saas-demo--{{ self.background_style }} mandelstudio-demo-split"
|
||||||
|
data-width="{{ self.layout_width }}">
|
||||||
|
<style>
|
||||||
|
.mandelstudio-demo-split {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 18px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(180deg, #f8fbff 0%, #f3f7fc 100%);
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: clamp(1.25rem, 2.2vw, 2.25rem);
|
||||||
|
gap: clamp(1rem, 2vw, 2rem);
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__title {
|
||||||
|
font-size: clamp(1.9rem, 3vw, 3rem);
|
||||||
|
line-height: 1.1;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
margin-bottom: .8rem;
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__subtitle {
|
||||||
|
color: #556070;
|
||||||
|
max-width: 54ch;
|
||||||
|
margin-bottom: .9rem;
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__benefits-list {
|
||||||
|
margin-bottom: 1.15rem;
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__benefit {
|
||||||
|
color: #212b3a;
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__visual {
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__image {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid rgba(39, 66, 107, .14);
|
||||||
|
box-shadow: 0 12px 28px rgba(20, 35, 68, .12);
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__form-wrapper {
|
||||||
|
border: 1px solid rgba(42, 72, 120, .15);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 14px 30px rgba(18, 38, 76, .09);
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__form {
|
||||||
|
padding: clamp(1rem, 2vw, 1.5rem);
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__input,
|
||||||
|
.mandelstudio-demo-split .saas-demo__select,
|
||||||
|
.mandelstudio-demo-split .saas-demo__textarea {
|
||||||
|
background: #fbfdff;
|
||||||
|
border-color: #d8e1ec;
|
||||||
|
transition: border-color .2s ease, box-shadow .2s ease;
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__input:focus,
|
||||||
|
.mandelstudio-demo-split .saas-demo__select:focus,
|
||||||
|
.mandelstudio-demo-split .saas-demo__textarea:focus {
|
||||||
|
border-color: #377dff;
|
||||||
|
box-shadow: 0 0 0 .2rem rgba(55, 125, 255, .15);
|
||||||
|
}
|
||||||
|
.mandelstudio-demo-split .saas-demo__submit {
|
||||||
|
box-shadow: 0 8px 18px rgba(40, 95, 214, .3);
|
||||||
|
}
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.mandelstudio-demo-split .saas-demo__visual {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="saas-demo__container">
|
||||||
|
<div class="saas-demo__content">
|
||||||
|
<h2 class="saas-demo__title">{{ self.section_title }}</h2>
|
||||||
|
{% if self.section_subtitle %}
|
||||||
|
<div class="saas-demo__subtitle">{{ self.section_subtitle }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if self.benefits_title or self.benefits %}
|
||||||
|
<div class="saas-demo__benefits">
|
||||||
|
{% if self.benefits_title %}
|
||||||
|
<h3 class="saas-demo__benefits-title">{{ self.benefits_title }}</h3>
|
||||||
|
{% endif %}
|
||||||
|
{% if self.benefits %}
|
||||||
|
<ul class="saas-demo__benefits-list">
|
||||||
|
{% for benefit in self.benefits %}
|
||||||
|
<li class="saas-demo__benefit">
|
||||||
|
<svg class="saas-demo__check" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M4 10L8 14L16 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
{{ benefit }}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if self.side_image %}
|
||||||
|
<div class="saas-demo__visual">
|
||||||
|
{% image self.side_image width-640 class="saas-demo__image" %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="saas-demo__form-wrapper">
|
||||||
|
<form class="saas-demo__form" action="{% url "contact_form:contact-form-handler" %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="saas-demo__fields">
|
||||||
|
{% for field in self.form_fields %}
|
||||||
|
<div class="saas-demo__field">
|
||||||
|
<label class="saas-demo__label" for="split-{{ field.field_type }}">
|
||||||
|
{{ field.label }}
|
||||||
|
{% if field.required %}<span class="saas-demo__required">*</span>{% endif %}
|
||||||
|
</label>
|
||||||
|
{% if field.field_type == 'message' %}
|
||||||
|
<textarea class="saas-demo__textarea"
|
||||||
|
id="split-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
placeholder="{{ field.placeholder }}"
|
||||||
|
{% if field.required %}required{% endif %}></textarea>
|
||||||
|
{% elif field.field_type == 'company_size' %}
|
||||||
|
<select class="saas-demo__select"
|
||||||
|
id="split-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
{% if field.required %}required{% endif %}>
|
||||||
|
<option value="">{{ field.placeholder|default:"Select company size" }}</option>
|
||||||
|
<option value="1-10">1-10 employees</option>
|
||||||
|
<option value="11-50">11-50 employees</option>
|
||||||
|
<option value="51-200">51-200 employees</option>
|
||||||
|
<option value="201-500">201-500 employees</option>
|
||||||
|
<option value="500+">500+ employees</option>
|
||||||
|
</select>
|
||||||
|
{% else %}
|
||||||
|
<input class="saas-demo__input"
|
||||||
|
type="{% if field.field_type == 'email' %}email{% elif field.field_type == 'phone' %}tel{% else %}text{% endif %}"
|
||||||
|
id="split-{{ field.field_type }}"
|
||||||
|
name="{% if field.field_type == "email" %}email_from{% elif field.field_type == "phone" %}phonenumber{% elif field.field_type == "text" %}name{% else %}{{ field.field_type }}{% endif %}"
|
||||||
|
placeholder="{{ field.placeholder }}"
|
||||||
|
{% if field.required %}required{% endif %}>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="saas-demo__submit">{{ self.submit_button_text }}</button>
|
||||||
|
|
||||||
|
{% if self.privacy_text %}
|
||||||
|
<div class="saas-demo__privacy">{{ self.privacy_text }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{% load wagtailimages_tags %}
|
||||||
|
<section class="saas-features saas-features--grid saas-features--{{ self.background_style }}"
|
||||||
|
data-width="{{ self.layout_width }}">
|
||||||
|
<div class="saas-features__container">
|
||||||
|
<header class="saas-features__header">
|
||||||
|
<h2 class="saas-features__title">{{ self.section_title }}</h2>
|
||||||
|
{% if self.section_subtitle %}
|
||||||
|
<div class="saas-features__subtitle">{{ self.section_subtitle }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
<div class="saas-features__grid saas-features__grid--cols-{{ self.columns }}">
|
||||||
|
{% for feature in self.features %}
|
||||||
|
<article class="saas-features__card{% if feature.highlight == 'featured' %} saas-features__card--featured{% endif %}">
|
||||||
|
{% if feature.highlight == 'new' %}
|
||||||
|
<span class="saas-features__badge">{% if request.LANGUAGE_CODE == 'ru' %}Ново{% elif request.LANGUAGE_CODE == 'de' %}Neu{% elif request.LANGUAGE_CODE == 'fr' %}Nouveau{% elif request.LANGUAGE_CODE == 'es' %}Nuevo{% elif request.LANGUAGE_CODE == 'it' %}Nuovo{% elif request.LANGUAGE_CODE == 'pt' %}Novo{% else %}New{% endif %}</span>
|
||||||
|
{% endif %}
|
||||||
|
<div class="saas-features__icon-wrapper">
|
||||||
|
{% if feature.icon_image %}
|
||||||
|
{% image feature.icon_image width-64 class="saas-features__icon-img" %}
|
||||||
|
{% elif feature.icon %}
|
||||||
|
<i class="saas-features__icon bi bi-{{ feature.icon }}"></i>
|
||||||
|
{% else %}
|
||||||
|
<div class="saas-features__icon-placeholder"></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<h3 class="saas-features__card-title">{{ feature.title }}</h3>
|
||||||
|
{% if feature.description %}<div class="saas-features__card-desc">{{ feature.description }}</div>{% endif %}
|
||||||
|
{% if feature.link_text and feature.link_url %}
|
||||||
|
<a href="{{ feature.link_url }}" class="saas-features__card-link">
|
||||||
|
{{ feature.link_text }}
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8H13M13 8L9 4M13 8L9 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{% load wagtailimages_tags %}
|
||||||
|
<section class="saas-integrations saas-integrations--logo-grid saas-integrations--{{ self.background_style }}" data-width="{{ self.layout_width }}">
|
||||||
|
<div class="saas-integrations__container">
|
||||||
|
<header class="saas-integrations__header">
|
||||||
|
<h2 class="saas-integrations__title">{{ self.section_title }}</h2>
|
||||||
|
{% if self.section_subtitle %}<div class="saas-integrations__subtitle">{{ self.section_subtitle }}</div>{% endif %}
|
||||||
|
{% if self.integration_count %}
|
||||||
|
<span class="saas-integrations__count">{{ self.integration_count }} {% if request.LANGUAGE_CODE == 'ru' %}интеграции{% elif request.LANGUAGE_CODE == 'de' %}Integrationen{% elif request.LANGUAGE_CODE == 'fr' %}intégrations{% elif request.LANGUAGE_CODE == 'es' %}integraciones{% elif request.LANGUAGE_CODE == 'it' %}integrazioni{% elif request.LANGUAGE_CODE == 'pt' %}integrações{% elif request.LANGUAGE_CODE == 'nl' %}integraties{% else %}integrations{% endif %}</span>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
<div class="saas-integrations__grid">
|
||||||
|
{% for integration in self.integrations %}
|
||||||
|
<div class="saas-integrations__item{% if integration.is_featured != 'none' %} saas-integrations__item--{{ integration.is_featured }}{% endif %}">
|
||||||
|
{% if integration.is_featured == 'new' %}
|
||||||
|
<span class="saas-integrations__badge">{% if request.LANGUAGE_CODE == 'ru' %}Ново{% elif request.LANGUAGE_CODE == 'de' %}Neu{% elif request.LANGUAGE_CODE == 'fr' %}Nouveau{% elif request.LANGUAGE_CODE == 'es' %}Nuevo{% elif request.LANGUAGE_CODE == 'it' %}Nuovo{% elif request.LANGUAGE_CODE == 'pt' %}Novo{% elif request.LANGUAGE_CODE == 'nl' %}Nieuw{% else %}New{% endif %}</span>
|
||||||
|
{% elif integration.is_featured == 'popular' %}
|
||||||
|
<span class="saas-integrations__badge saas-integrations__badge--popular">{% if request.LANGUAGE_CODE == 'ru' %}Populair{% elif request.LANGUAGE_CODE == 'de' %}Beliebt{% elif request.LANGUAGE_CODE == 'fr' %}Populaire{% elif request.LANGUAGE_CODE == 'es' %}Popular{% elif request.LANGUAGE_CODE == 'it' %}Popolare{% elif request.LANGUAGE_CODE == 'pt' %}Popular{% elif request.LANGUAGE_CODE == 'nl' %}Populair{% else %}Popular{% endif %}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if integration.url %}<a href="{{ integration.url }}" class="saas-integrations__link">{% endif %}
|
||||||
|
<div class="saas-integrations__logo">{% image integration.logo width-48 class="saas-integrations__logo-img" %}</div>
|
||||||
|
<span class="saas-integrations__name">{{ integration.name }}</span>
|
||||||
|
{% if integration.url %}</a>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% if self.cta_text and self.cta_url %}
|
||||||
|
<div class="saas-integrations__footer"><a href="{{ self.cta_url }}" class="saas-integrations__cta">{{ self.cta_text }}<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8H13M13 8L9 4M13 8L9 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></a></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
92
mandelstudio/templates/layout.html
Normal file
92
mandelstudio/templates/layout.html
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% load compress %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load oxyan %}
|
||||||
|
{% load ocyan_main %}
|
||||||
|
{% load ocyanjson %}
|
||||||
|
{% load static %}
|
||||||
|
{% load wagtailcore_tags wagtailimages_tags wagtailuserbar %}
|
||||||
|
|
||||||
|
{% block title %}{% firstof page.seo_title self.seo_title page.title self.title shop_name %}{% endblock %}
|
||||||
|
{% block description %}{% firstof page.search_description self.search_description "" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block extrahead %}
|
||||||
|
{% if cookie_jar.settings.google_tag_manager and cookie_jar.functional.is_allowed %}
|
||||||
|
<link rel="preconnect" href="https://www.googletagmanager.com"/>
|
||||||
|
{% endif %}
|
||||||
|
{% if cookie_jar.settings.google_analytics and cookie_jar.functional.is_allowed %}
|
||||||
|
<link rel="preconnect" href="https://www.google-analytics.com/">
|
||||||
|
{% endif %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% if cookie_jar.needs_approval %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'cookie_jar/css/cookie_jar.css' %}">
|
||||||
|
{% endif %}
|
||||||
|
{% for header_snippet in cookie_jar.activated_snippet_header_templates %}
|
||||||
|
{% include header_snippet %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block layout %}
|
||||||
|
{% if show_basket_popup_setting %}
|
||||||
|
{% esi_fragment "partials/added_success.html" with sessionid=True oscar_open_basket=True request=request csrf_token=csrf_token only %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block navbar %}
|
||||||
|
{% include "carbasa/headers/header.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content_wrapper %}
|
||||||
|
<div id="main_content" tabindex="-1">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
{% include "oxyan/partials/footer.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% ocyanjson "themes" "theme-switcher" as theme_switcher %}
|
||||||
|
{% if theme_switcher %}
|
||||||
|
{% include "oxyan/partials/theme_switcher.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrascripts %}
|
||||||
|
{% include "oscar/partials/extrascripts.html" %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% if cookie_jar.needs_approval %}
|
||||||
|
<script src="{% static 'cookie_jar/js/cookie_jar.js' %}"></script>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block onbodyload %}
|
||||||
|
{{ block.super }}
|
||||||
|
oxyan.layout()
|
||||||
|
oxyan.initModalPopup()
|
||||||
|
oxyan.initializePriceUpdate()
|
||||||
|
oxyan.IconHoverFix()
|
||||||
|
oxyan.lazyIconDropdown()
|
||||||
|
oxyan.toasts()
|
||||||
|
oxyan.commerseHeader()
|
||||||
|
oxyan.initWCAG()
|
||||||
|
{% ocyanjson "themes" "image_zoom" as image_zoom %}
|
||||||
|
{% if image_zoom %}
|
||||||
|
oxyan.initImageZoom()
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block cdn_scripts %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% ocyanjson "wagtail" "wagtailuserbar_position" as position %}
|
||||||
|
{% if position %}
|
||||||
|
{% wagtailuserbar position %}
|
||||||
|
{% endif %}
|
||||||
|
{% for footer_snippet in cookie_jar.activated_snippet_footer_templates %}
|
||||||
|
{% include footer_snippet %}
|
||||||
|
{% endfor %}
|
||||||
|
{% include "cookie_jar/cookie_banner.html" %}
|
||||||
|
{% if cookie_jar.needs_approval %}
|
||||||
|
{% include "cookie_jar/partials/preferences_saved_toast.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{% load wagtailcore_tags %}
|
||||||
|
{% if self.heading %}<p class="footer_header">{{ self.heading }}</p>{% endif %}
|
||||||
|
{% if children %}
|
||||||
|
<ul class="mb-footer-links list-unstyled m-0">
|
||||||
|
{% for page in children %}
|
||||||
|
<li class="mb-footer-links__item mb-2">
|
||||||
|
<a href="{% pageurl page %}">{{ page.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<form action="{% url 'set_language' %}" method="post" class="ms-lang-switcher me-2" aria-label="Language switcher">
|
<form action="{% url 'set_language' %}" method="post" class="ms-lang-switcher me-2" aria-label="Language switcher">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input name="next" type="hidden" value="{{ request.path|untranslated_url }}">
|
<input name="next" type="hidden" value="{{ request.get_full_path }}">
|
||||||
<label for="header-language-switcher" class="visually-hidden">{% trans "Language" %}</label>
|
<label for="header-language-switcher" class="visually-hidden">{% trans "Language" %}</label>
|
||||||
<select id="header-language-switcher" name="language" class="form-select form-select-sm" onchange="this.form.submit()">
|
<select id="header-language-switcher" name="language" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||||
<option value="nl" {% if LANGUAGE_CODE == 'nl' %}selected{% endif %}>NL</option>
|
<option value="nl" {% if LANGUAGE_CODE == 'nl' %}selected{% endif %}>NL</option>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<i class="fa fa-search"></i>
|
<i class="fa fa-search"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'customer:summary' %}" aria-label="{% trans 'Customer summary' %}" class="user-button menu-circle"><i class="fa fa-user-solid"></i></a>
|
<a href="{% url 'customer:summary' %}" aria-label="{% trans 'Customer summary' %}" class="user-button menu-circle"><i class="fa fa-user-solid"></i></a>
|
||||||
{% include 'oxyan/headers/partials/mini_basket.html' %}
|
{% include "oxyan/headers/partials/mini_basket.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert-messages-header" aria-live="polite">
|
<div class="alert-messages-header" aria-live="polite">
|
||||||
|
|||||||
3
mandelstudio/templates/svg/corner.svg
Normal file
3
mandelstudio/templates/svg/corner.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg viewBox="0 0 500 500" preserveAspectRatio="none" class="corner {{ class }}">
|
||||||
|
<path class="st0" d="M0,0c166.7,0,333.3,0,500,0c-31.4-0.5-212-0.1-356.5,145C0,289.1-0.5,468.2,0,500C0,333.3,0,166.7,0,0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 214 B |
24
mandelstudio/templates/webshop/mega_dropdown.html
Normal file
24
mandelstudio/templates/webshop/mega_dropdown.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{% load i18n ocyan_thumbnail %}
|
||||||
|
{% if menu_items %}
|
||||||
|
{% for menu_item in menu_items %}
|
||||||
|
{% with category_icon=menu_item.category.icons.first %}
|
||||||
|
{% if menu_item.has_children %}
|
||||||
|
<li class="nav-item has_children">
|
||||||
|
<a class="nav-link category-label" data-name="{{ menu_item.name|safe }}" data-href="{{ menu_item.get_absolute_url }}" tabindex="-1">
|
||||||
|
<span>{% trans "Show everything in" %}</span>{{ menu_item.name }}
|
||||||
|
</a>
|
||||||
|
<ul class="menu-level">
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item child">
|
||||||
|
<a class="nav-link child-category" href="{{ menu_item.get_absolute_url }}" tabindex="-1">
|
||||||
|
{{ menu_item.name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% for close in menu_item.num_to_close %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
85
mandelstudio/templatetags/agency_navigation.py
Normal file
85
mandelstudio/templatetags/agency_navigation.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
|
||||||
|
from wagtail.models import Locale, Page
|
||||||
|
|
||||||
|
from mandelstudio.management.commands._agency_content import COMMON_CTA
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
SOURCE_PAGE_IDS = {
|
||||||
|
"about": 128,
|
||||||
|
"services": 129,
|
||||||
|
"projects": 130,
|
||||||
|
"contact": 131,
|
||||||
|
"process": 192,
|
||||||
|
}
|
||||||
|
|
||||||
|
NAV_CHILDREN = {
|
||||||
|
"services": [200, 201, 202, 203],
|
||||||
|
}
|
||||||
|
|
||||||
|
NAV_ORDER = ["services", "projects", "process", "about", "contact"]
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_locale(language_code: str | None) -> Locale | None:
|
||||||
|
if not language_code:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return Locale.objects.get(language_code=language_code)
|
||||||
|
except Locale.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _translated_page(source_id: int, language_code: str | None) -> Page | None:
|
||||||
|
locale = _resolve_locale(language_code)
|
||||||
|
try:
|
||||||
|
source = Page.objects.get(id=source_id)
|
||||||
|
except Page.DoesNotExist:
|
||||||
|
return None
|
||||||
|
if locale is None:
|
||||||
|
return source.specific
|
||||||
|
translated = (
|
||||||
|
Page.objects.filter(translation_key=source.translation_key, locale=locale)
|
||||||
|
.live()
|
||||||
|
.public()
|
||||||
|
.specific()
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
return translated or source.specific
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def agency_nav_pages(context):
|
||||||
|
request = context.get("request")
|
||||||
|
language_code = getattr(request, "LANGUAGE_CODE", None)
|
||||||
|
pages = []
|
||||||
|
for key in NAV_ORDER:
|
||||||
|
page = _translated_page(SOURCE_PAGE_IDS[key], language_code)
|
||||||
|
if page is not None:
|
||||||
|
page.nav_children = [
|
||||||
|
child
|
||||||
|
for source_id in NAV_CHILDREN.get(key, [])
|
||||||
|
if (child := _translated_page(source_id, language_code)) is not None
|
||||||
|
]
|
||||||
|
page.nav_key = key
|
||||||
|
pages.append(page)
|
||||||
|
return pages
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def agency_page(context, key: str):
|
||||||
|
request = context.get("request")
|
||||||
|
language_code = getattr(request, "LANGUAGE_CODE", None)
|
||||||
|
source_id = SOURCE_PAGE_IDS.get(key)
|
||||||
|
if source_id is None:
|
||||||
|
return None
|
||||||
|
return _translated_page(source_id, language_code)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def agency_primary_cta(context):
|
||||||
|
request = context.get("request")
|
||||||
|
language_code = getattr(request, "LANGUAGE_CODE", None) or "nl"
|
||||||
|
return COMMON_CTA.get(language_code, COMMON_CTA["nl"])["primary"]
|
||||||
Reference in New Issue
Block a user