bucketlist added
This commit is contained in:
1 parent
97841f3f24
commit
650211e8ab
7 files changed
+240
-15
No files matched your search
@@ -0,0 +1,87 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## Project Structure & Module Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
website/
|
||||||
|
├── index.html # Single-page entry point — all 5 tabs live here
|
||||||
|
├── gallery-container.html # Static gallery image tags (50 images)
|
||||||
|
├── _redirects # Netlify SPA rewrite rule (/* → /index.html)
|
||||||
|
├── js/
|
||||||
|
│ ├── tabs.js # Client-side routing, tab switching, background video swap
|
||||||
|
│ ├── comments.js # Steam-style comment wall (Firestore: comments + stats)
|
||||||
|
│ ├── yuukabot.js # Live bot dashboard (Firestore: sysinfo/server)
|
||||||
|
│ ├── calendar.js # Event calendar (Firestore: calendar_events)
|
||||||
|
│ └── gallery.js # Lightbox + dynamic thumbnail loader
|
||||||
|
├── style/
|
||||||
|
│ ├── styles.css # Global layout, nav bar, base typography
|
||||||
|
│ ├── comments.css # Steam-profile comment UI
|
||||||
|
│ ├── yuukabot.css # Dashboard glassmorphism cards + grid
|
||||||
|
│ ├── calendar.css # Calendar grid, popups, sidebar
|
||||||
|
│ ├── gallery.css # Gallery grid + lightbox
|
||||||
|
│ └── ahmet.css # Bucketlist tab button
|
||||||
|
├── gallery/ # 50 full-quality images + thumbnails/ subdirectory
|
||||||
|
├── textures/ # Background MP4 videos + clickable character PNG
|
||||||
|
├── sounds/ # Click SFX (yuuka_click.mp3)
|
||||||
|
├── generate_thumbnails.py # Pillow script: resizes gallery/ images → thumbnails/
|
||||||
|
└── firebase.txt # Firestore security rules (reference only)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **No frameworks, no build step, no package manager.** Every file is served directly.
|
||||||
|
- Assets are organised by type (images in `gallery/`, videos/PNGs in `textures/`).
|
||||||
|
- Firebase config is duplicated per JS file, each guarding `firebase.initializeApp()` with `if (!firebase.apps.length)` to avoid collisions.
|
||||||
|
|
||||||
|
## Build, Test, and Development Commands
|
||||||
|
|
||||||
|
This is a static site with **no build system**. Run locally with any HTTP server:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Python 3 (recommended)
|
||||||
|
python -m http.server 8080
|
||||||
|
|
||||||
|
# Node.js alternative
|
||||||
|
npx serve .
|
||||||
|
```
|
||||||
|
|
||||||
|
- `_redirects` handles SPA routing on Netlify; for local dev, navigate to `/index.html` directly.
|
||||||
|
- `generate_thumbnails.py` regenerates gallery thumbnails: `python generate_thumbnails.py`. Requires `Pillow`.
|
||||||
|
|
||||||
|
There are **no automated tests** in this project.
|
||||||
|
|
||||||
|
## Coding Style & Naming Conventions
|
||||||
|
|
||||||
|
- **HTML:** Semantic elements where practical. Tab contents use `<section id="…" class="tab-content">`. IDs are kebab-case.
|
||||||
|
- **CSS:** Each tab has its own stylesheet under `style/`. Class names follow BEM-lite (`cal-day`, `dash-card`). CSS variables define layout knobs (`--dash-columns`, `--dash-gap`).
|
||||||
|
- **JavaScript:** Vanilla ES6+, no transpilation. Functions are `camelCase`, DOM-referencing IDs match kebab-case HTML IDs. Each script is self-contained with a `DOMContentLoaded` guard. Firebase config is repeated per-file (same values) — keep this pattern.
|
||||||
|
- **Whitespace:** 4-space indentation in JS/CSS, 2-space in HTML. No trailing semicolons are required but consistency within each file is expected.
|
||||||
|
- No linters or formatters are configured.
|
||||||
|
|
||||||
|
## Commit & Pull Request Guidelines
|
||||||
|
|
||||||
|
Commit history follows an informal style:
|
||||||
|
|
||||||
|
```
|
||||||
|
<verb> <short description>
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples from the repo: `calendar added`, `fix upcoming filter`, `css polish bs`, `tab specific routing added`.
|
||||||
|
|
||||||
|
- Use lowercase, imperative mood.
|
||||||
|
- Keep messages short (under 72 characters).
|
||||||
|
- Group related changes into a single commit where possible.
|
||||||
|
- PRs should include a brief description of what changed and why; screenshots are appreciated for visual/UI changes.
|
||||||
|
|
||||||
|
## Security & Configuration
|
||||||
|
|
||||||
|
- **Firebase API keys** are public by design (they identify the project, not authenticate). Do not commit service-account credentials or `.env` files.
|
||||||
|
- `firebase.txt` is in `.gitignore` — keep the live rules reference there, not hardcoded in source.
|
||||||
|
- All Firestore writes are guarded by security rules (see `firebase.txt`): only `comments` and `stats/global_clicks` accept public writes; everything else is read-only.
|
||||||
|
|
||||||
|
## Adding a New Feature
|
||||||
|
|
||||||
|
1. Add the new `<section class="tab-content" id="…">` in `index.html`.
|
||||||
|
2. Add a `<button id="…-btn">` to the nav bar (`#top-line`).
|
||||||
|
3. Add the tab name to the `valid` array in `js/tabs.js`.
|
||||||
|
4. Create a dedicated stylesheet in `style/` and JS module in `js/` if needed.
|
||||||
|
5. Link both in `index.html` `<head>` (CSS) and before `</body>` (JS).
|
||||||
|
6. If the feature reads/writes Firestore, add the matching security rules to `firebase.txt`.
|
||||||
+9
-4
@@ -8,6 +8,7 @@
|
|||||||
<link rel="stylesheet" href="style/comments.css">
|
<link rel="stylesheet" href="style/comments.css">
|
||||||
<link rel="stylesheet" href="style/yuukabot.css">
|
<link rel="stylesheet" href="style/yuukabot.css">
|
||||||
<link rel="stylesheet" href="style/calendar.css">
|
<link rel="stylesheet" href="style/calendar.css">
|
||||||
|
<link rel="stylesheet" href="style/bucketlist.css">
|
||||||
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
||||||
<title>Esef</title>
|
<title>Esef</title>
|
||||||
</head>
|
</head>
|
||||||
@@ -19,14 +20,14 @@
|
|||||||
<video muted loop playsinline preload="none" id="calendar-background-video" style="display:none">
|
<video muted loop playsinline preload="none" id="calendar-background-video" style="display:none">
|
||||||
<source src="textures/calendar_background.mp4" type="video/mp4">
|
<source src="textures/calendar_background.mp4" type="video/mp4">
|
||||||
</video>
|
</video>
|
||||||
<video muted loop playsinline preload="none" id="czscores-background-video" style="display:none">
|
<video muted loop playsinline preload="none" id="bucketlist-background-video" style="display:none">
|
||||||
<source src="textures/cz_background.mp4" type="video/mp4">
|
<source src="textures/cz_background.mp4" type="video/mp4">
|
||||||
</video>
|
</video>
|
||||||
<div id="top-line">
|
<div id="top-line">
|
||||||
<a href="index.html" id="home-btn"></a>
|
<a href="index.html" id="home-btn"></a>
|
||||||
<button id="about-btn">About This Website</button>
|
<button id="about-btn">About This Website</button>
|
||||||
<button id="gallery-btn">Gallery</button>
|
<button id="gallery-btn">Gallery</button>
|
||||||
<button id="czscores-btn">Cz Scores</button>
|
<button id="bucketlist-btn">Bucketlist</button>
|
||||||
<button id="yuukabot-btn">Bot Status</button>
|
<button id="yuukabot-btn">Bot Status</button>
|
||||||
<button id="calendar-btn">Calendar</button>
|
<button id="calendar-btn">Calendar</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,8 +117,11 @@
|
|||||||
<div id="gallery-container" class="gallery-grid"></div>
|
<div id="gallery-container" class="gallery-grid"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="czscores" class="tab-content">
|
<section id="bucketlist" class="tab-content">
|
||||||
<div id="czscores-container">
|
<div class="bl-panel">
|
||||||
|
<div class="bl-list" id="bl-list">
|
||||||
|
<p class="bl-empty">Loading...</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -221,6 +225,7 @@
|
|||||||
<script src="js/comments.js"></script>
|
<script src="js/comments.js"></script>
|
||||||
<script src="js/yuukabot.js"></script>
|
<script src="js/yuukabot.js"></script>
|
||||||
<script src="js/calendar.js"></script>
|
<script src="js/calendar.js"></script>
|
||||||
|
<script src="js/bucketlist.js"></script>
|
||||||
|
|
||||||
<!-- Lightbox -->
|
<!-- Lightbox -->
|
||||||
<div id="lightbox" class="lightbox">
|
<div id="lightbox" class="lightbox">
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// Bucketlist tab — real-time Firestore list
|
||||||
|
const BL_FB_CONFIG = {
|
||||||
|
apiKey: "AIzaSyDuSjEGEKx5FnWYnQq8f_owbpYRBRrl5x0",
|
||||||
|
authDomain: "esef-514bf.firebaseapp.com",
|
||||||
|
projectId: "esef-514bf",
|
||||||
|
storageBucket: "esef-514bf.firebasestorage.app",
|
||||||
|
messagingSenderId: "353969651290",
|
||||||
|
appId: "1:353969651290:web:41e3aaf8e54c743702a263"
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const tab = document.getElementById("bucketlist");
|
||||||
|
if (!tab) return;
|
||||||
|
|
||||||
|
if (!firebase.apps.length) firebase.initializeApp(BL_FB_CONFIG);
|
||||||
|
const db = firebase.firestore();
|
||||||
|
|
||||||
|
const listEl = document.getElementById("bl-list");
|
||||||
|
if (!listEl) return;
|
||||||
|
|
||||||
|
db.collection("bucketlist_items").onSnapshot(snap => {
|
||||||
|
const items = [];
|
||||||
|
snap.forEach(doc => {
|
||||||
|
const d = doc.data();
|
||||||
|
items.push({
|
||||||
|
id: doc.id,
|
||||||
|
title: d.title || "",
|
||||||
|
description: d.description || "",
|
||||||
|
date: d.date || "",
|
||||||
|
utc: d.utc || "",
|
||||||
|
done: d.done || false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
items.sort((a, b) => (a.utc || "").localeCompare(b.utc || ""));
|
||||||
|
render(items);
|
||||||
|
}, () => {
|
||||||
|
if (listEl) listEl.innerHTML = '<p class="bl-empty">Could not load.</p>';
|
||||||
|
});
|
||||||
|
|
||||||
|
function render(items) {
|
||||||
|
if (items.length === 0) {
|
||||||
|
listEl.innerHTML = '<p class="bl-empty">Nothing here yet.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listEl.innerHTML = items.map(item =>
|
||||||
|
'<div class="bl-item' + (item.done ? ' bl-done' : '') + '">' +
|
||||||
|
'<div class="bl-title">' + esc(item.title) + '</div>' +
|
||||||
|
(item.date ? '<div class="bl-date">' + esc(item.date) + '</div>' : '') +
|
||||||
|
(item.description ? '<div class="bl-desc">' + esc(item.description) + '</div>' : '') +
|
||||||
|
'</div>'
|
||||||
|
).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function esc(s) {
|
||||||
|
if (!s) return "";
|
||||||
|
return String(s).replace(/&/g,"&").replace(/</g,"<")
|
||||||
|
.replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'");
|
||||||
|
}
|
||||||
|
});
|
||||||
+6
-6
@@ -3,14 +3,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const tabs = document.querySelectorAll('.tab-content');
|
const tabs = document.querySelectorAll('.tab-content');
|
||||||
const mainVideo = document.getElementById('background-video');
|
const mainVideo = document.getElementById('background-video');
|
||||||
const calVideo = document.getElementById('calendar-background-video');
|
const calVideo = document.getElementById('calendar-background-video');
|
||||||
const czVideo = document.getElementById('czscores-background-video');
|
const bucketlistVideo = document.getElementById('bucketlist-background-video');
|
||||||
|
|
||||||
// ── Map URL path → tab id ──────────────────────────────
|
// ── Map URL path → tab id ──────────────────────────────
|
||||||
function pathToTab(path) {
|
function pathToTab(path) {
|
||||||
const slug = path.replace(/^\/+|\/+$/g, '') || 'about';
|
const slug = path.replace(/^\/+|\/+$/g, '') || 'about';
|
||||||
const valid = ['about', 'gallery', 'czscores', 'yuukabot', 'calendar'];
|
const valid = ['about', 'gallery', 'bucketlist', 'yuukabot', 'calendar'];
|
||||||
// backward compat: old /ahmet links
|
// backward compat: old /ahmet links
|
||||||
if (slug === 'ahmet') return 'czscores';
|
if (slug === 'ahmet') return 'bucketlist';
|
||||||
return valid.includes(slug) ? slug : 'about';
|
return valid.includes(slug) ? slug : 'about';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,12 +24,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// map tab id → its dedicated video element (null = use main)
|
// map tab id → its dedicated video element (null = use main)
|
||||||
const tabVideos = {
|
const tabVideos = {
|
||||||
calendar: calVideo,
|
calendar: calVideo,
|
||||||
czscores: czVideo
|
bucketlist: bucketlistVideo
|
||||||
};
|
};
|
||||||
|
|
||||||
function setBgForTab(tabId) {
|
function setBgForTab(tabId) {
|
||||||
// Hide + pause ALL videos first
|
// Hide + pause ALL videos first
|
||||||
[mainVideo, calVideo, czVideo].forEach(v => {
|
[mainVideo, calVideo, bucketlistVideo].forEach(v => {
|
||||||
if (v) { v.style.display = 'none'; v.pause(); }
|
if (v) { v.style.display = 'none'; v.pause(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// Top-bar theme toggle
|
// Top-bar theme toggle
|
||||||
if (topLine) {
|
if (topLine) {
|
||||||
topLine.classList.toggle('cal-theme', tabId === 'calendar');
|
topLine.classList.toggle('cal-theme', tabId === 'calendar');
|
||||||
topLine.classList.toggle('czscores-theme', tabId === 'czscores');
|
topLine.classList.toggle('bucketlist-theme', tabId === 'bucketlist');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
/* Cz Scores tab */
|
/* Bucketlist tab */
|
||||||
|
|
||||||
#czscores-btn {
|
#bucketlist-btn {
|
||||||
background-color: aliceblue;
|
background-color: aliceblue;
|
||||||
color: #153dee;
|
color: #153dee;
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/* Bucketlist tab — baked-in left panel, internal scroll only */
|
||||||
|
|
||||||
|
/* ── Lock section to viewport so body never scrolls ────────── */
|
||||||
|
#bucketlist.tab-content {
|
||||||
|
padding: 0;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Panel (framed, no extra space) ────────────────────────── */
|
||||||
|
.bl-panel {
|
||||||
|
width: 420px;
|
||||||
|
height: calc(100vh - 210px);
|
||||||
|
margin: 125px 0 85px 48px;
|
||||||
|
background: rgba(35, 35, 41, 0.6);
|
||||||
|
border: 1px solid rgba(181, 177, 198, 0.18);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 0;
|
||||||
|
color: #F4F2F5;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Scrollable list (fills the frame exactly) ────────────── */
|
||||||
|
.bl-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
padding: 14px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Item card ────────────────────────────────────────────── */
|
||||||
|
.bl-item {
|
||||||
|
padding: 14px 18px;
|
||||||
|
background: rgba(35, 35, 41, 0.75);
|
||||||
|
border: 1px solid rgba(181, 177, 198, 0.08);
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.bl-item:hover {
|
||||||
|
border-color: rgba(184, 68, 87, 0.3);
|
||||||
|
box-shadow: 0 3px 16px rgba(184, 68, 87, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bl-item .bl-title {
|
||||||
|
color: #F4F2F5;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.bl-item .bl-date {
|
||||||
|
color: rgba(244, 242, 245, 0.45);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.bl-item .bl-desc {
|
||||||
|
color: rgba(244, 242, 245, 0.55);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Empty state ─────────────────────────────────────────── */
|
||||||
|
.bl-empty {
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(244, 242, 245, 0.3);
|
||||||
|
padding: 60px 0;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
+3
-3
@@ -18,7 +18,7 @@ html, body {
|
|||||||
}
|
}
|
||||||
#background-video,
|
#background-video,
|
||||||
#calendar-background-video,
|
#calendar-background-video,
|
||||||
#czscores-background-video {
|
#bucketlist-background-video {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0%;
|
right: 0%;
|
||||||
left: 0%;
|
left: 0%;
|
||||||
@@ -76,8 +76,8 @@ html, body {
|
|||||||
transition: border-color 0.4s ease, color 0.4s ease;
|
transition: border-color 0.4s ease, color 0.4s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Cz Scores-themed top bar buttons ─────────────────── */
|
/* ── Bucketlist-themed top bar buttons ─────────────────── */
|
||||||
#top-line.czscores-theme button {
|
#top-line.bucketlist-theme button {
|
||||||
border-bottom-color: #B5B1C6;
|
border-bottom-color: #B5B1C6;
|
||||||
border-left-color: #B5B1C6;
|
border-left-color: #B5B1C6;
|
||||||
border-right-color: #B5B1C6;
|
border-right-color: #B5B1C6;
|
||||||
|
|||||||
Reference in new issue
Block a user