turf-tasker/Views/LawnCareEvents/Calendar.cshtml
Blake Ridgway 557fb72081 feat: Enhance UI/UX across multiple views with consistent styling and improved layout
This commit introduces significant user interface and experience improvements across the Lawn Care Log, Calendar, and Lawn Tips sections, focusing on consistent button styling, improved layout, and clearer navigation.

**Key Changes:**

*   **Lawn Care Event Models:**
    *   Added `NotApplicable` to `MowingPattern` enum with `[Display(Name = "N/A")]` for better logging flexibility.

*   **Lawn Care Log (`Views/LawnCareEvents/Index.cshtml`):**
    *   **Centered Page Title & Actions:** Wrapped `<h1>` and primary action buttons (`Create New Event`, `View Calendar`) in a `div` with `text-center` for better alignment.
    *   **Improved Search Bar Layout:** Encapsulated the search input and buttons in an `input-group` within a flex container (`d-flex justify-content-end`) with fixed width and auto margins, ensuring it's centered as a block but right-aligned internally.
    *   **Convert Table Actions to Buttons:** Replaced "Edit | Details | Delete" links in the main log table with `btn-sm btn-outline-primary/info/danger` styled buttons, wrapped in `d-flex flex-wrap gap-2` for consistent spacing and responsive behavior.
    *   Renamed "Back to Full List" to "Reset Filter" for clarity and changed its style to `btn-primary`.

*   **Lawn Care Calendar (`Views/LawnCareEvents/Calendar.cshtml`):**
    *   **Centralized Title & Button:** Implemented a flexbox container (`d-flex justify-content-between align-items-center`) for the calendar's page title and the "Create New Event" button, ensuring they are on the same line and properly spaced.
    *   **Restored JavaScript Integrity:** Re-structured the top-level HTML to ensure the calendar's internal JavaScript (`#prevMonth`, `#nextMonth`, `#currentMonthYear`) remains unaffected by the page title/button layout changes.

*   **Lawn Care Tips (`Views/LawnCareTip/Index.cshtml`):**
    *   **Consolidated Actions:** Converted "Edit | Details | Delete" links in the tips table into Bootstrap buttons (`btn-sm btn-outline-primary/info/danger`).
    *   **Improved Action Column Layout:** Applied new `.col-actions` CSS to the action column (`<th>` and `<td>`) to give it a fixed width and use `white-space: nowrap` to prevent action buttons from wrapping.
    *   **Content Column Wrapping:** Added `.col-content` CSS to the content column to limit its max-width and allow `word-wrap`.
    *   Changed "Create New" to "Create New Tip" with `btn-primary` styling for consistency.
    *   **Removed Details Link from Tips:** (Implied by diff) The Details link for `LawnCareTip` was removed from the table view, aligning with a common pattern where simple tip content might be fully displayed or only Edit/Delete actions are prioritized in the index.

*   **Global Styling (`wwwroot/css/site.css`):**
    *   Added `col-content` and `col-actions` CSS classes to manage table column widths and wrapping behavior for cleaner table layouts.

These changes significantly improve the aesthetic consistency and usability of the application's main views.
2025-06-18 21:32:44 -05:00

137 lines
No EOL
5.3 KiB
Text

@{
ViewData["Title"] = "Lawn Care Calendar";
}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>@ViewData["Title"]</h1>
<a asp-action="Create" asp-controller="LawnCareEvents" class="btn btn-primary">
<i class="bi bi-plus-circle-fill"></i> Create New Event
</a>
</div>
<div class="calendar-container">
<div class="calendar-header">
<button id="prevMonth" class="btn btn-secondary">&lt; Prev</button>
<h2 id="currentMonthYear"></h2>
<button id="nextMonth" class="btn btn-secondary">Next &gt;</button>
</div>
<div class="calendar-grid">
<div class="day-name">Sun</div>
<div class="day-name">Mon</div>
<div class="day-name">Tue</div>
<div class="day-name">Wed</div>
<div class="day-name">Thu</div>
<div class="day-name">Fri</div>
<div class="day-name">Sat</div>
</div>
<div id="calendarDays" class="calendar-grid">
</div>
</div>
@section Scripts {
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
const calendarDaysEl = $('#calendarDays');
const currentMonthYearEl = $('#currentMonthYear');
const prevMonthBtn = $('#prevMonth');
const nextMonthBtn = $('#nextMonth');
let currentMonth = new Date().getMonth();
let currentYear = new Date().getFullYear();
let allEvents = [];
function renderCalendar(month, year) {
calendarDaysEl.empty();
currentMonthYearEl.text(new Date(year, month).toLocaleString('default', { month: 'long', year: 'numeric' }));
const firstDayOfMonth = new Date(year, month, 1);
const lastDayOfMonth = new Date(year, month + 1, 0);
const daysInMonth = lastDayOfMonth.getDate();
const startDayOfWeek = firstDayOfMonth.getDay();
const prevMonthLastDay = new Date(year, month, 0).getDate();
for (let i = startDayOfWeek; i > 0; i--) {
const dayNum = prevMonthLastDay - i + 1;
calendarDaysEl.append(`<div class="calendar-day other-month"><span class="day-number">${dayNum}</span></div>`);
}
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(year, month, day);
const dateString = date.toISOString().split('T')[0];
let dayHtml = `<div class="calendar-day" data-date="${dateString}">`;
dayHtml += `<span class="day-number">${day}</span>`;
const eventsOnThisDay = allEvents.filter(event => event.start === dateString);
eventsOnThisDay.forEach(event => {
const typeClass = event.title.split(' ')[0].toLowerCase().replace(/[^a-z0-9]/g, '');
dayHtml += `<div class="event-indicator ${typeClass}" data-event-id="${event.id}" data-event-url="${event.url}">${event.title}</div>`;
});
dayHtml += `</div>`;
calendarDaysEl.append(dayHtml);
}
const totalDaysDisplayed = startDayOfWeek + daysInMonth;
const remainingCells = 42 - totalDaysDisplayed;
for (let i = 1; i <= remainingCells && totalDaysDisplayed + i <= 42; i++) {
calendarDaysEl.append(`<div class="calendar-day other-month"><span class="day-number">${i}</span></div>`);
}
$('.calendar-day .event-indicator').on('click', function (e) {
e.stopPropagation();
const url = $(this).data('event-url');
if (url) {
window.location.href = url;
}
});
$('.calendar-day:not(.other-month)').on('click', function () {
const date = $(this).data('date');
window.location.href = `/LawnCareEvents/Create?date=${date}`;
});
}
async function fetchEvents() {
try {
const response = await fetch('/LawnCareEvents/GetEventsJson');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
allEvents = await response.json();
renderCalendar(currentMonth, currentYear);
} catch (error) {
console.error('Error fetching events:', error);
}
}
prevMonthBtn.on('click', function () {
currentMonth--;
if (currentMonth < 0) {
currentMonth = 11;
currentYear--;
}
renderCalendar(currentMonth, currentYear);
});
nextMonthBtn.on('click', function () {
currentMonth++;
if (currentMonth > 11) {
currentMonth = 0;
currentYear++;
}
renderCalendar(currentMonth, currentYear);
});
fetchEvents();
});
</script>
}
@section Styles {
<link href="~/css/calendar.css" rel="stylesheet" asp-append-version="true" />
}