Initial import

This commit is contained in:
Flatlogic Bot 2026-03-05 12:15:04 +00:00
commit 69a882b160
8 changed files with 998 additions and 0 deletions

186
My_App-main/.idx/airules.md Normal file
View File

@ -0,0 +1,186 @@
# Gemini AI Rules for Firebase Studio Nix Projects
## 1. Persona & Expertise
You are an expert in configuring development environments within Firebase Studio. You are proficient in using the `dev.nix` file to define reproducible, declarative, and isolated development environments. You have experience with the Nix language in the context of Firebase Studio, including packaging, managing dependencies, and configuring services.
## 2. Project Context
This project is a Nix-based environment for Firebase Studio, defined by a `.idx/dev.nix` file. The primary goal is to ensure a reproducible and consistent development environment. The project leverages the power of Nix to manage dependencies, tools, and services in a declarative manner. **Note:** This is not a Nix Flake-based environment.
## 3. `dev.nix` Configuration
The `.idx/dev.nix` file is the single source of truth for the development environment. Here are some of the most common configuration options:
### `channel`
The `nixpkgs` channel determines which package versions are available.
```nix
{ pkgs, ... }: {
channel = "stable-24.05"; # or "unstable"
}
```
### `packages`
A list of packages to install from the specified channel. You can search for packages on the [NixOS package search](https://search.nixos.org/packages).
```nix
{ pkgs, ... }: {
packages = [
pkgs.nodejs_20
pkgs.go
];
}
```
### `env`
A set of environment variables to define within the workspace.
```nix
{ pkgs, ... }: {
env = {
API_KEY = "your-secret-key";
};
}
```
### `idx.extensions`
A list of VS Code extensions to install from the [Open VSX Registry](https://open-vsx.org/).
```nix
{ pkgs, ... }: {
idx = {
extensions = [
"vscodevim.vim"
"golang.go"
];
};
}
```
### `idx.workspace`
Workspace lifecycle hooks.
- **`onCreate`:** Runs when a workspace is first created.
- **`onStart`:** Runs every time the workspace is (re)started.
```nix
{ pkgs, ... }: {
idx = {
workspace = {
onCreate = {
npm-install = "npm install";
};
onStart = {
start-server = "npm run dev";
};
};
};
}
```
### `idx.previews`
Configure a web preview for your application. The `$PORT` variable is dynamically assigned.
```nix
{ pkgs, ... }: {
idx = {
previews = {
enable = true;
previews = {
web = {
command = ["npm" "run" "dev" "--" "--port" "$PORT"];
manager = "web";
};
};
};
};
}
```
## 4. Example Setups for Common Frameworks
Here are some examples of how to configure your `dev.nix` for common languages and frameworks.
### Node.js Web Server
This example sets up a Node.js environment, installs dependencies, and runs a development server with a web preview.
```nix
{ pkgs, ... }: {
packages = [ pkgs.nodejs_20 ];
idx = {
extensions = [ "dbaeumer.vscode-eslint" ];
workspace = {
onCreate = {
npm-install = "npm install";
};
onStart = {
dev-server = "npm run dev";
};
};
previews = {
enable = true;
previews = {
web = {
command = ["npm" "run" "dev" "--" "--port" "$PORT"];
manager = "web";
};
};
};
};
}
```
### Python with Flask
This example sets up a Python environment for a Flask web server. Remember to create a `requirements.txt` file with `Flask` in it.
```nix
{ pkgs, ... }: {
packages = [ pkgs.python3 pkgs.pip ];
idx = {
extensions = [ "ms-python.python" ];
workspace = {
onCreate = {
pip-install = "pip install -r requirements.txt";
};
};
previews = {
enable = true;
previews = {
web = {
command = ["flask" "run" "--port" "$PORT"];
manager = "web";
};
};
};
};
}
```
### Go CLI
This example sets up a Go environment for building a command-line interface.
```nix
{ pkgs, ... }: {
packages = [ pkgs.go ];
idx = {
extensions = [ "golang.go" ];
workspace = {
onCreate = {
go-mod = "go mod tidy";
};
onStart = {
run-app = "go run .";
};
};
};
}
```
## 5. Interaction Guidelines
- Assume the user is familiar with general software development concepts but may be new to Nix and Firebase Studio.
- When generating Nix code, provide comments to explain the purpose of different sections.
- Explain the benefits of using `dev.nix` for reproducibility and dependency management.
- If a request is ambiguous, ask for clarification on the desired tools, libraries, and versions to be included in the environment.
- When suggesting changes to `dev.nix`, explain the impact of the changes on the development environment and remind the user to reload the environment.

49
My_App-main/.idx/dev.nix Normal file
View File

@ -0,0 +1,49 @@
# To learn more about how to use Nix to configure your environment
# see: https://developers.google.com/idx/guides/customize-idx-env
{ pkgs, ... }: {
# Which nixpkgs channel to use.
channel = "stable-24.05"; # or "unstable"
# Use https://search.nixos.org/packages to find packages
packages = [
pkgs.python3
# pkgs.go
# pkgs.python311
# pkgs.python311Packages.pip
# pkgs.nodejs_20
# pkgs.nodePackages.nodemon
];
# Sets environment variables in the workspace
env = {};
idx = {
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
extensions = [
# "vscodevim.vim"
"google.gemini-cli-vscode-ide-companion"
];
# Enable previews
previews = {
enable = true;
previews = {
web = {
command = ["python3" "-m" "http.server" "$PORT"];
manager = "web";
};
};
};
# Workspace lifecycle hooks
workspace = {
# Runs when a workspace is first created
onCreate = {
# Example: install JS dependencies from NPM
# npm-install = "npm install";
# Open editors for the following files by default, if they exist:
default.openFiles = [ ".idx/dev.nix" "README.md" ];
};
# Runs when the workspace is (re)started
onStart = {
# Example: start a background task to watch and re-build backend code
# watch-backend = "npm run watch-backend";
};
};
};
}

3
My_App-main/README.md Normal file
View File

@ -0,0 +1,3 @@
Get started by customizing your environment (defined in the .idx/dev.nix file) with the tools and IDE extensions you'll need for your project!
Learn more at https://developers.google.com/idx/guides/customize-idx-env

192
My_App-main/app.js Normal file
View File

@ -0,0 +1,192 @@
// ==========================================
// 1. FIREBASE CONFIG
// ==========================================
const firebaseConfig = {
apiKey: "AIzaSyB_Fv9HLMOy9cCHT2cZLLwRQOGGBHA_8N0",
authDomain: "myapp-94cf9.firebaseapp.com",
projectId: "myapp-94cf9",
storageBucket: "myapp-94cf9.firebasestorage.app",
messagingSenderId: "542065139667",
appId: "1:542065139667:web:76ed67d78188ff3e6dd926"
};
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const auth = firebase.auth();
// ==========================================
// 2. GLOBAL VARIABLES
// ==========================================
let allEvents = [];
let currentCategory = "All";
let currentFilter = "All";
let searchQuery = "";
// ==========================================
// 3. AUTH GUARD & INITIALIZATION
// ==========================================
auth.onAuthStateChanged(user => {
// This code runs on every page load
// 1. GUARD: If NOT on login page and NO user, redirect to login
if (!window.location.pathname.includes('index.html') && !window.location.pathname.includes('login')) {
if (!user) {
window.location.href = 'index.html';
return;
}
}
// 2. If user is logged in (or guest)
if (user) {
console.log("Logged in as:", user.email || "Guest");
// HANDLE UI ELEMENTS
const userPhoto = document.getElementById('userPhoto');
const createBtn = document.querySelector('a[href="create.html"]');
const logoutBtn = document.getElementById('logoutBtn');
// Check if User is Guest (Anonymous)
if (user.isAnonymous) {
// Change Photo to Guest Icon
if(userPhoto) userPhoto.src = "https://cdn-icons-png.flaticon.com/512/1077/1077114.png";
// Hide Create Button (Guests cannot create)
if(createBtn) createBtn.style.display = 'none';
} else {
// Real User
if(userPhoto && user.photoURL) userPhoto.src = user.photoURL;
// Show Create Button
if(createBtn) createBtn.style.display = 'inline-flex';
}
// Logout Button Logic
if(logoutBtn) {
logoutBtn.addEventListener('click', () => auth.signOut());
}
// Load data if on home page
if (document.getElementById('eventsGrid')) {
loadEvents();
setupListeners();
}
}
});
// ==========================================
// 4. LOAD EVENTS FROM FIREBASE
// ==========================================
async function loadEvents() {
const eventsGrid = document.getElementById('eventsGrid');
if(!eventsGrid) return;
db.collection('events').orderBy('date', 'asc').onSnapshot(snapshot => {
allEvents = [];
snapshot.forEach(doc => {
allEvents.push({ id: doc.id, ...doc.data() });
});
renderEvents();
});
}
// ==========================================
// 5. RENDER & FILTER EVENTS
// ==========================================
function renderEvents() {
const eventsGrid = document.getElementById('eventsGrid');
let filtered = allEvents;
// Filter by Category
if (currentCategory !== "All") {
filtered = filtered.filter(e => e.category === currentCategory);
}
// Filter by Search
if (searchQuery) {
filtered = filtered.filter(e =>
e.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
e.location.toLowerCase().includes(searchQuery.toLowerCase())
);
}
// Date Filters
const today = new Date();
today.setHours(0,0,0,0);
if (currentFilter === "Today") {
filtered = filtered.filter(e => {
const d = e.date.toDate ? e.date.toDate() : new Date(e.date);
return d.toDateString() === today.toDateString();
});
} else if (currentFilter === "Tomorrow") {
const tom = new Date(today);
tom.setDate(tom.getDate() + 1);
filtered = filtered.filter(e => {
const d = e.date.toDate ? e.date.toDate() : new Date(e.date);
return d.toDateString() === tom.toDateString();
});
}
// Generate HTML
eventsGrid.innerHTML = filtered.map(event => {
const d = event.date.toDate ? event.date.toDate() : new Date(event.date);
const months = ["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"];
return `
<div class="event-card">
<div class="card-image">
<img src="${event.image}" alt="${event.title}">
</div>
<div class="card-content">
<div class="event-date-box">
<span class="month">${months[d.getMonth()]}</span>
<span class="day">${d.getDate()}</span>
</div>
<div class="event-info">
<h3>${event.title}</h3>
<div class="event-meta">
<span><i class="fas fa-map-marker-alt"></i> ${event.location}</span>
</div>
<div class="event-meta" style="margin-top:5px; font-weight:600; color:var(--primary);">
${event.isFree ? 'Free' : '$' + event.price}
</div>
</div>
</div>
</div>
`;
}).join('');
}
// ==========================================
// 6. EVENT LISTENERS (Tabs & Buttons)
// ==========================================
function setupListeners() {
// Category Tabs
document.querySelectorAll('.cat-item').forEach(item => {
item.addEventListener('click', () => {
document.querySelector('.cat-item.active').classList.remove('active');
item.classList.add('active');
currentCategory = item.getAttribute('data-cat');
renderEvents();
});
});
// Date Filters
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelector('.filter-btn.active').classList.remove('active');
btn.classList.add('active');
currentFilter = btn.getAttribute('data-filter');
renderEvents();
});
});
// Search
const heroSearchBtn = document.getElementById('heroSearchBtn');
if(heroSearchBtn) {
heroSearchBtn.addEventListener('click', () => {
searchQuery = document.getElementById('heroSearch').value;
renderEvents();
});
}
}

