Initial commit

This commit is contained in:
Kerboul
2026-03-09 07:44:27 -07:00
commit 14031f73a3
7 changed files with 589 additions and 0 deletions

59
app.js Normal file
View File

@@ -0,0 +1,59 @@
// Register Service Worker for PWA
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('./sw.js')
.then((registration) => {
console.log('SW registered: ', registration);
})
.catch((registrationError) => {
console.log('SW registration failed: ', registrationError);
});
});
}
// PWA Install Prompt Logic
let deferredPrompt;
const installBtn = document.getElementById('installBtn');
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
// Update UI to notify the user they can add to home screen
if(installBtn) {
installBtn.hidden = false;
}
});
if(installBtn) {
installBtn.addEventListener('click', async () => {
if (deferredPrompt !== null) {
// Show the install prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
const { outcome } = await deferredPrompt.userChoice;
if (outcome === 'accepted') {
console.log('User accepted the install prompt');
} else {
console.log('User dismissed the install prompt');
}
// We've used the prompt, and can't use it again, throw it away
deferredPrompt = null;
installBtn.hidden = true;
}
});
}
// Interactive element animation
const pulseElement = document.getElementById('pulseElement');
if(pulseElement) {
pulseElement.addEventListener('click', () => {
pulseElement.style.transform = 'scale(0.9)';
setTimeout(() => {
pulseElement.style.transform = 'scale(1)';
const randomColor = Math.floor(Math.random()*16777215).toString(16);
pulseElement.style.background = `#${randomColor}`;
}, 150);
});
}

11
icon.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#6366f1;stop-opacity:1" />
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:1" />
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="512" height="512" rx="100" fill="url(#grad)" />
<path d="M256 120 L380 340 L132 340 Z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 533 B

89
index.html Normal file
View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="theme-color" content="#0f172a" />
<title>Amusement - Stylish PWA Demo</title>
<meta name="description" content="A generic frontend demo showcasing beautiful, modern web design and PWA capabilities." />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800&family=Outfit:wght@400;600;800&display=swap" rel="stylesheet">
<!-- Styles -->
<link rel="stylesheet" href="./style.css" />
<!-- PWA Manifest & Icons -->
<link rel="manifest" href="./manifest.json" />
<link rel="icon" type="image/svg+xml" href="./icon.svg" />
<link rel="apple-touch-icon" href="./icon.svg" />
</head>
<body>
<div class="background-effects">
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
</div>
<main class="app-container">
<header class="glass-header">
<div class="logo">
<span class="logo-icon"></span>
<h1>Amusement</h1>
</div>
<nav>
<button class="nav-btn active">Home</button>
<button class="nav-btn">Features</button>
<button class="nav-btn primary">Get Started</button>
</nav>
</header>
<section class="hero-section">
<div class="hero-content">
<div class="badge">Next-Gen Experience</div>
<h2 class="display-text">Stunning visuals,<br/> <span class="gradient-text">Zero Compromises.</span></h2>
<p class="subtitle">Experience a breathtaking Progressive Web App designed with modern aesthetics, glassmorphism, and seamless interactions.</p>
<div class="action-group">
<button class="btn btn-primary" id="installBtn" hidden>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Install App
</button>
<button class="btn btn-secondary">Explore Demo</button>
</div>
</div>
<div class="hero-visual">
<div class="glass-card main-card">
<div class="card-header">
<div class="dots">
<span></span><span></span><span></span>
</div>
</div>
<div class="card-body">
<div class="skeleton-line full"></div>
<div class="skeleton-line medium"></div>
<div class="stats-grid">
<div class="stat-box">
<span class="stat-value">99%</span>
<span class="stat-label">Performance</span>
</div>
<div class="stat-box">
<span class="stat-value">PWA</span>
<span class="stat-label">Native Feel</span>
</div>
</div>
<div class="interactive-element" id="pulseElement">
Tap to Interact
</div>
</div>
</div>
</div>
</section>
</main>
<script src="./app.js" type="module"></script>
</body>
</html>

17
manifest.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "Amusement Dashboard",
"short_name": "Amusement",
"description": "A stunning visual demo and Progressive Web App template",
"start_url": "/index.html",
"display": "standalone",
"background_color": "#0f172a",
"theme_color": "#0f172a",
"icons": [
{
"src": "./icon.svg",
"sizes": "192x192 512x512",
"type": "image/svg+xml",
"purpose": "any maskable"
}
]
}

13
package.json Normal file
View File

@@ -0,0 +1,13 @@
{
"name": "amusement-pwa-template",
"version": "1.0.0",
"description": "Stylish PWA Demo",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"devDependencies": {
"vite": "^5.0.0"
}
}

352
style.css Normal file
View File

