@@ -8,7 +8,7 @@ import useSchedules, { getActiveSchedule, replaceSchedule, switchSchedule } from
88import { getUpdatedAtDateTimeString } from '@views/lib/getUpdatedAtDateTimeString' ;
99import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript' ;
1010import clsx from 'clsx' ;
11- import React , { useState } from 'react' ;
11+ import React , { useEffect , useState } from 'react' ;
1212
1313import CalendarIcon from '~icons/material-symbols/calendar-month' ;
1414import RefreshIcon from '~icons/material-symbols/refresh' ;
@@ -19,6 +19,7 @@ import { SmallLogo } from './common/LogoIcon';
1919import PopupCourseBlock from './common/PopupCourseBlock' ;
2020import ScheduleDropdown from './common/ScheduleDropdown' ;
2121import ScheduleListItem from './common/ScheduleListItem' ;
22+ import { ShadowDOM } from './injected/CourseCatalogInjectedPopup/ShadowDOMPortal' ;
2223
2324/**
2425 * Renders the main popup component.
@@ -27,6 +28,13 @@ import ScheduleListItem from './common/ScheduleListItem';
2728export default function PopupMain ( ) : JSX . Element {
2829 const [ activeSchedule , schedules ] = useSchedules ( ) ;
2930 const [ isRefreshing , setIsRefreshing ] = useState ( false ) ;
31+ const [ parentElement , setParentElement ] = useState < HTMLElement > ( document . createElement ( 'div' ) ) ;
32+
33+ useEffect ( ( ) => {
34+ let parent = document . getElementById ( 'root' ) ;
35+ setParentElement ( parent ) ;
36+ console . log ( parent ) ;
37+ } , [ ] ) ;
3038
3139 const handleOpenOptions = async ( ) => {
3240 const url = chrome . runtime . getURL ( '/options.html' ) ;
@@ -39,97 +47,99 @@ export default function PopupMain(): JSX.Element {
3947 } ;
4048
4149 return (
42- < ExtensionRoot >
43- < div className = 'h-screen max-h-full flex flex-col bg-white' >
44- < div className = 'p-5 py-3.5' >
45- < div className = 'flex items-center justify-between bg-white' >
46- < SmallLogo />
47- < div className = 'flex items-center gap-2.5' >
48- < button className = 'bg-ut-burntorange px-2 py-1.25 btn' onClick = { handleCalendarOpenOnClick } >
49- < CalendarIcon className = 'size-6 text-white' />
50- </ button >
51- < button className = 'bg-transparent px-2 py-1.25 btn' onClick = { handleOpenOptions } >
52- < SettingsIcon className = 'size-6 color-ut-black' />
53- </ button >
50+ < ShadowDOM parentElement = { parentElement } >
51+ < ExtensionRoot >
52+ < div className = 'utrp_shadow h-screen max-h-full flex flex-col bg-white' > { /* utrp_shadow creates a ShadowDOM subtree to protect CSS styles */ }
53+ < div className = 'p-5 py-3.5' >
54+ < div className = 'flex items-center justify-between bg-white' >
55+ < SmallLogo />
56+ < div className = 'flex items-center gap-2.5' >
57+ < button className = 'bg-ut-burntorange px-2 py-1.25 btn' onClick = { handleCalendarOpenOnClick } >
58+ < CalendarIcon className = 'size-6 text-white' />
59+ </ button >
60+ < button className = 'bg-transparent px-2 py-1.25 btn' onClick = { handleOpenOptions } >
61+ < SettingsIcon className = 'size-6 color-ut-black' />
62+ </ button >
63+ </ div >
5464 </ div >
5565 </ div >
56- </ div >
57- < Divider orientation = 'horizontal' size = '100%' />
58- < div className = 'px-5 pb-2.5 pt-3.75' >
59- < ScheduleDropdown >
60- < List
61- draggables = { schedules }
62- itemKey = { schedule => schedule . id }
63- onReordered = { reordered => {
64- const activeSchedule = getActiveSchedule ( ) ;
65- const activeIndex = reordered . findIndex ( s => s . id === activeSchedule . id ) ;
66+ < Divider orientation = 'horizontal' size = '100%' />
67+ < div className = 'px-5 pb-2.5 pt-3.75' >
68+ < ScheduleDropdown >
69+ < List
70+ draggables = { schedules }
71+ itemKey = { schedule => schedule . id }
72+ onReordered = { reordered => {
73+ const activeSchedule = getActiveSchedule ( ) ;
74+ const activeIndex = reordered . findIndex ( s => s . id === activeSchedule . id ) ;
6675
67- // don't care about the promise
68- UserScheduleStore . set ( 'schedules' , reordered ) ;
69- UserScheduleStore . set ( 'activeIndex' , activeIndex ) ;
70- } }
71- gap = { 10 }
72- >
73- { ( schedule , handleProps ) => (
74- < ScheduleListItem
75- schedule = { schedule }
76- onClick = { ( ) => {
77- switchSchedule ( schedule . id ) ;
78- } }
79- dragHandleProps = { handleProps }
80- />
81- ) }
82- </ List >
83- </ ScheduleDropdown >
84- </ div >
85- < div className = 'flex-1 self-stretch overflow-y-auto px-5' >
86- { activeSchedule ?. courses ?. length > 0 && (
87- < List
88- draggables = { activeSchedule . courses }
89- onReordered = { reordered => {
90- activeSchedule . courses = reordered ;
91- replaceSchedule ( getActiveSchedule ( ) , activeSchedule ) ;
92- } }
93- itemKey = { e => e . uniqueId }
94- gap = { 10 }
95- >
96- { ( course , handleProps ) => (
97- < PopupCourseBlock
98- key = { course . uniqueId }
99- course = { course }
100- colors = { course . colors }
101- dragHandleProps = { handleProps }
102- />
103- ) }
104- </ List >
105- ) }
106- </ div >
107-
108- < div className = 'w-full flex flex-col items-center gap-1.25 p-5 pt-3.75' >
109- < div className = 'flex gap-2.5' >
110- < CourseStatus status = 'WAITLISTED' size = 'mini' />
111- < CourseStatus status = 'CLOSED' size = 'mini' />
112- < CourseStatus status = 'CANCELLED' size = 'mini' />
76+ // don't care about the promise
77+ UserScheduleStore . set ( 'schedules' , reordered ) ;
78+ UserScheduleStore . set ( 'activeIndex' , activeIndex ) ;
79+ } }
80+ gap = { 10 }
81+ >
82+ { ( schedule , handleProps ) => (
83+ < ScheduleListItem
84+ schedule = { schedule }
85+ onClick = { ( ) => {
86+ switchSchedule ( schedule . id ) ;
87+ } }
88+ dragHandleProps = { handleProps }
89+ />
90+ ) }
91+ </ List >
92+ </ ScheduleDropdown >
93+ </ div >
94+ < div className = 'flex-1 self-stretch overflow-y-auto px-5' >
95+ { activeSchedule ?. courses ?. length > 0 && (
96+ < List
97+ draggables = { activeSchedule . courses }
98+ onReordered = { reordered => {
99+ activeSchedule . courses = reordered ;
100+ replaceSchedule ( getActiveSchedule ( ) , activeSchedule ) ;
101+ } }
102+ itemKey = { e => e . uniqueId }
103+ gap = { 10 }
104+ >
105+ { ( course , handleProps ) => (
106+ < PopupCourseBlock
107+ key = { course . uniqueId }
108+ course = { course }
109+ colors = { course . colors }
110+ dragHandleProps = { handleProps }
111+ />
112+ ) }
113+ </ List >
114+ ) }
113115 </ div >
114- < div className = 'inline-flex items-center self-center gap-1' >
115- < Text variant = 'mini' className = 'text-ut-gray' >
116- DATA LAST UPDATED: { getUpdatedAtDateTimeString ( activeSchedule . updatedAt ) }
117- </ Text >
118- < button
119- className = 'h-4 w-4 bg-transparent p-0 btn'
120- onClick = { ( ) => {
121- setIsRefreshing ( true ) ;
122- } }
123- >
124- < RefreshIcon
125- className = { clsx ( 'h-4 w-4 text-ut-black animate-duration-800' , {
126- 'animate-spin' : isRefreshing ,
127- } ) }
128- />
129- </ button >
116+
117+ < div className = 'w-full flex flex-col items-center gap-1.25 p-5 pt-3.75' >
118+ < div className = 'flex gap-2.5' >
119+ < CourseStatus status = 'WAITLISTED' size = 'mini' />
120+ < CourseStatus status = 'CLOSED' size = 'mini' />
121+ < CourseStatus status = 'CANCELLED' size = 'mini' />
122+ </ div >
123+ < div className = 'inline-flex items-center self-center gap-1' >
124+ < Text variant = 'mini' className = 'text-ut-gray' >
125+ DATA LAST UPDATED: { getUpdatedAtDateTimeString ( activeSchedule . updatedAt ) }
126+ </ Text >
127+ < button
128+ className = 'h-4 w-4 bg-transparent p-0 btn'
129+ onClick = { ( ) => {
130+ setIsRefreshing ( true ) ;
131+ } }
132+ >
133+ < RefreshIcon
134+ className = { clsx ( 'h-4 w-4 text-ut-black animate-duration-800' , {
135+ 'animate-spin' : isRefreshing ,
136+ } ) }
137+ />
138+ </ button >
139+ </ div >
130140 </ div >
131141 </ div >
132- </ div >
133- </ ExtensionRoot >
142+ </ ExtensionRoot >
143+ </ ShadowDOM >
134144 ) ;
135145}
0 commit comments