cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Community Advocate
Community Advocate

Global Nav Menu - Custom Tray

Hello,

A recent Canvas update left a lot of institutions without the ability to add additional resources to their Canvas Global Navigation. Previous discussions include:

Custom JavaScript/CSS Changes Adding custom menu items https://community.canvaslms.com/ideas/4034-custom-menu-items-for-new-ui 

I have been working to replace this custom javascript solution by tfullwood@instructure.com, which utilized the native React Tray in Canvas, with something that will work today without it. I have focused on keeping the functionality the same for now, if you have thoughts or want to contribute please join the discussion, feedback is appreciated.

Known Issues:

  • Sticky default with the active state process when switching to the custom tray, if there is a tray for the current canvas page (/accounts, /courses, /conversations). The current page nav icon will be active just before the custom tray navigation icon gets the active state. If you have a fix for this, please share.

Source Code: ccsd-canvas/global-nav-custom-tray at master · robert-carroll/ccsd-canvas · GitHub

README

This JavaScript will spawn and style (with CSS) DOM elements that mimic the Canvas global navigation tray, with animated easing for opening and closing the tray, and other interactions with the global navigation.

273495_global-nav-custom-tray.png

Features

  • Custom tray name with tooltip
  • SVG navigation icon included, or provide your own
  • Links with optional description
  • Footer text optional

Icon Size

Use the SVG element's width and height to set the icon size for the navigation tray icon.
26px is about the default. see #comment-157915

Role Based Conditions

Tray Limited To Role(s)

To create a tray that only shows up for certain roles, wrap the tray in an if condition that checks for role.

2 role example

