@@ -8,7 +8,7 @@ import useSchedules, { getActiveSchedule, replaceSchedule, switchSchedule } from
8
8
import { getUpdatedAtDateTimeString } from '@views/lib/getUpdatedAtDateTimeString' ;
9
9
import { openTabFromContentScript } from '@views/lib/openNewTabFromContentScript' ;
10
10
import clsx from 'clsx' ;
11
- import React , { useState } from 'react' ;
11
+ import React , { useEffect , useState } from 'react' ;
12
12
13
13
import CalendarIcon from '~icons/material-symbols/calendar-month' ;
14
14
import RefreshIcon from '~icons/material-symbols/refresh' ;
@@ -19,6 +19,7 @@ import { SmallLogo } from './common/LogoIcon';
19
19
import PopupCourseBlock from './common/PopupCourseBlock' ;
20
20
import ScheduleDropdown from './common/ScheduleDropdown' ;
21
21
import ScheduleListItem from './common/ScheduleListItem' ;
22
+ import { ShadowDOM } from './injected/CourseCatalogInjectedPopup/ShadowDOMPortal' ;
22
23
23
24
/**
24
25
* Renders the main popup component.
@@ -27,6 +28,13 @@ import ScheduleListItem from './common/ScheduleListItem';
27
28
export default function PopupMain ( ) : JSX . Element {
28
29
const [ activeSchedule , schedules ] = useSchedules ( ) ;
29
30
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
+ } , [ ] ) ;
30
38
31
39
const handleOpenOptions = async ( ) => {
32
40
const url = chrome . runtime . getURL ( '/options.html' ) ;
@@ -39,97 +47,99 @@ export default function PopupMain(): JSX.Element {
39
47
} ;
40
48
41
49
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 >
54
64
</ div >
55
65
</ 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 ) ;
66
75
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
+ ) }
113
115
</ 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 >
130
140
</ div >
131
141
</ div >
132
- </ div >
133
- </ ExtensionRoot >
142
+ </ ExtensionRoot >
143
+ </ ShadowDOM >
134
144
) ;
135
145
}
0 commit comments