diff --git a/my-app/src/App.jsx b/my-app/src/App.jsx
index dd45cca..9b891e3 100644
--- a/my-app/src/App.jsx
+++ b/my-app/src/App.jsx
@@ -2,14 +2,17 @@ import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import AppRoutes from './AppRoutes'; // move the routing and loading logic here
import { SettingsProvider } from './context/SettingsContext';
+import { ThemeProvider } from './context/ThemeContext';
function App() {
return (
-
-
-
-
-
+
+
+
+
+
+
+
);
}
diff --git a/my-app/src/AppRoutes.jsx b/my-app/src/AppRoutes.jsx
index 1879d74..d63ef8d 100644
--- a/my-app/src/AppRoutes.jsx
+++ b/my-app/src/AppRoutes.jsx
@@ -6,6 +6,8 @@ import Layout from './Layout';
import { RoomBooking } from './pages/RoomBooking';
import { NewBooking } from './pages/NewBooking';
import { BookingSettings } from './pages/BookingSettings';
+import { CourseSchedule } from './pages/CourseSchedule';
+import { CourseScheduleView } from './pages/CourseScheduleView';
import { TestSession } from './pages/TestSession';
import FullScreenLoader from './components/FullScreenLoader';
@@ -105,7 +107,7 @@ const AppRoutes = () => {
return (
<>
{/* Pass loading as isVisible to FullScreenLoader */}
- {/**/}
+ {}
@@ -115,6 +117,8 @@ const AppRoutes = () => {
}>
setShowSuccessBanner(false)} onBookingUpdate={updateBooking} onBookingDelete={deleteBooking} showDeleteBanner={showDeleteBanner} lastDeletedBooking={lastDeletedBooking} onDismissDeleteBanner={() => setShowDeleteBanner(false)} />} />
} />
+ } />
+ } />
} />
diff --git a/my-app/src/components/BookingCard.module.css b/my-app/src/components/BookingCard.module.css
index eacd6b3..aa4350c 100644
--- a/my-app/src/components/BookingCard.module.css
+++ b/my-app/src/components/BookingCard.module.css
@@ -1,17 +1,17 @@
.card {
- border: 1px solid #E5E5E5;
- padding: 1.25rem;
+ border: var(--border-width-thin) solid var(--border-light);
+ padding: var(--card-padding);
width: 100%;
- border-radius: 0.5rem;
- background: #fff;
- transition: all 0.2s ease;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ border-radius: var(--border-radius-md);
+ background: var(--bg-primary);
+ transition: var(--transition-medium);
+ box-shadow: var(--shadow-lg);
}
.card:hover {
cursor: pointer;
- border-color: #007AFF;
- box-shadow: 0 4px 16px rgba(0, 122, 255, 0.12);
+ border-color: var(--color-primary);
+ box-shadow: var(--shadow-xl);
transform: translateY(-2px);
}
@@ -28,55 +28,55 @@
.date {
text-transform: uppercase;
- font-size: 0.8rem;
- font-weight: 600;
- color: #999;
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-semibold);
+ color: var(--text-muted);
letter-spacing: 1px;
- margin-bottom: 0.5rem;
+ margin-bottom: var(--spacing-sm);
display: block;
}
.titleRow {
display: flex;
align-items: center;
- gap: 0.75rem;
- margin-bottom: 0.5rem;
+ gap: var(--spacing-md);
+ margin-bottom: var(--spacing-sm);
}
.title {
margin: 0;
- font-size: 1.25rem;
- font-weight: 700;
- color: #333;
+ font-size: var(--font-size-3xl);
+ font-weight: var(--font-weight-bold);
+ color: var(--text-primary);
line-height: 1.3;
}
.room {
- font-weight: 600;
- font-size: 0.875rem;
- padding: 0.375rem 0.75rem;
- border-radius: 1rem;
+ font-weight: var(--font-weight-semibold);
+ font-size: var(--font-size-base);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-lg);
white-space: nowrap;
}
.room-green {
- background: #D4EDDA;
- color: #155724;
+ background: var(--room-green-bg);
+ color: var(--room-green-text);
}
.room-red {
- background: #F8D7DA;
- color: #721C24;
+ background: var(--room-red-bg);
+ color: var(--room-red-text);
}
.room-blue {
- background: #D1ECF1;
- color: #0C5460;
+ background: var(--room-blue-bg);
+ color: var(--room-blue-text);
}
.room-yellow {
- background: #FFF3CD;
- color: #856404;
+ background: var(--room-yellow-bg);
+ color: var(--room-yellow-text);
}
.timeSection {
@@ -91,28 +91,28 @@
.startTime {
font-size: 1.6rem;
- font-weight: 400;
- color: #333;
+ font-weight: var(--font-weight-normal);
+ color: var(--text-primary);
line-height: 1;
}
.endTime {
font-size: 1.6rem;
- font-weight: 400;
- color: #acacac;
+ font-weight: var(--font-weight-normal);
+ color: var(--text-tertiary);
line-height: 1;
}
.participants {
margin: 0;
- font-size: 0.9rem;
- color: #999;
+ font-size: var(--font-size-md);
+ color: var(--text-muted);
}
/* Expanded card styles */
.expanded {
- border-color: #007AFF;
- box-shadow: 0 4px 16px rgba(0, 122, 255, 0.12);
+ border-color: var(--color-primary);
+ box-shadow: var(--shadow-xl);
}
.expanded:hover {
diff --git a/my-app/src/components/BookingDetailsModal.module.css b/my-app/src/components/BookingDetailsModal.module.css
index e1f2ec5..2632e3e 100644
--- a/my-app/src/components/BookingDetailsModal.module.css
+++ b/my-app/src/components/BookingDetailsModal.module.css
@@ -15,7 +15,7 @@
.dialog {
overflow: hidden;
- background: rgba(255, 255, 255, 0.95) !important;
+ background: var(--modal-dialog-bg) !important;
padding: 0;
border-radius: 0.4rem;
}
@@ -32,7 +32,7 @@
margin: 0;
font-size: 1.25rem;
font-weight: 600;
- color: #1f2937;
+ color: var(--text-primary);
flex: 1;
}
@@ -46,7 +46,7 @@
align-items: center;
justify-content: center;
border-radius: 0.25rem;
- color: #6b7280;
+ color: var(--text-secondary);
cursor: pointer;
transition: all 0.2s ease;
flex-shrink: 0;
@@ -54,12 +54,12 @@
}
.closeButton:hover {
- background-color: #f3f4f6;
- color: #374151;
+ background-color: var(--modal-close-hover-bg);
+ color: var(--text-primary);
}
.closeButton:focus {
- outline: 2px solid #2563eb;
+ outline: 2px solid var(--color-primary);
outline-offset: -1px;
}
@@ -75,7 +75,7 @@
.sectionWithTitle label {
font-size: 0.8rem;
- color: #717171;
+ color: var(--text-tertiary);
font-weight: 500;
margin-bottom: 0.25rem;
text-transform: uppercase;
@@ -85,16 +85,16 @@
.sectionWithTitle p {
margin: 0;
font-size: 1rem;
- color: #1f2937;
+ color: var(--text-primary);
font-weight: 500;
}
.timeDisplay {
margin: 1rem 0;
padding: 1rem;
- background-color: #f8f9fa;
+ background-color: var(--modal-display-bg);
border-radius: 8px;
- border: 1px solid #e9ecef;
+ border: 1px solid var(--modal-display-border);
width: fit-content;
margin-left: 0;
}
@@ -114,7 +114,7 @@
.startTime label, .endTime label {
font-size: 0.75rem;
- color: #6c757d;
+ color: var(--text-secondary);
font-weight: 500;
margin-bottom: 0.25rem;
text-transform: uppercase;
@@ -124,20 +124,20 @@
.timeValue {
font-size: 1.5rem;
font-weight: 600;
- color: #212529;
+ color: var(--text-primary);
}
.timeSeparator {
font-size: 1.5rem;
font-weight: 400;
- color: #6c757d;
+ color: var(--text-secondary);
margin: 0 0.5rem;
padding-top: 1.3rem;
}
.roomText {
font-weight: 600 !important;
- color: #059669 !important;
+ color: var(--modal-save-bg) !important;
}
.modalFooter {
@@ -152,74 +152,74 @@
.cancelButton {
flex: 2;
- background-color: white;
+ background-color: var(--modal-cancel-bg);
height: 4rem;
- color: #374151;
+ color: var(--modal-cancel-text);
font-weight: 600;
- border: 2px solid #d1d5db;
+ border: 2px solid var(--modal-cancel-border);
border-radius: 0.5rem;
transition: all 0.2s ease;
cursor: pointer;
}
.cancelButton:hover {
- background-color: #f9fafb;
- border-color: #9ca3af;
+ background-color: var(--modal-cancel-hover-bg);
+ border-color: var(--modal-cancel-hover-border);
}
.cancelButton:active {
- background-color: #e5e7eb;
+ background-color: var(--modal-cancel-active-bg);
transform: translateY(1px);
}
.saveButton {
flex: 3;
- background-color: #059669;
- color: white;
+ background-color: var(--modal-save-bg);
+ color: var(--modal-save-text);
height: 4rem;
font-weight: 600;
font-size: 1.1rem;
- border: 2px solid #047857;
+ border: 2px solid var(--modal-save-border);
border-radius: 0.5rem;
transition: all 0.2s ease;
- box-shadow: 0 2px 4px rgba(5, 150, 105, 0.2);
+ box-shadow: var(--modal-save-shadow);
cursor: pointer;
}
.saveButton:hover {
- background-color: #047857;
- box-shadow: 0 4px 8px rgba(5, 150, 105, 0.3);
+ background-color: var(--modal-save-hover-bg);
+ box-shadow: var(--modal-save-hover-shadow);
}
.saveButton:active {
- background-color: #065f46;
+ background-color: var(--modal-save-active-bg);
transform: translateY(1px);
- box-shadow: 0 1px 2px rgba(5, 150, 105, 0.2);
+ box-shadow: var(--modal-save-active-shadow);
}
.saveButton[data-focused],
.cancelButton[data-focused] {
- outline: 2px solid #2563EB;
+ outline: 2px solid var(--color-primary);
outline-offset: -1px;
}
.disabledButton {
- background-color: #f8f9fa !important;
- color: #adb5bd !important;
- border: 2px dashed #dee2e6 !important;
+ background-color: var(--button-disabled-bg) !important;
+ color: var(--button-disabled-text) !important;
+ border: 2px dashed var(--button-disabled-border) !important;
opacity: 0.6 !important;
box-shadow: none !important;
cursor: default !important;
}
.disabledButton:hover {
- background-color: #f8f9fa !important;
+ background-color: var(--button-disabled-bg) !important;
transform: none !important;
box-shadow: none !important;
}
.disabledButton:active {
- background-color: #f8f9fa !important;
+ background-color: var(--button-disabled-bg) !important;
transform: none !important;
}
diff --git a/my-app/src/components/BookingLengthField.module.css b/my-app/src/components/BookingLengthField.module.css
index c5ad2cc..582ae9e 100644
--- a/my-app/src/components/BookingLengthField.module.css
+++ b/my-app/src/components/BookingLengthField.module.css
@@ -1,6 +1,6 @@
.elementHeading {
margin: 0;
- color: #8E8E8E;
+ color: var(--text-tertiary);
font-size: 0.8rem;
font-style: normal;
font-weight: 520;
diff --git a/my-app/src/components/BookingModal.module.css b/my-app/src/components/BookingModal.module.css
index 285d7a3..6f6e4b1 100644
--- a/my-app/src/components/BookingModal.module.css
+++ b/my-app/src/components/BookingModal.module.css
@@ -9,7 +9,7 @@
.modalFooter {
height: fit-content;
width: 100%;
- color: blue;
+ color: var(--color-primary);
display: flex;
align-items: center;
gap: 1rem;
@@ -21,58 +21,58 @@
.cancelButton {
flex: 2;
- background-color: white;
+ background-color: var(--modal-cancel-bg);
height: 4rem;
- color: #374151;
+ color: var(--modal-cancel-text);
font-weight: 600;
- border: 2px solid #d1d5db;
+ border: 2px solid var(--modal-cancel-border);
border-radius: 0.5rem;
transition: all 0.2s ease;
}
@media (hover: hover) {
.cancelButton:hover {
- background-color: #f9fafb;
- border-color: #9ca3af;
+ background-color: var(--modal-cancel-hover-bg);
+ border-color: var(--modal-cancel-hover-border);
cursor: pointer;
}
}
.saveButton {
flex: 3;
- background-color: #059669;
- color: white;
+ background-color: var(--modal-save-bg);
+ color: var(--modal-save-text);
height: 4rem;
font-weight: 600;
font-size: 1.1rem;
- border: 2px solid #047857;
+ border: 2px solid var(--modal-save-border);
border-radius: 0.5rem;
transition: all 0.2s ease;
- box-shadow: 0 2px 4px rgba(5, 150, 105, 0.2);
+ box-shadow: var(--modal-save-shadow);
}
@media (hover: hover) {
.saveButton:hover {
- background-color: #047857;
- box-shadow: 0 4px 8px rgba(5, 150, 105, 0.3);
+ background-color: var(--modal-save-hover-bg);
+ box-shadow: var(--modal-save-hover-shadow);
cursor: pointer;
}
}
.saveButton:active {
- background-color: #065f46;
+ background-color: var(--modal-save-active-bg);
transform: translateY(1px);
- box-shadow: 0 1px 2px rgba(5, 150, 105, 0.2);
+ box-shadow: var(--modal-save-active-shadow);
}
.saveButton[data-focused],
.cancelButton[data-focused] {
- outline: 2px solid #2563EB;
+ outline: 2px solid var(--color-primary);
outline-offset: -1px;
}
.cancelButton:active {
- background-color: #e5e7eb;
+ background-color: var(--modal-cancel-active-bg);
transform: translateY(1px);
}
@@ -90,7 +90,7 @@
.sectionWithTitle label {
font-size: 0.8rem;
- color: #717171;
+ color: var(--text-tertiary);
}
.sectionWithTitle p {
@@ -98,15 +98,12 @@
}
.modalContainer {
- background-color: white;
+ background-color: var(--modal-bg);
width: 85%;
max-width: 400px;
overflow: hidden;
- border: 1px solid rgba(255, 255, 255, 0.18) !important;
- box-shadow: 0 32px 64px rgba(0, 0, 0, 0.12),
- 0 16px 32px rgba(0, 0, 0, 0.08),
- 0 8px 16px rgba(0, 0, 0, 0.04),
- inset 0 1px 0 rgba(255, 255, 255, 0.15) !important;
+ border: 1px solid var(--modal-border) !important;
+ box-shadow: var(--modal-shadow) !important;
backdrop-filter: blur(20px) saturate(140%) !important;
-webkit-backdrop-filter: blur(20px) saturate(140%) !important;
}
@@ -134,18 +131,18 @@
max-height: calc(100vh - 4rem) !important;
max-width: 90vw !important;
overflow-y: auto !important;
- background: white !important;
+ background: var(--modal-bg) !important;
border-radius: 0.5rem !important;
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important;
+ box-shadow: var(--modal-shadow) !important;
}
/* New time display styles */
.timeDisplay {
margin: 1rem 0;
padding: 1rem;
- background-color: #f8f9fa;
+ background-color: var(--modal-display-bg);
border-radius: 8px;
- border: 1px solid #e9ecef;
+ border: 1px solid var(--modal-display-border);
min-width: 196px;
width: fit-content;
}
@@ -165,7 +162,7 @@
.startTime label, .endTime label {
font-size: 0.75rem;
- color: #6c757d;
+ color: var(--text-secondary);
font-weight: 500;
margin-bottom: 0.25rem;
text-transform: uppercase;
@@ -175,11 +172,11 @@
.timeValue {
font-size: 1.5rem;
font-weight: 600;
- color: #212529;
+ color: var(--text-primary);
}
.timeValue.placeholder {
- color: #adb5bd;
+ color: var(--text-muted);
font-style: italic;
font-size: 1rem;
}
@@ -187,23 +184,23 @@
.timeSeparator {
font-size: 1.5rem;
font-weight: 400;
- color: #6c757d;
+ color: var(--text-secondary);
margin: 0 0.5rem;
padding-top: 1.3rem;
}
/* Disabled button styles */
.disabledButton {
- background-color: #f8f9fa !important;
- color: #adb5bd !important;
- border: 2px dashed #dee2e6 !important;
+ background-color: var(--button-disabled-bg) !important;
+ color: var(--button-disabled-text) !important;
+ border: 2px dashed var(--button-disabled-border) !important;
opacity: 0.6 !important;
box-shadow: none;
}
@media (hover: hover) {
.disabledButton:hover {
- background-color: #f8f9fa !important;
+ background-color: var(--button-disabled-bg) !important;
transform: none !important;
box-shadow: none;
cursor: default;
@@ -211,6 +208,6 @@
}
.disabledButton:active {
- background-color: #f8f9fa !important;
+ background-color: var(--button-disabled-bg) !important;
transform: none !important;
}
\ No newline at end of file
diff --git a/my-app/src/components/BookingTitleField.module.css b/my-app/src/components/BookingTitleField.module.css
index fb75a3b..d0c5d78 100644
--- a/my-app/src/components/BookingTitleField.module.css
+++ b/my-app/src/components/BookingTitleField.module.css
@@ -1,10 +1,11 @@
.textInput {
width: 100%;
margin-bottom: 10px;
- border: 1px solid #D2D9E0;
+ border: 1px solid var(--input-border);
border-radius: 0.5rem;
font-size: 16px;
- background-color: #FAFBFC;
+ background-color: var(--input-bg);
+ color: var(--input-text);
padding: 1rem;
width: 100%;
max-width: 600px;
@@ -12,12 +13,12 @@
}
.textInput::placeholder {
- color: #adadad;
+ color: var(--input-placeholder);
}
.elementHeading {
margin: 0;
- color: #8E8E8E;
+ color: var(--text-tertiary);
font-size: 0.8rem;
font-style: normal;
font-weight: 520;
@@ -29,7 +30,7 @@
/* Compact styles */
.compactElementHeading {
font-size: 0.75rem;
- color: #717171;
+ color: var(--text-tertiary);
font-weight: 500;
margin-bottom: 0.4rem;
margin-top: 0;
@@ -40,10 +41,11 @@
.compactTextInput {
width: 100%;
padding: 0.5rem 1rem;
- border: 1px solid #ccc;
+ border: 1px solid var(--input-border);
border-radius: 0.375rem;
font-size: 16px;
- background-color: white;
+ background-color: var(--input-bg);
+ color: var(--input-text);
font-family: inherit;
transition: border-color 0.2s ease;
box-sizing: border-box;
@@ -51,7 +53,7 @@
}
.compactTextInput:focus {
- outline: 2px solid #007AFF;
+ outline: 2px solid var(--color-primary);
outline-offset: 2px;
- border-color: #007AFF;
+ border-color: var(--color-primary);
}
\ No newline at end of file
diff --git a/my-app/src/components/BookingsList.module.css b/my-app/src/components/BookingsList.module.css
index de5ba1a..7910180 100644
--- a/my-app/src/components/BookingsList.module.css
+++ b/my-app/src/components/BookingsList.module.css
@@ -1,6 +1,5 @@
.bookingsListContainer {
- /*border-top: 1px solid gray;*/
- padding-bottom: 2rem;
+ padding-bottom: var(--spacing-3xl);
display: flex;
flex-direction: column;
}
@@ -8,45 +7,45 @@
.bookingsContainer {
display: flex;
flex-direction: column;
- gap: 0.5rem;
+ gap: var(--spacing-sm);
}
.message {
font-style: italic;
- color: #838383;
+ color: var(--text-secondary);
margin: 0;
}
.heading {
margin: 0;
- margin-bottom: 0.5rem;
+ margin-bottom: var(--spacing-sm);
}
.showMoreButton {
- background: #ffffff;
+ background: var(--button-secondary-bg);
border: none;
- border-radius: 0.75rem;
- padding: 1rem;
- font-size: 1rem;
- font-weight: 600;
- color: rgb(0, 0, 0);
+ border-radius: var(--border-radius-lg);
+ padding: var(--spacing-lg);
+ font-size: var(--font-size-xl);
+ font-weight: var(--font-weight-semibold);
+ color: var(--button-secondary-text);
cursor: pointer;
- transition: all 0.2s ease;
- margin-top: 1rem;
+ transition: var(--transition-medium);
+ margin-top: var(--spacing-lg);
width: 100%;
max-width: 100%;
- box-shadow: 0 2px 8px rgba(143, 143, 143, 0.2);
+ box-shadow: var(--button-secondary-shadow);
display: flex;
align-items: center;
justify-content: center;
- gap: 0.5rem;
+ gap: var(--spacing-sm);
box-sizing: border-box;
}
.showMoreButton:hover {
- background: #f2f6ff;
+ background: var(--button-secondary-hover-bg);
transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(192, 192, 192, 0.3);
+ box-shadow: var(--button-secondary-hover-shadow);
}
.showMoreButton:active {
diff --git a/my-app/src/components/Dropdown.module.css b/my-app/src/components/Dropdown.module.css
index 4b44050..c6e24f7 100644
--- a/my-app/src/components/Dropdown.module.css
+++ b/my-app/src/components/Dropdown.module.css
@@ -10,10 +10,10 @@
appearance: none;
-webkit-appearance: none;
padding: 0.5rem 2.5rem 0.5rem 1rem; /* More room on right for chevron */
- border: 1px solid #ccc;
+ border: 1px solid var(--input-border);
border-radius: 0.375rem;
- background-color: white;
- color: #333;
+ background-color: var(--input-bg);
+ color: var(--input-text);
cursor: pointer;
font-size: 1rem;
width: 100%;
@@ -27,7 +27,7 @@
top: 50%;
right: 1rem;
transform: translateY(-50%);
- color: #888;
+ color: var(--dropdown-chevron-color);
font-size: 0.8rem;
z-index: 1;
}
diff --git a/my-app/src/components/Header.jsx b/my-app/src/components/Header.jsx
index b96f4e0..e65c89e 100644
--- a/my-app/src/components/Header.jsx
+++ b/my-app/src/components/Header.jsx
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import styles from './Header.module.css'; // Import the CSS Module
import { Link } from 'react-router-dom';
+import { ThemeToggle } from './ThemeToggle';
const Header = () => {
const [menuOpen, setMenuOpen] = useState(false);
@@ -23,14 +24,18 @@ const Header = () => {
Studentportalen
-
- {/* Simple menu icon, you can replace it with an icon from a library */}
- ☰
+
+
+
+ {/* Simple menu icon, you can replace it with an icon from a library */}
+ ☰
+
{menuOpen && (
{/* Menu items */}
Lokalbokning
+ Schema
Booking Settings
)}
diff --git a/my-app/src/components/Header.module.css b/my-app/src/components/Header.module.css
index 03a4499..f8032ff 100644
--- a/my-app/src/components/Header.module.css
+++ b/my-app/src/components/Header.module.css
@@ -2,45 +2,68 @@
display: flex;
justify-content: space-between;
align-items: center;
- padding: 10px 20px;
- background-color: #f8f8f8;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- position: fixed; /* Make the header sticky */
- top: 0; /* Stick to the top */
- width: 100%; /* Full width */
- z-index: 1000; /* Ensure it stays on top of other content */
+ padding: var(--spacing-sm) var(--spacing-xl);
+ background-color: var(--bg-secondary);
+ box-shadow: var(--shadow-md);
+ position: fixed;
+ top: 0;
+ width: 100%;
+ z-index: var(--z-header);
+}
+
+.left {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-lg);
+ font-weight: var(--font-weight-semibold);
+ color: var(--text-primary);
+}
+
+.right {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-lg);
}
.logo img {
height: 40px; /* Adjust the height as needed */
+ transition: filter 0.2s ease;
}
.menuIcon {
font-size: 24px;
cursor: pointer;
+ color: var(--text-primary);
+ padding: var(--spacing-xs);
+ border-radius: var(--border-radius-md);
+ transition: var(--transition-fast);
+}
+
+.menuIcon:hover {
+ background-color: var(--bg-muted);
}
.menu {
position: absolute;
- top: 60px; /* Position below the header */
- right: 20px;
- background-color: white;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
- padding: 10px;
- border-radius: 5px;
+ top: var(--header-height);
+ right: var(--spacing-xl);
+ background-color: var(--bg-primary);
+ box-shadow: var(--shadow-lg);
+ padding: var(--spacing-sm);
+ border-radius: var(--border-radius-md);
display: flex;
flex-direction: column;
- gap: 10px;
+ gap: var(--spacing-sm);
}
.menu a {
text-decoration: none;
- color: #333;
- padding: 5px 10px;
+ color: var(--text-primary);
+ padding: var(--spacing-xs) var(--spacing-sm);
}
.menu a:hover {
- background-color: #f0f0f0;
+ background-color: var(--bg-muted);
}
/* Responsive design for larger screens */
@@ -70,5 +93,10 @@ body {
flex-direction: row;
align-items: center;
gap: 1rem;
- color: #002E5F;
+ color: var(--header-brand-color);
+}
+
+/* Dark mode logo filter */
+:global([data-theme="dark"]) .logo img {
+ filter: brightness(0) saturate(100%) invert(1);
}
\ No newline at end of file
diff --git a/my-app/src/components/NotificationBanner.module.css b/my-app/src/components/NotificationBanner.module.css
index c60b351..8c0a952 100644
--- a/my-app/src/components/NotificationBanner.module.css
+++ b/my-app/src/components/NotificationBanner.module.css
@@ -1,18 +1,18 @@
/* Base banner styles */
.banner {
- border-radius: 0.75rem;
- padding: 1rem 1.25rem;
- margin-bottom: 1.5rem;
+ border-radius: var(--border-radius-lg);
+ padding: var(--spacing-lg) var(--spacing-xl);
+ margin-bottom: var(--spacing-2xl);
display: flex;
align-items: center;
justify-content: space-between;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ box-shadow: var(--shadow-lg);
}
.bannerContent {
display: flex;
align-items: center;
- gap: 1rem;
+ gap: var(--spacing-lg);
}
.icon {
@@ -22,114 +22,114 @@
display: flex;
align-items: center;
justify-content: center;
- font-weight: bold;
- font-size: 1rem;
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size-xl);
flex-shrink: 0;
}
.text {
display: flex;
flex-direction: column;
- gap: 0.25rem;
+ gap: var(--spacing-xs);
}
.titleRow {
display: flex;
align-items: center;
- gap: 0.5rem;
+ gap: var(--spacing-sm);
}
.title {
- font-weight: 700;
- font-size: 1.1rem;
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size-2xl);
}
.details {
- font-weight: 500;
- font-size: 0.9rem;
+ font-weight: var(--font-weight-medium);
+ font-size: var(--font-size-md);
}
.bookingTitle {
- font-weight: 400;
+ font-weight: var(--font-weight-normal);
}
.closeButton {
background: none;
border: none;
- color: #6C757D;
+ color: var(--notification-close-button);
font-size: 1.5rem;
- font-weight: 300;
+ font-weight: var(--font-weight-light);
cursor: pointer;
- padding: 0.25rem 0.5rem;
- border-radius: 0.375rem;
- transition: all 0.2s ease;
+ padding: var(--spacing-xs) var(--spacing-sm);
+ border-radius: var(--border-radius-md);
+ transition: var(--transition-medium);
line-height: 1;
flex-shrink: 0;
width: fit-content;
}
.closeButton:hover {
- background: rgba(108, 117, 125, 0.1);
- color: #495057;
+ background: var(--notification-close-button-bg-hover);
+ color: var(--notification-close-button-hover);
}
/* Success variant styles */
.success {
- background: #E8F5E8;
- border: 1px solid #4CAF50;
+ background: var(--notification-success-bg);
+ border: var(--border-width-thin) solid var(--notification-success-border);
}
.successIcon {
- background: #4CAF50;
- color: white;
+ background: var(--notification-success-icon-bg);
+ color: var(--notification-success-icon-text);
}
.successTitle {
- color: #2E7D32;
+ color: var(--notification-success-title);
}
.successDetails {
- color: #388E3C;
+ color: var(--notification-success-details);
}
/* Delete variant styles */
.delete {
- background: #FFF4F4;
- border: 1px solid #F87171;
+ background: var(--notification-error-bg);
+ border: var(--border-width-thin) solid var(--notification-error-border);
}
.deleteIcon {
- background: #EF4444;
- color: white;
+ background: var(--notification-error-icon-bg);
+ color: var(--notification-error-icon-text);
}
.deleteTitle {
- color: #DC2626;
+ color: var(--notification-error-title);
}
.deleteDetails {
- color: #EF4444;
+ color: var(--notification-error-details);
}
/* Development variant styles */
.development {
- background: #FFF8E1;
- border: 1px solid #FFB74D;
+ background: var(--notification-warning-bg);
+ border: var(--border-width-thin) solid var(--notification-warning-border);
}
.developmentIcon {
font-size: 1.5rem;
- color: #FF9800;
+ color: var(--notification-warning-icon);
}
/* Test label styles */
.testLabel {
- background: #FF9800;
- color: white;
- font-size: 0.7rem;
- font-weight: 700;
+ background: var(--notification-warning-icon);
+ color: var(--color-white);
+ font-size: var(--font-size-xs);
+ font-weight: var(--font-weight-bold);
padding: 0.2rem 0.4rem;
- border-radius: 0.25rem;
+ border-radius: var(--border-radius-sm);
text-transform: uppercase;
letter-spacing: 0.5px;
}
@@ -143,15 +143,15 @@
position: absolute;
top: 100%;
right: 0;
- margin-top: 0.5rem;
- background: #333;
- color: white;
- padding: 0.75rem 1rem;
- border-radius: 0.375rem;
- font-size: 0.875rem;
+ margin-top: var(--spacing-sm);
+ background: var(--tooltip-bg);
+ color: var(--tooltip-text);
+ padding: var(--spacing-md) var(--spacing-lg);
+ border-radius: var(--border-radius-md);
+ font-size: var(--font-size-base);
white-space: nowrap;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- z-index: 10;
+ box-shadow: var(--shadow-xl);
+ z-index: var(--z-dropdown);
animation: fadeIn 0.2s ease-out;
}
@@ -159,10 +159,10 @@
content: '';
position: absolute;
bottom: 100%;
- right: 1rem;
+ right: var(--spacing-lg);
border-left: 6px solid transparent;
border-right: 6px solid transparent;
- border-bottom: 6px solid #333;
+ border-bottom: 6px solid var(--tooltip-bg);
}
@keyframes fadeIn {
diff --git a/my-app/src/components/ParticipantsSelector.module.css b/my-app/src/components/ParticipantsSelector.module.css
index 80c0487..ce1fc9a 100644
--- a/my-app/src/components/ParticipantsSelector.module.css
+++ b/my-app/src/components/ParticipantsSelector.module.css
@@ -4,7 +4,7 @@
.elementHeading {
margin: 0;
- color: #8E8E8E;
+ color: var(--text-tertiary);
font-size: 0.8rem;
font-style: normal;
font-weight: 520;
@@ -24,15 +24,15 @@
.participantChip {
display: flex;
align-items: center;
- background-color: #F0F8FF;
- border: 1px solid #D1E7FF;
+ background-color: var(--chip-bg);
+ border: 1px solid var(--chip-border);
border-radius: 1.25rem;
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
- color: #2563EB;
+ color: var(--chip-text);
gap: 0.5rem;
transition: all 0.2s ease;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: var(--chip-shadow);
}
@@ -48,38 +48,38 @@
}
.clickableChip:hover {
- background-color: #E0F2FE;
- border-color: #BAE6FD;
+ background-color: var(--chip-hover-bg);
+ border-color: var(--chip-hover-border);
}
.clickableChip:focus {
- outline: 2px solid #2563EB;
+ outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
.clickableChip:active {
- background-color: #BFDBFE;
+ background-color: var(--chip-active-bg);
transform: scale(0.98);
}
.removeIcon {
- color: #2563EB;
+ color: var(--chip-text);
font-size: 0.875rem;
font-weight: bold;
margin-left: 0.25rem;
}
.defaultUserChip {
- background-color: #F3F4F6;
- border-color: #D1D5DB;
- color: #374151;
+ background-color: var(--chip-default-bg);
+ border-color: var(--chip-default-border);
+ color: var(--chip-default-text);
}
.defaultUserChip:hover {
- background-color: #F3F4F6;
- border-color: #D1D5DB;
- color: #374151;
+ background-color: var(--chip-default-bg);
+ border-color: var(--chip-default-border);
+ color: var(--chip-default-text);
cursor: default;
}
@@ -93,23 +93,24 @@
.searchInput {
width: 100%;
margin-bottom: 10px;
- border: 1px solid #D2D9E0;
+ border: 1px solid var(--input-border);
border-radius: 0.5rem;
font-size: 16px;
- background-color: #FAFBFC;
+ background-color: var(--input-bg);
+ color: var(--input-text);
padding: 1rem;
font-family: inherit;
box-sizing: border-box;
}
.searchInput::placeholder {
- color: #adadad;
+ color: var(--input-placeholder);
}
.searchInput:focus {
- outline: 2px solid #2563EB;
+ outline: 2px solid var(--color-primary);
outline-offset: -1px;
- border-color: #2563EB;
+ border-color: var(--color-primary);
}
.dropdown {
@@ -117,10 +118,10 @@
top: 100%;
left: 0;
right: 0;
- background: white;
- border: 1px solid #D2D9E0;
+ background: var(--dropdown-bg);
+ border: 1px solid var(--dropdown-border);
border-radius: 0.5rem;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
+ box-shadow: var(--dropdown-shadow);
z-index: 1000;
max-height: 300px;
overflow-y: auto;
@@ -132,12 +133,12 @@
}
.section:not(:last-child) {
- border-bottom: 1px solid #F1F3F4;
+ border-bottom: 1px solid var(--dropdown-divider);
}
.sectionHeader {
font-weight: 600;
- color: #5F6368;
+ color: var(--text-tertiary);
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.5px;
@@ -150,8 +151,9 @@
cursor: pointer;
transition: background-color 0.2s;
border: none;
- border-bottom: 1px solid #F1F3F4;
+ border-bottom: 1px solid var(--dropdown-divider);
background: none;
+ color: var(--text-primary);
width: 100%;
text-align: left;
font-family: inherit;
@@ -165,11 +167,11 @@
}
.dropdownItem:hover {
- background-color: #F8F9FA;
+ background-color: var(--dropdown-hover-bg);
}
.dropdownItem:active {
- background-color: #E8F0FE;
+ background-color: var(--dropdown-active-bg);
}
.personAvatar {
@@ -190,8 +192,8 @@
width: 100%;
height: 100%;
border-radius: 50%;
- background-color: #2563EB;
- color: white;
+ background-color: var(--color-primary);
+ color: var(--color-white);
display: flex;
align-items: center;
justify-content: center;
@@ -208,7 +210,7 @@
.personName {
font-weight: 500;
- color: #202124;
+ color: var(--text-primary);
font-size: 0.875rem;
display: flex;
align-items: center;
@@ -217,11 +219,11 @@
.personUsername {
font-size: 0.75rem;
- color: #5F6368;
+ color: var(--text-secondary);
}
.addNewItem {
- color: #1A73E8;
+ color: var(--color-primary);
font-weight: 500;
opacity: 0.5;
cursor: not-allowed;
@@ -232,46 +234,46 @@
}
.selectedItem {
- background-color: #F0F8FF;
+ background-color: var(--dropdown-selected-bg);
opacity: 0.7;
}
.selectedItem:hover {
- background-color: #E0F2FE;
+ background-color: var(--dropdown-selected-hover-bg);
}
.selectedIndicator {
- color: #2563EB;
+ color: var(--color-primary);
font-weight: bold;
margin-left: 0.5rem;
}
.focusedItem {
- background-color: #2563EB !important;
- color: white !important;
+ background-color: var(--color-primary) !important;
+ color: var(--color-white) !important;
}
.focusedItem .personName {
- color: white !important;
+ color: var(--color-white) !important;
}
.focusedItem .personUsername {
- color: rgba(255, 255, 255, 0.8) !important;
+ color: var(--color-white-transparent) !important;
}
.focusedItem .selectedIndicator {
- color: white !important;
+ color: var(--color-white) !important;
}
.focusedItem .avatarInitials {
- background-color: rgba(255, 255, 255, 0.2);
- color: white;
+ background-color: var(--color-white-transparent-low);
+ color: var(--color-white);
}
.noResults {
padding: 1rem;
text-align: center;
- color: #5F6368;
+ color: var(--text-secondary);
font-size: 0.875rem;
font-style: italic;
}
@@ -283,7 +285,7 @@
.compactElementHeading {
font-size: 0.75rem;
- color: #717171;
+ color: var(--text-tertiary);
font-weight: 500;
margin-bottom: 0.4rem;
margin-top: 0;
@@ -294,17 +296,18 @@
.compactSearchInput {
width: 100%;
padding: 0.5rem 1rem;
- border: 1px solid #ccc;
+ border: 1px solid var(--input-border);
border-radius: 0.375rem;
font-size: 16px;
- background-color: white;
+ background-color: var(--input-bg);
+ color: var(--input-text);
font-family: inherit;
transition: border-color 0.2s ease;
box-sizing: border-box;
}
.compactSearchInput:focus {
- outline: 2px solid #007AFF;
+ outline: 2px solid var(--color-primary);
outline-offset: 2px;
- border-color: #007AFF;
+ border-color: var(--color-primary);
}
\ No newline at end of file
diff --git a/my-app/src/components/RoomSelectionField.module.css b/my-app/src/components/RoomSelectionField.module.css
index c5ad2cc..582ae9e 100644
--- a/my-app/src/components/RoomSelectionField.module.css
+++ b/my-app/src/components/RoomSelectionField.module.css
@@ -1,6 +1,6 @@
.elementHeading {
margin: 0;
- color: #8E8E8E;
+ color: var(--text-tertiary);
font-size: 0.8rem;
font-style: normal;
font-weight: 520;
diff --git a/my-app/src/components/ThemeToggle.jsx b/my-app/src/components/ThemeToggle.jsx
new file mode 100644
index 0000000..3d6ed5a
--- /dev/null
+++ b/my-app/src/components/ThemeToggle.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { useTheme } from '../context/ThemeContext';
+import styles from './ThemeToggle.module.css';
+
+export const ThemeToggle = () => {
+ const { isDarkMode, toggleTheme } = useTheme();
+
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/my-app/src/components/ThemeToggle.module.css b/my-app/src/components/ThemeToggle.module.css
new file mode 100644
index 0000000..c361983
--- /dev/null
+++ b/my-app/src/components/ThemeToggle.module.css
@@ -0,0 +1,107 @@
+.toggleButton {
+ background: none;
+ border: none;
+ cursor: pointer;
+ padding: var(--spacing-xs);
+ border-radius: var(--border-radius-md);
+ transition: var(--transition-fast);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ -webkit-tap-highlight-color: transparent;
+}
+
+.toggleButton:hover {
+ background-color: var(--bg-muted);
+}
+
+.toggleContainer {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.toggle {
+ width: 44px;
+ height: 24px;
+ border-radius: 12px;
+ position: relative;
+ transition: var(--transition-medium);
+ border: 1px solid var(--border-medium);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+
+.toggle.light {
+ background: linear-gradient(to bottom, #ffffff, #f0f0f0);
+}
+
+.toggle.dark {
+ background: linear-gradient(to bottom, #4a4a4a, #2a2a2a);
+}
+
+.toggleHandle {
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ background: linear-gradient(to bottom, #ffffff, #e0e0e0);
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ transition: var(--transition-medium);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+}
+
+.toggle.light .toggleHandle {
+ left: 2px;
+ background: linear-gradient(to bottom, #ffd700, #ffed4a);
+ border-color: rgba(255, 165, 0, 0.3);
+}
+
+.toggle.dark .toggleHandle {
+ left: calc(100% - 20px);
+ background: linear-gradient(to bottom, #e6e6e6, #cccccc);
+ border-color: rgba(0, 0, 0, 0.2);
+}
+
+.toggleLabel {
+ font-size: var(--font-size-lg);
+ line-height: 1;
+ user-select: none;
+ min-width: 20px;
+ text-align: center;
+}
+
+/* iPhone-style pressed state */
+.toggleButton:active .toggle {
+ transform: scale(0.95);
+}
+
+.toggleButton:active .toggleHandle {
+ width: 20px;
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .toggleContainer {
+ gap: var(--spacing-xs);
+ }
+
+ .toggle {
+ width: 40px;
+ height: 22px;
+ }
+
+ .toggleHandle {
+ width: 16px;
+ height: 16px;
+ }
+
+ .toggle.dark .toggleHandle {
+ left: calc(100% - 18px);
+ }
+
+ .toggleLabel {
+ font-size: var(--font-size-md);
+ }
+}
\ No newline at end of file
diff --git a/my-app/src/components/TimeCard.module.css b/my-app/src/components/TimeCard.module.css
index 98f4a06..e529c49 100644
--- a/my-app/src/components/TimeCard.module.css
+++ b/my-app/src/components/TimeCard.module.css
@@ -3,14 +3,15 @@
.container {
display: flex;
flex-direction: row;
- border: 1px solid #CECECE;
+ border: 1px solid var(--timecard-border);
min-width: 90px;
gap: 1rem;
padding: 1rem;
align-items: center;
justify-content: space-between;
border-radius: 6px;
- background-color: #F8FBFC;
+ background-color: var(--timecard-bg);
+ color: var(--timecard-text);
width: 135px;
height: 20px;
transition: all 0.15s ease;
@@ -18,36 +19,36 @@
@media (hover: hover) {
.container:hover {
- background-color: #E5E5E5;
+ background-color: var(--timecard-hover-bg);
}
}
.container:active,
.container[data-pressed] {
- background-color: #D1D5DB;
+ background-color: var(--timecard-active-bg);
transform: translateY(1px);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+ box-shadow: var(--timecard-active-shadow);
transition: all 0.1s ease;
}
.container[data-focus-visible] {
- outline: 2px solid #2563EB;
+ outline: 2px solid var(--color-primary);
outline-offset: -1px;
}
.selected {
- background-color: #2563EB !important;
- color: white !important;
- border-color: #1d4ed8 !important;
- box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
+ background-color: var(--color-primary) !important;
+ color: var(--color-white) !important;
+ border-color: var(--color-primary-dark) !important;
+ box-shadow: var(--timecard-selected-shadow);
}
.selected .upToText {
- color: rgba(255, 255, 255, 0.8) !important;
+ color: var(--color-white-transparent) !important;
}
.selected .hoursText {
- color: white !important;
+ color: var(--color-white) !important;
}
.container p {
@@ -62,13 +63,13 @@
.upToText {
font-weight: 300;
- color: #919191;
+ color: var(--timecard-muted-text);
font-size: 0.9rem
}
.hoursText {
font-weight: 500;
- color:#686765;
+ color: var(--timecard-secondary-text);
font-size: 0.9rem;
}
@@ -78,9 +79,9 @@
}
.unavailableSlot {
- background-color: #E5E5E5;
- color: #B1B1B1;
- border: 1px solid #CECECE;
+ background-color: var(--timecard-unavailable-bg);
+ color: var(--timecard-unavailable-text);
+ border: 1px solid var(--timecard-unavailable-border);
height: 50px;
width: 165px;
}
@@ -88,7 +89,7 @@
.modalFooter {
height: fit-content;
width: 100%;
- color: blue;
+ color: var(--color-primary);
display: flex;
align-items: center;
gap: 1rem;
@@ -100,52 +101,52 @@
.cancelButton {
flex: 2;
- background-color: white;
+ background-color: var(--modal-cancel-bg);
height: 4rem;
- color: #374151;
+ color: var(--modal-cancel-text);
font-weight: 600;
- border: 2px solid #d1d5db;
+ border: 2px solid var(--modal-cancel-border);
border-radius: 0.5rem;
transition: all 0.2s ease;
}
@media (hover: hover) {
.cancelButton:hover {
- background-color: #f9fafb;
- border-color: #9ca3af;
+ background-color: var(--modal-cancel-hover-bg);
+ border-color: var(--modal-cancel-hover-border);
cursor: pointer;
}
}
.saveButton {
flex: 3;
- background-color: #059669;
- color: white;
+ background-color: var(--modal-save-bg);
+ color: var(--modal-save-text);
height: 4rem;
font-weight: 600;
font-size: 1.1rem;
- border: 2px solid #047857;
+ border: 2px solid var(--modal-save-border);
border-radius: 0.5rem;
transition: all 0.2s ease;
- box-shadow: 0 2px 4px rgba(5, 150, 105, 0.2);
+ box-shadow: var(--modal-save-shadow);
}
@media (hover: hover) {
.saveButton:hover {
- background-color: #047857;
- box-shadow: 0 4px 8px rgba(5, 150, 105, 0.3);
+ background-color: var(--modal-save-hover-bg);
+ box-shadow: var(--modal-save-hover-shadow);
cursor: pointer;
}
}
.saveButton:active {
- background-color: #065f46;
+ background-color: var(--modal-save-active-bg);
transform: translateY(1px);
- box-shadow: 0 1px 2px rgba(5, 150, 105, 0.2);
+ box-shadow: var(--modal-save-active-shadow);
}
.cancelButton:active {
- background-color: #e5e7eb;
+ background-color: var(--modal-cancel-active-bg);
transform: translateY(1px);
}
@@ -163,7 +164,7 @@
.sectionWithTitle label {
font-size: 0.8rem;
- color: #717171;
+ color: var(--text-tertiary);
}
.sectionWithTitle p {
@@ -171,7 +172,7 @@
}
.modalContainer {
- background-color: white;
+ background-color: var(--modal-bg);
width: 85%;
max-width: 400px;
}
@@ -180,9 +181,9 @@
.timeDisplay {
margin: 1rem 0;
padding: 1rem;
- background-color: #f8f9fa;
+ background-color: var(--modal-display-bg);
border-radius: 8px;
- border: 1px solid #e9ecef;
+ border: 1px solid var(--modal-display-border);
}
.timeRange {
@@ -200,7 +201,7 @@
.startTime label, .endTime label {
font-size: 0.75rem;
- color: #6c757d;
+ color: var(--text-secondary);
font-weight: 500;
margin-bottom: 0.25rem;
text-transform: uppercase;
@@ -210,11 +211,11 @@
.timeValue {
font-size: 1.5rem;
font-weight: 600;
- color: #212529;
+ color: var(--text-primary);
}
.timeValue.placeholder {
- color: #adb5bd;
+ color: var(--text-muted);
font-style: italic;
font-size: 1rem;
}
@@ -222,28 +223,28 @@
.timeSeparator {
font-size: 1.5rem;
font-weight: 300;
- color: #6c757d;
+ color: var(--text-secondary);
margin: 0 0.5rem;
}
/* Disabled button styles */
.disabledButton {
- background-color: #f8f9fa !important;
- color: #adb5bd !important;
- border: 2px dashed #dee2e6 !important;
+ background-color: var(--button-disabled-bg) !important;
+ color: var(--button-disabled-text) !important;
+ border: 2px dashed var(--button-disabled-border) !important;
cursor: not-allowed !important;
opacity: 0.6 !important;
}
@media (hover: hover) {
.disabledButton:hover {
- background-color: #f8f9fa !important;
+ background-color: var(--button-disabled-bg) !important;
cursor: not-allowed !important;
transform: none !important;
}
}
.disabledButton:active {
- background-color: #f8f9fa !important;
+ background-color: var(--button-disabled-bg) !important;
transform: none !important;
}
\ No newline at end of file
diff --git a/my-app/src/context/ThemeContext.jsx b/my-app/src/context/ThemeContext.jsx
new file mode 100644
index 0000000..06cc8c0
--- /dev/null
+++ b/my-app/src/context/ThemeContext.jsx
@@ -0,0 +1,74 @@
+import React, { createContext, useContext, useState, useEffect } from 'react';
+
+const ThemeContext = createContext();
+
+export const useTheme = () => {
+ const context = useContext(ThemeContext);
+ if (!context) {
+ throw new Error('useTheme must be used within a ThemeProvider');
+ }
+ return context;
+};
+
+export const ThemeProvider = ({ children }) => {
+ const [isDarkMode, setIsDarkMode] = useState(() => {
+ // Check localStorage for saved preference
+ const savedTheme = localStorage.getItem('theme');
+ if (savedTheme) {
+ return savedTheme === 'dark';
+ }
+
+ // Check system preference if no saved preference
+ if (window.matchMedia) {
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
+ }
+
+ // Default to light mode
+ return false;
+ });
+
+ useEffect(() => {
+ // Apply theme to document element
+ document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
+
+ // Save to localStorage
+ localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
+ }, [isDarkMode]);
+
+ // Listen for system theme changes
+ useEffect(() => {
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+
+ const handleChange = (e) => {
+ // Only update if user hasn't manually set a preference
+ const savedTheme = localStorage.getItem('theme');
+ if (!savedTheme) {
+ setIsDarkMode(e.matches);
+ }
+ };
+
+ mediaQuery.addEventListener('change', handleChange);
+ return () => mediaQuery.removeEventListener('change', handleChange);
+ }, []);
+
+ const toggleTheme = () => {
+ setIsDarkMode(prev => !prev);
+ };
+
+ const setTheme = (theme) => {
+ setIsDarkMode(theme === 'dark');
+ };
+
+ const value = {
+ isDarkMode,
+ theme: isDarkMode ? 'dark' : 'light',
+ toggleTheme,
+ setTheme
+ };
+
+ return (
+
+ {children}
+
+ );
+};
\ No newline at end of file
diff --git a/my-app/src/data/courseScheduleData.js b/my-app/src/data/courseScheduleData.js
new file mode 100644
index 0000000..d6a7683
--- /dev/null
+++ b/my-app/src/data/courseScheduleData.js
@@ -0,0 +1,631 @@
+export const scheduleData = [
+ // Week 45
+ {
+ week: 45,
+ activities: [
+ {
+ id: 1,
+ date: '2024-11-04',
+ time: '13:00-14:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 1',
+ description: 'Introduktion till kursen, Konceptuell modellering och databasmodellering, UML analysmönster.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 2,
+ date: '2024-11-05',
+ time: '13:00-14:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 1',
+ description: 'Handledning.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 3,
+ date: '2024-11-06',
+ time: '13:00-14:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 1 grp 1',
+ description: 'Konceptuell modellering. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 4,
+ date: '2024-11-06',
+ time: '15:00-16:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 1 grp 2',
+ description: 'Konceptuell modellering. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 5,
+ date: '2024-11-07',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 2',
+ description: 'Handledning.',
+ teacher: 'Anders Thelemyr, Workneh Yilma Ayele'
+ },
+ {
+ id: 6,
+ date: '2024-11-07',
+ time: '15:00-16:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 3',
+ description: 'INSTÄLLD.',
+ teacher: 'Ann Maria Dorotea Bergholtz',
+ cancelled: true
+ }
+ ]
+ },
+ // Week 46
+ {
+ week: 46,
+ activities: [
+ {
+ id: 7,
+ date: '2024-11-11',
+ time: '16:00-17:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 2',
+ description: 'Syntetisk databasdesign: Översättning från UML till relationsmodellen.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 8,
+ date: '2024-11-12',
+ time: '13:00-14:45',
+ location: 'Aula NOD',
+ type: 'Introduktion',
+ title: 'Introduktion 1',
+ description: 'Introduktion till DBMS och projekt Databasdesign. Vi löser en mindre uppgift som liknar den som skall göras i projekt Databasdesign.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 9,
+ date: '2024-11-13',
+ time: '10:00-11:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 2 grp 1',
+ description: 'Relationsmodellen och syntetisk databasdesign. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 10,
+ date: '2024-11-13',
+ time: '13:00-14:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 4',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Workneh Yilma Ayele'
+ },
+ {
+ id: 11,
+ date: '2024-11-13',
+ time: '15:00-16:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 2 grp 2',
+ description: 'Relationsmodellen och syntetisk databasdesign. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 12,
+ date: '2024-11-15',
+ time: '13:00-15:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 5',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Anders Thelemyr, Workneh Yilma Ayele'
+ }
+ ]
+ },
+ // Week 47
+ {
+ week: 47,
+ activities: [
+ {
+ id: 13,
+ date: '2024-11-18',
+ time: '13:00-14:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 3',
+ description: 'SQL I : inledande operatorer',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 14,
+ date: '2024-11-18',
+ time: '14:45-15:45',
+ location: 'L30',
+ type: 'Info',
+ title: 'Info om år 3 EIT frivillig SVL',
+ description: '',
+ teacher: ''
+ },
+ {
+ id: 15,
+ date: '2024-11-19',
+ time: '12:00-17:00',
+ location: 'G10:6',
+ type: 'Redovisning',
+ title: 'Redovisning 1 grp 1',
+ description: 'Redov. första delen av Projekt Databasdesign. Tidsschema per grupp för Red 1 (och även Red 2) kommer på kurswebbplatsen senast dagen efter deadline för projektgruppsanmälan.',
+ teacher: 'Ann Maria Dorotea Bergholtz',
+ important: true
+ },
+ {
+ id: 16,
+ date: '2024-11-19',
+ time: '12:00-17:00',
+ location: 'G10:7',
+ type: 'Redovisning',
+ title: 'Redovisning 1 grp 2',
+ description: 'Redov. första delen av Projekt Databasdesign. Tidsschema per grupp för Red 1 (och även Red 2) kommer på kurswebbplatsen senast dagen efter deadline för projektgruppsanmälan.',
+ teacher: 'Anders Thelemyr',
+ important: true
+ },
+ {
+ id: 17,
+ date: '2024-11-19',
+ time: '12:00-17:00',
+ location: 'G10:8',
+ type: 'Redovisning',
+ title: 'Redovisning 1 grp 3',
+ description: 'Redov. första delen av Projekt Databasdesign. Tidsschema per grupp för Red 1 (och även Red 2) kommer på kurswebbplatsen senast dagen efter deadline för projektgruppsanmälan.',
+ teacher: 'Workneh Yilma Ayele',
+ important: true
+ },
+ {
+ id: 18,
+ date: '2024-11-20',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 6',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Adrian Olbricht, Jennifer Skopac, Melle Carnesten'
+ },
+ {
+ id: 19,
+ date: '2024-11-22',
+ time: '08:00-09:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 3 grp 1',
+ description: 'SQL introduktion - enkla operatorer. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 20,
+ date: '2024-11-22',
+ time: '13:00-14:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 3 grp 2',
+ description: 'SQL introduktion - enkla operatorer. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ }
+ ]
+ },
+ // Week 48
+ {
+ week: 48,
+ activities: [
+ {
+ id: 21,
+ date: '2024-11-25',
+ time: '10:00-11:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 4',
+ description: 'SQL II: avancerade operatorer.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 22,
+ date: '2024-11-25',
+ time: '13:00-14:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 7',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Jennifer Skopac, Melle Carnesten'
+ },
+ {
+ id: 23,
+ date: '2024-11-27',
+ time: '15:00-16:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 8',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Melle Carnesten, Workneh Yilma Ayele'
+ },
+ {
+ id: 24,
+ date: '2024-11-29',
+ time: '11:00-12:00',
+ location: 'L30',
+ type: 'Info',
+ title: 'Info om år 3 MarkIT frivillig',
+ description: '',
+ teacher: ''
+ },
+ {
+ id: 25,
+ date: '2024-11-29',
+ time: '13:00-14:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 4 grp 1',
+ description: 'SQL fortsättning. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 26,
+ date: '2024-11-29',
+ time: '15:00-16:45',
+ location: 'Aula NOD',
+ type: 'Lektion',
+ title: 'Lektion 4 grp 2',
+ description: 'SQL fortsättning. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ }
+ ]
+ },
+ // Week 49
+ {
+ week: 49,
+ activities: [
+ {
+ id: 27,
+ date: '2024-12-02',
+ time: '13:00-14:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 9',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Adrian Olbricht, Jennifer Skopac, Melle Carnesten'
+ },
+ {
+ id: 28,
+ date: '2024-12-03',
+ time: '15:00-16:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 5',
+ description: 'Frågespråk för relationsmodellen: relationsalgebra.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 29,
+ date: '2024-12-04',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 10',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Adrian Olbricht, Edwin Sundberg, Workneh Yilma Ayele'
+ },
+ {
+ id: 30,
+ date: '2024-12-06',
+ time: '10:00-11:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 5 grp 1',
+ description: 'Relationsalgebra. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 31,
+ date: '2024-12-06',
+ time: '15:00-16:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 5 grp 2',
+ description: 'Relationsalgebra. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ }
+ ]
+ },
+ // Week 50
+ {
+ week: 50,
+ activities: [
+ {
+ id: 32,
+ date: '2024-12-10',
+ time: '13:00-18:00',
+ location: 'G10:6',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 1',
+ description: 'Redov. av de fem första frågorna för projekt Frågespråk, både SQL och relationsalgebra.',
+ teacher: 'Ann Maria Dorotea Bergholtz',
+ important: true
+ },
+ {
+ id: 33,
+ date: '2024-12-10',
+ time: '13:00-18:00',
+ location: 'G10:7',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 2',
+ description: 'Redov. av de fem första frågorna för projekt Frågespråk, både SQL och relationsalgebra.',
+ teacher: 'Anders Thelemyr',
+ important: true
+ },
+ {
+ id: 34,
+ date: '2024-12-10',
+ time: '13:00-18:00',
+ location: 'G10:8',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 3',
+ description: 'Redov. av de fem första frågorna för projekt Frågespråk, både SQL och relationsalgebra.',
+ teacher: 'Workneh Yilma Ayele',
+ important: true
+ },
+ {
+ id: 35,
+ date: '2024-12-12',
+ time: '10:00-11:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 6',
+ description: 'Analytisk databasdesign: normalisering.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ }
+ ]
+ },
+ // Week 51
+ {
+ week: 51,
+ activities: [
+ {
+ id: 36,
+ date: '2024-12-16',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 11',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Adrian Olbricht, Edwin Sundberg'
+ },
+ {
+ id: 37,
+ date: '2024-12-17',
+ time: '10:00-12:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 12',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Edwin Sundberg, Workneh Yilma Ayele'
+ },
+ {
+ id: 38,
+ date: '2024-12-17',
+ time: '13:00-15:00',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 8',
+ description: 'Alternativ till relationsmodellen - noSQL-ansatser.',
+ teacher: 'Martin Duneld'
+ },
+ {
+ id: 39,
+ date: '2024-12-18',
+ time: '10:00-11:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 6 grp 1',
+ description: 'Analytisk databasdesign: normalisering. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 40,
+ date: '2024-12-18',
+ time: '13:00-14:45',
+ location: 'Lilla Hörsalen',
+ type: 'Lektion',
+ title: 'Lektion 6 grp 2',
+ description: 'Analytisk databasdesign: normalisering. Anmälan till lektionsdeltagande krävs. Lektionsgruppsanmälan görs i Daisy.',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 41,
+ date: '2024-12-19',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 14',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Edwin Sundberg, Melle Carnesten'
+ },
+ {
+ id: 42,
+ date: '2024-12-19',
+ time: '15:00-16:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 7',
+ description: 'Databashanteringssystem.',
+ teacher: 'Anders Thelemyr'
+ },
+ {
+ id: 43,
+ date: '2024-12-20',
+ time: '13:00-14:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 13',
+ description: 'Handledning. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Anders Thelemyr, Edwin Sundberg'
+ }
+ ]
+ },
+ // Week 52
+ {
+ week: 52,
+ activities: [
+ {
+ id: 44,
+ date: '2024-12-23',
+ time: '13:00-15:00',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning',
+ description: 'Zoom-handledning!!!',
+ teacher: 'Edwin Sundberg, Jennifer Skopac'
+ }
+ ]
+ },
+ // Week 2 (January)
+ {
+ week: 2,
+ activities: [
+ {
+ id: 45,
+ date: '2025-01-07',
+ time: '15:00-16:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 15',
+ description: 'Projekthandledning (ej labb). Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Edwin Sundberg, Jennifer Skopac'
+ },
+ {
+ id: 46,
+ date: '2025-01-08',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 16',
+ description: 'Projekthandledning (ej labb). Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Edwin Sundberg, Workneh Yilma Ayele'
+ },
+ {
+ id: 47,
+ date: '2025-01-08',
+ time: '13:00-14:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 9',
+ description: 'Embedded SQL och intro till Labb.',
+ teacher: 'Nikos Dimitrakas'
+ },
+ {
+ id: 48,
+ date: '2025-01-09',
+ time: '09:00-11:45',
+ location: '',
+ type: 'Laboration',
+ title: 'Laboration',
+ description: 'Öronmärkt tillfälle för arbete på plats i NOD med laborationen i "Embedded SQL i Java". Under tillfället kan labbgrupper, som behöver, få hjälp med labben genom att ställa sig i kö via handledningssystemet.',
+ teacher: 'Anders Thelemyr, Edwin Sundberg, Nikos Dimitrakas'
+ },
+ {
+ id: 49,
+ date: '2025-01-10',
+ time: '09:00-11:45',
+ location: '',
+ type: 'Laboration',
+ title: 'Laboration',
+ description: 'Öronmärkt tillfälle för arbete på plats i NOD med laborationen i "Embedded SQL i Java". Under tillfället kan labbgrupper, som behöver, få hjälp med labben genom att ställa sig i kö via handledningssystemet.',
+ teacher: 'Anders Thelemyr, Edwin Sundberg, Nikos Dimitrakas'
+ }
+ ]
+ },
+ // Week 3 (January)
+ {
+ week: 3,
+ activities: [
+ {
+ id: 50,
+ date: '2025-01-13',
+ time: '09:00-11:45',
+ location: '',
+ type: 'Laboration',
+ title: 'Laboration',
+ description: 'Öronmärkt tillfälle för arbete på plats i NOD med laborationen i "Embedded SQL i Java". Under tillfället kan labbgrupper, som behöver, få hjälp med labben genom att ställa sig i kö via handledningssystemet.',
+ teacher: 'Anders Thelemyr, Edwin Sundberg, Nikos Dimitrakas'
+ },
+ {
+ id: 51,
+ date: '2025-01-13',
+ time: '15:00-16:45',
+ location: 'Aula NOD',
+ type: 'Föreläsning',
+ title: 'Föreläsning 10',
+ description: 'Genomgång av en exempeltentamen',
+ teacher: 'Ann Maria Dorotea Bergholtz'
+ },
+ {
+ id: 52,
+ date: '2025-01-14',
+ time: '10:00-11:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 18',
+ description: 'Handledning för projekt och ev. kvarvarande övriga uppgifter. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Adrian Olbricht, Edwin Sundberg, Jennifer Skopac, Melle Carnesten'
+ },
+ {
+ id: 53,
+ date: '2025-01-17',
+ time: '13:00-14:45',
+ location: '',
+ type: 'Handledning',
+ title: 'Handledning 17',
+ description: 'Handledning för projekt och ev. kvarvarande övriga uppgifter. Via handledning.dsv.su.se - ange zoomid eller plats i NOD. Använd helst ingen passcode om Zoom används.',
+ teacher: 'Adrian Olbricht, Edwin Sundberg, Jennifer Skopac, Melle Carnesten'
+ }
+ ]
+ }
+];
+
+export const examData = [
+ {
+ id: 'exam1',
+ date: '2025-01-16',
+ time: '13:00-17:00',
+ type: 'Tentamen',
+ title: 'Tentamen (4hp)',
+ location: 'Aula NOD + flera salar',
+ important: true,
+ isExam: true
+ },
+ {
+ id: 'exam2',
+ date: '2025-01-19',
+ time: '',
+ type: 'Projektarbete',
+ title: 'Projektarbete (3.5hp)',
+ location: '',
+ important: true,
+ isExam: true
+ }
+];
+
+export const courseInfo = {
+ title: 'Databasmetodik',
+ code: 'DB HT2024',
+ credits: '7,5 hp',
+ coordinator: 'Ann Maria Dorotea Bergholtz',
+ examCredits: '4 hp',
+ projectCredits: '3,5 hp'
+};
\ No newline at end of file
diff --git a/my-app/src/data/coursesData.js b/my-app/src/data/coursesData.js
new file mode 100644
index 0000000..50fe2ba
--- /dev/null
+++ b/my-app/src/data/coursesData.js
@@ -0,0 +1,24 @@
+export const coursesData = [
+ {
+ id: 'db-ht2024',
+ title: 'Databasmetodik',
+ code: 'DB HT2024',
+ credits: '7,5 hp',
+ coordinator: 'Ann Maria Dorotea Bergholtz',
+ period: 'HT 2024',
+ description: 'Kursen behandlar konceptuell modellering, databasdesign, SQL, relationsalgebra och normalisering.',
+ color: '#1d4ed8',
+ dataModule: () => import('./courseScheduleData')
+ },
+ {
+ id: 'proto2-vt2025',
+ title: 'Prototyper inom interaktionsdesign II',
+ code: 'PROTO2 VT2025',
+ credits: '7,5 hp',
+ coordinator: 'Ola Knutsson, Johan Stymne',
+ period: 'VT 2025',
+ description: 'Kursen behandlar designsprintar, prototypning i fysiska och digitala material, användarflöden och testning av prototyper.',
+ color: '#059669',
+ dataModule: () => import('./proto2ScheduleData')
+ }
+];
\ No newline at end of file
diff --git a/my-app/src/data/proto2ScheduleData.js b/my-app/src/data/proto2ScheduleData.js
new file mode 100644
index 0000000..a66cab7
--- /dev/null
+++ b/my-app/src/data/proto2ScheduleData.js
@@ -0,0 +1,526 @@
+export const scheduleData = [
+ // Week 13
+ {
+ week: 13,
+ activities: [
+ {
+ id: 1,
+ date: '2025-03-24',
+ time: '08:00-09:00',
+ location: 'L70',
+ type: 'Föreläsning',
+ title: 'Föreläsning 1',
+ description: 'Kursintroduktion and Introduktion till Designsprint Fas 1: Map. Det är obligatoriskt att deltaga i designsprinten. Eget arbete i designteamet 09:00-11:00',
+ teacher: 'Lon Hansson, Ola Knutsson'
+ },
+ {
+ id: 2,
+ date: '2025-03-24',
+ time: '11:00-11:45',
+ location: 'L70',
+ type: 'Seminarium',
+ title: 'Seminarium 1',
+ description: 'Designsprint Fas 1: Map, Debriefing',
+ teacher: 'Lon Hansson'
+ },
+ {
+ id: 3,
+ date: '2025-03-24',
+ time: '13:00-15:00',
+ location: 'L70',
+ type: 'Lektion',
+ title: 'Lektion 1',
+ description: 'Designsprint Fas 2: Sketch & Decide, Introduktion',
+ teacher: 'Lon Hansson'
+ },
+ {
+ id: 4,
+ date: '2025-03-24',
+ time: '15:00-15:45',
+ location: 'L70',
+ type: 'Seminarium',
+ title: 'Seminarium 2',
+ description: 'Designsprint Fas 2: Sketch & Decide, Debriefing',
+ teacher: 'Lon Hansson, Ola Knutsson'
+ },
+ {
+ id: 5,
+ date: '2025-03-25',
+ time: '08:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Lektion',
+ title: 'Lektion 2 grp 1',
+ description: 'Designsprint Fas 3: Prototype in physical design material, Introduktion. Designsprint-grupp 1-7',
+ teacher: 'Johan Stymne'
+ },
+ {
+ id: 6,
+ date: '2025-03-25',
+ time: '13:00-16:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Lektion',
+ title: 'Lektion 2 grp 2',
+ description: 'Designsprint Fas 3: Prototype in physical design material, Introduktion. Designsprint-grupp 8-14',
+ teacher: 'Johan Stymne'
+ },
+ {
+ id: 7,
+ date: '2025-03-27',
+ time: '08:00-08:45',
+ location: 'D3, D4',
+ type: 'Lektion',
+ title: 'Lektion 3',
+ description: 'Designsprint Fas 4:Prototype in digital design material, Wireframing, Introduktion. Uppstart av dagen. Eget arbete i designteamet 08:20-11:00',
+ teacher: 'Lon Hansson'
+ },
+ {
+ id: 8,
+ date: '2025-03-27',
+ time: '11:00-11:45',
+ location: 'D3, D4',
+ type: 'Seminarium',
+ title: 'Seminarium 3',
+ description: 'Designsprint Fas 4: Prototype in digital design material, Wireframing, Debriefing. D3: Designsprint-grupp 1-7, D4: Designsprint-grupp 8-14',
+ teacher: 'Lon Hansson'
+ },
+ {
+ id: 9,
+ date: '2025-03-27',
+ time: '13:00-16:45',
+ location: 'L50',
+ type: 'Lektion',
+ title: 'Lektion 4 grp 1',
+ description: 'Designsprint Fas 5: Test: Introduktion, Tester, Debriefing. Designsprint-grupp 1-7',
+ teacher: 'Lon Hansson'
+ },
+ {
+ id: 10,
+ date: '2025-03-27',
+ time: '13:00-16:45',
+ location: 'L70',
+ type: 'Lektion',
+ title: 'Lektion 4 grp 2',
+ description: 'Designsprint Fas 5: Test: Introduktion, Tester, Debriefing. Designsprint-grupp 8-14',
+ teacher: 'Ola Knutsson'
+ },
+ {
+ id: 11,
+ date: '2025-03-28',
+ time: '13:00-15:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Laboration',
+ title: 'Laboration 1 grp 1',
+ description: 'Labb 1: Arduino. Muntlig redovisning på plats. Designsprint-grupp 1-5',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne'
+ }
+ ]
+ },
+ // Week 14
+ {
+ week: 14,
+ activities: [
+ {
+ id: 12,
+ date: '2025-03-31',
+ time: '09:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Laboration',
+ title: 'Laboration 1 grp 2',
+ description: 'Labb 1: Arduino. Muntlig redovisning på plats. Designsprint-grupp 6-10',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne'
+ },
+ {
+ id: 13,
+ date: '2025-03-31',
+ time: '13:00-15:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Laboration',
+ title: 'Laboration 1 grp 3',
+ description: 'Labb 1: Arduino. Muntlig redovisning på plats. Designsprint-grupp 11-14',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne'
+ },
+ {
+ id: 14,
+ date: '2025-04-01',
+ time: '10:00-12:45',
+ location: 'L70',
+ type: 'Workshop',
+ title: 'Workshop 1',
+ description: 'UI och Interaktionsprogrammering, del 1. Designsprint-grupp 1-14. Vi kommer att sluta ca kl. 12',
+ teacher: 'Ola Knutsson'
+ },
+ {
+ id: 15,
+ date: '2025-04-02',
+ time: '08:00-11:45',
+ location: 'Studentlabb ID Höger',
+ type: 'Laboration',
+ title: 'Laboration 2 grp 1',
+ description: 'Labb 2: Gränssnittsdesign och prototypning med SwiftUI i XCode. Muntlig redovisning på plats och filinlämning i iLearn. Designsprint-grupp 1-5',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Mika Haverås, Ola Knutsson'
+ },
+ {
+ id: 16,
+ date: '2025-04-02',
+ time: '13:00-16:45',
+ location: 'Studentlabb ID Höger',
+ type: 'Laboration',
+ title: 'Laboration 2 grp 2',
+ description: 'Labb 2: Gränssnittsdesign och prototypning med SwiftUI i XCode. Muntlig redovisning på plats och filinlämning i iLearn. Designsprint-grupp 6-10',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Mika Haverås, Ola Knutsson'
+ },
+ {
+ id: 17,
+ date: '2025-04-03',
+ time: '09:00-12:45',
+ location: 'Studentlabb ID Höger',
+ type: 'Laboration',
+ title: 'Laboration 2 grp 3',
+ description: 'Labb 2: Gränssnittsdesign och prototypning med SwiftUI i XCode. Muntlig redovisning på plats och filinlämning i iLearn. Designsprint-grupp 11-14',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Mika Haverås, Ola Knutsson'
+ },
+ {
+ id: 18,
+ date: '2025-04-03',
+ time: '15:00-17:00',
+ location: 'Lilla Hörsalen',
+ type: 'Workshop',
+ title: 'Workshop 2',
+ description: 'UI och Interaktionsprogrammering, del 2. Designsprint-grupp 1-14',
+ teacher: 'Ola Knutsson'
+ }
+ ]
+ },
+ // Week 15
+ {
+ week: 15,
+ activities: [
+ {
+ id: 19,
+ date: '2025-04-07',
+ time: '08:00-11:00',
+ location: 'Studentlabb ID Höger',
+ type: 'Laboration',
+ title: 'Laboration 3 grp 1',
+ description: 'Labb 3: Jetpack Compose i Android Studio. Muntlig redovisning på plats och filinlämning i iLearn. Designsprint-grupp 1-5',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Lon Hansson, Ola Knutsson'
+ },
+ {
+ id: 20,
+ date: '2025-04-07',
+ time: '12:00-15:00',
+ location: 'Studentlabb ID Höger',
+ type: 'Laboration',
+ title: 'Laboration 3 grp 2',
+ description: 'Labb 3: Jetpack Compose i Android Studio. Muntlig redovisning på plats och filinlämning i iLearn. Designsprint-grupp 6-10',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Kim Lindfors, Lon Hansson, Ola Knutsson'
+ },
+ {
+ id: 21,
+ date: '2025-04-08',
+ time: '09:00-12:00',
+ location: 'Studentlabb ID Höger',
+ type: 'Laboration',
+ title: 'Laboration 3 grp 3',
+ description: 'Labb 3: Jetpack Compose i Android Studio. Muntlig redovisning på plats och filinlämning i iLearn. Designsprint-grupp 11-14',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Kim Lindfors, Lon Hansson, Ola Knutsson'
+ },
+ {
+ id: 22,
+ date: '2025-04-10',
+ time: '13:00-15:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Handledning',
+ title: 'Handledning 1',
+ description: 'Skisser och Arduino',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne, Kim Lindfors, Mika Haverås'
+ }
+ ]
+ },
+ // Week 16
+ {
+ week: 16,
+ activities: [
+ {
+ id: 23,
+ date: '2025-04-14',
+ time: '09:00-09:45',
+ location: 'L50',
+ type: 'Workshop',
+ title: 'Workshop 3 grp 2',
+ description: 'Kick-off för individuella designprojektet. Designsprint-grupp 8-14',
+ teacher: 'Ola Knutsson'
+ },
+ {
+ id: 24,
+ date: '2025-04-14',
+ time: '10:00-10:45',
+ location: 'L50',
+ type: 'Workshop',
+ title: 'Workshop 3 grp 1',
+ description: 'Kick-off för individuella designprojektet. Designsprint-grupp 1-7',
+ teacher: 'Ola Knutsson'
+ },
+ {
+ id: 25,
+ date: '2025-04-14',
+ time: '13:00-16:45',
+ location: 'D3, D4',
+ type: 'Laboration',
+ title: 'Laboration 4 grp 1',
+ description: 'Labb 4: HTML, Bootstrap & JavaScript. Designsprint-grupp 1-7',
+ teacher: 'Lon Hansson, Stefan Nenzén'
+ },
+ {
+ id: 26,
+ date: '2025-04-15',
+ time: '09:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Handledning',
+ title: 'Handledning 2',
+ description: 'Användarflöden',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne'
+ },
+ {
+ id: 27,
+ date: '2025-04-15',
+ time: '13:00-16:45',
+ location: 'D3, D4',
+ type: 'Laboration',
+ title: 'Laboration 4 grp 2',
+ description: 'Labb 4: HTML, Bootstrap & JavaScript. Designsprint-grupp 8-14',
+ teacher: 'Lon Hansson, Stefan Nenzén'
+ },
+ {
+ id: 28,
+ date: '2025-04-16',
+ time: '09:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Redovisning',
+ title: 'Redovisning 1 grp 1',
+ description: 'Interaktion, gränssnittsskisser och UI i fysiska och digitala material. Designsprint-grupp 1-7',
+ teacher: 'Johan Stymne, Ola Knutsson',
+ important: true
+ },
+ {
+ id: 29,
+ date: '2025-04-16',
+ time: '14:00-16:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Redovisning',
+ title: 'Redovisning 1 grp 2',
+ description: 'Interaktion, gränssnittsskisser och UI i fysiska och digitala material. Designsprint-grupp 8-14',
+ teacher: 'Johan Stymne, Ola Knutsson',
+ important: true
+ }
+ ]
+ },
+ // Week 17
+ {
+ week: 17,
+ activities: [
+ {
+ id: 30,
+ date: '2025-04-23',
+ time: '09:00-10:45',
+ location: 'L70',
+ type: 'Workshop',
+ title: 'Workshop 4 grp 2',
+ description: 'McElroys begrepp. Designsprint-grupp 8-14',
+ teacher: 'Johan Stymne'
+ },
+ {
+ id: 31,
+ date: '2025-04-23',
+ time: '13:00-14:45',
+ location: 'L70',
+ type: 'Workshop',
+ title: 'Workshop 4 grp 1',
+ description: 'McElroys begrepp. Designsprint-grupp 1-7',
+ teacher: 'Johan Stymne'
+ },
+ {
+ id: 32,
+ date: '2025-04-24',
+ time: '09:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Handledning',
+ title: 'Handledning 3',
+ description: 'Gestaltning, Bredd, Djup, Interaktivitet, Data',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne, Kim Lindfors, Mika Haverås'
+ }
+ ]
+ },
+ // Week 18
+ {
+ week: 18,
+ activities: [
+ {
+ id: 33,
+ date: '2025-04-29',
+ time: '13:00-14:45',
+ location: 'Lilla Hörsalen',
+ type: 'Workshop',
+ title: 'Workshop 5',
+ description: 'Designsystem och värdering. Designsprint-grupp 1-14',
+ teacher: 'Johan Stymne'
+ }
+ ]
+ },
+ // Week 19
+ {
+ week: 19,
+ activities: [
+ {
+ id: 34,
+ date: '2025-05-05',
+ time: '09:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Handledning',
+ title: 'Handledning 4',
+ description: 'Integration av prototypens delar',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne, Kim Lindfors, Mika Haverås'
+ }
+ ]
+ },
+ // Week 20
+ {
+ week: 20,
+ activities: [
+ {
+ id: 35,
+ date: '2025-05-12',
+ time: '13:00-14:45',
+ location: 'L70',
+ type: 'Workshop',
+ title: 'Workshop 6 grp 1',
+ description: 'Testning av prototyper. Designsprint-grupp 1-7',
+ teacher: 'Johan Stymne, Lon Hansson'
+ },
+ {
+ id: 36,
+ date: '2025-05-12',
+ time: '15:00-16:45',
+ location: 'Lilla Hörsalen',
+ type: 'Workshop',
+ title: 'Workshop 6 grp 2',
+ description: 'Testning av prototyper. Designsprint-grupp 8-14',
+ teacher: 'Johan Stymne, Lon Hansson'
+ }
+ ]
+ },
+ // Week 21
+ {
+ week: 21,
+ activities: [
+ {
+ id: 37,
+ date: '2025-05-19',
+ time: '09:00-11:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Handledning',
+ title: 'Handledning 5',
+ description: 'Designsystem, Ändringar efter testerna',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Johan Stymne, Kim Lindfors'
+ },
+ {
+ id: 38,
+ date: '2025-05-22',
+ time: '15:00-17:00',
+ location: 'Studentlabb ID:fix',
+ type: 'Workshop',
+ title: 'Workshop 7',
+ description: 'Resttillfälle Workshop, möjlighet att hämta ut prototyper kl. 12 i ID:Fix för att förbereda dessa för testning.',
+ teacher: 'Ola Knutsson'
+ }
+ ]
+ },
+ // Week 22
+ {
+ week: 22,
+ activities: [
+ {
+ id: 39,
+ date: '2025-05-28',
+ time: '12:00-14:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Handledning',
+ title: 'Handledning 6',
+ description: 'Alla delar av projektet',
+ teacher: 'António Miguel Beleza Maciel Pinheiro Braga, Jacob Reinikainen Lindström, Mika Haverås, Ola Knutsson'
+ }
+ ]
+ },
+ // Week 23
+ {
+ week: 23,
+ activities: [
+ {
+ id: 40,
+ date: '2025-06-02',
+ time: '12:00-13:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 1',
+ description: 'Visning och demo av de individuella designprojekten',
+ teacher: 'Jacob Reinikainen Lindström, Johan Stymne, Ola Knutsson',
+ important: true
+ },
+ {
+ id: 41,
+ date: '2025-06-02',
+ time: '14:00-15:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 2',
+ description: 'Visning och demo av de individuella designprojekten',
+ teacher: 'Jacob Reinikainen Lindström, Johan Stymne, Ola Knutsson',
+ important: true
+ },
+ {
+ id: 42,
+ date: '2025-06-03',
+ time: '12:00-13:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 3',
+ description: 'Visning och demo av de individuella designprojekten',
+ teacher: 'Johan Stymne, Mika Haverås, Ola Knutsson',
+ important: true
+ },
+ {
+ id: 43,
+ date: '2025-06-03',
+ time: '14:00-15:45',
+ location: 'Studentlabb ID:fix',
+ type: 'Redovisning',
+ title: 'Redovisning 2 grp 4',
+ description: 'Visning och demo av de individuella designprojekten',
+ teacher: 'Johan Stymne, Mika Haverås, Ola Knutsson',
+ important: true
+ }
+ ]
+ }
+];
+
+export const examData = [
+ {
+ id: 'exam1',
+ date: '2025-06-09',
+ time: '',
+ type: 'Inlämningsuppgifter',
+ title: 'Inlämningsuppgifter (7,5hp)',
+ location: '',
+ important: true,
+ isExam: true
+ }
+];
+
+export const courseInfo = {
+ title: 'Prototyper inom interaktionsdesign II',
+ code: 'PROTO2 VT2025',
+ credits: '7,5 hp',
+ coordinator: 'Ola Knutsson, Johan Stymne',
+ examCredits: '7,5 hp',
+ projectCredits: 'Inlämningsuppgifter'
+};
\ No newline at end of file
diff --git a/my-app/src/index.css b/my-app/src/index.css
index eec8ac2..3192f77 100644
--- a/my-app/src/index.css
+++ b/my-app/src/index.css
@@ -1,4 +1,5 @@
@import './fonts.css';
+@import './styles/variables.css';
:root {
font-family: 'The Sans', system-ui, Avenir, Helvetica, Arial, sans-serif !important;
@@ -6,8 +7,8 @@
font-weight: 400;
color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
+ color: var(--text-primary);
+ background-color: var(--bg-primary);
font-synthesis: none;
text-rendering: optimizeLegibility;
@@ -17,11 +18,11 @@
a {
font-weight: 500;
- color: #646cff;
+ color: var(--color-primary);
text-decoration: inherit;
}
a:hover {
- color: #535bf2;
+ color: var(--color-primary-hover);
}
body {
@@ -56,14 +57,14 @@ button {
@media (prefers-color-scheme: light) {
:root {
- color: #213547;
- background-color: #ffffff;
+ color: var(--text-primary);
+ background-color: var(--bg-primary);
}
a:hover {
- color: #747bff;
+ color: var(--color-primary);
}
button {
- background-color: #f9f9f9;
+ background-color: var(--button-bg);
}
}
diff --git a/my-app/src/pages/CourseSchedule.jsx b/my-app/src/pages/CourseSchedule.jsx
new file mode 100644
index 0000000..25c629e
--- /dev/null
+++ b/my-app/src/pages/CourseSchedule.jsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import styles from './CourseSchedule.module.css';
+import { coursesData } from '../data/coursesData';
+
+export function CourseSchedule() {
+
+ return (
+
+
+
Kursscheman
+
Välj en kurs för att se dess schema
+
+
+
+
+ {coursesData.map((course) => (
+
+
+
+
+
{course.title}
+
{course.code} • {course.credits}
+
{course.description}
+
+ {course.period}
+ {course.coordinator}
+
+
+
+
+ ))}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/my-app/src/pages/CourseSchedule.module.css b/my-app/src/pages/CourseSchedule.module.css
new file mode 100644
index 0000000..068d994
--- /dev/null
+++ b/my-app/src/pages/CourseSchedule.module.css
@@ -0,0 +1,532 @@
+.pageContainer {
+ min-height: 100vh;
+ background: var(--bg-iphone-gradient);
+ padding: var(--container-padding);
+ max-width: var(--page-max-width);
+}
+
+.header {
+ margin-bottom: var(--spacing-3xl);
+ text-align: center;
+ padding: var(--spacing-2xl) var(--spacing-lg);
+ background: var(--bg-iphone-header);
+ border: var(--border-width-thin) solid var(--border-dark);
+ border-radius: var(--border-radius-xl);
+ box-shadow: var(--shadow-iphone-inset), var(--shadow-iphone-outer);
+}
+
+.courseTitle {
+ font-size: var(--font-size-5xl);
+ font-weight: var(--font-weight-bold);
+ color: var(--color-black);
+ margin: 0 0 var(--spacing-sm) 0;
+ font-family: var(--font-primary);
+ text-shadow: var(--text-shadow-light);
+}
+
+.courseInfo {
+ color: var(--text-primary);
+ font-size: var(--font-size-lg);
+ margin: 0;
+ font-weight: var(--font-weight-medium);
+ text-shadow: var(--text-shadow-light);
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-2xl);
+}
+
+.coursesList {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-lg);
+}
+
+.courseCard {
+ display: block;
+ background: var(--bg-primary);
+ border-radius: var(--border-radius-2xl);
+ overflow: hidden;
+ box-shadow: var(--shadow-lg);
+ text-decoration: none;
+ color: inherit;
+ transition: var(--transition-transform);
+}
+
+.courseCard:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-xl);
+}
+
+.courseCardHeader {
+ display: flex;
+ align-items: flex-start;
+ gap: var(--spacing-lg);
+ padding: var(--spacing-2xl);
+}
+
+.courseColorIndicator {
+ width: var(--color-indicator-width);
+ height: var(--color-indicator-height);
+ border-radius: var(--border-radius-sm);
+ flex-shrink: 0;
+}
+
+.courseCardContent {
+ flex: 1;
+ min-width: 0;
+}
+
+.courseCardTitle {
+ font-size: var(--font-size-3xl);
+ font-weight: var(--font-weight-semibold);
+ color: var(--color-gray-800);
+ margin: 0 0 var(--spacing-sm) 0;
+ line-height: var(--line-height-normal);
+}
+
+.courseCardCode {
+ color: var(--text-secondary);
+ font-size: var(--font-size-md);
+ margin: 0 0 var(--spacing-md) 0;
+ font-weight: var(--font-weight-medium);
+}
+
+.courseCardDescription {
+ color: var(--color-gray-600);
+ font-size: var(--font-size-md);
+ line-height: var(--line-height-relaxed);
+ margin: 0 0 var(--spacing-lg) 0;
+}
+
+.courseCardFooter {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-xs);
+}
+
+.courseCardPeriod {
+ color: var(--text-secondary);
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-medium);
+}
+
+.courseCardCoordinator {
+ color: var(--color-gray-400);
+ font-size: var(--font-size-sm);
+}
+
+/* Day grouping styles */
+.dayGroup {
+ margin-bottom: 1.5rem;
+}
+
+.dayGroup:last-child {
+ margin-bottom: 0;
+}
+
+.dayHeader {
+ margin-bottom: 0.75rem;
+ padding: 0 1.25rem;
+}
+
+.dayTitle {
+ font-size: 1rem;
+ font-weight: 600;
+ color: #374151;
+ margin: 0;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0;
+ border-bottom: 1px solid #e5e7eb;
+}
+
+.dayActivitiesList {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+ padding: 0 1.25rem;
+}
+
+.singleActivityWrapper {
+ padding: 0 1.25rem;
+ margin-bottom: 1rem;
+}
+
+/* Day divider styles */
+.dayDivider {
+ background: var(--bg-iphone-day-divider);
+ border-top: var(--border-width-thin) solid var(--border-dark);
+ border-bottom: var(--border-width-thin) solid var(--border-dark);
+ padding: var(--spacing-sm) var(--spacing-xl);
+ margin: 0;
+ position: relative;
+ box-shadow: var(--shadow-iphone-day-divider);
+}
+
+.dayDivider:first-child {
+ margin-top: 0;
+}
+
+.dayDividerText {
+ font-size: var(--font-size-base);
+ font-weight: var(--font-weight-semibold);
+ color: var(--color-black);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ text-shadow: var(--text-shadow-light);
+}
+
+.todayIndicator {
+ color: var(--color-iphone-blue);
+ font-weight: var(--font-weight-medium);
+ font-size: var(--font-size-sm);
+}
+
+.section {
+ background: var(--bg-primary);
+ border: var(--border-width-thin) solid var(--border-dark);
+ border-radius: var(--border-radius-xl);
+ overflow: hidden;
+ box-shadow: var(--shadow-iphone-inset), var(--shadow-iphone-outer);
+}
+
+.sectionTitle {
+ font-size: var(--font-size-2xl);
+ font-weight: var(--font-weight-semibold);
+ color: var(--color-black);
+ margin: 0;
+ padding: var(--spacing-lg) var(--spacing-xl);
+ background: var(--bg-iphone-section);
+ border-bottom: var(--border-width-thin) solid var(--border-dark);
+ text-shadow: var(--text-shadow-light);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.currentWeekBadge {
+ background: linear-gradient(to bottom, var(--color-iphone-blue), var(--color-iphone-blue-dark));
+ color: var(--color-white);
+ font-size: var(--font-size-xs);
+ padding: var(--spacing-xs) var(--spacing-sm);
+ border-radius: var(--border-radius-xl);
+ border: var(--border-width-thin) solid var(--color-iphone-blue-border);
+ font-weight: var(--font-weight-bold);
+ margin-left: var(--spacing-sm);
+ text-shadow: var(--text-shadow-dark);
+ box-shadow: var(--shadow-iphone-button);
+}
+
+.activitiesList {
+ display: flex;
+ flex-direction: column;
+}
+
+.activityCard {
+ padding: var(--spacing-lg) var(--spacing-xl);
+ border-bottom: var(--border-width-thin) solid var(--border-divider);
+ cursor: pointer;
+ transition: var(--transition-fast);
+ position: relative;
+ background: var(--bg-primary);
+}
+
+.activityCard:hover {
+ background: var(--bg-iphone-hover);
+}
+
+.activityCard:last-child {
+ border-bottom: none;
+}
+
+.activityCard.today {
+ background: var(--state-today-bg);
+ border-left: var(--border-width-thick) solid var(--state-today-border);
+}
+
+.activityCard.important {
+ border-left: var(--border-width-thick) solid var(--state-important-border);
+ background: var(--state-important-bg);
+}
+
+.activityCard.cancelled {
+ border-left: var(--border-width-thick) solid var(--state-cancelled-border);
+ background: var(--state-cancelled-bg);
+ opacity: 0.7;
+}
+
+.activityCard.cancelled .activityTitle {
+ text-decoration: line-through;
+ color: var(--state-cancelled-text);
+}
+
+.activityCard.cancelled .activityTitle {
+ background: var(--color-gray-200) !important;
+ color: var(--state-cancelled-text) !important;
+}
+
+.activityHeader {
+ display: flex;
+ align-items: flex-start;
+ gap: 1rem;
+ width: 100%;
+}
+
+.activityMeta {
+ min-width: 80px;
+ flex-shrink: 0;
+}
+
+.activityDate {
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: #374151;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin-bottom: 0.25rem;
+}
+
+.todayBadge {
+ background: #059669;
+ color: white;
+ font-size: 0.7rem;
+ padding: 0.15rem 0.4rem;
+ border-radius: 4px;
+ font-weight: 500;
+}
+
+.activityTime {
+ font-size: var(--font-size-sm);
+ color: var(--text-secondary);
+ font-weight: var(--font-weight-medium);
+}
+
+.activityMain {
+ flex: 1;
+ min-width: 0;
+}
+
+
+.activityTitle {
+ font-size: var(--font-size-xl);
+ font-weight: var(--font-weight-semibold);
+ color: var(--color-gray-900);
+ margin: 0 0 var(--spacing-xs) 0;
+ line-height: var(--line-height-normal);
+}
+
+.activityLocation {
+ font-size: var(--font-size-base);
+ color: var(--text-secondary);
+ margin: var(--spacing-xs) 0 0 0;
+}
+
+.expandIcon {
+ font-size: 1.2rem;
+ color: var(--color-gray-400);
+ font-weight: var(--font-weight-semibold);
+ flex-shrink: 0;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.activityDetails {
+ margin-top: var(--spacing-lg);
+ padding-top: var(--spacing-lg);
+ border-top: var(--border-width-thin) solid var(--color-gray-200);
+ margin-left: 92px;
+}
+
+.activityDescription {
+ font-size: var(--font-size-md);
+ color: var(--color-gray-600);
+ line-height: var(--line-height-loose);
+ margin: 0 0 var(--spacing-md) 0;
+}
+
+.activityTeacher {
+ font-size: var(--font-size-base);
+ color: var(--text-secondary);
+ margin: 0;
+}
+
+.courseInfoCard {
+ padding: var(--spacing-xl);
+}
+
+.courseInfoCard p {
+ margin: 0 0 var(--spacing-md) 0;
+ font-size: var(--font-size-md);
+ color: var(--color-gray-600);
+}
+
+.courseInfoCard p:last-child {
+ margin-bottom: 0;
+}
+
+/* Activity type colors for titles */
+.lecture .activityTitle {
+ background: var(--activity-lecture-bg);
+ color: var(--activity-lecture-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.lesson .activityTitle {
+ background: var(--activity-lesson-bg);
+ color: var(--activity-lesson-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.guidance .activityTitle {
+ background: var(--activity-guidance-bg);
+ color: var(--activity-guidance-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.presentation .activityTitle {
+ background: var(--activity-presentation-bg);
+ color: var(--activity-presentation-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.introduction .activityTitle {
+ background: var(--activity-info-bg);
+ color: var(--activity-info-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.exam .activityTitle {
+ background: var(--activity-exam-bg);
+ color: var(--activity-exam-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.project .activityTitle {
+ background: var(--activity-project-bg);
+ color: var(--activity-project-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.info .activityTitle {
+ background: var(--activity-info-bg);
+ color: var(--activity-info-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.laboration .activityTitle {
+ background: var(--activity-laboration-bg);
+ color: var(--activity-laboration-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.workshop .activityTitle {
+ background: var(--activity-workshop-bg);
+ color: var(--activity-workshop-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.seminar .activityTitle {
+ background: var(--activity-seminar-bg);
+ color: var(--activity-seminar-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+.default .activityTitle {
+ background: var(--activity-default-bg);
+ color: var(--activity-default-text);
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ width: fit-content;
+ font-size: var(--font-size-md);
+}
+
+/* Responsive design */
+@media (max-width: 640px) {
+ .pageContainer {
+ padding: 0.75rem;
+ }
+
+ .activityHeader {
+ gap: 0.75rem;
+ }
+
+ .activityDetails {
+ margin-left: 0;
+ margin-top: 0.75rem;
+ padding-top: 0.75rem;
+ }
+
+ .activityMeta {
+ min-width: 70px;
+ }
+
+ .courseTitle {
+ font-size: 1.5rem;
+ }
+
+ .header {
+ padding: 1.25rem 1rem;
+ }
+}
+
+@media (min-width: 768px) {
+ .pageContainer {
+ max-width: 768px;
+ margin: 0 auto;
+ padding: 2rem;
+ }
+
+ .content {
+ gap: 2rem;
+ }
+
+ .header {
+ padding: 2rem;
+ }
+
+ .courseTitle {
+ font-size: 2rem;
+ }
+}
\ No newline at end of file
diff --git a/my-app/src/pages/CourseScheduleView.jsx b/my-app/src/pages/CourseScheduleView.jsx
new file mode 100644
index 0000000..451be69
--- /dev/null
+++ b/my-app/src/pages/CourseScheduleView.jsx
@@ -0,0 +1,232 @@
+import React, { useState, useEffect } from 'react';
+import { useParams, Link } from 'react-router-dom';
+import styles from './CourseSchedule.module.css';
+import { coursesData } from '../data/coursesData';
+
+export function CourseScheduleView() {
+ const { courseId } = useParams();
+ const [courseData, setCourseData] = useState(null);
+ const [scheduleData, setScheduleData] = useState([]);
+ const [examData, setExamData] = useState([]);
+ const [courseInfo, setCourseInfo] = useState({});
+ const [expandedActivity, setExpandedActivity] = useState(null);
+ const [currentWeek, setCurrentWeek] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const loadCourseData = async () => {
+ const course = coursesData.find(c => c.id === courseId);
+ if (!course) {
+ setLoading(false);
+ return;
+ }
+
+ setCourseData(course);
+
+ try {
+ const dataModule = await course.dataModule();
+ setScheduleData(dataModule.scheduleData);
+ setExamData(dataModule.examData);
+ setCourseInfo(dataModule.courseInfo);
+ } catch (error) {
+ console.error('Failed to load course data:', error);
+ }
+
+ setLoading(false);
+ };
+
+ loadCourseData();
+
+ // Get current week number (simplified)
+ const now = new Date();
+ const week = Math.ceil(((now - new Date(now.getFullYear(), 0, 1)) / 86400000 + new Date(now.getFullYear(), 0, 1).getDay() + 1) / 7);
+ setCurrentWeek(week);
+ }, [courseId]);
+
+ const toggleActivity = (activityId) => {
+ setExpandedActivity(expandedActivity === activityId ? null : activityId);
+ };
+
+ const getActivityTypeClass = (type) => {
+ // Only apply color styling to clear activity categories
+ switch (type) {
+ case 'Föreläsning': return styles.lecture;
+ case 'Lektion': return styles.lesson;
+ case 'Handledning': return styles.guidance;
+ case 'Redovisning': return styles.presentation;
+ case 'Laboration': return styles.laboration;
+ case 'Tentamen': return styles.exam;
+ case 'Projektarbete': return styles.project;
+ case 'Workshop': return styles.workshop;
+ case 'Seminarium': return styles.seminar;
+ // Leave unclear/mixed categories without color styling
+ case 'Introduktion':
+ case 'Info':
+ case 'Inlämningsuppgifter':
+ default:
+ return ''; // No color styling
+ }
+ };
+
+ const formatDate = (dateString) => {
+ const date = new Date(dateString);
+ const today = new Date();
+ const isToday = date.toDateString() === today.toDateString();
+
+ const options = {
+ weekday: 'short',
+ month: 'short',
+ day: 'numeric'
+ };
+
+ return {
+ formatted: date.toLocaleDateString('sv-SE', options),
+ isToday
+ };
+ };
+
+ const ActivityCard = ({ activity, isExam = false, hideDayInfo = false }) => {
+ const { formatted: formattedDate, isToday } = formatDate(activity.date);
+ const isExpanded = expandedActivity === activity.id;
+
+ return (
+
toggleActivity(activity.id)}
+ >
+
+
+ {!hideDayInfo && (
+
+ {formattedDate}
+ {isToday && Idag}
+
+ )}
+
{activity.time}
+
+
+
{activity.title}
+ {activity.location && (
+
📍 {activity.location}
+ )}
+
+
+ {isExpanded ? '−' : '+'}
+
+
+
+ {isExpanded && (
+
+
{activity.description}
+ {activity.teacher && (
+
+ Lärare: {activity.teacher}
+
+ )}
+
+ )}
+
+ );
+ };
+
+ if (loading) {
+ return
Loading...
;
+ }
+
+ if (!courseData) {
+ return (
+
+
+
Course not found
+ ← Back to courses
+
+
+ );
+ }
+
+ return (
+
+
+
+ ← Tillbaka till kurser
+
+
{courseInfo.title}
+
{courseInfo.code} • {courseInfo.credits}
+
+
+
+ {/* Upcoming Exams */}
+ {examData.length > 0 && (
+
+ 📅 Examinationer
+
+ {examData.map((exam) => (
+
+ ))}
+
+
+ )}
+
+ {/* Schedule by weeks */}
+ {scheduleData.map((weekData) => {
+ // Group activities by date for day dividers
+ const activitiesByDate = weekData.activities.reduce((acc, activity) => {
+ const dateKey = activity.date;
+ if (!acc[dateKey]) {
+ acc[dateKey] = [];
+ }
+ acc[dateKey].push(activity);
+ return acc;
+ }, {});
+
+ // Sort dates chronologically
+ const sortedDates = Object.keys(activitiesByDate).sort((a, b) => new Date(a) - new Date(b));
+
+ return (
+
+
+ Vecka {weekData.week}
+ {currentWeek === weekData.week && Aktuell}
+
+
+ {sortedDates.map((date, dateIndex) => {
+ const { formatted: formattedDate, isToday } = formatDate(date);
+ const dayActivities = activitiesByDate[date];
+
+ return (
+
+
+
+ {formattedDate}
+ {isToday && • Idag}
+
+
+ {dayActivities.map((activity) => (
+
+ ))}
+
+ );
+ })}
+
+
+ );
+ })}
+
+ {/* Course Info */}
+
+ ℹ️ Kursinformation
+
+
Kursansvarig: {courseInfo.coordinator}
+
Omfattning: {courseInfo.credits}
+ {courseInfo.examCredits && (
+
Tentamen: {courseInfo.examCredits}
+ )}
+ {courseInfo.projectCredits && (
+
Projektarbete: {courseInfo.projectCredits}
+ )}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/my-app/src/pages/NewBooking.module.css b/my-app/src/pages/NewBooking.module.css
index 9a3b2c4..60f7b4f 100644
--- a/my-app/src/pages/NewBooking.module.css
+++ b/my-app/src/pages/NewBooking.module.css
@@ -1,6 +1,8 @@
.pageContainer {
- padding: 1rem;
- background-color: white;
+ padding: var(--container-padding);
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ min-height: 100vh;
}
.formContainer {
@@ -20,7 +22,7 @@
margin-top: 2rem;
padding: 2rem;
border-radius: 0.3rem;
- outline: 1px solid #E7E7E7;
+ outline: 1px solid var(--border-light);
display: flex;
flex-direction: column;
align-items: center;
@@ -38,8 +40,8 @@
padding: 0;
z-index: 10;
padding: 1rem;
- border-top: 1px solid rgb(214, 214, 214);
- box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
+ border-top: 1px solid var(--border-medium);
+ box-shadow: var(--modal-footer-shadow);
}
.cancelButton {
@@ -56,7 +58,7 @@
.inactiveButton {
- color: #D4D4D4;
+ color: var(--text-disabled);
}
@@ -95,9 +97,9 @@
font-size: 1.2rem;
padding: 1rem 4rem;
/*border: 1px solid #D4D4D4;*/
- background-color: #2B4EF5;
+ background-color: var(--color-primary);
box-sizing: border-box;
- color: white;
+ color: var(--color-white);
font-weight: bolder;
}
@@ -109,7 +111,7 @@
bottom: 16px;
right: 16px;
z-index: 1000;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ box-shadow: var(--button-mobile-shadow);
cursor: pointer;
}
.bookingSummaryRight {
@@ -118,17 +120,17 @@
bottom: 16px;
left: 16px;
z-index: 1000;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ box-shadow: var(--button-mobile-shadow);
height: fit-content;
- background-color: white;
+ background-color: var(--bg-primary);
padding: 1rem;
font-size: 0.5rem;
}
}
.inactiveButton {
- background-color: rgb(220, 220, 220);
- color: #8f8f8f;
+ background-color: var(--button-disabled-bg);
+ color: var(--button-disabled-text);
}
.bookingSummary p {
@@ -139,7 +141,7 @@
.line {
height: 1px;
- background-color: rgb(216, 216, 216);
+ background-color: var(--divider-color);
width: 100%;
margin: 1rem 0;
}
@@ -158,8 +160,8 @@
.filterButton {
width: fit-content;
- background: white;
- border: 1px solid #D1D5DB;
+ background: var(--filter-button-bg);
+ border: 1px solid var(--filter-button-border);
border-radius: 0.375rem;
padding: 0.5rem 0.75rem;
display: flex;
@@ -169,27 +171,27 @@
transition: all 0.2s ease;
font-size: 0.875rem;
font-weight: 500;
- color: #374151;
+ color: var(--filter-button-text);
}
.filterButton:hover {
- background: #F9FAFB;
- border-color: #9CA3AF;
+ background: var(--filter-button-hover-bg);
+ border-color: var(--filter-button-hover-border);
}
.filterButton:active {
- background: #F3F4F6;
+ background: var(--filter-button-active-bg);
}
.activeFilter {
- background: #EBF8FF !important;
- border-color: #3B82F6 !important;
- color: #1E40AF !important;
+ background: var(--filter-active-bg) !important;
+ border-color: var(--filter-active-border) !important;
+ color: var(--filter-active-text) !important;
}
.activeFilter:hover {
- background: #DBEAFE !important;
- border-color: #2563EB !important;
+ background: var(--filter-active-hover-bg) !important;
+ border-color: var(--filter-active-hover-border) !important;
}
.filterIcon {
@@ -198,7 +200,7 @@
.chevron {
font-size: 0.75rem;
- color: #6B7280;
+ color: var(--filter-chevron-color);
transition: transform 0.2s ease;
}
@@ -214,8 +216,8 @@
width: fit-content;
max-width: 600px;
padding: 1rem;
- background: #F9FAFB;
- border: 1px solid #E5E7EB;
+ background: var(--filter-content-bg);
+ border: 1px solid var(--filter-content-border);
border-radius: 0.5rem;
animation: slideDown 0.2s ease-out;
}
@@ -230,15 +232,15 @@
.resetSection {
margin-top: 1rem;
padding-top: 1rem;
- border-top: 1px solid #E5E7EB;
+ border-top: 1px solid var(--filter-reset-divider);
display: flex;
justify-content: center;
}
.resetButton {
- background: white;
- border: 1px solid #DC2626;
- color: #DC2626;
+ background: var(--reset-button-bg);
+ border: 1px solid var(--reset-button-border);
+ color: var(--reset-button-text);
border-radius: 0.375rem;
padding: 0.5rem 1rem;
font-size: 0.875rem;
@@ -248,13 +250,13 @@
}
.resetButton:hover {
- background: #FEF2F2;
- border-color: #B91C1C;
- color: #B91C1C;
+ background: var(--reset-button-hover-bg);
+ border-color: var(--reset-button-hover-border);
+ color: var(--reset-button-hover-text);
}
.resetButton:active {
- background: #FEE2E2;
+ background: var(--reset-button-active-bg);
transform: translateY(1px);
}
diff --git a/my-app/src/pages/RoomBooking.jsx b/my-app/src/pages/RoomBooking.jsx
index 13f0c48..c20b2c1 100644
--- a/my-app/src/pages/RoomBooking.jsx
+++ b/my-app/src/pages/RoomBooking.jsx
@@ -50,7 +50,7 @@ export function RoomBooking({ bookings, showSuccessBanner, lastCreatedBooking, o
Ny bokning
-
+
);
diff --git a/my-app/src/pages/RoomBooking.module.css b/my-app/src/pages/RoomBooking.module.css
index 2aaeff8..2997e76 100644
--- a/my-app/src/pages/RoomBooking.module.css
+++ b/my-app/src/pages/RoomBooking.module.css
@@ -1,24 +1,28 @@
.pageContainer {
- color: rgb(51, 51, 51);
- padding: 1rem;
+ color: var(--text-primary);
+ background-color: var(--bg-tertiary);
+ padding: var(--container-padding);
+ min-height: 100vh;
}
.pageHeading {
- font-size: 2.6rem;
- font-weight: 300;
- font-family: 'The Sans', system-ui, sans-serif;
+ font-size: var(--font-size-6xl);
+ font-weight: var(--font-weight-light);
+ font-family: var(--font-primary);
+ color: var(--text-primary);
}
.sectionHeading {
- font-size: 1.5rem;
- font-weight: 600;
- margin-bottom: 1rem;
+ font-size: var(--font-size-4xl);
+ font-weight: var(--font-weight-semibold);
+ margin-bottom: var(--spacing-lg);
+ color: var(--text-primary);
}
.sectionDivider {
border: none;
- border-top: 1px solid #dedede;
- margin-bottom: 2rem;
+ border-top: var(--border-width-thin) solid var(--border-medium);
+ margin-bottom: var(--spacing-3xl);
}
.welcomeSection {
@@ -26,10 +30,10 @@
align-items: center;
justify-content: space-between;
background: #3d50a8;
- padding: 2rem 2.5rem;
- margin: 1.5rem 0 2.5rem 0;
- color: white;
- box-shadow: 0 10px 30px rgba(102, 126, 234, 0.15);
+ padding: var(--spacing-3xl) var(--spacing-4xl);
+ margin: var(--spacing-2xl) 0 var(--spacing-4xl) 0;
+ color: var(--color-white);
+ box-shadow: var(--shadow-2xl);
position: relative;
overflow: hidden;
}
@@ -52,24 +56,24 @@
.welcomeTitle {
font-size: 1.8rem;
- font-weight: 700;
+ font-weight: var(--font-weight-bold);
margin: 0;
- font-family: 'The Sans', system-ui, sans-serif;
+ font-family: var(--font-primary);
letter-spacing: -0.5px;
}
.welcomeSubtitle {
- font-size: 1rem;
- margin: 0.5rem 0 0 0;
+ font-size: var(--font-size-xl);
+ margin: var(--spacing-sm) 0 0 0;
opacity: 0.9;
- font-weight: 400;
+ font-weight: var(--font-weight-normal);
}
.welcomeIcon {
width: 48px;
height: 48px;
opacity: 0.8;
- color: white;
+ color: var(--color-white);
}
.welcomeIcon svg {
diff --git a/my-app/src/react-aria-starter/src/Calendar.css b/my-app/src/react-aria-starter/src/Calendar.css
index 3a9e38d..b7ad985 100644
--- a/my-app/src/react-aria-starter/src/Calendar.css
+++ b/my-app/src/react-aria-starter/src/Calendar.css
@@ -44,7 +44,7 @@
}
&:hover:not([data-selected]):not([data-disabled]):not([data-unavailable]) {
- background-color: #e9e9e9;
+ background-color: var(--highlight-hover);
}
&[data-pressed] {
@@ -71,8 +71,7 @@
.react-aria-CalendarCell {
&[data-unavailable] {
text-decoration: line-through;
- color: var(--invalid-color);
- color: rgb(203, 203, 203);
+ color: var(--text-color-disabled);
}
}
diff --git a/my-app/src/react-aria-starter/src/DatePicker.css b/my-app/src/react-aria-starter/src/DatePicker.css
index 5e17c75..a6882d9 100644
--- a/my-app/src/react-aria-starter/src/DatePicker.css
+++ b/my-app/src/react-aria-starter/src/DatePicker.css
@@ -31,23 +31,26 @@
align-items: center;
justify-content: center;
border-radius: 4px;
- transition: background-color 0.2s, opacity 0.2s;
+ transition: background-color 0.2s, opacity 0.2s, color 0.2s;
+ color: var(--chevron-button-color);
}
.chevron-button:hover:not(:disabled) {
- background-color: rgba(0, 0, 0, 0.05);
+ background-color: var(--highlight-hover);
}
.chevron-button:active:not(:disabled) {
- background-color: rgba(0, 0, 0, 0.1);
+ background-color: var(--highlight-pressed);
}
.chevron-button:disabled {
cursor: default;
+ color: var(--chevron-button-disabled-color);
+ opacity: 0.4;
}
.chevron-button:focus-visible {
- outline: 2px solid #2563EB;
+ outline: 2px solid var(--focus-ring-color);
outline-offset: 2px;
}
@@ -58,7 +61,7 @@
forced-color-adjust: none;
border-radius: 4px;
/*border: none;*/
- border: 1px solid #D4D4D4;
+ border: 1px solid var(--border-color);
/*width: 1.429rem;*/
/*height: 1.429rem;*/
width: fit-content;
@@ -69,7 +72,7 @@
&[data-pressed] {
box-shadow: none;
/*background: var(--highlight-background);*/
- background: #f1f1f1;
+ background: var(--button-background-pressed);
}
&[data-focus-visible] {
@@ -85,12 +88,12 @@
justify-content: space-between !important;
gap: 0.75rem !important;
cursor: pointer !important;
- background: white !important;
- border: 1px solid #E5E7EB !important;
+ background: var(--field-background) !important;
+ border: 1px solid var(--border-color) !important;
border-radius: 8px !important;
padding: 12px 16px !important;
font-weight: 500 !important;
- color: #374151 !important;
+ color: var(--field-text-color) !important;
transition: all 0.2s ease !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important;
white-space: nowrap !important;
@@ -103,21 +106,21 @@
}
.calendar-button:hover {
- border-color: #D1D5DB !important;
+ border-color: var(--border-color-hover) !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
}
.calendar-button[data-pressed] {
- background: #F9FAFB !important;
- border-color: #9CA3AF !important;
+ background: var(--button-background-pressed) !important;
+ border-color: var(--border-color-pressed) !important;
transform: translateY(1px) !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important;
}
.calendar-button[data-focus-visible] {
- outline: 2px solid #2563EB !important;
+ outline: 2px solid var(--focus-ring-color) !important;
outline-offset: 2px !important;
- border-color: #2563EB !important;
+ border-color: var(--focus-ring-color) !important;
}
.calendar-date {
diff --git a/my-app/src/react-aria-starter/src/DatePicker.tsx b/my-app/src/react-aria-starter/src/DatePicker.tsx
index 5fb9f8a..a07e62c 100644
--- a/my-app/src/react-aria-starter/src/DatePicker.tsx
+++ b/my-app/src/react-aria-starter/src/DatePicker.tsx
@@ -71,7 +71,6 @@ export function DatePicker