if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0) { 
// tray source here
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

1 role example

if(ENV.current_user_roles.indexOf('student') >= 0){
$(document).ready(function() {
///* set tray title, icon, links and footer here *///
///* for user role based conditions see README *///
var title = 'Resources',
svg = '/pin-gregor-cresnar.svg',
trayLinks = [
{ href: 'http://www.example.com/your-library', title: 'Library', desc:'Optional text description' },
{ href: 'http://www.google.com', title: 'Google' },
{ href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional text description' }
],
footer = 'Optional footer text, put whatever you want here, or leave it blank.';

///* options are above for convenience, continue if you like *///
// tray source here
});
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Tray for everyone, links by role

You can also create a tray that will appear for all users, but provide links (or even the tray name, icon, and footer), specific to the user role.

var title   = 'Resources',
svg = '/pin-gregor-cresnar.svg',
// default links for all users
trayLinks = [
{ href: 'http://www.example.com/your-library', title: 'Library', desc:'Optional text description' },
{ href: 'http://www.google.com', title: 'Google' },
{ href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional text description' }
],
footer = 'Default footer for all users';

// these links are appended to the tray by user role
if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0){
trayLinks.push({ href: 'http://www.example.com/your-library', title: 'Teacher Library', desc:'Optional text description' })
trayLinks.push({ href: 'http://www.google.com', title: 'Google' })
footer = 'Teacher/Admin Footer overwrites default';
} else if (ENV.current_user_roles.indexOf('student') >= 0) {
trayLinks.push({ href: 'http://www.example.com/your-library', title: 'Student Library', desc:'Optional text description' })
trayLinks.push({ href: 'http://www.google.com', title: 'Google' })
footer = 'Student Footer overwrites default';
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Credits for the included navigation tray icon - Pin

Pin by Gregor Cresnar from The Noun Project

https://creativecommons.org/licenses/by/3.0/

102 Replies
Highlighted
Explorer III

This seems to be working great!  I'm having trouble adding a conditional statement to differentiate between course roles.  How would I add in something along the lines of...

if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0){

...

} else if (ENV.current_user_roles.indexOf('student') >= 0) {

...

} else {

}

0 Kudos
Highlighted

Clint,

That's a great question. I am currently fine tuning the list above, but one of my next questions was going to be...

Would people prefer:

If the entire tray can run multiple instances (ie, Resources & Tools or Per Role) being different trays (and icons in the nav)...

   or would they prefer if Tray Item Links could be separated by different roles, and placed in a single tray that adapts to roles?

What you have above would be pretty easy to customize, so maybe I wouldn't have to add too much.

Variations on that could look like the following, customized by the institution instead of bloating the code.

    var title   = 'Resources',
        svg     = 'linkto/menu.svg',
        trayLinks = [
            { href: 'http://www.example.com/your-library', title: 'Library', desc:'Optional text description' },
            { href: 'http://www.google.com', title: 'Google' },
            { href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional  text description' }
        ],
          footer  = 'Optional footer text, put whatever you want here, or leave it blank.';
              
     if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0){
          trayLinks.push({ href: '#teacher-admin1', title: 'Teacher/Admin Link 1', desc:'Optional text description' })
          trayLinks.push({ href: '#teacher-admin2', title: 'Teacher/Admin Link 2' })
          footer  = 'Teacher Admin Footer';
     } else if (ENV.current_user_roles.indexOf('student') >= 0) {
          trayLinks.push({ href: '#student1', title: 'Student Link 1', desc:'Optional text description' })
          trayLinks.push({ href: '#student2', title: 'Student Link 2' })
          footer  = 'Student Footer';
     // default
     } else {
          trayLinks.push({ href: '#default-roles1', title: 'Default Roles 1', desc:'Optional text description' })
          footer  = 'Who goes there?';
     }
       
    ///* options are above for convenience, continue if you like *///‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
Highlighted

Per role w/ unique icons per role would be pretty interesting!  But, we've been working with just the one icon and the menu tailoring itself to the user role.  Maybe 6 one way 1/2dozen the other.  Unique icons could always be set to the same and changed as needed....

Highlighted

A lot of that can be easily handled in just the top code of the file, ie the tray title, and icon could be set in the user role conditions just like the example above, running in one instance.

Edit: Maybe at a later time.

Most likely, I will offer the ability to do both, I've already made improvements which would allow multiple instances to run, I don't see the code getting too cumbersome to make it work for multiple purposes. Will have to weigh the end user customization vs feature set.

Highlighted
Community Advocate
Community Advocate

I wanted to point out one major difference for anyone who uses this.

While I tried to keep the end user configuration as close to the original contribution, I added the optional description value for each TrayLink. So please note that you should be able to copy/paste TrayLinks from your existing solution, after replacing key/val with href/title.

Old

trayLinks = [
     {key: 'http://www.example.com/your-library', val: 'Library'},
     {key: 'http://www.google.com', val: 'Google'},
     {key: 'http://www.example.com/help-desk', val: 'Help Desk'}
];‍‍‍‍‍

New

trayLinks = [
     { href: 'http://www.example.com/your-library', title: 'Library' },
     { href: 'http://www.google.com', title: 'Google' },
     { href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional  text description' }
],
Highlighted
Explorer III

carroll-ccsd,

Thank you for making this code available.

My institution is a new Canvas customer and we are looking to use it.  I am also new to JavaScript so please bear with me as I struggle with what may seem like simple aspects of JS coding.  Hopefully my struggles, my questions, and your answers will also help others.

In our beta environment, I simply tried copying your 20 lines of Tray for everyone, links by role code (this seemed to be the best place to start, please let me know if another option would be better) into a JS file, uploaded the JS file into the Canvas theme, and nothing happened.

My plan was to see what that did and then make any necessary adjustments (e.g. changing links) but nothing happened.

Based on that I have three questions:

  1. What needs to be changed to get this to work?  I do plan on making changes but I wanted to start with something that just works
  2. If not addressed in #1, how you add the SVG push-pin file?  I see that it is hosted, at least according to your code from April 20, 2018 at 12:33 PM, in your Canvas instance in "branding/images" but how did you add it there?
  3. Is it possible to use the icons at https://instructure.design/#iconography using something like 'icon-pin'?  If yes, how should it be formatted or is 'icon-pin' enough?

Thank you for your help.

dbrace@lccc.edu

0 Kudos
Highlighted
Community Advocate
Community Advocate

Hi Douglas,

The 20 lines in the comment above is a usage example to customize the default behavior of a larger script, based on features people expected/preferred from another project that no longer works.

I will do my best to get you started and answer any questions.

First, the entire source code for the project is available on Github, here ccsd-canvas/global-nav-custom-tray, including a README on setup, which I'm sure isn't going to be the easiest to understand if you are new to JavaScript. I recommend reviewing it after we get some plug-n-play functionality working for you.

Second, you need the whole thing. You can cheat off my paper here starter-tray · GitHub, where I've conveniently copied and pasted all the elements you requested above into a single script. Click the RAW button on the right, copy and paste (adding) it into your Canvas Themes - JavaScript file.

You will also need to upload the contents of the CSS file in the repository to your Canvas Themes - CSS file, here ccsd-canvas/global-nav-custom-tray.css

Finally, the SVG image is a bit tricky and there are lots of options. I've started you off by creating a Gist for the pin-icon with the SVG paths built in and shared via RawGit... so that when you use the Starter Tray code it will just work. This is a quick and dirty solution and I wouldn't recommend it for Production use, because it's not organized. We use Amazon Web Services for various reasons, mostly because it easy for us to host Secure files to push back into Canvas, often with these kinds of JavaScript hacks. Amazon S3 makes this kind of hosting cheap and easy. You may also check with whatever department or team manages your institutions web services/hosting/web site and see if they can start providing a Secure space to host images. To work in Canvas the files need to be served via HTTPS so users don't get mixed content warnings or the Browser doesn't exclude the content.

Regarding InstUI and those icons... I wasn't aware of this product until recently and from what I have played with it doesn't appear the components are available through Canvas Themes. They are designed to be used and compiled into an LTI or web service that gets plugged back into Canvas. Fortunately, SVG images are text and Canvas is Open Source. You can probably get away with copying and hosting an icon from InstUI as long as you give credit and read the license... instructure-ui/LICENSE at master · instructure/instructure-ui · GitHub 

I couldn't complete this reply without making the piggy bank pink, inst-ui-icon-bank-svg · GitHub 

Highlighted

Hello carroll-ccsd,

I would like to thank you again for your help.  I was able to get your code working in our Canvas environment.  However, we have decided to go in a different direction so that we have more flexibility and so we could reduce the risk of something breaking or not working when their is an update.

We ended up using JS code from Adding custom menu items  and/or Help With Custom Menu Icons and Script  to make a new button that does the following:

  1. the button links to a Canvas "Resources" course (which we have made public)
  2. the icon for the button comes from https://instructure.design/#iconography (this meant that we did not have to host an icon somewhere else)
  3. the Canvas "Resources" course will make it possible for us to use native Canvas course features (e.g. modules, pages, files, and links) to a share items with our users
  4. some of the resources will not be related to Canvas (e.g. links to college calendars, contact information for other departments, and a variety of other items)
  5. we will also link to a course called our "Canvas Student Orientation"
    1. this is a public course
    2. it will have documents, files, and videos from Canvas Guides, Canvas Community, and others that we make ourselves for anyone but primarily students
  6. a link to a "Canvas Certification Course" for our instructors
    1. this course will not be public and our instructors will be registered as students
    2. it will have documents, files, and videos from Canvas Guides, Canvas Community, and others that we make ourselves for our instructors

Ultimately we decided that if we were going to use code that was not supported by Canvas, we wanted to reduce the risk of something "breaking".  Another reason is because we did not want to modify any CSS or JS code in the event that we wanted to add an additional item; which we would have had to do if we used the code in this thread.

While we did not end up using this code, it helped me to learn more about JS, CSS, and Canvas and hopefully your assistance will also help others.

Thank you again,

dbrace@lccc.edu

0 Kudos
Highlighted
Community Advocate
Community Advocate

dbrace@lccc.edu,

That's great!

I'm glad you found a solution that works for you, and I fully understand that nothing is one-size-fits-all. Truthfully, we don't even use this feature ourselves, because we already have some help menu hacks in place and a 'Hub' course that provides some of the same features you describe above.