InfoCards
The
Dashboard
page opens with a set of infocards. Here is a simplified version of two of them.<App>
<variable name="dashboardStats" value="{
{
value:
[
{ outstanding: 3569, paid_this_year: 1745}
]
}
}" />
<HStack>
<Card>
<Text>Outstanding</Text>
<Text>{ dashboardStats.value[0].outstanding } </Text>
</Card>
<Card>
<Text>Paid this year</Text>
<Text>{ dashboardStats.value[0].paid_this_year } </Text>
</Card>
</HStack>
</App>
<App>
<variable name="dashboardStats" value="{
{
value:
[
{ outstanding: 3569, paid_this_year: 1745}
]
}
}" />
<HStack>
<Card>
<Text>Outstanding</Text>
<Text>{ dashboardStats.value[0].outstanding } </Text>
</Card>
<Card>
<Text>Paid this year</Text>
<Text>{ dashboardStats.value[0].paid_this_year } </Text>
</Card>
</HStack>
</App>
In the app,
dashboardStats
is a DataSource.<DataSource id="dashboardStats" url="/api/dashboard/stats" method="GET" />
It returns a structure like the variable we've defined above: an object with a
value
key that points to a list of objects corresponding to rows in the database. In this case there's only one row because the query behind /api/dashboard/stats
reports multiple values (count of invoices, total amount outstanding, total amount paid this year, etc) as columns in that single row.A custom Card
There are five infocards on the XMLUI Invoice dashboard. To style them all in a consistent way, the app defines an
InfoCard
that wraps Card
and Text
.<Component name="InfoCard">
<Card width="{$props.width}" borderRadius="8px" boxShadow="$boxShadow-spread">
<Text>{$props.title}</Text>
<Text fontWeight="$fontWeight-extra-bold" fontSize="larger">
{ $props.currency === 'true' ? '$' + $props.value : $props.value }
</Text>
</Card>
</Component>
These are in turn wrapped in a
Dashboard
that passes properties to InfoCard
: title
, width
, value
, and optionally a currency
flag for $
formatting.<Component name="Dashboard">
<DataSource id="dashboardStats" url="/api/dashboard/stats" method="GET"/>
<HStack>
<H1>Dashboard</H1>
<SpaceFiller/>
<Button label="Create Invoice" onClick="navigate('/invoices/new')"/>
</HStack>
<FlowLayout>
<InfoCard
width="20%"
title="Outstanding"
value="{ dashboardStats.value[0] }"
currency='true'
/>
<InfoCard
...
/>
<InfoCard
...
/>
<InfoCard
...
/>
<InfoCard
...
/>
<Statuses width="50%" title="Statuses"/>
<MonthlyStatus width="50%" title="Monthly Status"/>
</FlowLayout>
<DailyRevenue title="Daily Revenue"/>
</Component>
A user-defined component like
Dashboard
can define any set of names and values. InfoCard
receives them in its $props
context variable. InfoCard
is opinionated about borderRadius
and boxShadow
. It could also receive these in $props
but chooses not to. And while it is strongly opinionated about the borderRadius
, which it hardcodes, it is willing to use the theme variable $boxShadow-spread
so that setting can be theme-governed.Here's a more complete version of the row of
InfoCard
s used in the Invoices app.<App>
<Dashboard />
</App>
<App>
<Dashboard />
</App>