Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@
> Instructors can Accept, Reject or Delete workshops based on their preference, also they can postpone a workshop based on coordinators request.

__NOTE__: Check docs/Getting_Started.md for more info.

# Workshop Booking UI/UX Enhancement
By SANSKAR KUMAWAT

:- What I Did? -
- Replaced the old table layout with "modern, dynamic cards" for better readability.
- Added a "hero section" with a clear title and description.
- Made the "booking modal" work with the new card layout.
- Ensured "mobile-friendly design" using CSS media queries.
- Improved "visual hierarchy": highlighted workshop names, duration, and buttons.
- Added subtle "hover effects" for better interactivity.
6 changes: 5 additions & 1 deletion cms/templates/cms_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
{{ page.imports | safe }}
<script src="{% static 'cms/js/bootstrap.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'workshop_app/css/base.css' %}" type="text/css"/>
<link rel="stylesheet" href="{% static 'workshop_app/css/enhanced.css' %}" type="text/css"/>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;800&display=swap" rel="stylesheet">
</head>
<script src="{% static 'workshop_app/js/enhanced.js' %}" defer></script>

<body>

<nav class=" navbar navbar-dark navbar navbar-expand-lg bg-dark fixed-top">
Expand Down Expand Up @@ -56,4 +60,4 @@
{{ page.content | safe }}
</div>
</body>
</html>
</html>
67 changes: 67 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Workshop Booking</title>
<link rel="stylesheet" href="style.css">
<link rel="script" href="script.js">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;800&display=swap" rel="stylesheet">

</head>
<body>

<header class="topbar">
<div class="topbar-inner">
<button class="logo">WorkshopHub</button>
</div>
</header>

<section class="hero">
<div class="hero-inner">
<h1>Discover & Book Workshops</h1>
<p class="muted">Learn new skills, meet great people, grow your career.</p>
</div>
</section>

<main>
<div id="cards" class="cards" role="list">
<!-- Cards will be injected by JS -->
</div>
</main>

<div id="modal" class="modal" aria-hidden="true">
<div class="modal-panel">
<button id="closeModal" class="close">✕</button>
<h2 id="modalTitle">Book workshop</h2>
<form id="bookingForm">
<input type="hidden" id="workshopId">
<label for="name">Full name</label>
<input id="name" name="name" required minlength="3" placeholder="Your full name">

<label for="email">Email</label>
<input id="email" name="email" required type="email" placeholder="you@example.com">

<label for="phone">Phone</label>
<input id="phone" name="phone" required pattern="[0-9]{7,15}" placeholder="10 digit phone">

<label for="college">College / Organisation</label>
<input id="college" name="college" placeholder="Your college (optional)">

<div class="form-actions">
<button type="submit" class="btn primary">Confirm booking</button>
<button type="button" id="cancelBtn" class="btn ghost">Cancel</button>
</div>
</form>
</div>
</div>

<div id="toast" class="toast"></div>

<footer class="site-footer">
<small>Made with ♥ for learners — clean, mobile-first, human-friendly</small>
</footer>

<script src="script.js" defer></script>
</body>
</html>
67 changes: 67 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const modal = document.getElementById('modal');
const modalTitle = document.getElementById('modalTitle');
const bookingForm = document.getElementById('bookingForm');
const toast = document.getElementById('toast');

const workshops = [
{ id: 1, title: "Python Basics", desc: "Learn Python fundamentals", category: "python" },
{ id: 2, title: "Web Development", desc: "Build responsive websites", category: "web" },
{ id: 3, title: "Intro to ML", desc: "Start with Machine Learning", category: "ml" }
];

const cardsRoot = document.getElementById('cards');

