Files
tabler/core/scss/ui/_text-shimmer.scss

93 lines
3.0 KiB
SCSS

@use '../config' as *;
// A highlight that sweeps across the text, for "Thinking…" or "Generating…" labels
.text-shimmer {
// scss-docs-start text-shimmer-css-vars
--text-shimmer-duration: #{$text-shimmer-duration};
--text-shimmer-opacity: #{$text-shimmer-opacity};
--text-shimmer-width: #{$text-shimmer-width};
--text-shimmer-fade-duration: #{$text-shimmer-fade-duration};
--text-shimmer-fade-easing: #{$text-shimmer-fade-easing};
--text-shimmer-loader-size: #{$text-shimmer-loader-size};
--text-shimmer-loader-border-width: #{$text-shimmer-loader-border-width};
--text-shimmer-loader-margin: #{$text-shimmer-loader-margin};
--text-shimmer-loader-duration: #{$text-shimmer-loader-duration};
--text-shimmer-loader-opacity: #{$text-shimmer-loader-opacity};
// scss-docs-end text-shimmer-css-vars
display: inline-block;
// The mask dims the text and lets a band of full opacity move through it, so the text keeps its own color
mask-image: linear-gradient(90deg, rgba(0, 0, 0, var(--text-shimmer-opacity)) calc(50% - var(--text-shimmer-width) / 2), $black 50%, rgba(0, 0, 0, var(--text-shimmer-opacity)) calc(50% + var(--text-shimmer-width) / 2));
mask-size: 300% 100%;
// The label fades in once, then the highlight keeps sweeping
animation:
text-shimmer-in var(--text-shimmer-fade-duration) var(--text-shimmer-fade-easing) both,
text-shimmer var(--text-shimmer-duration) linear infinite;
@media (prefers-reduced-motion: reduce) {
mask-image: none;
animation: none;
}
}
// A small spinner before the label: the element is a 1em box, ::before draws
// a faint ring in the text color and ::after the bright arc that turns on top
// of it. It sits inside the mask, so it dims and lights up with the text
.text-shimmer-loader {
position: relative;
display: inline-block;
width: 1em;
height: 1em;
margin-inline-end: var(--text-shimmer-loader-margin);
vertical-align: -0.125em;
// The ring is --text-shimmer-loader-size wide, centered in the 1em box
&::before,
&::after {
position: absolute;
inset: 0;
width: var(--text-shimmer-loader-size);
height: var(--text-shimmer-loader-size);
margin: auto;
content: '';
border: var(--text-shimmer-loader-border-width) solid;
border-radius: 50%;
}
&::before {
border-color: currentColor;
opacity: var(--text-shimmer-loader-opacity);
}
&::after {
border-color: currentColor transparent transparent;
animation: rotate-360 var(--text-shimmer-loader-duration) linear infinite;
@media (prefers-reduced-motion: reduce) {
animation-duration: calc(var(--text-shimmer-loader-duration) * 2);
}
}
}
@keyframes text-shimmer-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
// The highlight travels in the reading direction: --dir flips the start and end in RTL
@keyframes text-shimmer {
from {
/* rtl:ignore */
mask-position: calc(50% + var(--dir) * 50%) 0;
}
to {
/* rtl:ignore */
mask-position: calc(50% - var(--dir) * 50%) 0;
}
}