feat: улучшить учебные периоды и просмотр расписаний
This commit is contained in:
@@ -29,6 +29,33 @@ const SEMESTER_LABELS = {
|
||||
|
||||
const WHOLE_GROUP_SUBGROUP_VALUE = '__whole_group__';
|
||||
const ACADEMIC_HOURS_PER_SLOT = 2;
|
||||
const VISUAL_MENU_GAP = 8;
|
||||
const VISUAL_MENU_VIEWPORT_PADDING = 8;
|
||||
|
||||
export function calculateVisualContextMenuPosition({
|
||||
anchorRect,
|
||||
menuWidth,
|
||||
menuHeight,
|
||||
viewportWidth,
|
||||
viewportHeight
|
||||
}) {
|
||||
const maxLeft = Math.max(VISUAL_MENU_VIEWPORT_PADDING, viewportWidth - menuWidth - VISUAL_MENU_VIEWPORT_PADDING);
|
||||
const maxTop = Math.max(VISUAL_MENU_VIEWPORT_PADDING, viewportHeight - menuHeight - VISUAL_MENU_VIEWPORT_PADDING);
|
||||
let left = anchorRect.right + VISUAL_MENU_GAP;
|
||||
let top = anchorRect.top;
|
||||
|
||||
if (left > maxLeft) {
|
||||
left = anchorRect.left - menuWidth - VISUAL_MENU_GAP;
|
||||
}
|
||||
if (top > maxTop) {
|
||||
top = anchorRect.bottom - menuHeight;
|
||||
}
|
||||
|
||||
return {
|
||||
left: Math.round(Math.max(VISUAL_MENU_VIEWPORT_PADDING, Math.min(left, maxLeft))),
|
||||
top: Math.round(Math.max(VISUAL_MENU_VIEWPORT_PADDING, Math.min(top, maxTop)))
|
||||
};
|
||||
}
|
||||
|
||||
export function scheduleSlotActionLabel(slotCount) {
|
||||
return slotCount === 1 ? 'Очистить' : 'Удалить';
|
||||
@@ -160,6 +187,7 @@ export async function initSchedule() {
|
||||
let syncingVisualPeriod = false;
|
||||
let pendingConflictResolution = null;
|
||||
let visualContextTarget = null;
|
||||
let visualContextMenuPositionAnimation = null;
|
||||
let pendingSlotMove = null;
|
||||
let creatingDraft = false;
|
||||
|
||||
@@ -207,6 +235,7 @@ export async function initSchedule() {
|
||||
visualSemesterSelect?.addEventListener('change', handleVisualSemesterChange);
|
||||
visualGroupFilter?.addEventListener('change', handleVisualGroupFilterChange);
|
||||
visualStage?.addEventListener('click', handleVisualStageClick);
|
||||
visualDrawer?.addEventListener('scroll', closeVisualContextMenu, true);
|
||||
conflictCloseButton?.addEventListener('click', closeConflictModal);
|
||||
conflictCancelButton?.addEventListener('click', closeConflictModal);
|
||||
conflictModal?.addEventListener('click', (event) => {
|
||||
@@ -555,6 +584,7 @@ export async function initSchedule() {
|
||||
|
||||
function closeVisualDrawer() {
|
||||
if (!visualDrawer) return;
|
||||
closeVisualContextMenu();
|
||||
visualDrawer.classList.remove('open');
|
||||
visualDrawer.setAttribute('aria-hidden', 'true');
|
||||
visualToggleButton?.classList.remove('open');
|
||||
@@ -882,6 +912,23 @@ export async function initSchedule() {
|
||||
};
|
||||
if (!visualContextMenu) return;
|
||||
visualContextMenu.hidden = false;
|
||||
const anchorRect = button.getBoundingClientRect();
|
||||
const position = calculateVisualContextMenuPosition({
|
||||
anchorRect,
|
||||
menuWidth: visualContextMenu.offsetWidth,
|
||||
menuHeight: visualContextMenu.offsetHeight,
|
||||
viewportWidth: window.innerWidth,
|
||||
viewportHeight: window.innerHeight
|
||||
});
|
||||
visualContextMenuPositionAnimation?.cancel();
|
||||
const positionedTransform = `translate3d(${position.left}px, ${position.top}px, 0)`;
|
||||
visualContextMenuPositionAnimation = visualContextMenu.animate(
|
||||
[
|
||||
{ transform: positionedTransform },
|
||||
{ transform: positionedTransform }
|
||||
],
|
||||
{ duration: 1, fill: 'forwards' }
|
||||
);
|
||||
visualContextMenu.querySelector('button')?.focus();
|
||||
}
|
||||
|
||||
@@ -889,6 +936,8 @@ export async function initSchedule() {
|
||||
visualContextTarget = null;
|
||||
if (!visualContextMenu) return;
|
||||
visualContextMenu.hidden = true;
|
||||
visualContextMenuPositionAnimation?.cancel();
|
||||
visualContextMenuPositionAnimation = null;
|
||||
}
|
||||
|
||||
async function handleVisualContextMenuClick(event) {
|
||||
|
||||
Reference in New Issue
Block a user