123
My_App-main/create.html Normal file
View File

@ -0,0 +1,123 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create Event - EventBee</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav class="navbar">
<div class="nav-container">
<a href="home.html" class="logo">
<div class="logo-icon"><i class="fas fa-calendar-check"></i></div>
<span>EventBee</span>
</a>
<div class="nav-links">
<a href="home.html" class="btn-create"><i class="fas fa-arrow-left"></i> Back</a>
<button id="logoutBtnCreate" class="btn-create">Logout</button>
</div>
</div>
</nav>
<main class="create-section">
<div class="container">
<div class="form-wrapper">
<div class="form-header">
<h1>Create Your Event</h1>
<p>Fill details to publish</p>
</div>
<form id="eventForm">
<div class="form-group">
<label>Event Title</label>
<input type="text" id="eventTitle" required>
</div>
<div class="form-row">
<div class="form-group">
<label>Date</label>
<input type="date" id="eventDate" required>
</div>
<div class="form-group">
<label>Time</label>
<input type="time" id="eventTime" required>
</div>
</div>
<div class="form-group">
<label>Location</label>
<input type="text" id="eventLocation" required>
</div>
<div class="form-row">
<div class="form-group">
<label>Category</label>
<select id="eventCategory">
<option>Business</option>
<option>Music</option>
<option>Food</option>
<option>Sports</option>
<option>Arts</option>
</select>
</div>
<div class="form-group">
<label>Price ($)</label>
<input type="number" id="eventPrice" placeholder="0 for Free">
</div>
</div>
<div class="form-group">
<label>Image URL (Optional)</label>
<input type="text" id="eventImage" placeholder="https://...">
</div>
<button type="submit" class="btn-submit">Publish Event</button>
</form>
</div>
</div>
</main>
<!-- Scripts -->
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-auth-compat.js"></script>
<script src="app.js"></script>
<script>
// Specific Logic for Create Page
const eventForm = document.getElementById('eventForm');
eventForm.addEventListener('submit', async (e) => {
e.preventDefault();
const title = document.getElementById('eventTitle').value;
const date = document.getElementById('eventDate').value;
const time = document.getElementById('eventTime').value;
const location = document.getElementById('eventLocation').value;
const category = document.getElementById('eventCategory').value;
const price = document.getElementById('eventPrice').value;
const image = document.getElementById('eventImage').value || "https://images.unsplash.com/photo-1540575467063-178a50c2df87?auto=format&fit=crop&w=800&q=80";
try {
await db.collection('events').add({
title,
date: new Date(date),
time,
location,
category,
price: price || "0",
image,
isFree: price > 0 ? false : true,
authorId: auth.currentUser.uid,
authorName: auth.currentUser.displayName
});
alert("Event Created!");
window.location.href = 'home.html';
} catch (err) {
alert("Error: " + err.message);
}
});
document.getElementById('logoutBtnCreate').addEventListener('click', () => {
auth.signOut();
});
</script>
</body>
</html>

