Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
Svelte
at icy/tmrrpn
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108<script module lang="ts"> import { tv, type VariantProps } from "tailwind-variants";
export const shimmerText = tv({ // the sweep is sized by the text rather than by the column base: "inline-block w-fit", variants: { color: { inherit: "", default: "text-foreground-default", muted: "text-foreground-muted", subtle: "text-foreground-subtle", success: "text-foreground-success", danger: "text-foreground-danger", warning: "text-foreground-warning", info: "text-foreground-info" } }, defaultVariants: { color: "inherit" } });
export type ShimmerTextVariants = VariantProps<typeof shimmerText>;</script>
<script lang="ts"> import type { Snippet } from "svelte"; import type { HTMLAttributes } from "svelte/elements";
// text whose own colour is swept by a lighter (or, in dark mode, darker) // highlight — for pending states like "cloning", "running", "waiting for a // runner". Ported from spelte.dev/docs/shimmer-text, with the js animation // dropped for plain css and the palette swapped for our semantic tokens. interface Props extends Omit<HTMLAttributes<HTMLSpanElement>, "class" | "children"> { color?: ShimmerTextVariants["color"]; /** seconds for one full cycle — the sweep takes half of it, then it rests */ duration?: number; /** seconds to wait before the first sweep, for staggering several lines */ delay?: number; class?: string; children: Snippet; }
let { color = "inherit", duration = 3, delay = 0, class: className, children, ...rest }: Props = $props();
const classes = $derived(shimmerText({ color, class: className }));</script>
<span class="shimmer {classes}" style:--shimmer-duration="{duration}s" style:--shimmer-delay="{delay}s" {...rest}> {@render children()}</span>
<style> @keyframes shimmer { from { background-position-x: -100%; } 50%, to { background-position-x: 250%; } }
.shimmer { /* mixing towards the page colour lightens the highlight in light mode and darkens it in dark mode, so no dark: override is needed. override the custom property when the text sits on a non-default surface. */ --shimmer-highlight: color-mix(in srgb, currentColor 40%, var(--color-background-default));
background-color: currentColor; background-image: linear-gradient( to right, currentColor 0%, var(--shimmer-highlight) 40%, var(--shimmer-highlight) 60%, currentColor 100% ); background-repeat: no-repeat; background-size: 50% 200%; background-position-x: -100%; background-clip: text; -webkit-text-fill-color: transparent;
animation: shimmer var(--shimmer-duration) linear var(--shimmer-delay) infinite; }
/* parked off to the left, the gradient never shows and the flat background-color paints the text in its own colour */ @media (prefers-reduced-motion: reduce) { .shimmer { animation: none; } }</style>