redesign: Layout2 design-system + dashboard/tasks rework + perf

Design system (Layout2):
- Solid token-driven theme (no animated grid); single-source tokens for bg,
  cards (bg/border/radius), popups, fonts (Inter), and full semantic +
  data-viz color palette. Swept ~168 hardcoded colors to tokens.

Dashboard:
- Reflow: To Do + Calendar row (fixed right rail) over Activity / In-Progress /
  Team Performance; CSS height-match (To Do = Calendar); responsive stacking.
- 'Tasks Not Started' -> 'To Do' card with R#/Assigned columns; compact money fmt.

Tasks page:
- Combined tabs into Tasks + Completed with a Status column.
- Column-header sort + filter (Status, R#/new-vs-revision, Project, Task Type,
  Company) via portaled, scrollable FilterDropdown; removed toolbar filters and
  the projects side panel; headers stay visible when empty; renamed to 'Tasks'.

Perf:
- FK/filter index migration; removed redundant client/external scope waterfall
  (rely on RLS); parallel follow-up queries.

Mobile:
- Responsive grids; mobile topbar = hamburger only, blends with bg, proper offset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Krao Hasanee
2026-06-26 10:08:40 -04:00
parent c5f020cf44
commit c91e292066
27 changed files with 879 additions and 548 deletions
+21 -21
View File
@@ -879,7 +879,7 @@ export default function BrandBook() {
<LoadingButton className="btn btn-primary btn-sm" loading={generating} loadingText="Generating..." onClick={handleGenerate}>Generate PDF</LoadingButton>
</div>
{notification && (
<span style={{ fontSize: 13, color: notification.type === 'error' ? 'var(--danger, #dc2626)' : 'var(--success, #16a34a)' }}>
<span style={{ fontSize: 13, color: notification.type === 'error' ? 'var(--danger, var(--danger-strong))' : 'var(--success, var(--success-strong))' }}>
{notification.msg}
</span>
)}
@@ -1182,7 +1182,7 @@ export default function BrandBook() {
<LoadingButton className="btn btn-primary btn-sm" loading={generating} loadingText="Generating..." onClick={handleGenerate}>Generate PDF</LoadingButton>
</div>
{notification && (
<span style={{ fontSize: 13, color: notification.type === 'error' ? 'var(--danger, #dc2626)' : 'var(--success, #16a34a)' }}>
<span style={{ fontSize: 13, color: notification.type === 'error' ? 'var(--danger, var(--danger-strong))' : 'var(--success, var(--success-strong))' }}>
{notification.msg}
</span>
)}
@@ -1230,7 +1230,7 @@ function SignCard({ sign, index, onChange, onPhotoChange, onRemove, canRemove, t
{sign.photo && <span style={{ fontSize: 11, color: 'var(--accent)' }}>unsaved photo</span>}
{canRemove && (
<span role="button" onClick={onRemove}
style={{ fontSize: 13, color: 'var(--danger, #dc2626)', padding: '2px 6px', cursor: 'pointer' }}></span>
style={{ fontSize: 13, color: 'var(--danger, var(--danger-strong))', padding: '2px 6px', cursor: 'pointer' }}></span>
)}
</div>
</div>
@@ -1336,7 +1336,7 @@ function PhotoField({ label, preview, fileName, dragging, inputRef, onDragEnter,
style={{
border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border)'}`,
borderRadius: 4,
background: dragging ? 'rgba(245,165,35,0.05)' : 'var(--input-bg, var(--card-bg))',
background: dragging ? 'color-mix(in srgb, var(--accent) 5%, transparent)' : 'var(--input-bg, var(--card-bg))',
padding: 12,
cursor: 'pointer',
display: 'flex',
@@ -1407,7 +1407,7 @@ function SiteMapDropZone({ preview, onFile, onClear, inputRef }) {
style={{
border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border)'}`,
borderRadius: 4,
background: dragging ? 'rgba(245,165,35,0.05)' : 'var(--input-bg, var(--card-bg))',
background: dragging ? 'color-mix(in srgb, var(--accent) 5%, transparent)' : 'var(--input-bg, var(--card-bg))',
padding: '24px 16px', textAlign: 'center', cursor: 'pointer',
color: dragging ? 'var(--accent)' : 'var(--text-muted)', fontSize: 13, transition: 'all 0.15s',
}}
@@ -1438,7 +1438,7 @@ function SitePhotosDropZone({ photoItems, onFiles, onRemove, inputRef }) {
style={{
border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border)'}`,
borderRadius: 4,
background: dragging ? 'rgba(245,165,35,0.05)' : 'var(--input-bg, var(--card-bg))',
background: dragging ? 'color-mix(in srgb, var(--accent) 5%, transparent)' : 'var(--input-bg, var(--card-bg))',
padding: '20px 16px', textAlign: 'center', cursor: 'pointer',
color: dragging ? 'var(--accent)' : 'var(--text-muted)', fontSize: 13,
marginBottom: photoItems.length > 0 ? 12 : 0, transition: 'all 0.15s',
@@ -1458,14 +1458,14 @@ function SitePhotosDropZone({ photoItems, onFiles, onRemove, inputRef }) {
style={{ width: 80, height: 60, objectFit: 'cover', borderRadius: 4, border: '1px solid var(--border)', display: 'block' }}
/>
{item.file && (
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, background: 'rgba(245,165,35,0.8)', fontSize: 8, textAlign: 'center', borderRadius: '0 0 4px 4px', padding: '1px 2px', color: '#1a1a1a', fontWeight: 400 }}>NEW</div>
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, background: 'color-mix(in srgb, var(--accent) 80%, transparent)', fontSize: 8, textAlign: 'center', borderRadius: '0 0 4px 4px', padding: '1px 2px', color: '#1a1a1a', fontWeight: 400 }}>NEW</div>
)}
<button
type="button"
onClick={() => onRemove(i)}
style={{
position: 'absolute', top: -6, right: -6,
background: '#dc2626', border: 'none', borderRadius: '50%',
background: 'var(--danger-strong)', border: 'none', borderRadius: '50%',
width: 18, height: 18, fontSize: 10, color: '#fff',
cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', lineHeight: 1,
}}
@@ -1510,7 +1510,7 @@ function CombinedMockupPhotoField({
const tileStyle = {
border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border)'}`,
borderRadius: 4,
background: dragging ? 'rgba(245,165,35,0.05)' : 'var(--input-bg, var(--card-bg))',
background: dragging ? 'color-mix(in srgb, var(--accent) 5%, transparent)' : 'var(--input-bg, var(--card-bg))',
padding: 12,
cursor: 'pointer',
display: 'flex',
@@ -1649,7 +1649,7 @@ function RecommendationPhotoField({ preview, fileName, dragging, inputRef, onDra
style={{
border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border)'}`,
borderRadius: 4,
background: dragging ? 'rgba(245,165,35,0.05)' : 'var(--input-bg, var(--card-bg))',
background: dragging ? 'color-mix(in srgb, var(--accent) 5%, transparent)' : 'var(--input-bg, var(--card-bg))',
padding: 12,
cursor: 'pointer',
display: 'flex',
@@ -1732,7 +1732,7 @@ function SignDetailPhotoField({ preview, fileName, dragging, inputRef, onDragEnt
style={{
border: `2px dashed ${dragging ? 'var(--accent)' : 'var(--border)'}`,
borderRadius: 4,
background: dragging ? 'rgba(245,165,35,0.05)' : 'var(--input-bg, var(--card-bg))',
background: dragging ? 'color-mix(in srgb, var(--accent) 5%, transparent)' : 'var(--input-bg, var(--card-bg))',
padding: 12,
cursor: preview ? 'pointer' : 'default',
display: 'flex',
@@ -2420,7 +2420,7 @@ function DimensionEditorModal({ sourceImage, onApply, onCancel }) {
)}
</span>
</div>
<div style={{ overflow: 'auto', flex: 1, background: '#2a2a2a', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', position: 'relative' }}>
<div style={{ overflow: 'auto', flex: 1, background: 'var(--card-bg-2)', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', position: 'relative' }}>
{!loaded && <div style={{ padding: 48, color: '#888', fontSize: 13 }}>Loading image</div>}
<canvas
ref={canvasRef}
@@ -2833,7 +2833,7 @@ function PhotoEditorModal({
ctx.restore();
if (showGuides && item.id === selectedArtworkId) {
const rotateHandle = getRotateHandle(item);
ctx.strokeStyle = '#f5a523';
ctx.strokeStyle = 'var(--accent)';
ctx.lineWidth = 2;
ctx.setLineDash([6, 4]);
ctx.beginPath();
@@ -2851,7 +2851,7 @@ function PhotoEditorModal({
ctx.stroke();
getArtworkHandles(item).forEach(({ x, y }) => {
ctx.fillStyle = '#ffffff';
ctx.strokeStyle = '#f5a523';
ctx.strokeStyle = 'var(--accent)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.rect(x - HANDLE_SIZE / 2, y - HANDLE_SIZE / 2, HANDLE_SIZE, HANDLE_SIZE);
@@ -2859,13 +2859,13 @@ function PhotoEditorModal({
ctx.stroke();
});
ctx.fillStyle = '#1a1a1a';
ctx.strokeStyle = '#f5a523';
ctx.strokeStyle = 'var(--accent)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(rotateHandle.x, rotateHandle.y, HANDLE_SIZE / 1.5, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.fillStyle = '#f5a523';
ctx.fillStyle = 'var(--accent)';
ctx.font = '700 10px Helvetica, Arial, sans-serif';
ctx.fillText('↻', rotateHandle.x - 4, rotateHandle.y + 4);
}
@@ -2895,14 +2895,14 @@ function PhotoEditorModal({
}
if (showGuides && calibrationPoints.length > 0) {
ctx.fillStyle = '#22c55e';
ctx.fillStyle = 'var(--success)';
calibrationPoints.forEach((point) => {
ctx.beginPath();
ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
ctx.fill();
});
if (calibrationPoints.length === 2) {
ctx.strokeStyle = '#22c55e';
ctx.strokeStyle = 'var(--success)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(calibrationPoints[0].x, calibrationPoints[0].y);
@@ -3604,7 +3604,7 @@ function PhotoEditorModal({
}}
style={{
border: `1px solid ${item.id === activeDimensionId ? 'var(--accent)' : 'var(--border)'}`,
background: item.id === activeDimensionId ? 'rgba(245,165,35,0.12)' : 'var(--card-bg-2)',
background: item.id === activeDimensionId ? 'color-mix(in srgb, var(--accent) 12%, transparent)' : 'var(--card-bg-2)',
color: 'var(--text-primary)',
borderRadius: 4,
padding: '8px 10px',
@@ -3648,7 +3648,7 @@ function PhotoEditorModal({
}}
style={{
border: `1px solid ${item.id === selectedArtworkId ? 'var(--accent)' : 'var(--border)'}`,
background: item.id === selectedArtworkId ? 'rgba(245,165,35,0.12)' : 'var(--card-bg-2)',
background: item.id === selectedArtworkId ? 'color-mix(in srgb, var(--accent) 12%, transparent)' : 'var(--card-bg-2)',
color: 'var(--text-primary)',
borderRadius: 4,
padding: '8px 10px',
@@ -3675,7 +3675,7 @@ function PhotoEditorModal({
<div
onDragOver={e => e.preventDefault()}
onDrop={handleArtworkDrop}
style={{ overflow: 'auto', background: '#2a2a2a', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', position: 'relative', minHeight: 420 }}
style={{ overflow: 'auto', background: 'var(--card-bg-2)', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', position: 'relative', minHeight: 420 }}
>
{!loaded && (
<div style={{ padding: 48, color: '#888', fontSize: 13 }}>Loading image</div>