96
My_App-main/home.html Normal file
View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EventBee - Home</title>
<link rel="manifest" href="manifest.json">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Navigation -->
<nav class="navbar">
<div class="nav-container">
<a href="home.html" class="logo">
<div class="logo-icon"><i class="fas fa-calendar-check"></i></div>
<span>EventBee</span>
</a>
<div class="search-bar">
<i class="fas fa-search"></i>
<input type="text" id="navSearch" placeholder="Search events...">
</div>
<div class="nav-links">
<a href="create.html" class="btn-create"><i class="fas fa-plus"></i> <span>Create Event</span></a>
<button id="logoutBtn" class="btn-create"><i class="fas fa-sign-out-alt"></i> <span>Logout</span></button>
<div class="user-profile">
<img id="userPhoto" src="https://i.pravatar.cc/40?img=12" alt="User">
</div>
</div>
</div>
</nav>
<!-- Hero Section -->
<header class="hero-section">
<div class="hero-content">
<h1>Discover <span>Events</span> Near You</h1>
<p>Explore the best events happening in your city</p>
<div class="search-main">
<div class="input-group search-input">
<i class="fas fa-search"></i>
<input type="text" id="heroSearch" placeholder="Search events...">
</div>
<div class="input-group location-input">
<i class="fas fa-map-marker-alt"></i>
<input type="text" id="heroLocation" placeholder="Location">
</div>
<button class="btn-search-hero" id="heroSearchBtn">Search</button>
</div>
</div>
</header>
<!-- Categories -->
<section class="categories-section">
<div class="container">
<div class="category-grid" id="categoryGrid">
<div class="cat-item active" data-cat="All"><div class="cat-circle"><i class="fas fa-globe"></i></div><span>All</span></div>
<div class="cat-item" data-cat="Music"><div class="cat-circle"><i class="fas fa-music"></i></div><span>Music</span></div>
<div class="cat-item" data-cat="Business"><div class="cat-circle"><i class="fas fa-briefcase"></i></div><span>Business</span></div>
<div class="cat-item" data-cat="Food"><div class="cat-circle"><i class="fas fa-utensils"></i></div><span>Food</span></div>
<div class="cat-item" data-cat="Sports"><div class="cat-circle"><i class="fas fa-futbol"></i></div><span>Sports</span></div>
<div class="cat-item" data-cat="Arts"><div class="cat-circle"><i class="fas fa-palette"></i></div><span>Arts</span></div>
</div>
</div>
</section>
<!-- Events Grid -->
<main class="main-content">
<div class="container">
<div class="section-top">
<h2>Upcoming Events</h2>
<div class="filters">
<button class="filter-btn active" data-filter="All">All</button>
<button class="filter-btn" data-filter="Today">Today</button>
<button class="filter-btn" data-filter="Tomorrow">Tomorrow</button>
</div>
</div>
<div class="events-grid" id="eventsGrid">
<!-- Events loaded here -->
</div>
</div>
</main>
<footer class="footer">
<p>&copy; 2024 EventBee. All rights reserved.</p>
</footer>
<!-- Scripts -->
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-auth-compat.js"></script>
<script src="app.js"></script>
</body>
</html>

