Files
zeekayandHanzo Dev 3bb90ee58e Mobile-first + Dework design tokens + Karma-as-points across all 9 views
Mobile-first (390px up, enhance to desktop):
- Sidebar → off-canvas drawer behind a hamburger (overlay + tap-close + safe-area);
  static 256px sidebar only at md+. Mobile top bar carries hamburger + workspace + Connect.
- Kanban → horizontal scroll-snap columns (~86vw, peek next) on mobile; 4-col grid at xl.
- Leaderboard / All-Contributors tables wrapped in overflow-x scroll regions (min-w),
  body never scrolls sideways. Tab row is horizontally scrollable.
- Task-detail + suggestion modals are full-bleed / bottom-sheet on mobile, centered cards at sm+.
- Overview stacks main + right rail on mobile; all view paddings responsive.
- index.css: overflow-x hidden, env(safe-area-inset-*), clamp() fluid type, thin scroll-x utility.

Design tokens: consolidated every surface hex to the Dework palette as CSS vars
(--bg #0e0e10 / --rail #141416 / --surface #17171b / --border #232328 / --hover #1e1e24),
set per-brand --brand accent at runtime. Deleted the now-unused theme.ts (dead code).

Leaderboards: Task Points = global Karma (formatAmount(karma)) with a transparent
tasks×100 proxy until Karma is canonical on-chain; dropped the separate Karma column.

Contract naming: ABI imports stay indirected via abi.ts (one-line swap for the
finished non-versioned Bounty/Escrow/Reputation/Karma set); scrubbed V1/V2 from
comments + README; README now documents the full platform.

Every view still renders from the fixture with no wallet/chain (screenshot-able).
Verified live at work.zoo.network (real Zoo data) + local at 390px and 1440px.

package: 0.2.0 -> 0.3.0

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-17 17:37:56 -07:00

88 lines
4.2 KiB
Markdown

# Work Board
White-label on-chain community work platform — a DAO's "Dework". It reads a live
Bounty / Escrow / Reputation / Karma work-market directly over JSON-RPC (no
subgraph) and renders the full Dework surface: **Overview** (org header + time-to-
payment / total-paid stats + Bounties category grid), **Board** (To Do / In
Progress / In Review / Done kanban), **Open Tasks**, **Leaderboards** (Top
Contributors / Reviewers; Task Points = global Karma), **Community Suggestions**,
**Combined Board**, per-Space tabs, a **task detail** with the real on-chain
activity log + apply flow, and a cross-org **Explore**. The differentiator is
**portable reputation**: per-DAO Reputation + global soul-bound Karma travel with
the worker's address, not the platform. Mobile-first (390px up); every view also
renders from a fixture with no wallet/chain, so it is always screenshot-able.
One repo, one Dockerfile. A build-time brand (`VITE_BRAND`, default `zoo`)
selects the white-label profile — chain, addresses, owner label, header/title,
and the RPC host baked into the CSP — from `src/brands.ts`:
| Brand | Chain | Site |
| ------ | -------- | --------------------------------------------- |
| `zoo` | 200200 | https://work.zoo.network |
| `pars` | 494949 | https://work.pars.network |
## Run
npm install
npm run dev # http://localhost:5173 (proxies /rpc -> 127.0.0.1:9631 port-forward)
npm run build # tsc --noEmit && vite build -> dist/
npm run preview # serve the production build
Point the dev proxy at any node instead of the local port-forward, and select a
brand:
RPC_TARGET=https://api.pars.network npm run dev
VITE_BRAND=pars VITE_RPC_URL=https://api.pars.network/v1/bc/C/rpc npm run build
If the RPC is unreachable, the board renders a faithful fixture of that brand's
live bounty #0 (behind the same render path) so the UI stays verifiable; the
source badge shows FIXTURE.
## Config
Brand-varying values live in one map: `src/brands.ts`; `src/config.ts` selects
the active brand from `VITE_BRAND`. To add a board, add a brand profile — it's a
data change, not a code change.
## Deploy
CI (`.github/workflows/docker.yml`) builds on every push to `main` on luxfi's
in-cluster ARC pool (`lux-build-amd64`) and pushes to `ghcr.io/luxfi/work-board`
— never built locally. A brand matrix stamps one immutable tag per brand from
the same Dockerfile:
- `zoo``:sha-<commit>` → zoo-k8s, namespace `zoo-mainnet` (manifests in `k8s/`)
- `pars``:pars-<commit>` → pars-k8s, namespace `pars` (manifests in `k8s/pars/`)
Each `deployment.yaml` + `service.yaml` runs 2 replicas serving `dist` on :3000,
Service :80 → :3000; pin the Deployment to the CI tag then `kubectl apply`. Each
`route.yaml` is the Traefik dynamic-config router (host → Service, TLS via the
ingress's built-in ACME resolver); hanzoai/ingress routes every public host
through a `@file` ConfigMap (zoo: `zoo-system/zoo-dynamic`; pars:
`hanzo/pars-dynamic`), not Ingress objects — merge the fragment in (see the
header in each `route.yaml`).
## Data source
**Zoo 200200**
| Contract | Address |
| ------------ | -------------------------------------------- |
| Bounty | `0x3EDb4a0104614b4aC12D5babCE984291aE8BE8E7` |
| Escrow | `0x095E68282aea751Cc70A2Be565270f1B6AB0229C` |
| Reputation | `0xed976852e8c2b1283e4F475845046B679224460D` |
| owner | `0x229599f227231d8C90fcF1a78589F5DC4b7A6962` (Zoo DAO Safe) |
**Pars 494949**
| Contract | Address |
| ------------ | -------------------------------------------- |
| Bounty | `0x316B41c886c7D4B4e38cBB08a243776Ed977cf1F` |
| Escrow | `0xD5890D32d603a04E35ec7dBAbDCD0CA400f07E92` |
| Reputation | `0x155d1363c23467929FB709FCFa0afC51F3497aB6` |
| owner | `0x4CEA4ac1C874a340B06e0422E77a477463C3a542` (Pars DAO Safe) |
`bountyCount()` + `bounties(i)` give the current struct; `BountyProposed` /
`WorkSubmitted` logs give `issueRef` / `deliverableRef`; `Reputation.completedOf` /
`earnedOf` give the worker's score. ABIs are copied into `src/abi.ts` (no cross-repo import).