K

Core

ProgressWidget

Řádky výplně proti dráze — jak daleko je číslo k číslu, kterého má dosáhnout, a položka, ze které je každý řádek složený.

Na této stránce

Panel pro číslo, které někam míří: prodejní kvóta, utracený rozpočet, zaplňující se disk, dohořívající sprint. Statistická karta říká číslo a sloupcový graf porovnává čísla mezi sebou; ani jedno neřekne, jak daleko po cestě to číslo je — a přesně na to výplň proti dráze odpoví jedním pohledem.

use NyonCode\WireCore\Widgets\ProgressWidget;

Jak to funguje

Čisté CSS, vyřešené na serveru. Stejně jako BarChartWidget a na rozdíl od ChartWidget tu není žádný Chart.js, žádné plátno a není na co čekat. Geometrii každého řádku počítá ProgressItem::getPercentage() v PHP — aritmetika v šabloně je aritmetika, kterou nic neotestuje.

Zlomek a jeho tři okraje. value / target × 100, oříznuté na 0–100 z obou stran:

Hodnota Vykreslí se jako Proč
value(300)->target(120) plná dráha Výplň je šířka v pevné krabici; překročený cíl nesmí nakreslit pruh širší než jeho dráha
value(-40)->target(120) prázdná dráha Ne pruh rostoucí doleva
target(0) prázdná dráha „0 z 0“ je mnohem častěji nenakonfigurovaný řádek než hotový, a plný pruh by ohlásil úspěch, kterého nikdo nedosáhl

Co každý řádek vypíše. Zaokrouhlená procenta, pokud formattedValue() neřekne jinak. Záměrně ne number_format($value): oddělovač tisíců a desetinná značka jsou rozhodnutí o locale a widget je špatné místo, kde ho dělat za volajícího. Kdo chce 1.2M / 2M, napíše přesně to.

Odkud se bere série. items() bere pole nebo closure. Closure dostane aktivní klíč filtru widgetu, běží při každém renderu a nikdy se nememoizuje — takže filtr na tomto widgetu data opravdu znovu vyřeší. Viz Filtry.

Co to stojí. Jeden render view na celý widget, ať je řádků kolik chce. Žádný render na řádek neexistuje: řádky jsou @foreach uvnitř vlastní šablony widgetu.

Past. Šířka výplně je inline style, ne třída Tailwindu. Procento je spojitá hodnota a utility třída je pevná množina, takže w-[73.4%] by vyžadovalo, aby JIT přesně to číslo viděl při buildu. Číslo se vyřeší a ořízne v PHP a nikdy se nedostane do názvu třídy, takže nic, co volající dodá, nemůže žádnou vsunout.

Základní použití

ProgressWidget::make()
->heading('Quarterly targets')
->items([
ProgressItem::make('New MRR')->value(84_000)->target(120_000)->color('success'),
ProgressItem::make('Churn budget')->value(31)->target(40)->color('warning'),
])

Hodnoty na řádcích

Každý řádek vypíše svůj údaj vedle popisku. Na husté nástěnce, kde je porovnáním sama výplň, ho vypněte a nechte mluvit pruhy:

ProgressWidget::make()
->items($items)
->showValues(false)

Formátování údaje

ProgressItem::make('Storage')
->value(412)
->target(1_000)
->formattedValue('412 GB / 1 TB') // vypíše se místo „41 %“

Prázdný stav

Widget, jehož dotaz se vrátil bez záznamů, ukáže větu, ne prázdnou kartu:

ProgressWidget::make()
->items(fn () => $this->quotas())
->emptyState('No targets set for this quarter.')

Předání null vrátí výchozí text (Není co zobrazit., přeložený).

Přístupnost

Každá dráha je role="progressbar" a nese aria-valuenow, aria-valuemin a aria-valuemax, popsaná popiskem řádku. Vypsaná hodnota je označená aria-hidden, protože stejný údaj už na pruhu je — bez toho by odečítač obrazovky každý řádek přečetl dvakrát.

Rozšířený příklad

namespace App\Dashboards;
 
use App\Models\Deal;
use NyonCode\WireCore\Widgets\Dashboard;
use NyonCode\WireCore\Widgets\ProgressItem;
use NyonCode\WireCore\Widgets\ProgressWidget;
 
class SalesDashboard extends Dashboard
{
public function widgets(): array
{
return [
ProgressWidget::make()
->heading('Quota attainment')
->description('Closed-won against target, per rep')
->columnSpan('full')
->filter(['quarter' => 'This quarter', 'year' => 'This year'])
->items(fn (?string $range) => Deal::quotaProgress($range)
->map(fn (array $row) => ProgressItem::make($row['rep'])
->value($row['closed'])
->target($row['quota'])
->formattedValue($row['closed_formatted'].' / '.$row['quota_formatted'])
->description($row['deals'].' deals')
->color($row['closed'] >= $row['quota'] ? 'success' : 'primary'))
->all())
->emptyState('No quotas configured.'),
];
}
}

ProgressWidget API

->showValues(bool $condition = true) // vypsat údaj vedle popisku každého řádku — výchozí true
->showsValues(): bool

Vše ostatní, co progress widget bere, je sdílené a zdokumentované centrálně: items(), emptyState(), filter(), lazy(), heading(), columnSpan(), pollingInterval() a settery autorizace jsou na základní třídě widgetu.


ProgressItem

Jeden řádek: popisek, údaj a údaj, ke kterému míří.

use NyonCode\WireCore\Widgets\ProgressItem;

Úplný příklad

ProgressItem::make('New MRR')
->value(84_000)
->target(120_000)
->formattedValue('84K / 120K')
->description('vs. 71K last quarter')
->icon('outline:arrow-trending-up')
->color('success')
->extraAttributes(['data-testid' => 'mrr'])

ProgressItem API

Vytváří se přes ProgressItem::make(string $label).

->value(int|float $value) // aktuální údaj — výchozí 0
->target(int|float $target) // kam míří — výchozí 100
->description(?string $description) // druhý řádek pod popiskem
->formattedValue(?string $value) // vypíše se místo procent
->icon(string|Icon|null $icon) // ikona vedle popisku
->color(?string $color) // libovolný klíč palety ('success', 'danger', …)
->extraAttributes(array $attrs) // vlastní HTML atributy na řádku
->getLabel(): string
->getValue(): float
->getTarget(): float
->getPercentage(): float // 0–100, oříznuté
->isComplete(): bool // údaj dosáhl svého cíle
->getFormattedValue(): string
->getDescription(): ?string
->getIcon(): ?string
->getColor(): ?string

Související

  • Statistiky — číslo s trendem, když není žádný cíl, kterého se má dosáhnout
  • GrafyBarChartWidget, když je porovnání mezi čísly navzájem, ne proti cíli
  • Seznamy — druhý čistě CSS widget, pro položky místo čísel
  • Widgety — sdílený základ: polling, filtry, odklad, autorizace