diff --git a/assets/css/components/marquee.css b/assets/css/components/marquee.css new file mode 100644 index 000000000..a56649ad7 --- /dev/null +++ b/assets/css/components/marquee.css @@ -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; + } +} diff --git a/exampleSite/content/samples/marquee/index.md b/exampleSite/content/samples/marquee/index.md new file mode 100644 index 000000000..f665b4bf6 --- /dev/null +++ b/exampleSite/content/samples/marquee/index.md @@ -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 >}} diff --git a/layouts/partials/vendor.html b/layouts/partials/vendor.html index 79f03d55c..54094debd 100644 --- a/layouts/partials/vendor.html +++ b/layouts/partials/vendor.html @@ -97,6 +97,17 @@ integrity="{{ $twelementsLib.Data.Integrity }}"> {{ end }} +{{/* marquee */}} +{{ if .Page.HasShortcode "marquee" }} + {{ $marqueeCSS := resources.Get "css/components/marquee.css" }} + {{ $marqueeCSS = $marqueeCSS | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }} + +{{ end }} + {{/* youtubeLite */}} {{ if .Page.HasShortcode "youtubeLite" }} {{ $youtubeLiteCSS := resources.Get "lib/lite-youtube-embed/lite-yt-embed.css" }} diff --git a/layouts/shortcodes/marquee-item.html b/layouts/shortcodes/marquee-item.html new file mode 100644 index 000000000..90cfa1bb0 --- /dev/null +++ b/layouts/shortcodes/marquee-item.html @@ -0,0 +1,18 @@ +{{ $icon := .Get "icon" }} +{{ $href := .Get "href" }} + +{{ if $href }} + + {{- with $icon -}} + + {{- end -}} + {{- .Inner | markdownify -}} + +{{ else }} + + {{- with $icon -}} + + {{- end -}} + {{- .Inner | markdownify -}} + +{{ end }} diff --git a/layouts/shortcodes/marquee.html b/layouts/shortcodes/marquee.html new file mode 100644 index 000000000..c850e729b --- /dev/null +++ b/layouts/shortcodes/marquee.html @@ -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") }} + +
+
+
+ {{- .Inner -}} +
+ +
+