InfoCards

The Dashboard page opens with a set of infocards. Here is a simplified version of two of them.

<App
  var.dashboardStats="{
    {  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
  var.dashboardStats="{
    {  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>

The definition of var.dashboardStats uses two sets of curly braces. The outer braces enclose the JavaScript expression to be evaluated. The inner braces enclose a literal object that emulates data returned from an API.

In the real 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.

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>