feat: Add SilverSHELL SDK documentation page with downloadable templates

Added comprehensive SDK page at /sdk with:
- Downloadable SilverSHELL starter template (6.3 KB)
- Downloadable SilverSHELL module template (14 KB)
- Quick start guide with step-by-step instructions
- Creating applications guide (configuration, UI, manual install)
- Creating modules guide with template options
- Publishing modules guide (automated CI/CD + manual)
- Available modules list from library.silverlabs.uk
- Resources and support links

Initial commit includes:
- Complete static website with Docker deployment
- SilverLabs branding and styling
- Nginx configuration for production serving

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-19 21:36:57 +01:00
commit cf01a75179
12 changed files with 1022 additions and 0 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
docker-compose.yml
.git
.gitignore
*.md
README.md

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM nginx:alpine
# Copy website files to nginx html directory
COPY index.html /usr/share/nginx/html/
COPY styles.css /usr/share/nginx/html/
COPY script.js /usr/share/nginx/html/
COPY logo.png /usr/share/nginx/html/
# Copy custom nginx configuration
COPY nginx-site.conf /etc/nginx/conf.d/default.conf
# Expose port 80
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

18
docker-compose.yml Normal file
View File

@@ -0,0 +1,18 @@
version: '3.8'
services:
silverlabs-web:
build: .
container_name: silverlabs-web
restart: unless-stopped
ports:
- "8210:80"
networks:
- web
labels:
- "com.silverlabs.service=website"
- "com.silverlabs.description=SilverLabs Landing Page"
networks:
web:
external: false

73
index.html Normal file
View File

@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SilverLabs - Innovation Gateway</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Loading Screen -->
<div id="loading-screen" class="loading-screen">
<div class="loading-content">
<img src="logo.png" alt="SilverLabs Logo" class="loading-logo">
<div class="loading-spinner"></div>
</div>
</div>
<!-- Main Content -->
<div id="main-content" class="main-content">
<header class="header">
<img src="logo.png" alt="SilverLabs Logo" class="logo">
</header>
<main class="main">
<h1 class="title">Welcome to SilverLabs</h1>
<p class="subtitle">Your Innovation Gateway</p>
<div class="gateway-grid">
<a href="https://helpdesk.silverlabs.uk" class="gateway-card">
<div class="card-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</svg>
</div>
<h2 class="card-title">Help Desk</h2>
<p class="card-description">Support & Assistance</p>
</a>
<a href="https://appstore.silverlabs.uk" class="gateway-card">
<div class="card-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="7" height="7"></rect>
<rect x="14" y="3" width="7" height="7"></rect>
<rect x="14" y="14" width="7" height="7"></rect>
<rect x="3" y="14" width="7" height="7"></rect>
</svg>
</div>
<h2 class="card-title">App Store</h2>
<p class="card-description">Applications & Tools</p>
</a>
<a href="https://cloud.silverlabs.uk" class="gateway-card">
<div class="card-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path>
</svg>
</div>
<h2 class="card-title">Cloud</h2>
<p class="card-description">Storage & Collaboration</p>
</a>
</div>
</main>
<footer class="footer">
<p>&copy; 2025 SilverLabs. All rights reserved.</p>
</footer>
</div>
<script src="script.js"></script>
</body>
</html>

BIN
logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

28
nginx-site.conf Normal file
View File

@@ -0,0 +1,28 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Enable gzip compression
gzip on;
gzip_types text/css application/javascript image/jpeg image/png;
gzip_min_length 1000;
# Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Main location
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}

139
script.js Normal file
View File

