diff --git a/Aberwyn/Data/MenuService.cs b/Aberwyn/Data/MenuService.cs index 1fe5b7e..c22bf2d 100644 --- a/Aberwyn/Data/MenuService.cs +++ b/Aberwyn/Data/MenuService.cs @@ -141,7 +141,7 @@ namespace Aberwyn.Data using (var connection = GetConnection()) { connection.Open(); - string query = "SELECT Id, Name FROM Meals"; + string query = "SELECT Id, Name, ImageUrl FROM Meals"; using (var cmd = new MySqlCommand(query, connection)) { using (var reader = cmd.ExecuteReader()) @@ -151,7 +151,8 @@ namespace Aberwyn.Data meals.Add(new Meal { Id = reader.GetInt32("Id"), - Name = reader.GetString("Name") + Name = reader.GetString("Name"), + ImageUrl = reader.IsDBNull(reader.GetOrdinal("ImageUrl")) ? null : reader.GetString(reader.GetOrdinal("ImageUrl")) }); } } @@ -167,7 +168,7 @@ namespace Aberwyn.Data { connection.Open(); string query = @" - SELECT Id, Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt + SELECT Id, Name, Description, ProteinType, CarbType, RecipeUrl, CreatedAt, ImageUrl FROM Meals ORDER BY CreatedAt DESC"; @@ -184,6 +185,7 @@ namespace Aberwyn.Data ProteinType = reader.IsDBNull(reader.GetOrdinal("ProteinType")) ? null : reader.GetString(reader.GetOrdinal("ProteinType")), CarbType = reader.IsDBNull(reader.GetOrdinal("CarbType")) ? null : reader.GetString(reader.GetOrdinal("CarbType")), RecipeUrl = reader.IsDBNull(reader.GetOrdinal("RecipeUrl")) ? null : reader.GetString(reader.GetOrdinal("RecipeUrl")), + ImageUrl = reader.IsDBNull(reader.GetOrdinal("ImageUrl")) ? null : reader.GetString(reader.GetOrdinal("ImageUrl")), CreatedAt = reader.GetDateTime(reader.GetOrdinal("CreatedAt")) }); } diff --git a/Aberwyn/Views/Home/Menu.cshtml b/Aberwyn/Views/Home/Menu.cshtml index 1ef2936..426d49e 100644 --- a/Aberwyn/Views/Home/Menu.cshtml +++ b/Aberwyn/Views/Home/Menu.cshtml @@ -1,61 +1,33 @@ -@model Aberwyn.Models.MenuViewModel - -@{ - var hideSidebar = Context.Request.Path.Value.EndsWith("/nosidebar", StringComparison.OrdinalIgnoreCase); - Layout = hideSidebar ? null : "_Layout"; -} - + - - Veckomeny + + Veckomeny - - - - + + + - - - + -
+

Veckomeny

