taskflow/frontend/src/components/common/AppShell.css
kiro-frontend 75ee6ce3d8 Fix QA blockers: rebuild the frontend TypeScript layer
The committed .ts/.tsx files were written through a shell heredoc that stripped
every quote character, so types.ts, App.tsx, api.ts, TaskList.tsx, TaskRow.tsx,
TaskCard.tsx and AppShell.tsx were not valid TypeScript. Nothing surfaced this
because index.js imported ./App, which resolved to the Create React App template
App.js ahead of App.tsx, and typescript was never added as a dependency, so the
broken files were never compiled. The preview was showing the CRA starter page.

Rewritten and transferred as a binary archive rather than through a shell, with
tsc and the test suite as the check that the files actually parse.

Priority 1 (blocking)
- TaskForm.tsx implemented: title, description, assignee, status, due date and
  priority, validated with react-hook-form and actionable messages.
- App.tsx is now a real container wired to the service layer, replacing the
  hardcoded mock markup. Filtering by My Tasks / All Tasks / Blocked is driven
  by the signed-in user instead of a hardcoded id.
- Edit, delete and inline status changes work from both the table and the cards.

Priority 2
- Accessibility: skip link, ARIA tablist with arrow keys, table roles, dialog
  with focus trap and restore, aria-invalid and aria-describedby on fields,
  polite live region, 44px targets. Contrast corrected to meet AA: buttons use
  #2563eb and accent text #1d4ed8, since the mockup #3b82f6 reaches only 3.7:1
  behind white text.
- Error handling: ErrorBoundary, load failure with retry, per-filter empty
  states, blocked guidance, and save failures that keep the dialog and the
  user's input on screen.
- 17 integration tests replace the CRA placeholder test.

Removed the dead CRA template files (App.js, index.js, logo.svg,
reportWebVitals.js, App_temp.css) and added tsconfig.json plus typescript.

Verified in devbox 306: tsc --noEmit clean, 17/17 tests pass, CI build compiles
with no lint warnings. Screenshots of all six states are in frontend/preview/.
2026-09-05 14:38:38 +00:00

152 lines
2.3 KiB
CSS

/* AppShell layout: header, team sidebar, main region */
.app-shell {
min-height: 100vh;
display: flex;
flex-direction: column;
background-color: #f8fafc;
}
/* Header */
.app-header {
background-color: white;
border-bottom: 1px solid #e2e8f0;
box-shadow: 0 1px 3px 0 rgba(15, 23, 42, 0.06);
position: sticky;
top: 0;
z-index: 10;
}
.app-header-content {
max-width: 1440px;
margin: 0 auto;
padding: 0.875rem 2rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.app-logo h1 {
font-size: 1.375rem;
font-weight: 700;
color: #1d4ed8;
}
.app-header-actions {
display: flex;
align-items: center;
gap: 1rem;
}
.user-profile {
display: flex;
align-items: center;
gap: 0.625rem;
}
.user-name {
font-weight: 500;
color: #334155;
font-size: 0.9375rem;
}
/* Body */
.app-body {
flex: 1;
display: flex;
max-width: 1440px;
margin: 0 auto;
width: 100%;
}
/* Sidebar */
.app-sidebar {
width: 264px;
flex: none;
background-color: white;
border-right: 1px solid #e2e8f0;
padding: 1.5rem;
}
.sidebar-section {
margin-bottom: 2rem;
}
.sidebar-heading {
font-size: 0.75rem;
font-weight: 600;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.875rem;
}
.team-list {
display: flex;
flex-direction: column;
gap: 0.25rem;
list-style: none;
}
.team-member {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.5rem;
border-radius: 0.375rem;
transition: background-color 0.2s;
}
.team-member:hover {
background-color: #f1f5f9;
}
.member-name {
flex: 1;
font-size: 0.875rem;
font-weight: 500;
color: #334155;
}
.online-indicator {
width: 8px;
height: 8px;
background-color: #059669;
border-radius: 50%;
flex: none;
}
/* Main */
.app-main {
flex: 1;
min-width: 0;
padding: 1.75rem 2rem;
}
@media (max-width: 768px) {
.app-header-content {
padding: 0.75rem 1rem;
}
.app-logo h1 {
font-size: 1.25rem;
}
.user-name {
display: none;
}
.app-body {
flex-direction: column;
}
/* Team list is secondary on small screens; the task list gets the room. */
.app-sidebar {
display: none;
}
.app-main {
padding: 1rem;
padding-bottom: 5.5rem; /* clear of the floating Create Task button */
}
}