Hourglass — hours and fee note
Worked hours turn into a fee note by themselves: log, review, print.
data space «studio-pro-en» — the suite’s glue: on your device, multi-user with one invite (link or QR), end-to-end encrypted.
▶ Open the suite (3 micro apps)
Integrates with: Datebook — same data space.
What it records
- Activity carried out
- Hours (e.g. 1.5)
- Hourly rate (€)
- Client
- Reference / email
Composed of 3 micro apps
One job each, over the same data: every micro app reads and writes the shared data space “studio-pro-en” (with your consent, asked on first open). Everything stays on your device — and with a single invite the whole suite goes multi-user, end-to-end encrypted.
Shared micro apps are the bridge between solutions: the same data also powers Datebook.
How it works
This is a Reactive app: a plain text document that your browser turns into a working app — forms, live data, tables, statistics and even charts, with nothing to install or configure.
- Use it right away. Hit “Use this app”: it opens right in your browser, ready to go, with data saved only on your device.
- Your data stays yours. Everything is stored locally on your device, kept separate for each app: no account, no server, nothing to set up.
- Make it your own. The text below is the entire app: copy it, tweak fields, views and words, and your changes become interactive instantly.
- Share it as a file. An app is a simple file: save it, export it or share it with a link; and with encrypted collaboration several people edit the same data in real time.
The app’s source
# ⏳ Hourglass
Worked hours turn into a fee note by themselves: log, review, print.
:::::page{title="Log" icon="⏱️"}
## Today's hours
::::form{path="entries" id="fvo"}
::input{form="fvo" field="date" type="date" required="true" legend="Day"}
::select-from{from="clients" form="fvo" field="client" label="name" value="name"}
::input{form="fvo" field="activity" placeholder="Activity carried out" required="true"}
::input{form="fvo" field="hours" type="number" placeholder="Hours (e.g. 1.5)" required="true"}
::input{form="fvo" field="rate" type="number" placeholder="Hourly rate (€)"}
::add-form{form="fvo" path="entries" label="Log"}
::::
:::table{path="entries" headers="Day,Client,Activity,Hours,Rate,Fee" deletable="true" editform="fvo"}
{date} | {client} | {activity} | {hours} | € {rate} | € {hours*rate}
:::
:::::
:::::page{title="Clients" icon="👥"}
## Who you work for
::::form{path="clients" id="fcl"}
::input{form="fcl" field="name" placeholder="Client" required="true"}
::input{form="fcl" field="contact" placeholder="Reference / email"}
::add-form{form="fcl" path="clients" label="Add client"}
::::
:::list{path="clients" deletable="true"}
**{name}** — {contact}
:::
:::::
:::::page{title="Fee note" icon="🧾"}
## Summary to print
::::card{id="parcella" title="Statement of services"}
:::group-by{path="entries" field="client" as="table" headers="Day,Activity,Hours,Fee"}
{date} | {activity} | {hours} | € {hours*rate}
:::
**Total hours: :sum[oret]{path="entries" field="hours"}** ·
**Total fee: € :sum[comp]{path="entries" field="hours*rate"}**
::::
::print{target="parcella" label="Print / PDF fee note"}
:::::