Merge branch 'main' of ssh://gitea.opossum-arcturus.ts.net:10000/CellTech/lms-frontend

This commit is contained in:
Jose Daniel G. Percy 2025-04-08 03:29:41 +08:00
commit cb82f80e8e
7 changed files with 123 additions and 76 deletions

View File

@ -4,6 +4,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LMS Prototype</title> <title>LMS Prototype</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/src/style.css"> <link rel="stylesheet" href="/src/style.css">
</head> </head>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 KiB

BIN
src/assets/images.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -7,7 +7,7 @@ import { createElement } from '../utils/utils';
class WelcomeWidget extends Widget { class WelcomeWidget extends Widget {
render(): HTMLElement { render(): HTMLElement {
const widgetDiv = createElement('div'); const widgetDiv = createElement('div');
widgetDiv.classList.add('widget'); widgetDiv.classList.add('widget', 'welcome-widget');
widgetDiv.innerHTML = ` widgetDiv.innerHTML = `
<div class="widget-header">Welcome to the Dashboard</div> <div class="widget-header">Welcome to the Dashboard</div>
<div class="widget-body"> <div class="widget-body">
@ -21,7 +21,7 @@ class WelcomeWidget extends Widget {
class QuickLinksWidget extends Widget { class QuickLinksWidget extends Widget {
render(): HTMLElement { render(): HTMLElement {
const widgetDiv = createElement('div'); const widgetDiv = createElement('div');
widgetDiv.classList.add('widget'); widgetDiv.classList.add('widget', 'quick-links-widget');
widgetDiv.innerHTML = ` widgetDiv.innerHTML = `
<div class="widget-header">Quick Links</div> <div class="widget-header">Quick Links</div>
<div class="widget-body"> <div class="widget-body">
@ -36,21 +36,20 @@ class QuickLinksWidget extends Widget {
} }
} }
class PlaceholderWidget extends Widget { // Corrected placeholder widget definition class PlaceholderWidget extends Widget {
render(): HTMLElement { render(): HTMLElement {
const div = createElement('div'); const div = createElement('div');
div.classList.add('widget'); div.classList.add('widget', 'placeholder-widget');
div.textContent = 'Placeholder Widget'; div.textContent = 'Placeholder Widget';
return div; return div;
} }
} }
export const renderDashboardPage = () => { export const renderDashboardPage = () => {
const layout = new ThreeColumnLayout(); const layout = new ThreeColumnLayout();
const welcomeWidget = new WelcomeWidget(); const welcomeWidget = new WelcomeWidget();
const quickLinksWidget = new QuickLinksWidget(); const quickLinksWidget = new QuickLinksWidget();
const placeholderWidget = new PlaceholderWidget(); // Use the corrected PlaceholderWidget class const placeholderWidget = new PlaceholderWidget();
layout.setColumn1Content(welcomeWidget.render()); layout.setColumn1Content(welcomeWidget.render());
layout.setColumn2Content(quickLinksWidget.render()); layout.setColumn2Content(quickLinksWidget.render());

View File

@ -1,4 +1,4 @@
/* Global styles */ /* --- Global styles --- */
h1, h1,
h2, h2,
h3, h3,
@ -12,41 +12,44 @@ body {
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
font-family: sans-serif; font-family: 'Roboto', sans-serif;
}
.scrolling-background {
position: fixed;
top: 0;
left: 0;
width: 100%; /* Ensure it covers full width */
height: 100vh; /* Full viewport height */
background-image: url('./assets/bg1.jpg');
background-repeat: repeat-x;
background-size: auto 100%; /* Maintain width and fill height */
animation: scroll-bg 30s linear infinite;
z-index: -2;
} }
@keyframes scroll-bg { @keyframes scroll-bg {
from { from {
background-position: 0 0; background-position: 0 0;
} }
to {
background-position: -100% 0; to {
} background-position: -100% 0;
}
} }
.color-overlay { .color-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background-color: rgba(33, 37, 41, 0.925); background-color: rgba(33, 37, 41, 0.925);
z-index: -1; z-index: -1;
} }
.scrolling-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-image: url('./assets/after-sunset-minimal-4k-zm-3840x2400.jpg');
background-repeat: repeat-x;
background-size: auto 100%;
animation: scroll-bg 30s linear infinite;
z-index: -2;
}
/* --- Widget Styling --- */
.widget { .widget {
border: 1px solid rgb(0, 0, 0, 0.20); border: 1px solid rgb(0, 0, 0, 0.20);
background-color: rgb(31, 35, 39, 0.9); background-color: rgb(31, 35, 39, 0.9);
@ -56,20 +59,18 @@ body {
} }
.widget-header { .widget-header {
font-size: 18px;
margin-bottom: 10px; margin-bottom: 10px;
font-weight: bold; font-weight: bold;
} }
.widget-body {
/* Widget body styles */
}
.icon-widget { .icon-widget {
padding: 10px; padding: 10px;
text-align: center; text-align: center;
} }
/* Layout Specific Styles */ /* --- Layout Specific Styles --- */
.centered-layout { .centered-layout {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -98,7 +99,7 @@ body {
} }
/* Modal Styles */ /* --- Modal Styles --- */
.modal-overlay { .modal-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
@ -125,7 +126,7 @@ body {
/* Maximum width */ /* Maximum width */
} }
/* Responsive adjustments (example) */ /* --- Responsive adjustments (example) --- */
@media (max-width: 768px) { @media (max-width: 768px) {
.three-column-layout { .three-column-layout {
grid-template-columns: 1fr; grid-template-columns: 1fr;
@ -141,4 +142,40 @@ body {
grid-template-columns: 1fr; grid-template-columns: 1fr;
/* Stack even if collapsed */ /* Stack even if collapsed */
} }
}
/* --- Custom styles --- */
.login-container {
background-image: url('./assets/images.jpg');
/* Replace with your logo path */
background-repeat: no-repeat;
background-position: center top;
/* Center the logo at the top */
background-size: 80x 80px;
/* Adjust the size of the logo */
padding-top: 60px;
/* Add padding to create space for the logo */
text-align: center;
/* Center text and form elements */
}
.logo {
display: block;
margin: 0 auto 20px;
/* Center the logo and add space below */
max-width: 100px;
/* Adjust the size as needed */
width: 80px;
/* Set the width of the logo */
height: 80px;
/* Set the height of the logo */
border-radius: 50%;
/* Make the logo circular */
background-image: url('./assets/images.jpg');
/* Replace with your logo path */
background-size: cover;
/* Cover the entire area */
margin: 0 auto 20px;
/* Center the logo and add space below */
} }

View File

@ -11,52 +11,40 @@ export class LoginWidget extends Widget {
render(): HTMLElement { render(): HTMLElement {
this.container.innerHTML = ''; this.container.innerHTML = '';
// Create a logo container
const logoContainer = createElement('div') as HTMLElement;
logoContainer.classList.add('logo'); // Add class for circular logo
this.container.appendChild(logoContainer);
// Create header
const header = createElement('h2'); const header = createElement('h2');
header.classList.add('widget-header'); header.classList.add('widget-header');
header.textContent = 'Login'; header.textContent = 'Login';
this.container.appendChild(header);
// Create form
const form = createElement('form'); const form = createElement('form');
const userIdInputGroup = createElement('div');
userIdInputGroup.classList.add('mb-3');
const userIdLabel = createElement('label') as HTMLLabelElement; // Cast first
userIdLabel.classList.add('form-label');
userIdLabel.htmlFor = 'userId'; // Set htmlFor as property
userIdLabel.textContent = 'Student ID';
const userIdInput = createElement('input') as HTMLInputElement;
userIdInput.type = 'text';
userIdInput.classList.add('form-control');
userIdInput.id = 'userId';
userIdInput.placeholder = '123456';
userIdInputGroup.appendChild(userIdLabel);
userIdInputGroup.appendChild(userIdInput);
const passwordInputGroup = createElement('div'); // User ID input group
passwordInputGroup.classList.add('mb-3'); const userIdInputGroup = this.createInputGroup('userId', 'Student ID', 'text', 'Student ID');
const passwordLabel = createElement('label') as HTMLLabelElement; // Cast first form.appendChild(userIdInputGroup);
passwordLabel.classList.add('form-label');
passwordLabel.htmlFor = 'password'; // Set htmlFor as property
passwordLabel.textContent = 'Password';
const passwordInput = createElement('input') as HTMLInputElement;
passwordInput.type = 'password';
passwordInput.classList.add('form-control');
passwordInput.id = 'password';
passwordInput.placeholder = 'Password';
passwordInputGroup.appendChild(passwordLabel);
passwordInputGroup.appendChild(passwordInput);
// Password input group
const passwordInputGroup = this.createInputGroup('password', 'Password', 'password', 'Password');
form.appendChild(passwordInputGroup);
// Login button
const loginButton = createElement('button'); const loginButton = createElement('button');
loginButton.type = 'submit'; loginButton.type = 'submit';
loginButton.classList.add('btn', 'btn-primary'); loginButton.classList.add('btn', 'btn-primary');
loginButton.textContent = 'Login'; loginButton.textContent = 'Login';
form.appendChild(userIdInputGroup);
form.appendChild(passwordInputGroup);
form.appendChild(loginButton); form.appendChild(loginButton);
// Form submission handler
form.addEventListener('submit', async (event) => { form.addEventListener('submit', async (event) => {
event.preventDefault(); event.preventDefault();
const userId = userIdInput.value; const userId = (userIdInputGroup.querySelector('input') as HTMLInputElement).value;
const password = passwordInput.value; const password = (passwordInputGroup.querySelector('input') as HTMLInputElement).value;
try { try {
const response: ApiResponse<LoginResponseData> = await globalAPI.login({ userId, password }); const response: ApiResponse<LoginResponseData> = await globalAPI.login({ userId, password });
@ -71,8 +59,28 @@ export class LoginWidget extends Widget {
} }
}); });
this.container.appendChild(header);
this.container.appendChild(form); this.container.appendChild(form);
return this.container; return this.container;
} }
private createInputGroup(id: string, labelText: string, inputType: string, placeholder: string): HTMLElement {
const inputGroup = createElement('div');
inputGroup.classList.add('mb-3');
const label = createElement('label') as HTMLLabelElement;
label.classList.add('form-label');
label.htmlFor = id;
label.textContent = labelText;
const input = createElement('input') as HTMLInputElement;
input.type = inputType;
input.classList.add('form-control');
input.id = id;
input.placeholder = placeholder;
inputGroup.appendChild(label);
inputGroup.appendChild(input);
return inputGroup;
}
} }

View File

@ -7,11 +7,11 @@ export class RegisterWidget extends Widget {
constructor(message?: string) { constructor(message?: string) {
super(); super();
this.message = message || "For registration, please contact your department head for further instructions."; this.message = message || "";
} }
render(): HTMLElement { render(): HTMLElement {
this.container.innerHTML = ''; // Clear previous content this.container.innerHTML = '';
const header = createElement('h2'); const header = createElement('h2');
header.classList.add('widget-header'); header.classList.add('widget-header');
@ -24,7 +24,7 @@ export class RegisterWidget extends Widget {
const button = createElement('button'); const button = createElement('button');
button.classList.add('btn', 'btn-secondary'); button.classList.add('btn', 'btn-secondary');
button.textContent = 'Register'; button.textContent = 'Register';
button.disabled = true;
button.addEventListener('click', () => { button.addEventListener('click', () => {
navigateTo('/register'); navigateTo('/register');
}); });
@ -34,4 +34,4 @@ export class RegisterWidget extends Widget {
this.container.appendChild(button); this.container.appendChild(button);
return this.container; return this.container;
} }
} }