@@ -0,0 +1,352 @@
:root {
--bg-dark: #0f172a;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--primary-gradient: linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%);
--glass-bg: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.08);
--glass-highlight: rgba(255, 255, 255, 0.15);
--font-sans: 'Inter', sans-serif;
--font-display: 'Outfit', sans-serif;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-sans);
background-color: var(--bg-dark);
color: var(--text-main);
min-height: 100vh;
overflow-x: hidden;
line-height: 1.5;
}
/* Background Effects */
.background-effects {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
z-index: -1;
overflow: hidden;
}
.blob {
position: absolute;
filter: blur(80px);
border-radius: 50%;
opacity: 0.6;
animation: float 20s infinite ease-in-out;
}
.blob-1 {
top: -10%; left: -10%;
width: 50vw; height: 50vw;
background: radial-gradient(circle, #6366f1, transparent 70%);
animation-delay: 0s;
}
.blob-2 {
bottom: -20%; right: -10%;
width: 60vw; height: 60vw;
background: radial-gradient(circle, #ec4899, transparent 70%);
animation-delay: -5s;
}
.blob-3 {
top: 30%; left: 40%;
width: 40vw; height: 40vw;
background: radial-gradient(circle, #a855f7, transparent 70%);
animation-delay: -10s;
opacity: 0.4;
}
@keyframes float {
0%, 100% { transform: translate(0, 0) scale(1); }
33% { transform: translate(5%, 10%) scale(1.1); }
66% { transform: translate(-5%, 5%) scale(0.9); }
}
/* Layout */
.app-container {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
display: flex;
flex-direction: column;
min-height: 100vh;
}
/* Header Glassmorphism */
.glass-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: var(--glass-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--glass-border);
border-radius: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.logo {
display: flex;
align-items: center;
gap: 0.75rem;
}
.logo h1 {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -0.5px;
}
.logo-icon {
font-size: 1.5rem;
}
nav {
display: flex;
gap: 1rem;
}
.nav-btn {
background: transparent;
border: none;
color: var(--text-muted);
font-family: var(--font-sans);
font-weight: 500;
font-size: 1rem;
cursor: pointer;
padding: 0.5rem 1rem;
border-radius: 12px;
transition: all 0.3s ease;
}
.nav-btn:hover {
color: var(--text-main);
background: var(--glass-highlight);
}
.nav-btn.active {
color: var(--text-main);
}
.nav-btn.primary {
background: var(--text-main);
color: var(--bg-dark);
font-weight: 600;
}
.nav-btn.primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(255, 255, 255, 0.2);
}
/* Hero Section */
.hero-section {
flex: 1;
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
gap: 4rem;
margin-top: 4rem;
}
.badge {
display: inline-block;
padding: 0.5rem 1rem;
background: rgba(99, 102, 241, 0.1);
border: 1px solid rgba(99, 102, 241, 0.3);
color: #818cf8;
border-radius: 100px;
font-size: 0.875rem;
font-weight: 600;
margin-bottom: 1.5rem;
letter-spacing: 0.5px;
text-transform: uppercase;
}
.display-text {
font-family: var(--font-display);
font-size: 4.5rem;
line-height: 1.1;
font-weight: 800;
margin-bottom: 1.5rem;
letter-spacing: -1px;
}
.gradient-text {
background: var(--primary-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.subtitle {
font-size: 1.25rem;
color: var(--text-muted);
max-width: 500px;
margin-bottom: 2.5rem;
}
.action-group {
display: flex;
gap: 1rem;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 1rem 2rem;
border-radius: 16px;
font-family: var(--font-sans);
font-weight: 600;
font-size: 1.125rem;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: none;
}
.btn-primary {
background: var(--primary-gradient);
color: white;
box-shadow: 0 10px 30px rgba(99, 102, 241, 0.4);
}
.btn-primary:hover {
transform: translateY(-3px) scale(1.02);
box-shadow: 0 15px 40px rgba(99, 102, 241, 0.5);
}
.btn-secondary {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
color: var(--text-main);
backdrop-filter: blur(10px);
}
.btn-secondary:hover {
background: var(--glass-highlight);
transform: translateY(-3px);
}
/* Glass Card right side */
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: 32px;
padding: 2rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
transform: perspective(1000px) rotateY(-5deg) rotateX(5deg);
transition: transform 0.5s ease;
}
.glass-card:hover {
transform: perspective(1000px) rotateY(0deg) rotateX(0deg);
}
.glass-card::before {
content: '';
position: absolute;
top: 0; left: -100%;
width: 50%; height: 100%;
background: linear-gradient(to right, transparent, rgba(255,255,255,0.1), transparent);
transform: skewX(-20deg);
animation: shine 6s infinite;
}
@keyframes shine {
0% { left: -100%; }
20% { left: 200%; }
100% { left: 200%; }
}
.card-header .dots {
display: flex;
gap: 8px;
margin-bottom: 2rem;
}
.dots span {
width: 12px; height: 12px;
border-radius: 50%;
}
.dots span:nth-child(1) { background: #ef4444; }
.dots span:nth-child(2) { background: #eab308; }
.dots span:nth-child(3) { background: #22c55e; }
.skeleton-line {
height: 24px;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
margin-bottom: 1rem;
}
.skeleton-line.full { width: 100%; }
.skeleton-line.medium { width: 70%; margin-bottom: 2rem; }
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 2rem;
}
.stat-box {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 16px;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.stat-value {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 800;
color: var(--text-main);
}
.stat-label {
font-size: 0.875rem;
color: var(--text-muted);
}
.interactive-element {
background: var(--primary-gradient);
padding: 1rem;
border-radius: 16px;
text-align: center;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
user-select: none;
}
.interactive-element:active {
transform: scale(0.95);
}
/* Responsive */
@media (max-width: 1024px) {
.hero-section {
grid-template-columns: 1fr;
text-align: center;
}
.display-text { font-size: 3.5rem; }
.subtitle { margin: 0 auto 2.5rem; }
.action-group { justify-content: center; }
.glass-card { margin-top: 2rem; transform: none; }
.glass-card:hover { transform: translateY(-5px); }
nav { display: none; }
}

48
sw.js Normal file
View File

@@ -0,0 +1,48 @@
const CACHE_NAME = 'amusement-pwa-cache-v1';
const urlsToCache = [
'./',
'./index.html',
'./style.css',
'./app.js',
'./manifest.json',
'./icon.svg',
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800&family=Outfit:wght@400;600;800&display=swap'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});