diff --git a/packages/bolt/app/components/ui/LoadingDots.tsx b/packages/bolt/app/components/ui/LoadingDots.tsx
new file mode 100644
index 0000000..47d28b7
--- /dev/null
+++ b/packages/bolt/app/components/ui/LoadingDots.tsx
@@ -0,0 +1,27 @@
+import { memo, useEffect, useState } from 'react';
+
+interface LoadingDotsProps {
+ text: string;
+}
+
+export const LoadingDots = memo(({ text }: LoadingDotsProps) => {
+ const [dotCount, setDotCount] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setDotCount((prevDotCount) => (prevDotCount + 1) % 4);
+ }, 500);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+
+ {text}
+ {'.'.repeat(dotCount)}
+ ...
+
+
+ );
+});
diff --git a/packages/bolt/app/routes/login.tsx b/packages/bolt/app/routes/login.tsx
index b609027..2e27a0c 100644
--- a/packages/bolt/app/routes/login.tsx
+++ b/packages/bolt/app/routes/login.tsx
@@ -8,6 +8,7 @@ import {
import { useFetcher, useLoaderData } from '@remix-run/react';
import { auth, type AuthAPI } from '@webcontainer/api';
import { useEffect, useState } from 'react';
+import { LoadingDots } from '~/components/ui/LoadingDots';
import { createUserSession, isAuthenticated, validateAccessToken } from '~/lib/.server/sessions';
import { CLIENT_ID, CLIENT_ORIGIN } from '~/lib/constants';
import { request as doRequest } from '~/lib/fetch';
@@ -96,12 +97,16 @@ export default function Login() {
return (
-
-
-
Login
+ {redirected ? (
+
+ ) : (
+
- {redirected ? 'Processing auth...' :
}
-
+ )}
);
}