From b5347e273280cd998051e534dddb95723610a6d6 Mon Sep 17 00:00:00 2001 From: Aden Linday Date: Fri, 24 Jul 2026 09:32:00 +0930 Subject: [PATCH] feat: minor fixes before update --- src/css/injected.scss | 48 +++++++- .../components/TabbedContainer.svelte | 7 +- .../timetable/CalendarSyncControl.svelte | 31 ++--- .../built-in/timetable/calendarSyncHost.css | 20 +--- .../built-in/timetable/calendarSyncUi.ts | 14 ++- src/seqta/ui/AddBetterSEQTAElements.ts | 25 +++- src/seqta/ui/sidebar/Sidebar.svelte | 36 +++++- src/seqta/ui/sidebar/SidebarItem.svelte | 46 ++++++-- src/seqta/ui/sidebar/mountCustomSidebar.ts | 60 +++++++++- src/seqta/ui/sidebar/sidebarState.svelte.ts | 43 +++++-- src/seqta/utils/Openers/whatsNewChangelog.ts | 2 +- .../utils/googleCalendar/eventMapper.test.ts | 25 ++++ src/seqta/utils/googleCalendar/eventMapper.ts | 14 ++- .../googleCalendar/fetchTimetable.test.ts | 54 +++++++++ .../utils/googleCalendar/fetchTimetable.ts | 109 +++++++++++++++++- src/seqta/utils/googleCalendar/types.ts | 1 + 16 files changed, 454 insertions(+), 81 deletions(-) create mode 100644 src/seqta/utils/googleCalendar/fetchTimetable.test.ts diff --git a/src/css/injected.scss b/src/css/injected.scss index f3221845..fd6a59ae 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -561,16 +561,32 @@ ul.magicDelete > li.deleting { display: flex !important; align-items: center; gap: 0.5rem; + width: calc(100% - 12px) !important; + max-width: none !important; + box-sizing: border-box !important; + padding: 0 !important; } -#menu.bsplus-sidebar-edit-mode .item.draggable > label { - flex: 1; - min-width: 0; +#menu.bsplus-sidebar-edit-mode .item.draggable > label:not(.toggle) { + flex: 1 1 0 !important; + width: 0 !important; + min-width: 0 !important; + max-width: none !important; } +#menu.bsplus-sidebar-edit-mode .item.draggable .label { + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + overflow-wrap: normal !important; +} + +#menu.bsplus-sidebar-edit-mode .item.draggable > .toggle, #menu.bsplus-sidebar-edit-mode .onoffswitch { pointer-events: auto !important; - flex-shrink: 0; + flex: 0 0 auto !important; + width: auto !important; + margin: 0 10px 0 0 !important; position: relative; z-index: 2; } @@ -655,6 +671,17 @@ html.bsplus-custom-sidebar-pending #menu > .icon-cover, height: 100%; z-index: 2; position: relative; + padding-top: 0 !important; + + /* + * Extend the logo spacer for the same gap as between items. + * SEQTA's #menu>ul::before border-bottom is the hairline under the logo. + */ + &::before { + box-shadow: none !important; + border-bottom: none !important; + height: calc(69.5px + 8px) !important; + } } li.hasChildren { @@ -667,7 +694,7 @@ html.bsplus-custom-sidebar-pending #menu > .icon-cover, pointer-events: auto !important; width: auto !important; max-width: none !important; - margin: 2px 6px !important; + margin: 0 6px 8px !important; box-sizing: border-box !important; } @@ -1044,6 +1071,12 @@ ol:has([class*="MessageList__avatar___"] svg) { -webkit-box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.2) !important; box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.2) !important; } +/* Custom sidebar: keep title depth to the right, not a hairline under the logo into the menu. */ +body:has(#menu.bsplus-custom-sidebar) #container #content #title, +body:has(#menu.bsplus-custom-sidebar).menuShown #container #content #title { + -webkit-box-shadow: 6px 0 8px -4px rgba(0, 0, 0, 0.25) !important; + box-shadow: 6px 0 8px -4px rgba(0, 0, 0, 0.25) !important; +} #main .timetablepage .quickbar { border: none; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5); @@ -1279,9 +1312,12 @@ html.transparencyEffects .assessmentsWrapper .message { display: none; } -#menu li:hover { +#menu li:hover:not(.active) { background: rgba(0, 0, 0, 0.15) !important; } +#menu li.active:hover { + background: rgba(0, 0, 0, 0.35) !important; +} #menu li:focus-visible, #menu section:focus-visible { diff --git a/src/interface/components/TabbedContainer.svelte b/src/interface/components/TabbedContainer.svelte index 853e0ac7..7d871d31 100644 --- a/src/interface/components/TabbedContainer.svelte +++ b/src/interface/components/TabbedContainer.svelte @@ -63,9 +63,12 @@ {#if activeTab === index}
-
+
{/if} diff --git a/src/plugins/built-in/timetable/CalendarSyncControl.svelte b/src/plugins/built-in/timetable/CalendarSyncControl.svelte index 7034fa4c..9fb1d369 100644 --- a/src/plugins/built-in/timetable/CalendarSyncControl.svelte +++ b/src/plugins/built-in/timetable/CalendarSyncControl.svelte @@ -327,12 +327,6 @@ if (menuEl) syncCalendarSyncTheme(menuEl); } - $effect(() => { - const host = rootEl?.closest(".timetable-calendar-controls"); - host?.classList.toggle("bsplus-cal-menu-open", menuOpen); - return () => host?.classList.remove("bsplus-cal-menu-open"); - }); - $effect(() => { if (menuOpen && menuEl) syncHostTheme(); }); @@ -496,7 +490,7 @@ >
Calendar sync - Copy your SEQTA timetable classes to Google or Outlook + Copy your SEQTA classes and appointments to Google or Outlook
{@render providerPanel( @@ -697,10 +691,14 @@ min-width: auto; height: auto; padding: 0 10px; - margin-left: 4px; + margin: 0; border-radius: 16px !important; font-family: inherit; - transition: transform 0.2s ease, opacity 0.2s ease; + background: var(--bsplus-cal-surface, var(--background-primary, #232323)) !important; + transition: + transform 0.2s ease, + opacity 0.2s ease, + background-color 0.2s ease; overflow: hidden; isolation: isolate; } @@ -751,8 +749,13 @@ transform: scale(0.97); } - .bsplus-cal-trigger--open { - background: color-mix(in srgb, var(--bsplus-cal-accent, var(--better-main, #3b82f6)) 14%, transparent) !important; + .bsplus-cal-trigger--open, + .bsplus-cal-trigger--open:hover, + .bsplus-cal-trigger--open:active { + background: var( + --bsplus-cal-surface-muted, + color-mix(in srgb, var(--bsplus-cal-text, #fff) 12%, var(--bsplus-cal-surface, #232323)) + ) !important; } .bsplus-cal-trigger--busy { @@ -829,7 +832,7 @@ .bsplus-cal-menu { position: fixed; - z-index: var(--bsplus-cal-z-menu, 2147483646); + z-index: var(--bsplus-cal-z-menu, 1200); width: min(320px, calc(100vw - 24px)); padding: 10px; border-radius: 14px; @@ -951,7 +954,7 @@ .bsplus-cal-modal-backdrop { position: fixed; inset: 0; - z-index: var(--bsplus-cal-z-modal, 2147483647); + z-index: var(--bsplus-cal-z-modal, 1300); display: flex; align-items: center; justify-content: center; @@ -1027,7 +1030,7 @@ position: fixed; right: 16px; bottom: 16px; - z-index: 100000; + z-index: var(--bsplus-cal-z-modal, 1300); max-width: min(360px, calc(100vw - 32px)); padding: 12px 14px; border-radius: 12px; diff --git a/src/plugins/built-in/timetable/calendarSyncHost.css b/src/plugins/built-in/timetable/calendarSyncHost.css index e0e3da77..673d79b7 100644 --- a/src/plugins/built-in/timetable/calendarSyncHost.css +++ b/src/plugins/built-in/timetable/calendarSyncHost.css @@ -1,28 +1,16 @@ -.timetablepage #toolbar { - position: relative; - z-index: 100; -} - .timetable-calendar-controls { position: relative; - z-index: 100001; display: inline-flex; align-items: center; -} - -.timetable-calendar-controls.bsplus-cal-menu-open { - z-index: 2147483645; -} - -.timetablepage #toolbar:has(.bsplus-cal-menu-open) { - z-index: 2147483645 !important; + vertical-align: middle; } :root { - --bsplus-cal-z-menu: 2147483646; - --bsplus-cal-z-modal: 2147483647; + --bsplus-cal-z-menu: 1200; + --bsplus-cal-z-modal: 1300; } .bsplus-calendar-sync-mount { display: inline-flex; + align-items: center; } diff --git a/src/plugins/built-in/timetable/calendarSyncUi.ts b/src/plugins/built-in/timetable/calendarSyncUi.ts index 40eb6e77..e87fb0b6 100644 --- a/src/plugins/built-in/timetable/calendarSyncUi.ts +++ b/src/plugins/built-in/timetable/calendarSyncUi.ts @@ -155,8 +155,18 @@ export async function mountGoogleCalendarButton(): Promise { registerCalendarContentHandlers(); const controls = document.createElement("div"); - controls.className = `${CONTROLS_CLASS} bsplus-timetable-control`; - toolbar.appendChild(controls); + controls.className = CONTROLS_CLASS; + + // Sit between the date selector and zoom controls (same spacing as neighbours). + const zoomControls = toolbar.querySelector(".timetable-zoom-controls"); + const dateButton = toolbar.querySelector(".buttonCalendar, button.calendar"); + if (zoomControls) { + toolbar.insertBefore(controls, zoomControls); + } else if (dateButton?.nextSibling) { + toolbar.insertBefore(controls, dateButton.nextSibling); + } else { + toolbar.appendChild(controls); + } const mountRoot = document.createElement("div"); mountRoot.className = "bsplus-calendar-sync-mount"; diff --git a/src/seqta/ui/AddBetterSEQTAElements.ts b/src/seqta/ui/AddBetterSEQTAElements.ts index b2774fd9..cc3e79d5 100644 --- a/src/seqta/ui/AddBetterSEQTAElements.ts +++ b/src/seqta/ui/AddBetterSEQTAElements.ts @@ -530,7 +530,30 @@ function setupSidebarAccessibility() { if (!menu) return; sidebarAccessibilityObserver?.disconnect(); - sidebarAccessibilityObserver = new MutationObserver(() => { + sidebarAccessibilityObserver = new MutationObserver((mutations) => { + // Custom Svelte sidebar owns drill a11y — ignore its DOM (opening Goals/Folios + // mutates a lot; re-running here used to help freeze the tab). + if (menu.classList.contains("bsplus-custom-sidebar")) { + const root = document.getElementById("bsplus-sidebar-root"); + if ( + root && + mutations.every( + (m) => root === m.target || root.contains(m.target as Node), + ) + ) { + return; + } + // Still ignore class/style-only native noise while custom sidebar is on. + if ( + mutations.every( + (m) => + m.type === "attributes" && + (m.attributeName === "class" || m.attributeName === "style"), + ) + ) { + return; + } + } scheduleSidebarAccessibilityUpdate(); }); sidebarAccessibilityObserver.observe(menu, { diff --git a/src/seqta/ui/sidebar/Sidebar.svelte b/src/seqta/ui/sidebar/Sidebar.svelte index ca6cdb79..b39ef99c 100644 --- a/src/seqta/ui/sidebar/Sidebar.svelte +++ b/src/seqta/ui/sidebar/Sidebar.svelte @@ -97,6 +97,20 @@ void sidebarState.isDrilling; restoreCustomMenuActive(); }); + + // Drill `.sub` is position:absolute inside this scrollport — if the list was + // scrolled down (e.g. Folios/Goals near the bottom), the panel sits under the + // logo until we reset. Also reset when going back up the stack. + $effect(() => { + void sidebarState.drillStack.length; + void sidebarState.enterFrameKey; + const root = document.getElementById("bsplus-sidebar-root"); + if (!root) return; + root.scrollTop = 0; + requestAnimationFrame(() => { + root.scrollTop = 0; + }); + });