Merge branch 'theme' into 'main'
Apply Servala Theme See merge request vshn/servala-frontend!1
This commit is contained in:
commit
0b017dd00c
34 changed files with 13915 additions and 886 deletions
|
@ -36,3 +36,5 @@ deploy:
|
||||||
environment:
|
environment:
|
||||||
name: prod
|
name: prod
|
||||||
url: https://poc.serva.la/
|
url: https://poc.serva.la/
|
||||||
|
only:
|
||||||
|
- main
|
||||||
|
|
18
hub/services/migrations/0005_service_is_featured.py
Normal file
18
hub/services/migrations/0005_service_is_featured.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 5.1.5 on 2025-02-25 15:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("services", "0004_lead_message"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="service",
|
||||||
|
name="is_featured",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 5.1.5 on 2025-02-25 15:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("services", "0005_service_is_featured"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="cloudprovider",
|
||||||
|
name="is_featured",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="consultingpartner",
|
||||||
|
name="is_featured",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -55,6 +55,7 @@ class CloudProvider(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
is_featured = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -105,6 +106,7 @@ class Service(models.Model):
|
||||||
)
|
)
|
||||||
categories = models.ManyToManyField(Category, related_name="services")
|
categories = models.ManyToManyField(Category, related_name="services")
|
||||||
features = ProseEditorField()
|
features = ProseEditorField()
|
||||||
|
is_featured = models.BooleanField(default=False)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
@ -139,6 +141,7 @@ class ConsultingPartner(models.Model):
|
||||||
cloud_providers = models.ManyToManyField(
|
cloud_providers = models.ManyToManyField(
|
||||||
CloudProvider, related_name="consulting_partners", blank=True
|
CloudProvider, related_name="consulting_partners", blank=True
|
||||||
)
|
)
|
||||||
|
is_featured = models.BooleanField(default=False)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
|
Binary file not shown.
BIN
hub/services/static/css/fonts/Archivo-VariableFont_wdth,wght.ttf
Normal file
BIN
hub/services/static/css/fonts/Archivo-VariableFont_wdth,wght.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
12311
hub/services/static/css/servala-main.css
Normal file
12311
hub/services/static/css/servala-main.css
Normal file
File diff suppressed because it is too large
Load diff
BIN
hub/services/static/img/favicon.ico
Normal file
BIN
hub/services/static/img/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
hub/services/static/img/footer-logo.png
Normal file
BIN
hub/services/static/img/footer-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
BIN
hub/services/static/img/header-logo.png
Normal file
BIN
hub/services/static/img/header-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
hub/services/static/img/header-logo1.png
Normal file
BIN
hub/services/static/img/header-logo1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
hub/services/static/img/hero-bg.jpg
Normal file
BIN
hub/services/static/img/hero-bg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
BIN
hub/services/static/img/section-logo.png
Normal file
BIN
hub/services/static/img/section-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
1
hub/services/static/js/alpine-collapse.min.js
vendored
Normal file
1
hub/services/static/js/alpine-collapse.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(()=>{function g(n){n.directive("collapse",e),e.inline=(t,{modifiers:i})=>{i.includes("min")&&(t._x_doShow=()=>{},t._x_doHide=()=>{})};function e(t,{modifiers:i}){let r=l(i,"duration",250)/1e3,h=l(i,"min",0),u=!i.includes("min");t._x_isShown||(t.style.height=`${h}px`),!t._x_isShown&&u&&(t.hidden=!0),t._x_isShown||(t.style.overflow="hidden");let c=(d,s)=>{let o=n.setStyles(d,s);return s.height?()=>{}:o},f={transitionProperty:"height",transitionDuration:`${r}s`,transitionTimingFunction:"cubic-bezier(0.4, 0.0, 0.2, 1)"};t._x_transition={in(d=()=>{},s=()=>{}){u&&(t.hidden=!1),u&&(t.style.display=null);let o=t.getBoundingClientRect().height;t.style.height="auto";let a=t.getBoundingClientRect().height;o===a&&(o=h),n.transition(t,n.setStyles,{during:f,start:{height:o+"px"},end:{height:a+"px"}},()=>t._x_isShown=!0,()=>{Math.abs(t.getBoundingClientRect().height-a)<1&&(t.style.overflow=null)})},out(d=()=>{},s=()=>{}){let o=t.getBoundingClientRect().height;n.transition(t,c,{during:f,start:{height:o+"px"},end:{height:h+"px"}},()=>t.style.overflow="hidden",()=>{t._x_isShown=!1,t.style.height==`${h}px`&&u&&(t.style.display="none",t.hidden=!0)})}}}}function l(n,e,t){if(n.indexOf(e)===-1)return t;let i=n[n.indexOf(e)+1];if(!i)return t;if(e==="duration"){let r=i.match(/([0-9]+)ms/);if(r)return r[1]}if(e==="min"){let r=i.match(/([0-9]+)px/);if(r)return r[1]}return i}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(g)});})();
|
9
hub/services/static/js/servala-main.js
Normal file
9
hub/services/static/js/servala-main.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -5,60 +5,208 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Servala - The Cloud Native Services Hub</title>
|
<title>Servala - The Cloud Native Services Hub</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="{% static "img/favicon.ico" %}">
|
||||||
|
|
||||||
<link rel="stylesheet" href='{% static "css/bootstrap-icons.min.css" %}'>
|
<link rel="stylesheet" href='{% static "css/bootstrap-icons.min.css" %}'>
|
||||||
<link rel="stylesheet" type="text/css" href='{% static "css/bootstrap.min.css" %}'>
|
<link rel="stylesheet" type="text/css" href='{% static "css/servala-main.css" %}'>
|
||||||
<style>
|
|
||||||
.rich-text-content {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
.rich-text-content img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.description-preview img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% block extra_css %}{% endblock %}
|
{% block extra_css %}{% endblock %}
|
||||||
|
|
||||||
<script defer data-domain="serva.la" src="https://plausible.io/js/script.outbound-links.tagged-events.js"></script>
|
<script defer data-domain="serva.la" src="https://plausible.io/js/script.outbound-links.tagged-events.js"></script>
|
||||||
|
<script defer src="{% static "js/alpine-collapse.min.js" %}"></script>
|
||||||
|
<script defer src="{% static "js/servala-main.js" %}"></script>
|
||||||
|
{% block extra_js %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<div class="overflow-hidden">
|
||||||
<div class="container">
|
<header x-data="{sideNav: false, atTop: true}" class="site-header position-relative">
|
||||||
<a class="navbar-brand" href="{% url 'services:homepage' %}">Servala</a>
|
<div class="header-nav" :class="{ 'header-nav--top': atTop, 'header-nav--fixed': !atTop }"
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
x-on:scroll.window="atTop = (window.pageYOffset > 200) ? false : true;">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<div class="container-xl mx-auto px-3 px-lg-0 position-relative">
|
||||||
</button>
|
<div class="nav__wrapper d-flex justify-content-between align-items-center">
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="nav__brand logo">
|
||||||
<ul class="navbar-nav">
|
<a class="navbar__logo" href="{% url 'services:homepage' %}" title="logo">
|
||||||
<li class="nav-item">
|
<img src="{% static "img/header-logo.png" %}" alt="Servala Logo" width="191" height="43">
|
||||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:service_list' %}active{% endif %}"
|
</a>
|
||||||
href="{% url 'services:service_list' %}">Services</a>
|
</div>
|
||||||
</li>
|
<div x-cloak class="nav__menu" :class="sideNav ? 'nav__menu-active' : 'nav__menu-hidden'">
|
||||||
<li class="nav-item">
|
<nav class="navbar d-lg-flex justify-content-lg-end align-items-lg-center">
|
||||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:offering_list' %}active{% endif %}"
|
<ul class="navbar__menu menu mr-lg-27">
|
||||||
href="{% url 'services:offering_list' %}">Service Offerings</a>
|
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:homepage' %}">Home</a></li>
|
||||||
</li>
|
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:service_list' %}">Services</a></li>
|
||||||
<li class="nav-item">
|
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:offering_list' %}">Offerings</a></li>
|
||||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:provider_list' %}active{% endif %}"
|
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:provider_list' %}">Cloud Providers</a></li>
|
||||||
href="{% url 'services:provider_list' %}">Cloud Providers</a>
|
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:partner_list' %}">Consulting Partners</a></li>
|
||||||
</li>
|
</ul>
|
||||||
<li class="nav-item">
|
</nav>
|
||||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:partner_list' %}active{% endif %}"
|
</div>
|
||||||
href="{% url 'services:partner_list' %}">Consulting Partners</a>
|
<div class="nav__toggle">
|
||||||
</li>
|
<button @click="sideNav = !sideNav" name="menu" class="nav__button" role="button">
|
||||||
</ul>
|
<svg class="nav__button-svg" width="22" height="24">
|
||||||
|
<line class="button-svg__line" :class="{ 'svg-line-top': sideNav === true }" id="top" x1="0" x2="22"
|
||||||
|
y1="6" y2="6"></line>
|
||||||
|
<line class="button-svg__line" :class="{ 'svg-line-center': sideNav === true }" id="middle" x1="0"
|
||||||
|
x2="22" y1="12" y2="12">
|
||||||
|
</line>
|
||||||
|
<line class="button-svg__line" :class="{ 'svg-line-bottom': sideNav === true }" id="bottom" x1="0"
|
||||||
|
x2="22" y1="18" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</header>
|
||||||
|
|
||||||
<div class="container mt-4">
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="{% static "js/bootstrap.bundle.min.js" %}"></script>
|
<section class="section">
|
||||||
|
<div class="section-wrapper container mx-auto px-20 px-lg-0 pt-60 pb-60">
|
||||||
|
<div class="bg-primary-subtle rounded-40 py-100 px-20 px-lg-0">
|
||||||
|
<header class="section-primary__header text-center">
|
||||||
|
<div class="d-inline-flex position-relative">
|
||||||
|
<div class="section-title-svg position-absolute d-none d-lg-block">
|
||||||
|
<svg width="45" height="50" viewBox="0 0 45 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M29.9436 46.0084C34.2405 44.8026 38.7391 44.1943 43.1031 43.6371C44.0431 43.5203 44.9157 44.1722 44.9829 45.0906C45.1171 46.0097 44.4454 46.8503 43.5726 46.9671C39.3428 47.5036 34.9793 48.0776 30.8838 49.2384C30.011 49.4902 29.0707 48.9719 28.8021 48.0803C28.5336 47.1894 29.0708 46.2608 29.9436 46.0084Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M16.9192 28.9129C23.8344 21.856 31.6225 15.7075 38.4034 8.46126C39.0077 7.78451 40.0819 7.74825 40.7533 8.38002C41.4247 9.01246 41.4915 10.0759 40.8202 10.7527C34.0392 18.0197 26.2512 24.1884 19.3359 31.2661C18.6645 31.9268 17.5906 31.9362 16.9192 31.2863C16.3149 30.637 16.2478 29.5736 16.9192 28.9129Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M3.9606 1.7696C3.75918 5.80864 3.55816 9.84768 3.35675 13.8874C3.35675 14.8126 2.55069 15.5269 1.61076 15.4819C0.670821 15.4363 -0.000168324 14.6487 -0.000168324 13.7229C0.201247 9.67715 0.402268 5.63207 0.603683 1.58699C0.670821 0.661821 1.47661 -0.0478314 2.41655 0.00252227C3.28935 0.052876 4.02774 0.84511 3.9606 1.7696Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2 class="section-h1 fs-40 fs-lg-60 d-inline-block mb-24">Ready to Get Started?</h2>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-300 w-lg-37 mx-auto mb-24">
|
||||||
|
<p class="mb-0">Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-primary btn-lg mr-md-17 mb-17 mb-md-0 w-100 w-md-auto" href="{% url 'services:homepage' %}" role="button">Discover
|
||||||
|
Services</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<section>
|
||||||
|
<div class="container mx-auto px-20 px-lg-0 py-36 border-y">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-lg-4 mb-60 mb-lg-0">
|
||||||
|
<div class="mb-10">
|
||||||
|
<a href="">
|
||||||
|
<img class="img-fluid" src="{% static "img/footer-logo.png" %}" alt="Servala by VSHN Logo">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="fs-14 fw-semibold">
|
||||||
|
<p>Unlock the Power of Cloud Native Applications</p>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center space-x-20">
|
||||||
|
<a href="https://www.linkedin.com/company/5395280/">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M20.5831 0.631348C21.2609 0.631348 21.9109 0.900593 22.3902 1.37985C22.8694 1.85911 23.1387 2.50913 23.1387 3.1869V21.0758C23.1387 21.7536 22.8694 22.4036 22.3902 22.8828C21.9109 23.3621 21.2609 23.6313 20.5831 23.6313H2.69423C2.01645 23.6313 1.36644 23.3621 0.887177 22.8828C0.407917 22.4036 0.138672 21.7536 0.138672 21.0758V3.1869C0.138672 2.50913 0.407917 1.85911 0.887177 1.37985C1.36644 0.900593 2.01645 0.631348 2.69423 0.631348H20.5831ZM19.9442 20.4369V13.6647C19.9442 12.5599 19.5054 11.5004 18.7242 10.7192C17.943 9.93799 16.8834 9.49912 15.7787 9.49912C14.6926 9.49912 13.4276 10.1636 12.8142 11.1602V9.7419H9.24923V20.4369H12.8142V14.1375C12.8142 13.1536 13.6065 12.3486 14.5903 12.3486C15.0648 12.3486 15.5198 12.537 15.8553 12.8725C16.1908 13.208 16.3792 13.663 16.3792 14.1375V20.4369H19.9442ZM5.09645 7.73579C5.66578 7.73579 6.21179 7.50963 6.61437 7.10705C7.01695 6.70447 7.24312 6.15846 7.24312 5.58913C7.24312 4.40079 6.28478 3.42968 5.09645 3.42968C4.52373 3.42968 3.97447 3.65719 3.56949 4.06217C3.16452 4.46714 2.93701 5.01641 2.93701 5.58913C2.93701 6.77746 3.90812 7.73579 5.09645 7.73579ZM6.87256 20.4369V9.7419H3.33312V20.4369H6.87256Z"
|
||||||
|
fill="#4B5563" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-lg-2 mb-60 mb-lg-0">
|
||||||
|
<div class="space-y-20">
|
||||||
|
<h4 class="fs-base fw-semibold">Contents</h4>
|
||||||
|
<ul class="list-unstyled space-y-20 fs-15 fw-medium ps-0">
|
||||||
|
<li><a href="{% url 'services:homepage' %}">Home</a></li>
|
||||||
|
<li><a href="{% url 'services:service_list' %}">Services</a></li>
|
||||||
|
<li><a href="{% url 'services:offering_list' %}">Offerings</a></li>
|
||||||
|
<li><a href="{% url 'services:provider_list' %}">Cloud Providers</a></li>
|
||||||
|
<li><a href="{% url 'services:partner_list' %}">Consulting Partners</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-lg-2 mb-60 mb-lg-0">
|
||||||
|
<div class="space-y-20">
|
||||||
|
<h4 class="fs-base fw-semibold">Company</h4>
|
||||||
|
<ul class="list-unstyled space-y-20 fs-15 fw-medium ps-0">
|
||||||
|
<li><a href="https://www.vshn.ch/en/about/">About Us</a></li>
|
||||||
|
<li><a href="https://products.vshn.ch/legal/gtc_en.html">Terms & Conditions</a></li>
|
||||||
|
<li><a href="https://products.vshn.ch/legal/privacy_policy_en.html">Privacy Policy</a></li>
|
||||||
|
<li><a href="https://products.vshn.ch/legal/dpa_en.html">Data Processing Agreement</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-lg-4">
|
||||||
|
<div class="space-y-20 w-lg-90">
|
||||||
|
<h4 class="fs-base fw-semibold">Contact</h4>
|
||||||
|
<ul class="list-unstyled space-y-20 fs-base fw-medium ps-0">
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center" href="tel:+41445455300">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M18.984 15.5283C17.8172 14.5982 16.6332 14.0349 15.4808 14.9635L14.7927 15.5248C14.2892 15.9322 13.3531 17.8358 9.73382 13.9555C6.11531 10.0801 8.26863 9.47668 8.77286 9.07277L9.46475 8.51081C10.6111 7.58006 10.1785 6.40838 9.3517 5.20228L8.85275 4.47173C8.02217 3.26844 7.11773 2.47818 5.96834 3.40752L5.3473 3.91328C4.8393 4.25819 3.41933 5.37929 3.07489 7.50912C2.66036 10.0646 3.96803 12.991 6.96398 16.2019C9.95617 19.4142 12.8858 21.0277 15.6609 20.9996C17.9672 20.9765 19.3601 19.823 19.7957 19.4037L20.419 18.8972C21.5654 17.9686 20.8531 17.0231 19.6857 16.0909L18.984 15.5283Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>+41 44 545 53 00</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center" href="mailto:hi@serva.la">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_3315_428" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0"
|
||||||
|
width="24" height="24">
|
||||||
|
<rect width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_3315_428)">
|
||||||
|
<path
|
||||||
|
d="M4 20C3.45 20 2.97917 19.8042 2.5875 19.4125C2.19583 19.0208 2 18.55 2 18V6C2 5.45 2.19583 4.97917 2.5875 4.5875C2.97917 4.19583 3.45 4 4 4H20C20.55 4 21.0208 4.19583 21.4125 4.5875C21.8042 4.97917 22 5.45 22 6V18C22 18.55 21.8042 19.0208 21.4125 19.4125C21.0208 19.8042 20.55 20 20 20H4ZM12 13L20 8V6L12 11L4 6V8L12 13Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>hi@serva.la</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center" href="https://www.openstreetmap.org/node/3666762517">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_3315_433)">
|
||||||
|
<path
|
||||||
|
d="M12 0C7.038 0 3 4.066 3 9.065C3 16.168 11.154 23.502 11.501 23.81C11.644 23.937 11.822 24 12 24C12.178 24 12.356 23.937 12.499 23.811C12.846 23.502 21 16.168 21 9.065C21 4.066 16.962 0 12 0ZM12 14C9.243 14 7 11.757 7 9C7 6.243 9.243 4 12 4C14.757 4 17 6.243 17 9C17 11.757 14.757 14 12 14Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_3315_433">
|
||||||
|
<rect width="24" height="24" fill="white" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>Neugasse 10, 8005 Zurich, Switzerland</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<div class="container mx-auto px-20 px-lg-0 pt-36 pb-40">
|
||||||
|
<div class="text-center fs-base fw-medium">
|
||||||
|
<p class="mb-0">© 2025 VSHN. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -2,17 +2,184 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="px-4 py-5 my-5 text-center">
|
<section class="section section-hero bg-primary-subtle">
|
||||||
<img class="d-block mx-auto mb-4" src="{% static "img/servala-logo.png" %}" alt="" height="150">
|
<div class="section-wrapper container mx-auto position-relative">
|
||||||
<h1 class="display-5 fw-bold text-body-emphasis">The Cloud Native Service Hub</h1>
|
<div class="section-hero-mask"></div>
|
||||||
<div class="col-lg-6 mx-auto">
|
<div class="px-3 px-lg-0 pt-80 pb-120 position-relative">
|
||||||
<p class="lead mb-4">Minions ipsum uuuhhh me want bananaaa! Ti aamoo! Daa la bodaaa tatata bala tu uuuhhh. Aaaaaah pepete uuuhhh po kass.</p>
|
<header class="section-hero__header">
|
||||||
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
|
<h1 class="section-h1 fs-40 fs-lg-64">Servala - The Cloud Native Service Hub</h1>
|
||||||
<a href="{% url 'services:service_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Services</button></a>
|
<div class="section-hero__desc">
|
||||||
<a href="{% url 'services:offering_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Offerings</button></a>
|
<p>Unlock the Power of Cloud Native Applications.</p>
|
||||||
<a href="{% url 'services:provider_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Cloud Providers</button></a>
|
</div>
|
||||||
<a href="{% url 'services:partner_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Consulting</button></a>
|
<div>
|
||||||
|
<a class="btn btn-primary btn-lg mr-md-17 mb-17 mb-md-0 w-100 w-md-auto" href="{% url 'services:service_list' %}" role="button">Discover
|
||||||
|
Services</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-40">
|
||||||
|
<div class="">
|
||||||
|
<header class="section__header w-100 d-flex justify-content-between align-items-center">
|
||||||
|
<div class="section__header-text">
|
||||||
|
<h2 class="section__header-h2">Services</h2>
|
||||||
|
<div class="section__desc">
|
||||||
|
<p>Lorem ipsum dolor sit amet consectetur. Gravida nec amet rhoncus placerat. Diam est faucibus
|
||||||
|
dignissim porttitor.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-none d-lg-block">
|
||||||
|
<a class="section__header-link" href="{% url 'services:service_list' %}">See All</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="section__grid">
|
||||||
|
<div class="row">
|
||||||
|
{% for service in featured_services %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-3 mb-20 mb-lg-0">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card__image">
|
||||||
|
<a href="{{ service.get_absolute_url }}"><img class="img-fluid" src="{{ service.logo.url }}" alt="{{ service.name }} logo"></a>
|
||||||
|
</div>
|
||||||
|
<div class="card__header">
|
||||||
|
<h3 class="card__title"><a href="{{ service.get_absolute_url }}" class="text-decoration-none">{{ service.name }}</a></h3>
|
||||||
|
{% for category in service.categories.all|slice:":1" %}
|
||||||
|
<p class="card__subtitle">{{ category.name }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="card__desc">
|
||||||
|
<p>{{ service.description|safe|truncatewords:15 }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% empty %}
|
||||||
|
<div class="col-12">
|
||||||
|
<p class="text-center">No featured services available at the moment.</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-action d-lg-none">
|
||||||
|
<a class="btn btn-outline-primary btn-lg w-100" href="#" role="button">See All</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-40">
|
||||||
|
<div class="">
|
||||||
|
<header class="section__header w-100 d-flex justify-content-between align-items-center">
|
||||||
|
<div class="section__header-text">
|
||||||
|
<h2 class="section__header-h2">Cloud Providers</h2>
|
||||||
|
<div class="section__desc">
|
||||||
|
<p>Lorem ipsum dolor sit amet consectetur. Gravida nec amet rhoncus placerat. Diam est faucibus
|
||||||
|
dignissim porttitor.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-none d-lg-block">
|
||||||
|
<a class="section__header-link" href="{% url 'services:provider_list' %}">See All</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="section__grid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="section__grid">
|
||||||
|
<div class="row">
|
||||||
|
{% for provider in featured_providers %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-3 mb-20 mb-lg-0">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card__image__wide mb-4">
|
||||||
|
<a href="{{ provider.get_absolute_url }}"><img class="img-fluid" src="{{ provider.logo.url }}" alt="{{ provider.name }} logo"></a>
|
||||||
|
</div>
|
||||||
|
<div class="card__header">
|
||||||
|
<h3 class="card__title"><a href="{{ provider.get_absolute_url }}" class="text-decoration-none">{{ provider.name }}</a></h3>
|
||||||
|
</div>
|
||||||
|
<div class="card__desc">
|
||||||
|
<p>{{ provider.description|safe|truncatewords:15 }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% empty %}
|
||||||
|
<div class="col-12">
|
||||||
|
<p class="text-center">No featured provider available at the moment.</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-action d-lg-none">
|
||||||
|
<a class="btn btn-outline-primary btn-lg w-100" href="#" role="button">See All</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-80">
|
||||||
|
<div class="">
|
||||||
|
<header class="section__header w-100 d-flex justify-content-between align-items-center">
|
||||||
|
<div class="section__header-text">
|
||||||
|
<h2 class="section__header-h2">Consulting Partners</h2>
|
||||||
|
<div class="section__desc">
|
||||||
|
<p>Lorem ipsum dolor sit amet consectetur. Gravida nec amet rhoncus placerat. Diam est faucibus
|
||||||
|
dignissim porttitor.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-none d-lg-block">
|
||||||
|
<a class="section__header-link" href="{% url 'services:partner_list' %}">See All</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="section__grid">
|
||||||
|
<div class="row">
|
||||||
|
{% for partner in featured_partners %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-3 mb-20 mb-lg-0">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card__image__wide mb-4">
|
||||||
|
<a href="{{ partner.get_absolute_url }}"><img class="img-fluid" src="{{ partner.logo.url }}" alt="{{ partner.name }} logo"></a>
|
||||||
|
</div>
|
||||||
|
<div class="card__header">
|
||||||
|
<h3 class="card__title"><a href="{{ partner.get_absolute_url }}" class="text-decoration-none">{{ partner.name }}</a></h3>
|
||||||
|
</div>
|
||||||
|
<div class="card__desc">
|
||||||
|
<p>{{ partner.description|safe|truncatewords:15 }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% empty %}
|
||||||
|
<div class="col-12">
|
||||||
|
<p class="text-center">No featured partner available at the moment.</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-action d-lg-none">
|
||||||
|
<a class="btn btn-outline-primary btn-lg w-100" href="#" role="button">See All</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section bg-primary-subtle">
|
||||||
|
<div class="section-wrapper container mx-auto px-20 px-lg-0 pt-80 pb-120">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-lg-4 mb-30 mb-lg-0">
|
||||||
|
<div class="section-logo mx-auto">
|
||||||
|
<img class="img-fluid" src="{% static "img/section-logo.png" %}" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-8">
|
||||||
|
<header class="section-primary__header">
|
||||||
|
<h2 class="section-h1 fs-40 fs-lg-60">Servala - The Cloud Native Service Hub</h2>
|
||||||
|
<div class="section-primary__desc">
|
||||||
|
<p>Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-primary btn-lg mr-md-17 mb-17 mb-md-0 w-100 w-md-auto" href="{% url 'services:offering_list' %}" role="button">Discover
|
||||||
|
Services</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,100 +1,109 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
{% load form_tags %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row justify-content-center">
|
<section class="section">
|
||||||
<div class="col-md-8">
|
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||||
<div class="card">
|
<div class="d-lg-flex">
|
||||||
<div class="card-body">
|
<div class="flex-1 pr-lg-40 mb-40 mb-lg-0">
|
||||||
<h2 class="card-title mb-4">Interested in {{ service.name }}</h2>
|
<div class="bg-gray-50 rounded-20 p-40">
|
||||||
|
<header>
|
||||||
|
<h2 class="fs-44 fw-semibold mb-40">Enter your details</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
{% if selected_offering %}
|
<form method="post">
|
||||||
<div class="mb-4">
|
{% csrf_token %}
|
||||||
<h5>Service Details</h5>
|
|
||||||
{% if selected_offering %}
|
<div class="mb-40">
|
||||||
<p><strong>Provider:</strong> {{ selected_offering.cloud_provider.name }}</p>
|
<label for="{{ form.name.id_for_label }}" class="form-label text-purple">Your Name</label>
|
||||||
{% endif %}
|
{{ form.name|addclass:"form-control" }}
|
||||||
{% if selected_plan %}
|
{% if form.name.errors %}
|
||||||
<p><strong>Plan:</strong> {{ selected_plan.name }}</p>
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.name.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-40">
|
||||||
|
<label for="{{ form.email.id_for_label }}" class="form-label text-purple">Your Email Address</label>
|
||||||
|
{{ form.email|addclass:"form-control" }}
|
||||||
|
{% if form.email.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.email.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-40">
|
||||||
|
<label for="{{ form.phone.id_for_label }}" class="form-label text-purple">Your Phone Number</label>
|
||||||
|
{{ form.phone|addclass:"form-control" }}
|
||||||
|
{% if form.phone.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.phone.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-40">
|
||||||
|
<label for="{{ form.company.id_for_label }}" class="form-label text-purple">Your Company</label>
|
||||||
|
{{ form.company|addclass:"form-control" }}
|
||||||
|
{% if form.company.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.company.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-40">
|
||||||
|
<label for="{{ form.message.id_for_label }}" class="form-label text-purple">Message (Optional)</label>
|
||||||
|
{{ form.message|addclass:"form-control" }}
|
||||||
|
{% if form.message.errors %}
|
||||||
|
<div class="invalid-feedback d-block">
|
||||||
|
{{ form.message.errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg w-100">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if selected_offering %}
|
||||||
|
<div class="w-lg-34 bg-purple-50 rounded-16 p-24 d-flex flex-column">
|
||||||
|
<div class="d-flex align-items-center mb-24">
|
||||||
|
<div class="card__image mb-0">
|
||||||
|
{% if selected_offering.service.logo %}
|
||||||
|
<img class="img-fluid" src="{{ selected_offering.service.logo.url }}" alt="">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="card__header ps-16">
|
||||||
|
<h3 class="card__title">{{ service.name }}</h3>
|
||||||
|
<p class="card__subtitle mb-0">on {{ selected_offering.cloud_provider.name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if selected_plan %}
|
||||||
|
<div class="mb-24">
|
||||||
|
<div class="bg-white border-all rounded-7 p-20">
|
||||||
|
<h3 class="text-purple fs-18 fw-semibold lh-1-7 mb-0">{{ selected_plan.name }}</h3>
|
||||||
{% if selected_plan.prices.exists %}
|
{% if selected_plan.prices.exists %}
|
||||||
<p><strong>Pricing:</strong></p>
|
<div>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled text-gray-500 fs-14 lh-1-7 ps-0 mb-0">
|
||||||
{% for price in selected_plan.prices.all %}
|
{% for price in selected_plan.prices.all %}
|
||||||
<li>{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}</li>
|
<li>{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-{{ message.tags }}">
|
|
||||||
{{ message }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="{{ form.name.id_for_label }}" class="form-label">Name</label>
|
|
||||||
{{ form.name }}
|
|
||||||
{% if form.name.errors %}
|
|
||||||
<div class="invalid-feedback d-block">
|
|
||||||
{{ form.name.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="{{ form.company.id_for_label }}" class="form-label">Company</label>
|
|
||||||
{{ form.company }}
|
|
||||||
{% if form.company.errors %}
|
|
||||||
<div class="invalid-feedback d-block">
|
|
||||||
{{ form.company.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="{{ form.email.id_for_label }}" class="form-label">Email</label>
|
|
||||||
{{ form.email }}
|
|
||||||
{% if form.email.errors %}
|
|
||||||
<div class="invalid-feedback d-block">
|
|
||||||
{{ form.email.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="{{ form.phone.id_for_label }}" class="form-label">Phone</label>
|
|
||||||
{{ form.phone }}
|
|
||||||
{% if form.phone.errors %}
|
|
||||||
<div class="invalid-feedback d-block">
|
|
||||||
{{ form.phone.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="{{ form.message.id_for_label }}" class="form-label">Message (Optional)</label>
|
|
||||||
{{ form.message }}
|
|
||||||
{% if form.message.errors %}
|
|
||||||
<div class="invalid-feedback d-block">
|
|
||||||
{{ form.message.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-4">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<a href="{% url 'services:service_detail' service.slug %}" class="btn btn-secondary">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,87 +1,160 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card mb-4">
|
<section class="section">
|
||||||
<div class="card-body">
|
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
<div class="row">
|
||||||
<div class="d-flex align-items-start">
|
<!-- Left Sidebar -->
|
||||||
{% if offering.service.logo %}
|
<div class="col-12 col-lg-3">
|
||||||
<img src="{{ offering.service.logo.url }}" alt="{{ offering.service.name }} logo" class="me-4"
|
<div class="pr-lg-6">
|
||||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
<!-- Logo -->
|
||||||
{% endif %}
|
<div class="mb-40 border rounded-4 p-4 d-flex align-items-center justify-content-center" style="min-height: 160px;">
|
||||||
<div>
|
{% if offering.service.logo %}
|
||||||
<h2 class="card-title mb-2">{{ offering.service.name }}</h2>
|
<img class="img-fluid w-100 w-lg-auto" src="{{ offering.service.logo.url }}"
|
||||||
<h4 class="text-muted">
|
alt="{{ offering.service.name }} logo" style="max-height: 120px; object-fit: contain;">
|
||||||
on
|
{% endif %}
|
||||||
<a href="{{ offering.cloud_provider.get_absolute_url }}" class="text-decoration-none">
|
</div>
|
||||||
{{ offering.cloud_provider.name }}
|
|
||||||
</a>
|
<!-- Highlights -->
|
||||||
</h4>
|
{% if offering.highlights.exists %}
|
||||||
|
<div class="mb-40">
|
||||||
|
<h3 class="fw-semibold mb-12">Highlights</h3>
|
||||||
|
<ul class="list-unstyled space-y-12 fs-19 ps-0">
|
||||||
|
{% for highlight in offering.highlights.all %}
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center text-gray-500 h-32 lh-32" href="">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
|
||||||
|
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" fill="#9A63EC"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>{{ highlight.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Consulting Partners -->
|
||||||
|
{% if offering.service.consulting_partners.exists %}
|
||||||
|
<div class="mb-40">
|
||||||
|
<h3 class="fw-semibold mb-12">Consulting Partners</h3>
|
||||||
|
<ul class="list-unstyled space-y-12 fs-19 ps-0">
|
||||||
|
{% for partner in offering.service.consulting_partners.all %}
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center text-gray-500 h-32 lh-32" href="{{ partner.get_absolute_url }}">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-people-fill" viewBox="0 0 16 16">
|
||||||
|
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6m-5.784 6A2.24 2.24 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.3 6.3 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1zM4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5" fill="#9A63EC"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>{{ partner.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- External Links -->
|
||||||
|
{% if offering.service.external_links.exists %}
|
||||||
|
<div class="mb-40">
|
||||||
|
<h3 class="fw-semibold mb-12">External Links</h3>
|
||||||
|
<ul class="list-unstyled space-y-12 fs-19 ps-0">
|
||||||
|
{% for link in offering.service.external_links.all %}
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center text-gray-500 h-32 lh-32" href="{{ link.url }}" target="_blank">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5" fill="#9A63EC"/>
|
||||||
|
<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z" fill="#9A63EC"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>{{ link.description }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if offering.cloud_provider.logo %}
|
|
||||||
<img src="{{ offering.cloud_provider.logo.url }}"
|
|
||||||
alt="{{ offering.cloud_provider.name }} logo"
|
|
||||||
style="max-height: 80px; max-width: 160px; object-fit: contain;">
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rich-text-content mb-4">
|
<!-- Main Content -->
|
||||||
{{ offering.description|safe }}
|
<div class="col-12 col-lg-9">
|
||||||
</div>
|
<div class="pr-lg-32">
|
||||||
</div>
|
<!-- Header -->
|
||||||
</div>
|
<div class="pt-60 pb-lg-60 w-lg-70">
|
||||||
|
<header>
|
||||||
<!-- Plans -->
|
{% if offering.cloud_provider.logo %}
|
||||||
<div class="card mb-4">
|
<p class="mb-6"><a href="{{ offering.cloud_provider.website }}" target="_blank">
|
||||||
<div class="card-body">
|
<img class="img-fluid" src="{{ offering.cloud_provider.logo.url }}"
|
||||||
<h3 class="mb-4">Available Plans</h3>
|
alt="{{ offering.cloud_provider.name }} logo" style="max-height: 40px;"></a>
|
||||||
<div class="row row-cols-1 row-cols-md-3 g-4">
|
</p>
|
||||||
{% for plan in offering.plans.all %}
|
|
||||||
<div class="col">
|
|
||||||
<div class="card h-100 {% if plan.is_default %}border-primary{% endif %}">
|
|
||||||
{% if plan.is_default %}
|
|
||||||
<div class="card-header text-primary">
|
|
||||||
Recommended Plan
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="card-body">
|
|
||||||
<h4 class="card-title mb-3">{{ plan.name }}</h4>
|
|
||||||
|
|
||||||
<div class="rich-text-content mb-3">
|
|
||||||
{{ plan.description|safe }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if plan.features %}
|
|
||||||
<div class="rich-text-content mb-3">
|
|
||||||
{{ plan.features|safe }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h2 class="fs-50 fw-semibold lh-1 mb-12">{{ offering.service.name }}</h2>
|
||||||
|
</header>
|
||||||
|
<div class="fs-19 text-gray-500">
|
||||||
|
{% for category in offering.service.categories.all %}
|
||||||
|
<button class="btn btn-tertiary btn-sm mr-12">{{ category.full_path }}</button>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="fs-19 text-gray-500">
|
||||||
|
{{ offering.short_description|safe }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- Description -->
|
||||||
{% for price in plan.prices.all %}
|
<div class="pt-40 pt-lg-34">
|
||||||
<div class="mb-2">
|
<h3 class="fs-24 fw-semibold lh-1 mb-12">Overview</h3>
|
||||||
<strong>{{ price.currency.symbol }}{{ price.price }}</strong>
|
<div class="fs-19 text-gray-500">
|
||||||
{{ price.currency.code }} per {{ price.term.name }}
|
{{ offering.description|safe }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Plans -->
|
||||||
|
<div class="pt-24">
|
||||||
|
<h3 class="fs-24 fw-semibold lh-1 mb-12">Available Plans</h3>
|
||||||
|
<div class="row">
|
||||||
|
{% for plan in offering.plans.all %}
|
||||||
|
<div class="col-12 col-lg-6 {% if not forloop.last %}mb-20 mb-lg-0{% endif %}">
|
||||||
|
<div class="bg-purple-50 rounded-16 border-all p-24">
|
||||||
|
<div class="text-black mb-20">
|
||||||
|
<p class="mb-0">{{ plan.description|safe }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
<div class="bg-white border-all rounded-7 p-20 mb-20">
|
||||||
|
<h3 class="text-purple fs-22 fw-semibold lh-1-7 mb-0">{{ plan.name }}</h3>
|
||||||
|
<div>
|
||||||
|
<ul class="list-unstyled text-gray-500 fs-19 lh-1-7 ps-0 mb-0">
|
||||||
|
{% for price in plan.prices.all %}
|
||||||
|
<li>{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-primary btn-lg w-100"
|
||||||
|
href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}&plan={{ plan.id }}">
|
||||||
|
Order Now
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% empty %}
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}&plan={{ plan.id }}"
|
<div class="col-12">
|
||||||
class="btn btn-success">Select This Plan</a>
|
<div class="alert alert-info">
|
||||||
|
No plans available yet.
|
||||||
|
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
||||||
|
class="btn btn-success ms-3">Show Interest</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
</div>
|
||||||
<div class="col-12">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
No plans available yet.
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success ms-3">Show Interest</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,167 +1,204 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<section class="section bg-primary-subtle">
|
||||||
<div class="col-md-3">
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||||
<div class="card">
|
<header class="section-primary__header text-center">
|
||||||
<div class="card-body">
|
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Service Offerings</h2>
|
||||||
<h5 class="card-title">Filters</h5>
|
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||||
<form method="get">
|
<p class="mb-0">Explore our available service offerings</p>
|
||||||
<div class="mb-3">
|
|
||||||
<label for="search" class="form-label">Search</label>
|
|
||||||
<input type="text" class="form-control" id="search" name="search" value="{{ request.GET.search }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="cloud_provider" class="form-label">Cloud Provider</label>
|
|
||||||
<select class="form-select" id="cloud_provider" name="cloud_provider">
|
|
||||||
<option value="">All Providers</option>
|
|
||||||
{% for provider in cloud_providers %}
|
|
||||||
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ provider.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="category" class="form-label">Category</label>
|
|
||||||
<select class="form-select" id="category" name="category">
|
|
||||||
<option value="">All Categories</option>
|
|
||||||
{% for category in categories %}
|
|
||||||
<option value="{{ category.id }}" {% if request.GET.category == category.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ category.name }}
|
|
||||||
</option>
|
|
||||||
{% for subcategory in category.children.all %}
|
|
||||||
<option value="{{ subcategory.id }}" {% if request.GET.category == subcategory.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ subcategory.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
|
||||||
<a href="{% url 'services:offering_list' %}" class="btn btn-secondary">Clear</a>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="col-md-9">
|
<section class="section">
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
<div class="container-xl mx-auto px-3 px-lg-0 pt-60 pt-lg-80 pb-40">
|
||||||
{% for offering in offerings %}
|
<div x-data="{ open: window.innerWidth > 1024 }"
|
||||||
<div class="col">
|
@resize.window="open = window.innerWidth > 1024 ? open : true" class="d-lg-flex">
|
||||||
<div class="card h-100">
|
<!-- Filters -->
|
||||||
<div class="card-body">
|
<div class="w-lg-20 flex-none">
|
||||||
<div class="d-flex align-items-start mb-3">
|
<!-- Mobile Menu -->
|
||||||
<div class="me-3">
|
<div class="page-action d-lg-none mb-40">
|
||||||
{% if offering.service.logo %}
|
<button @click="open = !open"
|
||||||
<img src="{{ offering.service.logo.url }}"
|
class="btn btn-outline-primary btn-md w-100 d-flex justify-content-center align-items-center"
|
||||||
alt="{{ offering.service.name }}"
|
type="button">
|
||||||
style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||||
{% endif %}
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3182" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0"
|
||||||
|
y="0" width="24" height="24">
|
||||||
|
<rect width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3182)">
|
||||||
|
<path d="M7 18V16H17V18H7ZM5 13V11H19V13H5ZM3 8V6H21V8H3Z" fill="#9A63EC" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="ms-2">Filters</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Desktop View -->
|
||||||
|
<div x-cloak x-show="open || window.innerWidth >= 1024" class="w-lg-85" x-collapse>
|
||||||
|
<div class="d-flex d-lg-none justify-content-between align-items-center mb-24"
|
||||||
|
role="button">
|
||||||
|
<h3 class="sidebar-dropdown__title mb-0">Filters</h3>
|
||||||
|
<span @click="open = false">
|
||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3177" style="mask-type:alpha" maskUnits="userSpaceOnUse"
|
||||||
|
x="0" y="0" width="24" height="25">
|
||||||
|
<rect y="0.5" width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3177)">
|
||||||
|
<path
|
||||||
|
d="M6.4 19.5L5 18.1L10.6 12.5L5 6.9L6.4 5.5L12 11.1L17.6 5.5L19 6.9L13.4 12.5L19 18.1L17.6 19.5L12 13.9L6.4 19.5Z"
|
||||||
|
fill="#160037" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-form position-relative mb-24">
|
||||||
|
<form method="get" x-data="{submitForm() { $refs.filterForm.submit(); } }" x-ref="filterForm">
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="mb-24">
|
||||||
|
<label for="search" class="d-none">Search</label>
|
||||||
|
<input type="text" id="search" class="input-search" placeholder="Search" name="search" value="{{ request.GET.search }}">
|
||||||
|
<button class="search-button position-absolute top-0 start-0 d-flex justify-content-center align-items-center border-0 bg-transparent p-0"
|
||||||
|
type="button" title="search">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.5 17.5L22 22" stroke="#9A63EC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path d="M20 11C20 6.02944 15.9706 2 11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C15.9706 20 20 15.9706 20 11Z"
|
||||||
|
stroke="#9A63EC" stroke-width="1.5" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Service Filter -->
|
||||||
|
<div class="pt-24 mb-24">
|
||||||
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
|
<h3 class="sidebar-title mb-0">Service</h3>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 class="card-title mb-1">
|
<select class="form-select" id="service" name="service" @change="submitForm()">
|
||||||
<a href="{{ offering.service.get_absolute_url }}" class="text-decoration-none">
|
<option value="">All Services</option>
|
||||||
{{ offering.service.name }}
|
{% for service in services %}
|
||||||
</a>
|
<option value="{{ service.id }}" {% if request.GET.service == service.id|stringformat:'i' %}selected{% endif %}>
|
||||||
</h5>
|
{{ service.name }}
|
||||||
<div class="d-flex align-items-center">
|
</option>
|
||||||
{% if offering.cloud_provider.logo %}
|
{% endfor %}
|
||||||
<a href="{{ offering.cloud_provider.get_absolute_url }}" class="me-2">
|
</select>
|
||||||
<img src="{{ offering.cloud_provider.logo.url }}"
|
</div>
|
||||||
alt="{{ offering.cloud_provider.name }}"
|
</div>
|
||||||
style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
|
||||||
</a>
|
<!-- Cloud Provider Filter -->
|
||||||
{% endif %}
|
<div class="pt-24 mb-24">
|
||||||
<small class="text-muted">
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
{{ offering.cloud_provider.name }}
|
<h3 class="sidebar-title mb-0">Cloud Provider</h3>
|
||||||
</small>
|
</div>
|
||||||
|
<div>
|
||||||
|
<select class="form-select" id="cloud_provider" name="cloud_provider" @change="submitForm()">
|
||||||
|
<option value="">All Providers</option>
|
||||||
|
{% for provider in cloud_providers %}
|
||||||
|
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
|
||||||
|
{{ provider.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Category Filter -->
|
||||||
|
<div class="pt-24 mb-24">
|
||||||
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
|
<h3 class="sidebar-title mb-0">Category</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<select class="form-select" id="category" name="category" @change="submitForm()">
|
||||||
|
<option value="">All Categories</option>
|
||||||
|
{% for category in categories %}
|
||||||
|
<option value="{{ category.id }}" {% if request.GET.category == category.id|stringformat:'i' %}selected{% endif %}>
|
||||||
|
{{ category.name }}
|
||||||
|
</option>
|
||||||
|
{% for subcategory in category.children.all %}
|
||||||
|
<option value="{{ subcategory.id }}" {% if request.GET.category == subcategory.id|stringformat:'i' %}selected{% endif %}>
|
||||||
|
{{ subcategory.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Actions -->
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a href="{% url 'services:offering_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Offerings Listing -->
|
||||||
|
<div class="section__grid flex-1">
|
||||||
|
<div class="row">
|
||||||
|
{% for offering in offerings %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-4 mb-30">
|
||||||
|
<div class="card h-100 d-flex flex-column">
|
||||||
|
<div class="card__content d-flex flex-column flex-grow-1">
|
||||||
|
<div class="card__header">
|
||||||
|
<div class="d-flex align-items-start mb-3">
|
||||||
|
<div class="me-3">
|
||||||
|
{% if offering.service.logo %}
|
||||||
|
<img src="{{ offering.service.logo.url }}"
|
||||||
|
alt="{{ offering.service.name }}"
|
||||||
|
style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="card__title">
|
||||||
|
<a href="{{ offering.get_absolute_url }}" class="text-decoration-none">
|
||||||
|
{{ offering.service.name }}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
{% if offering.cloud_provider.logo %}
|
||||||
|
<a href="{{ offering.get_absolute_url }}" class="me-2">
|
||||||
|
<img src="{{ offering.cloud_provider.logo.url }}"
|
||||||
|
alt="{{ offering.cloud_provider.name }}"
|
||||||
|
style="max-height: 30px; max-width: 100px; object-fit: contain;">
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<small class="text-muted">
|
||||||
|
{{ offering.cloud_provider.name }}
|
||||||
|
</small>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3 card__subtitle">
|
||||||
|
{% for category in offering.service.categories.all %}
|
||||||
|
<span>{{ category.full_path }}</span>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
<div class="card__desc flex-grow-1 rich-text-content">
|
||||||
{% for category in offering.service.categories.all %}
|
{{ offering.description|safe|truncatewords_html:30 }}
|
||||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rich-text-content mb-3">
|
|
||||||
{{ offering.description|safe|truncatewords_html:30 }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if offering.plans.exists %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<strong>Available Plans:</strong>
|
|
||||||
<ul class="list-unstyled small">
|
|
||||||
{% for plan in offering.plans.all %}
|
|
||||||
<li>• {{ plan.name }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="mt-auto d-flex gap-2">
|
|
||||||
<a href="{{ offering.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
|
||||||
{% if offering.plans.exists %}
|
|
||||||
{% if offering.status == 'available' %}
|
|
||||||
{% if offering.plans.count == 1 %}
|
|
||||||
{% with plan=offering.plans.first %}
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}&plan={{ plan.id }}"
|
|
||||||
class="btn btn-success">Order</a>
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
<div class="dropdown">
|
|
||||||
<button class="btn btn-success dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
|
||||||
Order
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
{% for plan in offering.plans.all %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}&plan={{ plan.id }}">
|
|
||||||
{{ plan.name }}
|
|
||||||
{% if plan.is_default %}(Recommended){% endif %}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% elif offering.status == 'planned' %}
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success">Show Interest</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success">Request Information</a>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{% if offering.status == 'available' %}
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success">Order</a>
|
|
||||||
{% elif offering.status == 'planned' %}
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success">Show Interest</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success">Request Information</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% empty %}
|
||||||
{% empty %}
|
<div class="col-12">
|
||||||
<div class="col">
|
<div class="alert alert-info">
|
||||||
<div class="alert alert-info">
|
No service offerings found matching your criteria.
|
||||||
No service offerings found matching your criteria.
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,71 +1,77 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card">
|
<section class="section bg-primary-subtle">
|
||||||
<div class="card-body">
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||||
<div class="d-flex align-items-start mb-4">
|
<div class="row align-items-center">
|
||||||
{% if partner.logo %}
|
<div class="col-12 col-lg-5 mb-47 mb-lg-0">
|
||||||
<img src="{{ partner.logo.url }}" alt="{{ partner.name }} logo" class="me-4"
|
<header class="section-primary__header">
|
||||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
<h2 class="section-h1 fs-40 fs-lg-64 mb-14">{{ partner.name }}</h2>
|
||||||
{% endif %}
|
<div class="text-gray-300 mb-14">
|
||||||
<div>
|
<div class="rich-text-content">
|
||||||
<h2 class="card-title mb-3">{{ partner.name }}</h2>
|
{{ partner.description|safe }}
|
||||||
{% if partner.website %}
|
</div>
|
||||||
<a href="{{ partner.website }}" class="btn btn-outline-primary mb-3" target="_blank">
|
</div>
|
||||||
Visit Website
|
{% if partner.website %}
|
||||||
</a>
|
<div>
|
||||||
{% endif %}
|
<a class="btn btn-primary btn-lg" href="{{ partner.website }}" target="_blank" role="button">Visit Website</a>
|
||||||
<div class="rich-text-content">
|
</div>
|
||||||
{{ partner.description|safe }}
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-7">
|
||||||
|
<div>
|
||||||
|
{% if partner.logo %}
|
||||||
|
<img class="img-fluid d-block ml-lg-auto" src="{{ partner.logo.url }}" alt="{{ partner.name }} logo">
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<h3 class="mb-4">Available Services</h3>
|
<div class="container mx-auto px-20 px-lg-0 py-60">
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
<h3 class="section-h2 fs-32 fs-lg-48 mb-40 mt-5">Available Services</h3>
|
||||||
{% for service in services %}
|
<p>{{ partner.name }} provides consulting services for the following services</p>
|
||||||
<div class="col">
|
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||||
<div class="card h-100">
|
{% for service in services %}
|
||||||
<div class="card-body">
|
<div class="col">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="card h-100">
|
||||||
{% if service.logo %}
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
{% if service.logo %}
|
||||||
|
<a href="{{ service.get_absolute_url }}">
|
||||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo"
|
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo"
|
||||||
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
||||||
{% endif %}
|
</a>
|
||||||
<div>
|
{% endif %}
|
||||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
<div>
|
||||||
<div class="d-flex align-items-center mt-2">
|
<h5 class="card-title mb-0"><a href="{{ service.get_absolute_url }}" class="text-decoration-none">{{ service.name }}</a></h5>
|
||||||
{% if service.cloud_provider.logo %}
|
<div class="d-flex align-items-center mt-2">
|
||||||
<img src="{{ service.cloud_provider.logo.url }}" alt="{{ service.cloud_provider.name }} logo"
|
{% if service.cloud_provider.logo %}
|
||||||
class="me-2" style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
<img src="{{ service.cloud_provider.logo.url }}" alt="{{ service.cloud_provider.name }} logo"
|
||||||
{% endif %}
|
class="me-2" style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
||||||
<h6 class="card-subtitle text-muted mb-0">
|
{% endif %}
|
||||||
<a href="{{ service.cloud_provider.get_absolute_url }}"
|
<h6 class="card-subtitle text-muted mb-0">
|
||||||
class="text-decoration-none text-muted">{{ service.cloud_provider.name }}</a>
|
<a href="{{ service.cloud_provider.get_absolute_url }}"
|
||||||
</h6>
|
class="text-decoration-none text-muted">{{ service.cloud_provider.name }}</a>
|
||||||
</div>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-text description-preview mb-3">
|
</div>
|
||||||
{{ service.description|safe|truncatewords_html:30 }}
|
<div class="card-text description-preview mb-3">
|
||||||
</div>
|
{{ service.description|safe|truncatewords_html:30 }}
|
||||||
<div class="mb-2">
|
|
||||||
{% for category in service.categories.all %}
|
|
||||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<a href="{{ service.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
</div>
|
||||||
<div class="col-12">
|
{% empty %}
|
||||||
<div class="alert alert-info">
|
<div class="col-12">
|
||||||
No services available from this partner yet.
|
<div class="alert alert-info">
|
||||||
</div>
|
No services available from this partner yet.
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,93 +1,163 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<section class="section bg-primary-subtle">
|
||||||
<div class="col-md-3">
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||||
<div class="card">
|
<header class="section-primary__header text-center">
|
||||||
<div class="card-body">
|
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Consulting Partners</h2>
|
||||||
<h5 class="card-title">Filters</h5>
|
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||||
<form method="get">
|
<p class="mb-0">Explore our available consulting partners</p>
|
||||||
<div class="mb-3">
|
|
||||||
<label for="search" class="form-label">Search</label>
|
|
||||||
<input type="text" class="form-control" id="search" name="search" value="{{ request.GET.search }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="cloud_provider" class="form-label">Cloud Provider</label>
|
|
||||||
<select class="form-select" id="cloud_provider" name="cloud_provider">
|
|
||||||
<option value="">All Providers</option>
|
|
||||||
{% for provider in cloud_providers %}
|
|
||||||
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ provider.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
|
||||||
<a href="{% url 'services:partner_list' %}" class="btn btn-secondary">Clear</a>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="col-md-9">
|
<section class="section">
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
<div class="container-xl mx-auto px-3 px-lg-0 pt-60 pt-lg-80 pb-40">
|
||||||
{% for partner in partners %}
|
<div x-data="{ open: window.innerWidth > 1024 }"
|
||||||
<div class="col">
|
@resize.window="open = window.innerWidth > 1024 ? open : true" class="d-lg-flex">
|
||||||
<div class="card h-100">
|
<!-- Filters -->
|
||||||
<div class="card-body">
|
<div class="w-lg-20 flex-none">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<!-- Mobile Menu -->
|
||||||
{% if partner.logo %}
|
<div class="page-action d-lg-none mb-40">
|
||||||
<img src="{{ partner.logo.url }}"
|
<button @click="open = !open"
|
||||||
alt="{{ partner.name }}"
|
class="btn btn-outline-primary btn-md w-100 d-flex justify-content-center align-items-center"
|
||||||
class="me-3" style="max-height: 60px; max-width: 120px; object-fit: contain;">
|
type="button">
|
||||||
{% endif %}
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||||
<h5 class="card-title mb-0">{{ partner.name }}</h5>
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3182" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0"
|
||||||
|
y="0" width="24" height="24">
|
||||||
|
<rect width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3182)">
|
||||||
|
<path d="M7 18V16H17V18H7ZM5 13V11H19V13H5ZM3 8V6H21V8H3Z" fill="#9A63EC" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="ms-2">Filters</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Desktop View -->
|
||||||
|
<div x-cloak x-show="open || window.innerWidth >= 1024" class="w-lg-85" x-collapse>
|
||||||
|
<div class="d-flex d-lg-none justify-content-between align-items-center mb-24"
|
||||||
|
role="button">
|
||||||
|
<h3 class="sidebar-dropdown__title mb-0">Filters</h3>
|
||||||
|
<span @click="open = false">
|
||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3177" style="mask-type:alpha" maskUnits="userSpaceOnUse"
|
||||||
|
x="0" y="0" width="24" height="25">
|
||||||
|
<rect y="0.5" width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3177)">
|
||||||
|
<path d="M6.4 19.5L5 18.1L10.6 12.5L5 6.9L6.4 5.5L12 11.1L17.6 5.5L19 6.9L13.4 12.5L19 18.1L17.6 19.5L12 13.9L6.4 19.5Z"
|
||||||
|
fill="#160037" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-form position-relative mb-24">
|
||||||
|
<form method="get" x-data="{submitForm() { $refs.filterForm.submit(); } }" x-ref="filterForm">
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="mb-24">
|
||||||
|
<label for="search" class="d-none">Search</label>
|
||||||
|
<input type="text" id="search" class="input-search" placeholder="Search" name="search" value="{{ request.GET.search }}">
|
||||||
|
<button class="search-button position-absolute top-0 start-0 d-flex justify-content-center align-items-center border-0 bg-transparent p-0"
|
||||||
|
type="button" title="search">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.5 17.5L22 22" stroke="#9A63EC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path d="M20 11C20 6.02944 15.9706 2 11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C15.9706 20 20 15.9706 20 11Z"
|
||||||
|
stroke="#9A63EC" stroke-width="1.5" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rich-text-content mb-3">
|
<!-- Service Filter -->
|
||||||
{{ partner.description|safe|truncatewords_html:50 }}
|
<div class="pt-24 mb-24">
|
||||||
</div>
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
|
<h3 class="sidebar-title mb-0">Service</h3>
|
||||||
<div class="mb-3">
|
</div>
|
||||||
<strong>Cloud Providers:</strong>
|
<div>
|
||||||
<div class="mt-2">
|
<select class="form-select" id="service" name="service" @change="submitForm()">
|
||||||
{% for provider in partner.cloud_providers.all %}
|
<option value="">All Services</option>
|
||||||
<div class="d-inline-block me-2 mb-2">
|
{% for service in services %}
|
||||||
{% if provider.logo %}
|
<option value="{{ service.id }}" {% if request.GET.service == service.id|stringformat:'i' %}selected{% endif %}>
|
||||||
<img src="{{ provider.logo.url }}"
|
{{ service.name }}
|
||||||
alt="{{ provider.name }}"
|
</option>
|
||||||
style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
{% endfor %}
|
||||||
{% else %}
|
</select>
|
||||||
<span class="badge bg-secondary">{{ provider.name }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- Cloud Provider Filter -->
|
||||||
<strong>Services Available:</strong> {{ partner.services.count }}
|
<div class="pt-24 mb-24">
|
||||||
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
|
<h3 class="sidebar-title mb-0">Cloud Provider</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<select class="form-select" id="cloud_provider" name="cloud_provider" @change="submitForm()">
|
||||||
|
<option value="">All Providers</option>
|
||||||
|
{% for provider in cloud_providers %}
|
||||||
|
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
|
||||||
|
{{ provider.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-auto">
|
<!-- Filter Actions -->
|
||||||
<a href="{{ partner.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
<div class="d-flex gap-2">
|
||||||
{% if partner.website %}
|
<a href="{% url 'services:partner_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>
|
||||||
<a href="{{ partner.website }}" class="btn btn-outline-secondary" target="_blank">Visit Website</a>
|
</div>
|
||||||
{% endif %}
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Partners Listing -->
|
||||||
|
<div class="section__grid flex-1">
|
||||||
|
<div class="row">
|
||||||
|
{% for partner in partners %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-4 mb-30">
|
||||||
|
<div class="card h-100 d-flex flex-column">
|
||||||
|
<div class="card__content d-flex flex-column flex-grow-1">
|
||||||
|
<div class="card__header">
|
||||||
|
<div class="d-flex align-items-start mb-3">
|
||||||
|
<div class="me-3">
|
||||||
|
<a href="{{ partner.get_absolute_url }}">
|
||||||
|
<img src="{{ partner.logo.url }}"
|
||||||
|
alt="{{ partner.name }}"
|
||||||
|
style="max-height: 75px; max-width: 200px; object-fit: contain;">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card__desc flex-grow-1 rich-text-content">
|
||||||
|
{{ partner.description|safe|truncatewords_html:30 }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card__footer mt-3">
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
{% if partner.website %}
|
||||||
|
<a href="{{ partner.website }}" class="btn btn-primary btn-sm" target="_blank">Visit Website</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% empty %}
|
||||||
{% empty %}
|
<div class="col-12">
|
||||||
<div class="col">
|
<div class="alert alert-info">
|
||||||
<div class="alert alert-info">
|
No consulting partners found matching your criteria.
|
||||||
No consulting partners found matching your criteria.
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,56 +1,69 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card">
|
<section class="section bg-primary-subtle">
|
||||||
<div class="card-body">
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||||
<div class="d-flex align-items-start mb-4">
|
<div class="row align-items-center">
|
||||||
{% if provider.logo %}
|
<div class="col-12 col-lg-5 mb-47 mb-lg-0">
|
||||||
<img src="{{ provider.logo.url }}" alt="{{ provider.name }} logo" class="me-4"
|
<header class="section-primary__header">
|
||||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
<h2 class="section-h1 fs-40 fs-lg-64 mb-14">{{ provider.name }}</h2>
|
||||||
{% endif %}
|
<div class="text-gray-300 mb-14">
|
||||||
<div>
|
<div class="rich-text-content">
|
||||||
<h2 class="card-title mb-3">{{ provider.name }}</h2>
|
{{ provider.description|safe }}
|
||||||
<div class="rich-text-content">
|
</div>
|
||||||
{{ provider.description|safe }}
|
</div>
|
||||||
|
{% if provider.website %}
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-primary btn-lg" href="{{ provider.website }}" target="_blank" role="button">Visit Website</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-7">
|
||||||
|
<div>
|
||||||
|
{% if provider.logo %}
|
||||||
|
<img class="img-fluid d-block ml-lg-auto" src="{{ provider.logo.url }}" alt="{{ provider.name }} logo">
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<h3 class="mb-4">Available Services</h3>
|
<div class="container mx-auto px-20 px-lg-0 py-60">
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
<h3 class="section-h2 fs-32 fs-lg-48 mb-40 mt-5">Available Services</h3>
|
||||||
{% for service in services %}
|
<p>The following services are available on {{ provider.name }} through Servala</p>
|
||||||
<div class="col">
|
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||||
<div class="card h-100">
|
{% for offering in provider.offerings.all %}
|
||||||
<div class="card-body">
|
<div class="col">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="card h-100">
|
||||||
{% if service.logo %}
|
<div class="card-body">
|
||||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo"
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
{% if offering.service.logo %}
|
||||||
|
<a href="{{ offering.get_absolute_url }}">
|
||||||
|
<img src="{{ offering.service.logo.url }}" alt="{{ offering.service.name }} logo"
|
||||||
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
||||||
{% endif %}
|
</a>
|
||||||
<div>
|
{% endif %}
|
||||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
<div>
|
||||||
</div>
|
<h5 class="card-title mb-0">
|
||||||
|
<a href="{{ offering.get_absolute_url }}" class="text-decoration-none">{{ offering.service.name }}</a>
|
||||||
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-text description-preview mb-3">
|
</div>
|
||||||
{{ service.description|safe|truncatewords_html:30 }}
|
<div class="card-text description-preview mb-3">
|
||||||
</div>
|
{{ offering.description|safe|truncatewords_html:30 }}
|
||||||
<div class="mb-2">
|
|
||||||
{% for category in service.categories.all %}
|
|
||||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<a href="{% url 'services:service_detail' service.slug %}" class="btn btn-primary">View Details</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
</div>
|
||||||
<div class="col-12">
|
{% empty %}
|
||||||
<div class="alert alert-info">
|
<div class="col-12">
|
||||||
No services available from this provider yet.
|
<div class="alert alert-info">
|
||||||
</div>
|
No services available from this provider yet.
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,68 +1,129 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<section class="section bg-primary-subtle">
|
||||||
<div class="col-md-3">
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||||
<div class="card">
|
<header class="section-primary__header text-center">
|
||||||
<div class="card-body">
|
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Cloud Providers</h2>
|
||||||
<h5 class="card-title">Filters</h5>
|
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||||
<form method="get">
|
<p class="mb-0">Explore our available cloud providers</p>
|
||||||
<div class="mb-3">
|
</div>
|
||||||
<label for="search" class="form-label">Search</label>
|
</header>
|
||||||
<input type="text" class="form-control" id="search" name="search" value="{{ request.GET.search }}">
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container-xl mx-auto px-3 px-lg-0 pt-60 pt-lg-80 pb-40">
|
||||||
|
<div x-data="{ open: window.innerWidth > 1024 }"
|
||||||
|
@resize.window="open = window.innerWidth > 1024 ? open : true" class="d-lg-flex">
|
||||||
|
<!-- Filters -->
|
||||||
|
<div class="w-lg-20 flex-none">
|
||||||
|
<!-- Mobile Menu -->
|
||||||
|
<div class="page-action d-lg-none mb-40">
|
||||||
|
<button @click="open = !open"
|
||||||
|
class="btn btn-outline-primary btn-md w-100 d-flex justify-content-center align-items-center"
|
||||||
|
type="button">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3182" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0"
|
||||||
|
y="0" width="24" height="24">
|
||||||
|
<rect width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3182)">
|
||||||
|
<path d="M7 18V16H17V18H7ZM5 13V11H19V13H5ZM3 8V6H21V8H3Z" fill="#9A63EC" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="ms-2">Filters</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Desktop View -->
|
||||||
|
<div x-cloak x-show="open || window.innerWidth >= 1024" class="w-lg-85" x-collapse>
|
||||||
|
<div class="d-flex d-lg-none justify-content-between align-items-center mb-24"
|
||||||
|
role="button">
|
||||||
|
<h3 class="sidebar-dropdown__title mb-0">Filters</h3>
|
||||||
|
<span @click="open = false">
|
||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3177" style="mask-type:alpha" maskUnits="userSpaceOnUse"
|
||||||
|
x="0" y="0" width="24" height="25">
|
||||||
|
<rect y="0.5" width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3177)">
|
||||||
|
<path d="M6.4 19.5L5 18.1L10.6 12.5L5 6.9L6.4 5.5L12 11.1L17.6 5.5L19 6.9L13.4 12.5L19 18.1L17.6 19.5L12 13.9L6.4 19.5Z"
|
||||||
|
fill="#160037" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
<div class="search-form position-relative mb-24">
|
||||||
<a href="{% url 'services:provider_list' %}" class="btn btn-secondary">Clear</a>
|
<form method="get">
|
||||||
</form>
|
<!-- Search -->
|
||||||
|
<div class="mb-24">
|
||||||
|
<label for="search" class="d-none">Search</label>
|
||||||
|
<input type="text" id="search" class="input-search" placeholder="Search" name="search" value="{{ request.GET.search }}">
|
||||||
|
<button class="search-button position-absolute top-0 start-0 d-flex justify-content-center align-items-center border-0 bg-transparent p-0"
|
||||||
|
type="button" title="search">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.5 17.5L22 22" stroke="#9A63EC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path d="M20 11C20 6.02944 15.9706 2 11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C15.9706 20 20 15.9706 20 11Z"
|
||||||
|
stroke="#9A63EC" stroke-width="1.5" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Actions -->
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a href="{% url 'services:provider_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-9">
|
<!-- Providers Listing -->
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
<div class="section__grid flex-1">
|
||||||
{% for provider in providers %}
|
<div class="row">
|
||||||
<div class="col">
|
{% for provider in providers %}
|
||||||
<div class="card h-100">
|
<div class="col-12 col-md-6 col-lg-4 mb-30">
|
||||||
<div class="card-body">
|
<div class="card h-100 d-flex flex-column">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="card__content d-flex flex-column flex-grow-1">
|
||||||
{% if provider.logo %}
|
<div class="card__header">
|
||||||
<img src="{{ provider.logo.url }}"
|
<div class="d-flex align-items-start mb-3">
|
||||||
alt="{{ provider.name }}"
|
<div class="me-3">
|
||||||
class="me-3" style="max-height: 60px; max-width: 120px; object-fit: contain;">
|
<a href="{{ provider.get_absolute_url }}">
|
||||||
{% endif %}
|
<img src="{{ provider.logo.url }}"
|
||||||
<h5 class="card-title mb-0">{{ provider.name }}</h5>
|
alt="{{ provider.name }}"
|
||||||
</div>
|
style="max-height: 70px; max-width: 200px; object-fit: contain;">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="rich-text-content mb-3">
|
<div class="card__desc flex-grow-1 rich-text-content">
|
||||||
{{ provider.description|safe|truncatewords_html:50 }}
|
{{ provider.description|safe|truncatewords_html:100 }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="card__footer mt-3">
|
||||||
<strong>Services Available:</strong> {{ provider.offerings.count }}
|
<div class="d-flex gap-2">
|
||||||
</div>
|
{% if provider.website %}
|
||||||
|
<a href="{{ provider.website }}" class="btn btn-primary btn-sm" target="_blank">Visit Website</a>
|
||||||
<div class="mb-3">
|
{% endif %}
|
||||||
<strong>Partners:</strong> {{ provider.consulting_partners.count }}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-auto">
|
|
||||||
<a href="{{ provider.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
|
||||||
{% if provider.website %}
|
|
||||||
<a href="{{ provider.website }}" class="btn btn-outline-secondary" target="_blank">Visit Website</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% empty %}
|
||||||
{% empty %}
|
<div class="col-12">
|
||||||
<div class="col">
|
<div class="alert alert-info">
|
||||||
<div class="alert alert-info">
|
No cloud providers found matching your criteria.
|
||||||
No cloud providers found matching your criteria.
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,165 +1,120 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card mb-4">
|
<section class="section">
|
||||||
<div class="card-body">
|
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||||
<div class="d-flex align-items-start mb-4">
|
<div class="row">
|
||||||
{% if service.logo %}
|
<!-- Left Sidebar -->
|
||||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo" class="me-4"
|
<div class="col-12 col-lg-3">
|
||||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
<div class="pr-lg-6">
|
||||||
{% endif %}
|
<!-- Logo -->
|
||||||
<div>
|
<div class="mb-40 border rounded-4 p-4 d-flex align-items-center justify-content-center" style="min-height: 160px;">
|
||||||
<h2 class="card-title mb-3">{{ service.name }}</h2>
|
{% if service.logo %}
|
||||||
<div class="mb-3">
|
<img class="img-fluid w-100 w-lg-auto" src="{{ service.logo.url }}" alt="{{ service.name }} logo" style="max-height: 120px; object-fit: contain;">
|
||||||
{% for category in service.categories.all %}
|
{% endif %}
|
||||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
</div>
|
||||||
{% endfor %}
|
|
||||||
|
<!-- Offerings -->
|
||||||
|
{% if service.offerings.exists %}
|
||||||
|
<div class="mb-40">
|
||||||
|
<h3 class="fw-semibold mb-12">Cloud Providers</h3>
|
||||||
|
<ul class="list-unstyled space-y-12 fs-19 ps-0">
|
||||||
|
{% for offering in service.offerings.all %}
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center text-gray-500 h-32 lh-32" href="{% url 'services:offering_detail' offering.slug %}">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cloud-fill" viewBox="0 0 16 16">
|
||||||
|
<path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383" fill="#9A63EC"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>{{ offering.cloud_provider.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Consulting Partners -->
|
||||||
|
{% if service.consulting_partners.exists %}
|
||||||
|
<div class="mb-40">
|
||||||
|
<h3 class="fw-semibold mb-12">Consulting Partners</h3>
|
||||||
|
<ul class="list-unstyled space-y-12 fs-19 ps-0">
|
||||||
|
{% for partner in service.consulting_partners.all %}
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center text-gray-500 h-32 lh-32" href="{{ partner.get_absolute_url }}">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-people-fill" viewBox="0 0 16 16">
|
||||||
|
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6m-5.784 6A2.24 2.24 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.3 6.3 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1zM4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5" fill="#9A63EC"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>{{ partner.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- External Links -->
|
||||||
|
{% if service.external_links.exists %}
|
||||||
|
<div class="mb-40">
|
||||||
|
<h3 class="fw-semibold mb-12">External Links</h3>
|
||||||
|
<ul class="list-unstyled space-y-12 fs-19 ps-0">
|
||||||
|
{% for link in service.external_links.all %}
|
||||||
|
<li>
|
||||||
|
<a class="d-flex align-items-center text-gray-500 h-32 lh-32" href="{{ link.url }}" target="_blank">
|
||||||
|
<span class="pr-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5" fill="#9A63EC"/>
|
||||||
|
<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z" fill="#9A63EC"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>{{ link.description }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="col-12 col-lg-9">
|
||||||
|
<div class="pr-lg-32">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="pt-60 pb-lg-60 w-lg-70">
|
||||||
|
<header>
|
||||||
|
<h2 class="fs-50 fw-semibold lh-1 mb-12">{{ service.name }}</h2>
|
||||||
|
</header>
|
||||||
|
<div class="fs-19 text-gray-500">
|
||||||
|
{% for category in service.categories.all %}
|
||||||
|
<button class="btn btn-tertiary btn-sm mr-12">{{ category.full_path }}</button>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<div class="pt-40 pt-lg-34">
|
||||||
|
<h3 class="fs-24 fw-semibold lh-1 mb-12">Overview</h3>
|
||||||
|
<div class="fs-19 text-gray-500">
|
||||||
|
{{ service.description|safe }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Features -->
|
||||||
|
{% if service.features %}
|
||||||
|
<div class="pt-24">
|
||||||
|
<h3 class="fs-24 fw-semibold lh-1 mb-12">Features</h3>
|
||||||
|
<div class="page-content fs-19 text-gray-500">
|
||||||
|
{{ service.features|safe }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rich-text-content mb-4">
|
|
||||||
{{ service.description|safe }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if service.features %}
|
|
||||||
<h3>Features</h3>
|
|
||||||
<div class="rich-text-content mb-4">
|
|
||||||
{{ service.features|safe }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<!-- Cloud Provider Offerings -->
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h3 class="mb-4">Available Offerings</h3>
|
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
|
||||||
{% for offering in service.offerings.all %}
|
|
||||||
<div class="col">
|
|
||||||
<div class="card h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex align-items-center mb-3">
|
|
||||||
{% if offering.cloud_provider.logo %}
|
|
||||||
<img src="{{ offering.cloud_provider.logo.url }}"
|
|
||||||
alt="{{ offering.cloud_provider.name }} logo"
|
|
||||||
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
|
||||||
{% endif %}
|
|
||||||
<div>
|
|
||||||
<h5 class="card-title mb-0">
|
|
||||||
<a href="{{ offering.cloud_provider.get_absolute_url }}" class="text-decoration-none">
|
|
||||||
{{ offering.cloud_provider.name }}
|
|
||||||
</a>
|
|
||||||
</h5>
|
|
||||||
{% if offering.cloud_provider.website %}
|
|
||||||
<a href="{{ offering.cloud_provider.website }}" class="text-muted small" target="_blank">
|
|
||||||
Visit Provider Website
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rich-text-content mb-3">
|
|
||||||
{{ offering.description|safe|truncatewords_html:50 }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if offering.plans.exists %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<h6>Plans:</h6>
|
|
||||||
{% for plan in offering.plans.all %}
|
|
||||||
<div class="card mb-2">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title">{{ plan.name }}</h6>
|
|
||||||
{% for price in plan.prices.all %}
|
|
||||||
<div class="small text-muted">
|
|
||||||
{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<a href="{% url 'services:create_lead' service.slug %}?offering={{ offering.id }}"
|
|
||||||
class="btn btn-success">
|
|
||||||
{% if offering.status == 'available' %}
|
|
||||||
Order
|
|
||||||
{% elif offering.status == 'planned' %}
|
|
||||||
Show Interest
|
|
||||||
{% else %}
|
|
||||||
Request Information
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% empty %}
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="alert alert-info d-flex justify-content-between align-items-center">
|
|
||||||
<span>No offerings available yet.</span>
|
|
||||||
<a href="{% url 'services:create_lead' service.slug %}" class="btn btn-success">Show Interest</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Consulting Partners -->
|
|
||||||
{% if service.consulting_partners.exists %}
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h3 class="mb-4">Consulting Partners</h3>
|
|
||||||
<div class="row row-cols-1 row-cols-md-3 g-4">
|
|
||||||
{% for partner in service.consulting_partners.all %}
|
|
||||||
<div class="col">
|
|
||||||
<div class="card h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex align-items-center mb-3">
|
|
||||||
{% if partner.logo %}
|
|
||||||
<img src="{{ partner.logo.url }}"
|
|
||||||
alt="{{ partner.name }} logo"
|
|
||||||
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
|
||||||
{% endif %}
|
|
||||||
<div>
|
|
||||||
<h5 class="card-title mb-0">
|
|
||||||
<a href="{{ partner.get_absolute_url }}" class="text-decoration-none">
|
|
||||||
{{ partner.name }}
|
|
||||||
</a>
|
|
||||||
</h5>
|
|
||||||
{% if partner.website %}
|
|
||||||
<a href="{{ partner.website }}" class="text-muted small" target="_blank">
|
|
||||||
Visit Website
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- External Links -->
|
|
||||||
{% if service.external_links.exists %}
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h3>Additional Information</h3>
|
|
||||||
<div class="list-group">
|
|
||||||
{% for link in service.external_links.all %}
|
|
||||||
<a href="{{ link.url }}" target="_blank" rel="noopener noreferrer"
|
|
||||||
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
||||||
{{ link.description }}
|
|
||||||
<i class="bi bi-box-arrow-up-right"></i>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,138 +1,178 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<section class="section bg-primary-subtle">
|
||||||
<div class="col-md-3">
|
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||||
<div class="card">
|
<header class="section-primary__header text-center">
|
||||||
<div class="card-body">
|
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Discover Services</h2>
|
||||||
<h5 class="card-title">Filters</h5>
|
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||||
<form method="get">
|
<p class="mb-0">Discover our service catalog</p>
|
||||||
<div class="mb-3">
|
|
||||||
<label for="search" class="form-label">Search</label>
|
|
||||||
<input type="text" class="form-control" id="search" name="search" value="{{ request.GET.search }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="category" class="form-label">Category</label>
|
|
||||||
<select class="form-select" id="category" name="category">
|
|
||||||
<option value="">All Categories</option>
|
|
||||||
{% for category in categories %}
|
|
||||||
<option value="{{ category.id }}" {% if request.GET.category == category.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ category.name }}
|
|
||||||
</option>
|
|
||||||
{% for subcategory in category.children.all %}
|
|
||||||
<option value="{{ subcategory.id }}" {% if request.GET.category == subcategory.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ subcategory.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="cloud_provider" class="form-label">Cloud Provider</label>
|
|
||||||
<select class="form-select" id="cloud_provider" name="cloud_provider">
|
|
||||||
<option value="">All Providers</option>
|
|
||||||
{% for provider in cloud_providers %}
|
|
||||||
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ provider.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="consulting_partner" class="form-label">Consulting Partner</label>
|
|
||||||
<select class="form-select" id="consulting_partner" name="consulting_partner">
|
|
||||||
<option value="">All Partners</option>
|
|
||||||
{% for partner in consulting_partners %}
|
|
||||||
<option value="{{ partner.id }}" {% if request.GET.consulting_partner == partner.id|stringformat:'i' %}selected{% endif %}>
|
|
||||||
{{ partner.name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
|
||||||
<a href="{% url 'services:service_list' %}" class="btn btn-secondary">Clear</a>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="col-md-9">
|
<section class="section">
|
||||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
<div class="container-xl mx-auto px-3 px-lg-0 pt-60 pt-lg-80 pb-40">
|
||||||
{% for service in services %}
|
<div x-data="{ open: window.innerWidth > 1024 }"
|
||||||
<div class="col">
|
@resize.window="open = window.innerWidth > 1024 ? open : true" class="d-lg-flex">
|
||||||
<div class="card h-100">
|
<!-- Filters -->
|
||||||
<div class="card-body">
|
<div class="w-lg-20 flex-none">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<!-- Mobile Menu -->
|
||||||
{% if service.logo %}
|
<div class="page-action d-lg-none mb-40">
|
||||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo" class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
<button @click="open = !open"
|
||||||
{% endif %}
|
class="btn btn-outline-primary btn-md w-100 d-flex justify-content-center align-items-center"
|
||||||
|
type="button">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3182" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0"
|
||||||
|
y="0" width="24" height="24">
|
||||||
|
<rect width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3182)">
|
||||||
|
<path d="M7 18V16H17V18H7ZM5 13V11H19V13H5ZM3 8V6H21V8H3Z" fill="#9A63EC" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="ms-2">Filters</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Desktop View -->
|
||||||
|
<div x-cloak x-show="open || window.innerWidth >= 1024" class="w-lg-85" x-collapse>
|
||||||
|
<div class="d-flex d-lg-none justify-content-between align-items-center mb-24"
|
||||||
|
role="button">
|
||||||
|
<h3 class="sidebar-dropdown__title mb-0">Filters</h3>
|
||||||
|
<span @click="open = false">
|
||||||
|
<svg width="24" height="25" viewBox="0 0 24 25" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<mask id="mask0_115_3177" style="mask-type:alpha" maskUnits="userSpaceOnUse"
|
||||||
|
x="0" y="0" width="24" height="25">
|
||||||
|
<rect y="0.5" width="24" height="24" fill="#D9D9D9" />
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_115_3177)">
|
||||||
|
<path
|
||||||
|
d="M6.4 19.5L5 18.1L10.6 12.5L5 6.9L6.4 5.5L12 11.1L17.6 5.5L19 6.9L13.4 12.5L19 18.1L17.6 19.5L12 13.9L6.4 19.5Z"
|
||||||
|
fill="#160037" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-form position-relative mb-24">
|
||||||
|
<form method="get" x-data="{submitForm() { $refs.filterForm.submit(); } }" x-ref="filterForm">
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="mb-24">
|
||||||
|
<label for="search" class="d-none">Search</label>
|
||||||
|
<input type="text" id="search" class="input-search" placeholder="Search" name="search" value="{{ request.GET.search }}">
|
||||||
|
<button class="search-button position-absolute top-0 start-0 d-flex justify-content-center align-items-center border-0 bg-transparent p-0"
|
||||||
|
type="button" title="search">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.5 17.5L22 22" stroke="#9A63EC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path d="M20 11C20 6.02944 15.9706 2 11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C15.9706 20 20 15.9706 20 11Z"
|
||||||
|
stroke="#9A63EC" stroke-width="1.5" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Category Filter -->
|
||||||
|
<div class="pt-24 mb-24">
|
||||||
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
|
<h3 class="sidebar-title mb-0">Category</h3>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
<select class="form-select" id="category" name="category" @change="submitForm()">
|
||||||
<div class="mt-2">
|
<option value="">All Categories</option>
|
||||||
{% for offering in service.offerings.all %}
|
{% for category in categories %}
|
||||||
<div class="d-inline-block me-2">
|
<option value="{{ category.id }}" {% if request.GET.category == category.id|stringformat:'i' %}selected{% endif %}>
|
||||||
{% if offering.cloud_provider.logo %}
|
{{ category.name }}
|
||||||
<a href="{% url 'services:provider_detail' offering.cloud_provider.slug %}" title="{{ offering.cloud_provider.name }}">
|
</option>
|
||||||
<img src="{{ offering.cloud_provider.logo.url }}"
|
{% if category.children.all %}
|
||||||
alt="{{ offering.cloud_provider.name }}"
|
{% for subcategory in category.children.all %}
|
||||||
style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
<option value="{{ subcategory.id }}" {% if request.GET.category == subcategory.id|stringformat:'i' %}selected{% endif %}>
|
||||||
</a>
|
{{ subcategory.name }}
|
||||||
{% else %}
|
</option>
|
||||||
<a href="{% url 'services:provider_detail' offering.cloud_provider.slug %}"
|
{% endfor %}
|
||||||
class="badge bg-secondary text-decoration-none">
|
{% endif %}
|
||||||
{{ offering.cloud_provider.name }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-2">
|
|
||||||
{% for category in service.categories.all %}
|
|
||||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<p class="card-text">{{ service.description|safe|truncatewords:30 }}</p>
|
|
||||||
|
|
||||||
<div class="mt-3">
|
<!-- Consulting Partners Filter -->
|
||||||
<a href="{{ service.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
<div class="pt-24 mb-24">
|
||||||
{% if service.offerings.exists %}
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
<div class="dropdown d-inline-block">
|
<h3 class="sidebar-title mb-0">Consulting Partners</h3>
|
||||||
<button class="btn btn-success dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
</div>
|
||||||
Order
|
<div>
|
||||||
</button>
|
<select class="form-select" id="consulting_partner" name="consulting_partner" @change="submitForm()">
|
||||||
<ul class="dropdown-menu">
|
<option value="">All Partners</option>
|
||||||
{% for offering in service.offerings.all %}
|
{% for partner in consulting_partners %}
|
||||||
<li>
|
<option value="{{ partner.id }}" {% if request.GET.consulting_partner == partner.id|stringformat:'i' %}selected{% endif %}>
|
||||||
<a class="dropdown-item" href="{% url 'services:create_lead' service.slug %}?offering={{ offering.id }}">
|
{{ partner.name }}
|
||||||
via {{ offering.cloud_provider.name }}
|
</option>
|
||||||
</a>
|
{% endfor %}
|
||||||
</li>
|
</select>
|
||||||
{% endfor %}
|
</div>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
|
||||||
{% else %}
|
<!-- Cloud Providers Filter -->
|
||||||
<a href="{% url 'services:create_lead' service.slug %}" class="btn btn-success">
|
<div class="pt-24 mb-24">
|
||||||
Show Interest
|
<div class="d-flex justify-content-between align-items-center h-33 mb-5px" role="button">
|
||||||
</a>
|
<h3 class="sidebar-title mb-0">Cloud Providers</h3>
|
||||||
{% endif %}
|
</div>
|
||||||
|
<div>
|
||||||
|
<select class="form-select" id="cloud_provider" name="cloud_provider" @change="submitForm()">
|
||||||
|
<option value="">All Providers</option>
|
||||||
|
{% for provider in cloud_providers %}
|
||||||
|
<option value="{{ provider.id }}" {% if request.GET.cloud_provider == provider.id|stringformat:'i' %}selected{% endif %}>
|
||||||
|
{{ provider.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Actions -->
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<a href="{% url 'services:service_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Service Listing -->
|
||||||
|
<div class="section__grid flex-1">
|
||||||
|
<div class="row">
|
||||||
|
{% for service in services %}
|
||||||
|
<div class="col-12 col-md-6 col-lg-4 mb-30">
|
||||||
|
<div class="card h-100 d-flex flex-column">
|
||||||
|
{% if service.logo %}
|
||||||
|
<div class="card__image flex-shrink-0">
|
||||||
|
<a href="{{ service.get_absolute_url }}">
|
||||||
|
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo" class="img-fluid">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="card__content d-flex flex-column flex-grow-1">
|
||||||
|
<div class="card__header">
|
||||||
|
<h3 class="card__title"><a href="{{ service.get_absolute_url }}" class="text-decoration-none">{{ service.name }}</a></h3>
|
||||||
|
<p class="card__subtitle">
|
||||||
|
{% for category in service.categories.all %}
|
||||||
|
<span>{{ category.full_path }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card__desc flex-grow-1">
|
||||||
|
<p class="mb-0">{{ service.description|safe|truncatewords:30 }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
</div>
|
||||||
<div class="col">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
No services found matching your criteria.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -1,31 +1,81 @@
|
||||||
{% extends 'services/base.html' %}
|
{% extends 'services/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row justify-content-center">
|
<section class="section">
|
||||||
<div class="col-md-8">
|
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||||
<div class="card">
|
<div class="d-lg-flex">
|
||||||
<div class="card-body text-center">
|
<div class="flex-1 pr-lg-40 mb-40 mb-lg-0">
|
||||||
<h2 class="card-title mb-4">Thank You!</h2>
|
<div class="bg-gray-50 rounded-20 py-40 px-20 px-lg-40 d-flex justify-content-center align-items-center h-100">
|
||||||
|
<div class="text-center">
|
||||||
<div class="mb-4">
|
<div class="mb-20">
|
||||||
<p class="lead">Thank you for your interest in {{ service.name }}!</p>
|
<svg class="mx-auto d-block" width="101" height="102" viewBox="0 0 101 102" fill="none"
|
||||||
<p>We have received your inquiry and our team will contact you shortly.</p>
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_8_818)">
|
||||||
|
<path d="M50.5 101.5C78.3904 101.5 101 78.8904 101 51C101 23.1096 78.3904 0.5 50.5 0.5C22.6096 0.5 0 23.1096 0 51C0 78.8904 22.6096 101.5 50.5 101.5Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
<path d="M37.5957 73.7808L63.5626 99.7476C85.0689 94.0126 100.999 74.418 100.999 51C100.999 50.5221 100.999 50.0442 100.999 49.5662L80.6083 30.7681L37.5957 73.7808Z"
|
||||||
|
fill="#9A63EC" />
|
||||||
|
<path d="M51.7752 62.3107C54.0054 64.541 54.0054 68.3644 51.7752 70.5946L47.1553 75.2145C44.925 77.4448 41.1017 77.4448 38.8714 75.2145L18.6395 54.8233C16.4092 52.5931 16.4092 48.7697 18.6395 46.5394L23.2594 41.9196C25.4897 39.6893 29.313 39.6893 31.5433 41.9196L51.7752 62.3107Z"
|
||||||
|
fill="white" />
|
||||||
|
<path d="M69.4583 27.1041C71.6886 24.8738 75.5119 24.8738 77.7422 27.1041L82.3621 31.724C84.5924 33.9543 84.5924 37.7776 82.3621 40.0079L47.3148 74.8959C45.0845 77.1262 41.2612 77.1262 39.0309 74.8959L34.411 70.276C32.1807 68.0457 32.1807 64.2224 34.411 61.9921L69.4583 27.1041Z"
|
||||||
|
fill="white" />
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_8_818">
|
||||||
|
<rect width="101" height="101" fill="white" transform="translate(0 0.5)" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<header class="mb-20">
|
||||||
|
<h2 class="fs-32 fs-lg-40 fw-semibold mb-20">Inquiry Received Successfully!</h2>
|
||||||
|
<div class="fs-base text-gray-600 w-lg-75 mx-auto">
|
||||||
|
<p class="mb-0">Thank you for your interest in {{ service.name }}! We have received your inquiry and our team will contact you shortly. A confirmation email will be sent to your provided email address.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'services:service_list' %}" class="btn btn-primary btn-lg w-100 w-md-auto" role="button">Browse More Services</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="mb-4">
|
<div class="w-lg-34 bg-purple-50 rounded-16 p-24 d-flex flex-column justify-content-between">
|
||||||
<p class="text-muted">A confirmation email will be sent to your provided email address.</p>
|
<div class="d-flex align-items-center mb-24">
|
||||||
|
<div class="card__image mb-0">
|
||||||
|
{% if service.image %}
|
||||||
|
<img class="img-fluid" src="{{ service.image.url }}" alt="{{ service.name }}">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="card__header ps-16">
|
||||||
|
<h3 class="card__title">{{ service.name }}</h3>
|
||||||
|
<p class="card__subtitle mb-0">{{ service.category }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if service.description %}
|
||||||
<div class="mt-4">
|
<div class="mb-24">
|
||||||
<a href="{% url 'services:service_detail' service.slug %}" class="btn btn-primary me-2">
|
<div class="text-black">
|
||||||
Back to Service Details
|
<p class="mb-0">{{ service.description|safe }}</p>
|
||||||
</a>
|
</div>
|
||||||
<a href="{% url 'services:service_list' %}" class="btn btn-secondary">
|
|
||||||
Browse More Services
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if service.pricing_plans %}
|
||||||
|
<div>
|
||||||
|
{% for plan in service.pricing_plans %}
|
||||||
|
<div class="bg-white border-all rounded-7 p-20 {% if not forloop.last %}mb-12{% endif %}">
|
||||||
|
<h3 class="text-purple fs-18 fw-semibold lh-1-7 mb-0">{{ plan.name }}</h3>
|
||||||
|
<div>
|
||||||
|
<ul class="list-unstyled text-gray-500 fs-14 lh-1-7 ps-0 mb-0">
|
||||||
|
{% for price in plan.prices %}
|
||||||
|
<li>{{ price.amount }} {{ price.currency }} per {{ price.interval }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
0
hub/services/templatetags/__init__.py
Normal file
0
hub/services/templatetags/__init__.py
Normal file
8
hub/services/templatetags/form_tags.py
Normal file
8
hub/services/templatetags/form_tags.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from django import template
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(name="addclass")
|
||||||
|
def addclass(value, arg):
|
||||||
|
return value.as_widget(attrs={"class": arg})
|
|
@ -1,10 +1,6 @@
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from hub.services.models import (
|
from hub.services.models import ServiceOffering, CloudProvider, Category, Service
|
||||||
ServiceOffering,
|
|
||||||
CloudProvider,
|
|
||||||
Category,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def offering_list(request):
|
def offering_list(request):
|
||||||
|
@ -22,6 +18,7 @@ def offering_list(request):
|
||||||
|
|
||||||
cloud_providers = CloudProvider.objects.all()
|
cloud_providers = CloudProvider.objects.all()
|
||||||
categories = Category.objects.filter(parent=None).prefetch_related("children")
|
categories = Category.objects.filter(parent=None).prefetch_related("children")
|
||||||
|
services = Service.objects.all().order_by("name")
|
||||||
|
|
||||||
# Handle cloud provider filter
|
# Handle cloud provider filter
|
||||||
if request.GET.get("cloud_provider"):
|
if request.GET.get("cloud_provider"):
|
||||||
|
@ -37,6 +34,11 @@ def offering_list(request):
|
||||||
Q(service__categories=category) | Q(service__categories__in=subcategories)
|
Q(service__categories=category) | Q(service__categories__in=subcategories)
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
|
# Handle service filter
|
||||||
|
if request.GET.get("service"):
|
||||||
|
service_id = request.GET.get("service")
|
||||||
|
offerings = offerings.filter(service_id=service_id)
|
||||||
|
|
||||||
# Handle search
|
# Handle search
|
||||||
if request.GET.get("search"):
|
if request.GET.get("search"):
|
||||||
query = request.GET.get("search")
|
query = request.GET.get("search")
|
||||||
|
@ -50,6 +52,7 @@ def offering_list(request):
|
||||||
"offerings": offerings,
|
"offerings": offerings,
|
||||||
"cloud_providers": cloud_providers,
|
"cloud_providers": cloud_providers,
|
||||||
"categories": categories,
|
"categories": categories,
|
||||||
|
"services": services,
|
||||||
}
|
}
|
||||||
return render(request, "services/offering_list.html", context)
|
return render(request, "services/offering_list.html", context)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,22 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from hub.services.models import Service, CloudProvider, ConsultingPartner
|
||||||
|
|
||||||
|
|
||||||
def homepage(request):
|
def homepage(request):
|
||||||
return render(request, "services/homepage.html")
|
featured_services = Service.objects.filter(is_featured=True).prefetch_related(
|
||||||
|
"categories"
|
||||||
|
)[:4]
|
||||||
|
|
||||||
|
featured_providers = CloudProvider.objects.filter(is_featured=True)[:4]
|
||||||
|
|
||||||
|
featured_partners = ConsultingPartner.objects.filter(
|
||||||
|
is_featured=True
|
||||||
|
).prefetch_related("services", "cloud_providers")[:4]
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"featured_services": featured_services,
|
||||||
|
"featured_providers": featured_providers,
|
||||||
|
"featured_partners": featured_partners,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "services/homepage.html", context)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from hub.services.models import (
|
from hub.services.models import ConsultingPartner, CloudProvider, Service
|
||||||
ConsultingPartner,
|
|
||||||
CloudProvider,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def partner_list(request):
|
def partner_list(request):
|
||||||
|
@ -11,11 +8,18 @@ def partner_list(request):
|
||||||
"services", "cloud_providers"
|
"services", "cloud_providers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
services = Service.objects.all().order_by("name")
|
||||||
|
|
||||||
# Handle cloud provider filter
|
# Handle cloud provider filter
|
||||||
if request.GET.get("cloud_provider"):
|
if request.GET.get("cloud_provider"):
|
||||||
provider_id = request.GET.get("cloud_provider")
|
provider_id = request.GET.get("cloud_provider")
|
||||||
partners = partners.filter(cloud_providers__id=provider_id)
|
partners = partners.filter(cloud_providers__id=provider_id)
|
||||||
|
|
||||||
|
# Handle service filter
|
||||||
|
if request.GET.get("service"):
|
||||||
|
service_id = request.GET.get("service")
|
||||||
|
partners = partners.filter(services__id=service_id)
|
||||||
|
|
||||||
# Handle search
|
# Handle search
|
||||||
if request.GET.get("search"):
|
if request.GET.get("search"):
|
||||||
query = request.GET.get("search")
|
query = request.GET.get("search")
|
||||||
|
@ -25,6 +29,7 @@ def partner_list(request):
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"partners": partners,
|
"partners": partners,
|
||||||
|
"services": services,
|
||||||
"cloud_providers": CloudProvider.objects.all(),
|
"cloud_providers": CloudProvider.objects.all(),
|
||||||
}
|
}
|
||||||
return render(request, "services/partner_list.html", context)
|
return render(request, "services/partner_list.html", context)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue