diff --git a/apps/web/src/components/clerk/MobileClientsUserProfilePage.tsx b/apps/web/src/components/clerk/MobileClientsUserProfilePage.tsx
index 22449c336742fcf110d39c08f0b873d159a3b246..83fcde596ec5c87f9ab6f988b7ddd22c0cfb7323 100644
--- a/apps/web/src/components/clerk/MobileClientsUserProfilePage.tsx
+++ b/apps/web/src/components/clerk/MobileClientsUserProfilePage.tsx
@@ -69,7 +69,7 @@ function MobileClientsSkeleton() {
{MOBILE_CLIENT_SKELETON_ROWS.map((row) => (
-
+
diff --git a/apps/web/src/components/cloud/CloudEnvironmentConnectList.tsx b/apps/web/src/components/cloud/CloudEnvironmentConnectList.tsx
index 5d4e002cf8653d0c26cd729a74e567f3f091b35b..de054d0a5d29c82c0a6bd87b0e6b837f64d73656 100644
--- a/apps/web/src/components/cloud/CloudEnvironmentConnectList.tsx
+++ b/apps/web/src/components/cloud/CloudEnvironmentConnectList.tsx
@@ -57,10 +57,10 @@ function RemoteEnvironmentRowsSkeleton() {
);
diff --git a/apps/web/src/components/settings/SourceControlSettings.tsx b/apps/web/src/components/settings/SourceControlSettings.tsx
index d7d8be98cc66cb8e3a4f1776a092c31a65f336a6..82ccab88c6a54202c1ddfafc01d1b8ea3758be1c 100644
--- a/apps/web/src/components/settings/SourceControlSettings.tsx
+++ b/apps/web/src/components/settings/SourceControlSettings.tsx
@@ -440,20 +440,21 @@ function SourceControlSectionSkeleton({
-
-
+
+
diff --git a/apps/web/src/components/ui/skeleton.tsx b/apps/web/src/components/ui/skeleton.tsx
index 0d6e12eaa580fe249642972fd971140c60a9af43..f9fe5b5592f8c68c62881a3c027ade64a7185a7c 100644
--- a/apps/web/src/components/ui/skeleton.tsx
+++ b/apps/web/src/components/ui/skeleton.tsx
@@ -1,12 +1,27 @@
+import { cva, type VariantProps } from "class-variance-authority";
+
import { cn } from "~/lib/utils";
-function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
+// A skeleton's width and height are its content, so consumers size it through
+// className (the lint contract allows layout there). Its shape is not.
+const skeletonVariants = cva("bg-muted-foreground/15 motion-safe:animate-skeleton", {
+ variants: {
+ shape: {
+ block: "rounded-sm",
+ card: "rounded-lg",
+ pill: "rounded-full",
+ },
+ },
+ defaultVariants: { shape: "block" },
+});
+
+function Skeleton({
+ className,
+ shape,
+ ...props
+}: React.ComponentProps<"div"> & VariantProps
) {
return (
-
+
);
}
diff --git a/apps/web/src/components/usage/UsagePage.tsx b/apps/web/src/components/usage/UsagePage.tsx
index 0936217f970278c1bc3d11f86f2fa6e9200ca21d..02650a16edce3f342346eaf85d6e410c212348c3 100644
--- a/apps/web/src/components/usage/UsagePage.tsx
+++ b/apps/web/src/components/usage/UsagePage.tsx
@@ -868,8 +868,8 @@ function UsageSkeleton() {
-
-
+
+
@@ -882,8 +882,8 @@ function UsageSkeleton() {
@@ -905,9 +905,9 @@ function UsageSkeleton() {
>
);
diff --git a/scripts/lint-restyle-ceiling.ts b/scripts/lint-restyle-ceiling.ts
index bdf34708ecd7101f0e266073ae2355dc3a7c7ee2..db8a73b20326fb891a39006072178a8b19ec8a98 100644
--- a/scripts/lint-restyle-ceiling.ts
+++ b/scripts/lint-restyle-ceiling.ts
@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";
// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the
// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you
// migrate a file, and delete this script when the rule becomes an error.
-export const RESTYLE_CEILING = 1008;
+export const RESTYLE_CEILING = 981;
const RULE = "shadcn(no-restyle)";