add weight sorting, github links, README fix (#2571)

* add weight sorting, github links, README fix

* fix

* Point 4 demos at original repos, lead with ecommerce and fraud

Startup Discovery, Product Categorization, Food Discovery, and Semantic
Code Search link to their canonical repos in the qdrant org instead of
the qdrant-labs copies. E-Commerce search and Fraud detection move to
weights 1 and 2 so they lead the catalog.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: kanungle <neil.kanungo@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
trean
2026-07-30 23:32:43 +02:00
committed by GitHub
co-authored by Claude Opus 5 kanungle
parent 5ecb99dbd3
commit c86374270a
5 changed files with 177 additions and 86 deletions
+5 -1
View File
@@ -381,12 +381,16 @@ demos:
description: Short description shown on the card.
category: Semantic Search # must match a filter field (see below)
image: /img/demos/demo-0.png # optional; omit for a placeholder
github: https://github.com/org/repo # optional; icon link on the card
weight: 10 # optional; same rules as Hugo page weight
link:
text: View Demo
url: https://example.com/
```
Put card images in `themes/qdrant-2024/static/img/demos/`. Provide a PNG at **800×296px** (2x) and WebP at both **1x (400×148px)** and **2x (800×296px)**. Only list the PNG file in the markdown; WebP will be used automatically if available.
`weight` follows Hugo’s built-in page weight rules: use a non-zero integer; lighter items float to the top, heavier sink to the bottom; missing or `0` weight is placed at the end. Ties break by title.
Put card images in `themes/qdrant-2024/static/img/demos/`. Provide a PNG and a matching WebP at **800×296px** (same basename, e.g. `demo-0.png` + `demo-0.webp`). Only list the PNG file in the markdown; the picture partial swaps the extension to serve WebP when available.
### Add a filter
@@ -11,47 +11,59 @@ demos:
description: Compare semantic, keyword, and hybrid search over startup profiles, with metadata filters on every query.
category: Hybrid Search
image: /img/demos/demo-0.png
github: https://github.com/qdrant/qdrant_demo
link:
text: View Demo
url: https://qdrant-demo-qvpw.vercel.app/
weight: 3
- id: product-categorization
title: Product Categorization
description: Categorize products automatically as semantic search groups similar descriptions, even when wording differs.
category: Classification
image: /img/demos/demo-2.png
github: https://github.com/qdrant/goods_categorization_demo
link:
text: View Demo
url: https://goods-categorization-demo.vercel.app/
weight: 4
- id: food-discovery
title: Food Discovery
description: Find foods by taste and meaning, with recommendations that adapt to your likes and skips.
category: Recommendations
image: /img/demos/demo-1.png
github: https://github.com/qdrant/demo-food-discovery
link:
text: View Demo
url: https://demo-food-discovery-v2x8-xi.vercel.app/
weight: 5
- id: semantic-code-search
title: Semantic Code Search
description: Search the Qdrant codebase by describing what the code does, using MiniLM and UniXcoder embeddings.
category: Code Search
image: /img/demos/demo-3.png
github: https://github.com/qdrant/demo-code-search
link:
text: View Demo
url: https://demo-code-search-gules.vercel.app/
weight: 6
- id: ecommerce-search
title: E-Commerce search
description: Hybrid search, personalization, recommendations, and merchandising across a catalog of 5.7M+ products.
category: Hybrid Search
image: /img/demos/demo-4.png
github: https://github.com/qdrant-labs/demo-ecommerce-search
link:
text: View Demo
url: https://demo-ecommerce-search.vercel.app/
weight: 1
- id: fraud-detection
title: Fraud detection
description: Score every charge against that customer's own history, with evidence behind every fraud alert.
category: Anomaly Detection
image: /img/demos/demo-5.png
github: https://github.com/qdrant-labs/demo-fraud-detection
link:
text: View Demo
url: https://demo-fraud-detection-eta.vercel.app/
weight: 2
---
@@ -340,6 +340,8 @@
}
&__card {
position: relative;
z-index: 0;
display: flex;
flex-direction: column;
gap: $spacer;
@@ -347,18 +349,35 @@
border-radius: $spacer;
border: pxToRem(0.64) solid $neutral-90;
background-color: $neutral-98;
text-decoration: none;
color: inherit;
transition: box-shadow 0.2s ease;
&:hover {
text-decoration: none;
color: inherit;
box-shadow:
0 pxToRem(5) pxToRem(11) 0 rgba(22, 30, 51, 0.1),
0 pxToRem(19) pxToRem(21) 0 rgba(22, 30, 51, 0.09);
}
&-link {
color: inherit;
text-decoration: none;
&:hover,
&:focus {
color: inherit;
text-decoration: none;
}
// Stretched link: whole card opens the demo; GitHub sits above via z-index
&::after {
content: '';
position: absolute;
inset: 0;
z-index: 1;
border-radius: inherit;
}
}
&-image {
width: 100%;
aspect-ratio: 404 / 148;
@@ -396,11 +415,17 @@
padding: 0 $spacer;
}
&-meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: $spacer * 0.5;
}
&-badge {
display: inline-flex;
align-items: center;
justify-content: center;
align-self: flex-start;
padding: pxToRem(2) $spacer * 0.5;
border-radius: calc($spacer / 4);
border: pxToRem(1) solid $neutral-90;
@@ -412,6 +437,40 @@
color: $neutral-50;
}
&-github {
position: relative;
z-index: 2;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: pxToRem(24);
height: pxToRem(24);
border-radius: calc($spacer / 4);
border: pxToRem(1) solid $neutral-90;
background-color: $neutral-98;
color: $neutral-50;
text-decoration: none;
transition:
color 0.15s ease,
border-color 0.15s ease,
background-color 0.15s ease;
svg {
display: block;
width: pxToRem(14);
height: pxToRem(14);
}
&:hover,
&:focus-visible {
color: $neutral-20;
border-color: $neutral-80;
background-color: $neutral-94;
text-decoration: none;
}
}
&-title {
margin-bottom: 0;
font-size: $font-size-l; // 18px
@@ -0,0 +1,70 @@
{{/*
Demo catalog card.
Params:
demo – demo map from content/demo/items
filterKeys – slice of filter field keys
list – true for list view styling
*/}}
{{- $demo := .demo -}}
{{- $filterKeys := .filterKeys | default slice -}}
{{- $isList := .list | default false -}}
{{- $isExternal := strings.HasPrefix $demo.link.url "http" -}}
{{- $searchParts := slice $demo.title $demo.description -}}
{{- range $filterKeys -}}
{{- with index $demo . -}}
{{- $searchParts = $searchParts | append . -}}
{{- end -}}
{{- end -}}
<article
class="demos-catalog__card{{ if $isList }} demos-catalog__card--list{{ end }}"
data-catalog-card
data-id="{{ $demo.id }}"
data-name="{{ $demo.title }}"
{{- range $filterKeys }}
data-{{ . }}="{{ index $demo . }}"
{{- end }}
data-search="{{ delimit $searchParts " " }}"
>
<div class="demos-catalog__card-image{{ if not $demo.image }} demos-catalog__card-image--placeholder{{ end }}">
{{ with $demo.image }}
{{ partial "picture.html" (dict
"src" .
"alt" $demo.title
"loading" "lazy"
"decoding" "async"
"width" (cond $isList "800" "400")
"height" (cond $isList "296" "148")
) }}
{{ else }}
<span class="demos-catalog__card-image-label" aria-hidden="true">Demo</span>
{{ end }}
</div>
<div class="demos-catalog__card-body">
<div class="demos-catalog__card-meta">
<span class="demos-catalog__card-badge">{{ $demo.category }}</span>
{{ with $demo.github }}
<a
href="{{ . }}"
class="demos-catalog__card-github"
target="_blank"
rel="noopener noreferrer"
aria-label="View {{ $demo.title }} on GitHub"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8Z" fill="currentColor"/>
</svg>
</a>
{{ end }}
</div>
<h3 class="demos-catalog__card-title">
<a
href="{{ $demo.link.url }}"
class="demos-catalog__card-link"
{{ if $isExternal }}target="_blank" rel="noopener noreferrer"{{ end }}
>
{{ $demo.title }}
</a>
</h3>
<p class="demos-catalog__card-description">{{ $demo.description }}</p>
</div>
</article>
@@ -1,4 +1,21 @@
{{- $all := .Params.demos | default slice -}}
{{/* Mimic Hugo Pages.ByWeight: non-zero lighter first; 0/unset last; title tiebreaker */}}
{{- $keyed := slice -}}
{{- range (.Params.demos | default slice) -}}
{{- $w := .weight | default 0 -}}
{{- $titleKey := .title | lower -}}
{{- $sortKey := "" -}}
{{- if eq $w 0 -}}
{{- $sortKey = printf "1-%s" $titleKey -}}
{{- else -}}
{{- /* Offset so negative weights still sort numerically as strings */ -}}
{{- $sortKey = printf "0-%010d-%s" (add $w 1000000) $titleKey -}}
{{- end -}}
{{- $keyed = $keyed | append (dict "sortKey" $sortKey "demo" .) -}}
{{- end -}}
{{- $all := slice -}}
{{- range (sort $keyed "sortKey" "asc") -}}
{{- $all = $all | append .demo -}}
{{- end -}}
{{- $filters := .Params.filters | default slice -}}
{{- $batchSize := .Params.batchSize | default 8 -}}
@@ -104,46 +121,10 @@
data-results-grid
>
{{ range $all }}
{{ $demo := . }}
{{ $isExternal := strings.HasPrefix .link.url "http" }}
{{- $searchParts := slice .title .description -}}
{{- range $filterKeySlice -}}
{{- with index $demo . -}}
{{- $searchParts = $searchParts | append . -}}
{{- end -}}
{{- end -}}
<a
href="{{ .link.url }}"
class="demos-catalog__card"
data-catalog-card
data-id="{{ .id }}"
data-name="{{ .title }}"
{{- range $filterKeySlice }}
data-{{ . }}="{{ index $demo . }}"
{{- end }}
data-search="{{ delimit $searchParts " " }}"
{{ if $isExternal }}target="_blank"{{ end }}
>
<div class="demos-catalog__card-image{{ if not .image }} demos-catalog__card-image--placeholder{{ end }}">
{{ with .image }}
{{ partial "picture.html" (dict
"src" .
"alt" $demo.title
"loading" "lazy"
"decoding" "async"
"width" "400"
"height" "148"
) }}
{{ else }}
<span class="demos-catalog__card-image-label" aria-hidden="true">Demo</span>
{{ end }}
</div>
<div class="demos-catalog__card-body">
<span class="demos-catalog__card-badge">{{ .category }}</span>
<h3 class="demos-catalog__card-title">{{ .title }}</h3>
<p class="demos-catalog__card-description">{{ .description }}</p>
</div>
</a>
{{ partial "demo/demos-catalog-card.html" (dict
"demo" .
"filterKeys" $filterKeySlice
) }}
{{ end }}
</div>
@@ -153,46 +134,11 @@
data-results-list
>
{{ range $all }}
{{ $demo := . }}
{{ $isExternal := strings.HasPrefix .link.url "http" }}
{{- $searchParts := slice .title .description -}}
{{- range $filterKeySlice -}}
{{- with index $demo . -}}
{{- $searchParts = $searchParts | append . -}}
{{- end -}}
{{- end -}}
<a
href="{{ .link.url }}"
class="demos-catalog__card demos-catalog__card--list"
data-catalog-card
data-id="{{ .id }}"
data-name="{{ .title }}"
{{- range $filterKeySlice }}
data-{{ . }}="{{ index $demo . }}"
{{- end }}
data-search="{{ delimit $searchParts " " }}"
{{ if $isExternal }}target="_blank" rel="noopener noreferrer"{{ end }}
>
<div class="demos-catalog__card-image{{ if not .image }} demos-catalog__card-image--placeholder{{ end }}">
{{ with .image }}
{{ partial "picture.html" (dict
"src" .
"alt" $demo.title
"loading" "lazy"
"decoding" "async"
"width" "800"
"height" "296"
) }}
{{ else }}
<span class="demos-catalog__card-image-label" aria-hidden="true">Demo</span>
{{ end }}
</div>
<div class="demos-catalog__card-body">
<span class="demos-catalog__card-badge">{{ .category }}</span>
<h3 class="demos-catalog__card-title">{{ .title }}</h3>
<p class="demos-catalog__card-description">{{ .description }}</p>
</div>
</a>
{{ partial "demo/demos-catalog-card.html" (dict
"demo" .
"filterKeys" $filterKeySlice
"list" true
) }}
{{ end }}
</div>