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>infocards
<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
InfoCards used in the Invoices app.<App>
<Dashboard />
</App><App>
<Dashboard />
</App>