Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 0 additions & 81 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions src/components/shared/ScanSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import GlassCard from "../GlassCard";
export default function ScanSkeleton() {
return (
<div className="p-6 space-y-6 animate-pulse">
<div className="flex flex-col md:flex-row gap-6">
<GlassCard className="flex-1 p-8">
<div className="h-4 w-32 skeleton-shimmer rounded mb-4"></div>
<div className="h-16 w-40 skeleton-shimmer rounded mb-4"></div>
<div className="h-2 w-full skeleton-shimmer rounded"></div>
</GlassCard>

<GlassCard className="md:w-72 p-6">
<div className="h-4 w-24 skeleton-shimmer rounded mb-4"></div>
<div className="h-8 w-full skeleton-shimmer rounded mb-3"></div>
<div className="h-8 w-full skeleton-shimmer rounded"></div>
</GlassCard>
</div>

<GlassCard className="p-6">
<div className="h-5 w-40 skeleton-shimmer rounded mb-4"></div>
<div className="space-y-3">
<div className="h-16 skeleton-shimmer rounded"></div>
<div className="h-16 skeleton-shimmer rounded"></div>
<div className="h-16 skeleton-shimmer rounded"></div>
</div>
</GlassCard>

<GlassCard className="p-4">
<div className="h-12 skeleton-shimmer rounded"></div>
</GlassCard>
</div>
Comment on lines +4 to +31

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Loading shell dimensions don’t match the final dashboard, causing avoidable layout shift.

Line 4 uses a different outer layout than the loaded dashboard (min-h, responsive horizontal padding, centered max-w-4xl wrapper), so the page reflows when loading completes. This misses the acceptance requirement to minimize content jumping.

Proposed fix
 export default function ScanSkeleton()  {
   return (
-    <div className="p-6 space-y-6 animate-pulse">
-      <div className="flex flex-col md:flex-row gap-6">
+    <div className="min-h-[calc(100vh-4rem)] px-6 md:px-16 lg:px-24 py-8 md:py-12">
+      <div className="max-w-4xl mx-auto space-y-6 animate-pulse">
+        <div className="flex flex-col md:flex-row gap-6">
           <GlassCard className="flex-1 p-8">
             <div className="h-4 w-32 skeleton-shimmer rounded mb-4"></div>
             <div className="h-16 w-40 skeleton-shimmer rounded mb-4"></div>
             <div className="h-2 w-full skeleton-shimmer rounded"></div>
           </GlassCard>
@@
-      <GlassCard className="p-4">
-        <div className="h-12 skeleton-shimmer rounded"></div>
-      </GlassCard>
+        <GlassCard className="p-4">
+          <div className="h-12 skeleton-shimmer rounded"></div>
+        </GlassCard>
+      </div>
     </div>
   );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="p-6 space-y-6 animate-pulse">
<div className="flex flex-col md:flex-row gap-6">
<GlassCard className="flex-1 p-8">
<div className="h-4 w-32 skeleton-shimmer rounded mb-4"></div>
<div className="h-16 w-40 skeleton-shimmer rounded mb-4"></div>
<div className="h-2 w-full skeleton-shimmer rounded"></div>
</GlassCard>
<GlassCard className="md:w-72 p-6">
<div className="h-4 w-24 skeleton-shimmer rounded mb-4"></div>
<div className="h-8 w-full skeleton-shimmer rounded mb-3"></div>
<div className="h-8 w-full skeleton-shimmer rounded"></div>
</GlassCard>
</div>
<GlassCard className="p-6">
<div className="h-5 w-40 skeleton-shimmer rounded mb-4"></div>
<div className="space-y-3">
<div className="h-16 skeleton-shimmer rounded"></div>
<div className="h-16 skeleton-shimmer rounded"></div>
<div className="h-16 skeleton-shimmer rounded"></div>
</div>
</GlassCard>
<GlassCard className="p-4">
<div className="h-12 skeleton-shimmer rounded"></div>
</GlassCard>
</div>
export default function ScanSkeleton() {
return (
<div className="min-h-[calc(100vh-4rem)] px-6 md:px-16 lg:px-24 py-8 md:py-12">
<div className="max-w-4xl mx-auto space-y-6 animate-pulse">
<div className="flex flex-col md:flex-row gap-6">
<GlassCard className="flex-1 p-8">
<div className="h-4 w-32 skeleton-shimmer rounded mb-4"></div>
<div className="h-16 w-40 skeleton-shimmer rounded mb-4"></div>
<div className="h-2 w-full skeleton-shimmer rounded"></div>
</GlassCard>
<GlassCard className="md:w-72 p-6">
<div className="h-4 w-24 skeleton-shimmer rounded mb-4"></div>
<div className="h-8 w-full skeleton-shimmer rounded mb-3"></div>
<div className="h-8 w-full skeleton-shimmer rounded"></div>
</GlassCard>
</div>
<GlassCard className="p-6">
<div className="h-5 w-40 skeleton-shimmer rounded mb-4"></div>
<div className="space-y-3">
<div className="h-16 skeleton-shimmer rounded"></div>
<div className="h-16 skeleton-shimmer rounded"></div>
<div className="h-16 skeleton-shimmer rounded"></div>
</div>
</GlassCard>
<GlassCard className="p-4">
<div className="h-12 skeleton-shimmer rounded"></div>
</GlassCard>
</div>
</div>
);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/shared/ScanSkeleton.tsx` around lines 4 - 31, The ScanSkeleton
root container currently uses "p-6 space-y-6 animate-pulse" which differs from
the final dashboard layout and causes layout shift; update the root element in
ScanSkeleton (the top-level div wrapping GlassCard instances) to match the
dashboard's outer wrapper classes (add the same min-height, responsive
horizontal padding, centered max-width wrapper — e.g. include classes like
min-h-... , px-..., mx-auto, max-w-4xl — while preserving internal spacing and
animate-pulse) so the skeleton reserves the same shell dimensions as the loaded
dashboard and prevents reflow; keep GlassCard usages and their internal classes
unchanged.

);
}
21 changes: 21 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -396,4 +396,25 @@ input::placeholder {

@media print {
nav, .print\:hidden { display: none !important; }
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}

100% {
background-position: 200% 0;
}
}

.skeleton-shimmer {
background: linear-gradient(
90deg,
var(--color-surface-mid) 25%,
var(--color-surface-highest) 50%,
var(--color-surface-mid) 75%
);

background-size: 200% 100%;
animation: shimmer 1.5s linear infinite;
Comment on lines +418 to +419

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix stylelint violation before animation declaration (Line 418).

There is an empty line before animation that violates declaration-empty-line-before and can fail linting.

Proposed fix
 .skeleton-shimmer {
   background: linear-gradient(
     90deg,
     var(--color-surface-mid) 25%,
     var(--color-surface-highest) 50%,
     var(--color-surface-mid) 75%
   );
-
   background-size: 200% 100%;
   animation: shimmer 1.5s linear infinite;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
background-size: 200% 100%;
animation: shimmer 1.5s linear infinite;
.skeleton-shimmer {
background: linear-gradient(
90deg,
var(--color-surface-mid) 25%,
var(--color-surface-highest) 50%,
var(--color-surface-mid) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s linear infinite;
}
🧰 Tools
🪛 Stylelint (17.12.0)

[error] 418-418: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.css` around lines 418 - 419, Remove the blank line before the
animation declaration to satisfy the declaration-empty-line-before lint rule:
ensure the CSS block with the properties background-size and animation has no
empty line between them (i.e., place animation: shimmer 1.5s linear infinite;
directly after background-size: 200% 100%;), then re-run stylelint to confirm
the violation is resolved.

Source: Linters/SAST tools

}
14 changes: 6 additions & 8 deletions src/pages/AnalysisDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import GlassCard from '../components/GlassCard';
import StatusTerminal from '../components/StatusTerminal';
import { api } from '../lib/api';
import type { ScanResult } from '../lib/types';
import ScanSkeleton from "../components/shared/ScanSkeleton";

const BIOMARKER_META = {
gill_saturation: { label: 'Gill Saturation', icon: Droplets },
Expand All @@ -21,6 +22,7 @@ function gradeColor(grade: string) {
}

export default function AnalysisDashboard() {

const [params] = useSearchParams();
const [scan, setScan] = useState<ScanResult | null>(null);
const [loading, setLoading] = useState(true);
Expand All @@ -43,20 +45,16 @@ export default function AnalysisDashboard() {
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load scan data.');
} finally {
setLoading(false);
setLoading(false);
}
}
load();
}, [params]);

// ── Loading state ────────────────────────────────────────────────────────
if (loading) {
return (
<div className="min-h-[calc(100vh-4rem)] flex items-center justify-center">
<StatusTerminal messages={['LOADING_ANALYSIS...', 'FETCHING_RESULT']} />
</div>
);
}
if (loading) {
return <ScanSkeleton />;
}

// ── Error state ──────────────────────────────────────────────────────────
if (error || !scan) {
Expand Down
Loading