parent
3dd322475f
commit
0e769c3de6
3 changed files with 240 additions and 128 deletions
|
|
@ -7,69 +7,18 @@
|
|||
<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>">
|
||||
|
||||
<script async src="{{ url_for("static", filename="es-module-shims/es-module-shims.js") }}"></script>
|
||||
|
||||
<script type='importmap'>
|
||||
{
|
||||
"imports": {
|
||||
"@fullcalendar/core": "https://cdn.skypack.dev/@fullcalendar/core@6.1.9",
|
||||
"@fullcalendar/daygrid": "https://cdn.skypack.dev/@fullcalendar/daygrid@6.1.9",
|
||||
"@fullcalendar/timegrid": "https://cdn.skypack.dev/@fullcalendar/timegrid@6.1.9",
|
||||
"@fullcalendar/list": "https://cdn.skypack.dev/@fullcalendar/list@6.1.9",
|
||||
"@fullcalendar/core/locales/en-gb": "https://cdn.skypack.dev/@fullcalendar/core@6.1.9/locales/en-gb"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type='module'>
|
||||
import { Calendar } from '@fullcalendar/core'
|
||||
import dayGridPlugin from '@fullcalendar/daygrid'
|
||||
import timeGridPlugin from '@fullcalendar/timegrid'
|
||||
import listPlugin from '@fullcalendar/list'
|
||||
import gbLocale from '@fullcalendar/core/locales/en-gb';
|
||||
|
||||
// Function to save the current view to local storage
|
||||
function saveView(view) {
|
||||
localStorage.setItem('fullCalendarDefaultView', view);
|
||||
}
|
||||
|
||||
// Function to get the saved view from local storage
|
||||
function getSavedView() {
|
||||
return localStorage.getItem('fullCalendarDefaultView') || 'dayGridMonth';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const calendarEl = document.getElementById('calendar')
|
||||
const calendar = new Calendar(calendarEl, {
|
||||
locale: gbLocale,
|
||||
plugins: [dayGridPlugin, timeGridPlugin, listPlugin ],
|
||||
themeSystem: 'bootstrap5',
|
||||
firstDay: 1,
|
||||
initialView: getSavedView(),
|
||||
viewDidMount: function(info) {
|
||||
saveView(info.view.type);
|
||||
},
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
|
||||
},
|
||||
nowIndicator: true,
|
||||
weekNumbers: true,
|
||||
eventTimeFormat: {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
},
|
||||
events: {{ fullcalendar_events | tojson(indent=2) }},
|
||||
eventDidMount: function(info) {
|
||||
info.el.title = info.event.title;
|
||||
},
|
||||
})
|
||||
calendar.render()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<!-- 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 = {
|
||||
|
|
@ -91,16 +40,6 @@
|
|||
}
|
||||
%}
|
||||
|
||||
{%set class_map = {
|
||||
"bank_holiday": "bg-success-subtle",
|
||||
"conference": "bg-primary-subtle",
|
||||
"us_holiday": "bg-secondary-subtle",
|
||||
"birthday": "bg-info-subtle",
|
||||
"waste_schedule": "bg-danger-subtle",
|
||||
} %}
|
||||
|
||||
|
||||
|
||||
{% from "navbar.html" import navbar with context %}
|
||||
<body>
|
||||
{{ navbar() }}
|
||||
|
|
@ -108,7 +47,7 @@
|
|||
<div class="container-fluid mt-2">
|
||||
<h1>Agenda</h1>
|
||||
<p>
|
||||
<a href="/tools">← personal tools</a>
|
||||
<a href="/tools">← personal tools</a>
|
||||
</p>
|
||||
|
||||
{% if errors %}
|
||||
|
|
@ -126,8 +65,25 @@
|
|||
| <a href="{{ url_for(request.endpoint, markets="hide") }}">Hide all</a>
|
||||
</div>
|
||||
|
||||
<div class="mb-3" id="calendar"></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>
|
||||
|
|
@ -137,11 +93,137 @@
|
|||
{% 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
|
||||
// We've removed `visibleWeeksCount: 6` to allow the calendar
|
||||
// to dynamically show 4, 5, or 6 weeks as needed.
|
||||
},
|
||||
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 tzDate = calendar.getDate();
|
||||
const nativeDate = tzDate.toDate();
|
||||
|
||||
const year = nativeDate.getFullYear();
|
||||
const monthName = nativeDate.toLocaleDateString('en-GB', { month: 'long' });
|
||||
|
||||
calendarTitle.textContent = `${monthName} ${year}`;
|
||||
}
|
||||
|
||||
// --- CORRECTED NAVIGATION LOGIC ---
|
||||
prevBtn.addEventListener('click', () => {
|
||||
const currentDate = calendar.getDate().toDate();
|
||||
// Go to the previous month
|
||||
currentDate.setMonth(currentDate.getMonth() - 1);
|
||||
// **Crucially, set the day to the 1st to align the view**
|
||||
currentDate.setDate(1);
|
||||
calendar.setDate(currentDate);
|
||||
updateCalendarTitle();
|
||||
});
|
||||
|
||||
nextBtn.addEventListener('click', () => {
|
||||
const currentDate = calendar.getDate().toDate();
|
||||
// Go to the next month
|
||||
currentDate.setMonth(currentDate.getMonth() + 1);
|
||||
// **Crucially, set the day to the 1st to align the view**
|
||||
currentDate.setDate(1);
|
||||
calendar.setDate(currentDate);
|
||||
updateCalendarTitle();
|
||||
});
|
||||
|
||||
todayBtn.addEventListener('click', () => {
|
||||
calendar.today();
|
||||
updateCalendarTitle();
|
||||
});
|
||||
|
||||
monthViewBtn.addEventListener('click', () => calendar.changeView('month'));
|
||||
weekViewBtn.addEventListener('click', () => calendar.changeView('week'));
|
||||
dayViewBtn.addEventListener('click', () => calendar.changeView('day'));
|
||||
|
||||
// Initial setup
|
||||
updateCalendarTitle();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue