New homepage (#2172)

* two new sections

* enterprise capabilities and enterprise ready sections

* sections: engineered-for-builders and performance-by-design

* sections: cta-banner, integrations-logos, solutions

# Conflicts:
#	qdrant-landing/themes/qdrant-2024/assets/css/partials/_cta-banner.scss
#	qdrant-landing/themes/qdrant-2024/layouts/partials/cta-banner.html

* remove old sections from index.html

* wip: home page

* reuse links, carousel width

* globe and globe lights

* globe lights

* finalyzing the globe, add customers icons

* new icons set + svg partial update

* upd icons in the enterprise-ready section

* lines background

* globe lights as gradient and svg

* fix carousel responsiveness

* fix cut box shadow

* accordion slider responsiveness

* new hero

* hero customers

* some hero responsiveness

* customers layout fix

* cards responsiveness

* fixes

* remove floating github link

* hero - bigger screens

* refactor css

* more hero responsiveness

* fix

* hero parallax

* replace svg as img with embedded svg logos

* fix marquee

* slider's tabs responsiveness

* remove horizontal scroll on the mobile

* moved images

* images optim

* moved paths to markdown

* svg -> png

* some refactoring and clean up

* moved scss

* svg to png

* more images optimization and cleaning

* optimizing png

* fix globe cards height

* add reveal effect

* improve reveal effect

* fix for the hero animation in Safari

* removed type:page preventing use-cases page from rendering with newer version of Hugo

* restore static/img/home/reranking.webp

* remove unused files

* formatting

* hero and reveal fixes

* fixes

* update cta banner

* links and content fix

* fixes: content, links, web-ui illustration

* canva testimonial

* upd link

* fix

* replace links

* slider links
This commit is contained in:
trean
2026-03-11 23:27:37 +01:00
committed by GitHub
parent 724821b675
commit 305aea6b9a
442 changed files with 7194 additions and 829 deletions
@@ -1,39 +0,0 @@
{{ with (.Site.GetPage "/headless/main/core-features") }}
<section class="core-features">
<div class="container">
<div class="row gy-4">
<div class="col-12">
<h2 class="core-features__title mx-auto">{{ .Params.title }}</h2>
<p class="core-features__subtitle mx-auto">{{ .Params.description }}</p>
<div class="text-start text-lg-center">
<a class="link link_xl" href="{{ .Params.link.url }}">{{ .Params.link.text }}</a>
</div>
</div>
<div class="col-12">
<a href="{{ .Params.cloudFeature.link.url }}" class="card core-features__cloud-native">
<div>
<h4 class="core-features__card-title">{{ .Params.cloudFeature.title }}</h4>
<p class="core-features__card-content">{{ .Params.cloudFeature.content }}</p>
<span class="link link_dark link_md">
{{ .Params.cloudFeature.link.text }}
</span>
</div>
<div class="core-features__cloud-native-image"></div>
</a>
</div>
{{ range .Params.featureCards }}
<div class="col-12 col-xl-4">
<a href="{{ .link.url }}" class="card core-features__card">
<div>
{{ .icon | safeHTML }}
<h6 class="core-features__card-title">{{ .title }}</h6>
<p class="core-features__card-content">{{ .content }}</p>
</div>
<span class="link link_dark link_md align-self-start"> {{ .link.text }} </span>
</a>
</div>
{{ end }}
</div>
</div>
</section>
{{ end }}
@@ -1,9 +1,9 @@
{{ $background := default (dict "src" "/img/cta-banner-stars.png" "webp" "/img/cta-banner-stars.webp") .Params.background }}
{{ $illustration := default (dict "src" "/img/cta-illustration.png" "alt" "Rocket flying over globe illustration") .Params.illustration }}
<section class="cta-banner">
<div class="container">
<div class="cta-banner__banner">
{{ if .Params.background }}
<div class="cta-banner__background" style="background-image: url('{{ .Params.background.src }}');"></div>
{{ end }}
<div class="cta-banner__background" style="background-image: url('{{ $background.src }}');{{ if $background.webp }} background-image: image-set(url('{{ $background.webp }}') type('image/webp'), url('{{ $background.src }}') type('image/png'));{{ end }}"></div>
<div class="cta-banner__content">
<div class="cta-banner__text">
<h2 class="cta-banner__title">{{ .Params.title }}</h2>
@@ -14,11 +14,9 @@
{{ .Params.button.text }}
</a>
</div>
{{ if .Params.illustration }}
<div class="cta-banner__illustration">
<img src="{{ .Params.illustration.src }}" alt="{{ .Params.illustration.alt }}" />
</div>
{{ end }}
<div class="cta-banner__illustration">
{{ partial "picture" (dict "src" $illustration.src "alt" $illustration.alt "loading" "lazy" "decoding" "async") }}
</div>
</div>
</div>
</div>
@@ -1,17 +0,0 @@
{{ with (.Site.GetPage "/headless/main/customers") }}
<section class="customers">
{{ $context := slice }}
{{ range .Params.customers }}
{{ $context = $context | append (dict "svg" .logo "name" .name) }}
{{ end }}
{{ partial "marquee.html" (dict "context" $context "marqueeClass" "customers__logos") }}
<div class="customers__description">
<span class="customers__title">{{ .Params.customerStories.text }}</span>
{{ if .Params.customerStories.url }}
<a class="link link_xl" href="{{ .Params.customerStories.url }}"> {{ .Params.customerStories.textLink }} </a>
{{ end }}
</div>
</section>
{{ end }}
@@ -29,6 +29,17 @@
{{ partial "css" . }}
{{ if .IsHome }}
{{ with .Site.GetPage "/headless/main/hero" }}
{{ with .Params.astronauts }}
<link rel="preload" as="image" type="image/webp" fetchpriority="high"
imagesrcset="{{ .webpSrcset }}"
imagesizes="100vw"
/>
{{ end }}
{{ end }}
{{ end }}
{{ hugo.Generator }}
{{ with .OutputFormats.Get "RSS" }}
@@ -1,48 +0,0 @@
{{ with (.Site.GetPage "/headless/main/hero") }}
<section class="hero">
<div class="container">
<div class="row">
<div class="col-12">
<div class="hero__content">
<h1 class="hero__title">{{ .Params.title }}</h1>
<p class="hero__subtitle">{{ .Params.subtitle }}</p>
<div class="hero__buttons">
<a data-metric-loc="hero" href="{{ .Params.startFree.url }}" class="button button_contained button_lg"
>{{ .Params.startFree.text }}</a
>
<a data-metric-loc="hero" href="{{ .Params.learnMore.url }}" class="button button_outlined button_lg"
>{{ .Params.learnMore.text }}</a
>
</div>
</div>
</div>
</div>
<a href="{{ .Params.githubStars.actionUrl }}" type="button" class="hero__stars" target="_blank">
{{ .Params.githubStars.logo | safeHTML }}
<span class="hero__stars-text">{{ .Params.githubStars.actionText }}</span>
<span class="hero__stars-count">
{{ .Params.githubStars.starIcon | safeHTML }}
{{ with (.Site.GetPage "/headless/stats") }}
{{ .Params.stats.githubStars }}
{{ end }}
</span>
</a>
</div>
<div class="hero__image">
<picture>
{{ range .Params.heroImageSources }}
<source
{{ if
.minWidth
}}
media="(min-width: {{ .minWidth }})"
{{ end }}
srcset="{{ .srcset }}"
type="{{ .type }}"
/>
{{ end }}
<img src="{{ .Params.fallbackHeroImage.src }}" alt="{{ .Params.fallbackHeroImage.alt }}" draggable="false" />
</picture>
</div>
</section>
{{ end }}
@@ -0,0 +1,152 @@
{{ with (.Site.GetPage "/headless/main/case-studies") }}
<section class="case-studies">
<div class="container case-studies__container">
<div class="case-studies__header">
<h2 class="case-studies__title">{{ .Params.title }}</h2>
<div class="case-studies__controls">
<button type="button" class="case-studies__arrow case-studies__arrow--prev" aria-label="Previous slide">
<svg width="24" height="14" viewBox="0 0 17 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.5 1L1.5 5L5.5 9M1.5 5H16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<button type="button" class="case-studies__arrow case-studies__arrow--next" aria-label="Next slide">
<svg width="24" height="14" viewBox="0 0 17 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5 1L15.5 5M15.5 5L11.5 9M15.5 5H1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
<div class="case-studies__carousel-outer">
<div class="case-studies__carousel">
<div class="case-studies__track">
{{ range .Params.caseStudies }}
<div class="case-studies__slide">
{{ if .link }}<a href="{{ .link }}" class="case-studies__card-link">{{ end }}
<div class="case-studies__card">
<p class="case-studies__card-text">
{{ .text }}
{{ if .highlight }}
<span class="case-studies__phrase{{ if eq (trim .textAfter " ") "." }} case-studies__phrase--no-break{{ end }}"><span class="case-studies__highlight">{{ .highlight }}</span>{{ if ne (trim .textAfter " ") "." }} {{ end }}{{ .textAfter }}</span>
{{ end }}
{{ if and (not .highlight) .textAfter }}{{ .textAfter }}{{ end }}
{{ if .highlight2 }}
<span class="case-studies__phrase{{ if eq (trim .textAfter2 " ") "." }} case-studies__phrase--no-break{{ end }}"><span class="case-studies__highlight">{{ .highlight2 }}</span>{{ if ne (trim .textAfter2 " ") "." }} {{ end }}{{ .textAfter2 }}</span>
{{ end }}
{{ if and (not .highlight2) .textAfter2 }}{{ .textAfter2 }}{{ end }}
</p>
<div class="case-studies__card-footer">
<div class="case-studies__card-logo" role="img" aria-label="{{ .logoAlt }}">
{{ partial "svg" (dict "icon" .logoIcon "path" "themes/qdrant-2024/static/img/customer-logo/") }}
</div>
<div class="case-studies__card-arrow">
<svg width="24" height="14" viewBox="0 0 17 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.5 1L15.5 5M15.5 5L11.5 9M15.5 5H1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</div>
</div>
{{ if .link }}</a>{{ end }}
</div>
{{ end }}
</div>
</div>
</div>
</div>
</section>
<script>
(function() {
const container = document.querySelector('.case-studies__container');
const carousel = document.querySelector('.case-studies__carousel');
const track = document.querySelector('.case-studies__track');
const prevBtn = document.querySelector('.case-studies__arrow--prev');
const nextBtn = document.querySelector('.case-studies__arrow--next');
if (!container || !carousel || !track || !prevBtn || !nextBtn) return;
const slides = track.querySelectorAll('.case-studies__slide');
const gap = 30;
const breakpoints = { sm: 576, md: 768, xl: 1200 };
let currentOffset = 0;
function getVisibleCount() {
const w = window.innerWidth;
if (w < breakpoints.sm) return 1;
if (w < breakpoints.md) return 2;
if (w < breakpoints.xl) return 3;
return 4;
}
function getContainerContentWidth() {
const style = getComputedStyle(container);
const paddingLeft = parseFloat(style.paddingLeft) || 0;
const paddingRight = parseFloat(style.paddingRight) || 0;
return container.offsetWidth - paddingLeft - paddingRight;
}
function getSlideWidth() {
const contentWidth = getContainerContentWidth();
const count = Math.min(getVisibleCount(), slides.length);
const gaps = Math.max(0, count - 1) * gap;
return Math.floor((contentWidth - gaps) / count);
}
function applySlideWidth() {
const slideWidth = getSlideWidth();
carousel.style.setProperty('--case-studies-slide-width', slideWidth + 'px');
}
function getMaxOffset() {
applySlideWidth();
const slideWidth = getSlideWidth();
const trackWidth = slides.length * slideWidth + (slides.length - 1) * gap;
const contentWidth = getContainerContentWidth();
return Math.max(0, trackWidth - contentWidth);
}
function updateTrack() {
const maxOffset = getMaxOffset();
currentOffset = Math.min(Math.max(0, currentOffset), maxOffset);
track.style.transform = `translateX(-${currentOffset}px)`;
}
function updateButtons() {
const maxOffset = getMaxOffset();
prevBtn.disabled = currentOffset <= 0;
nextBtn.disabled = currentOffset >= maxOffset;
}
prevBtn.addEventListener('click', function() {
const slideWidth = getSlideWidth();
currentOffset = Math.max(0, currentOffset - (slideWidth + gap));
updateTrack();
updateButtons();
});
nextBtn.addEventListener('click', function() {
const maxOffset = getMaxOffset();
const slideWidth = getSlideWidth();
currentOffset = Math.min(maxOffset, currentOffset + (slideWidth + gap));
updateTrack();
updateButtons();
});
function onResize() {
applySlideWidth();
updateTrack();
updateButtons();
}
let resizeTimer;
window.addEventListener('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
requestAnimationFrame(onResize);
}, 100);
});
applySlideWidth();
updateTrack();
updateButtons();
})();
</script>
{{ end }}
@@ -0,0 +1,15 @@
{{ with (.Site.GetPage "/headless/main/customers") }}
<section class="customers">
<div class="container">
<div class="customers__grid">
{{ range .Params.logoRows }}
{{ range .logos }}
<div class="customers__logo">
{{ partial "svg.html" (dict "icon" .src "path" "static" "fill" "#B4BACC") }}
</div>
{{ end }}
{{ end }}
</div>
</div>
</section>
{{ end }}
@@ -0,0 +1,53 @@
{{ with (.Site.GetPage "/headless/main/engineered-for-builders") }}
<section class="engineered-for-builders">
<div class="engineered-for-builders__background" aria-hidden="true"></div>
<div class="engineered-for-builders__background-texture" aria-hidden="true"></div>
<div class="container">
<div class="engineered-for-builders__header">
<h2 class="engineered-for-builders__title">{{ .Params.title }}</h2>
<p class="engineered-for-builders__subtitle">{{ .Params.subtitle }}</p>
</div>
{{ with .Params.illustration }}
<div class="engineered-for-builders__illustration">
{{ if .srcset }}
<picture>
{{ with .webpSrcset }}<source type="image/webp" srcset="{{ . }}" />{{ end }}
<img
src="{{ .src }}"
srcset="{{ .srcset }}"
alt="{{ .alt }}"
class="engineered-for-builders__illustration-image"
width="{{ .width }}"
height="{{ .height }}"
loading="lazy"
decoding="async"
/>
</picture>
{{ else }}
{{ partial "picture" (dict "src" .src "alt" .alt "class" "engineered-for-builders__illustration-image" "loading" "lazy" "decoding" "async" "width" .width "height" .height) }}
{{ end }}
</div>
{{ end }}
<div class="engineered-for-builders__features">
{{ range .Params.features }}
<div class="engineered-for-builders__feature">
<h3 class="engineered-for-builders__feature-title">{{ .title }}</h3>
<p class="engineered-for-builders__feature-description">{{ .description }}</p>
<a href="{{ .link.url }}" class="engineered-for-builders__feature-link">
{{ .link.text }}
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.33 8H12.67M12.67 8L8.67 4M12.67 8L8.67 12"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</a>
</div>
{{ end }}
</div>
</div>
</section>
{{ end }}
@@ -0,0 +1,45 @@
{{ with (.Site.GetPage "/headless/main/enterprise-capabilities") }}
{{ $iconsPath := "static/img/components/icons/" }}
<section class="enterprise-capabilities">
<div class="enterprise-capabilities__stars" aria-hidden="true"></div>
<div class="container enterprise-capabilities__white-light" aria-hidden="true"></div>
<div class="enterprise-capabilities__background" aria-hidden="true">
<div class="enterprise-capabilities__globe-blue-light"></div>
<div class="enterprise-capabilities__globe-blue-light"></div>
<div class="enterprise-capabilities__globe-blue-light"></div>
<div class="enterprise-capabilities__globe-front"></div>
</div>
<div class="container enterprise-capabilities__white-light" aria-hidden="true"></div>
<div class="enterprise-capabilities__background" aria-hidden="true">
<div class="enterprise-capabilities__globe-front"></div>
</div>
<div class="container">
<div class="enterprise-capabilities__content">
<div class="enterprise-capabilities__header">
<h2 class="enterprise-capabilities__title">{{ .Params.title }}</h2>
<p class="enterprise-capabilities__subtitle">{{ .Params.subtitle }}</p>
</div>
<div class="enterprise-capabilities__cards">
{{ range .Params.deploymentOptions }}
<a href="{{ .link.url }}" class="enterprise-capabilities__card enterprise-capabilities__card--{{ .position }}">
{{ if .connector }}
<img src="{{ .connector }}" alt="" class="enterprise-capabilities__connector" />
{{ end }}
<div class="enterprise-capabilities__card-icon">
{{ partial "svg" (dict "icon" .icon "path" $iconsPath "color" .iconColor ) }}
</div>
<div class="enterprise-capabilities__card-content">
<h3 class="enterprise-capabilities__card-title">{{ .title }}</h3>
<p class="enterprise-capabilities__card-description">{{ .description }}</p>
</div>
<span class="link link_white link_md enterprise-capabilities__card-link"
>{{ .link.text }}</span
>
</a>
{{ end }}
</div>
</div>
</div>
</section>
{{ end }}
@@ -0,0 +1,50 @@
{{ with (.Site.GetPage "/headless/main/enterprise-ready") }}
<section class="enterprise-ready">
<div class="container">
<div class="enterprise-ready__header">
<h2 class="enterprise-ready__title">{{ .Params.title }}</h2>
<p class="enterprise-ready__subtitle">{{ .Params.subtitle }}</p>
</div>
<div class="enterprise-ready__content">
{{/* Large cards row */}}
<div class="enterprise-ready__row enterprise-ready__row--large">
{{ range .Params.largeCards }}
{{ if and .link .link.url }}
<a href="{{ .link.url }}" class="enterprise-ready__card enterprise-ready__card--large enterprise-ready__card--link"{{ if or (hasPrefix .link.url "http://") (hasPrefix .link.url "https://") }} target="_blank" rel="noopener noreferrer"{{ end }}>
{{ else }}
<div class="enterprise-ready__card enterprise-ready__card--large">
{{ end }}
<div class="enterprise-ready__card-visual enterprise-ready__card-visual--{{ .visual }}">
{{ if .image }}
{{ partial "picture" (dict "src" .image.src "alt" .image.alt "class" "enterprise-ready__card-img" "loading" "lazy" "decoding" "async") }}
{{ end }}
</div>
<div class="enterprise-ready__card-footer">
<span class="link link_dark link_md enterprise-ready__card-link">{{ .title }}</span>
</div>
{{ if and .link .link.url }}</a>{{ else }}</div>{{ end }}
{{ end }}
</div>
{{/* Small cards row */}}
{{ $iconsPath := "static/img/components/icons/" }}
<div class="enterprise-ready__row enterprise-ready__row--small">
{{ range .Params.smallCards }}
{{ if and .link .link.url }}
<a href="{{ .link.url }}" class="enterprise-ready__card enterprise-ready__card--small enterprise-ready__card--link"{{ if or (hasPrefix .link.url "http://") (hasPrefix .link.url "https://") }} target="_blank" rel="noopener noreferrer"{{ end }}>
{{ else }}
<div class="enterprise-ready__card enterprise-ready__card--small">
{{ end }}
<div class="enterprise-ready__card-icon">
{{ if .icon }}
{{ partial "svg" (dict "icon" .icon.name "path" $iconsPath "color" .icon.color "stroke" .icon.stroke "fill" .icon.fill) }}
{{ end }}
</div>
<span class="enterprise-ready__card-label">{{ .title }}</span>
{{ if and .link .link.url }}</a>{{ else }}</div>{{ end }}
{{ end }}
</div>
</div>
</div>
</section>
{{ end }}
@@ -0,0 +1,95 @@
{{ with (.Site.GetPage "/headless/main/hero") }}
<section class="hero">
<div class="hero__container">
<div class="hero__grid"></div>
<div class="hero__content">
<div class="hero__heading">
<h1 class="hero__title">{{ .Params.title }}</h1>
<p class="hero__subtitle">{{ .Params.subtitle }}</p>
</div>
<div class="hero__buttons">
<a data-metric-loc="hero" href="{{ .Params.startFree.url }}" class="button button_contained button_lg"
data-metric-loc="hero">{{ .Params.startFree.text }}</a>
<a data-metric-loc="hero" href="{{ .Params.learnMore.url }}" class="button button_outlined button_lg"
data-metric-loc="hero">{{ .Params.learnMore.text }}</a>
</div>
</div>
<div class="hero__planet">
{{ with .Params.planet }}
<img class="hero__planet-blur" src="{{ .blur }}" alt="" width="570" height="544" decoding="async" />
<img
class="hero__planet-blur hero__planet-blur--alt"
src="{{ .blur2 }}"
alt=""
width="570"
height="544"
decoding="async"
/>
<img class="hero__planet-sphere" src="{{ .sphere }}" alt="" width="514" height="488" decoding="async" />
{{ with .texture }}
<picture>
<source srcset="{{ .webp }}" type="image/webp" />
<img
class="hero__planet-texture"
src="{{ .png }}"
alt=""
width="1012"
height="960"
loading="eager"
decoding="async"
/>
</picture>
{{ end }}
{{ end }}
</div>
{{ with .Params.blueHaze }}
<img class="hero__blue-haze" src="{{ . }}" alt="" width="1200" height="600" decoding="async" />
{{ end }}
<div class="hero__astronauts">
{{ with .Params.astronauts }}
<picture>
<source type="image/webp" srcset="{{ .webpSrcset }}" sizes="100vw" />
<img
src="{{ .fallbackSrc }}"
srcset="{{ .pngSrcset }}"
sizes="100vw"
alt="{{ .alt }}"
width="{{ .width }}"
height="{{ .height }}"
draggable="false"
loading="eager"
decoding="async"
fetchpriority="high"
/>
</picture>
{{ end }}
</div>
<div class="hero__fade-top"></div>
<div class="hero__fade-bottom"></div>
<div class="hero__fade-left"></div>
<div class="hero__fade-right"></div>
</div>
{{ if .Params.valueBadges }}
<div class="hero__badges">
{{ range .Params.valueBadges }}
{{ if .url }}
<a href="{{ .url }}" class="hero__badge hero__badge--link"{{ if or (hasPrefix .url "http://") (hasPrefix .url "https://") }} target="_blank" rel="noopener noreferrer"{{ end }}>
<img src="{{ .icon }}" alt="" class="hero__badge-icon" width="16" height="16" decoding="async" />
<span class="hero__badge-text">{{ .text }}</span>
</a>
{{ else }}
<span class="hero__badge">
<img src="{{ .icon }}" alt="" class="hero__badge-icon" width="16" height="16" decoding="async" />
<span class="hero__badge-text">{{ .text }}</span>
</span>
{{ end }}
{{ end }}
</div>
{{ end }}
</section>
{{ end }}
@@ -0,0 +1,46 @@
{{ with (.Site.GetPage "/headless/main/integrations-logos") }}
{{ $logosFirstRow := .Params.logosFirstRow }}
{{ $logosSecondRow := .Params.logosSecondRow }}
<section class="integrations-logos">
<div class="container">
<p class="integrations-logos__title">{{ .Params.title }}</p>
</div>
<div class="integrations-logos__content">
<div class="integrations-logos__cards">
<div class="integrations-logos__cards__container">
<div class="integrations-logos__cards__block">
<div class="integrations-logos__cards__inner integrations-logos__cards__inner_to-left">
<span>
{{ partial "integrations-logos-cards" (dict "context" $logosFirstRow) }}
</span>
<span>
{{ partial "integrations-logos-cards" (dict "context" $logosFirstRow) }}
</span>
</div>
</div>
</div>
</div>
<div class="integrations-logos__cards">
<div class="integrations-logos__cards__container">
<div class="integrations-logos__cards__block">
<div class="integrations-logos__cards__inner integrations-logos__cards__inner_to-right">
<span>
{{ partial "integrations-logos-cards" (dict "context" $logosSecondRow) }}
</span>
<span>
{{ partial "integrations-logos-cards" (dict "context" $logosSecondRow) }}
</span>
</div>
</div>
</div>
</div>
<div class="integrations-logos__gradient-left"></div>
<div class="integrations-logos__gradient-right"></div>
</div>
</section>
{{ end }}
@@ -0,0 +1,110 @@
{{ with (.Site.GetPage "/headless/main/performance-by-design") }}
<section class="performance-by-design">
<div class="container">
<div class="performance-by-design__header">
<span class="performance-by-design__tagline">{{ .Params.tagline }}</span>
<h2 class="performance-by-design__title">{{ .Params.title }}</h2>
<p class="performance-by-design__subtitle">{{ .Params.subtitle }}</p>
</div>
{{/* Slider layout: visible only below md */}}
<div class="performance-by-design__slider">
<div class="performance-by-design__content">
<div class="performance-by-design__features">
{{ range $index, $feature := .Params.features }}
<div class="performance-by-design__feature{{ if eq $index 0 }} performance-by-design__feature--active{{ end }}" data-feature-index="{{ $index }}">
<h3 class="performance-by-design__feature-title">{{ $feature.title }}</h3>
<div class="performance-by-design__feature-body">
<p class="performance-by-design__feature-description">{{ $feature.description }}</p>
</div>
</div>
{{ end }}
</div>
<div class="performance-by-design__visual">
{{ range $index, $feature := .Params.features }}
<div class="performance-by-design__image{{ if eq $index 0 }} performance-by-design__image--active{{ end }}" data-image-index="{{ $index }}">
{{ if $feature.image }}
{{ partial "picture" (dict "src" $feature.image.src "alt" $feature.image.alt "loading" "lazy" "decoding" "async") }}
{{ end }}
</div>
{{ end }}
</div>
</div>
</div>
{{/* Card grid: visible from md up, 2 cards per row */}}
<div class="performance-by-design__grid">
{{ range .Params.features }}
<div class="performance-by-design__card">
{{ if .image }}
<div class="performance-by-design__card-visual">
{{ partial "picture" (dict "src" .image.src "alt" .image.alt "class" "performance-by-design__card-image" "loading" "lazy" "decoding" "async") }}
</div>
{{ end }}
<div class="performance-by-design__card-content">
<h3 class="performance-by-design__card-title">{{ .title }}</h3>
<p class="performance-by-design__card-description">{{ .description }}</p>
</div>
</div>
{{ end }}
</div>
</div>
</section>
<script>
(function () {
var section = document.querySelector('.performance-by-design');
if (!section) return;
var features = section.querySelectorAll('.performance-by-design__feature');
var images = section.querySelectorAll('.performance-by-design__image');
if (!features.length) return;
var currentIndex = 0;
var autoplayInterval = null;
var AUTOPLAY_DELAY = 5000;
function goToFeature(index) {
if (index < 0 || index >= features.length) return;
features.forEach(function (f) {
f.classList.remove('performance-by-design__feature--active');
});
images.forEach(function (img) {
img.classList.remove('performance-by-design__image--active');
});
features[index].classList.add('performance-by-design__feature--active');
if (images[index]) images[index].classList.add('performance-by-design__image--active');
currentIndex = index;
}
function nextFeature() {
var next = (currentIndex + 1) % features.length;
goToFeature(next);
}
function startAutoplay() {
stopAutoplay();
autoplayInterval = setInterval(nextFeature, AUTOPLAY_DELAY);
}
function stopAutoplay() {
if (autoplayInterval) {
clearInterval(autoplayInterval);
autoplayInterval = null;
}
}
features.forEach(function (feature, i) {
feature.addEventListener('click', function () {
goToFeature(i);
startAutoplay();
});
});
startAutoplay();
})();
</script>
{{ end }}
@@ -0,0 +1,23 @@
{{ with (.Site.GetPage "/headless/main/solutions") }}
<section class="solutions">
<div class="solutions__background"></div>
<div class="container">
<div class="solutions__header">
<span class="solutions__label">{{ .Params.label }}</span>
<h2 class="solutions__title">{{ .Params.title }}</h2>
<p class="solutions__subtitle">{{ .Params.subtitle }}</p>
</div>
<div>
{{ partial "tab-slider" (dict
"sectionClass" "solutions"
"tabs" .Params.tabs
"items" .Params.tabs
"slidePartial" "solutions-slide-content"
"showControls" true
)
}}
</div>
</div>
</section>
{{ end }}
@@ -0,0 +1,27 @@
{{ with (.Site.GetPage "/headless/main/why-qdrant") }}
<section class="why-qdrant">
<div class="container">
<div class="why-qdrant__header">
<span class="why-qdrant__pill">{{ .Params.pill }}</span>
<h2 class="why-qdrant__title">{{ .Params.title }}</h2>
<p class="why-qdrant__subtitle">{{ .Params.subtitle }}</p>
</div>
<div class="why-qdrant__grid">
{{ range .Params.featureCards }}
<div class="why-qdrant__card why-qdrant__card--{{ .size }}" data-card-id="{{ .id }}">
<div class="why-qdrant__card-visual why-qdrant__card-visual--{{ .id }}">
{{ if .image }}
{{ partial "picture" (dict "src" .image.src "alt" .image.alt "class" "why-qdrant__card-image" "loading" "lazy" "decoding" "async") }}
{{ end }}
</div>
<div class="why-qdrant__card-content">
<h3 class="why-qdrant__card-title">{{ .title }}</h3>
<p class="why-qdrant__card-description">{{ .description | safeHTML }}</p>
<a href="{{ .link.url }}" class="link link_md why-qdrant__card-link">{{ .link.text }}</a>
</div>
</div>
{{ end }}
</div>
</div>
</section>
{{ end }}
@@ -0,0 +1,10 @@
{{ range .context }}
<div class="integrations-logos__cards__item" role="img" aria-label="{{ .logo.alt }}">
{{ partial "svg" (dict "icon" .logo.icon "path" "themes/qdrant-2024/static/img/customer-logo/") }}
</div>
{{ end }}
{{ range .context }}
<div class="integrations-logos__cards__item" role="img" aria-label="{{ .logo.alt }}">
{{ partial "svg" (dict "icon" .logo.icon "path" "themes/qdrant-2024/static/img/customer-logo/") }}
</div>
{{ end }}
@@ -1,15 +0,0 @@
{{ with (.Site.GetPage "/headless/main/integrations") }}
<section class="integrations">
<div class="container">
<h2 class="integrations__title mx-auto">{{ .Params.title }}</h2>
<p class="integrations__subtitle">
Qdrant integrates with all leading
<a class="integrations__link" href="{{ .Params.embedLink.url }}">{{ .Params.embedLink.text }}</a> and
<a class="integrations__link" href="{{ .Params.frameworkLink.url }}">{{ .Params.frameworkLink.text }}</a>.
</p>
<div class="text-center">{{ .Scratch.Set "cssClass" "link_light link_xl" }} {{ partial "link" . }}</div>
<div class="integrations__preview mx-auto"></div>
<div class="integrations__overlay"></div>
</div>
</section>
{{ end }}
@@ -7,7 +7,12 @@
<!-- OneTrust Cookies Consent Notice start for local.qdrant.tech -->
{{ if .Site.Params.onetrustScriptID }}
<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" type="text/javascript" charset="UTF-8" data-domain-script="{{ .Site.Params.onetrustScriptID }}" ></script>
<script
src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js"
type="text/javascript"
charset="UTF-8"
data-domain-script="{{ .Site.Params.onetrustScriptID }}"
></script>
<script async type="text/javascript">
function OptanonWrapper() {
const onetrustAnalyticsChoice = new CustomEvent('onetrust_loaded');
@@ -36,6 +41,7 @@
</script>
{{ end }}
<!--Google Measurement ID-->
{{ $googleJs := resources.Get "js/google-setup.js" | js.Build (dict "params" (dict "gaMeasurementId" .Site.Config.Services.GoogleAnalytics.ID)) | minify | resources.Fingerprint "sha512" }}
<script src="{{ $googleJs.RelPermalink }}"></script>
@@ -44,6 +50,12 @@
<script src="{{ $indexJs.RelPermalink }}"></script>
{{ if .IsHome }}
{{ $homeAnimationsJs := resources.Get "/js/home-animations.js" | js.Build | minify | resources.Fingerprint "sha512" }}
<script src="{{ $homeAnimationsJs.RelPermalink }}"></script>
{{ $scrollRevealJs := resources.Get "/js/scroll-reveal.js" | js.Build | minify | resources.Fingerprint "sha512" }}
<script src="{{ $scrollRevealJs.RelPermalink }}"></script>
<!--splide.js carousel-->
{{ $splideJs := resources.Get "/js/vendor/splide.js" | js.Build | minify | resources.Fingerprint "sha512" }}
<script src="{{ $splideJs.RelPermalink }}"></script>
@@ -153,27 +165,22 @@
{{ if and (eq .Section "blog") (.IsPage) }}
<script>
document.addEventListener("scroll", () => {
const article = document.getElementById("article");
const progress = document.getElementById("progress");
document.addEventListener('scroll', () => {
const article = document.getElementById('article');
const progress = document.getElementById('progress');
const articleHeight = article.scrollHeight - window.innerHeight;
const scrollTop = window.scrollY - article.offsetTop;
progress.value = Math.min(
Math.max((scrollTop / articleHeight) * 100, 0),
100
);
progress.value = Math.min(Math.max((scrollTop / articleHeight) * 100, 0), 100);
});
</script>
{{ end }}
<script>
window.addEventListener("message", event => {
if (
event.data.type === "hsFormCallback" &&
event.data.eventName === "onFormReady"
) {
window.addEventListener('message', (event) => {
if (event.data.type === 'hsFormCallback' && event.data.eventName === 'onFormReady') {
const formEl = document.querySelector(`form[data-form-id="${event.data.id}"]`);
if (formEl) {
const hiddenCurrentUrl = formEl.querySelector('[name="last_form_fill_url"]');
@@ -0,0 +1,30 @@
{{- $src := .src -}}
{{- $alt := .alt | default "" -}}
{{- $ext := path.Ext $src -}}
{{- if eq $ext ".svg" -}}
<img
src="{{ $src }}"
alt="{{ $alt }}"
{{- with .class }}class="{{ . }}"{{ end -}}
{{- with .loading }}loading="{{ . }}"{{ end -}}
{{- with .decoding }}decoding="{{ . }}"{{ end -}}
{{- with .width }}width="{{ . }}"{{ end -}}
{{- with .height }}height="{{ . }}"{{ end -}}
/>
{{- else -}}
{{- $webpSrc := replace $src $ext ".webp" -}}
<picture>
<source srcset="{{ $webpSrc }}" type="image/webp" />
<img
src="{{ $src }}"
alt="{{ $alt }}"
{{- with .class }}class="{{ . }}"{{ end -}}
{{- with .loading }}loading="{{ . }}"{{ end -}}
{{- with .decoding }}decoding="{{ . }}"{{ end -}}
{{- with .fetchpriority }}fetchpriority="{{ . }}"{{ end -}}
{{- with .width }}width="{{ . }}"{{ end -}}
{{- with .height }}height="{{ . }}"{{ end -}}
/>
</picture>
{{- end -}}
@@ -0,0 +1,21 @@
{{ $item := .item }}
<div class="row align-items-center">
<div class="col-12 col-lg-5">
<div class="solutions__panel-content">
<h3 class="solutions__panel-title">{{ $item.title }}</h3>
<p class="solutions__panel-description">{{ $item.description }}</p>
<a href="{{ $item.link.url }}" class="solutions__panel-link">
{{ $item.link.text }}
</a>
</div>
</div>
<div class="col-12 col-lg-7">
<div class="solutions__panel-illustration">
{{ if $item.image }}
{{ partial "picture" (dict "src" $item.image.src "alt" $item.image.alt "loading" "lazy" "decoding" "async") }}
{{ else }}
<div class="solutions__panel-placeholder" data-label="{{ $item.title }}"></div>
{{ end }}
</div>
</div>
</div>
@@ -1 +1,77 @@
{{ $path := "static/icons/outline/" }} {{ $filename := . }} {{ readFile (printf "%s%s" $path $filename) | safeHTML }}
<!-- {{/* svg.html partial
-----------------
This partial renders SVG icons dynamically with Hugo templating.
- Usage:
{{ partial "svg.html" (dict "icon" "icon-filename" "stroke" "color" "fill" "path" "custom/path/")
}}
OR just:
{{ partial "svg.html" "icon-filename" }}
- Parameters:
- icon / filename: Name of SVG file (without or with .svg extension).
- path (optional): Folder path (default: static/icons/outline/).
- stroke, fill, color (optional): Override respective SVG attributes, using CSS variables (e.g. "primary", "teal", etc).
* For Bootstrap color variables, use just the color name (e.g., "primary", "violet"), which becomes: var(--bs-primary).
* You can also use "currentColor" to inherit from CSS context.
* HEX values are supported as well.
- How it works:
- Loads the SVG file as text.
- Replaces stroke/fill/color attributes if provided.
- Allows color to be controlled via style or CSS variables.
- Safe for direct HTML inclusion.
- Typical use:
For icons in cards, buttons, menus, etc.
Maintainers: Update this file if icon assets or color conventions change.
*/}} -->
{{ $path := "static/icons/outline/" }}
{{ $filename := "" }}
{{ $stroke := "" }}
{{ $fill := "" }}
{{ $color := "" }}
{{ if reflect.IsMap . }}
{{ $path = default $path .path }}
{{ $filename = default .filename .icon }}
{{ $stroke = .stroke }}
{{ $fill = .fill }}
{{ $color = .color }}
{{ else }}
{{ $filename = . }}
{{ end }}
{{ if not (strings.HasSuffix $filename ".svg") }}
{{ $filename = printf "%s.svg" $filename }}
{{ end }}
{{ $svg := readFile (printf "%s%s" $path $filename) }}
{{ if $stroke }}
{{ $strokeVal := $stroke }}
{{ if and (ne (strings.HasPrefix $stroke "#") true) (ne (strings.HasPrefix $stroke "var(") true) (ne $stroke "currentColor") (ne $stroke "inherit") (ne $stroke "none") }}
{{ $strokeVal = printf "var(--bs-%s)" $stroke }}
{{ end }}
{{ $svg = replaceRE `stroke="[^"]*"` (printf `stroke="%s"` $strokeVal) $svg }}
{{ $svg = replaceRE `stroke='[^']*'` (printf `stroke="%s"` $strokeVal) $svg }}
{{ end }}
{{ if $fill }}
{{ $fillVal := $fill }}
{{ if and (ne (strings.HasPrefix $fill "#") true) (ne (strings.HasPrefix $fill "var(") true) (ne $fill "currentColor") (ne $fill "inherit") (ne $fill "none") }}
{{ $fillVal = printf "var(--bs-%s)" $fill }}
{{ end }}
{{ $svg = replaceRE `fill="[^"]*"` (printf `fill="%s"` $fillVal) $svg }}
{{ $svg = replaceRE `fill='[^']*'` (printf `fill="%s"` $fillVal) $svg }}
{{ end }}
{{ if $color }}
{{ $colorVal := $color }}
{{ if and (ne (strings.HasPrefix $color "#") true) (ne (strings.HasPrefix $color "var(") true) (ne $color "currentColor") (ne $color "inherit") (ne $color "none") }}
{{ $colorVal = printf "var(--bs-%s)" $color }}
{{ end }}
{{ $svg = replaceRE `(<svg)(\s)` (printf `$1 style="color:%s"$2` $colorVal) $svg }}
{{ $svg = replaceRE `stroke="[^"]*"` `stroke="currentColor"` $svg }}
{{ $svg = replaceRE `stroke='[^']*'` `stroke="currentColor"` $svg }}
{{ end }}
{{ $svg | safeHTML }}
@@ -0,0 +1,133 @@
{{/*
Reusable Tab-Slider Partial
Params (passed via dict):
- sectionClass: CSS class prefix for the section (e.g., "solutions", "healthcare-use-cases")
- tabs: array of tab objects with at least .id and .label (or .name)
- items: array of slide items to render
- slidePartial: name of the partial to render each slide's content
- showControls: (optional) whether to show arrow/dot controls (default: true)
*/}}
{{ $sectionClass := .sectionClass }}
{{ $tabs := .tabs }}
{{ $items := .items }}
{{ $slidePartial := .slidePartial }}
{{ $showControls := true }}
{{ if isset . "showControls" }}
{{ $showControls = .showControls }}
{{ end }}
<div class="{{ $sectionClass }}__tabs-wrapper">
<div class="{{ $sectionClass }}__tabs">
{{ range $index, $tab := $tabs }}
<button
type="button"
class="{{ $sectionClass }}__tab{{ if eq $index 0 }} {{ $sectionClass }}__tab--active{{ end }}"
data-tab-index="{{ $index }}"
>
{{ with $tab.label }}{{ . }}{{ else }}{{ $tab.name }}{{ end }}
</button>
{{ end }}
<div class="{{ $sectionClass }}__tab-indicator"></div>
</div>
</div>
<div class="{{ $sectionClass }}__slider">
{{ range $index, $item := $items }}
<div class="{{ $sectionClass }}__slide{{ if eq $index 0 }} {{ $sectionClass }}__slide--active{{ end }}" data-slide="{{ $index }}">
{{ partial $slidePartial (dict "item" $item "index" $index "sectionClass" $sectionClass) }}
</div>
{{ end }}
</div>
{{ if $showControls }}
<div class="{{ $sectionClass }}__controls">
<button type="button" class="{{ $sectionClass }}__arrow {{ $sectionClass }}__arrow--prev" aria-label="Previous slide">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.5 15L7.5 10L12.5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div class="{{ $sectionClass }}__dots">
{{ range $index, $tab := $tabs }}
<button
type="button"
class="{{ $sectionClass }}__dot{{ if eq $index 0 }} {{ $sectionClass }}__dot--active{{ end }}"
data-slide-index="{{ $index }}"
aria-label="Go to slide {{ add $index 1 }}"
>
<span></span>
</button>
{{ end }}
</div>
<button type="button" class="{{ $sectionClass }}__arrow {{ $sectionClass }}__arrow--next" aria-label="Next slide">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 5L12.5 10L7.5 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
{{ end }}
<script>
(function() {
var section = document.querySelector('.{{ $sectionClass }}');
if (!section) return;
var tabs = section.querySelectorAll('.{{ $sectionClass }}__tab');
var dots = section.querySelectorAll('.{{ $sectionClass }}__dot');
var slides = section.querySelectorAll('.{{ $sectionClass }}__slide');
var prevBtn = section.querySelector('.{{ $sectionClass }}__arrow--prev');
var nextBtn = section.querySelector('.{{ $sectionClass }}__arrow--next');
var indicator = section.querySelector('.{{ $sectionClass }}__tab-indicator');
var currentIndex = 0;
var totalSlides = slides.length;
function updateIndicator(activeTab) {
if (indicator && activeTab) {
indicator.style.width = activeTab.offsetWidth + 'px';
indicator.style.left = activeTab.offsetLeft + 'px';
}
}
function goToSlide(index) {
if (index < 0) index = totalSlides - 1;
if (index >= totalSlides) index = 0;
currentIndex = index;
slides.forEach(function(slide, i) {
slide.classList.toggle('{{ $sectionClass }}__slide--active', i === index);
});
tabs.forEach(function(tab, i) {
tab.classList.toggle('{{ $sectionClass }}__tab--active', i === index);
if (i === index) updateIndicator(tab);
});
dots.forEach(function(dot, i) {
dot.classList.toggle('{{ $sectionClass }}__dot--active', i === index);
});
}
tabs.forEach(function(tab, i) {
tab.addEventListener('click', function() { goToSlide(i); });
});
dots.forEach(function(dot, i) {
dot.addEventListener('click', function() { goToSlide(i); });
});
if (prevBtn) prevBtn.addEventListener('click', function() { goToSlide(currentIndex - 1); });
if (nextBtn) nextBtn.addEventListener('click', function() { goToSlide(currentIndex + 1); });
// Initialize indicator
var activeTab = section.querySelector('.{{ $sectionClass }}__tab--active');
if (activeTab) updateIndicator(activeTab);
window.addEventListener('resize', function() {
var activeTab = section.querySelector('.{{ $sectionClass }}__tab--active');
if (activeTab) updateIndicator(activeTab);
});
})();
</script>
@@ -1,7 +1,11 @@
{{ $class := .class }}
<section class="testimonial-light {{ $class }}">
{{ $ctx := .context }}
{{ $hasReview := and $ctx.Params.review (ne (trim (string $ctx.Params.review) " \t\n\r") "") }}
{{ $hasEmployees := and $ctx.Params.avatar $ctx.Params.avatar.src }}
{{ $hasContent := or $hasReview $hasEmployees }}
<section class="testimonial-light {{ $class }}{{ if $ctx.Params.gradient }} testimonial-light--gradient-layout{{ end }}">
<div class="container">
{{ with .context.Params.partners }}
{{ with $ctx.Params.partners }}
<div class="testimonial-light__partners">
<p class="testimonial-light__partners-title">{{ .title }}</p>
<div class="testimonial-light__partners-logos">
@@ -14,25 +18,35 @@
</div>
{{ end }}
<div class="row gy-4 gx-3">
{{ if $hasContent }}
<div class="col-12 col-xl-9">
<div class="testimonial-light__content">
<p class="testimonial-light__review">{{ .context.Params.review | safeHTML }}</p>
{{ if $hasReview }}
<p class="testimonial-light__review">{{ $ctx.Params.review | safeHTML }}</p>
{{ end }}
{{ with $ctx.Params.avatar }}
{{ if .src }}
<div class="testimonial-light__employees">
<div class="testimonial-light__employees-avatar">
<img src="{{ .context.Params.avatar.src }}" alt="{{ .context.Params.avatar.alt }}" />
<img src="{{ .src }}" alt="{{ .alt }}" />
</div>
<div class="testimonial-light__employees-position">
<p>{{ .context.Params.names }}</p>
<p>{{ .context.Params.positions }}</p>
{{ with $ctx.Params.names }}<p>{{ . }}</p>{{ end }}
{{ with $ctx.Params.positions }}<p>{{ . }}</p>{{ end }}
</div>
</div>
{{ end }}
{{ end }}
</div>
</div>
<div class="col-12 col-xl-3">
<div class="testimonial-light__logo">
<img src="{{ .context.Params.logo.src }}" alt="{{ .context.Params.logo.alt }}" />
{{ end }}
{{ with $ctx.Params.logo }}
<div class="col-12 {{ if $hasContent }}col-xl-3{{ else }}col-12{{ end }}">
<div class="testimonial-light__logo{{ if $ctx.Params.gradient }} testimonial-light__logo--gradient{{ end }}">
<img src="{{ .src }}" alt="{{ .alt }}" />
</div>
</div>
{{ end }}
</div>
</div>
</section>