Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions __tests__/hero-panel.test.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,10 @@ import { Clock } from "lucide-react";
import { describe, expect, it } from "vitest";
import { HeroPanel } from "@/components/molecules/hero-panel";

function readValueCqi(element: HTMLElement): number {
return Number.parseFloat(/([\d.]+)cqi/.exec(element.style.getPropertyValue("--hero-value-size"))?.[1] ?? "");
}

describe("HeroPanel", () => {
it("renders the label and the highlighted value", () => {
render(<HeroPanel icon={Clock} label="FALTAM" value="01:23:45" tone="emerald" />);
Expand DownExpand Up@@ -30,6 +34,24 @@ describe("HeroPanel", () => {
expect(screen.getByText("Resumo Financeiro")).toBeInTheDocument();
});

it("shrinks the font as the value gets longer so it never wraps", () => {
const { rerender } = render(<HeroPanel icon={Clock} label="Valor" value="R$ 25,00" tone="blue" />);
const shortValueCqi = readValueCqi(screen.getByText("R$ 25,00"));

rerender(<HeroPanel icon={Clock} label="Valor" value="R$ 926.150,68" tone="blue" />);
const longValueCqi = readValueCqi(screen.getByText("R$ 926.150,68"));

expect(shortValueCqi).toBeGreaterThan(0);
expect(longValueCqi).toBeLessThan(shortValueCqi);
});

it("still asks for a finite size when there is no value to show", () => {
const { container } = render(<HeroPanel icon={Clock} label="Valor" value="" tone="blue" />);
const valueElement = container.querySelector<HTMLElement>("p.font-black");

expect(readValueCqi(valueElement as HTMLElement)).toBeGreaterThan(0);
});

it("omits the footer separator when there is no footer", () => {
render(<HeroPanel icon={Clock} label="HORA EXTRA" value="00:10:00" tone="rose" />);

Expand Down
15 changes: 12 additions & 3 deletions components/molecules/hero-panel.tsx
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
import type { ElementType, ReactNode } from "react";
import type { CSSProperties, ElementType, ReactNode } from "react";
import { cn } from "@/lib/utils";

const TONE_CLASSES = {
Expand All@@ -7,6 +7,8 @@ const TONE_CLASSES = {
blue: "bg-blue-600 shadow-blue-500/30",
} as const;

const VALUE_INLINE_SIZE_CQI = 208;

interface HeroPanelProps {
icon: ElementType;
label: string;
Expand DownExpand Up@@ -37,8 +39,15 @@ export function HeroPanel({ icon: Icon, label, value, tone, badge, footer, child
</div>
{badge}
</div>
<div className="space-y-4 text-center">
<p className="text-4xl sm:text-6xl xl:text-8xl font-black tracking-tighter tabular-nums break-words">
<div className="@container space-y-4 text-center">
<p
className="font-black tracking-tighter tabular-nums whitespace-nowrap text-[length:var(--hero-value-size)]"
style={
{
"--hero-value-size": `clamp(1.5rem, ${VALUE_INLINE_SIZE_CQI / Math.max(1, value.length)}cqi, 6rem)`,
} as CSSProperties
}
>
{value}
</p>
{children}
Expand Down