Apex 5 Universal Theme – Navigation Experiment #4

Coloring side menu entries

Sometimes you want to add a little more color to the navigation menu. The idea in one project was to use colors for certain areas in an application. The color would show the user where he is currently working. Whether such colors are a feature that end users like, is still part of an ongoing discussion. But here are the technical details how to implement it.

The example uses a very small apex application that I’ll be using for a DOAG2015 presentation “Exotic SQL” (http://syntegris-doag.de/#vortraege).

Before / After
apex5_sidebar_colored_beforeapex5_sidebar_colored_after

Steps to create this

I explain the changes in detail a little further down.

  1. Create a new List template based upon the current one.
  2. Switch the user interface from the old to the new template
  3. Edit the template
  4. Add colors to the parent list entries
  5. Update alls sub menus to match the parent color

Special Features:

  • can be changed with theme roller
  • matches other colors like Cards, Region accents, etc.
  • hovering with matching slightly darker background color
  • mass color update for sub menues

Problems:

  • theme roller does not change card colors and some other items that use the same palette as basis
  • font color is overwritten by other classes, therefore light background with dark colors do not always work
  • Colors from parent menu entries are not automatically used for the sub menu entries
  • Slight coloring issues with hover+toggle on sub menu items

Details

Steps to create a colored side menu

  1. Create a new list template based upon the current one.
    Shared Components/Templates/List => Copy

    I named my new list template: “Side Navigation Menu with Colors”

  2. Switch the user interface from the old to the new templateApplication Builder/Shared Components/User Interface/Edit Desktop/Navigation MenuHere switch from the old template to the new template.
    apex5_sidebar_colored_switch_template
  3. Edit the list template
    Add the following classes to all top and sub level template entries
    class=”u-ColorFG–#A03# u-ColorBG–#A03#”
    apex5_sidebar_colored_template1
    Attribute 3 is used in other templates often for setting the color. Thats why I used the same attribute. We should also add some helping text as explaination of the attribute.apex5_sidebar_colored_template2

    The classes u-ColorFG–1|2|3…|10 and u-ColorBG–1|2|3…|10 can be set using the theme roller. Those predefined classes can be changed using the palette. It is hidden in normal mode, but when all properties are shown, the palette can be changed.
    apex5_sidebar_colored_themeroller
    Some additional css needs to be added to the final “cascading stylesheet – inline” section. This css enables better hovering optics.

    .u-ColorFG--1.is-hover,.u-ColorFG--2.is-hover,.u-ColorFG--3.is-hover,.u-ColorFG--4.is-hover,.u-ColorFG--5.is-hover,.u-ColorFG--6.is-hover,.u-ColorFG--7.is-hover,.u-ColorFG--8.is-hover,.u-ColorFG--9.is-hover,.u-ColorFG--10.is-hover,.u-ColorFG--11.is-hover,.u-ColorFG--12.is-hover,.u-ColorFG--13.is-hover,.u-ColorFG--14.is-hover,.u-ColorFG--15.is-hover,.u-ColorFG--16.is-hover,.u-ColorFG--17.is-hover {
    filter: brightness(85%);
    }
    .t-TreeNav .a-TreeView-node--topLevel > ul {
    padding: 0px 0px;
    }
    

    The style “filter: brightness(85%)” will add a slightly darker shadow when hovering over an entry. The advantage is that this brightness filter will match the base background color. This avoids hard coding the colors for the hover-state in the css. 

    Not all browsers do support this yet. Browser specific css might be needed. I still have to confirm this on the Major Versions.

    filter: brightness(0.2);
    
    // Browser Specific
    
    -webkit-filter: brightness(0.2);
    
    -moz-filter: brightness(0.2);
    
    -o-filter: brightness(0.2);
    
    -ms-filter: brightness(0.2);
    
    

    The padding style is needed, to remove some small lines at the beginning and at the end of a sub menu, where the base color of the list shines through.
    apex5_sidebar_colored_padding

  4. Add colors to the parent list entries
    Edit the list and change attribute 03 for each list entry that needs get a new color. You can do that for all top level menu points and for all child entries. If you want to save time, then change only the parent menus and use SQL (explained in the next step) to recolor all sub menus.
    Simply add the number from the color palette to the list entry. In my case 1 = red, 2 = blue, 3 = orange, 4 = green.
  5. Update alls sub menus to match the parent color
    You can do it manually for each menu sub entry. Or change all with a single SQL Statement. To do so you need DBA privs, because it updaten some apex tables directly.
-- set our DBA session to the APEX schema
alter session set current_schema = apex_050000;
execute wwv_flow_security.g_security_group_id := 10;

-- Find our navigation list
select *
from wwv_flow_lists l
where l.flow_id = 200 -- Application ID
and l.name = 'Desktop Navigation Menu' -- Name of the list
;

-- find all listitems
select *
from wwv_flow_list_items i
where i.list_id = (select l.id from wwv_flow_lists l
where l.flow_id = 200
and l.name = 'Desktop Navigation Menu')
;

-- find all listitems where the parent has a color, but the child not
select id, i.list_item_link_text, list_text_03, list_text_06, i.parent_list_item_id
,sys_connect_by_path(i.list_item_link_text,'>')
from wwv_flow_list_items i
where i.list_id = (select l.id from wwv_flow_lists l
where l.flow_id = 200
and l.name = 'Desktop Navigation Menu')
and i.list_text_03 is null
connect by prior i.id = i.parent_list_item_id
start with i.parent_list_item_id is null and i.list_text_03 is not null
;

-- find all listitems where the parent has a color, but the child not, including path and parent color
-- this uses recursive with instead of connect by
with colored_entries
as (select i.id, i.list_item_link_text, list_text_03 as color
from wwv_flow_list_items i
join wwv_flow_lists l on l.id = i.list_id
where i.list_text_03 is not null -- start with items that already have a color set
and l.flow_id = 200
and l.name = 'Desktop Navigation Menu'
)
,child_entries (parent_id, id, target_color, menu)
as (select p.id as parent_id, i.id, p.color as target_color, p.list_item_link_text||'>'||i.list_item_link_text as menu
from colored_entries p
join wwv_flow_list_items i on i.parent_list_item_id = p.id
and i.list_text_03 is null
UNION ALL
select p.id as parent_id, i.id, p.target_color, p.menu||'>'||i.list_item_link_text as menu
from child_entries p
join wwv_flow_list_items i on i.parent_list_item_id = p.id
and i.list_text_03 is null
)
select * from child_entries;

-- recolor all child entries

-- a single UPDATE command is difficult to use.
-- It would require a subquery as a filter in the where condition and a second subquery for the SET part
-- MERGE is a good alternative
merge into wwv_flow_list_items m
using (with colored_entries
as (select i.id, i.list_item_link_text, list_text_03 as color
from wwv_flow_list_items i
join wwv_flow_lists l on l.id = i.list_id
where i.list_text_03 is not null -- start with items that already have a color set
and l.flow_id = 200 -- Application id
and l.name = 'Desktop Navigation Menu'  -- Name of the navigation list
)
,child_entries (parent_id, id, target_color, menu, list_text_03)
as (select p.id as parent_id, i.id, p.color as target_color, p.list_item_link_text||'>'||i.list_item_link_text as menu, i.list_text_03
from colored_entries p
join wwv_flow_list_items i on i.parent_list_item_id = p.id
and i.list_text_03 is null
UNION ALL
select p.id as parent_id, i.id, p.target_color, p.menu||'>'||i.list_item_link_text as menu, i.list_text_03
from child_entries p
join wwv_flow_list_items i on i.parent_list_item_id = p.id
and i.list_text_03 is null
)
select * from child_entries) v
ON (v.id = m.id)
when matched then update set m.list_text_03 = v.target_color;

The important code part here is the final merge statement. You need to add your own application id and your own list name there.

It will change all sub menu entries that do not have attribute 3 set. The entry from the parent menu is choosen.

Problem discussion

The apex team did a wonderful job to give us easly accessible functionality using a side navigation menu. But when we start to change something a lot of nasty things (I avoid saying BUGs) surface.

Problem 1)

