# oU1TS Portal Documentation

A centralized hub for UITS students to access resources, projects, and community links. Built with vanilla HTML, CSS, and JavaScript for maximum simplicity and portability.

This project is an Academic Resources Portal called "oU1TS Portal" designed to serve as a centralized hub for UITS students to discover and access academic resources, projects, and community platforms. 
- The portal's primary purpose is to make it easy for students to find study materials, useful tools, course repositories, guidance tutorials, and social groups all in one place through an organized category-based navigation system.
- Students can actively contribute by submitting their own resources via Google Forms, and contributors are recognized in a dedicated "Contributors" section, fostering a culture of collaboration and peer support.
- By integrating authentication (via Supabase with Google OAuth and email options), featured project showcases, and links to various social platforms (Facebook, Telegram, Discord, Reddit, GitHub), the project builds community value and encourages students to participate in creating a productive, student-centered online ecosystem that helps them navigate university life more effectively while showcasing student-made projects and portfolios.

---

## Table of Contents
- [Project Structure](#project-structure)
- [Pages Overview](#pages-overview)
- [Authentication & Starring System](#authentication--starring-system)
- [Supabase Setup Guide](#supabase-setup-guide)
- [Customization Guide](#customization)
- [Google Sheets Integration](#google-sheets-setup)
- [Changelog](#changelog)

---

## Project Structure

```
ou1ts.portal/
├── index.html          # Main portal entry & Single Page Application (SPA) container
├── style.css           # Global unified stylesheet (glassmorphism, animations, responsive rules)
├── script.js           # Core controllers: intro preloader docking, brand typewriter, idle auto-scroll
├── changes.json        # Structured visitor changelog dataset (versioned release notes)
├── service-worker.js   # Service Worker with PWA offline caching & CACHE_NAME version detection
├── manifest.json       # Web App Manifest for mobile installation
├── official.html       # Standalone subview fallback: Official UITS portals
├── materials.html      # Standalone subview fallback: Study resources & Drive links
├── tools.html          # Standalone subview fallback: Student developer utilities
├── community.html      # Standalone subview fallback: Social groups & channels
├── portfolios.html     # Standalone subview fallback: Student portfolios & developer tags
├── courses.html        # Standalone subview fallback: GitHub course repositories
├── guidance.html       # Standalone subview fallback: Student tutorials & guides
├── inspirations.html   # Standalone subview fallback: Inspiring portals
├── contributions.html  # Dynamic contributor showcase integrated with Google Sheets
├── json/               # Curated JSON data source files
│   ├── sync.bat        # 1-Click launcher to sync JSON folder with Supabase
│   ├── capstones.json  # Capstone projects dataset
│   ├── community.json  # Social channels & club links
│   ├── courses.json    # Course repos by semester
│   ├── featured.json   # Featured initiatives showcase
│   ├── guidance.json   # Tips, guides & tutorials
│   ├── inspirations.json # Other academic portals
│   ├── materials.json  # Department resources & links
│   ├── mentors.json    # Student mentors directory
│   ├── official.json   # University portal notices
│   ├── portfolios.json # Student portfolios
│   └── tools.json      # Student developer tools
├── scripts/            # Developer automation & CLI utilities
│   └── sync-database.js # Supabase <-> JSON bidirectional sync engine
├── sync.bat            # Root 1-Click launcher for database synchronization
├── js/                 # Modular JavaScript architecture
│   ├── auth.js             # Authentication logic (Email & Google OAuth)
│   ├── auth-modal.js       # Reusable authentication modal injection
│   ├── changelog-modal.js  # What's New changelog modal controller & SW version watcher
│   ├── cms.js              # Portal Content Management System & Admin Role Delegation controller
│   ├── data-renderer.js    # Universal JSON data fetching & dynamic DOM rendering
│   ├── spa-controller.js   # Single Page Application router & subview transitions
│   ├── stars.js            # Resource starring, upvoting & ranking engine
│   └── supabase-config.js  # Supabase client initializer
├── portfolio-icon/     # Icons and graphic assets
└── doc/
    ├── DOCUMENTATION.md    # Main project technical documentation
    ├── history.md          # Comprehensive developer release history
    └── prompts/            # Full unabridged conversation & plan archives
```

---

## Pages Overview

### Homepage (`index.html`)

The central SPA entry point featuring modern reactive components:

| Component | Description |
|-----------|-------------|
| **Centered Intro Preloader** | Centered brand animation on initial load that smoothly calculates delta vectors to dock directly into `#siteBrand`. |
| **Top-Left Brand & Typewriter** | Clean header branding where subtitles load via character-by-character typewriter animation once preloader docks. |
| **Featured Projects Gallery** | Interactive showcase displaying top-ranked projects with integrated corner badges, auto-rotation, and mobile layout. |
| **Floating Bubbles Canvas** | Dynamic, playful bubble navigation canvas (`#floatingCanvas`) for exploring all portal resource categories. |
| **7-Second Inactivity Scroll** | Automatically glides the page down to the Explore Hub Resources after 7 seconds of idle time (runs once only). |
| **Visitor Changelog Modal** | "What's New" modal triggered automatically when `service-worker.js` cache versions change, with desktop and mobile buttons. |
| **Floating Submit Button** | Glassmorphic floating action button centered at the bottom of the screen linking to the resource submission form. |
| **SPA Subviews** | Seamless in-place views for categories, capstone gallery, mentors directory, and student talent hiring without full reloads. |

**Sidebar Navigation:**
- Collapsible sidebar drawer with quick links to all categories, mentors, and talent directory.
- "Open in App" button and dedicated What's New changelog trigger with a live version badge.

---

### Category Pages

Each category page follows a consistent structure:

```html
<div class="category-page">
    <header class="category-header">
        <!-- Back button, icon, title, and "Add Link" button -->
    </header>
    <div class="project-list">
        <!-- List of .project-item elements -->
    </div>
</div>
```

| Page | Category | Icon | Description |
|------|----------|------|-------------|
| `official.html` | Official UITS | 🌐 Globe | University portals (Student Portal, Library, Notice Board) |
| `materials.html` | Materials | 🎓 Graduation Cap | Google Drive links, study resources, notes |
| `tools.html` | Tools | 📖 Book Open | Student-made tools and utilities |
| `community.html` | Community | 🔗 Share Nodes | Social groups, Facebook groups, Discord servers |
| `portfolios.html` | Portfolios | 👤 User | Student portfolio showcases with **Core Expertise Tags** |
| `courses.html` | Course Repos | 📦 GitHub | GitHub repositories organized by course with dropdown menus |
| `guidance.html` | Guidance | 💡 Lightbulb | Tips, tutorials, and helpful guides |
| `inspirations.html` | Inspirations | ✨ Magic Wand | Portals from other universities (UIU, DIU) |

**Common Features:**
- Back button → returns to `index.html`
- "+ ADD LINK" button → opens Google Form for submissions
- Numbered project items with visit/copy buttons
- Consistent dark theme styling
- **Star button** for each resource (requires login)
- **Login/Logout button** in header
- Resources sorted by star count (most starred first)

> **Note:** `courses.html` uses **per-dropdown ranking** — resources are sorted by stars only within their respective course section, not across the entire page.

---

### Contributors Page (`contributions.html`)

A dynamic page that fetches contributor data from Google Sheets in real-time.

**Features:**
| Feature | Description |
|---------|-------------|
| **Dynamic Data Fetching** | Pulls data from Google Sheets on page load |
| **Contributor Cards** | Displays name, email, department, batch, and resource count |
| **Grouped by Name** | Multiple submissions by the same person are grouped |
| **Sorted by Contributions** | Top contributors appear first |
| **Clickable Cards** | Opens modal popup with resource details |
| **Modal Popup** | Shows all resources submitted by a contributor with title, type, and link |
| **Loading State** | Spinner displayed while fetching data |
| **Empty State** | Shown when no contributions exist |
| **Error State** | Displayed if fetch fails |
| **Recent Submissions** | Sliding panel showing the 10 most recent community contributions |

**Modal Features:**
- Click card to open
- Click ✕, overlay, or press Escape to close
- **Recent Submissions Panel:**
  - Click "Recent Submissions" bell button to open
  - Displays 10 most recent submissions in reverse chronological order
  - Each item shows contributor name, resource title, and type
  - **Clickable Type Badges**: Redirects to the corresponding category page
- **Contact Information Section:**
  - Email (clickable mailto: link with envelope icon)
  - Social Links (clickable if URL, with link icon)
  - Fallback message if no contact info provided
- **Resources Section:**
  - Project Title
  - Project Type (as clickable badge linking to corresponding category page)
  - Project Link (clickable, opens in new tab)

---

### Progressive Web App (PWA)

The portal is a fully functional Progressive Web App, allowing it to be installed on mobile and desktop devices.

| Feature | Description |
|---------|-------------|
| **Installable** | Users can "Add to Home Screen" on Android/iOS via the browser menu |
| **Offline Support** | Core assets are cached for offline access |
| **Notifications** | Browser notifications for new resource submissions on the Contributors page |
| **Theme Sync** | The PWA uses the `#1a1a2e` theme color to match the site's dark mode |
| **Custom Icon** | High-quality portal icon used for app shortcuts and splash screen |

---

## Authentication & Starring System

The portal includes a user authentication system with Supabase that allows students to:
- Register with Student ID (10+ digits), email, and password
- Login/logout across all pages
- Complete Student ID after Google OAuth (mandatory)
- Star resources to show appreciation
- See resources ranked by popularity (star count)

### How It Works

| Component | Description |
|-----------|-------------|
| **Supabase Auth** | Handles user registration, login, and session management |
| **Profiles Table** | Stores user Student ID and email |
| **Stars Table** | Tracks which users starred which resources |
| **Row Level Security** | Ensures users can only modify their own data |

### Authentication Flow

1. User clicks **Login** button (top-right on any page)
2. Modal appears with authentication options:
   - **Google OAuth** (recommended) - One-click sign in, no email verification needed
   - **Email/Password** - Traditional registration with Student ID
3. **Google Login:** Click "Continue with Google" → Select Google account
4. **Required Step:** User must enter Student ID (10+ digits) in the prompt
  - If they do not want to add it, they can choose **Logout**
5. **Register:** Student ID (10+ digits) + Email + Password
6. **Login:** Email + Password
7. On success, user info displayed in header
8. Session persists across pages via Supabase

### Google OAuth (Recommended)

Google OAuth bypasses Supabase's email rate limits and provides a faster login experience.
After OAuth sign-in, users must add their Student ID to complete their profile.

| Benefit | Description |
|---------|-------------|
| **No Email Limits** | No verification emails needed |
| **One-Click Login** | Users sign in with existing Google account |
| **Faster UX** | No password to remember |
| **Secure** | OAuth 2.0 industry standard |

### Starring System

| Feature | Description |
|---------|-------------|
| **Star Button** | Appears on each resource item |
| **Disabled State** | Shown when not logged in (tooltip: "Login to star") |
| **Active State** | Yellow filled star when user has starred |
| **Star Count** | Number displayed next to star icon |
| **Auto-Sort** | Resources sorted by star count (descending) |
| **Per-Dropdown Sort** | `courses.html` sorts within each dropdown section independently |
| **Optimistic UI** | Instant visual feedback, reverts on error |

| File / Folder | Purpose |
|------|--------|
| `js/supabase-config.js` | Supabase client initialization with project URL and anon key |
| `js/auth-modal.js` | Auth Modal module: reusable script to dynamically inject the auth modal HTML template |
| `js/auth.js` | Auth module: register, login, logout, session management, UI updates |
| `js/cms.js` | Content Management System: approvals, central database management, feedback triage, and admin delegation |
| `js/stars.js` | Stars module: toggle stars, load counts, sort resources |
| `js/data-renderer.js` | Universal data renderer: dynamically fetches JSON files and builds DOM components for lists, dropdowns, and featured marquee tracks |
| `json/` | Folder containing structured data (.json files) representing all items/resources on category pages and index marquee |
| `courses.html` (inline) | `CoursesStars` module: per-dropdown star sorting for course repositories |

### Resource ID Format

Each resource has a unique `data-resource-id` attribute:
- Format: `{page}-{identifier}`
- Examples: `community-facebook`, `courses-spl-b1tranger`, `tools-handgesture`

---

## Portal Content Management System (CMS) & Admin Delegation

The oU1TS Portal includes a comprehensive administrative dashboard ([`js/cms.js`](../js/cms.js)) accessible exclusively to designated portal administrators.

### 1. Key Capabilities
- **Submissions & Approvals:** Review student-submitted links, verify metadata, and approve them with one click. Approved resources are automatically slugified and published into `public.portal_resources` under their corresponding category (`materials`, `tools`, `guidance`, `community`, `courses`, `portfolios`, `capstones`, `mentors`, `talent`).
- **Google Sheets / Form Sync:** Live integration with the community contribution sheet (`1oQ5Mkavjm62UGZwNjM-52yvKppWZHfX-Qpq6jtEVIOY`) automatically pulls and categorizes both new resource submissions and student `FEEDBACK` records.
- **Content Manager:** Live catalog browser allowing admins to view, edit, reorder, or directly add new resources across all 10 categories without modifying JSON files.
- **Feedback Inbox:** Triage and track resolutions for bug reports, general suggestions, and user feedback.
- **Admin User Selector Modal:** Existing portal admins can delegate or revoke administrator privileges for any student who has accessed the portal (`'portal' = ANY(project_tags)`). Self-demotion safeguards prevent accidental lockout.

### 2. Designating the Initial Portal Admin
The initial portal admin is designated directly in the central Supabase database:
```sql
UPDATE public.profiles
SET is_portal_admin = true
WHERE email = 'your.email@uits.edu.bd';
```

### 3. Dual-Loading Strategy
- The application automatically queries approved resources from `public.portal_resources` first.
- If offline, unconfigured, or if the database is unreachable, the portal transparently falls back to local `json/*.json` catalogs.
- Institutional inspirations (`json/inspirations.json`) remain manually curated as designed.
- Featured initiatives are ranked automatically using real-time star metrics from `public.resource_star_rankings`.

---

## Supabase Setup Guide

### 1. Create Supabase Account & Project

1. Go to **https://supabase.com** → Click **"Start your project"**
2. Sign up with **GitHub** (recommended)
3. Click **"New Project"** and fill:
   - **Name:** `ou1ts-portal`
   - **Database Password:** (save securely!)
   - **Region:** Singapore (closest to Bangladesh)
4. Wait 2-3 minutes for project creation

### 2. Get API Keys

1. Go to **Settings** (gear icon) → **API**
2. Copy:
   - **Project URL:** `https://xxxxx.supabase.co`
   - **anon public key:** `eyJhbGc...`

### 3. Update Environment Credentials

For local development, copy `env-config.example.js` to `env-config.js` (which is gitignored):

```javascript
window.__ENV = {
    SUPABASE_URL: 'https://<YOUR-PROJECT-ID>.supabase.co',
    SUPABASE_ANON_KEY: '<YOUR-ANON-KEY>'
};
```

For production deployments, inject `SUPABASE_URL` and `SUPABASE_ANON_KEY` as repository secrets in GitHub Actions.

### 4. Create Central Database Tables & Views

In the Supabase SQL Editor on your central project (`oU1TS-Central`), run the unified setup script from [`doc/query/query-4-central-db-portal-stars.sql`](query/query-4-central-db-portal-stars.sql) (see [`doc/db/CENTRAL_DATABASE_SETUP_GUIDE.md`](db/CENTRAL_DATABASE_SETUP_GUIDE.md) for full walkthrough):

```sql
-- 1. Create profiles table (aligned with ou1ts.github.io central schema)
CREATE TABLE IF NOT EXISTS public.profiles (
  id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY,
  email TEXT NOT NULL,
  full_name TEXT,
  student_id TEXT,
  department TEXT,
  batch TEXT,
  blood_group TEXT,
  social_facebook TEXT,
  social_instagram TEXT,
  social_telegram TEXT,
  social_discord TEXT,
  project_tags TEXT[] DEFAULT ARRAY['root']::TEXT[],
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  CONSTRAINT check_student_id_numeric_or_oauth 
    CHECK (student_id ~ '^[0-9]+$' OR student_id = 'OAUTH_USER' OR student_id IS NULL),
  CONSTRAINT check_blood_group_valid 
    CHECK (blood_group IN ('A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-') OR blood_group IS NULL)
);

-- Partial index for student IDs
CREATE UNIQUE INDEX IF NOT EXISTS profiles_student_id_unique
  ON public.profiles (student_id)
  WHERE student_id IS NOT NULL AND student_id <> 'OAUTH_USER';

-- Enable RLS & Policies
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own profile" ON public.profiles FOR SELECT USING (auth.uid() = id);
CREATE POLICY "Users can update own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
CREATE POLICY "Service role can insert profiles" ON public.profiles FOR INSERT WITH CHECK (true);

-- 2. Create stars table for portal resources
CREATE TABLE IF NOT EXISTS public.stars (
  id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  user_id UUID REFERENCES public.profiles(id) ON DELETE CASCADE NOT NULL,
  resource_type TEXT NOT NULL,
  resource_id TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  CONSTRAINT unique_user_resource_star UNIQUE (user_id, resource_type, resource_id)
);

CREATE INDEX IF NOT EXISTS idx_stars_resource ON public.stars(resource_type, resource_id);
CREATE INDEX IF NOT EXISTS idx_stars_user ON public.stars(user_id);

ALTER TABLE public.stars ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can view star counts" ON public.stars FOR SELECT USING (true);
CREATE POLICY "Authenticated users can star" ON public.stars FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can unstar own stars" ON public.stars FOR DELETE USING (auth.uid() = user_id);

-- 3. Star Ranking Analytics View
CREATE OR REPLACE VIEW public.resource_star_rankings AS
SELECT 
  s.resource_type,
  s.resource_id,
  COUNT(*)::INTEGER AS total_stars,
  DENSE_RANK() OVER (PARTITION BY s.resource_type ORDER BY COUNT(*) DESC) AS category_rank,
  DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS global_rank
FROM public.stars s
GROUP BY s.resource_type, s.resource_id;
```

### 5. Configure Authentication URLs

1. Go to **Authentication** → **URL Configuration**
2. Set **Site URL:** `https://ou1ts.github.io/`
3. Add to **Redirect URLs:**
   - `https://ou1ts.github.io/**`
   - `https://ou1ts.github.io/portal/**`
   - `http://localhost:3000/**`
   - `http://127.0.0.1:5500/**`

### 6. Configure Google OAuth

#### Step 1: Google Cloud Console
1. Go to [console.cloud.google.com](https://console.cloud.google.com/)
2. Create a new project or select existing
3. Navigate to **APIs & Services → Credentials**
4. Click **Create Credentials → OAuth client ID**
5. Select **Web application**
6. Add **Authorized redirect URI:**
   ```
   https://YOUR-PROJECT-ID.supabase.co/auth/v1/callback
   ```
7. Copy the **Client ID** and **Client Secret**

#### Step 2: Supabase Configuration
1. Go to **Authentication → Providers → Google**
2. Toggle **Enable** on
3. Paste **Client ID** and **Client Secret**
4. Save

### 7. Troubleshooting OAuth Login Issues

If Google OAuth fails with **"Database error saving new user"**, run the fix scripts in order:

#### Script 1: Core OAuth Fix (`supabase_fix.sql`)
Fixes the trigger to handle OAuth users correctly:
```sql
-- Run this first - updates trigger, makes student_id nullable
ALTER TABLE public.profiles ALTER COLUMN student_id DROP NOT NULL;
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
DROP FUNCTION IF EXISTS public.handle_new_user();
-- ... (see supabase_fix.sql for complete script)
```

#### Script 2: Constraint Fix (`supabase_constraint_fix.sql`)
Fixes "duplicate key value violates unique constraint" error:
```sql
-- Run this if you see duplicate OAUTH_USER errors
ALTER TABLE public.profiles DROP CONSTRAINT IF EXISTS profiles_student_id_key;
CREATE UNIQUE INDEX IF NOT EXISTS profiles_student_id_unique
  ON public.profiles (student_id)
  WHERE student_id IS NOT NULL AND student_id <> 'OAUTH_USER';
```

**Why?** Multiple OAuth users can't all have `student_id = 'OAUTH_USER'` with a UNIQUE constraint. The partial index allows duplicates of 'OAUTH_USER' while keeping real student IDs unique.

### Database Schema

```
profiles
├── id (UUID, PK, FK → auth.users)
├── student_id (TEXT, UNIQUE)
├── email (TEXT)
└── created_at (TIMESTAMPTZ)

stars
├── id (SERIAL, PK)
├── user_id (UUID, FK → profiles)
├── resource_type (TEXT)  -- e.g., 'community', 'tools'
├── resource_id (TEXT)    -- e.g., 'community-facebook'
├── created_at (TIMESTAMPTZ)
└── UNIQUE(user_id, resource_type, resource_id)
```

### 8. Bidirectional Database & JSON Sync Automation

To keep the local catalog files in `json/*.json` and the live Supabase central database (`public.portal_resources`) synchronized without manual database SQL queries:

1. **One-Click Execution**:
   - Double-click [`sync.bat`](../sync.bat) in the project root or [`json/sync.bat`](../json/sync.bat) directly inside the `json/` directory.
   - Or run from terminal:
     ```bash
     node scripts/sync-database.js        # Default Smart Sync: keeps the newest changes
     node scripts/sync-database.js push   # Push local json/ to Supabase
     node scripts/sync-database.js pull   # Pull Supabase to local json/
     ```
2. **Smart Sync Mechanism**:
   - Compares the file modification time (`mtime`) against the highest `updated_at` timestamp in Supabase for each dataset.
   - If local JSON was modified more recently, it automatically pushes and merges the changes to Supabase (`portal_resources`).
   - If Supabase records are newer (e.g. approved submissions from the CMS), it pulls the records and updates the local JSON file.
3. **Credentials**:
   - Reads `SUPABASE_URL`, `SUPABASE_ANON_KEY`, and optional `SUPABASE_SERVICE_ROLE_KEY` from `env-config.js` or `.env`.
   - The public `anon` key is sufficient for pulling data.
   - Pushing data requires the `SUPABASE_SERVICE_ROLE_KEY` (to satisfy RLS policies); the script interactively prompts and offers to save it into `env-config.js` (gitignored) for continuous 1-click operation.

---

## Customization

### Adding New Resources Manually

1. Open the corresponding category page (e.g., `materials.html`)
2. Locate the `.project-list` div
3. Add a new `.project-item` following this structure:

```html
<div class="project-item" data-resource-id="category-unique-id">
    <span class="project-number">01</span>
    <div class="project-icon" style="background: linear-gradient(135deg, #e3f2fd, #bbdefb);">
        <i class="fa-solid fa-icon-name" style="color: #1976d2;"></i>
    </div>
    <div class="project-info">
        <h3>Resource Title</h3>
        <p>https://example.com/</p>
        <div class="expertise-tags">
            <span class="expertise-tag">Core Expertise</span>
        </div>
    </div>
    <div class="project-actions">
        <button class="star-btn disabled" onclick="Stars.toggleStar('category-unique-id')" title="Login to star resources">
            <i class="fa-solid fa-star"></i>
            <span class="star-count">0</span>
        </button>
        <a href="https://example.com/" class="visit-btn" target="_blank">
            Visit <i class="fa-solid fa-arrow-up-right-from-square"></i>
        </a>
        <button class="copy-btn" onclick="copyLink('https://example.com/')">
            <i class="fa-regular fa-copy"></i>
        </button>
    </div>
</div>
```

**Important:** The `data-resource-id` must be unique across the page and match the ID passed to `Stars.toggleStar()`.
```

### Modifying Course Repositories

In `courses.html`, each course uses a dropdown structure with **per-dropdown star sorting** (resources ranked within each section independently):

```html
<div class="course-dropdown">
    <button class="course-header" onclick="toggleDropdown(this)">
        <span><i class="fa-solid fa-code"></i> Course Name (CODE)</span>
        <i class="fa-solid fa-chevron-down"></i>
    </button>
    <div class="course-content">
        <div class="repo-item" data-resource-id="courses-{course}-{author}">
            <i class="fa-brands fa-github"></i>
            <div class="repo-info">
                <a href="https://github.com/..." target="_blank">@author/student-id</a>
                <p>author/repository-name</p>
            </div>
            <button class="star-btn disabled" onclick="Stars.toggleStar('courses-{course}-{author}')" title="Login to star resources">
                <i class="fa-solid fa-star"></i>
                <span class="star-count">0</span>
            </button>
        </div>
    </div>
</div>
```

**Important:** The `CoursesStars` module (inline in `courses.html`) handles starring differently than other pages — it sorts resources only within their parent `.course-content` container, not page-wide.

### Updating Form Links

The Google Form URL appears in multiple places:

| Location | Element |
|----------|---------|
| Homepage hero | `.submit-btn` |
| Category pages | `.add-link-btn` |
| Contributors empty state | `.submit-resource-btn` |

**Current Form URL:** `https://forms.gle/UR1HSavWJYdPBPnC8`

### Styling Customization

The site uses a consistent color scheme defined in `style.css`:

| Color | Usage |
|-------|-------|
| `#1a1a2e` | Primary background |
| `#16213e` | Secondary background |
| `#64b5f6` | Accent blue |
| `#e0e6ed` | Primary text |
| `#a0a0a0` | Secondary text |

---

## Google Sheets Setup

The Contributors page fetches data dynamically from a Google Sheet linked to the submission form.

### How It Works
1. User submits a resource via Google Form
2. Response is automatically saved to Google Sheet
3. Contributors page fetches sheet data via Google Visualization API
4. Data is parsed, grouped by contributor name, and displayed

### Publishing the Sheet (Required)
1. Open the Google Sheet: [Link](https://docs.google.com/spreadsheets/d/1oQ5Mkavjm62UGZwNjM-52yvKppWZHfX-Qpq6jtEVIOY/)
2. Go to **File → Share → Publish to web**
3. Select **"Entire Document"** or the specific sheet tab
4. Click **Publish** and confirm

### Column Mapping (0-indexed)

| Index | Column Name | Used For |
|-------|-------------|----------|
| 0 | Timestamp | Not displayed |
| 1 | Email Address | Not displayed |
| 2 | Student Education Email | Displayed on contributor card & modal |
| 3 | What is this submission for? | Not displayed |
| 4 | Your Name | Contributor name (grouping key) |
| 5 | Contacts and Social Links | Displayed in modal contact section |
| 6 | Project Title | Shown in modal popup |
| 7 | Project Link | Clickable link in modal |
| 8 | Project Type | Badge in modal popup |
| 9 | Department | Shown on contributor card |
| 10 | Batch | Shown on contributor card |

### Modifying Column Indices

Edit the constants at the top of the `<script>` section in `contributions.html`:

```javascript
const COL_EMAIL = 2;           // Student Education Email
const COL_NAME = 4;            // Your Name
const COL_SOCIAL = 5;          // Contacts and Social Links
const COL_PROJECT_TITLE = 6;   // Project Title
const COL_PROJECT_LINK = 7;    // Project Link
const COL_PROJECT_TYPE = 8;    // Project Type
const COL_DEPARTMENT = 9;      // Department
const COL_BATCH = 10;          // Batch
```

### Changing the Google Sheet

To use a different Google Sheet:
1. Get the Sheet ID from the URL: `https://docs.google.com/spreadsheets/d/{SHEET_ID}/edit`
2. Update the `SHEET_ID` constant in `contributions.html`:
```javascript
const SHEET_ID = 'your-new-sheet-id-here';
```

### Troubleshooting

| Issue | Solution |
|-------|----------|
| Loading spinner stuck | Ensure sheet is published to web |
| Error state shown | Check browser console for errors; verify sheet ID |
| Data not updating | Refresh the page; published sheets have slight delay |
| Wrong data displayed | Verify column indices match your form structure |

---

## Changelog

| Version | Feature / Change | Description |
| :--- | :--- | :--- |
| **v3.12** | **Hub Section Spacing Optimization** | Reduced vertical gaps between the Featured Projects gallery, Floating Navigation canvas, and About & Socials section by stripping extraneous break tags and compacting padding and margins. |
| **v3.11** | **Interactive Preloader, Floating Canvas & Gallery Restructure** | Added gliding intro preloader, dynamic typewriter branding, playful floating bubble canvas, structured featured gallery cards, and interactive visitor changelog modal (`changes.json`). |
| **v3.10** | **Course Dropdowns Divider Cleanup** | Removed horizontal divider (`<hr>`) lines below all course dropdowns on `courses.html` except for the 'All Courses' dropdown. |
| **v3.9** | **Dynamic JSON-Driven Rendering** | Replaced static list items on all resource pages and index featured projects marquee with a dynamic fetching loader (`js/data-renderer.js`) pulling data from individual JSON files in `json/`, preserving full Supabase starring compatibility and isolated ranking logic. |
| **v3.8** | **Reusable Auth Modal Script** | Extracted the hardcoded Auth Modal HTML template into a separate reusable `js/auth-modal.js` script dynamically injected across all category pages, index page, and guidance page. |
| **v3.7** | **Inspirations & Style Fixes** | Added `inspirations.html` with project portals from UIU/DIU. Added "All Courses" section to `courses.html`. Fixed scrollbar display and word-wrapping for long links. |
| **v3.6** | **Portfolio Expertise Tags** | Added core expertise tags (e.g., Full Stack, Cybersecurity, Backend) to each entry in `portfolios.html` for better categorization and visibility. |
| **v3.5** | **PWA & Notifications** | Enabled Progressive Web App (PWA) features including offline support, manifest installation, and browser notifications for new submissions. |
| **v3.4** | **Recent Submissions** | Added a sliding panel showing the 10 most recent contributions with clickable category links and smooth animations. Fixed individual contributor modal content. |
| **v3.3** | **Courses Star Fix** | Resolved "Failed to update star" error and consolidated repository items into single containers for proper star-based ranking. |
| **v3.2** | **Google OAuth** | Integrated "Continue with Google" for faster login, avoiding email rate limits. Added Student ID requirement for OAuth users. |
| **v3.1** | **Isolated Rankings** | Implemented per-dropdown star sorting for `courses.html`, ranking resources only within their respective course sections. |
| **v3.0** | **Auth & Starring** | Major update: Supabase integration for Student ID authentication, resource starring, and auto-sorting by popularity. |
| **v2.6** | **Guidance Page** | Added `guidance.html` for tutorials and tips, updated resource mapping. |
| **v2.5** | **Resource Linking** | Connected resource type badges in contributor modals to their respective category pages (e.g., Tools -> `tools.html`). |
| **v2.4** | **Modal Contact Info** | Added clickable contact info (Email/Socials) and department/batch subtitles to contributor modals. |
| **v2.3** | **Enhanced Modal** | Cards now open modals showing all submitted resources for that contributor. |
| **v2.2** | **Dynamic Fetching** | Linked the Contributors page to Google Sheets for real-time data updates from form submissions. |
| **v2.1** | **Contributors Page** | Initial release of the `contributions.html` page to recognize student submitters. |
| **v2.0** | **UIU Restructure** | Complete site redesign: hero section, category cards, featured marquee, and responsive navigation. |




---

## Credits

- **Design Inspiration**: [UIU LinkSphere](https://uiulinks.vercel.app/)
- **Contributors Page Design**: [DIUQBank Contributors](https://diuqbank.com/contributors/)
- **Icons**: [Font Awesome 6.5.0](https://fontawesome.com/)
- **Built by**: oU1TS Initiative - Students of UITS