@@ -0,0 +1,139 @@
// Loading screen functionality
document.addEventListener('DOMContentLoaded', function() {
const loadingScreen = document.getElementById('loading-screen');
const mainContent = document.getElementById('main-content');
// Minimum loading time (in milliseconds) to show the loading screen
const minLoadingTime = 2000;
const startTime = Date.now();
// Function to hide loading screen and show main content
function hideLoadingScreen() {
const elapsedTime = Date.now() - startTime;
const remainingTime = Math.max(0, minLoadingTime - elapsedTime);
setTimeout(() => {
loadingScreen.classList.add('fade-out');
mainContent.classList.add('visible');
// Remove loading screen from DOM after transition
setTimeout(() => {
loadingScreen.style.display = 'none';
}, 500);
}, remainingTime);
}
// Hide loading screen when page is fully loaded
if (document.readyState === 'complete') {
hideLoadingScreen();
} else {
window.addEventListener('load', hideLoadingScreen);
}
// Add floating particles animation to background
createFloatingParticles();
});
// Create floating particles for background effect
function createFloatingParticles() {
const mainContent = document.getElementById('main-content');
const particleCount = 20;
for (let i = 0; i < particleCount; i++) {
createParticle(mainContent);
}
}
function createParticle(container) {
const particle = document.createElement('div');
particle.className = 'particle';
// Random size between 2px and 6px
const size = Math.random() * 4 + 2;
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
// Random position
particle.style.left = `${Math.random() * 100}%`;
particle.style.top = `${Math.random() * 100}%`;
// Random animation duration between 10s and 30s
const duration = Math.random() * 20 + 10;
particle.style.animationDuration = `${duration}s`;
// Random delay
const delay = Math.random() * 5;
particle.style.animationDelay = `${delay}s`;
// Random opacity
const opacity = Math.random() * 0.3 + 0.1;
particle.style.opacity = opacity;
// Apply styles
particle.style.position = 'absolute';
particle.style.borderRadius = '50%';
particle.style.background = 'rgba(255, 255, 255, 0.5)';
particle.style.pointerEvents = 'none';
particle.style.zIndex = '0';
particle.style.animation = 'float ' + particle.style.animationDuration + ' ease-in-out infinite';
container.appendChild(particle);
}
// Add CSS animation for particles
const style = document.createElement('style');
style.textContent = `
@keyframes float {
0%, 100% {
transform: translate(0, 0) rotate(0deg);
}
25% {
transform: translate(10px, -20px) rotate(90deg);
}
50% {
transform: translate(-15px, -10px) rotate(180deg);
}
75% {
transform: translate(-10px, 20px) rotate(270deg);
}
}
.particle {
filter: blur(1px);
}
`;
document.head.appendChild(style);
// Add smooth scroll behavior for potential internal links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth'
});
}
});
});
// Add interactive hover effect to cards
document.querySelectorAll('.gateway-card').forEach(card => {
card.addEventListener('mousemove', function(e) {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const rotateX = (y - centerY) / 10;
const rotateY = (centerX - x) / 10;
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateY(-10px)`;
});
card.addEventListener('mouseleave', function() {
card.style.transform = '';
});
});

Binary file not shown.

Binary file not shown.

429
sdk/index.html Normal file
View File

@@ -0,0 +1,429 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SilverSHELL SDK - SilverLabs</title>
<link rel="stylesheet" href="../styles.css">
<style>
.sdk-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.sdk-header {
text-align: center;
margin-bottom: 3rem;
}
.sdk-header h1 {
font-size: 3rem;
margin-bottom: 1rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sdk-section {
background: rgba(255, 255, 255, 0.05);
border-radius: 1rem;
padding: 2rem;
margin-bottom: 2rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.sdk-section h2 {
font-size: 2rem;
margin-bottom: 1rem;
color: #667eea;
}
.sdk-section h3 {
font-size: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
color: #a78bfa;
}
.code-block {
background: rgba(0, 0, 0, 0.3);
border-radius: 0.5rem;
padding: 1rem;
margin: 1rem 0;
overflow-x: auto;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.code-block code {
color: #a5f3fc;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
white-space: pre;
}
.download-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.download-card {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
border-radius: 1rem;
padding: 1.5rem;
border: 1px solid rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
text-decoration: none;
display: block;
}
.download-card:hover {
transform: translateY(-4px);
border-color: rgba(102, 126, 234, 0.6);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.2);
}
.download-card h3 {
margin: 0 0 0.5rem 0;
color: #fff;
}
.download-card p {
color: rgba(255, 255, 255, 0.7);
margin: 0.5rem 0;
}
.download-btn {
display: inline-block;
margin-top: 1rem;
padding: 0.75rem 1.5rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 0.5rem;
color: white;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
}
.download-btn:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.steps-list {
counter-reset: step-counter;
list-style: none;
padding-left: 0;
}
.steps-list li {
counter-increment: step-counter;
position: relative;
padding-left: 3rem;
margin-bottom: 1.5rem;
}
.steps-list li::before {
content: counter(step-counter);
position: absolute;
left: 0;
top: 0;
width: 2rem;
height: 2rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
}
.info-box {
background: rgba(102, 126, 234, 0.1);
border-left: 4px solid #667eea;
padding: 1rem;
margin: 1rem 0;
border-radius: 0.5rem;
}
.back-link {
display: inline-block;
margin-top: 2rem;
color: #667eea;
text-decoration: none;
font-size: 1.1rem;
}
.back-link:hover {
color: #764ba2;
}
ul {
color: rgba(255, 255, 255, 0.8);
line-height: 1.8;
}
p {
color: rgba(255, 255, 255, 0.8);
line-height: 1.8;
}
</style>
</head>
<body>
<div id="main-content" class="main-content">
<header class="header">
<img src="../logo.png" alt="SilverLabs Logo" class="logo">
</header>
<div class="sdk-container">
<div class="sdk-header">
<h1>SilverSHELL SDK</h1>
<p style="font-size: 1.2rem; color: rgba(255, 255, 255, 0.7);">Build modular Blazor WebAssembly applications with ease</p>
</div>
<!-- Quick Start Section -->
<div class="sdk-section">
<h2>🚀 Quick Start</h2>
<p>Get started with SilverSHELL in just a few minutes. Follow these simple steps:</p>
<ol class="steps-list">
<li>
<strong>Download the templates</strong> (see downloads below)
</li>
<li>
<strong>Extract the templates</strong> to a directory of your choice
</li>
<li>
<strong>Install the templates</strong>
<div class="code-block"><code>dotnet new install ./path/to/SilverSHELL.Starter.Template
dotnet new install ./path/to/SilverSHELL.AppModule.Template</code></div>
</li>
<li>
<strong>Create your first project</strong>
<div class="code-block"><code>dotnet new silvershell-starter -n MyApp --pwa true --module-repository true
cd MyApp
dotnet run</code></div>
</li>
<li>
<strong>Access your application</strong> at <code>https://localhost:5001</code>
</li>
</ol>
</div>
<!-- Downloads Section -->
<div class="sdk-section">
<h2>📦 Downloads</h2>
<p>Download the SilverSHELL project templates to get started:</p>
<div class="download-grid">
<div class="download-card">
<h3>Starter Template</h3>
<p>Create a new SilverSHELL application with minimal configuration</p>
<p><strong>Size:</strong> 6.3 KB</p>
<p><strong>Includes:</strong> Blazor WebAssembly setup, module loading, PWA support</p>
<a href="downloads/silvershell-starter-template.tar.gz" class="download-btn" download>
Download Starter Template
</a>
</div>
<div class="download-card">
<h3>Module Template</h3>
<p>Create reusable SilverSHELL modules with best practices</p>
<p><strong>Size:</strong> 14 KB</p>
<p><strong>Includes:</strong> Module structure, configuration, CI/CD templates</p>
<a href="downloads/silvershell-module-template.tar.gz" class="download-btn" download>
Download Module Template
</a>
</div>
</div>
</div>
<!-- Creating Applications Section -->
<div class="sdk-section">
<h2>🏗️ Creating Applications</h2>
<h3>Using the Starter Template</h3>
<div class="code-block"><code># Create a new application
dotnet new silvershell-starter -n MyAwesomeApp
# With PWA support
dotnet new silvershell-starter -n MyAwesomeApp --pwa true
# With Module Repository integration
dotnet new silvershell-starter -n MyAwesomeApp --module-repository true</code></div>
<h3>Adding Modules</h3>
<p>SilverSHELL supports multiple ways to add modules to your application:</p>
<h3>Option 1: Configuration File</h3>
<p>Edit <code>wwwroot/appsettings.json</code>:</p>
<div class="code-block"><code>{
"AMS": {
"Deployment": {
"PreloadModules": [
"SilverLabs.SilverSHELL.Auth.Login",
"SilverSHELL.Modules.ModuleBrowser"
]
}
}
}</code></div>
<h3>Option 2: Module Browser UI</h3>
<ol>
<li>Navigate to <code>/modules/browse</code> in your application</li>
<li>Search for modules from <strong>library.silverlabs.uk</strong></li>
<li>Click "Install" on any module</li>
<li>Modules are downloaded and installed automatically</li>
</ol>
<h3>Option 3: Manual Installation</h3>
<div class="code-block"><code># Copy module DLLs to the modules directory
cp SomeModule.dll wwwroot/modules/
dotnet run
# Module is automatically discovered and loaded!</code></div>
</div>
<!-- Creating Modules Section -->
<div class="sdk-section">
<h2>🔧 Creating Modules</h2>
<h3>Using the Module Template</h3>
<div class="code-block"><code># Create a basic module
dotnet new silvershell-module -n MyModule
# Create a module with widgets
dotnet new silvershell-module -n MyModule --includeWidgets true
# Create a module with search provider
dotnet new silvershell-module -n MyModule --includeSearchProvider true
# Create a module with everything
dotnet new silvershell-module -n MyModule \
--includeWidgets true \
--includeSearchProvider true \
--includeTests true</code></div>
<h3>Module Structure</h3>
<p>The template creates an organized structure:</p>
<div class="code-block"><code>MyModule/
├── Configuration/
│ ├── ModuleMetadata.cs # Module identity and version
│ ├── EndpointConfiguration.cs # Navigation routes
│ └── WidgetConfiguration.cs # Dashboard widgets
├── Pages/
│ └── Index.razor # Razor pages
├── Components/
│ └── ... # Razor components
├── .gitlab-ci.yml # GitLab CI/CD
├── .github/workflows/
│ └── publish.yml # GitHub Actions
└── MyModuleMain.cs # Module entry point</code></div>
</div>
<!-- Publishing Modules Section -->
<div class="sdk-section">
<h2>🚀 Publishing Modules</h2>
<div class="info-box">
<strong>CI/CD Included!</strong> The module template includes ready-to-use CI/CD pipelines for both GitLab and GitHub.
</div>
<h3>Automated Publishing (Recommended)</h3>
<p>The templates include CI/CD pipelines for automatic publishing:</p>
<ol class="steps-list">
<li>
<strong>Configure CI/CD variables</strong>
<div class="code-block"><code># In GitLab: Settings > CI/CD > Variables
# In GitHub: Settings > Secrets > Actions
# Add variable:
MODULE_REPO_TOKEN: [your token from library.silverlabs.uk]</code></div>
</li>
<li>
<strong>Commit and push your code</strong>
<div class="code-block"><code>git add .
git commit -m "feat: Initial module implementation"
git push</code></div>
</li>
<li>
<strong>Create a release tag</strong>
<div class="code-block"><code>git tag v1.0.0
git push --tags</code></div>
</li>
<li>
<strong>Trigger publish</strong> from your CI/CD pipeline UI
</li>
</ol>
<h3>Manual Publishing</h3>
<div class="code-block"><code># Build and package
dotnet pack --configuration Release -o dist/
# Upload to repository
curl -X POST "https://library.silverlabs.uk/api/modules/publish" \
-F "id=MyModule" \
-F "name=My Awesome Module" \
-F "version=1.0.0" \
-F "description=A great module" \
-F "author=Your Name" \
-F "package=@dist/MyModule.1.0.0.nupkg"</code></div>
</div>
<!-- Available Modules Section -->
<div class="sdk-section">
<h2>📚 Available Modules</h2>
<p>Browse and install modules from the SilverSHELL module repository:</p>
<div class="info-box">
<strong>Module Repository:</strong> <a href="https://library.silverlabs.uk" target="_blank" style="color: #a78bfa;">library.silverlabs.uk</a>
</div>
<h3>Featured Modules:</h3>
<ul>
<li><strong>Auth.Login</strong> - User authentication and login UI</li>
<li><strong>Auth.Registration</strong> - User registration system</li>
<li><strong>Auth.UserManagement</strong> - User administration</li>
<li><strong>Auth.MyAccount</strong> - User profile management</li>
<li><strong>ModuleBrowser</strong> - Browse and install modules from the UI</li>
</ul>
<h3>Explore All Modules</h3>
<div class="code-block"><code># List all available modules via API
curl https://library.silverlabs.uk/api/modules
# Search for specific modules
curl https://library.silverlabs.uk/api/modules/search?q=auth</code></div>
</div>
<!-- Resources Section -->
<div class="sdk-section">
<h2>📖 Resources</h2>
<ul>
<li><strong>Module Repository API:</strong> <a href="https://library.silverlabs.uk/api/modules" target="_blank" style="color: #a78bfa;">https://library.silverlabs.uk/api/modules</a></li>
<li><strong>Demo Application:</strong> <a href="https://demo.silverlabs.uk" target="_blank" style="color: #a78bfa;">https://demo.silverlabs.uk</a></li>
<li><strong>GitLab Repository:</strong> <a href="https://gitlab.silverlabs.uk/silverlabs/silvershell" target="_blank" style="color: #a78bfa;">GitLab</a></li>
</ul>
</div>
<!-- Support Section -->
<div class="sdk-section">
<h2>💬 Support</h2>
<p>Need help? We're here for you:</p>
<ul>
<li><strong>Help Desk:</strong> <a href="https://helpdesk.silverlabs.uk" target="_blank" style="color: #a78bfa;">helpdesk.silverlabs.uk</a></li>
<li><strong>Issues:</strong> <a href="https://gitlab.silverlabs.uk/silverlabs/silvershell/-/issues" target="_blank" style="color: #a78bfa;">GitLab Issues</a></li>
</ul>
</div>
<a href="/" class="back-link">← Back to SilverLabs Home</a>
</div>
</div>
<script src="../script.js"></script>
</body>
</html>

314
styles.css Normal file
View File

@@ -0,0 +1,314 @@
:root {
--primary-blue: #2E3192;
--secondary-blue: #1E5A9E;
--cyan: #00B8D4;
--light-cyan: #4DD0E1;
--gradient: linear-gradient(135deg, #2E3192 0%, #1E5A9E 50%, #00B8D4 100%);
--text-primary: #FFFFFF;
--text-secondary: rgba(255, 255, 255, 0.8);
--card-bg: rgba(255, 255, 255, 0.1);
--card-border: rgba(255, 255, 255, 0.2);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: var(--gradient);
background-attachment: fixed;
color: var(--text-primary);
min-height: 100vh;
overflow-x: hidden;
}
/* Loading Screen */
.loading-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--gradient);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
transition: opacity 0.5s ease, visibility 0.5s ease;
}
.loading-screen.fade-out {
opacity: 0;
visibility: hidden;
}
.loading-content {
text-align: center;
}
.loading-logo {
width: 300px;
height: auto;
max-width: 80vw;
animation: pulse 2s ease-in-out infinite;
filter: drop-shadow(0 10px 30px rgba(0, 0, 0, 0.3));
}
.loading-spinner {
margin-top: 30px;
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top-color: var(--text-primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-left: auto;
margin-right: auto;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Main Content */
.main-content {
opacity: 0;
transition: opacity 0.5s ease;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.main-content.visible {
opacity: 1;
}
.header {
padding: 40px 20px;
text-align: center;
}
.logo {
width: 200px;
height: auto;
max-width: 80vw;
filter: drop-shadow(0 5px 20px rgba(0, 0, 0, 0.2));
animation: fadeInDown 0.8s ease;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.main {
flex: 1;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.title {
font-size: 3rem;
font-weight: 700;
text-align: center;
margin-bottom: 10px;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
animation: fadeInUp 0.8s ease 0.2s both;
}
.subtitle {
font-size: 1.5rem;
text-align: center;
color: var(--text-secondary);
margin-bottom: 60px;
animation: fadeInUp 0.8s ease 0.3s both;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.gateway-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 30px;
margin-bottom: 60px;
}
.gateway-card {
background: var(--card-bg);
backdrop-filter: blur(10px);
border: 1px solid var(--card-border);
border-radius: 20px;
padding: 40px 30px;
text-align: center;
text-decoration: none;
color: var(--text-primary);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
animation: fadeInScale 0.6s ease both;
}
.gateway-card:nth-child(1) {
animation-delay: 0.4s;
}
.gateway-card:nth-child(2) {
animation-delay: 0.5s;
}
.gateway-card:nth-child(3) {
animation-delay: 0.6s;
}
@keyframes fadeInScale {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.gateway-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transition: left 0.5s ease;
}
.gateway-card:hover::before {
left: 100%;
}
.gateway-card:hover {
transform: translateY(-10px);
background: rgba(255, 255, 255, 0.15);
border-color: rgba(255, 255, 255, 0.4);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}
.card-icon {
width: 80px;
height: 80px;
margin: 0 auto 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.card-icon svg {
width: 40px;
height: 40px;
stroke: var(--light-cyan);
transition: all 0.3s ease;
}
.gateway-card:hover .card-icon {
background: rgba(255, 255, 255, 0.2);
transform: rotate(10deg) scale(1.1);
}
.gateway-card:hover .card-icon svg {
stroke: var(--text-primary);
}
.card-title {
font-size: 1.8rem;
font-weight: 600;
margin-bottom: 10px;
}
.card-description {
font-size: 1rem;
color: var(--text-secondary);
}
.footer {
padding: 30px 20px;
text-align: center;
color: var(--text-secondary);
font-size: 0.9rem;
}
/* Responsive Design */
@media (max-width: 768px) {
.title {
font-size: 2rem;
}
.subtitle {
font-size: 1.2rem;
margin-bottom: 40px;
}
.gateway-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.logo {
width: 150px;
}
.loading-logo {
width: 200px;
}
}
@media (max-width: 480px) {
.title {
font-size: 1.5rem;
}
.subtitle {
font-size: 1rem;
}
.card-title {
font-size: 1.5rem;
}
.gateway-card {
padding: 30px 20px;
}
}