feat: expense/invoice popups, task row hover fix, delivery submissions
- Expense detail popup: 80vw×80vh, inline editing, save gated on dirty state, Download Receipt in footer - Add expense form: same layout with FileAttachment drag-drop on right - New invoice popup: 80vw×80vh inline form replacing navigate-away page - Tasks table: suppress row hover background, only Name/Project table-links highlight - TaskDetail Submissions tab: reads from deliveries table, shows R## version, sent_by, message - Submit for Review: writes to deliveries + delivery_files (deliveries bucket) - deliveries.version_number column added and backfilled from revision history - Port 4173 for dev server Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# Fourge Portal — Claude Instructions
|
||||
|
||||
## Project
|
||||
React + Vite SPA. Supabase backend. Deployed on Vercel. Local dev on port 5173 (or next available). Remote: `gitea` remote at `gitea.krao.us`.
|
||||
|
||||
## Dev workflow
|
||||
- Dev server: `npm run dev` (Vite, HMR active — no restart needed for code changes)
|
||||
- Deploy: `vercel --prod` after every change, no need to ask
|
||||
- Push: `git push gitea main`
|
||||
|
||||
## Design system — follow layout.md as single source of truth
|
||||
|
||||
### Card shell (all new widgets)
|
||||
```
|
||||
background: var(--card-bg)
|
||||
border: 1px solid var(--border)
|
||||
border-radius: 8px
|
||||
padding: 18px 21px
|
||||
backdrop-filter: blur(12px)
|
||||
-webkit-backdrop-filter: blur(12px)
|
||||
```
|
||||
|
||||
### Tokens
|
||||
- Accent: `#F5A523`
|
||||
- Card bg: `var(--card-bg)` = `rgba(255,255,255,0.02)` dark / `rgba(0,0,0,0.02)` light
|
||||
- Secondary card: `var(--card-bg-2)`
|
||||
- Border: `var(--border)`
|
||||
- Text: `var(--text-primary)`, `var(--text-secondary)`, `var(--text-muted)`
|
||||
|
||||
### Widget title (card section headers)
|
||||
```
|
||||
font-size: 11px
|
||||
font-weight: 500
|
||||
text-transform: uppercase
|
||||
letter-spacing: 0.8px
|
||||
color: var(--text-secondary)
|
||||
margin-bottom: 14px
|
||||
```
|
||||
|
||||
### Tables
|
||||
- `table-layout: fixed`, `border-collapse: collapse`
|
||||
- Headers: `font-size: 10px`, `font-weight: 500`, uppercase, `letter-spacing: 0.6px`, `padding-bottom: 12px`, `border: none`, `background: transparent`
|
||||
- Use `SortTh` component for all sortable columns — every data column must be sortable
|
||||
- Body cells: primary `13px`, secondary `12px`, `padding: 5px 0`, `border: none`, `background: transparent`
|
||||
- Scrollable tables: container gets `className="scrollbar-thin-theme table-scroll-hidden"`, table gets `className="table-sticky-head"`
|
||||
- Do NOT add `background: transparent` inline on TD — it blocks the `tr:hover td` CSS rule
|
||||
|
||||
### Row hover
|
||||
- Standard table rows: `tr:hover td { background: rgba(255,255,255,0.02) }` via global CSS — do not add inline bg to TD
|
||||
- Clickable text inside rows: use `className="table-link"` — turns gold on hover, no full-row fill
|
||||
- Do NOT use whole-row click + cursor pointer as the primary interaction pattern for new tables
|
||||
|
||||
### Section control bar (tabs + actions)
|
||||
```
|
||||
display: flex, align-items: center, gap: 4, margin-bottom: 10, flex-shrink: 0
|
||||
```
|
||||
- Tabs on the left
|
||||
- Action buttons on the right via `margin-left: auto` — do NOT use hardcoded spacer divs for alignment
|
||||
- Reference: Tasks.jsx tabs + `+ Task` button pattern
|
||||
|
||||
### Buttons
|
||||
- All buttons use `.btn` class with CSS vars (`--btn-height: 22px`, `--btn-radius: 8px`, etc.)
|
||||
- Do not hardcode button geometry inline — use `btn btn-outline`, `btn btn-primary`, `btn btn-danger`
|
||||
- Height controlled by `--h-control` = `--btn-height`
|
||||
|
||||
### Modal forms
|
||||
- Surface: `background: var(--card-bg)`, use `popupSurfaceStyle` + `popupOverlayStyle` from `../../lib/popupStyles`
|
||||
- Field labels: `11px`, `500`, uppercase, `letter-spacing: 0.8px`, `color: var(--text-secondary)`
|
||||
- Inputs: `font-size: 13px`, `background: var(--card-bg-2)`, `border: 1px solid var(--border)`, `border-radius: 6px`, `padding: 6px 10px`
|
||||
- Form gap: `14px` between fields
|
||||
- Action buttons: right-aligned, `btn btn-outline`, gap `8px`
|
||||
- Header: single `11px` uppercase secondary label — no large heading
|
||||
|
||||
### Status badges
|
||||
- Use `<StatusBadge status={...} />` — do not hand-roll status tags
|
||||
- Badge height: `20px`, `border-radius: 4px`, `font-size: 10px`
|
||||
|
||||
### Spacing rhythm
|
||||
- Page/grid/section gaps: `24px`
|
||||
- Tabs-to-card gap: `margin-bottom: 10` on tabs bar
|
||||
|
||||
### Height-filling layouts
|
||||
For pages where cards should fill the window:
|
||||
```jsx
|
||||
<Layout>
|
||||
<div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
||||
{/* fixed sections: flexShrink: 0 */}
|
||||
{/* filling section: flex: 1, minHeight: 0 */}
|
||||
</div>
|
||||
</Layout>
|
||||
```
|
||||
Cards that scroll internally: `display: flex, flexDirection: column, minHeight: 0` + inner `overflowY: auto, flex: 1, minHeight: 0`
|
||||
|
||||
### File browser paths (per role)
|
||||
- `team`: `/Clients/{Co}/Projects/{Proj}/{Task}` (real path)
|
||||
- `client`: `/{Co}/Projects/{Proj}/{Task}` (virtual — no `/Clients/` prefix)
|
||||
- `external`: `/Projects/{Proj}/{Task}` (virtual)
|
||||
|
||||
## Empty states
|
||||
Use `.card-empty-center` class for all "No …" messages inside cards.
|
||||
|
||||
## Key files
|
||||
- `layout.md` — visual spec, always check before building new UI
|
||||
- `src/index.css` — global tokens and shared classes
|
||||
- `src/components/SortTh.jsx` — sortable table header
|
||||
- `src/components/StatusBadge.jsx` — status tags
|
||||
- `src/lib/popupStyles.js` — modal overlay/surface styles
|
||||
- `api/filebrowser.js` — file browser API (Vercel serverless)
|
||||
- `supabase/functions/fbq-proxy/` — Supabase edge function for FileBrowser Quantum
|
||||
Reference in New Issue
Block a user