Files
fourge-portal/CLAUDE.md
T
Krao Hasanee 96e90561b9 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>
2026-06-02 21:41:02 -04:00

110 lines
4.5 KiB
Markdown

# 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