summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/tool-count-label.tsx
blob: c374d2d3762c526297afd8ace8e3bedc09fc8b77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import { createMemo } from "solid-js"
import { AnimatedNumber } from "./animated-number"
import { commonPrefix } from "./text-utils"

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),
  }
}

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(() => commonPrefix(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().prefix : active().after))
  const tail = createMemo(() => {
    if (!splitSuffix()) return ""
    if (singular()) return suffix().aSuffix
    return suffix().bSuffix
  })
  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>
  )
}