One major problem is that the list template as we build it in the template designer is not what finally can be seen in the source code.

The classes that we added to the LI tag are moved and replaced to a DIV tag below the main LI tag. But this DIV is only the normal text part, the icon and the toggle parts are separate. Also the background color that we set for the div is not used for the margin and padding area when hovering over the entry.

apex5_sidebar_colored_problem1

Problem 2)
If we use the theme roller to change the color palette, then our menu colors are changed accordingly. However several other parts in the application that seem to use the same colors are not changed. For example the color for cards. The reason is, because the cards use an coloring system using nth-child css selectors. And they are stored in the core.min.css not even in the vita.min.css (which can be changed by Theme roller).

I guess there is not so much we could do at the moment. I would avoid hardcoding all the colors. That would just require more effort and will be a maintenence hell.

A good solution by the Apex team could be using less|sass as a hierachical css generator and exposing that to the developers.

Problem 3)

The navigation menus use there own special classes all the time. Among others the forgound color is set there. This overwrites our class settings. The problem now is that the forground color will always be white. So we can’t use light backgrounds. Also the toggle icon to show a sub menu is not visible anymore if a gray background is choosen.

These a minor issues and can eventually be solved by overwriting more css classes from the side navigation menu.

Other things
The copy functionality is often extremly slow. I do not know yet, why this happens. It seems worse on the apex.oracle.com cloud.

On my apex wish list is a grid edit functionality for list item custom attributes.