diff --git a/README.md b/README.md index 62c0cb8770be98a42ed334c5740087d5638232fc..adb10fa9a82a6e83c81cfc2064a45314cb3b2001 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ You can view a test of this component being used with the myuw-app-bar by openin - **Login URL (login-url):** The URL to redirect users to on login - **Logout URL (logout-url):** The Logout URL to redirect users to on logout - **Session Endpoint (session-endpoint):** The endpoint URL for session info +- **Open Menu Right (open-right):** Include this attribute if you would like the profile menu to open to the right, instead of left #### Slots diff --git a/index.html b/index.html index c6e7e88aff32a37adbcec64c626dd054ba30acfd..a5f861e9ab40f7ff67ba03429474107a10632f38 100644 --- a/index.html +++ b/index.html @@ -6,20 +6,28 @@ margin: 0; } </style> + <link rel="import" href="https://unpkg.com/@myuw-web-components/myuw-app-bar@1.0.0/myuw-app-bar.html"> <link rel="import" href="myuw-profile.html"> - <link rel="import" href="https://unpkg.com/@myuw-web-components/myuw-app-bar@1.0.1/myuw-app-bar.html"> + </head> <body> - <myuw-app-bar theme-name="MyUW" app-name="Profile" background="#c5050c" color="#fff"> + <myuw-app-bar + theme-name="MyUW" + theme-url="" + app-name="Component Test" + app-url="" + background="rgb(197, 5, 12)" + color="white" + > <myuw-profile slot="myuw-profile" login-url="https://wisc.edu/" logout-url="https://wisc.edu/" - session-endpoint="https://my.wisc.edu/portal/web/session.json" + session-endpoint="http://localhost:3474/session.json" > - <a href="https://wisc.edu" slot="nav-item">UW Madison Home</a> - <a href="https://wisc.edu" slot="nav-item">STAR</a> + <a href="https://wisc.edu" slot="nav-item">UW Madison Home</a> + <a href="https://wisc.edu" slot="nav-item">STAR</a> </myuw-profile> </myuw-app-bar> </body> diff --git a/myuw-profile.css b/myuw-profile.css deleted file mode 100644 index 210d00e823cfd1fcd101509e577448bbb1593fa2..0000000000000000000000000000000000000000 --- a/myuw-profile.css +++ /dev/null @@ -1,111 +0,0 @@ -#myuw-profile-login { - font-family: 'Roboto', 'Noto', sans-serif; - text-transform: uppercase; - text-decoration: none; - color: white; - padding: 10px 13px; - letter-spacing: 1px; - font-size: 14px; - position: relative; - display: inline-block; -} - -#myuw-profile-login.hidden { - display: none; -} - -#myuw-profile-circle { - position: relative; - display: inline-block; - width: 40px; - height: 40px; - background: teal; - border-radius: 100%; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; -} - -#myuw-profile-circle-initial { - padding: 0; - margin: 0; - font-weight: 100; - user-select: none; - text-transform: capitalize; -} - -#myuw-profile-wrapper { - position: relative; - display: inline-block; -} - -#myuw-profile-wrapper.hidden { - display: none; -} - -#myuw-profile-nav { - position: absolute; - top: 45px; - right: 0; - background-color:white; - min-width: 320px; - color: black; - list-style: none; - margin: 0; - padding: 0; - font-size: 14px; - - transform-origin: top right; - transform: scale(0); - opacity: 0; - transition: all .25s cubic-bezier(0.0, 0.0, 0.2, 1); - - -webkit-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75); - -moz-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75); - box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75); -} - -#myuw-profile-nav.visible { - transform: scale(1); - opacity: 1; -} - -#myuw-profile-nav p { - padding: 0; - margin: 0; -} - -#myuw-profile-nav a, -#myuw-profile-nav p, -::slotted(a), -::slotted(p){ - transition: all .3s ease; - position: relative; - display: block; - padding: 14px 16px; - color: black; - text-decoration: none; - background-color: #f9f9f9; - border-bottom: solid 1px #e5e5e5; - user-select: none; -} - -#myuw-profile-nav a:first-child, -#myuw-profile-nav p:first-child { - padding: 14px 16px; - font-weight: bold; - background-color: white; -} - -#myuw-profile-nav a:first-child:hover, -#myuw-profile-nav p:first-child:hover { - background-color: white; -} - -#myuw-profile-wrapper a:hover, -#myuw-profile-wrapper p:hover, -::slotted(a:hover), -::slotted(p:hover) { - background-color: rgba(158,158,158,0.2); -} \ No newline at end of file diff --git a/myuw-profile.html b/myuw-profile.html index c60f3bec5304284c65c4360e41a92590233179b3..e7d32d83772ec8d7967c7051cca400254f657529 100644 --- a/myuw-profile.html +++ b/myuw-profile.html @@ -1,10 +1,133 @@ <!DOCTYPE html> <template id="myuw-profile-template"> - <link href="./myuw-profile.css" rel="stylesheet"> + <style> + #myuw-profile-login { + font-family: 'Montserrat', 'Roboto', Arial, sans-serif; + text-transform: uppercase; + text-decoration: none; + color: white; + padding: 10px 13px; + font-weight: bold; + letter-spacing: 0px; + font-size: 14px; + position: relative; + display: inline-block; + } + + #myuw-profile-login.hidden { + display: none; + } + + #myuw-profile-circle { + position: relative; + display: inline-block; + width: 40px; + height: 40px; + border-radius: 100%; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + } + + #myuw-profile-circle-initial { + padding: 0; + margin: 0; + font-weight: 500; + font-size: 18px; + font-family: 'Montserrat', 'Roboto', Arial, sans-serif; + user-select: none; + color: white; + text-transform: capitalize; + } + + #myuw-profile-wrapper { + position: relative; + display: inline-block; + } + + #myuw-profile-wrapper.hidden { + display: none; + } + + #myuw-profile-nav { + position: absolute; + top: 45px; + right: 0; + background-color:white; + min-width: 320px; + color: black; + list-style: none; + margin: 0; + padding: 0; + font-size: 14px; + + transform-origin: top right; + transform: scale(0); + opacity: 0; + transition: opacity .25s cubic-bezier(0.0, 0.0, 0.2, 1), transform .25s cubic-bezier(0.0, 0.0, 0.2, 1); + + -webkit-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75); + -moz-box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75); + box-shadow: 0px 0px 7px 0px rgba(50, 50, 50, 0.75); + } + + #myuw-profile-nav.open-right { + left: 0; + right: inherit; + transform-origin: top left; + } + + #myuw-profile-nav.visible { + transform: scale(1); + opacity: 1; + } + + #myuw-profile-nav p { + padding: 0; + margin: 0; + } + + #myuw-profile-nav a, + #myuw-profile-nav p, + ::slotted(a), + ::slotted(p){ + transition: all .3s ease; + position: relative; + font-size: 15px; + font-family: 'Montserrat', 'Roboto', Arial, sans-serif; + display: block; + padding: 14px 16px; + color: black; + text-decoration: none; + background-color: #f9f9f9; + border-bottom: solid 1px #e5e5e5; + user-select: none; + } + + #myuw-profile-nav a:first-child, + #myuw-profile-nav p:first-child { + padding: 14px 16px; + font-weight: bold; + background-color: white; + } + + #myuw-profile-nav a:first-child:hover, + #myuw-profile-nav p:first-child:hover { + background-color: white; + } + + #myuw-profile-nav a:hover, + #myuw-profile-nav p:hover, + ::slotted(a:hover), + ::slotted(p:hover) { + background-color: rgba(158,158,158,0.2); + } + </style> - <a href="#" id="myuw-profile-login">Login</a> + <a href="#" id="myuw-profile-login" class="hidden">Login</a> - <div id="myuw-profile-wrapper"> + <div id="myuw-profile-wrapper" class="hidden"> <div id="myuw-profile-circle"> <p id="myuw-profile-circle-initial">B</p> </div> @@ -19,14 +142,15 @@ </template> <script> -const testMyUW = {"person":{"firstName":"Bucky","lastName":"Badger","sessionKey":"111111111","displayName":"Bucky Badger","serverName":"prod","userName":"bbadger"}}; + +// Get the script document +const thisDoc = (document._currentScript || document.currentScript).ownerDocument; class MyUWProfile extends HTMLElement { constructor() { super(); - - // Get the script document - const thisDoc = (document._currentScript || document.currentScript).ownerDocument; + + this['open-right'] = false; // Create a shadowroot for this element this.attachShadow({mode: 'open'}); @@ -38,15 +162,14 @@ class MyUWProfile extends HTMLElement { this.shadowRoot.appendChild(template.content.cloneNode(true)); } - static get observedAttributes() {return ['login-url', 'logout-url', 'session-endpoint']; } + static get observedAttributes() {return ['login-url', 'logout-url', 'open-right']; } attributeChangedCallback(name, oldValue, newValue){ // Update the attribute internally - // console.log(`${name} has updated from "${oldValue}" to "${newValue}"`); this[name] = newValue; - // Update the component - this.updateComponent(); + // Update the component with new att value + this.updateAttribute(name); } connectedCallback(){ @@ -54,68 +177,163 @@ class MyUWProfile extends HTMLElement { this['login-url'] = this.getAttribute('login-url'); this['logout-url'] = this.getAttribute('logout-url'); this['session-endpoint'] = this.getAttribute('session-endpoint'); + this['user'] = false; + + if(this.getAttribute('open-right') !== null){ + this['open-right'] = true; + } - // Get the user info + // If the session endpoint is set, fetch session info if(this['session-endpoint']){ - - this['user'] = testMyUW.person; - // this['user'] = false + fetch(this['session-endpoint']) + .then(res => { + + // Check if the request was valid + if(res.status === 200){ + res.json() + .then( data => { + // If data.person is not set, return. + if(!data.person){ return; } + + // Set user data to the component + this.user = data.person; + this.componentReady(); + }) + } else { + this.componentReady(); + } + }) + .catch( e => console.log(e) ); } else { - throw 'No session endpoint has been defiend. Please pass the session endpoint URL into the myuw-profile element!'; - this['user'] = false; + throw Error('No session endpoint has been defiend. Please set the "session-endpoint" attribute URL into the myuw-profile element!'); } - // Attach onClick to profile button - this.shadowRoot.getElementById('myuw-profile-circle').addEventListener('click', e => { - e.stopPropagation(); - this.shadowRoot.getElementById('myuw-profile-nav').classList.toggle('visible'); + /* + Add an on click event to the window. + This allows us to close the menu if the user + clicks anywhere but on the menu. + */ + window.addEventListener('click', e => { + let nav = this.shadowRoot.getElementById('myuw-profile-nav'); + + if(nav.classList.contains('visible')){ + nav.classList.remove('visible') + } }); + /* + Add an on click event to the profile nav menu. + We need to do this in order to stop the propagation + of click events on the menu specifically. + + If a user clicks on the nav menu, the window on click + event will not fire, and it will not close the nav menu + */ this.shadowRoot.getElementById('myuw-profile-nav').addEventListener('click', e => { e.stopPropagation(); }); - + /* + Add an on click event to profile bubble - // Add onclick to body - window.addEventListener('click', e => { - let nav = this.shadowRoot.getElementById('myuw-profile-nav'); - if(nav.classList.contains('visible')){ - nav.classList.remove('visible') - } + We need to make sure that we stop propagation on + this event or else the window on click will always fire + and the menu will never open. + */ + this.shadowRoot.getElementById('myuw-profile-circle').addEventListener('click', e => { + e.stopPropagation(); + this.shadowRoot.getElementById('myuw-profile-nav').classList.toggle('visible'); }); // Update the component to use the new attributes - this.updateComponent(); + this.updateAttribute('login-url'); + this.updateAttribute('logout-url'); + this.updateAttribute('session-endpoint'); + this.updateAttribute('open-right'); } - updateComponent(){ - // Set the Login URL - this.shadowRoot.getElementById('myuw-profile-login').setAttribute('href', this['login-url']); + // Update the component with attribute values + updateAttribute(att){ + switch(att){ + case 'login-url': + this.shadowRoot.getElementById('myuw-profile-login').setAttribute('href', this['login-url']); + break; - // Set the logout URL - this.shadowRoot.getElementById('myuw-profile-logout').setAttribute('href', this['logout-url']); + case 'logout-url': + this.shadowRoot.getElementById('myuw-profile-logout').setAttribute('href', this['logout-url']); + break; - // Show / hide elements based on shib state - if(this.user){ - // Hide login button - this.shadowRoot.getElementById('myuw-profile-login').classList.add('hidden'); - // Show Profile circle - this.shadowRoot.getElementById('myuw-profile-wrapper').classList.remove('hidden'); + case 'open-right': + if(this['open-right']){ + this.shadowRoot.getElementById('myuw-profile-nav').classList.add('open-right'); + } + break; + } + } + + /* + Function to run after the session endpoint + has been hit and the component has all the + data that it needs to render. + If user data was returned from the endpoint, + the profile bubble will show. + + If not, the login button will show. + */ + componentReady(){ + if(this.user){ // Add user's name to first menu item this.shadowRoot.getElementById('myuw-profile-nav-user').innerHTML = this.user.firstName; - // Change the letter in the profile circle this.shadowRoot.getElementById('myuw-profile-circle-initial').innerHTML = this.user.firstName.substring(0,1); + + this.setProfileColor(); + + this.showProfileBubble(); } else { - // Show Login Button - this.shadowRoot.getElementById('myuw-profile-login').classList.remove('hidden'); - // Hide profile Circle - this.shadowRoot.getElementById('myuw-profile-wrapper').classList.add('hidden'); + this.showLoginButton(); } } + + /* + Programmatically select a profile background + color based on the length of the users first name + and the first letter of their first name + */ + setProfileColor(){ + const colors = [ + '#093145', + '#107896', + '#829356', + '#00A996', + '#BCA136', + '#744196' + ]; + + const firstName = this.user.firstName.length; + const initial = this.user.firstName.substring(0,1).charCodeAt(); + const colorIndex = (initial + firstName) % colors.length; + + this.shadowRoot.getElementById('myuw-profile-circle').style.backgroundColor = colors[colorIndex]; + + } + + showLoginButton(){ + // Show Login Button + this.shadowRoot.getElementById('myuw-profile-login').classList.remove('hidden'); + // Hide profile Circle + this.shadowRoot.getElementById('myuw-profile-wrapper').classList.add('hidden'); + } + + showProfileBubble(){ + // Hide login button + this.shadowRoot.getElementById('myuw-profile-login').classList.add('hidden'); + // Show Profile circle + this.shadowRoot.getElementById('myuw-profile-wrapper').classList.remove('hidden'); + } + } window.customElements.define('myuw-profile', MyUWProfile); </script> \ No newline at end of file diff --git a/session.json b/session.json new file mode 100644 index 0000000000000000000000000000000000000000..23f8aa47fe151e5b7d83356440d46461dab73c94 --- /dev/null +++ b/session.json @@ -0,0 +1 @@ +{"person":{"firstName":"Bucky","lastName":"Badger","sessionKey":"111111111","displayName":"Bucky Badger","serverName":"prod","userName":"bbadger"}} \ No newline at end of file