Skip to content
Open
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
102 changes: 102 additions & 0 deletions assets/css/components/marquee.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* Marquee — infinite scrolling banner */

.marquee-wrapper {
width: 100%;
overflow: hidden;
position: relative;
padding: 1rem 0;
mask-image: linear-gradient(
to right,
transparent 0%,
black 10%,
black 90%,
transparent 100%
);
-webkit-mask-image: linear-gradient(
to right,
transparent 0%,
black 10%,
black 90%,
transparent 100%
);
}

.marquee-track {
display: flex;
width: max-content;
animation: marquee-scroll var(--marquee-speed, 40s) linear infinite;
animation-direction: var(--marquee-direction, normal);
will-change: transform;
}

.marquee-track[data-pause-on-hover]:hover {
animation-play-state: paused;
}

.marquee-content {
display: flex;
gap: 1.5rem;
padding-right: 1.5rem;
}

.marquee-item {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
white-space: nowrap;
text-decoration: none;
cursor: default;
transition: all 0.2s ease;

@apply bg-neutral-100 dark:bg-neutral-800
border border-neutral-200 dark:border-neutral-700
text-neutral-700 dark:text-neutral-300;
}

a.marquee-item {
cursor: pointer;
}

.marquee-item:hover {
@apply border-primary-500 dark:border-primary-400
bg-neutral-50 dark:bg-neutral-700;
transform: translateY(-1px);
}

.marquee-item-icon {
width: 24px;
height: 24px;
object-fit: contain;
flex-shrink: 0;
}

.marquee-item-label {
font-size: 0.8125rem;
font-weight: 500;
line-height: 1;
}

@keyframes marquee-scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}

/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
.marquee-track {
animation: none;
}
.marquee-content[aria-hidden="true"] {
display: none;
}
.marquee-content {
flex-wrap: wrap;
justify-content: center;
}
}
53 changes: 53 additions & 0 deletions exampleSite/content/samples/marquee/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: "Marquee"
date: 2026-04-15
draft: false
description: "Demonstration of the marquee shortcode"
summary: "Showcase an infinite scrolling banner of items such as tech stacks, sponsors, or partner logos."
tags: ["shortcodes", "marquee"]
---

## Basic Usage

A simple marquee scrolling left at default speed:

{{< marquee >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/go/go-original.svg" >}}Go{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/python/python-original.svg" >}}Python{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/docker/docker-original.svg" >}}Docker{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/linux/linux-original.svg" >}}Linux{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/git/git-original.svg" >}}Git{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/kubernetes/kubernetes-original.svg" >}}Kubernetes{{< /marquee-item >}}
{{< /marquee >}}

## Custom Speed & Direction

Scrolling right at a slower pace:

{{< marquee speed="60" direction="right" >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/rust/rust-original.svg" >}}Rust{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/typescript/typescript-original.svg" >}}TypeScript{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/react/react-original.svg" >}}React{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/nextjs/nextjs-original.svg" >}}Next.js{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/postgresql/postgresql-original.svg" >}}PostgreSQL{{< /marquee-item >}}
{{< /marquee >}}

## With Links

Items can link to external pages:

{{< marquee speed="35" >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg" href="https://github.com" >}}GitHub{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/gitlab/gitlab-original.svg" href="https://gitlab.com" >}}GitLab{{< /marquee-item >}}
{{< marquee-item icon="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/bitbucket/bitbucket-original.svg" href="https://bitbucket.org" >}}Bitbucket{{< /marquee-item >}}
{{< /marquee >}}

## Text Only (No Icons)

{{< marquee speed="30" label="Partner list" >}}
{{< marquee-item >}}Acme Corp{{< /marquee-item >}}
{{< marquee-item >}}Globex Inc{{< /marquee-item >}}
{{< marquee-item >}}Initech{{< /marquee-item >}}
{{< marquee-item >}}Umbrella Corp{{< /marquee-item >}}
{{< marquee-item >}}Stark Industries{{< /marquee-item >}}
{{< /marquee >}}
11 changes: 11 additions & 0 deletions layouts/partials/vendor.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@
integrity="{{ $twelementsLib.Data.Integrity }}"></script>
{{ end }}

{{/* marquee */}}
{{ if .Page.HasShortcode "marquee" }}
{{ $marqueeCSS := resources.Get "css/components/marquee.css" }}
{{ $marqueeCSS = $marqueeCSS | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
<link
type="text/css"
rel="stylesheet"
href="{{ $marqueeCSS.RelPermalink }}"
integrity="{{ $marqueeCSS.Data.Integrity }}">
{{ end }}

{{/* youtubeLite */}}
{{ if .Page.HasShortcode "youtubeLite" }}
{{ $youtubeLiteCSS := resources.Get "lib/lite-youtube-embed/lite-yt-embed.css" }}
Expand Down
18 changes: 18 additions & 0 deletions layouts/shortcodes/marquee-item.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{ $icon := .Get "icon" }}
{{ $href := .Get "href" }}

{{ if $href }}
<a class="marquee-item" href="{{ $href }}" target="_blank" rel="noopener noreferrer">
{{- with $icon -}}
<img class="marquee-item-icon nozoom" src="{{ . }}" alt="" loading="lazy">
{{- end -}}
<span class="marquee-item-label">{{- .Inner | markdownify -}}</span>
</a>
{{ else }}
<span class="marquee-item">
{{- with $icon -}}
<img class="marquee-item-icon nozoom" src="{{ . }}" alt="" loading="lazy">
{{- end -}}
<span class="marquee-item-label">{{- .Inner | markdownify -}}</span>
</span>
{{ end }}
22 changes: 22 additions & 0 deletions layouts/shortcodes/marquee.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{ $id := delimit (slice "marquee" (partial "functions/uid.html" .) (now.UnixNano)) "-" }}
{{ $speed := default "40" (.Get "speed") }}
{{ $direction := default "left" (.Get "direction") }}
{{ $pauseOnHover := default true (.Get "pauseOnHover") }}

<div
id="{{ $id }}"
class="marquee-wrapper"
role="marquee"
aria-label="{{ .Get "label" | default "Scrolling content" }}">
<div
class="marquee-track"
style="--marquee-speed: {{ $speed }}s; --marquee-direction: {{ if eq $direction "right" }}reverse{{ else }}normal{{ end }};"
{{ if $pauseOnHover }}data-pause-on-hover{{ end }}>
<div class="marquee-content" aria-hidden="false">
{{- .Inner -}}
</div>
<div class="marquee-content" aria-hidden="true">
{{- .Inner -}}
</div>
</div>
</div>