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( disabled={!canNavigatePrevious} > @@ -85,7 +84,6 @@ export function DatePicker( disabled={!canNavigateNext} > diff --git a/my-app/src/react-aria-starter/src/theme.css b/my-app/src/react-aria-starter/src/theme.css index b4bc1e3..139022a 100644 --- a/my-app/src/react-aria-starter/src/theme.css +++ b/my-app/src/react-aria-starter/src/theme.css @@ -61,6 +61,32 @@ } } +/* Dark mode support for data-theme attribute */ +[data-theme="dark"] { + --background-color: #1d1d1d; + --gray-50: #101010; + --gray-100: #393939; + --gray-200: #4f4f4f; + --gray-300: #CECECE; + --gray-400: #848484; + --gray-500: #a7a7a7; + --gray-600: #cfcfcf; + --purple-100: #3c1e95; + --purple-200: #522acd; + --purple-300: #6f46ed; + --purple-400: #8e6ef1; + --purple-500: #b099f5; + --purple-600: #d5c8fa; + --red-100: #721200; + --red-200: #9c1900; + --red-300: #cc2000; + --red-400: #e95034; + --red-500: #f08c79; + --red-600: #f7c3ba; + --highlight-hover: rgb(255 255 255 / 0.1); + --highlight-pressed: rgb(255 255 255 / 0.2); +} + /* Semantic colors */ :root { --focus-ring-color: var(--purple-400); diff --git a/my-app/src/styles/variables.css b/my-app/src/styles/variables.css new file mode 100644 index 0000000..4576c4b --- /dev/null +++ b/my-app/src/styles/variables.css @@ -0,0 +1,616 @@ +:root { + /* === COLORS === */ + + /* Primary Colors */ + --color-primary: #007AFF; + --color-primary-hover: #0056b3; + --color-primary-light: rgba(0, 122, 255, 0.12); + + /* iPhone/iPod Style Colors */ + --color-iphone-blue: #4d90fe; + --color-iphone-blue-dark: #3e7ce0; + --color-iphone-blue-border: #2d5aa0; + + /* Grayscale */ + --color-black: #000; + --color-gray-900: #111827; + --color-gray-800: #1f2937; + --color-gray-700: #374151; + --color-gray-600: #4b5563; + --color-gray-500: #6b7280; + --color-gray-400: #9ca3af; + --color-gray-300: #d1d5db; + --color-gray-200: #e5e7eb; + --color-gray-100: #f3f4f6; + --color-gray-50: #f9fafb; + --color-white: #fff; + + /* Text Colors */ + --text-primary: #333; + --text-secondary: #6b7280; + --text-tertiary: #9ca3af; + --text-muted: #999; + + /* Background Colors */ + --bg-primary: #fff; + --bg-secondary: #f8f8f8; + --bg-tertiary: #fafafa; + --bg-muted: #f0f0f0; + + /* iPhone/iPod Style Backgrounds */ + --bg-iphone-gradient: linear-gradient(to bottom, #c5ccd4, #92a5b8); + --bg-iphone-header: linear-gradient(to bottom, #ffffff, #e6e6e6); + --bg-iphone-section: linear-gradient(to bottom, #f2f2f2, #d9d9d9); + --bg-iphone-day-divider: linear-gradient(to bottom, #e6e6e6, #d9d9d9); + --bg-iphone-hover: linear-gradient(to bottom, #e8f0ff, #d0e2ff); + + /* Activity Type Colors */ + --activity-lecture-bg: #dbeafe; + --activity-lecture-text: #1d4ed8; + --activity-lesson-bg: #dcfce7; + --activity-lesson-text: #166534; + --activity-guidance-bg: #fef3c7; + --activity-guidance-text: #b45309; + --activity-presentation-bg: #f3e8ff; + --activity-presentation-text: #7c3aed; + --activity-exam-bg: #fee2e2; + --activity-exam-text: #dc2626; + --activity-project-bg: #f0fdf4; + --activity-project-text: #15803d; + --activity-info-bg: #fef3c7; + --activity-info-text: #b45309; + --activity-laboration-bg: #ecfdf5; + --activity-laboration-text: #047857; + --activity-workshop-bg: #fef2f2; + --activity-workshop-text: #dc2626; + --activity-seminar-bg: #f0f4ff; + --activity-seminar-text: #3b82f6; + --activity-default-bg: #f1f5f9; + --activity-default-text: #475569; + + /* Border Colors */ + --border-light: #E5E5E5; + --border-medium: #dedede; + --border-dark: #999; + --border-divider: #d9d9d9; + + /* === SPACING === */ + --spacing-xs: 0.25rem; /* 4px */ + --spacing-sm: 0.5rem; /* 8px */ + --spacing-md: 0.75rem; /* 12px */ + --spacing-lg: 1rem; /* 16px */ + --spacing-xl: 1.25rem; /* 20px */ + --spacing-2xl: 1.5rem; /* 24px */ + --spacing-3xl: 2rem; /* 32px */ + --spacing-4xl: 2.5rem; /* 40px */ + --spacing-5xl: 3rem; /* 48px */ + + /* === TYPOGRAPHY === */ + + /* Font Family */ + --font-primary: 'The Sans', system-ui, sans-serif; + --font-secondary: system-ui, -apple-system, sans-serif; + + /* Font Weights */ + --font-weight-light: 300; + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + --font-weight-extrabold: 800; + + /* Font Sizes */ + --font-size-xs: 0.7rem; /* 11.2px */ + --font-size-sm: 0.8rem; /* 12.8px */ + --font-size-base: 0.85rem; /* 13.6px */ + --font-size-md: 0.9rem; /* 14.4px */ + --font-size-lg: 0.95rem; /* 15.2px */ + --font-size-xl: 1rem; /* 16px */ + --font-size-2xl: 1.1rem; /* 17.6px */ + --font-size-3xl: 1.25rem; /* 20px */ + --font-size-4xl: 1.5rem; /* 24px */ + --font-size-5xl: 1.75rem; /* 28px */ + --font-size-6xl: 2.6rem; /* 41.6px */ + + /* Line Heights */ + --line-height-tight: 1.1; + --line-height-normal: 1.3; + --line-height-relaxed: 1.4; + --line-height-loose: 1.5; + + /* === BORDERS === */ + --border-radius-sm: 0.25rem; /* 4px */ + --border-radius-md: 0.5rem; /* 8px */ + --border-radius-lg: 0.75rem; /* 12px */ + --border-radius-xl: 10px; /* iPhone style */ + --border-radius-2xl: 12px; /* Modern style */ + + --border-width-thin: 1px; + --border-width-medium: 2px; + --border-width-thick: 4px; + + /* === SHADOWS === */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); + --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 2px 8px rgba(0, 0, 0, 0.06); + --shadow-xl: 0 4px 16px rgba(0, 0, 0, 0.12); + --shadow-2xl: 0 10px 30px rgba(102, 126, 234, 0.15); + + /* iPhone/iPod Style Shadows */ + --shadow-iphone-inset: inset 0 1px 0 rgba(255, 255, 255, 0.8); + --shadow-iphone-outer: 0 1px 3px rgba(0, 0, 0, 0.3); + --shadow-iphone-button: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-iphone-day-divider: inset 0 1px 0 rgba(255, 255, 255, 0.5); + + /* Text Shadows */ + --text-shadow-light: 0 1px 0 rgba(255, 255, 255, 0.8); + --text-shadow-dark: 0 -1px 0 rgba(0, 0, 0, 0.25); + + /* === TRANSITIONS === */ + --transition-fast: 0.15s ease; + --transition-medium: 0.2s ease; + --transition-slow: 0.3s ease; + --transition-transform: transform 0.2s ease, box-shadow 0.2s ease; + + /* === Z-INDEX === */ + --z-dropdown: 10; + --z-sticky: 100; + --z-header: 1000; + --z-modal: 9999; + + /* === LAYOUT === */ + --container-padding: var(--spacing-lg); + --page-max-width: 100%; + --header-height: 60px; + + /* === SPECIFIC COMPONENT SIZES === */ + --card-padding: var(--spacing-xl); + --button-padding-y: var(--spacing-sm); + --button-padding-x: var(--spacing-lg); + --input-padding: var(--spacing-md); + + /* Color indicator sizes */ + --color-indicator-width: 4px; + --color-indicator-height: 60px; + + /* Special states */ + --state-today-bg: linear-gradient(135deg, #fef3c7, #fde68a); + --state-today-border: #f59e0b; + --state-important-bg: linear-gradient(135deg, #fef2f2, #fee2e2); + --state-important-border: #ef4444; + --state-cancelled-bg: linear-gradient(135deg, #f9fafb, #f3f4f6); + --state-cancelled-border: #6b7280; + --state-cancelled-text: #6b7280; + + /* Room category colors */ + --room-green-bg: #D4EDDA; + --room-green-text: #155724; + --room-red-bg: #F8D7DA; + --room-red-text: #721C24; + --room-blue-bg: #D1ECF1; + --room-blue-text: #0C5460; + --room-yellow-bg: #FFF3CD; + --room-yellow-text: #856404; + + /* Notification colors */ + --notification-success-bg: #E8F5E8; + --notification-success-border: #4CAF50; + --notification-success-icon-bg: #4CAF50; + --notification-success-icon-text: white; + --notification-success-title: #2E7D32; + --notification-success-details: #388E3C; + + --notification-error-bg: #FFF4F4; + --notification-error-border: #F87171; + --notification-error-icon-bg: #EF4444; + --notification-error-icon-text: white; + --notification-error-title: #DC2626; + --notification-error-details: #EF4444; + + --notification-warning-bg: #FFF8E1; + --notification-warning-border: #FFB74D; + --notification-warning-icon: #FF9800; + + --notification-close-button: #6C757D; + --notification-close-button-hover: #495057; + --notification-close-button-bg-hover: rgba(108, 117, 125, 0.1); + + --tooltip-bg: #333; + --tooltip-text: white; + + /* Button colors */ + --button-bg: #f9f9f9; + --button-secondary-bg: #ffffff; + --button-secondary-text: #000; + --button-secondary-hover-bg: #f2f6ff; + --button-secondary-shadow: 0 2px 8px rgba(143, 143, 143, 0.2); + --button-secondary-hover-shadow: 0 4px 12px rgba(192, 192, 192, 0.3); + + /* Input colors */ + --input-bg: #FAFBFC; + --input-text: #333; + --input-border: #D2D9E0; + --input-placeholder: #adadad; + + /* Chip colors */ + --chip-bg: #F0F8FF; + --chip-text: #2563EB; + --chip-border: #D1E7FF; + --chip-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + --chip-hover-bg: #E0F2FE; + --chip-hover-border: #BAE6FD; + --chip-active-bg: #BFDBFE; + --chip-default-bg: #F3F4F6; + --chip-default-text: #374151; + --chip-default-border: #D1D5DB; + + /* Dropdown colors */ + --dropdown-bg: white; + --dropdown-border: #D2D9E0; + --dropdown-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08); + --dropdown-divider: #F1F3F4; + --dropdown-hover-bg: #F8F9FA; + --dropdown-active-bg: #E8F0FE; + --dropdown-selected-bg: #F0F8FF; + --dropdown-selected-hover-bg: #E0F2FE; + + /* TimeCard colors */ + --timecard-bg: #F8FBFC; + --timecard-text: #333; + --timecard-border: #CECECE; + --timecard-hover-bg: #E5E5E5; + --timecard-active-bg: #D1D5DB; + --timecard-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + --timecard-selected-shadow: 0 2px 8px rgba(37, 99, 235, 0.3); + --timecard-muted-text: #919191; + --timecard-secondary-text: #686765; + --timecard-unavailable-bg: #E5E5E5; + --timecard-unavailable-text: #B1B1B1; + --timecard-unavailable-border: #CECECE; + + /* Modal colors */ + --modal-bg: white; + --modal-display-bg: #f8f9fa; + --modal-display-border: #e9ecef; + --modal-cancel-bg: white; + --modal-cancel-text: #374151; + --modal-cancel-border: #d1d5db; + --modal-cancel-hover-bg: #f9fafb; + --modal-cancel-hover-border: #9ca3af; + --modal-cancel-active-bg: #e5e7eb; + --modal-save-bg: #059669; + --modal-save-text: white; + --modal-save-border: #047857; + --modal-save-shadow: 0 2px 4px rgba(5, 150, 105, 0.2); + --modal-save-hover-bg: #047857; + --modal-save-hover-shadow: 0 4px 8px rgba(5, 150, 105, 0.3); + --modal-save-active-bg: #065f46; + --modal-save-active-shadow: 0 1px 2px rgba(5, 150, 105, 0.2); + + /* Button disabled states */ + --button-disabled-bg: #f8f9fa; + --button-disabled-text: #adb5bd; + --button-disabled-border: #dee2e6; + + /* Additional color variants */ + --color-primary-dark: #1d4ed8; + --color-white-transparent: rgba(255, 255, 255, 0.8); + --color-white-transparent-low: rgba(255, 255, 255, 0.2); + + /* Header colors */ + --header-brand-color: #002E5F; + + /* Filter colors */ + --filter-button-bg: white; + --filter-button-text: #374151; + --filter-button-border: #D1D5DB; + --filter-button-hover-bg: #F9FAFB; + --filter-button-hover-border: #9CA3AF; + --filter-button-active-bg: #F3F4F6; + --filter-active-bg: #EBF8FF; + --filter-active-text: #1E40AF; + --filter-active-border: #3B82F6; + --filter-active-hover-bg: #DBEAFE; + --filter-active-hover-border: #2563EB; + --filter-chevron-color: #6B7280; + --filter-content-bg: #F9FAFB; + --filter-content-border: #E5E7EB; + --filter-reset-divider: #E5E7EB; + + /* Reset button colors */ + --reset-button-bg: white; + --reset-button-text: #DC2626; + --reset-button-border: #DC2626; + --reset-button-hover-bg: #FEF2F2; + --reset-button-hover-text: #B91C1C; + --reset-button-hover-border: #B91C1C; + --reset-button-active-bg: #FEE2E2; + + /* Additional UI colors */ + --border-light: #E7E7E7; + --border-medium: #d6d6d6; + --text-disabled: #D4D4D4; + --divider-color: #d8d8d8; + --button-mobile-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); + --modal-footer-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); + + /* Modal specific colors */ + --modal-border: rgba(255, 255, 255, 0.18); + --modal-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); + --modal-dialog-bg: rgba(255, 255, 255, 0.95); + --modal-close-hover-bg: #f3f4f6; + + /* Dropdown chevron */ + --dropdown-chevron-color: #888; + + /* Date picker chevron buttons */ + --chevron-button-color: #111; + --chevron-button-disabled-color: #666; +} + +/* === DARK MODE === */ +[data-theme="dark"] { + /* Primary Colors - keep same for consistency */ + --color-primary: #007AFF; + --color-primary-hover: #0056b3; + --color-primary-light: rgba(0, 122, 255, 0.2); + + /* iPhone/iPod Style Colors - darker variants */ + --color-iphone-blue: #4d90fe; + --color-iphone-blue-dark: #3e7ce0; + --color-iphone-blue-border: #2d5aa0; + + /* Grayscale - inverted for dark mode */ + --color-black: #fff; + --color-gray-900: #f9fafb; + --color-gray-800: #f3f4f6; + --color-gray-700: #e5e7eb; + --color-gray-600: #d1d5db; + --color-gray-500: #9ca3af; + --color-gray-400: #6b7280; + --color-gray-300: #4b5563; + --color-gray-200: #374151; + --color-gray-100: #1f2937; + --color-gray-50: #111827; + --color-white: #1a1a1a; + + /* Text Colors */ + --text-primary: #e5e5e5; + --text-secondary: #b0b0b0; + --text-tertiary: #888; + --text-muted: #666; + + /* Background Colors */ + --bg-primary: #1a1a1a; + --bg-secondary: #2a2a2a; + --bg-tertiary: #333; + --bg-muted: #3a3a3a; + + /* iPhone/iPod Style Backgrounds - dark variants */ + --bg-iphone-gradient: linear-gradient(to bottom, #2a2a2a, #1a1a1a); + --bg-iphone-header: linear-gradient(to bottom, #333, #2a2a2a); + --bg-iphone-section: linear-gradient(to bottom, #2a2a2a, #222); + --bg-iphone-day-divider: linear-gradient(to bottom, #333, #2a2a2a); + --bg-iphone-hover: linear-gradient(to bottom, #3a4a6a, #2a3a5a); + + /* Activity Type Colors - darker backgrounds, brighter text */ + --activity-lecture-bg: #1e3a8a; + --activity-lecture-text: #93c5fd; + --activity-lesson-bg: #166534; + --activity-lesson-text: #86efac; + --activity-guidance-bg: #92400e; + --activity-guidance-text: #fcd34d; + --activity-presentation-bg: #581c87; + --activity-presentation-text: #c4b5fd; + --activity-exam-bg: #991b1b; + --activity-exam-text: #fca5a5; + --activity-project-bg: #166534; + --activity-project-text: #86efac; + --activity-info-bg: #92400e; + --activity-info-text: #fcd34d; + --activity-laboration-bg: #047857; + --activity-laboration-text: #6ee7b7; + --activity-workshop-bg: #991b1b; + --activity-workshop-text: #fca5a5; + --activity-seminar-bg: #1d4ed8; + --activity-seminar-text: #93c5fd; + --activity-default-bg: #374151; + --activity-default-text: #d1d5db; + + /* Border Colors */ + --border-light: #404040; + --border-medium: #555; + --border-dark: #666; + --border-divider: #444; + + /* Shadows - adjusted for dark mode */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 2px 8px rgba(0, 0, 0, 0.5); + --shadow-xl: 0 4px 16px rgba(0, 0, 0, 0.6); + --shadow-2xl: 0 10px 30px rgba(0, 0, 0, 0.7); + + /* iPhone/iPod Style Shadows - adjusted */ + --shadow-iphone-inset: inset 0 1px 0 rgba(255, 255, 255, 0.1); + --shadow-iphone-outer: 0 1px 3px rgba(0, 0, 0, 0.7); + --shadow-iphone-button: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 2px rgba(0, 0, 0, 0.7); + --shadow-iphone-day-divider: inset 0 1px 0 rgba(255, 255, 255, 0.05); + + /* Text Shadows */ + --text-shadow-light: 0 1px 0 rgba(0, 0, 0, 0.5); + --text-shadow-dark: 0 -1px 0 rgba(255, 255, 255, 0.1); + + /* Special states - dark mode */ + --state-today-bg: linear-gradient(135deg, #92400e, #78350f); + --state-today-border: #f59e0b; + --state-important-bg: linear-gradient(135deg, #991b1b, #7f1d1d); + --state-important-border: #ef4444; + --state-cancelled-bg: linear-gradient(135deg, #374151, #1f2937); + --state-cancelled-border: #9ca3af; + --state-cancelled-text: #9ca3af; + + /* Room category colors - dark mode */ + --room-green-bg: #166534; + --room-green-text: #86efac; + --room-red-bg: #991b1b; + --room-red-text: #fca5a5; + --room-blue-bg: #1e40af; + --room-blue-text: #93c5fd; + --room-yellow-bg: #92400e; + --room-yellow-text: #fcd34d; + + /* Notification colors - dark mode */ + --notification-success-bg: #164e36; + --notification-success-border: #22c55e; + --notification-success-icon-bg: #22c55e; + --notification-success-icon-text: white; + --notification-success-title: #86efac; + --notification-success-details: #4ade80; + + --notification-error-bg: #991b1b; + --notification-error-border: #f87171; + --notification-error-icon-bg: #ef4444; + --notification-error-icon-text: white; + --notification-error-title: #fca5a5; + --notification-error-details: #f87171; + + --notification-warning-bg: #92400e; + --notification-warning-border: #f59e0b; + --notification-warning-icon: #fbbf24; + + --notification-close-button: #9ca3af; + --notification-close-button-hover: #d1d5db; + --notification-close-button-bg-hover: rgba(156, 163, 175, 0.1); + + --tooltip-bg: #1f2937; + --tooltip-text: #e5e7eb; + + /* Button colors - dark mode */ + --button-bg: #374151; + --button-secondary-bg: #374151; + --button-secondary-text: #e5e7eb; + --button-secondary-hover-bg: #4b5563; + --button-secondary-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + --button-secondary-hover-shadow: 0 4px 12px rgba(0, 0, 0, 0.6); + + /* Input colors - dark mode */ + --input-bg: #374151; + --input-text: #e5e7eb; + --input-border: #4b5563; + --input-placeholder: #9ca3af; + + /* Chip colors - dark mode */ + --chip-bg: #1e3a8a; + --chip-text: #93c5fd; + --chip-border: #3b82f6; + --chip-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + --chip-hover-bg: #1e40af; + --chip-hover-border: #60a5fa; + --chip-active-bg: #1d4ed8; + --chip-default-bg: #4b5563; + --chip-default-text: #d1d5db; + --chip-default-border: #6b7280; + + /* Dropdown colors - dark mode */ + --dropdown-bg: #374151; + --dropdown-border: #4b5563; + --dropdown-shadow: 0 4px 6px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2); + --dropdown-divider: #4b5563; + --dropdown-hover-bg: #4b5563; + --dropdown-active-bg: #1e3a8a; + --dropdown-selected-bg: #1e3a8a; + --dropdown-selected-hover-bg: #1e40af; + + /* TimeCard colors - dark mode */ + --timecard-bg: #374151; + --timecard-text: #e5e7eb; + --timecard-border: #4b5563; + --timecard-hover-bg: #4b5563; + --timecard-active-bg: #6b7280; + --timecard-active-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + --timecard-selected-shadow: 0 2px 8px rgba(59, 130, 246, 0.5); + --timecard-muted-text: #9ca3af; + --timecard-secondary-text: #d1d5db; + --timecard-unavailable-bg: #4b5563; + --timecard-unavailable-text: #6b7280; + --timecard-unavailable-border: #6b7280; + + /* Modal colors - dark mode */ + --modal-bg: #1f2937; + --modal-display-bg: #374151; + --modal-display-border: #4b5563; + --modal-cancel-bg: #374151; + --modal-cancel-text: #d1d5db; + --modal-cancel-border: #4b5563; + --modal-cancel-hover-bg: #4b5563; + --modal-cancel-hover-border: #6b7280; + --modal-cancel-active-bg: #6b7280; + --modal-save-bg: #059669; + --modal-save-text: white; + --modal-save-border: #047857; + --modal-save-shadow: 0 2px 4px rgba(5, 150, 105, 0.3); + --modal-save-hover-bg: #047857; + --modal-save-hover-shadow: 0 4px 8px rgba(5, 150, 105, 0.4); + --modal-save-active-bg: #065f46; + --modal-save-active-shadow: 0 1px 2px rgba(5, 150, 105, 0.3); + + /* Button disabled states - dark mode */ + --button-disabled-bg: #374151; + --button-disabled-text: #6b7280; + --button-disabled-border: #4b5563; + + /* Additional color variants - dark mode */ + --color-primary-dark: #1d4ed8; + --color-white-transparent: rgba(255, 255, 255, 0.8); + --color-white-transparent-low: rgba(255, 255, 255, 0.2); + + /* Header colors - dark mode */ + --header-brand-color: #ffffff; + + /* Filter colors - dark mode */ + --filter-button-bg: #374151; + --filter-button-text: #d1d5db; + --filter-button-border: #4b5563; + --filter-button-hover-bg: #4b5563; + --filter-button-hover-border: #6b7280; + --filter-button-active-bg: #6b7280; + --filter-active-bg: #1e3a8a; + --filter-active-text: #93c5fd; + --filter-active-border: #3b82f6; + --filter-active-hover-bg: #1e40af; + --filter-active-hover-border: #60a5fa; + --filter-chevron-color: #9ca3af; + --filter-content-bg: #374151; + --filter-content-border: #4b5563; + --filter-reset-divider: #4b5563; + + /* Reset button colors - dark mode */ + --reset-button-bg: #374151; + --reset-button-text: #f87171; + --reset-button-border: #dc2626; + --reset-button-hover-bg: #450a0a; + --reset-button-hover-text: #fca5a5; + --reset-button-hover-border: #b91c1c; + --reset-button-active-bg: #7f1d1d; + + /* Additional UI colors - dark mode */ + --border-light: #4b5563; + --border-medium: #6b7280; + --text-disabled: #6b7280; + --divider-color: #4b5563; + --button-mobile-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + --modal-footer-shadow: 0 -2px 8px rgba(0, 0, 0, 0.3); + + /* Modal specific colors - dark mode */ + --modal-border: rgba(75, 85, 99, 0.4); + --modal-shadow: 0 32px 64px rgba(0, 0, 0, 0.4), 0 16px 32px rgba(0, 0, 0, 0.3), 0 8px 16px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05); + --modal-dialog-bg: rgba(31, 41, 55, 0.95); + --modal-close-hover-bg: #4b5563; + + /* Dropdown chevron - dark mode */ + --dropdown-chevron-color: #9ca3af; + + /* Date picker chevron buttons - dark mode */ + --chevron-button-color: #e5e7eb; + --chevron-button-disabled-color: #6b7280; +} \ No newline at end of file