Merge branch 'main' of ssh://gitea.opossum-arcturus.ts.net:10000/CellTech/lms-frontend
This commit is contained in:
commit
cb82f80e8e
@ -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>
|
||||||
|
|||||||
BIN
src/assets/after-sunset-minimal-4k-zm-3840x2400.jpg
Normal file
BIN
src/assets/after-sunset-minimal-4k-zm-3840x2400.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1011 KiB |
BIN
src/assets/images.jpg
Normal file
BIN
src/assets/images.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@ -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());
|
||||||
|
|||||||
105
src/style.css
105
src/style.css
@ -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 */
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user