Merge pull request #152 from fsolla/cursor/pool-i150-ccf81e9f-a156
B111 — Início strip edge-to-edge + delta flat silencioso
This commit is contained in:
commit
64e7be699f
6 changed files with 61 additions and 7 deletions
|
|
@ -15,11 +15,14 @@ const HomeChromeRetractionShell = ({
|
|||
slot,
|
||||
className,
|
||||
children,
|
||||
allowHorizontalBleed = false,
|
||||
}: {
|
||||
retracted: boolean
|
||||
slot?: string
|
||||
className?: string
|
||||
children: ReactNode
|
||||
/** B111 — keep Y clip for grid-rows retraction without clipping -mx bleed on X. */
|
||||
allowHorizontalBleed?: boolean
|
||||
}) => (
|
||||
<div
|
||||
data-slot={slot}
|
||||
|
|
@ -27,7 +30,12 @@ const HomeChromeRetractionShell = ({
|
|||
className={cn(homeChromeRetractionClass(retracted), className)}
|
||||
aria-hidden={retracted || undefined}
|
||||
>
|
||||
<div className="min-h-0 overflow-hidden">{children}</div>
|
||||
<div
|
||||
className={cn('min-h-0', allowHorizontalBleed ? 'overflow-y-hidden' : 'overflow-hidden')}
|
||||
data-allow-horizontal-bleed={allowHorizontalBleed || undefined}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
|
@ -63,6 +71,7 @@ export const CampaignHomeLayout = ({
|
|||
retracted={focused}
|
||||
slot="home-actions-chrome"
|
||||
className="order-1 md:order-2"
|
||||
allowHorizontalBleed
|
||||
>
|
||||
<div
|
||||
data-slot="home-actions"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ArrowDownIcon, ArrowUpIcon, MinusIcon } from 'lucide-react'
|
||||
import { ArrowDownIcon, ArrowUpIcon } from 'lucide-react'
|
||||
|
||||
import { Progress } from '@/components/ui/Progress'
|
||||
import {
|
||||
|
|
@ -6,6 +6,7 @@ import {
|
|||
homeSummaryDeltaAriaLabel,
|
||||
homeSummaryDeltaPeriodLabel,
|
||||
resolveHomeSummaryDeltaDirection,
|
||||
shouldShowHomeSummaryDelta,
|
||||
} from '@/lib/campaignHomeSummaryDelta'
|
||||
import { formatElectionNumber } from '@/lib/electionFormat'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
|
@ -16,6 +17,8 @@ import {
|
|||
} from '@/utilities/municipality/goalCoverage'
|
||||
|
||||
const HomeSummaryDelta = ({ delta }: { delta: number | null }) => {
|
||||
if (!shouldShowHomeSummaryDelta(delta)) return null
|
||||
|
||||
const direction = resolveHomeSummaryDeltaDirection(delta)
|
||||
const magnitude = formatHomeSummaryDeltaMagnitude(delta)
|
||||
|
||||
|
|
@ -26,13 +29,11 @@ const HomeSummaryDelta = ({ delta }: { delta: number | null }) => {
|
|||
'inline-flex items-center gap-0.5 text-sm font-medium tabular-nums',
|
||||
direction === 'up' && 'text-emerald-700 dark:text-emerald-400',
|
||||
direction === 'down' && 'text-rose-700 dark:text-rose-400',
|
||||
(direction === 'flat' || direction === 'unavailable') && 'text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{direction === 'up' ? <ArrowUpIcon aria-hidden className="size-3.5 shrink-0" /> : null}
|
||||
{direction === 'down' ? <ArrowDownIcon aria-hidden className="size-3.5 shrink-0" /> : null}
|
||||
{direction === 'flat' ? <MinusIcon aria-hidden className="size-3.5 shrink-0" /> : null}
|
||||
<span>{magnitude ?? '—'}</span>
|
||||
<span>{magnitude}</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
@ -47,7 +48,7 @@ export const CampaignHomeSummary = ({ view }: { view: CampaignHomeSummaryView })
|
|||
</p>
|
||||
<HomeSummaryDelta delta={view.homeSummaryDelta} />
|
||||
</div>
|
||||
{view.homeSummaryDelta !== null ? (
|
||||
{shouldShowHomeSummaryDelta(view.homeSummaryDelta) ? (
|
||||
<p className="text-xs text-muted-foreground">{homeSummaryDeltaPeriodLabel}</p>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ export const resolveHomeSummaryDeltaDirection = (
|
|||
return delta > 0 ? 'up' : 'down'
|
||||
}
|
||||
|
||||
/** B111 — render the Δ chip only when there was movement in the window. */
|
||||
export const shouldShowHomeSummaryDelta = (delta: number | null): boolean =>
|
||||
delta !== null && delta !== 0
|
||||
|
||||
/** Absolute magnitude for display; null when unavailable; "0" when flat. */
|
||||
export const formatHomeSummaryDeltaMagnitude = (delta: number | null): string | null => {
|
||||
if (delta === null) return null
|
||||
|
|
|
|||
|
|
@ -30,6 +30,16 @@ describe('CampaignHomeLayout', () => {
|
|||
expect(actions?.className).toContain('md:w-auto')
|
||||
})
|
||||
|
||||
it('does not clip horizontal bleed on the actions retraction shell', () => {
|
||||
const { container } = render(<CampaignHomeLayout actions={<p>Actions block</p>} />)
|
||||
|
||||
const actionsChrome = container.querySelector('[data-slot="home-actions-chrome"]')
|
||||
const bleedWrapper = actionsChrome?.querySelector('[data-allow-horizontal-bleed="true"]')
|
||||
expect(bleedWrapper).not.toBeNull()
|
||||
expect(bleedWrapper?.className).toContain('overflow-y-hidden')
|
||||
expect(bleedWrapper?.className).not.toContain('overflow-hidden')
|
||||
})
|
||||
|
||||
it('renders search slot inside home-dock when provided', () => {
|
||||
render(
|
||||
<CampaignHomeLayout
|
||||
|
|
|
|||
|
|
@ -50,7 +50,29 @@ describe('CampaignHomeSummary', () => {
|
|||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByLabelText('Variação nos últimos 7 dias indisponível')).toBeTruthy()
|
||||
expect(screen.queryByLabelText(/nos últimos 7 dias/)).toBeNull()
|
||||
expect(screen.queryByRole('progressbar')).toBeNull()
|
||||
})
|
||||
|
||||
it('omits the delta chip and period caption when delta is flat', () => {
|
||||
render(
|
||||
<CampaignHomeSummary
|
||||
view={{
|
||||
staffVoteTotalCentral: 12_345,
|
||||
homeSummaryDelta: 0,
|
||||
goalCoverage: {
|
||||
goal: 0,
|
||||
committed: 0,
|
||||
coverageRatio: null,
|
||||
deficit: 0,
|
||||
},
|
||||
}}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('12.345')).toBeTruthy()
|
||||
expect(screen.queryByLabelText(/nos últimos 7 dias/)).toBeNull()
|
||||
expect(screen.queryByText('nos últimos 7 dias')).toBeNull()
|
||||
expect(screen.queryByText('0')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
formatHomeSummaryDeltaMagnitude,
|
||||
homeSummaryDeltaAriaLabel,
|
||||
resolveHomeSummaryDeltaDirection,
|
||||
shouldShowHomeSummaryDelta,
|
||||
} from '@/lib/campaignHomeSummaryDelta'
|
||||
|
||||
describe('campaignHomeSummaryDelta', () => {
|
||||
|
|
@ -30,4 +31,11 @@ describe('campaignHomeSummaryDelta', () => {
|
|||
expect(homeSummaryDeltaAriaLabel(0)).toBe('Sem variação nos últimos 7 dias')
|
||||
expect(homeSummaryDeltaAriaLabel(null)).toBe('Variação nos últimos 7 dias indisponível')
|
||||
})
|
||||
|
||||
it('shows the delta chip only when movement occurred', () => {
|
||||
expect(shouldShowHomeSummaryDelta(500)).toBe(true)
|
||||
expect(shouldShowHomeSummaryDelta(-200)).toBe(true)
|
||||
expect(shouldShowHomeSummaryDelta(0)).toBe(false)
|
||||
expect(shouldShowHomeSummaryDelta(null)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue