mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-22 16:44:36 +00:00
Animation Smorgasbord (#15637)
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
This commit is contained in:
58
packages/ui/src/components/tool-count-label.tsx
Normal file
58
packages/ui/src/components/tool-count-label.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { createMemo } from "solid-js"
|
||||
import { AnimatedNumber } from "./animated-number"
|
||||
|
||||
function split(text: string) {
|
||||
const match = /{{\s*count\s*}}/.exec(text)
|
||||
if (!match) return { before: "", after: text }
|
||||
if (match.index === undefined) return { before: "", after: text }
|
||||
return {
|
||||
before: text.slice(0, match.index),
|
||||
after: text.slice(match.index + match[0].length),
|
||||
}
|
||||
}
|
||||
|
||||
function common(one: string, other: string) {
|
||||
const a = Array.from(one)
|
||||
const b = Array.from(other)
|
||||
let i = 0
|
||||
while (i < a.length && i < b.length && a[i] === b[i]) i++
|
||||
return {
|
||||
stem: a.slice(0, i).join(""),
|
||||
one: a.slice(i).join(""),
|
||||
other: b.slice(i).join(""),
|
||||
}
|
||||
}
|
||||
|
||||
export function AnimatedCountLabel(props: { count: number; one: string; other: string; class?: string }) {
|
||||
const one = createMemo(() => split(props.one))
|
||||
const other = createMemo(() => split(props.other))
|
||||
const singular = createMemo(() => Math.round(props.count) === 1)
|
||||
const active = createMemo(() => (singular() ? one() : other()))
|
||||
const suffix = createMemo(() => common(one().after, other().after))
|
||||
const splitSuffix = createMemo(
|
||||
() =>
|
||||
one().before === other().before &&
|
||||
(one().after.startsWith(other().after) || other().after.startsWith(one().after)),
|
||||
)
|
||||
const before = createMemo(() => (splitSuffix() ? one().before : active().before))
|
||||
const stem = createMemo(() => (splitSuffix() ? suffix().stem : active().after))
|
||||
const tail = createMemo(() => {
|
||||
if (!splitSuffix()) return ""
|
||||
if (singular()) return suffix().one
|
||||
return suffix().other
|
||||
})
|
||||
const showTail = createMemo(() => splitSuffix() && tail().length > 0)
|
||||
|
||||
return (
|
||||
<span data-component="tool-count-label" class={props.class}>
|
||||
<span data-slot="tool-count-label-before">{before()}</span>
|
||||
<AnimatedNumber value={props.count} />
|
||||
<span data-slot="tool-count-label-word">
|
||||
<span data-slot="tool-count-label-stem">{stem()}</span>
|
||||
<span data-slot="tool-count-label-suffix" data-active={showTail() ? "true" : "false"}>
|
||||
<span data-slot="tool-count-label-suffix-inner">{tail()}</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user