1- import { LitElement , css , html } from "lit" ;
1+ import { LitElement , css , html , nothing } from "lit" ;
22import { unsafeSVG } from "lit/directives/unsafe-svg.js" ;
33import { customElement , state } from "lit/decorators.js" ;
44import { getUserInfo } from "../auth.service.js" ;
55import copySvg from "../../assets/icons/copy.svg?raw" ;
66import burgerOutlineSvg from "../../assets/icons/burger-outline.svg?raw" ;
7+ import cardSvg from "../../assets/icons/card.svg?raw" ;
78
89export const apiBaseUrl : string =
910 import . meta. env . VITE_REGISTRATION_API_URL || "" ;
@@ -14,12 +15,50 @@ export class UserCard extends LitElement {
1415 @state ( ) protected isLoading = false ;
1516 @state ( ) protected hasError = false ;
1617 @state ( ) protected username : string = "" ;
18+ @state ( ) protected isOpen = false ;
1719
1820 constructor ( ) {
1921 super ( ) ;
2022 this . getUserId ( ) ;
2123 }
2224
25+ openModal ( ) {
26+ this . isOpen = true ;
27+ document . body . style . overflow = 'hidden' ;
28+ }
29+
30+ closeModal ( ) {
31+ this . isOpen = false ;
32+ document . body . style . overflow = '' ;
33+ }
34+
35+ protected handleNavClick = ( ) => {
36+ this . openModal ( ) ;
37+ } ;
38+
39+ protected handleOverlayClick = ( e : Event ) => {
40+ if ( e . target === e . currentTarget ) {
41+ this . closeModal ( ) ;
42+ }
43+ } ;
44+
45+ protected handleEscapeKey = ( e : KeyboardEvent ) => {
46+ if ( e . key === 'Escape' ) {
47+ this . closeModal ( ) ;
48+ }
49+ } ;
50+
51+ override connectedCallback ( ) {
52+ super . connectedCallback ( ) ;
53+ document . addEventListener ( 'keydown' , this . handleEscapeKey ) ;
54+ }
55+
56+ override disconnectedCallback ( ) {
57+ super . disconnectedCallback ( ) ;
58+ document . removeEventListener ( 'keydown' , this . handleEscapeKey ) ;
59+ document . body . style . overflow = '' ;
60+ }
61+
2362 protected renderLoading = ( ) => html `<p> Loading...</ p> ` ;
2463
2564 protected copyUserIdToClipboard = async ( ) => {
@@ -49,9 +88,10 @@ export class UserCard extends LitElement {
4988
5089 protected renderRegistrationCard = ( ) => html `
5190 <div class= "card card-shine" >
52- <span class= "slice " > ${ unsafeSVG ( burgerOutlineSvg ) } </ span>
91+ <span class= "burger " > ${ unsafeSVG ( burgerOutlineSvg ) } </ span>
5392 <div class= "card-content" >
54- <h1> Contoso Burgers Membership </ h1>
93+ <h1> Contoso Burgers </ h1>
94+ <h2> Membership Card </ h2>
5595 <p> Card attributed to : </ p>
5696 <div> <pre> ${ this . username } </ pre> </ div>
5797 <p> Unique user ID : </ p>
@@ -96,59 +136,150 @@ export class UserCard extends LitElement {
96136 }
97137 } ;
98138
139+ protected renderNavLink = ( ) => html `
140+ <butto n @click = "${ this . handleNavClick } " class = "member- card- link">
141+ <span class= "card-icon" > ${ unsafeSVG ( cardSvg ) } </ span>
142+ Member card
143+ </ butto n>
144+ ` ;
145+
146+ protected renderModal = ( ) => html `
147+ <div class= "modal-overlay" @click = "${ this . handleOverlayClick } " >
148+ <div class= "modal-content" >
149+ <butto n class= "close-button" @click = "${ this . closeModal } " aria-label = "Close modal"> × </ butto n>
150+ ${ this . isLoading
151+ ? this . renderLoading ( )
152+ : ! this . username
153+ ? this . renderError ( )
154+ : this . renderRegistrationCard ( ) }
155+ </ div>
156+ </ div>
157+ ` ;
158+
99159 protected override render ( ) {
100- return this . isLoading
101- ? this . renderLoading ( )
102- : ! this . username
103- ? this . renderError ( )
104- : this . renderRegistrationCard ( ) ;
160+ return html `
161+ ${ this . renderNavLink ( ) }
162+ ${ this . isOpen ? this . renderModal ( ) : nothing }
163+ ` ;
105164 }
106165
107166 static override styles = css `
108167 : host {
109- max-width : 1280px ;
110- margin : 0 auto;
168+ --reg-primary : linear-gradient (135deg , # de471d 0% , # ff6b3d 100% );
169+ --reg-border-radius : 16px ;
170+ }
171+
172+ .member-card-link {
173+ background : none;
174+ border : none;
175+ color : # fff ;
176+ text-decoration : none;
177+ padding : 0.5rem 1rem ;
178+ border-radius : 4px ;
179+ transition : background 0.2s ;
180+ display : flex;
181+ align-items : center;
182+ gap : 0.5rem ;
183+ cursor : pointer;
184+ font-family : inherit;
185+ font-size : inherit;
186+ }
187+
188+ .member-card-link : hover {
189+ background : rgba (255 , 255 , 255 , 0.1 );
190+ }
191+
192+ .card-icon {
193+ display : inline-block;
194+ fill : currentColor;
195+ }
196+
197+ .modal-overlay {
198+ position : fixed;
199+ top : 0 ;
200+ left : 0 ;
201+ right : 0 ;
202+ bottom : 0 ;
203+ background-color : rgba (0 , 0 , 0 , 0.7 );
204+ display : flex;
205+ align-items : center;
206+ justify-content : center;
207+ z-index : 1000 ;
111208 padding : 2rem ;
112- text-align : center;
209+ box-sizing : border-box;
210+ }
211+
212+ .modal-content {
213+ position : relative;
214+ max-width : 600px ;
215+ width : 100% ;
216+ max-height : 90vh ;
217+ background : var (--reg-primary );
218+ border-radius : var (--reg-border-radius , 16px );
219+ }
220+
221+ .close-button {
222+ position : absolute;
223+ top : 1rem ;
224+ right : 1rem ;
225+ background : rgba (255 , 255 , 255 , 0.2 );
226+ border : none;
227+ border-radius : 50% ;
228+ width : 2.5rem ;
229+ height : 2.5rem ;
230+ font-size : 1.5rem ;
231+ font-weight : bold;
232+ cursor : pointer;
233+ display : flex;
234+ align-items : center;
235+ justify-content : center;
236+ z-index : 1001 ;
237+ color : # fff ;
238+ transition : background 0.2s ;
113239 }
240+
241+ .close-button : hover {
242+ background : rgba (255 , 255 , 255 , .4 );
243+ }
244+
114245 svg {
115246 fill : currentColor;
116247 width : 100% ;
117248 }
118249 h1 {
119- font-family : "Sofia Sans Condensed" , sans-serif;
120- font-size : 2.5em ;
250+ font-size : 2em ;
121251 color : # fff ;
252+ margin : 0 ;
253+ font-weight : 600 ;
254+ text-transform : uppercase;
122255 }
123- h1 , p , pre , .warning {
256+ h1 , h2 {
257+ font-family : "Sofia Sans Condensed" , sans-serif;
258+ }
259+ h1 , h2 , pre , .warning {
124260 text-shadow : 0 1px 0px rgba (0 , 0 , 0 , 0.5 );
125261 }
126262 .card {
127263 position : relative;
128- background-color : var (--reg-primary );
264+ background : var (--reg-primary );
129265 border-radius : var (--reg-border-radius );
130266 padding : 2rem ;
131- margin-bottom : 2rem ;
132267 box-shadow : 0 0 0 1px rgba (0 , 0 , 0 , 0.2 ),
133268 -1px -1px 1px rgba (255 , 255 , 255 , 0.3 ),
134269 2px 4px 8px rgba (0 , 0 , 0 , 0.4 );
135270 font-family : "Sofia Sans Condensed" , sans-serif;
136271 text-align : left;
137- overflow : hidden;
138272 width : 100% ;
139273 box-sizing : border-box;
140274 color : # fff ;
141275 font-size : 1.2rem ;
142276
143- h1 {
144- font-size : 2.5rem ;
145- margin : 0 ;
146- font-weight : 600 ;
147- text-transform : uppercase;
148- }
149277 h2 {
278+ font-size : 1em ;
150279 margin : 0 ;
151280 font-weight : 600 ;
281+ font-style : italic;
282+ text-transform : uppercase;
152283 }
153284 pre {
154285 font-size : 1.5rem ;
@@ -164,7 +295,6 @@ export class UserCard extends LitElement {
164295 .card-shine {
165296 --shine-deg : 45deg ;
166297 position : relative;
167- overflow : hidden;
168298 background-repeat : no-repeat;
169299 background-position : 0% 0 , 0 0 ;
170300 background-image : linear-gradient (
@@ -182,7 +312,7 @@ export class UserCard extends LitElement {
182312 .card-shine : hover {
183313 background-position : 90% 0 , 0 0 ;
184314 }
185- .slice {
315+ .burger {
186316 z-index : 1 ;
187317 width : 10rem ;
188318 height : 10rem ;
@@ -191,7 +321,7 @@ export class UserCard extends LitElement {
191321 opacity : 0.4 ;
192322 position : absolute;
193323 right : -1rem ;
194- top : 2 rem ;
324+ top : 3.5 rem ;
195325 pointer-events : none;
196326 }
197327 .user-id-row {
0 commit comments