Skip to content

Commit

Permalink
Signed-off-by: Saurabhsing21 <[email protected]>
Browse files Browse the repository at this point in the history
SkeletonLoaderSkeletonLoader#
  • Loading branch information
Saurabhsing21 committed Jan 15, 2025
1 parent 3b27568 commit f3dd0a3
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 15 deletions.
82 changes: 68 additions & 14 deletions landing.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,76 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="robots" content="index, follow, NOODP" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16">
<title>tscircuit - Code Electronics with React</title>
<meta name="description" content="tscircuit is an open-source electronics design tool that lets you create circuits using React components. Design schematics, generate PCB layouts, export and manufacture PCBs online!" />
<meta name="keywords" content="electronic design, PCB design, schematic capture, React components, circuit design, electronics CAD, open source EDA" />
<meta property="og:title" content="tscircuit - Design Electronics with React Components" />
<meta property="og:description" content="Create electronic circuits using React components. Design schematics, generate PCB layouts, and manufacture custom PCBs with this free open-source tool." />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="tscircuit - Design Electronics with React Components" />
<meta name="twitter:description" content="Create electronic circuits using React components. Free open-source electronics design tool." />
<link rel="canonical" href="https://tscircuit.com" />
<title>AI Page - Loading</title>
<style>
/* Skeleton styling */
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f2f5;
}

#skeleton {
text-align: center;
}

.loading-circle {
width: 50px;
height: 50px;
border: 5px solid #ccc;
border-top: 5px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}

@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

.loading-text {
font-size: 18px;
color: #555;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/pages/landing.tsx"></script>
<!-- Skeleton Loader -->
<div id="skeleton">
<div class="loading-circle"></div>
<div class="loading-text">Loading AI Page...</div>
</div>

<!-- Placeholder for actual content -->
<div id="content" style="display: none;">
<!-- This is where the /ai navigation page content will go -->
<h1>Welcome to the AI Page</h1>
<p>Sign in to use the AI chat or <a href="/editor">use the regular editor</a>.</p>
<button>Sign In</button>
<button>Sign Up</button>
</div>

<script>
// Simulate content loading
document.addEventListener("DOMContentLoaded", function () {
setTimeout(function () {
// Remove the skeleton loader
document.getElementById("skeleton").style.display = "none";
// Show the actual content
document.getElementById("content").style.display = "block";
}, 2000); // Simulate a 2-second load time
});
</script>
</body>
</html>
7 changes: 6 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { Route, Switch } from "wouter"
import "./components/CmdKMenu"
import { ContextProviders } from "./ContextProviders"
import React from "react"
import { Skeleton } from "./components/ui/skeleton"
import SkeletonLoadingPage from "./components/SkeletonLoader"
import UniversalSkeleton from "./components/SkeletonLoader"
import FullSkeletonLoader from "./components/SkeletonLoader"
import FullPageSkeletonLoader from "./components/SkeletonLoader"

const lazyImport = (importFn: () => Promise<any>) =>
lazy<ComponentType<any>>(async () => {
Expand Down Expand Up @@ -85,7 +90,7 @@ function App() {
return (
<ContextProviders>
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<Suspense fallback={<FullPageSkeletonLoader/>}>
<Switch>
<Route path="/" component={LandingPage} />
<Route path="/editor" component={EditorPage} />
Expand Down
175 changes: 175 additions & 0 deletions src/components/SkeletonLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import React from "react";
import styled, { keyframes } from "styled-components";

const FullPageSkeletonLoader: React.FC = () => {
return (
<PageWrapper>
{/* Navigation Skeleton */}
<NavSkeleton>
<LogoPlaceholder />
<NavItems>
{[...Array(4)].map((_, index) => (
<NavItem key={index} />
))}
</NavItems>
<ActionButtons>
<ActionPlaceholder width="80px" />
<ActionPlaceholder width="120px" />
</ActionButtons>
</NavSkeleton>

{/* Mid Content Skeleton */}
<ContentSkeleton>
<MainContent>
{/* Initial lines with different lengths */}
{[...Array(3)].map((_, index) => (
<HorizontalLine
key={`line-top-${index}`}
style={{ width: `${Math.floor(Math.random() * (90 - 70 + 1) + 70)}%` }}
/>
))}

{/* Two horizontal boxes */}
<BoxContainer>
<Box />
<Box />
</BoxContainer>

{/* Additional lines with varying lengths */}
{[...Array(5)].map((_, index) => (
<HorizontalLine
key={`line-bottom-${index}`}
style={{ width: `${Math.floor(Math.random() * (80 - 50 + 1) + 50)}%` }}
/>
))}
</MainContent>
<Sidebar>
{[...Array(5)].map((_, index) => (
<SidebarBlock key={index} />
))}
</Sidebar>
</ContentSkeleton>
</PageWrapper>
);
};

// Shimmer animation for skeleton
const shimmer = keyframes`
0% {
background-position: -150%;
}
100% {
background-position: 150%;
}
`;

// Styled Skeleton Components
const SkeletonBase = styled.div`
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: ${shimmer} 1.5s infinite ease-in-out;
border-radius: 8px;
`;

const PageWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 16px;
height: 100vh; /* Full screen height */
padding: 0;
margin: 0;
`;

const NavSkeleton = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 20px;
background: #ffffff;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
`;

const LogoPlaceholder = styled(SkeletonBase)`
width: 100px;
height: 40px;
border-radius: 4px;
`;

const NavItems = styled.div`
display: flex;
gap: 16px;
`;

const NavItem = styled(SkeletonBase)`
width: 80px;
height: 20px;
border-radius: 4px;
`;

const ActionButtons = styled.div`
display: flex;
gap: 12px;
`;

const ActionPlaceholder = styled(SkeletonBase)<{ width: string }>`
width: ${(props) => props.width};
height: 40px;
border-radius: 8px;
`;

const ContentSkeleton = styled.div`
flex: 1; /* Fills remaining space dynamically */
display: flex;
flex-direction: row;
gap: 24px; /* Space between content and sidebar */
padding: 20px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
overflow-y: auto; /* Allows scrolling if content overflows */
`;

const MainContent = styled.div`
flex: 3; /* Takes up most of the width */
display: flex;
flex-direction: column;
gap: 24px; /* Space between lines */
`;

const BoxContainer = styled.div`
display: flex;
gap: 16px; /* Space between boxes */
`;

const Box = styled(SkeletonBase)`
flex: 1; /* Equal width for both boxes */
height: 120px;
border-radius: 8px;
`;

const Sidebar = styled.div`
flex: 1; /* Smaller width for the sidebar */
display: flex;
flex-direction: column;
gap: 16px; /* Space between blocks */
`;

const HorizontalLine = styled(SkeletonBase)`
width: 100%;
height: 16px;
border-radius: 8px;
`;

const SidebarBlock = styled(SkeletonBase)`
width: 100%;
height: 80px;
border-radius: 8px;
`;

export default FullPageSkeletonLoader;

0 comments on commit f3dd0a3

Please sign in to comment.