Create a dashboard to visualize your Airtable data using Konsta UI. Ideal for tracking purchases, customers, and earnings
Build a responsive mobile dashboard app using Konsta UI and TailwindCSS to interact with your Airtable base.
Create a Token
👉 https://airtable.com/create/tokens
Scopes:
data.records:read
, data.records:write
, schema.bases:read
, schema.bases:write
Access: Choose your workspace
Create a Table
Format: https://airtable.com/appXXX/tblXXX/viwXXX
Initialize the table with the expected schema in your Airtable note.
Configure Access in Znote Copy the following values:
airtable_base
→ "appXXX"
airtable_token
→ "XXXXX"
airtable_table
→ "tblXXX"
Write Credentials
{
"airtable_base": "appXXXXX",
"airtable_token": "XXXXXXX",
"airtable_table": "tblXXXXXX"
}
const credentials = loadBlock('credentials');
_fs.writeFileSync(`${__dirname}/credentials-airtable-properties.json`, credentials);
Install dependencies:
npm i -S konsta tailwindcss
Tailwind Config (
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
safelist: [
'text-2xl',
'text-3xl',
'grow',
'sm:flex-1',
'md:flex',
{
pattern: /bg-(red|green|blue)-(100|200|300|400|500)/,
variants: ['lg', 'hover', 'focus', 'lg:hover'],
},
],
});
CSS Entry (
@tailwind base;
@tailwind components;
@tailwind utilities;
Write config files and build CSS:
const config = loadBlock('konstaConfig');
const basecss = loadBlock('inputcss');
_fs.writeFileSync(`${__dirname}/tailwind.config.js`, config);
_fs.writeFileSync(`${__dirname}/input.css`, basecss);
npx tailwindcss -i ./input.css -o ./output.css
In Znote Settings, add:
konsta
output.css
import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom';
import { App, Page, Navbar, Block, BlockTitle, Badge, List, ListItem, Card } from 'konsta/react';
const properties = require("./credentials-airtable-properties.json");
const Airtable = require("./airtable-api.js");
const airtable = new Airtable(properties.airtable_token, properties.airtable_base);
const PRODUCT_PRICE = 135;
const MyApp = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
(async () => {
const result = await airtable.listRecordsSorted(properties.airtable_table, 100, 0, "purchaseDate");
setUsers(result.records);
})();
}, []);
const filterThisMonth = (user) => {
return new Date(user.fields.purchaseDate).getMonth() === new Date().getMonth();
};
return (
<App theme="ios">
<Page>
<Navbar title="My Dashboard" />
<BlockTitle>Statistics</BlockTitle>
<Block className="sm:flex-1 md:flex">
<Card className="grow" raised header="Earning" footer={<Badge>+${users.filter(filterThisMonth).length * PRODUCT_PRICE} this month</Badge>}>
<span className="text-3xl text-black font-bold">${users.length * PRODUCT_PRICE}</span>
</Card>
<Card className="grow" raised header="Customers 🧑💻" footer={<Badge>+{users.filter(filterThisMonth).length} this month</Badge>}>
<span className="text-3xl text-black font-bold">{users.length}</span>
</Card>
</Block>
<BlockTitle>Recent Purchases</BlockTitle>
<List strong outline inset>
{users.map((u) => (
<ListItem
key={u.id}
title={u.fields.Email}
after={
<>
<Badge colors={{ bg: 'bg-green-500' }}>V{u.fields.version}</Badge>
<span className="text-md text-black font-bold">{u.fields.purchaseDate}</span>
</>
}
/>
))}
</List>
</Page>
</App>
);
};
ReactDOM.render(<MyApp />, htmlEl);