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:
|
||||
name: prod
|
||||
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,
|
||||
blank=True,
|
||||
)
|
||||
is_featured = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -105,6 +106,7 @@ class Service(models.Model):
|
|||
)
|
||||
categories = models.ManyToManyField(Category, related_name="services")
|
||||
features = ProseEditorField()
|
||||
is_featured = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
@ -139,6 +141,7 @@ class ConsultingPartner(models.Model):
|
|||
cloud_providers = models.ManyToManyField(
|
||||
CloudProvider, related_name="consulting_partners", blank=True
|
||||
)
|
||||
is_featured = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=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 name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<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" type="text/css" href='{% static "css/bootstrap.min.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>
|
||||
<link rel="stylesheet" type="text/css" href='{% static "css/servala-main.css" %}'>
|
||||
{% block extra_css %}{% endblock %}
|
||||
|
||||
<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>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'services:homepage' %}">Servala</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
<div class="overflow-hidden">
|
||||
<header x-data="{sideNav: false, atTop: true}" class="site-header position-relative">
|
||||
<div class="header-nav" :class="{ 'header-nav--top': atTop, 'header-nav--fixed': !atTop }"
|
||||
x-on:scroll.window="atTop = (window.pageYOffset > 200) ? false : true;">
|
||||
<div class="container-xl mx-auto px-3 px-lg-0 position-relative">
|
||||
<div class="nav__wrapper d-flex justify-content-between align-items-center">
|
||||
<div class="nav__brand logo">
|
||||
<a class="navbar__logo" href="{% url 'services:homepage' %}" title="logo">
|
||||
<img src="{% static "img/header-logo.png" %}" alt="Servala Logo" width="191" height="43">
|
||||
</a>
|
||||
</div>
|
||||
<div x-cloak class="nav__menu" :class="sideNav ? 'nav__menu-active' : 'nav__menu-hidden'">
|
||||
<nav class="navbar d-lg-flex justify-content-lg-end align-items-lg-center">
|
||||
<ul class="navbar__menu menu mr-lg-27">
|
||||
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:homepage' %}">Home</a></li>
|
||||
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:service_list' %}">Services</a></li>
|
||||
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:offering_list' %}">Offerings</a></li>
|
||||
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:provider_list' %}">Cloud Providers</a></li>
|
||||
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:partner_list' %}">Consulting Partners</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="nav__toggle">
|
||||
<button @click="sideNav = !sideNav" name="menu" class="nav__button" role="button">
|
||||
<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 class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:service_list' %}active{% endif %}"
|
||||
href="{% url 'services:service_list' %}">Services</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
|
||||
<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 class="nav-item">
|
||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:offering_list' %}active{% endif %}"
|
||||
href="{% url 'services:offering_list' %}">Service Offerings</a>
|
||||
<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 class="nav-item">
|
||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:provider_list' %}active{% endif %}"
|
||||
href="{% url 'services:provider_list' %}">Cloud Providers</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.resolver_match.view_name == 'services:partner_list' %}active{% endif %}"
|
||||
href="{% url 'services:partner_list' %}">Consulting Partners</a>
|
||||
<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>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<script src="{% static "js/bootstrap.bundle.min.js" %}"></script>
|
||||
</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>
|
||||
</html>
|
|
@ -2,17 +2,184 @@
|
|||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="px-4 py-5 my-5 text-center">
|
||||
<img class="d-block mx-auto mb-4" src="{% static "img/servala-logo.png" %}" alt="" height="150">
|
||||
<h1 class="display-5 fw-bold text-body-emphasis">The Cloud Native Service Hub</h1>
|
||||
<div class="col-lg-6 mx-auto">
|
||||
<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>
|
||||
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
|
||||
<a href="{% url 'services:service_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Services</button></a>
|
||||
<a href="{% url 'services:offering_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Offerings</button></a>
|
||||
<a href="{% url 'services:provider_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Cloud Providers</button></a>
|
||||
<a href="{% url 'services:partner_list' %}"><button type="button" class="btn btn-primary btn-lg px-4 gap-3">Discover Consulting</button></a>
|
||||
<section class="section section-hero bg-primary-subtle">
|
||||
<div class="section-wrapper container mx-auto position-relative">
|
||||
<div class="section-hero-mask"></div>
|
||||
<div class="px-3 px-lg-0 pt-80 pb-120 position-relative">
|
||||
<header class="section-hero__header">
|
||||
<h1 class="section-h1 fs-40 fs-lg-64">Servala - The Cloud Native Service Hub</h1>
|
||||
<div class="section-hero__desc">
|
||||
<p>Unlock the Power of Cloud Native Applications.</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: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>
|
||||
</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 %}
|
|
@ -1,46 +1,22 @@
|
|||
{% extends 'services/base.html' %}
|
||||
{% load form_tags %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-4">Interested in {{ service.name }}</h2>
|
||||
|
||||
{% if selected_offering %}
|
||||
<div class="mb-4">
|
||||
<h5>Service Details</h5>
|
||||
{% if selected_offering %}
|
||||
<p><strong>Provider:</strong> {{ selected_offering.cloud_provider.name }}</p>
|
||||
{% endif %}
|
||||
{% if selected_plan %}
|
||||
<p><strong>Plan:</strong> {{ selected_plan.name }}</p>
|
||||
{% if selected_plan.prices.exists %}
|
||||
<p><strong>Pricing:</strong></p>
|
||||
<ul class="list-unstyled">
|
||||
{% for price in selected_plan.prices.all %}
|
||||
<li>{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<section class="section">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||
<div class="d-lg-flex">
|
||||
<div class="flex-1 pr-lg-40 mb-40 mb-lg-0">
|
||||
<div class="bg-gray-50 rounded-20 p-40">
|
||||
<header>
|
||||
<h2 class="fs-44 fw-semibold mb-40">Enter your details</h2>
|
||||
</header>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.name.id_for_label }}" class="form-label">Name</label>
|
||||
{{ form.name }}
|
||||
<div class="mb-40">
|
||||
<label for="{{ form.name.id_for_label }}" class="form-label text-purple">Your Name</label>
|
||||
{{ form.name|addclass:"form-control" }}
|
||||
{% if form.name.errors %}
|
||||
<div class="invalid-feedback d-block">
|
||||
{{ form.name.errors }}
|
||||
|
@ -48,19 +24,9 @@
|
|||
{% 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 }}
|
||||
<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 }}
|
||||
|
@ -68,9 +34,9 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.phone.id_for_label }}" class="form-label">Phone</label>
|
||||
{{ form.phone }}
|
||||
<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 }}
|
||||
|
@ -78,9 +44,19 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.message.id_for_label }}" class="form-label">Message (Optional)</label>
|
||||
{{ form.message }}
|
||||
<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 }}
|
||||
|
@ -89,12 +65,45 @@
|
|||
</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>
|
||||
<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>
|
||||
<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 %}
|
||||
<div>
|
||||
<ul class="list-unstyled text-gray-500 fs-14 lh-1-7 ps-0 mb-0">
|
||||
{% for price in selected_plan.prices.all %}
|
||||
<li>{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,74 +1,143 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div class="d-flex align-items-start">
|
||||
<section class="section">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||
<div class="row">
|
||||
<!-- Left Sidebar -->
|
||||
<div class="col-12 col-lg-3">
|
||||
<div class="pr-lg-6">
|
||||
<!-- Logo -->
|
||||
<div class="mb-40 border rounded-4 p-4 d-flex align-items-center justify-content-center" style="min-height: 160px;">
|
||||
{% if offering.service.logo %}
|
||||
<img src="{{ offering.service.logo.url }}" alt="{{ offering.service.name }} logo" class="me-4"
|
||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<div>
|
||||
<h2 class="card-title mb-2">{{ offering.service.name }}</h2>
|
||||
<h4 class="text-muted">
|
||||
on
|
||||
<a href="{{ offering.cloud_provider.get_absolute_url }}" class="text-decoration-none">
|
||||
{{ offering.cloud_provider.name }}
|
||||
</a>
|
||||
</h4>
|
||||
</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;">
|
||||
<img class="img-fluid w-100 w-lg-auto" src="{{ offering.service.logo.url }}"
|
||||
alt="{{ offering.service.name }} logo" style="max-height: 120px; object-fit: contain;">
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="rich-text-content mb-4">
|
||||
<!-- Highlights -->
|
||||
{% 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>
|
||||
|
||||
<!-- 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>
|
||||
{% if offering.cloud_provider.logo %}
|
||||
<p class="mb-6"><a href="{{ offering.cloud_provider.website }}" target="_blank">
|
||||
<img class="img-fluid" src="{{ offering.cloud_provider.logo.url }}"
|
||||
alt="{{ offering.cloud_provider.name }} logo" style="max-height: 40px;"></a>
|
||||
</p>
|
||||
{% 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>
|
||||
|
||||
<!-- 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">
|
||||
{{ offering.description|safe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plans -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h3 class="mb-4">Available Plans</h3>
|
||||
<div class="row row-cols-1 row-cols-md-3 g-4">
|
||||
<!-- 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">
|
||||
<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 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>
|
||||
{% 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 %}
|
||||
|
||||
<div class="mb-3">
|
||||
<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 %}
|
||||
<div class="mb-2">
|
||||
<strong>{{ price.currency.symbol }}{{ price.price }}</strong>
|
||||
{{ price.currency.code }} per {{ price.term.name }}
|
||||
</div>
|
||||
<li>{{ price.currency.symbol }}{{ price.price }} {{ price.currency.code }} per {{ price.term.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<a href="{% url 'services:create_lead' offering.service.slug %}?offering={{ offering.id }}&plan={{ plan.id }}"
|
||||
class="btn btn-success">Select This Plan</a>
|
||||
</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>
|
||||
|
@ -83,5 +152,9 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,20 +1,102 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filters</h5>
|
||||
<form method="get">
|
||||
<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 }}">
|
||||
<section class="section bg-primary-subtle">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||
<header class="section-primary__header text-center">
|
||||
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Service Offerings</h2>
|
||||
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||
<p class="mb-0">Explore our available service offerings</p>
|
||||
</div>
|
||||
</header>
|
||||
</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 class="mb-3">
|
||||
<label for="cloud_provider" class="form-label">Cloud Provider</label>
|
||||
<select class="form-select" id="cloud_provider" name="cloud_provider">
|
||||
<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>
|
||||
<select class="form-select" id="service" name="service" @change="submitForm()">
|
||||
<option value="">All Services</option>
|
||||
{% for service in services %}
|
||||
<option value="{{ service.id }}" {% if request.GET.service == service.id|stringformat:'i' %}selected{% endif %}>
|
||||
{{ service.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cloud Provider 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">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 %}>
|
||||
|
@ -23,10 +105,15 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="category" class="form-label">Category</label>
|
||||
<select class="form-select" id="category" name="category">
|
||||
<!-- 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 %}>
|
||||
|
@ -40,20 +127,25 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
<a href="{% url 'services:offering_list' %}" class="btn btn-secondary">Clear</a>
|
||||
<!-- 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>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||
<!-- Offerings Listing -->
|
||||
<div class="section__grid flex-1">
|
||||
<div class="row">
|
||||
{% for offering in offerings %}
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<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 %}
|
||||
|
@ -63,99 +155,42 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="card-title mb-1">
|
||||
<a href="{{ offering.service.get_absolute_url }}" class="text-decoration-none">
|
||||
<h3 class="card__title">
|
||||
<a href="{{ offering.get_absolute_url }}" class="text-decoration-none">
|
||||
{{ offering.service.name }}
|
||||
</a>
|
||||
</h5>
|
||||
</h3>
|
||||
<div class="d-flex align-items-center">
|
||||
{% if offering.cloud_provider.logo %}
|
||||
<a href="{{ offering.cloud_provider.get_absolute_url }}" class="me-2">
|
||||
<a href="{{ offering.get_absolute_url }}" class="me-2">
|
||||
<img src="{{ offering.cloud_provider.logo.url }}"
|
||||
alt="{{ offering.cloud_provider.name }}"
|
||||
style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
||||
style="max-height: 30px; max-width: 100px; object-fit: contain;">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<small class="text-muted">
|
||||
{{ offering.cloud_provider.name }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<div class="mb-3 card__subtitle">
|
||||
{% for category in offering.service.categories.all %}
|
||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
||||
<span>{{ category.full_path }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-content mb-3">
|
||||
<div class="card__desc flex-grow-1 rich-text-content">
|
||||
{{ 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>
|
||||
{% 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>
|
||||
{% empty %}
|
||||
<div class="col">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
No service offerings found matching your criteria.
|
||||
</div>
|
||||
|
@ -163,5 +198,7 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,27 +1,38 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start mb-4">
|
||||
{% if partner.logo %}
|
||||
<img src="{{ partner.logo.url }}" alt="{{ partner.name }} logo" class="me-4"
|
||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<div>
|
||||
<h2 class="card-title mb-3">{{ partner.name }}</h2>
|
||||
{% if partner.website %}
|
||||
<a href="{{ partner.website }}" class="btn btn-outline-primary mb-3" target="_blank">
|
||||
Visit Website
|
||||
</a>
|
||||
{% endif %}
|
||||
<section class="section bg-primary-subtle">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-12 col-lg-5 mb-47 mb-lg-0">
|
||||
<header class="section-primary__header">
|
||||
<h2 class="section-h1 fs-40 fs-lg-64 mb-14">{{ partner.name }}</h2>
|
||||
<div class="text-gray-300 mb-14">
|
||||
<div class="rich-text-content">
|
||||
{{ partner.description|safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% if partner.website %}
|
||||
<div>
|
||||
<a class="btn btn-primary btn-lg" href="{{ partner.website }}" target="_blank" role="button">Visit Website</a>
|
||||
</div>
|
||||
{% 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>
|
||||
</section>
|
||||
|
||||
<h3 class="mb-4">Available Services</h3>
|
||||
<div class="container mx-auto px-20 px-lg-0 py-60">
|
||||
<h3 class="section-h2 fs-32 fs-lg-48 mb-40 mt-5">Available Services</h3>
|
||||
<p>{{ partner.name }} provides consulting services for the following services</p>
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||
{% for service in services %}
|
||||
<div class="col">
|
||||
|
@ -29,11 +40,13 @@
|
|||
<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"
|
||||
class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
||||
</a>
|
||||
{% endif %}
|
||||
<div>
|
||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
||||
<h5 class="card-title mb-0"><a href="{{ service.get_absolute_url }}" class="text-decoration-none">{{ service.name }}</a></h5>
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
{% if service.cloud_provider.logo %}
|
||||
<img src="{{ service.cloud_provider.logo.url }}" alt="{{ service.cloud_provider.name }} logo"
|
||||
|
@ -49,12 +62,6 @@
|
|||
<div class="card-text description-preview mb-3">
|
||||
{{ service.description|safe|truncatewords_html:30 }}
|
||||
</div>
|
||||
<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>
|
||||
|
@ -66,6 +73,5 @@
|
|||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,20 +1,101 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filters</h5>
|
||||
<form method="get">
|
||||
<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 }}">
|
||||
<section class="section bg-primary-subtle">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||
<header class="section-primary__header text-center">
|
||||
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Consulting Partners</h2>
|
||||
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||
<p class="mb-0">Explore our available consulting partners</p>
|
||||
</div>
|
||||
</header>
|
||||
</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 class="mb-3">
|
||||
<label for="cloud_provider" class="form-label">Cloud Provider</label>
|
||||
<select class="form-select" id="cloud_provider" name="cloud_provider">
|
||||
<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>
|
||||
<select class="form-select" id="service" name="service" @change="submitForm()">
|
||||
<option value="">All Services</option>
|
||||
{% for service in services %}
|
||||
<option value="{{ service.id }}" {% if request.GET.service == service.id|stringformat:'i' %}selected{% endif %}>
|
||||
{{ service.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cloud Provider 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">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 %}>
|
||||
|
@ -23,65 +104,52 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
<a href="{% url 'services:partner_list' %}" class="btn btn-secondary">Clear</a>
|
||||
<!-- Filter Actions -->
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'services:partner_list' %}" class="btn btn-outline-secondary btn-sm">Clear</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||
<!-- Partners Listing -->
|
||||
<div class="section__grid flex-1">
|
||||
<div class="row">
|
||||
{% for partner in partners %}
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
{% if partner.logo %}
|
||||
<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 }}"
|
||||
class="me-3" style="max-height: 60px; max-width: 120px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<h5 class="card-title mb-0">{{ partner.name }}</h5>
|
||||
style="max-height: 75px; max-width: 200px; object-fit: contain;">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-content mb-3">
|
||||
{{ partner.description|safe|truncatewords_html:50 }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Cloud Providers:</strong>
|
||||
<div class="mt-2">
|
||||
{% for provider in partner.cloud_providers.all %}
|
||||
<div class="d-inline-block me-2 mb-2">
|
||||
{% if provider.logo %}
|
||||
<img src="{{ provider.logo.url }}"
|
||||
alt="{{ provider.name }}"
|
||||
style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ provider.name }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Services Available:</strong> {{ partner.services.count }}
|
||||
<div class="card__desc flex-grow-1 rich-text-content">
|
||||
{{ partner.description|safe|truncatewords_html:30 }}
|
||||
</div>
|
||||
|
||||
<div class="mt-auto">
|
||||
<a href="{{ partner.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
||||
<div class="card__footer mt-3">
|
||||
<div class="d-flex gap-2">
|
||||
{% if partner.website %}
|
||||
<a href="{{ partner.website }}" class="btn btn-outline-secondary" target="_blank">Visit Website</a>
|
||||
<a href="{{ partner.website }}" class="btn btn-primary btn-sm" target="_blank">Visit Website</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
No consulting partners found matching your criteria.
|
||||
</div>
|
||||
|
@ -89,5 +157,7 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,45 +1,59 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start mb-4">
|
||||
{% if provider.logo %}
|
||||
<img src="{{ provider.logo.url }}" alt="{{ provider.name }} logo" class="me-4"
|
||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<div>
|
||||
<h2 class="card-title mb-3">{{ provider.name }}</h2>
|
||||
<section class="section bg-primary-subtle">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-12 col-lg-5 mb-47 mb-lg-0">
|
||||
<header class="section-primary__header">
|
||||
<h2 class="section-h1 fs-40 fs-lg-64 mb-14">{{ provider.name }}</h2>
|
||||
<div class="text-gray-300 mb-14">
|
||||
<div class="rich-text-content">
|
||||
{{ provider.description|safe }}
|
||||
</div>
|
||||
</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>
|
||||
</section>
|
||||
|
||||
<h3 class="mb-4">Available Services</h3>
|
||||
<div class="container mx-auto px-20 px-lg-0 py-60">
|
||||
<h3 class="section-h2 fs-32 fs-lg-48 mb-40 mt-5">Available Services</h3>
|
||||
<p>The following services are available on {{ provider.name }} through Servala</p>
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||
{% for service in services %}
|
||||
{% for offering in provider.offerings.all %}
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
{% if service.logo %}
|
||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo"
|
||||
{% 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;">
|
||||
</a>
|
||||
{% endif %}
|
||||
<div>
|
||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
||||
<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">
|
||||
{{ service.description|safe|truncatewords_html:30 }}
|
||||
{{ offering.description|safe|truncatewords_html:30 }}
|
||||
</div>
|
||||
<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>
|
||||
|
@ -51,6 +65,5 @@
|
|||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,62 +1,121 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filters</h5>
|
||||
<form method="get">
|
||||
<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 }}">
|
||||
<section class="section bg-primary-subtle">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||
<header class="section-primary__header text-center">
|
||||
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Cloud Providers</h2>
|
||||
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||
<p class="mb-0">Explore our available cloud providers</p>
|
||||
</div>
|
||||
</header>
|
||||
</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>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
<a href="{% url 'services:provider_list' %}" class="btn btn-secondary">Clear</a>
|
||||
<div class="search-form position-relative mb-24">
|
||||
<form method="get">
|
||||
<!-- 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 class="col-md-9">
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||
<!-- Providers Listing -->
|
||||
<div class="section__grid flex-1">
|
||||
<div class="row">
|
||||
{% for provider in providers %}
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
{% if provider.logo %}
|
||||
<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="{{ provider.get_absolute_url }}">
|
||||
<img src="{{ provider.logo.url }}"
|
||||
alt="{{ provider.name }}"
|
||||
class="me-3" style="max-height: 60px; max-width: 120px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<h5 class="card-title mb-0">{{ provider.name }}</h5>
|
||||
style="max-height: 70px; max-width: 200px; object-fit: contain;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rich-text-content mb-3">
|
||||
{{ provider.description|safe|truncatewords_html:50 }}
|
||||
<div class="card__desc flex-grow-1 rich-text-content">
|
||||
{{ provider.description|safe|truncatewords_html:100 }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Services Available:</strong> {{ provider.offerings.count }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Partners:</strong> {{ provider.consulting_partners.count }}
|
||||
</div>
|
||||
|
||||
<div class="mt-auto">
|
||||
<a href="{{ provider.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
||||
<div class="card__footer mt-3">
|
||||
<div class="d-flex gap-2">
|
||||
{% if provider.website %}
|
||||
<a href="{{ provider.website }}" class="btn btn-outline-secondary" target="_blank">Visit Website</a>
|
||||
<a href="{{ provider.website }}" class="btn btn-primary btn-sm" target="_blank">Visit Website</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
No cloud providers found matching your criteria.
|
||||
</div>
|
||||
|
@ -64,5 +123,7 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,165 +1,120 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start mb-4">
|
||||
<section class="section">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||
<div class="row">
|
||||
<!-- Left Sidebar -->
|
||||
<div class="col-12 col-lg-3">
|
||||
<div class="pr-lg-6">
|
||||
<!-- Logo -->
|
||||
<div class="mb-40 border rounded-4 p-4 d-flex align-items-center justify-content-center" style="min-height: 160px;">
|
||||
{% if service.logo %}
|
||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo" class="me-4"
|
||||
style="max-height: 120px; max-width: 240px; object-fit: contain;">
|
||||
<img class="img-fluid w-100 w-lg-auto" src="{{ service.logo.url }}" alt="{{ service.name }} logo" style="max-height: 120px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<div>
|
||||
<h2 class="card-title mb-3">{{ service.name }}</h2>
|
||||
<div class="mb-3">
|
||||
{% for category in service.categories.all %}
|
||||
<span class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<div class="rich-text-content mb-4">
|
||||
<!-- 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 %}
|
||||
<h3>Features</h3>
|
||||
<div class="rich-text-content mb-4">
|
||||
<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>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 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 %}
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -1,49 +1,109 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filters</h5>
|
||||
<form method="get">
|
||||
<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 }}">
|
||||
<section class="section bg-primary-subtle">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
|
||||
<header class="section-primary__header text-center">
|
||||
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Discover Services</h2>
|
||||
<div class="text-gray-300 w-lg-37 mx-auto">
|
||||
<p class="mb-0">Discover our service catalog</p>
|
||||
</div>
|
||||
</header>
|
||||
</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 class="mb-3">
|
||||
<label for="category" class="form-label">Category</label>
|
||||
<select class="form-select" id="category" name="category">
|
||||
<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>
|
||||
<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>
|
||||
{% if category.children.all %}
|
||||
{% for subcategory in category.children.all %}
|
||||
<option value="{{ subcategory.id }}" {% if request.GET.category == subcategory.id|stringformat:'i' %}selected{% endif %}>
|
||||
{{ subcategory.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% 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">
|
||||
<!-- Consulting Partners 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">Consulting Partners</h3>
|
||||
</div>
|
||||
<div>
|
||||
<select class="form-select" id="consulting_partner" name="consulting_partner" @change="submitForm()">
|
||||
<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 %}>
|
||||
|
@ -52,87 +112,67 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
<a href="{% url 'services:service_list' %}" class="btn btn-secondary">Clear</a>
|
||||
<!-- Cloud Providers 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">Cloud Providers</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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4">
|
||||
<!-- Service Listing -->
|
||||
<div class="section__grid flex-1">
|
||||
<div class="row">
|
||||
{% for service in services %}
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="col-12 col-md-6 col-lg-4 mb-30">
|
||||
<div class="card h-100 d-flex flex-column">
|
||||
{% if service.logo %}
|
||||
<img src="{{ service.logo.url }}" alt="{{ service.name }} logo" class="me-3" style="max-height: 50px; max-width: 100px; object-fit: contain;">
|
||||
{% endif %}
|
||||
<div>
|
||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
||||
<div class="mt-2">
|
||||
{% for offering in service.offerings.all %}
|
||||
<div class="d-inline-block me-2">
|
||||
{% if offering.cloud_provider.logo %}
|
||||
<a href="{% url 'services:provider_detail' offering.cloud_provider.slug %}" title="{{ offering.cloud_provider.name }}">
|
||||
<img src="{{ offering.cloud_provider.logo.url }}"
|
||||
alt="{{ offering.cloud_provider.name }}"
|
||||
style="max-height: 25px; max-width: 50px; object-fit: contain;">
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url 'services:provider_detail' offering.cloud_provider.slug %}"
|
||||
class="badge bg-secondary text-decoration-none">
|
||||
{{ offering.cloud_provider.name }}
|
||||
<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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<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 class="badge bg-secondary me-1">{{ category.full_path }}</span>
|
||||
<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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="card-text">{{ service.description|safe|truncatewords:30 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{{ service.get_absolute_url }}" class="btn btn-primary">View Details</a>
|
||||
{% if service.offerings.exists %}
|
||||
<div class="dropdown d-inline-block">
|
||||
<button class="btn btn-success dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
Order
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% for offering in service.offerings.all %}
|
||||
<li>
|
||||
<a class="dropdown-item" href="{% url 'services:create_lead' service.slug %}?offering={{ offering.id }}">
|
||||
via {{ offering.cloud_provider.name }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="{% url 'services:create_lead' service.slug %}" class="btn btn-success">
|
||||
Show Interest
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col">
|
||||
<div class="alert alert-info">
|
||||
No services found matching your criteria.
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,31 +1,81 @@
|
|||
{% extends 'services/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h2 class="card-title mb-4">Thank You!</h2>
|
||||
|
||||
<div class="mb-4">
|
||||
<p class="lead">Thank you for your interest in {{ service.name }}!</p>
|
||||
<p>We have received your inquiry and our team will contact you shortly.</p>
|
||||
<section class="section">
|
||||
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-60">
|
||||
<div class="d-lg-flex">
|
||||
<div class="flex-1 pr-lg-40 mb-40 mb-lg-0">
|
||||
<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-20">
|
||||
<svg class="mx-auto d-block" width="101" height="102" viewBox="0 0 101 102" fill="none"
|
||||
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>
|
||||
|
||||
<div class="mb-4">
|
||||
<p class="text-muted">A confirmation email will be sent to your provided email address.</p>
|
||||
<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>
|
||||
|
||||
<div class="mt-4">
|
||||
<a href="{% url 'services:service_detail' service.slug %}" class="btn btn-primary me-2">
|
||||
Back to Service Details
|
||||
</a>
|
||||
<a href="{% url 'services:service_list' %}" class="btn btn-secondary">
|
||||
Browse More Services
|
||||
</a>
|
||||
</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="w-lg-34 bg-purple-50 rounded-16 p-24 d-flex flex-column justify-content-between">
|
||||
<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>
|
||||
{% if service.description %}
|
||||
<div class="mb-24">
|
||||
<div class="text-black">
|
||||
<p class="mb-0">{{ service.description|safe }}</p>
|
||||
</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>
|
||||
</section>
|
||||
{% 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.db.models import Q
|
||||
from hub.services.models import (
|
||||
ServiceOffering,
|
||||
CloudProvider,
|
||||
Category,
|
||||
)
|
||||
from hub.services.models import ServiceOffering, CloudProvider, Category, Service
|
||||
|
||||
|
||||
def offering_list(request):
|
||||
|
@ -22,6 +18,7 @@ def offering_list(request):
|
|||
|
||||
cloud_providers = CloudProvider.objects.all()
|
||||
categories = Category.objects.filter(parent=None).prefetch_related("children")
|
||||
services = Service.objects.all().order_by("name")
|
||||
|
||||
# Handle cloud provider filter
|
||||
if request.GET.get("cloud_provider"):
|
||||
|
@ -37,6 +34,11 @@ def offering_list(request):
|
|||
Q(service__categories=category) | Q(service__categories__in=subcategories)
|
||||
).distinct()
|
||||
|
||||
# Handle service filter
|
||||
if request.GET.get("service"):
|
||||
service_id = request.GET.get("service")
|
||||
offerings = offerings.filter(service_id=service_id)
|
||||
|
||||
# Handle search
|
||||
if request.GET.get("search"):
|
||||
query = request.GET.get("search")
|
||||
|
@ -50,6 +52,7 @@ def offering_list(request):
|
|||
"offerings": offerings,
|
||||
"cloud_providers": cloud_providers,
|
||||
"categories": categories,
|
||||
"services": services,
|
||||
}
|
||||
return render(request, "services/offering_list.html", context)
|
||||
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
from django.shortcuts import render
|
||||
from hub.services.models import Service, CloudProvider, ConsultingPartner
|
||||
|
||||
|
||||
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.db.models import Q
|
||||
from hub.services.models import (
|
||||
ConsultingPartner,
|
||||
CloudProvider,
|
||||
)
|
||||
from hub.services.models import ConsultingPartner, CloudProvider, Service
|
||||
|
||||
|
||||
def partner_list(request):
|
||||
|
@ -11,11 +8,18 @@ def partner_list(request):
|
|||
"services", "cloud_providers"
|
||||
)
|
||||
|
||||
services = Service.objects.all().order_by("name")
|
||||
|
||||
# Handle cloud provider filter
|
||||
if request.GET.get("cloud_provider"):
|
||||
provider_id = request.GET.get("cloud_provider")
|
||||
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
|
||||
if request.GET.get("search"):
|
||||
query = request.GET.get("search")
|
||||
|
@ -25,6 +29,7 @@ def partner_list(request):
|
|||
|
||||
context = {
|
||||
"partners": partners,
|
||||
"services": services,
|
||||
"cloud_providers": CloudProvider.objects.all(),
|
||||
}
|
||||
return render(request, "services/partner_list.html", context)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue