diff --git a/src/SEQTA.ts b/src/SEQTA.ts index c6699e64..370c1dfe 100644 --- a/src/SEQTA.ts +++ b/src/SEQTA.ts @@ -2158,8 +2158,7 @@ export async function loadHomePage() { // Create root container first const homeRoot = stringToHTML(` -
-
+
`) // Clear main and add home root @@ -2167,91 +2166,72 @@ export async function loadHomePage() { main.appendChild(homeRoot?.firstChild!) // Get reference to home container for all subsequent additions - const homeContainer = document.getElementById('home-container') + const homeContainer = document.getElementById('home-root') if (!homeContainer) return - // Add initial style to prevent flash - if (settingsState.animations) { - const style = document.createElement('style') - style.textContent = ` - .home-container > div { - opacity: 0; - transform: translateY(10px) scale(0.99); - } - ` - document.head.appendChild(style) - } - - // Use DocumentFragment for batch DOM updates inside home-container - const fragment = document.createDocumentFragment() - - // Batch state updates - const date = new Date() - currentSelectedDate = new Date() - const TodayFormatted = formatDate(date) - - // Create shortcuts section - const shortcutContainer = stringToHTML(` -
-
-
`) - fragment.appendChild(shortcutContainer?.firstChild!) - - // Create timetable section with optimized structure - const timetable = stringToHTML(` -
-
-

Today's Lessons

-
- - - - - - + const skeletonStructure = stringToHTML(` +
+
+
+
+
+
+

Today's Lessons

+
+ + + + + + +
+
+
-
-
`) - fragment.appendChild(timetable?.firstChild!) - - // Create upcoming assessments section - const upcomingContainer = document.createElement('div') - upcomingContainer.classList.add('upcoming-container', 'border') - - const upcomingTitleDiv = CreateElement('div', 'upcoming-title') - const upcomingTitle = document.createElement('h2') - upcomingTitle.classList.add('home-subtitle') - upcomingTitle.innerText = 'Upcoming Assessments' - upcomingTitleDiv.append(upcomingTitle) - - const upcomingFilterDiv = CreateElement('div', 'upcoming-filters', 'upcoming-filters') - upcomingTitleDiv.append(upcomingFilterDiv) - upcomingContainer.append(upcomingTitleDiv) - - const upcomingItems = document.createElement('div') - upcomingItems.id = 'upcoming-items' - upcomingItems.classList.add('upcoming-items') - upcomingContainer.append(upcomingItems) - fragment.appendChild(upcomingContainer) - - // Create notices section - const notices = stringToHTML(` -
-
-

Notices

- +
+
+

Upcoming Assessments

+
+
+
+
+
+
+
+

Notices

+ +
+
+
-
`) - fragment.appendChild(notices?.firstChild!) - // Single DOM update to home-container - homeContainer.appendChild(fragment) + // Add skeleton structure + homeContainer.appendChild(skeletonStructure.firstChild!) + + // Run animations if enabled + if (settingsState.animations) { + animate( + '.home-container > div', + { opacity: [0, 1], y: [10, 0], scale: [0.99, 1] }, + { + delay: stagger(0.15, { startDelay: 0.1 }), + type: 'spring', + stiffness: 341, + damping: 20, + mass: 1 + } + ) + } // Setup event listeners with cleanup const cleanup = setupTimetableListeners() + // Initialize shortcuts immediately + addShortcuts(settingsState.shortcuts) + AddCustomShortcutsToPage() + // Parallel data fetching const [assessments, classes, prefs] = await Promise.all([ GetUpcomingAssessments(), @@ -2272,10 +2252,20 @@ export async function loadHomePage() { .sort(comparedate) // Initialize components - addShortcuts(settingsState.shortcuts) - AddCustomShortcutsToPage() + const date = new Date() + const TodayFormatted = formatDate(date) + + // Load timetable await callHomeTimetable(TodayFormatted, true) - await CreateUpcomingSection(currentAssessments, activeSubjects) + + // Load upcoming assessments + const upcomingItems = document.getElementById('upcoming-items') + if (upcomingItems) { + await CreateUpcomingSection(currentAssessments, activeSubjects) + delay(100) + upcomingItems.classList.remove('loading') + console.log('Upcoming assessments created') + } // Setup notices const labelArray = prefs.payload @@ -2283,32 +2273,17 @@ export async function loadHomePage() { .map((item: any) => item.value) if (labelArray.length > 0) { - setupNotices(labelArray[0].split(' '), TodayFormatted) + const noticeContainer = document.getElementById('notice-container') + if (noticeContainer) { + noticeContainer.classList.remove('loading') + setupNotices(labelArray[0].split(' '), TodayFormatted) + } } if (settingsState.notificationcollector) { enableNotificationCollector() } - // Setup animations - if (settingsState.animations) { - // Remove the initial style - document.head.querySelector('style:last-child')?.remove() - - // Animate with motion - animate( - '.home-container > div', - { opacity: [0, 1], y: [10, 0], scale: [0.99, 1] }, - { - delay: stagger(0.15, { startDelay: 0.1 }), - type: 'spring', - stiffness: 341, - damping: 20, - mass: 1 - } - ) - } - return cleanup } diff --git a/src/css/injected.scss b/src/css/injected.scss index da9ad98e..aa77acca 100644 --- a/src/css/injected.scss +++ b/src/css/injected.scss @@ -2724,7 +2724,7 @@ li.MessageList__unread___3imtO { display: flex; flex-direction: column; color: var(--text-primary); - transition: 200ms; + transition: 200ms, background-color 0s; border-radius: 16px; } .dark .upcoming-items { @@ -3093,4 +3093,30 @@ li.MessageList__unread___3imtO { aspect-ratio: 16/9; object-fit: cover; margin-bottom: 12px; -} \ No newline at end of file +} + +@keyframes shimmer { + 0% { + background-position: -1000px 0; + } + 100% { + background-position: 1000px 0; + } +} + +.loading { + &.upcoming-items, + &.day-container { + background: linear-gradient(90deg, + var(--background-primary) 0%, + var(--background-secondary) 50%, + var(--background-primary) 100% + ); + background-size: 1000px 100%; + animation: shimmer 2s infinite linear; + } + + &.upcoming-items { + height: 35em; + } +}