function renderCards(list) {
cardsRoot.innerHTML = '';
list.forEach(w => {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<h3>${w.title}</h3>
<p>${w.desc}</p>
<button class="btn primary">Book Now</button>
`;
card.querySelector('button').addEventListener('click', () => openModal(w));
cardsRoot.appendChild(card);
});
}

function openModal(workshop) {
modalTitle.textContent = `Book: ${workshop.title}`;
document.getElementById('workshopId').value = workshop.id;
modal.setAttribute('aria-hidden', 'false');
document.getElementById('name').focus();
}

function closeModal() {
modal.setAttribute('aria-hidden', 'true');
}

document.getElementById('closeModal').addEventListener('click', closeModal);
document.getElementById('cancelBtn').addEventListener('click', closeModal);

bookingForm.addEventListener('submit', e => {
e.preventDefault();
const name = document.getElementById('name').value.trim();
const email = document.getElementById('email').value.trim();
const phone = document.getElementById('phone').value.trim();

if (!name || !email || !phone) {
return showToast('Please fill all required fields');
}

showToast('Booking confirmed!');
closeModal();

const all = JSON.parse(localStorage.getItem('bookings') || '[]');
all.push({ name, email, phone, ts: Date.now() });
localStorage.setItem('bookings', JSON.stringify(all));
});

function showToast(msg) {
toast.textContent = msg;
toast.classList.add('show');
setTimeout(() => toast.classList.remove('show'), 2500);
}

renderCards(workshops);
217 changes: 217 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@


.hero-title {
font-family: 'Montserrat', sans-serif;
font-weight: 800;
font-size: 4rem;
line-height: 1.1;
}

:root {
--bg: #0f1720;
--card: #1a2432;
--muted: #a0a7b3;
--accent: #f79b72;
--radius: 14px;
--maxwidth: 1100px;
--transition: 0.25s ease;
font-family: 'Inter', system-ui, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
background: linear-gradient(180deg, #040404 0%, #8d98b9 100%);
color: #e6eef6;
min-height: 100vh;
display: flex;
flex-direction: column;
}

.topbar {
background: rgba(10, 15, 25, 0.7);
backdrop-filter: blur(6px);
position: sticky;
top: 0;
z-index: 100;
}

.topbar-inner {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 20px;
max-width: var(--maxwidth);
margin: auto;
}

.logo {
font-weight: 700;
font-size: 18px;
background: none;
border: none;
color: #fff;
}

.icon-btn {
background: none;
border: 0;
color: inherit;
font-size: 18px;
cursor: pointer;
}

.hero {
text-align: center;
padding: 40px 16px;
}

.hero h1 {
font-size: 26px;
margin-bottom: 10px;
}

.hero .muted {
color: var(--muted);
}

.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 18px;
padding: 20px;
max-width: var(--maxwidth);
margin: auto;
}

.card {
background: var(--card);
border-radius: var(--radius);
padding: 16px;
display: flex;
flex-direction: column;
justify-content: space-between;
transition: transform var(--transition), box-shadow var(--transition);
}

.card:hover {
transform: translateY(-6px);
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.4);
}

.card h3 { margin-bottom: 8px; }
.card p { color: var(--muted); font-size: 14px; }

.btn {
padding: 10px 14px;
border-radius: 10px;
font-weight: 600;
cursor: pointer;
border: none;
transition: background var(--transition);
}

.btn.primary {
background: linear-gradient(90deg, var(--accent), #ffb88c);
color: #031018;
}

.btn.primary:hover {
filter: brightness(1.05);
}

.btn.ghost {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: #fff;
}

.modal {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.65);
display: none;
align-items: center;
justify-content: center;
}

.modal[aria-hidden="false"] {
display: flex;
animation: fadeIn 0.3s ease;
}

.modal-panel {
background: rgba(30, 40, 60, 0.9);
backdrop-filter: blur(10px);
border-radius: var(--radius);
padding: 24px;
width: 100%;
max-width: 420px;
animation: slideUp 0.35s ease;
}

.modal-panel h2 {
margin-bottom: 16px;
}

.modal-panel label {
display: block;
margin: 12px 0 4px;
font-size: 14px;
color: var(--muted);
}

.modal-panel input {
width: 100%;
padding: 10px;
border-radius: 8px;
border: none;
margin-bottom: 8px;
background: #222c3c;
color: #fff;
}

.close {
background: none;
border: none;
font-size: 20px;
color: #fff;
float: right;
cursor: pointer;
}

.toast {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%) translateY(100px);
background: var(--accent);
color: #031018;
padding: 12px 18px;
border-radius: 8px;
opacity: 0;
transition: all 0.4s ease;
}

.toast.show {
transform: translateX(-50%) translateY(0);
opacity: 1;
}

.site-footer {
text-align: center;
padding: 20px;
margin-top: auto;
font-size: 14px;
color: #040404;
}

@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}

@keyframes slideUp {
from { transform: translateY(40px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
Loading