Initial commit
This commit is contained in:
59
app.js
Normal file
59
app.js
Normal 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
11
icon.svg
Normal 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
89
index.html
Normal 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
17
manifest.json
Normal 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
13
package.json
Normal 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
352
style.css
Normal 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
48
sw.js
Normal 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);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user