Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions content/compare/_content.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{{/* Generate one comparison page per unordered pair of products that share a
category. Only products in the data/compare.yaml allowlist are eligible,
and pairs never cross categories (e.g. CMS vs Content provider).
Only slugs are stored in params; the layout looks up full data by slug. */}}

{{/* Allowlist set */}}
{{ $allow := dict }}
{{ range .Site.Data.compare.products }}
{{ $allow = merge $allow (dict . true) }}
{{ end }}

{{/* Group active, allowlisted products by category */}}
{{ $byCat := dict }}
{{ range $slug, $p := .Site.Data.products }}
{{ if and (not $p.discontinued) (index $allow $slug) }}
{{ range $p.categories }}
{{ $list := index $byCat . | default slice }}
{{ $byCat = merge $byCat (dict . ($list | append $slug)) }}
{{ end }}
{{ end }}
{{ end }}

{{ $seen := newScratch }}
{{ range $cat, $slugs := $byCat }}
{{ $sorted := sort $slugs }}
{{ range $i, $a := $sorted }}
{{ range $j, $b := $sorted }}
{{ if lt $i $j }}
{{ $key := printf "%s|%s" $a $b }}
{{ if not ($seen.Get $key) }}
{{ $seen.Set $key true }}
{{ $pa := index $.Site.Data.products $a }}
{{ $pb := index $.Site.Data.products $b }}
{{ $.AddPage (dict
"kind" "page"
"path" (printf "%s-vs-%s" $a $b)
"title" (printf "%s vs %s" $pa.name $pb.name)
"params" (dict
"a" $a
"b" $b
"cat" $cat
"seo_title" (printf "%s vs %s: Compare %s Digital Signage" $pa.name $pb.name $cat)
"description" (printf "Compare %s and %s, two %s digital signage products, side by side on pricing, supported platforms, and capabilities." $pa.name $pb.name $cat)
)
"content" (dict "mediaType" "text/html" "value" "")
) }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
6 changes: 6 additions & 0 deletions content/compare/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Compare Digital Signage Software"
build:
render: never
list: never
---
9 changes: 9 additions & 0 deletions content/updates/2026-07-27.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: "Compare products side by side"
date: 2026-07-27
description: "New side-by-side comparison pages for popular digital signage products."
---

You can now compare popular digital signage products head to head. Each comparison puts two products in the same category next to each other, with their pricing, supported platforms, headquarters, and capabilities laid out in one table.

To open one, look for the "Compare with" section on a product's page and pick another product.
54 changes: 54 additions & 0 deletions data/compare.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
products:
- 22miles
- anthias
- appspace
- axistv
- brightsign
- broadsign
- carousel
- cenareo
- dise
- displai
- displ
- embed-signage
- enplug
- fugo
- fusion-signage
- garlic-signage
- grassfish-ixm-platform
- info-beamer
- intuiface
- juuno
- kitcast
- korbyt
- lg-supersign
- livesignage
- magicinfo
- media4display
- mediacloud
- mvix
- navori
- novisign
- nowsignage
- omnivex
- onsign-tv
- optisigns
- pickcel
- pisignage
- playsignage
- poppulo
- posterbooking
- reach
- rise-vision
- scala
- screencloud
- screenly
- signagelive
- skykit
- spectrio
- spinetix-elementi
- telemetrytv
- uniguest
- wallboard
- xibo
- yodeck
80 changes: 80 additions & 0 deletions layouts/compare/single.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{{ define "main" }}
{{ $a := index site.Data.products .Params.a }}
{{ $b := index site.Data.products .Params.b }}
{{ $cat := .Params.cat }}

{{/* Small helpers */}}
{{ $yesno := "text-neutral-400" }}

<div class="max-w-4xl mx-auto px-6 py-8">

<nav class="text-sm text-neutral-400 mb-6 flex items-center gap-1.5">
<a href="/" class="hover:text-neutral-600 transition-colors">Home</a>
<span>/</span>
<span class="text-neutral-900 font-medium">{{ $a.name }} vs {{ $b.name }}</span>
</nav>

<h1 class="text-2xl font-semibold text-neutral-900 leading-tight">{{ $a.name }} vs {{ $b.name }}</h1>

{{/* SEO intro paragraph, generated from data */}}
<p class="text-neutral-600 mt-3 leading-relaxed">
{{ $a.name }} and {{ $b.name }} are both {{ $cat }} digital signage products.
{{ with $a.description }}{{ $a.name }} is {{ . | lower }}{{ end }}
{{ with $b.description }}{{ $b.name }} is {{ . | lower }}{{ end }}
This page compares them side by side on pricing, supported platforms, and capabilities so you can decide which fits your screens.
</p>

{{/* Two header cards */}}
<div class="grid grid-cols-2 gap-4 mt-6">
{{ range slice $a $b }}
<div class="bg-white rounded-2xl border border-neutral-200/80 shadow-sm p-5">
{{ partial "product-logo.html" (dict "Params" . "size" "lg") }}
<h2 class="text-base font-semibold text-neutral-900 mt-3">
<a href="/products/{{ .slug }}/" class="hover:text-neutral-600 transition-colors">{{ .name }}</a>
</h2>
{{ with .description }}<p class="text-sm text-neutral-500 mt-1.5 leading-relaxed">{{ . }}</p>{{ end }}
</div>
{{ end }}
</div>

{{/* Spec comparison table */}}
{{ $rows := slice
(dict "label" "Category" "a" (delimit $a.categories ", ") "b" (delimit $b.categories ", "))
(dict "label" "Headquarters" "a" (delimit $a.headquarters ", ") "b" (delimit $b.headquarters ", "))
(dict "label" "Founded" "a" ($a.year_founded) "b" ($b.year_founded))
(dict "label" "Platforms" "a" (delimit $a.platforms ", ") "b" (delimit $b.platforms ", "))
(dict "label" "Open source" "a" (cond $a.open_source "Yes" "No") "b" (cond $b.open_source "Yes" "No"))
(dict "label" "Self-signup" "a" (cond $a.self_signup "Yes" "No") "b" (cond $b.self_signup "Yes" "No"))
(dict "label" "API" "a" (cond $a.has_api "Yes" "No") "b" (cond $b.has_api "Yes" "No"))
(dict "label" "Documentation" "a" (cond (ne (printf "%v" $a.docs_url) "<nil>") "Yes" "No") "b" (cond (ne (printf "%v" $b.docs_url) "<nil>") "Yes" "No"))
}}
<div class="bg-white rounded-2xl border border-neutral-200/80 shadow-sm overflow-hidden mt-4">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-neutral-100 bg-neutral-50/50">
<th class="py-2.5 px-5 text-left text-xs font-medium text-neutral-400 uppercase tracking-wide"></th>
<th class="py-2.5 px-4 text-left text-xs font-medium text-neutral-500">{{ $a.name }}</th>
<th class="py-2.5 px-4 text-left text-xs font-medium text-neutral-500">{{ $b.name }}</th>
</tr>
</thead>
<tbody>
{{ range $rows }}
<tr class="border-b border-neutral-100 last:border-0">
<td class="py-3 px-5 text-neutral-400">{{ .label }}</td>
<td class="py-3 px-4 text-neutral-900">{{ if .a }}{{ .a }}{{ else }}<span class="text-neutral-300">—</span>{{ end }}</td>
<td class="py-3 px-4 text-neutral-900">{{ if .b }}{{ .b }}{{ else }}<span class="text-neutral-300">—</span>{{ end }}</td>
</tr>
{{ end }}
</tbody>
</table>
</div>

<div class="grid grid-cols-2 gap-4 mt-4">
{{ range slice $a $b }}
{{ $url := partial "outbound-url.html" (dict "url" .website "campaign" "compare_cta") | safeURL }}
<a href="{{ $url }}" target="_blank" rel="noopener nofollow ugc" class="inline-flex items-center justify-center gap-2 px-4 py-2.5 bg-neutral-900 text-white text-sm font-medium rounded-xl hover:bg-neutral-700 transition-colors">Visit {{ .name }}</a>
{{ end }}
</div>

</div>
{{ end }}
30 changes: 30 additions & 0 deletions layouts/products/single.html
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,36 @@ <h2 class="text-sm font-semibold text-neutral-900 mb-3">Notes</h2>

{{/* RSS Feed */}}
{{ partial "rss-feed.html" . }}

{{/* Comparisons — only for products in the compare allowlist */}}
{{ $allow := site.Data.compare.products }}
{{ if in $allow $p.slug }}
{{ $cur := index site.Data.products $p.slug }}
{{ $peers := slice }}
{{ range $allow }}
{{ if ne . $p.slug }}
{{ $peer := index site.Data.products . }}
{{ if and $peer (not $peer.discontinued) }}
{{ $shared := false }}
{{ range $peer.categories }}{{ if in $cur.categories . }}{{ $shared = true }}{{ end }}{{ end }}
{{ if $shared }}
{{ $pair := sort (slice $p.slug .) }}
{{ $peers = $peers | append (dict "name" $peer.name "url" (printf "/compare/%s-vs-%s/" (index $pair 0) (index $pair 1))) }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ if $peers }}
<div class="bg-white rounded-2xl border border-neutral-200/80 shadow-sm p-6">
<h2 class="text-sm font-semibold text-neutral-900 mb-3">Compare {{ $p.name }} with</h2>
<div class="flex flex-wrap gap-2">
{{ range sort $peers "name" }}
<a href="{{ .url }}" class="px-3 py-1.5 bg-neutral-100 text-neutral-700 rounded-lg text-sm hover:bg-neutral-200 transition-colors">{{ .name }}</a>
{{ end }}
</div>
</div>
{{ end }}
{{ end }}
</div>

{{/* ── Sidebar ── */}}
Expand Down
Loading