180
My_App-main/index.html Normal file
View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EventBee - Login</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="auth-body">
<div class="auth-container">
<!-- Left Side -->
<div class="auth-brand">
<div class="brand-content">
<div class="logo">
<div class="logo-icon"><i class="fas fa-calendar-check"></i></div>
<span>EventBee</span>
</div>
<h2>Start your journey with us.</h2>
<p>Discover the best events happening around you. Login to explore, connect, and create memories.</p>
</div>
</div>
<!-- Right Side Forms -->
<div class="auth-forms">
<!-- Login Form -->
<div class="form-box" id="loginBox">
<div class="form-header">
<h1>Welcome Back</h1>
<p>Login to continue</p>
</div>
<div class="social-login">
<button class="google-btn" id="googleLoginBtn">
<img src="https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg" alt="G">
Sign in with Google
</button>
<!-- NEW: Guest Login Button -->
<button class="google-btn" id="guestLoginBtn" style="background: #f0f2f5; border: 1px solid #ccc;">
<i class="fas fa-user-secret" style="font-size: 20px; color: #555;"></i>
Continue as Guest
</button>
</div>
<div class="divider"><span>or use email</span></div>
<form id="loginForm">
<div class="input-group-auth"><i class="fas fa-envelope"></i><input type="email" id="loginEmail" placeholder="Email" required></div>
<div class="input-group-auth"><i class="fas fa-lock"></i><input type="password" id="loginPassword" placeholder="Password" required></div>
<button type="submit" class="btn-submit-auth">Login</button>
</form>
<div class="switch-auth"><p>Don't have an account? <a id="showSignupBtn">Sign Up</a></p></div>
</div>
<!-- Signup Form -->
<div class="form-box hidden" id="signupBox">
<div class="form-header">
<h1>Create Account</h1>
<p>Join EventBee today</p>
</div>
<div class="social-login">
<button class="google-btn" id="googleSignupBtn">
<img src="https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg" alt="G">
Sign up with Google
</button>
</div>
<div class="divider"><span>or register with email</span></div>
<form id="signupForm">
<div class="input-group-auth"><i class="fas fa-user"></i><input type="text" id="signupName" placeholder="Full Name" required></div>
<div class="input-group-auth"><i class="fas fa-envelope"></i><input type="email" id="signupEmail" placeholder="Email" required></div>
<div class="input-group-auth"><i class="fas fa-lock"></i><input type="password" id="signupPassword" placeholder="Password" required></div>
<button type="submit" class="btn-submit-auth">Sign Up</button>
</form>
<div class="switch-auth"><p>Already have an account? <a id="showLoginBtn">Login</a></p></div>
</div>
</div>
</div>
<!-- Scripts -->
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-auth-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore-compat.js"></script>
<script>
// ==========================================
// 1. FIREBASE CONFIG
// ==========================================
const firebaseConfig = {
apiKey: "AIzaSyB_Fv9HLMOy9cCHT2cZLLwRQOGGBHA_8N0",
authDomain: "myapp-94cf9.firebaseapp.com",
projectId: "myapp-94cf9",
storageBucket: "myapp-94cf9.firebasestorage.app",
messagingSenderId: "542065139667",
appId: "1:542065139667:web:76ed67d78188ff3e6dd926"
};
firebase.initializeApp(firebaseConfig);
const auth = firebase.auth();
const db = firebase.firestore();
// ==========================================
// 2. AUTH STATE LISTENER
// ==========================================
auth.onAuthStateChanged(user => {
if (user) {
window.location.href = 'home.html';
}
});
// ==========================================
// 3. UI SWITCHING
// ==========================================
const loginBox = document.getElementById('loginBox');
const signupBox = document.getElementById('signupBox');
document.getElementById('showSignupBtn').addEventListener('click', () => {
loginBox.classList.add('hidden');
signupBox.classList.remove('hidden');
});
document.getElementById('showLoginBtn').addEventListener('click', () => {
signupBox.classList.add('hidden');
loginBox.classList.remove('hidden');
});
// ==========================================
// 4. LOGIN LOGIC
// ==========================================
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('loginEmail').value;
const pass = document.getElementById('loginPassword').value;
try {
await auth.signInWithEmailAndPassword(email, pass);
} catch (err) { alert(err.message); }
});
// Google Login
document.getElementById('googleLoginBtn').addEventListener('click', async () => {
const provider = new firebase.auth.GoogleAuthProvider();
try { await auth.signInWithPopup(provider); } catch (err) { alert(err.message); }
});
// NEW: Guest Login
document.getElementById('guestLoginBtn').addEventListener('click', async () => {
try {
await auth.signInAnonymously();
} catch (err) {
alert(err.message);
}
});
// ==========================================
// 5. SIGNUP LOGIC
// ==========================================
document.getElementById('signupForm').addEventListener('submit', async (e) => {
e.preventDefault();
const name = document.getElementById('signupName').value;
const email = document.getElementById('signupEmail').value;
const pass = document.getElementById('signupPassword').value;
try {
const cred = await auth.createUserWithEmailAndPassword(email, pass);
await cred.user.updateProfile({ displayName: name });
await db.collection('users').doc(cred.user.uid).set({ name, email });
} catch (err) { alert(err.message); }
});
document.getElementById('googleSignupBtn').addEventListener('click', async () => {
const provider = new firebase.auth.GoogleAuthProvider();
try { await auth.signInWithPopup(provider); } catch (err) { alert(err.message); }
});
</script>
</body>
</html>

