agenda/templates/calendar.html

267 lines
9.5 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Agenda - Edward Betts</title>
<link href="{{ url_for("static", filename="bootstrap5/css/bootstrap.min.css") }}" rel="stylesheet">
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📅</text></svg>">
<!-- TOAST UI Calendar CSS -->
<link rel="stylesheet" href="https://uicdn.toast.com/calendar/latest/toastui-calendar.min.css" />
<style>
/* Custom styles to better integrate with Bootstrap */
.toastui-calendar-layout {
border: 1px solid #dee2e6;
border-radius: 0.375rem;
}
#calendar-header {
margin-bottom: 1rem;
}
</style>
</head>
{% set event_labels = {
"economist": "📰 The Economist",
"mothers_day": "Mothers' day",
"fathers_day": "Fathers' day",
"uk_financial_year_end": "End of financial year",
"bank_holiday": "UK bank holiday",
"us_holiday": "US holiday",
"uk_clock_change": "UK clock change",
"us_clock_change": "US clock change",
"us_presidential_election": "US pres. election",
"xmas_last_second": "Christmas last posting 2nd class",
"xmas_last_first": "Christmas last posting 1st class",
"up_series": "Up documentary",
"waste_schedule": "Waste schedule",
"gwr_advance_tickets": "GWR advance tickets",
"critical_mass": "Critical Mass",
}
%}
{% from "navbar.html" import navbar with context %}
<body>
{{ navbar() }}
<div class="container-fluid mt-2">
<h1>Agenda</h1>
<p>
<a href="/tools">← personal tools</a>
</p>
{% if errors %}
{% for error in errors %}
<div class="alert alert-danger" role="alert">
Error: {{ error }}
</div>
{% endfor %}
{% endif %}
<div>
Markets:
<a href="{{ url_for(request.endpoint) }}">Hide while away</a>
| <a href="{{ url_for(request.endpoint, markets="show") }}">Show all</a>
| <a href="{{ url_for(request.endpoint, markets="hide") }}">Hide all</a>
</div>
<!-- Header for calendar controls -->
<div id="calendar-header" class="d-flex justify-content-between align-items-center mt-3">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" id="prevBtn">Prev</button>
<button type="button" class="btn btn-primary" id="nextBtn">Next</button>
<button type="button" class="btn btn-outline-primary" id="todayBtn">Today</button>
</div>
<h3 id="calendar-title" class="mb-0"></h3>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-primary" id="monthViewBtn">Month</button>
<button type="button" class="btn btn-outline-primary" id="weekViewBtn">Week</button>
<button type="button" class="btn btn-outline-primary" id="dayViewBtn">Day</button>
</div>
</div>
<div class="mb-3" id="calendar" style="height: 80vh;"></div>
{#
<div class="mt-2">
<h5>Page generation time</h5>
<ul>
<li>Data gather took {{ "%.1f" | format(data_gather_seconds) }} seconds</li>
<li>Stock market open/close took
{{ "%.1f" | format(stock_market_times_seconds) }} seconds</li>
{% for name, seconds in timings %}
<li>{{ name }} took {{ "%.1f" | format(seconds) }} seconds</li>
{% endfor %}
</ul>
</div>
#}
</div>
<!-- TOAST UI Calendar JS -->
<script src="https://uicdn.toast.com/calendar/latest/toastui-calendar.min.js"></script>
<script src="{{ url_for("static", filename="bootstrap5/js/bootstrap.bundle.min.js") }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const Calendar = tui.Calendar;
const container = document.getElementById('calendar');
// --- Configuration ---
const calendars = {{ toastui_calendars | tojson }};
const events = {{ toastui_events | tojson }};
function getSavedView() {
return localStorage.getItem('toastUiCalendarDefaultView') || 'month';
}
function saveView(view) {
localStorage.setItem('toastUiCalendarDefaultView', view);
}
const options = {
defaultView: getSavedView(),
useDetailPopup: true,
useCreationPopup: false,
calendars: calendars,
week: {
startDayOfWeek: 1, // Monday
taskView: false,
eventView: ['time'],
showNowIndicator: true,
},
month: {
startDayOfWeek: 1, // Monday
},
timezone: {
zones: [{
timezoneName: Intl.DateTimeFormat().resolvedOptions().timeZone
}]
},
template: {
allday(event) {
return `<span title="${event.title}">${event.title}</span>`;
},
time(event) {
return `<span title="${event.title}">${event.title}</span>`;
},
},
};
const calendar = new Calendar(container, options);
calendar.createEvents(events);
// --- Event Handlers ---
calendar.on('clickEvent', ({ event }) => {
if (event.raw && event.raw.url) {
window.open(event.raw.url, '_blank');
}
});
calendar.on('afterRenderEvent', () => {
const currentView = calendar.getViewName();
saveView(currentView);
updateCalendarTitle();
});
// --- UI Control Logic ---
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const todayBtn = document.getElementById('todayBtn');
const monthViewBtn = document.getElementById('monthViewBtn');
const weekViewBtn = document.getElementById('weekViewBtn');
const dayViewBtn = document.getElementById('dayViewBtn');
const calendarTitle = document.getElementById('calendar-title');
function updateCalendarTitle() {
const currentView = calendar.getViewName();
const currentDate = calendar.getDate().toDate();
let titleText = '';
if (currentView === 'month') {
const year = currentDate.getFullYear();
const monthName = currentDate.toLocaleDateString('en-GB', { month: 'long' });
titleText = `${monthName} ${year}`;
} else if (currentView === 'week') {
// Manually calculate the start and end of the week
const startDayOfWeek = options.week.startDayOfWeek; // 1 for Monday
const day = currentDate.getDay(); // 0 for Sunday, 1 for Monday...
// Calculate days to subtract to get to the start of the week
const offset = (day - startDayOfWeek + 7) % 7;
const startDate = new Date(currentDate);
startDate.setDate(currentDate.getDate() - offset);
const endDate = new Date(startDate);
endDate.setDate(startDate.getDate() + 6);
const startMonth = startDate.toLocaleDateString('en-GB', { month: 'short' });
const endMonth = endDate.toLocaleDateString('en-GB', { month: 'short' });
if (startMonth === endMonth) {
titleText = `${startDate.getDate()} - ${endDate.getDate()} ${startMonth} ${startDate.getFullYear()}`;
} else {
titleText = `${startDate.getDate()} ${startMonth} - ${endDate.getDate()} ${endMonth} ${startDate.getFullYear()}`;
}
} else { // Day view
titleText = currentDate.toLocaleDateString('en-GB', { dateStyle: 'full' });
}
calendarTitle.textContent = titleText;
}
// --- View-aware navigation logic (no changes here) ---
prevBtn.addEventListener('click', () => {
const currentView = calendar.getViewName();
if (currentView === 'month') {
const currentDate = calendar.getDate().toDate();
currentDate.setMonth(currentDate.getMonth() - 1);
currentDate.setDate(1);
calendar.setDate(currentDate);
} else {
calendar.prev();
}
updateCalendarTitle();
});
nextBtn.addEventListener('click', () => {
const currentView = calendar.getViewName();
if (currentView === 'month') {
const currentDate = calendar.getDate().toDate();
currentDate.setMonth(currentDate.getMonth() + 1);
currentDate.setDate(1);
calendar.setDate(currentDate);
} else {
calendar.next();
}
updateCalendarTitle();
});
todayBtn.addEventListener('click', () => {
calendar.today();
updateCalendarTitle();
});
monthViewBtn.addEventListener('click', () => {
calendar.changeView('month');
updateCalendarTitle();
});
weekViewBtn.addEventListener('click', () => {
calendar.changeView('week');
updateCalendarTitle();
});
dayViewBtn.addEventListener('click', () => {
calendar.changeView('day');
updateCalendarTitle();
});
// Initial setup
updateCalendarTitle();
});
</script>
</body>
</html>