Initial import
This commit is contained in:
commit
69a882b160
186
My_App-main/.idx/airules.md
Normal file
186
My_App-main/.idx/airules.md
Normal 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
49
My_App-main/.idx/dev.nix
Normal 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
3
My_App-main/README.md
Normal 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
192
My_App-main/app.js
Normal 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
123
My_App-main/create.html
Normal 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
96
My_App-main/home.html
Normal 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>© 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
180
My_App-main/index.html
Normal 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
169
My_App-main/style.css
Normal 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; }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user