169
My_App-main/style.css Normal file
View File

@ -0,0 +1,169 @@
/* ==========================================
1. GLOBAL STYLES & VARIABLES
========================================== */
:root {
--primary: #4a4ef7;
--primary-dark: #3d41d6;
--bg-color: #f7f7f7;
--card-bg: #ffffff;
--text-main: #222222;
--text-light: #888888;
--shadow: 0 10px 30px rgba(0,0,0,0.08);
--radius: 16px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; background-color: var(--bg-color); color: var(--text-main); line-height: 1.6; }
.container { max-width: 1200px; margin: 0 auto; padding: 0 20px; }
/* Utility Class for Hiding Elements */
.hidden { display: none !important; }
/* ==========================================
2. LOGIN PAGE STYLES (index.html)
========================================== */
.auth-body { margin: 0; min-height: 100vh; display: flex; background: #f0f2f5; }
.auth-container { display: flex; width: 100%; min-height: 100vh; }
.auth-brand {
flex: 1;
background: linear-gradient(135deg, var(--primary) 0%, #6c5ce7 100%);
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
color: white;
}
.auth-brand .logo span { color: white; font-size: 2rem; font-weight: 700; }
.auth-brand .logo-icon { background: rgba(255,255,255,0.2); width: 50px; height: 50px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; }
.brand-content { max-width: 400px; }
.brand-content h2 { font-size: 2.5rem; margin: 20px 0; font-weight: 700; }
.brand-content p { font-size: 1.1rem; opacity: 0.9; }
.auth-forms {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: white;
padding: 40px;
}
.form-box { width: 100%; max-width: 400px; }
.form-header h1 { font-size: 2rem; margin-bottom: 10px; }
.form-header p { color: var(--text-light); margin-bottom: 30px; }
.social-login { margin-bottom: 20px; }
.google-btn {
width: 100%; padding: 12px; background: white; border: 1px solid #ddd; border-radius: 8px;
display: flex; align-items: center; justify-content: center; gap: 10px; font-weight: 600;
cursor: pointer; font-family: inherit; transition: 0.3s;
}
.google-btn:hover { background: #f9f9f9; }
.google-btn img { width: 20px; height: 20px; }
.divider { text-align: center; position: relative; margin: 20px 0; color: #aaa; }
.divider::before, .divider::after { content: ""; position: absolute; top: 50%; width: 40%; height: 1px; background: #eee; }
.divider::before { left: 0; } .divider::after { right: 0; }
.input-group-auth {
display: flex; align-items: center; background: #f5f5f5; border-radius: 8px;
margin-bottom: 15px; padding: 0 15px; border: 2px solid transparent; transition: 0.3s; height: 50px;
}
.input-group-auth:focus-within { border-color: var(--primary); background: white; }
.input-group-auth input { width: 100%; border: none; background: transparent; font-family: inherit; outline: none; font-size: 1rem; }
.input-group-auth i { color: #888; margin-right: 15px; width: 20px; text-align: center; }
.btn-submit-auth {
width: 100%; padding: 14px; background: var(--primary); color: white; border: none;
border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: 0.3s;
}
.btn-submit-auth:hover { background: var(--primary-dark); }
.switch-auth { text-align: center; margin-top: 25px; color: #666; }
.switch-auth a { color: var(--primary); font-weight: 600; text-decoration: none; cursor: pointer; }
/* ==========================================
3. MAIN APP STYLES (home.html & create.html)
========================================== */
/* Navbar */
.navbar { background: var(--card-bg); height: 75px; display: flex; align-items: center; position: sticky; top: 0; z-index: 1000; box-shadow: 0 1px 0 rgba(0,0,0,0.05); padding: 0 40px; }
.nav-container { width: 100%; display: flex; align-items: center; justify-content: space-between; }
.logo { display: flex; align-items: center; gap: 10px; text-decoration: none; }
.logo-icon { width: 40px; height: 40px; background: var(--primary); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.2rem; }
.logo span { font-size: 1.5rem; font-weight: 700; color: var(--text-main); }
.search-bar { display: flex; align-items: center; background: var(--bg-color); padding: 12px 25px; border-radius: 40px; width: 30%; }
.search-bar input { border: none; background: transparent; width: 100%; margin-left: 10px; font-family: inherit; outline: none; }
.nav-links { display: flex; align-items: center; gap: 15px; }
.btn-create { background: var(--bg-color); color: var(--text-main); padding: 10px 20px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: 0.3s; border: none; cursor: pointer; font-family: inherit; font-size: 0.95rem; }
.btn-create:hover { background: var(--primary); color: white; }
.user-profile img { width: 40px; height: 40px; border-radius: 50%; cursor: pointer; object-fit: cover; }
/* Hero Section */
.hero-section { background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%); padding: 100px 20px 120px; text-align: center; }
.hero-section h1 { font-size: 3.5rem; color: #1a1a1a; margin-bottom: 15px; font-weight: 800; }
.hero-section h1 span { color: var(--primary); }
.hero-section p { color: #666; font-size: 1.1rem; margin-bottom: 40px; }
.search-main { background: var(--card-bg); padding: 8px; border-radius: 70px; display: flex; align-items: center; box-shadow: var(--shadow); max-width: 900px; margin: 0 auto; }
.input-group { display: flex; align-items: center; padding: 10px 20px; flex: 1; color: #888; }
.input-group i { margin-right: 12px; color: var(--primary); }
.input-group input { border: none; width: 100%; font-family: inherit; font-size: 1rem; background: transparent; outline: none; }
.search-input { flex: 1.5; border-right: 1px solid #eee; }
.location-input { flex: 1; border-right: 1px solid #eee; }
.btn-search-hero { background: var(--primary); color: white; border: none; padding: 18px 40px; border-radius: 50px; font-weight: 600; cursor: pointer; transition: 0.3s; }
/* Categories */
.categories-section { margin-top: -50px; position: relative; z-index: 10; padding-bottom: 40px; }
.category-grid { display: flex; gap: 15px; overflow-x: auto; padding: 20px 0; scrollbar-width: none; justify-content: center; }
.cat-item { display: flex; flex-direction: column; align-items: center; gap: 10px; cursor: pointer; min-width: 80px; }
.cat-circle { width: 60px; height: 60px; background: white; border-radius: 20px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; color: #555; box-shadow: 0 5px 15px rgba(0,0,0,0.08); transition: 0.3s; }
.cat-item:hover .cat-circle, .cat-item.active .cat-circle { background: var(--primary); color: white; transform: translateY(-5px); }
/* Events Grid */
.main-content { padding: 40px 0; }
.section-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; }
.filters { display: flex; gap: 10px; }
.filter-btn { background: white; border: 1px solid #eee; padding: 8px 20px; border-radius: 8px; cursor: pointer; transition: 0.3s; font-family: inherit; }
.filter-btn.active, .filter-btn:hover { background: var(--primary); color: white; border-color: var(--primary); }
.events-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 30px; }
/* Event Card */
.event-card { background: white; border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); transition: 0.3s; }
.event-card:hover { transform: translateY(-10px); box-shadow: 0 15px 30px rgba(0,0,0,0.1); }
.card-image { height: 200px; position: relative; overflow: hidden; background: #eee; }
.card-image img { width: 100%; height: 100%; object-fit: cover; }
.love-btn { position: absolute; top: 15px; right: 15px; width: 35px; height: 35px; border-radius: 50%; background: white; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.card-content { padding: 20px; display: flex; gap: 15px; }
.event-date-box { display: flex; flex-direction: column; align-items: center; justify-content: center; background: #f8f9fa; border-radius: 12px; padding: 10px; width: 60px; height: 70px; border: 1px solid #eee; text-align: center; }
.event-date-box .month { font-size: 0.7rem; color: #999; font-weight: 600; }
.event-date-box .day { font-size: 1.5rem; font-weight: 700; color: var(--text-main); line-height: 1.1; }
.event-info { flex: 1; }
.event-info h3 { font-size: 1rem; margin-bottom: 8px; }
.event-meta { font-size: 0.85rem; color: #666; display: flex; align-items: center; gap: 5px; }
.load-more { text-align: center; margin-top: 40px; }
.btn-load-more { background: transparent; border: 2px solid var(--primary); color: var(--primary); padding: 12px 30px; border-radius: 30px; font-weight: 600; cursor: pointer; transition: 0.3s; }
.btn-load-more:hover { background: var(--primary); color: white; }
/* Footer */
.footer { background: #222; color: #aaa; padding: 30px; text-align: center; margin-top: 50px; }
/* Create Form */
.create-section { padding: 60px 20px; background: #f0f2f5; min-height: 80vh; }
.form-wrapper { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 20px; box-shadow: var(--shadow); }
.form-group { margin-bottom: 20px; }
.form-group label { display: block; margin-bottom: 8px; font-weight: 600; }
.form-group input, .form-group select, .form-group textarea { width: 100%; padding: 14px; border: 1px solid #ddd; border-radius: 8px; font-family: inherit; font-size: 1rem; }
.form-row { display: flex; gap: 20px; }
.form-row .form-group { flex: 1; }
.btn-submit { width: 100%; padding: 16px; background: var(--primary); color: white; border: none; border-radius: 10px; font-size: 1.1rem; font-weight: 600; cursor: pointer; }
.btn-submit:hover { background: var(--primary-dark); }
/* Mobile Responsive */
@media (max-width: 768px) {
.search-bar, .nav-links .btn-create span { display: none; }
.hero-section h1 { font-size: 2rem; }
.search-main { flex-direction: column; border-radius: 20px; padding: 15px; }
.input-group { width: 100%; border-right: none !important; border-bottom: 1px solid #eee; padding: 15px; }
.auth-brand { display: none; }
.form-row { flex-direction: column; }
}