From 014bb53fa152c9d438bba69f48f03172b345be8c Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Tue, 30 Dec 2025 14:33:15 -0800 Subject: [PATCH] homepage: add animations --- .../Home/components/AppContainer.tsx | 17 +++- .../components/Home/components/AppDrawer.tsx | 7 +- .../components/Home/components/AppIcon.tsx | 22 +++-- .../components/Home/components/HomeScreen.tsx | 1 + .../src/components/Home/components/Modal.tsx | 4 +- .../src/components/Home/styles/animations.css | 88 +++++++++++++++++++ hyperdrive/packages/homepage/ui/src/index.css | 71 +++++++++++++++ 7 files changed, 198 insertions(+), 12 deletions(-) diff --git a/hyperdrive/packages/homepage/ui/src/components/Home/components/AppContainer.tsx b/hyperdrive/packages/homepage/ui/src/components/Home/components/AppContainer.tsx index b6ab69a15..95967d5af 100644 --- a/hyperdrive/packages/homepage/ui/src/components/Home/components/AppContainer.tsx +++ b/hyperdrive/packages/homepage/ui/src/components/Home/components/AppContainer.tsx @@ -10,6 +10,14 @@ export const AppContainer: React.FC = ({ app, isVisible }) => const iframeRef = useRef(null); const [hasError, setHasError] = useState(false); const [isLoading, setIsLoading] = useState(true); + const [hasAnimatedIn, setHasAnimatedIn] = useState(false); + + // Track when the app first becomes visible to trigger entrance animation + useEffect(() => { + if (isVisible && !hasAnimatedIn) { + setHasAnimatedIn(true); + } + }, [isVisible, hasAnimatedIn]); // Ensure we have a valid path const appUrl = useMemo(() => { @@ -29,8 +37,13 @@ export const AppContainer: React.FC = ({ app, isVisible }) => return (
{hasError ? (
diff --git a/hyperdrive/packages/homepage/ui/src/components/Home/components/AppDrawer.tsx b/hyperdrive/packages/homepage/ui/src/components/Home/components/AppDrawer.tsx index 6099ae1af..c79d934f3 100644 --- a/hyperdrive/packages/homepage/ui/src/components/Home/components/AppDrawer.tsx +++ b/hyperdrive/packages/homepage/ui/src/components/Home/components/AppDrawer.tsx @@ -33,7 +33,7 @@ export const AppDrawer: React.FC = () => { return (
@@ -59,10 +59,11 @@ export const AppDrawer: React.FC = () => { 'grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6': filteredApps.length > 0, 'grid-cols-2': filteredApps.length === 0, })}> - {filteredApps.map(app => ( + {filteredApps.map((app, index) => (
{ diff --git a/hyperdrive/packages/homepage/ui/src/components/Home/components/AppIcon.tsx b/hyperdrive/packages/homepage/ui/src/components/Home/components/AppIcon.tsx index 40263e495..232553672 100644 --- a/hyperdrive/packages/homepage/ui/src/components/Home/components/AppIcon.tsx +++ b/hyperdrive/packages/homepage/ui/src/components/Home/components/AppIcon.tsx @@ -18,6 +18,7 @@ export const AppIcon: React.FC = ({ }) => { const { openApp } = useNavigationStore(); const [isPressed, setIsPressed] = useState(false); + const [isHovered, setIsHovered] = useState(false); const handlePress = () => { if (!isEditMode && app.path && app.path !== null) { @@ -25,19 +26,30 @@ export const AppIcon: React.FC = ({ } }; + // Calculate scale based on state priority: pressed > hovered > default + const getScale = () => { + if (isPressed) return 'scale(0.94)'; + if (isHovered && !isEditMode && isFloating) return 'scale(1.08)'; + return 'scale(1)'; + }; + return (
setIsPressed(true)} onMouseUp={() => setIsPressed(false)} - onMouseLeave={() => setIsPressed(false)} + onMouseEnter={() => setIsHovered(true)} + onMouseLeave={() => { setIsPressed(false); setIsHovered(false); }} + onTouchStart={() => setIsPressed(true)} + onTouchEnd={() => setIsPressed(false)} onClick={handlePress} data-app-id={app.id} data-app-path={app.path} diff --git a/hyperdrive/packages/homepage/ui/src/components/Home/components/HomeScreen.tsx b/hyperdrive/packages/homepage/ui/src/components/Home/components/HomeScreen.tsx index 303359612..90a55a9a6 100644 --- a/hyperdrive/packages/homepage/ui/src/components/Home/components/HomeScreen.tsx +++ b/hyperdrive/packages/homepage/ui/src/components/Home/components/HomeScreen.tsx @@ -430,6 +430,7 @@ export const HomeScreen: React.FC = () => { > {app ? (
{ e.dataTransfer.setData('appId', app.id); diff --git a/hyperdrive/packages/homepage/ui/src/components/Home/components/Modal.tsx b/hyperdrive/packages/homepage/ui/src/components/Home/components/Modal.tsx index 6f51bd43b..75eec412a 100644 --- a/hyperdrive/packages/homepage/ui/src/components/Home/components/Modal.tsx +++ b/hyperdrive/packages/homepage/ui/src/components/Home/components/Modal.tsx @@ -18,8 +18,8 @@ export const Modal: React.FC = ({ title }) => { return ( -
-
+
+
{title &&

{title}

}