-
Vecka {{selectedWeek}} – {{selectedYear}}
-
- - + + +
-
-
Inte bestämd
+
+ Inte bestämd +
-
+
{{day}}
Frukost: {{menu[day].breakfastMealName}}
diff --git a/Aberwyn/wwwroot/css/Veckomeny.css b/Aberwyn/wwwroot/css/Veckomeny.css index 98ca523..147e6a7 100644 --- a/Aberwyn/wwwroot/css/Veckomeny.css +++ b/Aberwyn/wwwroot/css/Veckomeny.css @@ -127,7 +127,8 @@ /* Dag-cell med ikonknapp */ .day-cell { - max-width: 0px; + min-width: 25px; + max-width: 20px; padding: 8px 12px; font-weight: bold; vertical-align: top; diff --git a/Aberwyn/wwwroot/css/meal-menu.css b/Aberwyn/wwwroot/css/meal-menu.css deleted file mode 100644 index eab75de..0000000 --- a/Aberwyn/wwwroot/css/meal-menu.css +++ /dev/null @@ -1,214 +0,0 @@ -/* Meal Menu Page Styles */ -.meal-menu-page { - background-color: #2A3A48; /* Dark background to match theme */ - padding: 30px 60px; /* Add more padding to the sides */ - border-radius: 12px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); - max-width: 900px; /* Adjust width to provide more space */ - margin: 0 auto; - color: #B0BEC5; /* Light gray text */ -} - - .meal-menu-page h1 { - font-size: 2rem; - text-align: center; - color: #FFFFFF; - margin-bottom: 20px; - } - -/* Date Picker */ -.date-picker { - display: flex; - justify-content: center; - align-items: center; - margin-bottom: 30px; - gap: 20px; -} - - .date-picker span { - font-size: 1.2rem; - color: #B0BEC5; - } - - .date-picker button { - background-color: #4A6572; - color: #ffffff; - padding: 12px 25px; - border: none; - border-radius: 8px; - cursor: pointer; - font-size: 1rem; - transition: background-color 0.3s; - } - - .date-picker button:hover { - background-color: #3A4E62; - } - -/* Mode Toggle */ -.mode-toggle { - text-align: center; - margin-bottom: 30px; -} - - .mode-toggle button { - background-color: #4CAF50; - color: #ffffff; - padding: 12px 20px; - border: none; - border-radius: 8px; - cursor: pointer; - font-size: 1rem; - transition: background-color 0.3s; - } - - .mode-toggle button:hover { - background-color: #45a049; - } - -/* Meal Menu Container - Vertical Layout */ -.meal-menu-container { - display: flex; - flex-direction: column; /* Align the days vertically */ - gap: 20px; - justify-content: flex-start; -} - -/* Day Block Styling */ -.day-block { - background-color: #1F2C3C; /* Darker background for day blocks */ - padding: 20px; - border-radius: 10px; - width: 100%; - text-align: center; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); -} - -/* Day Header with Line */ -.day-header { - font-size: 1.5rem; - font-weight: bold; - margin-bottom: 15px; - color: #FFEB3B; /* Brighter yellow for the text */ - position: relative; /* Allows absolute positioning for the line */ -} - - .day-header::after { - content: ""; - position: absolute; - bottom: 0; /* Place it at the bottom of the header */ - left: 0; - width: 100%; /* Make the line span across the header */ - height: 2px; /* Thickness of the line */ - background-color: #FFEB3B; /* Yellow line for contrast */ - border-radius: 2px; /* Rounded corners for the line */ - } - -/* Meal Selection */ -.meal-selection { - font-size: 1rem; - color: #B0BEC5; - margin-bottom: 10px; -} - - .meal-selection strong { - color: #FFFFFF; - } - - .meal-selection span { - color: #FFEB3B; /* Highlight the meal names */ - } - -/* Edit Mode Styling */ -.edit-mode select { - background-color: #444; - color: #fff; - border: none; - padding: 10px; - border-radius: 6px; - width: 100%; - font-size: 1rem; - margin-top: 5px; - cursor: pointer; -} - - .edit-mode select:focus { - outline: none; - box-shadow: 0 0 8px rgba(66, 133, 244, 0.8); - } - -/* Save Button */ -.save-menu-button { - display: block; - background-color: #FF9800; - color: #fff; - padding: 12px 25px; - border: none; - border-radius: 8px; - cursor: pointer; - font-size: 1rem; - width: 200px; - margin: 30px auto; - text-align: center; - transition: background-color 0.3s; -} - - .save-menu-button:hover { - background-color: #F57C00; - } - -/* New Meal Form Styling */ -.new-meal-form { - display: flex; - flex-direction: column; /* Stack input fields vertically */ - gap: 15px; /* Space between fields */ - padding: 20px; - background-color: #1F2C3C; /* Dark background to match theme */ - border-radius: 10px; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); - max-width: 400px; /* Control the width of the form */ - margin: 0 auto; -} - - /* Input Fields */ - .new-meal-form input, - .new-meal-form select, - .new-meal-form textarea { - background-color: #444; /* Dark background for inputs */ - color: #fff; /* White text */ - border: none; - padding: 12px 15px; - border-radius: 6px; - font-size: 1rem; - width: 100%; /* Ensure inputs take full width */ - } - - /* Focused Input Fields */ - .new-meal-form input:focus, - .new-meal-form select:focus, - .new-meal-form textarea:focus { - outline: none; - box-shadow: 0 0 8px rgba(66, 133, 244, 0.8); /* Blue focus highlight */ - } - - /* Submit Button */ - .new-meal-form button { - background-color: #FF9800; /* Button color */ - color: #fff; - padding: 12px 20px; - border: none; - border-radius: 8px; - cursor: pointer; - font-size: 1rem; - transition: background-color 0.3s; - width: 100%; /* Button takes full width */ - } - - /* Button Hover */ - .new-meal-form button:hover { - background-color: #F57C00; - } - -.meal-hover { - cursor: pointer; -} diff --git a/Aberwyn/wwwroot/css/menu.css b/Aberwyn/wwwroot/css/menu.css new file mode 100644 index 0000000..324140a --- /dev/null +++ b/Aberwyn/wwwroot/css/menu.css @@ -0,0 +1,204 @@ +:root { + --bg: #F9FAFB; + --bg-mid: #EDF2F7; + --text: #2D3748; + --accent: #3182CE; + --card-bg: #ffffff; + --border-radius: 10px; + --spacing: 20px; + --font-size: 1rem; + --faint-text: #718096; + --subtle-text: #4A5568; +} + +[data-theme="dark"] { + --bg: #1F2C3C; + --bg-mid: #2E3C4F; + --text: #E0E6ED; + --accent: #3182CE; + --card-bg: #2A3A48; + --faint-text: #A0AAB5; + --subtle-text: #D0DCE4; +} + +body { + margin: 0; + font-family: "Segoe UI", sans-serif; + background-color: var(--bg); + color: var(--text); +} + +.meal-menu-page { + position: relative; + padding: var(--spacing); + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + background: radial-gradient(circle at center, var(--bg-mid), var(--bg) 80%); +} + + .meal-menu-page > * { + position: relative; + z-index: 1; + width: 100%; + max-width: 960px; + } + +h1 { + font-size: 2rem; + margin-bottom: var(--spacing); + text-align: center; + color: var(--accent); +} + +.date-picker { + display: flex; + justify-content: center; + align-items: center; + gap: 1rem; + margin-bottom: var(--spacing); + font-size: var(--font-size); + color: var(--subtle-text); +} + + .date-picker button { + background: var(--accent); + border: none; + padding: 0.5rem 1rem; + border-radius: var(--border-radius); + cursor: pointer; + font-weight: bold; + color: #ffffff; + transition: background 0.2s ease; + } + + .date-picker button:hover { + background: #2B6CB0; + } + +.view-selector { + position: absolute; + top: var(--spacing); + right: var(--spacing); + display: flex; + align-items: center; + gap: 8px; +} + + .view-selector select { + display: none; + } + + .view-selector .toggle-view-btn, + .view-selector .theme-toggle-btn { + background: none; + border: none; + color: var(--text); + font-size: 1.2rem; + padding: 6px; + cursor: pointer; + border-radius: 4px; + transition: background-color 0.2s; + } + + .view-selector .toggle-view-btn:hover, + .view-selector .theme-toggle-btn:hover { + background-color: rgba(0, 0, 0, 0.1); + } + +.list-view .day-item { + background: var(--card-bg); + margin-bottom: var(--spacing); + padding: var(--spacing); + border-radius: var(--border-radius); +} + +.day-header { + font-size: 1.4rem; + color: var(--accent); + margin-bottom: 8px; + position: relative; +} + + .day-header::after { + content: ''; + position: absolute; + bottom: -4px; + left: 0; + width: 40px; + height: 3px; + background: var(--accent); + border-radius: 2px; + } + +.meal-selection { + margin: 6px 0; + font-size: 1rem; +} + + .meal-selection a { + color: var(--text); + text-decoration: none; + } + + .meal-selection a:hover { + text-decoration: underline; + } + +.not-assigned { + color: var(--faint-text); + font-style: italic; +} + +.card-view .card-container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: var(--spacing); +} + +.meal-card { + position: relative; + height: 200px; + color: #fff; + background-size: cover; + background-position: center; + border-radius: var(--border-radius); + overflow: hidden; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + display: flex; + align-items: flex-end; + cursor: pointer; +} + + .meal-card::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(to top, rgba(49, 130, 206, 0.3), rgba(0, 0, 0, 0.7), transparent); + pointer-events: none; + transition: opacity 0.3s ease; + opacity: 1; + } + + .meal-card[data-has-image="true"]::before { + opacity: 0; + } + +.card-content { + position: relative; + padding: 12px; + z-index: 1; + width: 100%; +} + + .card-content .day { + font-size: 1.2rem; + font-weight: bold; + margin-bottom: 6px; + } + + .card-content .meal { + font-size: 0.9rem; + line-height: 1.2; + } diff --git a/Aberwyn/wwwroot/images/meals/test_bbecaddf-0f4b-46c5-8666-62582e61de61.png b/Aberwyn/wwwroot/images/meals/test_bbecaddf-0f4b-46c5-8666-62582e61de61.png new file mode 100644 index 0000000..e39e4c9 Binary files /dev/null and b/Aberwyn/wwwroot/images/meals/test_bbecaddf-0f4b-46c5-8666-62582e61de61.png differ diff --git a/Aberwyn/wwwroot/js/menu.js b/Aberwyn/wwwroot/js/menu.js index 7b2a07a..777d272 100644 --- a/Aberwyn/wwwroot/js/menu.js +++ b/Aberwyn/wwwroot/js/menu.js @@ -1,4 +1,9 @@ -angular.module('mealMenuApp', ['ngSanitize']) +function setTheme(mode) { + document.documentElement.setAttribute('data-theme', mode); + localStorage.setItem('theme', mode); +} + +angular.module('mealMenuApp', ['ngSanitize']) .controller('MealMenuController', function ($scope, $http, $sce) { console.log("Controller initierad"); @@ -17,6 +22,7 @@ .then(res => { console.log("Måltider hämtade:", res.data); $scope.meals = res.data; + console.log("Alla måltider med bilder:", $scope.meals); return res; }) .catch(err => console.error("Fel vid hämtning av måltider:", err)); @@ -53,8 +59,10 @@ $scope.menu[day][type + 'MealId'] = item[idKey]; $scope.menu[day][type + 'MealName'] = m?.Name || item[nameKey] || 'Okänd rätt'; - if (m?.ImageUrl) { - $scope.menu[day].imageUrl = m.ImageUrl; + if (m?.ImageUrl && !$scope.menu[day].imageUrl) { + $scope.menu[day].imageUrl = m.ImageUrl.startsWith('/') + ? m.ImageUrl + : '/' + m.ImageUrl; } } }); @@ -71,7 +79,17 @@ $scope.getDayImage = function (day) { const item = $scope.menu[day]; - return (item && item.imageUrl) || '/images/default-meal.jpg'; + const img = item?.imageUrl; + + if (img && img.startsWith('/')) { + return img; + } + + if (img && !img.startsWith('/')) { + return '/' + img; // Fixa ev. saknad inledande snedstreck + } + + return '/images/default-meal.jpg'; }; $scope.getMealIdByDay = function (day) { @@ -106,10 +124,57 @@ const yearStart = new Date(d.getFullYear(), 0, 1); return Math.ceil((((d - yearStart) / 86400000) + 1) / 7); } + $scope.getViewIcon = function () { + return $scope.viewMode === 'list' ? '🗒️' : '▣'; + }; + + $scope.toggleView = function () { + $scope.viewMode = $scope.viewMode === 'list' ? 'card' : 'list'; + // Uppdatera knappens ikon + setTimeout(() => { + const btn = document.getElementById('toggle-view'); + if (btn) { + btn.textContent = $scope.getViewIcon(); + } + }, 0); + }; + console.log("Initierar måltidsladdning..."); $scope.loadMeals().then(() => { console.log("Laddar meny efter måltider..."); $scope.loadMenu(); + setTimeout(() => { + const viewBtn = document.getElementById('toggle-view'); + if (viewBtn) viewBtn.textContent = $scope.getViewIcon(); + }, 0); + }); }); +document.addEventListener("DOMContentLoaded", function () { + const themeBtn = document.getElementById('toggle-theme'); + const viewBtn = document.getElementById('toggle-view'); + + if (themeBtn) { + themeBtn.addEventListener('click', () => { + const current = document.documentElement.getAttribute('data-theme'); + const newTheme = current === 'dark' ? 'light' : 'dark'; + setTheme(newTheme); + themeBtn.textContent = newTheme === 'dark' ? '🌙' : '☀️'; + }); + } + + const saved = localStorage.getItem('theme'); + if (saved) { + setTheme(saved); + } else { + const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + setTheme(systemPrefersDark ? 'dark' : 'light'); + } + + // Initiera ikon för vy + const scope = angular.element(document.body).scope(); + if (viewBtn && scope) { + viewBtn.textContent = scope.viewMode === 'list' ? '🗒️' : '▣'; + } +});