24 | {# Add any additional markup above the form with this variable. #}
25 | {{ signup_form_content }}
26 |
32 |
33 |
--------------------------------------------------------------------------------
/dist/templates/decanter/components/site-search/site-search.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Global Site Search Component
5 | *
6 | * A search bar for the website.
7 | *
8 | * Available variables:
9 | * - attributes: For additional HTML attributes not already provided.
10 | * - modifier_class: Additional css classes to change look and behaviour of the component
11 | * - action: Action of the form
12 | * - method: Method of the form
13 | * - search_label: Custom screen reader label
14 | * - search_input_name: Name for the search input field. Also used as the "for" attribute of the search input field label.
15 | * - search_input_id: ID for the search input field. If not provided, it will take on the same value as search_input_name.
16 | * - search_input_attributes: Additional HTML attributes for the search input field
17 | * - placeholder: Placeholder text for the search input field
18 | * - search_button_attributes: Additional HTML attributes for the submit button
19 | * - search_button_name: The name for the form element. Defaults to 'search'
20 | * - search_button_text: The user facing text for the button. Defaults to 'Submit Search'
21 | * - additional_fields: Any additional fields for the search form, e.g., hidden input fields
22 | *
23 | */
24 | #}
25 | {%- if search_input_id is empty -%}
26 | {%- set search_input_id = search_input_name -%}
27 | {%- endif -%}
28 |
18 |
19 |
20 | {{ first }}
21 |
22 |
23 |
24 | {{ second }}
25 |
26 |
27 |
28 | {{ third }}
29 |
30 |
31 |
32 | {{ fourth }}
33 |
34 |
35 |
36 | {{ fifth }}
37 |
38 |
39 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/three-column/valmer/valmer.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Template for a complex column panel layout.
5 | *
6 | * This template provides a complex column panel display layout, with
7 | * each column roughly equal in width.
8 | *
9 | * Variables:
10 | * -
11 | * -
12 | *
13 | *
14 | *
15 | */
16 | #}
17 |
18 | {% if header is not empty %}
19 |
20 |
21 | {{ header }}
22 |
23 |
24 | {% endif %}
25 |
26 |
27 |
28 | {{ first }}
29 |
30 |
31 |
32 | {{ second }}
33 |
34 |
35 |
36 | {{ third }}
37 |
38 |
39 |
40 | {% if footer is not empty %}
41 |
42 |
43 | {{ footer }}
44 |
45 |
46 | {% endif %}
47 |
48 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/donies/donies.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Template for a complex column panel layout.
5 | *
6 | * This template provides a complex column panel display layout, with
7 | * each column roughly equal in width.
8 | *
9 | * Variables:
10 | * -
11 | * -
12 | *
13 | *
14 | *
15 | */
16 | #}
17 |
18 | {# Optional header region #}
19 | {% if header is not empty %}
20 |
21 |
22 | {{ header }}
23 |
24 |
25 | {% endif %}
26 |
27 | {# Mandatory content region #}
28 |
29 |
30 | {{ first }}
31 |
32 |
33 |
34 | {{ second }}
35 |
36 |
37 |
38 | {# Optional footer region #}
39 | {% if footer is not empty %}
40 |
41 |
42 | {{ footer }}
43 |
44 |
45 | {% endif %}
46 |
47 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/frogger/frogger.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Template for a complex column panel layout.
5 | *
6 | * This template provides a complex column panel display layout, with
7 | * each column roughly equal in width.
8 | *
9 | * Variables:
10 | * -
11 | * -
12 | *
13 | *
14 | *
15 | */
16 | #}
17 |
18 |
19 | {# Optional Header #}
20 | {% if header is not empty %}
21 |
22 |
23 | {{ header }}
24 |
25 |
26 | {% endif %}
27 |
28 | {# Required content section #}
29 |
30 |
31 | {{ first }}
32 |
33 |
34 |
35 | {{ second }}
36 |
37 |
38 |
39 | {# Optional centered container #}
40 | {% if middle is not empty %}
41 |
42 |
43 | {{ middle }}
44 |
45 |
46 | {% endif %}
47 |
48 | {# Optional third row #}
49 | {% if third is not empty %}
50 |
51 |
52 | {{ third }}
53 |
54 |
55 |
56 | {{ fourth }}
57 |
58 |
59 | {% endif %}
60 |
61 | {# Optional footer #}
62 | {% if footer is not empty %}
63 |
64 |
65 | {{ footer }}
66 |
67 |
68 | {% endif %}
69 |
70 |
{# end layout wrapper #}
71 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/pacman/pacman.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Template for a complex column panel layout.
5 | *
6 | * This template provides a complex column panel display layout, with
7 | * each column roughly equal in width.
8 | *
9 | * Variables:
10 | * -
11 | * -
12 | *
13 | *
14 | *
15 | */
16 | #}
17 |
18 | {# Optional Header #}
19 | {% if header is not empty %}
20 |
21 |
22 | {{ header }}
23 |
24 |
25 | {% endif %}
26 |
27 | {# Required content section #}
28 |
37 |
38 | {# Optional footer #}
39 | {% if footer is not empty %}
40 |
41 |
42 | {{ footer }}
43 |
44 |
45 | {% endif %}
46 |
47 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/plakes/plakes.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Template for a complex column panel layout.
5 | *
6 | * This template provides a complex column panel display layout, with
7 | * each column roughly equal in width.
8 | *
9 | * Variables:
10 | * -
11 | * -
12 | *
13 | *
14 | *
15 | */
16 | #}
17 |
18 | {# Optional Header #}
19 | {% if header is not empty %}
20 |
21 |
22 | {{ header }}
23 |
24 |
25 | {% endif %}
26 |
27 | {# Grid Container #}
28 |
29 | {# Manditory sidebar #}
30 |
33 |
34 | {# Manditory content #}
35 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/toucan/toucan.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Toucan
5 | *
6 | *
7 | */
8 | #}
9 |
10 |
11 |
12 | {# Required column #}
13 |
14 | {{ first }}
15 |
16 |
17 | {# Required column #}
18 |
19 | {{ second }}
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/trunks/trunks.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Template for a complex column panel layout.
5 | *
6 | * This template provides a complex column panel display layout, with
7 | * each column roughly equal in width.
8 | *
9 | * Variables:
10 | * -
11 | * -
12 | *
13 | *
14 | *
15 | */
16 | #}
17 |
18 |
19 |
20 | {{ first }}
21 |
22 |
23 |
24 | {{ second }}
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/dist/templates/decanter/layout/flex/two-column/wedge/wedge.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Wedge 2 column layout
5 | *
6 | * A 25/75 style two column layout.
7 | *
8 | * Variants:
9 | * layout-wedge-flex--right - A right sidebar variant to the layout.
10 | *
11 | * Variables:
12 | * attributes - html attributes for the template wrapper tag
13 | * modifier_class - Variant modifier css classes
14 | * first - First column and 25% width
15 | * second - Second Column and 75% width
16 | *
17 | *
18 | */
19 | #}
20 |
21 |
22 |
23 | {{ first }}
24 |
25 |
26 |
27 | {{ second }}
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/dist/templates/decanter/utilities/macros/link-list.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * Macro for creating a simple single level list of links.
4 | */
5 | #}
6 | {% macro link_list(items) %}
7 | {% spaceless %}
8 | {% for item in items %}
9 |
10 | {# Define the attributes vars fresh on each loop #}
11 | {% set list_attributes = "" %}
12 | {% set link_attributes = "" %}
13 |
14 | {#
15 | The map function is not available in twigjs so we have to do this :(
16 | see: https://github.com/twigjs/twig.js/wiki/Implementation-Notes
17 | #}
18 | {% if item.list_attributes is iterable %}
19 | {% for key, val in item.list_attributes %}
20 | {% if val.twig_markup == true %}
21 | {% set val = val|merge({'twig_markup': null}) %}
22 | {% endif %}
23 | {% set list_attributes = list_attributes ~ key|trim ~ '="' ~ val|join|trim ~ '" ' %}
24 | {% endfor %}
25 | {% endif %}
26 |
27 | {#
28 | The map function is not available in twigjs so we have to do this :(
29 | see: https://github.com/twigjs/twig.js/wiki/Implementation-Notes
30 | #}
31 | {% if item.link_attributes is iterable %}
32 | {% for key, val in item.link_attributes %}
33 | {% if val.twig_markup == true %}
34 | {% set val = val|merge({'twig_markup': null}) %}
35 | {% endif %}
36 | {% set link_attributes = link_attributes ~ key|trim ~ '="' ~ val|join|trim ~ '" ' %}
37 | {% endfor %}
38 | {% endif %}
39 |
40 | {# Actually output something #}
41 |
42 | {{ item.text }}
43 |
44 | {% endfor %}
45 | {% endspaceless %}
46 | {% endmacro %}
47 |
--------------------------------------------------------------------------------
/dist/templates/decanter/utilities/macros/menu-loop.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * Macro for creating nested menus.
4 | */
5 | #}
6 | {% macro nav_menu(items, menu_level, class_prefix) %}
7 | {% import _self as menus %}
8 |
41 | {% endmacro %}
42 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/favicon.ico
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/screenshot.png
--------------------------------------------------------------------------------
/src/assets/fonts/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/fonts/.gitkeep
--------------------------------------------------------------------------------
/src/assets/img/header-stanford-logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/header-stanford-logo@2x.png
--------------------------------------------------------------------------------
/src/assets/img/lockup-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/lockup-example.png
--------------------------------------------------------------------------------
/src/assets/img/login-page.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/login-page.jpg
--------------------------------------------------------------------------------
/src/assets/img/logo-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/logo-dark.png
--------------------------------------------------------------------------------
/src/assets/img/logo-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/logo-light.png
--------------------------------------------------------------------------------
/src/assets/img/logo-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/logo-white.png
--------------------------------------------------------------------------------
/src/assets/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SU-SWS/stanford_basic/cfb677958c950e044a77eea1e6bacdceffa3c19a/src/assets/img/logo.png
--------------------------------------------------------------------------------
/src/assets/svg/caret-down-red.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/js/base.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file
3 | * A Webpack entry file for the theme.
4 | */
5 |
6 | // Include Decanter.
7 | // Right now we import the components as the main decanter.js file always
8 | // imports all of the SASS and we want to make changes to it before we render.
9 | import 'decanter/core/src/js/components/components.js';
10 |
11 | // Import this theme's components.
12 | import './polyfills/index.js';
13 | import './components/index.js';
14 |
15 | // MY Base SCSS styles.
16 | import '../scss/base/index.scss';
17 |
--------------------------------------------------------------------------------
/src/js/behaviors.js:
--------------------------------------------------------------------------------
1 | // Theme code.
2 | import './theme/index.js';
3 | import './stanford_basic.behavior.js';
4 |
--------------------------------------------------------------------------------
/src/js/components/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Primary roll up file for all javascript components.
3 | */
4 |
5 | // The Secondary Navigation Component.
6 | import './secondary-nav/index.js';
7 | // The Mulit Menu Component.
8 | import './multi-menu/index.js';
9 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/MultiNavItem.js:
--------------------------------------------------------------------------------
1 | import SecondaryNavItem from '../../secondary-nav/common/SecondaryNavItem';
2 | import OnArrowLeftLV1 from './events/OnArrowLeftLV1';
3 | import OnArrowRightLV1 from './events/OnArrowRightLV1';
4 |
5 | /**
6 | * SecondarySubNavAccordion Class
7 | *
8 | * A sub menu class for creating a menu with accordion functionality.
9 | */
10 | export default class MultiNavItem extends SecondaryNavItem {
11 |
12 | /**
13 | * Creates an event registry for handling types of events.
14 | *
15 | * This registry is used by the EventHandlerDispatch class to bind and
16 | * execute the events in the created property key.
17 | *
18 | * @param {Object} options Options to merge in with the defaults.
19 | *
20 | * @return {Object} A key/value registry of events and handlers.
21 | */
22 | createEventRegistry(options) {
23 | var registryDefaults = super.createEventRegistry({});
24 |
25 | if (this.getDepth() === 1) {
26 | registryDefaults = Object.assign(registryDefaults, {
27 | onKeydownArrowLeft: OnArrowLeftLV1,
28 | onKeydownArrowRight: OnArrowRightLV1
29 | });
30 | }
31 |
32 | return registryDefaults;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/MultiSubNavButtons.js:
--------------------------------------------------------------------------------
1 | import SecondarySubNavButtons from '../../secondary-nav/buttons/SecondarySubNavButtons';
2 | import OnArrowRightToggleLV1 from './events/OnArrowRightToggleLV1';
3 | import OnArrowLeftLV1 from './events/OnArrowLeftLV1';
4 | import OnArrowRightLV1 from './events/OnArrowRightLV1';
5 | import OnArrowDownToggleLV1 from './events/OnArrowDownToggleLV1';
6 | import OnClickToggleLV1 from './events/OnClickToggleLV1';
7 | import OnArrowUpToggleLV1 from './events/OnArrowUpToggleLV1';
8 | import OnEsc from '../../secondary-nav/common/events/OnEsc.js';
9 |
10 |
11 | /**
12 | * SecondarySubNavAccordion Class
13 | *
14 | * A sub menu class for creating a menu with accordion functionality.
15 | */
16 | export default class MultiSubNavButtons extends SecondarySubNavButtons {
17 |
18 | /**
19 | * Creates an event registry for handling types of events.
20 | *
21 | * This registry is used by the EventHandlerDispatch class to bind and
22 | * execute the events in the created property key.
23 | *
24 | * @param {Object} options Options to merge in with the defaults.
25 | *
26 | * @return {Object} A key/value registry of events and handlers.
27 | */
28 | createEventRegistry(options) {
29 |
30 | var registryDefaults = super.createEventRegistry({});
31 | // If we are the first level (top) we need to adjust for mobile vs desktop.
32 | if (this.getDepth() === 1) {
33 | registryDefaults = Object.assign(registryDefaults, {
34 | onKeydownArrowLeft: OnArrowLeftLV1,
35 | onKeydownArrowRight: OnArrowRightLV1
36 | });
37 | }
38 |
39 | return registryDefaults;
40 | }
41 |
42 | /**
43 | * Initialize the toggle button.
44 | */
45 | initToggleButton() {
46 | var options = {};
47 | // Overrides for level 1 desktop.
48 | if (this.getDepth() === 1) {
49 | options.eventRegistry = {
50 | onKeydownArrowRight: OnArrowRightToggleLV1,
51 | onKeydownArrowDown: OnArrowDownToggleLV1,
52 | onKeydownArrowUp: OnArrowUpToggleLV1,
53 | onClick: OnClickToggleLV1,
54 | onKeydownEscape: OnEsc
55 | };
56 | }
57 |
58 | // Do eet.
59 | super.initToggleButton(options);
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/MultiMenuEventAbstract.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../../secondary-nav/common/events/EventAbstract';
2 |
3 | /**
4 | * MultiMenuEventAbstract class
5 | *
6 | * Event action handler with common code for MultiMenu.
7 | */
8 | export default class MultiMenuEventAbstract extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | if (this.isDesktop()) {
15 | this.handleDesktop();
16 | }
17 | else {
18 | this.handleMobile();
19 | }
20 | }
21 |
22 | /**
23 | * Handle the events for desktop sized screens.
24 | */
25 | handleDesktop() {
26 | // Do something.
27 | }
28 |
29 | /**
30 | * Handle the events for mobile sized screens.
31 | */
32 | handleMobile() {
33 | // Do something.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/OnArrowDownToggleLV1.js:
--------------------------------------------------------------------------------
1 | import MultiMenuEventAbstract from './MultiMenuEventAbstract';
2 | import SubNavToggleSpace from '../../../secondary-nav/buttons/events/SubNavToggleSpace';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowDownToggleLV1 extends MultiMenuEventAbstract {
10 |
11 | /**
12 | * Handle the events for desktop sized screens.
13 | */
14 | handleDesktop() {
15 | if (drupalSettings.stanford_basic.nav_dropdown_enabled) {
16 | this.handleMobile();
17 | return;
18 | }
19 |
20 | }
21 |
22 | /**
23 | * Handle the events for mobile sized screens.
24 | */
25 | handleMobile() {
26 | var expandEvent = new SubNavToggleSpace(this.item, this.event, this.target);
27 | expandEvent.init();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/OnArrowLeftLV1.js:
--------------------------------------------------------------------------------
1 | import MultiMenuEventAbstract from './MultiMenuEventAbstract';
2 | import OnArrowLeft from '../../../secondary-nav/common/events/OnArrowLeft';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowLeftLV1 extends MultiMenuEventAbstract {
10 |
11 | /**
12 | * Handle the events for desktop sized screens.
13 | */
14 | handleDesktop() {
15 |
16 | if (drupalSettings.stanford_basic.nav_dropdown_enabled) {
17 | this.handleMobile();
18 | return;
19 | }
20 |
21 | var element =
22 | this.getElement('prev') ||
23 | this.getElement('last');
24 |
25 | element.focus();
26 | }
27 |
28 | /**
29 | * Handle the events for mobile sized screens.
30 | */
31 | handleMobile() {
32 | var classicEvent = new OnArrowLeft(this.item, this.event, this.target);
33 | classicEvent.init();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/OnArrowRightLV1.js:
--------------------------------------------------------------------------------
1 | import MultiMenuEventAbstract from './MultiMenuEventAbstract';
2 | import OnArrowRight from '../../../secondary-nav/common/events/OnArrowRight';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowRightLV1 extends MultiMenuEventAbstract {
10 |
11 | /**
12 | * Handle the events for desktop sized screens.
13 | */
14 | handleDesktop() {
15 |
16 | if (drupalSettings.stanford_basic.nav_dropdown_enabled) {
17 | this.handleMobile();
18 | return;
19 | }
20 |
21 | var element =
22 | this.getElement('next') ||
23 | this.getElement('first');
24 |
25 | element.focus();
26 | }
27 |
28 | /**
29 | * Handle the events for mobile sized screens.
30 | */
31 | handleMobile() {
32 |
33 | let node = this.elem.nextElementSibling;
34 | if (node) {
35 | node.focus();
36 | return;
37 | }
38 |
39 | var classicEvent = new OnArrowRight(this.item, this.event, this.target);
40 | classicEvent.init();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/OnArrowRightToggleLV1.js:
--------------------------------------------------------------------------------
1 | import MultiMenuEventAbstract from './MultiMenuEventAbstract';
2 | import SubNavToggleSpace from '../../../secondary-nav/buttons/events/SubNavToggleSpace';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowRightToggleLV1 extends MultiMenuEventAbstract {
10 |
11 | /**
12 | * Handle the events for desktop sized screens.
13 | */
14 | handleDesktop() {
15 | if (this.getElement('next')) {
16 | this.getElement('next').focus();
17 | }
18 | else {
19 | this.getElement('parentNavFirst').focus();
20 | }
21 | }
22 |
23 | /**
24 | * Handle the events for mobile sized screens.
25 | */
26 | handleMobile() {
27 | var expandEvent = new SubNavToggleSpace(this.item, this.event, this.target);
28 | expandEvent.init();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/OnArrowUpToggleLV1.js:
--------------------------------------------------------------------------------
1 | import MultiMenuEventAbstract from './MultiMenuEventAbstract';
2 | import SubNavToggleSpace from '../../../secondary-nav/buttons/events/SubNavToggleSpace';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowUpToggleLV1 extends MultiMenuEventAbstract {
10 |
11 | /**
12 | * Handle the events for desktop sized screens.
13 | */
14 | handleDesktop() {
15 | if (drupalSettings.stanford_basic.nav_dropdown_enabled) {
16 | this.handleMobile();
17 | return;
18 | }
19 | }
20 |
21 | /**
22 | * Handle the events for mobile sized screens.
23 | */
24 | handleMobile() {
25 | var collapseEvent = new SubNavToggleSpace(this.item, this.event, this.target);
26 | collapseEvent.init();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/buttons/events/OnClickToggleLV1.js:
--------------------------------------------------------------------------------
1 | import MultiMenuEventAbstract from './MultiMenuEventAbstract';
2 | import SubNavToggleClick from '../../../secondary-nav/buttons/events/SubNavToggleClick';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnClickToggleLV1 extends MultiMenuEventAbstract {
10 |
11 | /**
12 | * Handle the events for desktop sized screens.
13 | */
14 | handleDesktop() {
15 | if (drupalSettings.stanford_basic.nav_dropdown_enabled) {
16 | this.handleMobile();
17 | return;
18 | }
19 |
20 | this.event.preventDefault();
21 | var node = this.parentNav.elem;
22 | node.click();
23 | node.focus();
24 | }
25 |
26 | /**
27 | * Handle the events for mobile sized screens.
28 | */
29 | handleMobile() {
30 | var clickEvent = new SubNavToggleClick(this.item, this.event, this.target);
31 | clickEvent.init();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/common/globals.js:
--------------------------------------------------------------------------------
1 | // The css class that this following behaviour is applied to.
2 | const multiMenuClass = 'su-multi-menu';
3 |
4 | // All Secondary navs.
5 | export var multiMenus = document.querySelectorAll('.' + multiMenuClass);
6 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/index.js:
--------------------------------------------------------------------------------
1 | // Get'm
2 | import './multi-menu-buttons.js';
3 |
--------------------------------------------------------------------------------
/src/js/components/multi-menu/multi-menu-buttons.js:
--------------------------------------------------------------------------------
1 | import {multiMenus} from './common/globals';
2 | import MultiMenuButtons from './buttons/MultiMenuButtons';
3 | import MobileToggle from './common/MobileToggle';
4 |
5 | document.addEventListener('DOMContentLoaded', event => {
6 | multiMenus.forEach((nav, index) => {
7 | if (nav.className.match(/su-multi-menu--buttons/)) {
8 | var theNav = new MultiMenuButtons(nav);
9 | var toggleElem = nav.querySelector(':scope .su-multi-menu__nav-toggle');
10 | if (toggleElem) {
11 | new MobileToggle(toggleElem, theNav);
12 | }
13 | }
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/accordion/events/OnArrowLeft.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 | import NavItemOnArrowLeft from '../../common/events/OnArrowLeft';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowLeft extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | // Go up a level.
16 | this.event.preventDefault();
17 |
18 | // Previous nav parents link item to focus on.
19 | var node = this.getElement('parentItem');
20 |
21 | // If we found a previous item focus on it.
22 | if (node) {
23 | node.focus();
24 | }
25 | // Overwise do what the navigate left option does.
26 | else {
27 | var otherLeft = new NavItemOnArrowLeft(this.item, this.event, this.target);
28 | otherLeft.init();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/accordion/events/OnArrowRight.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * OnArrowRight
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnArrowRight extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | // Go down a level and open the SubNav.
15 | this.event.preventDefault();
16 | this.item.openSubNav();
17 | this.getElement('firstSubnavLink').focus();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/accordion/events/OnClick.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * OnClick
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnClick extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.preventDefault();
15 |
16 | if (this.item.isExpanded()) {
17 | this.item.closeSubNav();
18 | // We blur then focus so that the browser announces the collapse to
19 | // those using screen readers and other assistive devices.
20 | this.elem.blur();
21 | this.elem.focus();
22 | }
23 | else {
24 | this.item.openSubNav();
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/accordion/events/OnSpace.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 | import OnClick from './OnClick';
3 |
4 | /**
5 | * OnSpace
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnSpace extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | this.event.preventDefault();
16 |
17 | // Do the rest of the stuff click does.
18 | var eventClick = new OnClick(this.item, this.event, this.target);
19 | eventClick.init();
20 |
21 | // Focus on the first element for keyboard but not clicks.
22 | if (this.item.isExpanded()) {
23 | var elem = this.getElement('firstSubnavLink');
24 | elem.focus();
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/buttons/events/OnArrowRight.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * OnArrowRight
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnArrowRight extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.item.toggleElement.focus();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/buttons/events/SubNavToggleArrowDown.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * SubNavToggleArrowDown
5 | *
6 | * Event action handler class.
7 | */
8 | export default class SubNavToggleArrowDown extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.preventDefault();
15 |
16 | // If on the toggle item and the menu is expanded go down in to the first
17 | // menu item link as the focus.
18 | if (this.parentNav.isExpanded()) {
19 | event.stopPropagation();
20 | event.preventDefault();
21 | this.getElement('firstSubnavLink').focus();
22 | }
23 | // If current focus is on the toggle and the menu is not open, go to the
24 | // next sibling menu item.
25 | else {
26 | var node =
27 | this.getElement('next') ||
28 | this.getElement('parentNavNext') ||
29 | this.getElement('last');
30 | if (node) {
31 | node.focus();
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/buttons/events/SubNavToggleArrowLeft.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * SubNavToggleArrowLeft
5 | *
6 | * Event action handler class.
7 | */
8 | export default class SubNavToggleArrowLeft extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | event.stopPropagation();
15 | event.preventDefault();
16 | this.parentNav.elem.focus();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/buttons/events/SubNavToggleArrowUp.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * SubNavToggleArrowUp
5 | *
6 | * Event action handler class.
7 | */
8 | export default class SubNavToggleArrowUp extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.preventDefault();
15 |
16 | // If the current focus is on the toggle and the menu is expanded, close
17 | // this nav menu and go to the parent list item.
18 | if (this.parentNav.isExpanded()) {
19 | event.stopPropagation();
20 | event.preventDefault();
21 | this.parentNav.closeSubNav();
22 | this.getElement('parentItem').focus();
23 | }
24 | // If the focus is on the toggle and the menu is not expanded, go to the
25 | // previous sibling item by calling the super method.
26 | else {
27 | var node =
28 | this.getElement('prev') ||
29 | this.getElement('parentNavPrev') ||
30 | this.getElement('first');
31 | if (node) {
32 | node.focus();
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/buttons/events/SubNavToggleClick.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * SubNavToggleClick
5 | *
6 | * Event action handler class.
7 | */
8 | export default class SubNavToggleClick extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | if (this.parentNav.isExpanded()) {
15 | this.parentNav.closeSubNav();
16 | this.elem.blur();
17 | this.elem.focus();
18 | }
19 | else {
20 | this.parentNav.openSubNav();
21 | }
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/buttons/events/SubNavToggleSpace.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 | import SubNavToggleClick from './SubNavToggleClick';
3 |
4 | /**
5 | * SubNavToggleSpace
6 | *
7 | * Event action handler class.
8 | */
9 | export default class SubNavToggleSpace extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | // No jumping around.
16 | this.event.preventDefault();
17 |
18 | // Call the click because it is pretty much the same thing.
19 | var eventClick = new SubNavToggleClick(this.item, this.event, this.target);
20 | eventClick.init();
21 |
22 | // Only focus on keyboard nav not on click.
23 | if (this.parentNav.isExpanded()) {
24 | var node = this.getElement('firstSubnavLink');
25 | if (node) {
26 | node.focus();
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/SecondarySubNavItem.js:
--------------------------------------------------------------------------------
1 | import SecondaryNavItem from './SecondaryNavItem';
2 |
3 | /**
4 | * SecondaryNav Class
5 | */
6 | export default class SecondarySubNavItem extends SecondaryNavItem {
7 |
8 | /**
9 | * Initialize.
10 | *
11 | * @param {HTMLElement} element The HTMLElement to bind to.
12 | * @param {Object|Mixed} masterNav The top most navigation instance.
13 | * @param {Object|Mixed} parentNav The parent nav instance if available.
14 | * @param {Object} options An object of metadata.
15 | */
16 | constructor(element, masterNav, parentNav = null, options = {}) {
17 | super(element, masterNav, parentNav, options);
18 | }
19 |
20 | /**
21 | * Close all SubNavs.
22 | *
23 | * Please override this method in your class.
24 | */
25 | closeAllSubNavs() {
26 | return;
27 | }
28 |
29 | /**
30 | * Close this SubNav.
31 | *
32 | * Please override this method in your class.
33 | */
34 | closeSubNav() {
35 | return;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnArrowDown.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 | import OnHome from './OnHome';
3 |
4 | /**
5 | * OnArrowDown
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowDown extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | this.event.preventDefault();
16 |
17 | // Go to the next item.
18 | let node = this.getElement('next');
19 | if (node) {
20 | node.focus();
21 | return;
22 | }
23 |
24 | // If a node is not found go to home.
25 | var eventHome = new OnHome(this.item, this.event, this.target);
26 | eventHome.init();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnArrowLeft.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 | import OnArrowUp from './OnArrowUp';
3 |
4 | /**
5 | * OnArrowLeft
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowLeft extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | this.event.preventDefault();
16 |
17 | // If this is a nested item. Go back up a level.
18 | if (this.item.getDepth() > 1) {
19 | this.nestedLeft();
20 | }
21 | // Otherwise just to to the previous sibling.
22 | else if (this.item.getDepth() === 1) {
23 | this.firstLevelLeft();
24 | }
25 | }
26 |
27 | /**
28 | * Action to take on a first level left key press.
29 | */
30 | firstLevelLeft() {
31 | var upevent = new OnArrowUp(this.item, this.event, this.target);
32 | upevent.init();
33 | }
34 |
35 | /**
36 | * Action to take on a nested level left key press
37 | */
38 | nestedLeft() {
39 | let node = this.getElement('parentItem') || this.getElement('parentNavLast');
40 | // this.parentNav.closeSubNav();
41 |
42 | if (node) {
43 | node.focus();
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnArrowRight.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 | import OnArrowDown from './OnArrowDown';
3 |
4 | /**
5 | * OnArrowRight
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowRight extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | // If we are in the second level or more we check about traversing
16 | // the parent.
17 | if (this.item.getDepth() > 1) {
18 | let node = this.getElement('parentNavNext');
19 | // this.parentNav.closeSubNav();
20 |
21 | if (node) {
22 | node.querySelector('a').focus();
23 | }
24 | // Go back to start.
25 | else {
26 | this.getElement('parentNavFirst').focus();
27 | }
28 | }
29 | else {
30 | var eventDown = new OnArrowDown(this.item, this.event, this.target);
31 | eventDown.init();
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnArrowUp.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 | import OnEnd from './OnEnd';
3 |
4 | /**
5 | * OnArrowUp
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowUp extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | this.event.preventDefault();
16 |
17 | // Go to the previous item.
18 | let node = this.getElement('prev');
19 | if (node) {
20 | node.focus();
21 | return;
22 | }
23 |
24 | // Go to the prev item last subnav item.
25 | node = this.getElement('prevElementSiblingSubnavLast');
26 | if (node) {
27 | node.focus();
28 | return;
29 | }
30 |
31 | // Default to the end..
32 | var eventEnd = new OnEnd(this.item, this.event, this.target);
33 | eventEnd.init();
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnEnd.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 |
3 | /**
4 | * OnEnd
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnEnd extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.preventDefault();
15 | var node = this.getElement('last');
16 | if (node) {
17 | node.focus();
18 | }
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnEnter.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 |
3 | /**
4 | * OnEnter
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnEnter extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.stopPropagation();
15 | this.event.preventDefault();
16 | window.location = this.target.getAttribute('href');
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnEsc.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 | import { createEvent } from '../../../../polyfills/createEvent';
3 |
4 | /**
5 | * OnEsc
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnEsc extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | this.event.preventDefault();
16 | let node = false;
17 |
18 | if (this.parentNav.getDepth() > 2) {
19 | this.event.stopPropagation();
20 | this.parentNav.closeSubNav();
21 | node = this.getElement('parentItem').parentElement.getElementsByTagName('button')[0];
22 | }
23 |
24 | else {
25 | if (this.isDesktop()) {
26 | this.masterNav.closeAllSubNavs();
27 | node = this.elem;
28 | }
29 | else {
30 | var closeAllEvent = createEvent('closeAllMobileNavs', { bubbles: true, data: this.item });
31 | this.elem.dispatchEvent(closeAllEvent);
32 | }
33 | }
34 |
35 | if (node) {
36 | node.focus();
37 | }
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnHome.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 |
3 | /**
4 | * OnHome
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnHome extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.preventDefault();
15 | var node = this.getElement('first');
16 | if (node) {
17 | node.focus();
18 | }
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnSpace.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 |
3 | /**
4 | * OnSpace
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnSpace extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.stopPropagation();
15 | this.event.preventDefault();
16 | window.location = this.target.getAttribute('href');
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/events/OnTab.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from './EventAbstract';
2 |
3 | /**
4 | * OnTab
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnTab extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | const shifted = event.shiftKey;
15 | let firstItem = false;
16 | let lastItem = false;
17 |
18 | try {
19 | firstItem = this.masterNav.elem.querySelector('a');
20 | }
21 | catch (err) {
22 | firstItem = this.masterNav.elem.firstElementChild;
23 | }
24 |
25 | try {
26 | lastItem = this.masterNav.elem.querySelector(':scope > ul > li:last-child');
27 | }
28 | catch (err) {
29 | lastItem = this.masterNav.elem.lastElementChild.lastElementChild;
30 | }
31 |
32 | // If shift key is held.
33 | if (shifted) {
34 | if (this.target === firstItem) {
35 | this.masterNav.closeAllSubNavs();
36 | return;
37 | }
38 | }
39 | // No shift key, just regular ol tab.
40 | else {
41 | if (this.target.parentNode === lastItem) {
42 | this.masterNav.closeAllSubNavs();
43 | return;
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/common/globals.js:
--------------------------------------------------------------------------------
1 | // The css class that this following behaviour is applied to.
2 | const secondaryNavClass = 'su-secondary-nav';
3 |
4 | // All Secondary navs.
5 | export var secondaryNavs = document.querySelectorAll('.' + secondaryNavClass);
6 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/index.js:
--------------------------------------------------------------------------------
1 | // Get'm
2 | import './secondary-nav-static.js';
3 |
4 | // Not importing these as they come from Decanter already and we plan to remove
5 | // them from this theme once the multi-menu has moved in to Decanter as well.
6 | // import './secondary-nav-accordion.js';
7 | // import './secondary-nav-buttons.js';
8 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/secondary-nav-accordion.js:
--------------------------------------------------------------------------------
1 | import {secondaryNavs} from './common/globals';
2 | import SecondaryNavAccordion from './accordion/SecondaryNavAccordion';
3 |
4 | document.addEventListener('DOMContentLoaded', event => {
5 |
6 | // Process each secondary nav accordion.
7 | secondaryNavs.forEach((nav, index) => {
8 | if (nav.className.match(/su-secondary-nav--accordion/)) {
9 | new SecondaryNavAccordion(nav);
10 | }
11 | });
12 |
13 | });
14 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/secondary-nav-buttons.js:
--------------------------------------------------------------------------------
1 | import {secondaryNavs} from './common/globals';
2 | import SecondaryNavButtons from './buttons/SecondaryNavButtons';
3 |
4 | document.addEventListener('DOMContentLoaded', event => {
5 |
6 | secondaryNavs.forEach((nav, index) => {
7 | if (nav.className.match(/su-secondary-nav--buttons/)) {
8 | new SecondaryNavButtons(nav);
9 | }
10 | });
11 |
12 | });
13 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/secondary-nav-static.js:
--------------------------------------------------------------------------------
1 | import SecondaryNavStatic from './static/SecondaryNavStatic';
2 | document.addEventListener('DOMContentLoaded', event => {
3 | var secondaryNavs = document.querySelectorAll('.su-secondary-nav');
4 | secondaryNavs.forEach((nav, index) => {
5 | if (nav.className.match(/su-secondary-nav--static/)) {
6 | var options = {
7 | expand: false,
8 | activeTrail: false
9 | };
10 | new SecondaryNavStatic(nav, options);
11 | }
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/static/SecondarySubNavItemStatic.js:
--------------------------------------------------------------------------------
1 | import SecondaryNavItem from '../common/SecondaryNavItem';
2 | import OnArrowUpSubNav from './events/OnArrowUpSubNav';
3 | import OnArrowRightSubNav from './events/OnArrowRightSubNav';
4 | import OnArrowDownSubNav from './events/OnArrowDownSubNav';
5 |
6 | /**
7 | * SecondaryNav Class
8 | */
9 | export default class SecondarySubNavItem extends SecondaryNavItem {
10 |
11 | /**
12 | * Initialize.
13 | *
14 | * @param {HTMLElement} element The HTMLElement to bind to.
15 | * @param {Object|Mixed} masterNav The top most navigation instance.
16 | * @param {Object|Mixed} parentNav The parent nav instance if available.
17 | * @param {Object} options An object of metadata.
18 | */
19 | constructor(element, masterNav, parentNav = null, options = {}) {
20 | super(element, masterNav, parentNav, options);
21 | }
22 |
23 | /**
24 | * Creates an event registry for handling types of events.
25 | *
26 | * This registry is used by the EventHandlerDispatch class to bind and
27 | * execute the events in the created property key.
28 | *
29 | * @param {Object} options Options to merge in with the defaults.
30 | *
31 | * @return {Object} A key/value registry of events and handlers.
32 | */
33 | createEventRegistry(options) {
34 |
35 | var registryDefaults = super.createEventRegistry(options);
36 | registryDefaults['onKeydownArrowUp'] = OnArrowUpSubNav;
37 | registryDefaults['onKeydownArrowRight'] = OnArrowRightSubNav;
38 | registryDefaults['onKeydownArrowDown'] = OnArrowDownSubNav;
39 |
40 | return Object.assign(registryDefaults, options.eventRegistry);
41 | }
42 |
43 | /**
44 | * Close all SubNavs.
45 | *
46 | * Please override this method in your class.
47 | */
48 | closeAllSubNavs() {
49 | return;
50 | }
51 |
52 | /**
53 | * Close this SubNav.
54 | *
55 | * Please override this method in your class.
56 | */
57 | closeSubNav() {
58 | return;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/static/events/OnArrowDownSubNav.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 |
3 | /**
4 | * OnArrowDownSubNav
5 | *
6 | * Event action handler class.
7 | */
8 | export default class OnArrowDownSubNav extends EventAbstract {
9 |
10 | /**
11 | * Execute the action to the event.
12 | */
13 | exec() {
14 | this.event.preventDefault();
15 |
16 | // Go to the first subnav item.
17 | let node = this.getElement('firstSubnavLink');
18 | if (node) {
19 | node.focus();
20 | return;
21 | }
22 |
23 | // Go to the next item.
24 | node = this.getElement('next');
25 | if (node) {
26 | node.focus();
27 | return;
28 | }
29 |
30 | // If there is no subnav item and no next item we must look for the next
31 | // link as far as it shows up in the html markup rather than the DOM. This
32 | // next link could be up and down a few sub nav items so the most reliable
33 | // key would be a tab key but as I am having trouble mimicking a tab event
34 | // with javascript we are going to do it the long way.
35 |
36 | var above = this.elem.parentNode;
37 | while (above.tagName !== 'NAV') {
38 | try {
39 | node = above.nextElementSibling.querySelector(':scope a:last-child');
40 | }
41 | catch (err) {
42 | // Nada.
43 | }
44 |
45 | // We got one or we are at the top.
46 | if (node) {
47 | break;
48 | }
49 |
50 | // Iterate.
51 | above = above.parentNode;
52 | }
53 |
54 | // If we find a link after all go to it.
55 | if (node) {
56 | node.focus();
57 | return;
58 | }
59 |
60 | // Go back to start, do not pass go.
61 | above.querySelector(':scope a').focus();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/static/events/OnArrowRightSubNav.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 | import OnArrowDownSubNav from './OnArrowDownSubNav';
3 |
4 | /**
5 | * OnArrowRightSubNav
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowRightSubNav extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | // Go to the next sibling then go to the parent next sibling.
16 | let node = this.getElement('next');
17 | if (node) {
18 | node.focus();
19 | return;
20 | }
21 |
22 | // Do what down does.
23 | var eventDown = new OnArrowDownSubNav(this.item, this.event, this.target);
24 | eventDown.exec();
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/js/components/secondary-nav/static/events/OnArrowUpSubNav.js:
--------------------------------------------------------------------------------
1 | import EventAbstract from '../../common/events/EventAbstract';
2 | import OnEnd from '../../common/events/OnEnd';
3 |
4 | /**
5 | * OnArrowUpSubNav
6 | *
7 | * Event action handler class.
8 | */
9 | export default class OnArrowUpSubNav extends EventAbstract {
10 |
11 | /**
12 | * Execute the action to the event.
13 | */
14 | exec() {
15 | this.event.preventDefault();
16 |
17 | // Go to the previous item.
18 | let node = this.getElement('prevElement');
19 | if (node) {
20 | var links = node.querySelectorAll(':scope a');
21 | links[links.length - 1].focus();
22 | return;
23 | }
24 |
25 | // Go to the prev item last subnav item.
26 | node = this.getElement('parentItem');
27 | if (node) {
28 | node.focus();
29 | return;
30 | }
31 |
32 | // Default to the end..
33 | var eventEnd = new OnEnd(this.item, this.event, this.target);
34 | eventEnd.init();
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/js/polyfills/createEvent.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create an event with the specified name in a browser-agnostic way.
3 | *
4 | * @param {string} eventName - the name of the event
5 | * @param {Object} data - Additional data along with the event.
6 | *
7 | * @return {Event} - instance of event which can be dispatched / listened for
8 | */
9 | export const createEvent = (eventName, data) => {
10 | if (typeof eventName !== 'string' || eventName.length <= 0) {
11 | return null;
12 | }
13 | // Modern browsers.
14 | if (typeof Event == 'function') {
15 | return new Event(eventName, data);
16 | }
17 | // IE
18 | else {
19 | let ev = document.createEvent('UIEvent');
20 | ev.initEvent(eventName, true, true, data);
21 | return ev;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/src/js/polyfills/foreach.js:
--------------------------------------------------------------------------------
1 | // if NodeList doesn't support forEach, use Array's forEach()
2 | NodeList.prototype.forEach = NodeList.prototype.forEach || Array.prototype.forEach;
3 |
--------------------------------------------------------------------------------
/src/js/polyfills/ie-edge.js:
--------------------------------------------------------------------------------
1 | // All the polyfills.
2 | require('@babel/polyfill');
3 |
4 | // IE11 Fix for Element.matches
5 | // See: https://www.npmjs.com/package/element-matches-polyfill
6 | require('element-matches-polyfill');
7 |
8 | // Polyfill - :scope in IE/Edge.
9 | import 'element-qsa-scope';
10 |
11 | // Polyfill for Object.assign function.
12 | // See: https://stackoverflow.com/questions/35215360/getting-error-object-doesnt-support-property-or-method-assign
13 | require('es6-object-assign').polyfill();
14 |
15 | // https://www.npmjs.com/package/element-closest-polyfill
16 | require('element-closest-polyfill');
17 |
--------------------------------------------------------------------------------
/src/js/polyfills/index.js:
--------------------------------------------------------------------------------
1 | // Roll up.
2 | import './createEvent';
3 | import './foreach';
4 | import './ie-edge';
5 |
--------------------------------------------------------------------------------
/src/js/theme/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Primary roll up file
3 | */
4 |
5 | // The Local Task Menu
6 | import './menu/index.js';
7 |
--------------------------------------------------------------------------------
/src/js/theme/menu/StickyHeaderOnScroll.js:
--------------------------------------------------------------------------------
1 | var header = document.getElementById('block-stanford-basic-local-tasks');
2 | var sticky = 0;
3 |
4 | if (header) {
5 | sticky = header.getBoundingClientRect().top;
6 | window.onscroll = function () {
7 | stickyHeaderOnScroll();
8 | };
9 | }
10 |
11 | /**
12 | * Stick the local block tasks to the top of the window.
13 | */
14 | function stickyHeaderOnScroll() {
15 | var toolbarHeight = 0;
16 | var toolbarOpen = document.body.classList.contains('toolbar-tray-open');
17 |
18 | if (toolbarOpen === true) {
19 | toolbarHeight = 79;
20 | }
21 | else {
22 | toolbarHeight = 39;
23 | }
24 |
25 | if (window.pageYOffset >= sticky - toolbarHeight) {
26 | header.classList.add('sticky');
27 | header.style.marginTop = toolbarHeight + 'px';
28 | }
29 | else {
30 | header.classList.remove('sticky');
31 | header.style.marginTop = '0px';
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/js/theme/menu/index.js:
--------------------------------------------------------------------------------
1 | import './StickyHeaderOnScroll.js';
2 |
--------------------------------------------------------------------------------
/src/js/utilities/keyboard.js:
--------------------------------------------------------------------------------
1 | // ---------------------------------------------------------------------------
2 | // Keyboard helper functions
3 | // ---------------------------------------------------------------------------
4 |
5 | export const isHome = theKey => (theKey === 'Home' || theKey === 122);
6 | export const isEnd = theKey => (theKey === 'End' || theKey === 123);
7 | export const isTab = theKey => (theKey === 'Tab' || theKey === 9);
8 | export const isEsc = theKey => (theKey === 'Escape' || theKey === 'Esc' || theKey === 27);
9 | export const isSpace = theKey => (theKey === ' ' || theKey === 'Spacebar' || theKey === 32);
10 | export const isEnter = theKey => (theKey === 'Enter' || theKey === 13);
11 | export const isLeftArrow = theKey => (theKey === 'ArrowLeft' || theKey === 'Left' || theKey === 37);
12 | export const isRightArrow = theKey => (theKey === 'ArrowRight' || theKey === 'Right' || theKey === 39);
13 | export const isUpArrow = theKey => (theKey === 'ArrowUp' || theKey === 'Up' || theKey === 38);
14 | export const isDownArrow = theKey => (theKey === 'ArrowDown' || theKey === 'Down' || theKey === 40);
15 |
16 | /**
17 | * Return a consistent string for each key validation.
18 | *
19 | * @param {*} theKey the code from a keypress event.
20 | *
21 | * @return {String} A string name for the key that was pressed.
22 | */
23 | export const normalizeKey = (theKey) => {
24 |
25 | // Key Value Map of the normalized string and the check function.
26 | const map = {
27 | home: isHome,
28 | end: isEnd,
29 | tab: isTab,
30 | escape: isEsc,
31 | space: isSpace,
32 | enter: isEnter,
33 | arrowLeft: isLeftArrow,
34 | arrowRight: isRightArrow,
35 | arrowUp: isUpArrow,
36 | arrowDown: isDownArrow
37 | };
38 |
39 | // Loop through the key/val object and run the check function (val) in order
40 | // to return the normalized string (key)
41 | for (var entry of Object.entries(map)) {
42 | if (entry[1](theKey)) {
43 | return entry[0];
44 | }
45 | }
46 |
47 | return false;
48 | };
49 |
--------------------------------------------------------------------------------
/src/scss/admin/_contextual_links.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | // Overlapping contextual links are difficult. Different links show at the top for different users.
4 | // Space them all out so we can see them all.
5 | $sel: '';
6 | @for $i from 0 through 4 {
7 | $sel: if($i == 0, '.contextual-region .contextual-region', selector-nest($sel, '.contextual-region')) !global;
8 |
9 | #{$sel} {
10 | .contextual {
11 | right: 32px * $i;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/scss/admin/_menu.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @keyframes fade {
4 | 0% { opacity: 0; }
5 | 20% { opacity: 1; }
6 | 80% { opacity: 1; }
7 | 100% { opacity: 0; }
8 | }
9 |
10 | a:hover,
11 | a:focus {
12 | .unpublished-indicator {
13 | display: inline-block;
14 | opacity: 1;
15 | animation: fade 5s ease-in-out;
16 | }
17 | }
18 |
19 | .unpublished-indicator {
20 | @include padding(4px 10px);
21 |
22 | // Animation definition
23 | opacity: 0;
24 | animation: fade ease-in-out 5s;
25 | animation-fill-mode: forwards;
26 |
27 | display: block;
28 | background: $su-color-blue;
29 | color: $su-color-white;
30 | font-size: 11px;
31 | position: absolute;
32 | top: -15px;
33 | left: 0;
34 | width: 115px;
35 |
36 | &::after {
37 | content: '';
38 | width: 0;
39 | height: 0;
40 | border-left: 10px solid transparent;
41 | border-right: 10px solid transparent;
42 | border-top: 10px solid $su-color-blue;
43 | position: absolute;
44 | bottom: -10px;
45 | right: 90px;
46 | }
47 |
48 | }
49 |
50 | .su-secondary-nav {
51 | .unpublished-indicator {
52 | left: 25px;
53 | top: -25px;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/scss/admin/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Base rules consist of styling for HTML elements only, such as used in a CSS
4 | // reset or Normalize.css. Base rules should never include class selectors.
5 | //
6 | // To avoid "undoing" styles in components, base styles should reflect the
7 | // simplest possible appearance of each element. For example, the simplest usage
8 | // of the ul element may be completely unstyled, removing list markers and
9 | // indents and relying on a component class for other applications.
10 | @import '../config/index';
11 |
12 | // First import decanter as no markup.
13 | @import 'decanter/core/src/scss/decanter-no-markup';
14 |
15 | @import 'contextual_links', 'menu';
16 |
--------------------------------------------------------------------------------
/src/scss/admin/user_login.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Base rules consist of styling for HTML elements only, such as used in a CSS
4 | // reset or Normalize.css. Base rules should never include class selectors.
5 | //
6 | // To avoid "undoing" styles in components, base styles should reflect the
7 | // simplest possible appearance of each element. For example, the simplest usage
8 | // of the ul element may be completely unstyled, removing list markers and
9 | // indents and relying on a component class for other applications.
10 | @import '../config/index';
11 |
12 | @import 'decanter/core/src/scss/decanter-no-markup';
13 |
14 | .dialog-off-canvas-main-canvas {
15 | background: url("../../assets/img/login-page.jpg") no-repeat;
16 | background-size: cover;
17 | background-position: center;
18 | background-attachment: fixed;
19 | }
20 |
21 | h1 {
22 | @include hide-visually;
23 | }
24 |
25 | .system-main-block {
26 | display: flex;
27 | align-items: center;
28 | justify-content: center;
29 | @include padding(100px null);
30 |
31 | form {
32 | background: $su-color-black;
33 | color: $su-color-white;
34 | text-align: center;
35 | max-width: 300px;
36 | @include padding(40px 40px 60px);
37 |
38 | input {
39 | &:focus {
40 | @include box-shadow('paper', '2px solid ' + $su-color-vivid-red);
41 | }
42 | }
43 |
44 | .su-button,
45 | input[type="submit"] {
46 | &:hover,
47 | &:focus {
48 | background-color: $su-color-vivid-red;
49 | }
50 | }
51 |
52 | a {
53 | &:hover,
54 | &:focus {
55 | color: $su-color-white;
56 | }
57 |
58 | &:focus {
59 | @include box-shadow('paper');
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/scss/base/_table.scss:
--------------------------------------------------------------------------------
1 | table {
2 | @include modular-spacing('margin-bottom', 5);
3 | border-collapse: collapse;
4 |
5 | caption {
6 | @include caption;
7 | }
8 |
9 | thead,
10 | tbody {
11 |
12 | th {
13 | background: transparent;
14 | font-weight: $su-font-semi-bold;
15 | }
16 |
17 | tr {
18 | border-top: 1px solid $su-color-cool-grey-25;
19 |
20 | &:first-of-type {
21 | border-top: 0;
22 | }
23 | }
24 | }
25 |
26 | thead + tbody {
27 | border-top: 1px solid $su-color-cool-grey-25;
28 | }
29 |
30 | td,
31 | th {
32 | border: 0;
33 | background: transparent;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/scss/base/_typography.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 | /**
3 | * This file overrides and extends base typography styles found in Decanter.
4 | * See: https://github.com/SU-SWS/decanter/blob/master/core/src/scss/elements/typography/_typography.scss
5 | * See: node_modules/decanter/core/src/scss/elements/typography/_typography.scss
6 | */
7 |
8 | // Restore font style when using font awesome icons on an element.
9 | a,
10 | aside,
11 | dd,
12 | div,
13 | h2,
14 | h3,
15 | h4,
16 | h5,
17 | li,
18 | p,
19 | td {
20 | &.fab {
21 | font-family: inherit;
22 | font-weight: inherit;
23 |
24 | &:before {
25 | font-family: "Font Awesome 5 Brands";
26 | font-weight: 400;
27 | }
28 | }
29 |
30 | &.fas,
31 | &.far {
32 | font-family: inherit;
33 | font-weight: inherit;
34 |
35 | &:before {
36 | font-family: "Font Awesome 5 Free";
37 | }
38 | }
39 |
40 |
41 | &.fas {
42 | &:before {
43 | font-weight: 900;
44 | }
45 | }
46 |
47 | &.fas {
48 | &:before {
49 |
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/scss/base/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // 1. Base
5 | //
6 |
7 | // Base rules consist of styling for HTML elements only, such as used in a CSS
8 | // reset or Normalize.css. Base rules should never include class selectors.
9 | //
10 | // To avoid "undoing" styles in components, base styles should reflect the
11 | // simplest possible appearance of each element. For example, the simplest usage
12 | // of the ul element may be completely unstyled, removing list markers and
13 | // indents and relying on a component class for other applications.
14 | @import '../config/index';
15 |
16 | // First import decanter as no markup.
17 | @import 'decanter/core/src/scss/decanter-no-markup';
18 |
19 | // Then we override the variables, mixins, and functions.
20 | @import '../utilities/index';
21 |
22 | // Then we import All of Decanter.
23 | @import "decanter/core/src/scss/core/index";
24 | @import "decanter/core/src/scss/elements/index";
25 | @import "decanter/core/src/scss/layout/index";
26 | @import "decanter/core/src/scss/components/index";
27 |
28 | // Roll up partial imports.
29 | @import
30 | 'table',
31 | 'typography';
32 |
--------------------------------------------------------------------------------
/src/scss/ckeditor.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Load the decanter dependencies.
4 | @import 'decanter/core/src/scss/decanter-no-markup';
5 |
6 | // Load up the theme config overrides first.
7 | @import 'config/index';
8 | @import 'utilities/index';
9 |
10 | // Then import Decanter styles.
11 | @import 'decanter/core/src/scss/elements/typography/typography';
12 | @import 'decanter/core/src/scss/elements/list/index';
13 | @import 'decanter/core/src/scss/elements/table/index';
14 | @import 'decanter/core/src/scss/components/button/index';
15 | @import 'decanter/core/src/scss/components/link/index';
16 |
17 | // Add our custom styles.
18 | @import
19 | 'base/typography',
20 | 'base/table';
21 |
--------------------------------------------------------------------------------
/src/scss/components/alert/_alert--info.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Add theme customizations here.
4 |
--------------------------------------------------------------------------------
/src/scss/components/alert/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import 'alert--info';
4 |
--------------------------------------------------------------------------------
/src/scss/components/all/_link--pager.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Load more button used on filtered pages and
4 | // paragraph lists.
5 |
6 | .js-pager__items {
7 | text-align: center;
8 |
9 | .pager__item {
10 | display: inline-block;
11 |
12 | .button {
13 | @include button-primary;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/scss/components/all/_vertical-spacing.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | .content {
4 | .paragraph-item {
5 | @include modular-spacing('margin-bottom', 7);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/scss/components/all/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import 'link--pager';
4 | @import 'vertical-spacing';
--------------------------------------------------------------------------------
/src/scss/components/filter-menu/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
7 | @import 'filter-menu';
8 |
--------------------------------------------------------------------------------
/src/scss/components/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | //
4 | // 3. Component
5 | //
6 |
7 | // Discrete, reusable UI elements.
8 | //
9 | // Components should not be responsible for their positioning or layout within
10 | // the site. Never apply widths or heights except to elements that natively have
11 | // these properties (e.g. images have these properties, so it's okay to use CSS
12 | // to modify their width and height). Within components, separate structural
13 | // rules from stylistic rules.
14 | //
15 | // Component Naming Convention
16 | // .component-name
17 | // .component-name--variant
18 | // .component-name__sub-object
19 |
20 | // First import decanter as no markup.
21 | @import 'decanter/core/src/scss/decanter-no-markup';
22 |
23 | // Then we override the variables, mixins, and functions.
24 | @import
25 | '../config/index',
26 | '../utilities/index';
27 |
28 | // Stanford Basic components
29 | @import
30 | 'all/index', // All comes first so others can override.
31 | 'alert/index',
32 | 'filter-menu/index',
33 | 'link/index.scss',
34 | 'lockup/index',
35 | 'masthead/index',
36 | 'multi-menu/index',
37 | 'paragraphs/paragraph--people',
38 | 'secondary-nav/index',
39 | 'stanford-page/index',
40 | 'wysiwyg/index';
41 |
42 |
--------------------------------------------------------------------------------
/src/scss/components/link/_link--action.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | .su-link--action {
4 |
5 | &:hover,
6 | &:active,
7 | &:focus {
8 | text-decoration: underline;
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/scss/components/link/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
7 | @import 'link--action'
8 |
--------------------------------------------------------------------------------
/src/scss/components/lockup/_lockup.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | .su-lockup--option-a {
4 | .su-lockup__line1 {
5 | @include grid-media('md') {
6 | line-height: 1.15em;
7 | @include margin(-8px null -6px null);
8 | }
9 | }
10 | }
11 |
12 | .su-lockup__custom-logo {
13 | max-width: 150px;
14 | }
15 |
16 | .su-lockup--option-none {
17 | .su-lockup__cell1 {
18 | border-right: 0;
19 | }
20 |
21 | .su-lockup__custom-logo {
22 | max-width: 300px;
23 | }
24 | }
25 |
26 | .su-lockup--option-s,
27 | .su-lockup--option-t {
28 | .su-lockup__line4 {
29 | &::after {
30 | width: auto;
31 | }
32 | }
33 | }
34 |
35 | .su-lockup__cell2 {
36 | max-width: 380px;
37 | }
38 |
39 | .su-lockup__cell1 {
40 | .su-lockup__line4 {
41 | overflow-wrap: break-word;
42 | word-break: break-all;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/scss/components/lockup/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import 'lockup';
4 |
--------------------------------------------------------------------------------
/src/scss/components/masthead/_wrapper.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | // Decanter overrides.
4 | // ----------------------------------------------------------------------
5 | .su-masthead {
6 | z-index: 11;
7 |
8 | @include grid-media-max('sm') {
9 | .su-multi-menu {
10 | @include margin(-57px null null);
11 | }
12 | }
13 |
14 | @include grid-media-only('md') {
15 | .su-multi-menu {
16 | @include flex-column(2);
17 | @include margin(auto null null);
18 | }
19 | }
20 |
21 | .su-multi-menu {
22 | @include grid-media-max('md') {
23 | > ul {
24 | @include box-shadow('medium', 0);
25 | }
26 | }
27 |
28 | @include grid-media('lg') {
29 | width: 100%;
30 | }
31 |
32 | .su-multi-menu__nav-toggle[aria-expanded=true] + .su-multi-menu__menu-lv1 {
33 | @include grid-media-only('xs') {
34 | right: -20px;
35 | }
36 |
37 | @include grid-media-only('sm') {
38 | right: -30px;
39 | }
40 |
41 | @include grid-media-only('md') {
42 | right: 0;
43 | }
44 | }
45 |
46 | > ul,
47 | .su-multi-menu__nav-toggle[aria-expanded="true"] + .su-multi-menu__menu-lv1 + .su-site-search {
48 | @include grid-media-only('md') {
49 | width: 40rem;
50 | }
51 |
52 | }
53 | }
54 |
55 | .su-multi-menu,
56 | .su-multi-menu > ul,
57 | .su-multi-menu .su-multi-menu__nav-toggle[aria-expanded="true"] + .su-multi-menu__menu-lv1 + .su-site-search {
58 | @include grid-media-only('xs') {
59 | // We can't use 100vw for this because it doesn't work with OSX system preference to always show scrollbar
60 | width: calc(100% + #{map-get($su-screen-margins, 'xs') * 2});
61 | }
62 |
63 | @include grid-media-only('sm') {
64 | width: calc(100% + #{map-get($su-screen-margins, 'sm') * 2});
65 | }
66 | }
67 |
68 | > section:last-of-type {
69 | @include grid-media('lg') {
70 | @include padding(3.6rem null null null);
71 | }
72 | }
73 |
74 | .su-lockup {
75 | @include grid-media('lg') {
76 | @include margin(null null 2.2rem null);
77 | }
78 | }
79 |
80 | .su-site-search__input {
81 | @include padding(0.6rem 2rem 0.8rem);
82 | font-family: $su-font-sans;
83 | border: 1px solid #d9d9d9;
84 | }
85 |
86 | .su-site-search__submit {
87 | color: unset;
88 | opacity: 100;
89 | right: 1.6rem;
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/scss/components/masthead/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import
4 | 'wrapper';
5 |
--------------------------------------------------------------------------------
/src/scss/components/multi-menu/_animation.scss:
--------------------------------------------------------------------------------
1 | // Pulse shadow animation For the Menu.
2 | @keyframes pulse-dark {
3 | 0% {
4 | filter: drop-shadow(0 0 0 rgba(177, 4, 14, 1));
5 | }
6 |
7 | 70% {
8 | filter: drop-shadow(0 0 6px rgba(177, 4, 14, 0.5));
9 | }
10 |
11 | 100% {
12 | filter: drop-shadow(0 0 10px rgba(177, 4, 14, 0));
13 | }
14 | }
15 |
16 | // Hover up and down animation.
17 | @keyframes hoverboard {
18 | 0% {
19 | top: calc(50% - 19px);
20 | }
21 |
22 | 30% {
23 | top: calc(50% - 21px);
24 | }
25 |
26 | 50% {
27 | top: calc(50% - 23px);
28 | }
29 |
30 | 70% {
31 | top: calc(50% - 21px);
32 | }
33 |
34 | 100% {
35 | top: calc(50% - 19px);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/scss/components/multi-menu/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
7 | @import
8 | 'animation',
9 | 'multi-menu';
10 |
--------------------------------------------------------------------------------
/src/scss/components/paragraphs/_paragraph--people.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Aligning the people cards
4 | .stanford-people-grid {
5 | .flex-container {
6 | justify-content: left;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/scss/components/secondary-nav/_secondary-nav--light.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Secondary Navigation - Light theme
4 | //
5 | // Decanter overrides.
6 |
7 | .su-secondary-nav--light {
8 | .su-secondary-nav__link {
9 | color: $su-color-bright-red;
10 |
11 | &:hover,
12 | &:focus {
13 | &::before {
14 | background-color: $su-color-bright-red;
15 | }
16 | }
17 | }
18 |
19 | .su-secondary-nav__item--current {
20 | > .su-secondary-nav__link {
21 | color: $su-color-black;
22 |
23 | &::before {
24 | background-color: $su-color-black;
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/scss/components/secondary-nav/_secondary-nav.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Secondary Navigation
3 | //
4 | // Decanter overrides.
5 |
6 | .su-secondary-nav {
7 | @include modular-spacing('margin-bottom', 8);
8 |
9 | &,
10 | .su-secondary-nav__menu {
11 | background: transparent;
12 | }
13 |
14 | .su-secondary-nav__link {
15 | border-top: 0;
16 | }
17 |
18 | > .su-secondary-nav__menu {
19 | @include margin(null null null 0);
20 | @include padding(null null null 0);
21 |
22 | > .su-secondary-nav__item {
23 | border-top: solid 1px #d9d9d9;
24 | line-height: 1.2em;
25 | }
26 |
27 | > .su-secondary-nav__item:first-child {
28 | border: 0;
29 | }
30 |
31 | }
32 | }
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/scss/components/secondary-nav/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
7 | @import
8 | 'secondary-nav',
9 | 'secondary-nav--light';
10 |
--------------------------------------------------------------------------------
/src/scss/components/stanford-page/_page-title.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | //
4 | // Custom Styles For Stanford Page Content Type.
5 | //
6 | .node-stanford-page-title,
7 | .block--page-title {
8 | @include modular-spacing('margin-top', 6);
9 | }
10 |
--------------------------------------------------------------------------------
/src/scss/components/stanford-page/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import
4 | 'page-title';
5 |
--------------------------------------------------------------------------------
/src/scss/components/wysiwyg/_line_length.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | // Set a maximum line length in the WYSIWYG.
4 | //
5 | // This controls the number of characters that can be displayed in a line
6 | // This sets a maximum width based the size of the letter "O".
7 |
8 | .su-wysiwyg-text {
9 | p {
10 | max-width: 100ch;
11 | }
12 |
13 | p {
14 | &.text-align-right {
15 | text-align: right;
16 | margin-left: auto;
17 | }
18 |
19 | &.text-align-center {
20 | text-align: center;
21 | margin-left: auto;
22 | margin-right: auto;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/scss/components/wysiwyg/_media.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | .su-wysiwyg-text {
4 | .align-center {
5 | img,
6 | picture {
7 | @include margin(0 auto);
8 | }
9 |
10 | .media {
11 | &.file {
12 | text-align: center;
13 | }
14 | }
15 | }
16 |
17 | .align-left {
18 | .file {
19 | &.media {
20 | padding: 0.4em 1.5em 0 0;
21 | }
22 | }
23 | }
24 |
25 | .align-right {
26 | .file {
27 | &.media {
28 | padding: 0.4em 0 0 1.5em;
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/scss/components/wysiwyg/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import
4 | 'line_length',
5 | 'media';
6 |
--------------------------------------------------------------------------------
/src/scss/config/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Path to Decanter Assets.
4 | $su-image-path: "~decanter-assets";
5 | $basic-image-path: "basic-assets" + "/img";
6 | $basic-svg-path: "basic-assets" + "/svg";
7 | $fa-font-path: "~fa-fonts";
8 | $theme-asset-path: "../../assets/svg";
9 |
--------------------------------------------------------------------------------
/src/scss/layout/_page.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 | //
3 | // Styles for page.html.twig layout.
4 | //
5 | //
6 |
7 | body {
8 | @include padding(0);
9 | @include margin(0);
10 | height: 100%;
11 | min-height: 100vh;
12 | width: 100%;
13 | }
14 |
15 | // Slam the footer to the bottom of the page.
16 | .dialog-off-canvas-main-canvas {
17 | width: 100%;
18 | @include sticky-footer("#footer");
19 | }
20 |
--------------------------------------------------------------------------------
/src/scss/layout/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // 2. Layout
5 | //
6 |
7 | // Macro arrangement of a web page, including any grid systems.
8 | // Grid systems should be thought of as shelves. They contain content but are
9 | // not content in themselves. You put up your shelves then fill them with your
10 | // stuff [i.e. components]. – Harry Roberts, CSS Guidelines
11 | //
12 | // Separate style from behavior by using dedicated classes for JavaScript
13 | // manipulation rather than relying on classes already in use for CSS. This way,
14 | // we can modify classes for style purposes without fear of breaking JS, and
15 | // vice versa. To make the distinction clear, classes used for JavaScript
16 | // manipulation should be prefixed with 'js-'. These JavaScript hooks must never
17 | // be used for styling purposes. See the section ‘Formatting Class Names’ for
18 | // more information on naming conventions.
19 | //
20 |
21 | // First import decanter as no markup.
22 | @import 'decanter/core/src/scss/decanter-no-markup';
23 |
24 | // Then we override the variables, mixins, and functions.
25 | @import
26 | '../config/index',
27 | '../utilities/index';
28 |
29 | // Roll ups.
30 | @import
31 | 'page';
32 |
--------------------------------------------------------------------------------
/src/scss/pages/search/_search-page.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 | //
3 | // Custom Styles For Stanford Page Search form and search results.
4 | //
5 | // Search form on search results page
6 |
7 | // Search Header
8 | h1 {
9 | @include type-a;
10 | @include modular-spacing('margin-top', 6);
11 | }
12 |
13 | //Search results
14 | .search-result__item {
15 | @include modular-spacing('padding', 3 3 4 3);
16 |
17 | border-top: 1px solid $su-color-cool-grey-25;
18 | list-style: none;
19 | }
20 |
21 | // Mobile spacing changes
22 | @include grid-media-only('xs') {
23 | ol {
24 | @include padding(null 0 null);
25 | }
26 |
27 | .search-result__item {
28 | @include modular-spacing('padding', 1);
29 | }
30 | }
31 |
32 | .search-form {
33 | @include margin(0 auto);
34 | @include padding(5rem 0 0 0);
35 | @include modular-spacing('margin-bottom', 6);
36 |
37 | @include grid-media-only('xs') {
38 | @include modular-spacing('margin-bottom', 4);
39 | }
40 |
41 | max-width: 775px;
42 |
43 | .form-search {
44 | border-color: $su-color-cool-grey-25;
45 | display: inline-block;
46 | @include grid-media-between('md', 'xl') {
47 | @include margin(3px null null);
48 | }
49 | @include grid-media-between('lg', 'xl') {
50 | @include modular-spacing('margin-left', -1);
51 | }
52 | }
53 |
54 | @include grid-media-between('xs', 'md') {
55 | .button {
56 | @include margin(0);
57 | @include modular-spacing('margin-bottom', -1);
58 | @include modular-spacing('margin-top', -1);
59 | }
60 | }
61 |
62 | @include grid-media-between('sm', 'md') {
63 | label,
64 | .form-submit {
65 | display: block;
66 | }
67 |
68 | .button {
69 | &.form-submit {
70 | width: 100vw;
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/scss/pages/search/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import '../../config/index';
4 |
5 | // First import decanter as no markup.
6 | @import 'decanter/core/src/scss/decanter-no-markup';
7 |
8 | @import
9 | 'search-page';
10 |
--------------------------------------------------------------------------------
/src/scss/print/_print.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | //
4 | // Print Styles
5 | //
6 |
7 | // Use this stylesheet for print styles only.
8 |
9 | * {
10 | background-color: transparent;
11 | }
12 |
13 | .sidebar,
14 | #navigation,
15 | #header-region,
16 | #footer,
17 | .breadcrumb,
18 | .tabs,
19 | .feed-icon,
20 | .links {
21 | display: none;
22 | }
23 |
24 | .layout-container {
25 | width: 100%;
26 | }
27 |
28 | #content,
29 | .title {
30 | margin: 20px 0;
31 | width: auto;
32 | }
33 |
34 | a {
35 | &:hover,
36 | &:active,
37 | &:link,
38 | &:visited {
39 | color: $su-color-black;
40 | }
41 | }
42 |
43 | // CSS2 selector to add visible href after links.
44 | #content {
45 | a {
46 | &:link:after,
47 | &:visited:after {
48 | content: " (" attr(href) ") ";
49 | font-size: 0.8em;
50 | font-weight: normal;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/scss/print/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // Print styles.
5 | //
6 |
7 | @import
8 | '../config/index',
9 | '../utilities/index',
10 | 'decanter/core/src/scss/decanter-no-markup',
11 | 'print';
12 |
--------------------------------------------------------------------------------
/src/scss/state/_hidden.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | .hidden {
4 | display: none;
5 | }
6 |
--------------------------------------------------------------------------------
/src/scss/state/_mobile-hidden.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Remove the secondary skip nav from devices using the mobile menu.
4 | .su-skipnav--secondary {
5 | @include grid-media-max(md) {
6 | display: none;
7 | }
8 | }
9 |
10 | .hidden {
11 | display: none;
12 | }
13 |
--------------------------------------------------------------------------------
/src/scss/state/_visually-hidden.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | .visually-hidden {
4 | @include accessibly-hidden;
5 | }
6 |
--------------------------------------------------------------------------------
/src/scss/state/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // 4. State
5 | //
6 |
7 | // Styles that deal with client-side changes to components.
8 | //
9 | // Separate style from behavior by using dedicated classes for JavaScript
10 | // manipulation rather than relying on classes already in use for CSS. This way,
11 | // we can modify classes for style purposes without fear of breaking JS, and
12 | // vice versa. To make the distinction clear, classes used for JavaScript
13 | // manipulation should be prefixed with 'js-'. These JavaScript hooks must never
14 | // be used for styling purposes. See the section ‘Formatting Class Names’ for
15 | // more information on naming conventions.
16 |
17 | // First import decanter as no markup.
18 | @import 'decanter/core/src/scss/decanter-no-markup';
19 |
20 | // Then we override the variables, mixins, and functions.
21 | @import
22 | '../config/index',
23 | '../utilities/index';
24 |
25 | // Roll up.
26 |
27 | @import
28 | 'hidden',
29 | 'mobile-hidden',
30 | 'visually-hidden';
31 |
--------------------------------------------------------------------------------
/src/scss/theme/_back_to_top.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | #back-to-top {
4 | display: none;
5 | position: fixed;
6 | bottom: 20px;
7 | right: 20px;
8 | text-align: center;
9 | border-radius: 7px;
10 | }
11 |
--------------------------------------------------------------------------------
/src/scss/theme/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // 5. Theme
5 | //
6 |
7 | // Purely visual styling (“look-and-feel”) for a component.
8 | //
9 | // Purely visual styling, such as border, box-shadow, colors and backgrounds,
10 | // font properties, etc. Ideally, these should be separated enough from a
11 | // component’s structure to be “swappable”, and omitting these entirely should
12 | // not break the component’s functionality or basic usability.
13 |
14 | // First import decanter as no markup.
15 | @import 'decanter/core/src/scss/decanter-no-markup';
16 |
17 | // Then we override the variables, mixins, and functions.
18 | @import
19 | '../config/index',
20 | '../utilities/index';
21 |
22 | @import 'menu/index', 'back_to_top';
23 |
--------------------------------------------------------------------------------
/src/scss/theme/menu/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import "local-tasks";
4 |
--------------------------------------------------------------------------------
/src/scss/utilities/functions/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
--------------------------------------------------------------------------------
/src/scss/utilities/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // First import decanter as no markup.
4 | @import 'decanter/core/src/scss/decanter-no-markup';
5 |
6 | // Then we override the variables, mixins, and functions.
7 | @import
8 | '../config/index',
9 | 'functions/index',
10 | 'mixins/index',
11 | 'variables/index';
12 |
--------------------------------------------------------------------------------
/src/scss/utilities/mixins/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
7 | @import 'typography/index';
8 |
--------------------------------------------------------------------------------
/src/scss/utilities/mixins/typography/_type-a.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // Type A font style.
5 | //
6 | // Overrides A Decanter mixin.
7 | // See: node_modules/decanter/core/src/scss/utilities/mixins/typography/_type-a.scss
8 | //
9 | @mixin type-a {
10 | @include modular-typography(5);
11 | letter-spacing: -0.016em;
12 |
13 | @include grid-media-max('sm') {
14 | font-size: modular-scale(5) * $su-displays-mobile-factor;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/scss/utilities/mixins/typography/index.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | //
4 | // Typography
5 | //
6 | // Mixins for Typography.
7 | //
8 |
9 | @import 'type-a';
10 |
--------------------------------------------------------------------------------
/src/scss/utilities/variables/components/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | //
4 | // Components
5 | //
6 | // Variables for components.
7 | //
8 | // Style guide: Variables.Components
9 | //
10 |
11 | @import
12 | 'multi-menu',
13 | 'secondary-nav';
14 |
--------------------------------------------------------------------------------
/src/scss/utilities/variables/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | ///
4 | /// ROLL UP
5 | ///
6 |
7 | @import 'components/index';
8 |
--------------------------------------------------------------------------------
/stanford_basic.breakpoints.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Used to generate responsive images and other items.
3 | # https://www.advomatic.com/blog/adding-responsive-images-to-your-drupal-8-site
4 | #
5 | stanford_basic.xs:
6 | label: XS
7 | mediaQuery: '(min-width: 0em)'
8 | weight: 0
9 | multipliers:
10 | - 1x
11 | - 2x
12 | stanford_basic.sm:
13 | label: SM
14 | mediaQuery: 'screen and (min-width: 576px)'
15 | weight: 0
16 | multipliers:
17 | - 1x
18 | - 2x
19 | stanford_basic.md:
20 | label: MD
21 | mediaQuery: 'screen and (min-width: 768px)'
22 | weight: 0
23 | multipliers:
24 | - 1x
25 | - 2x
26 | stanford_basic.lg:
27 | label: LG
28 | mediaQuery: 'screen and (min-width: 992px)'
29 | weight: 0
30 | multipliers:
31 | - 1x
32 | - 2x
33 | stanford_basic.xl:
34 | label: XL
35 | mediaQuery: 'screen and (min-width: 1200px)'
36 | weight: 0
37 | multipliers:
38 | - 1x
39 | - 2x
40 | stanford_basic.2xl:
41 | label: 2XL
42 | mediaQuery: 'screen and (min-width: 1500px)'
43 | weight: 0
44 | multipliers:
45 | - 1x
46 | - 2x
47 |
--------------------------------------------------------------------------------
/stanford_basic.info.yml:
--------------------------------------------------------------------------------
1 | name: 'Stanford Basic'
2 | type: theme
3 | description: 'Stanford Basic Branding Theme.'
4 | package: Stanford
5 | version: 8.5.20-dev
6 | core_version_requirement: ^9
7 | dependencies:
8 | - components:components
9 | 'base theme': stable9
10 | regions:
11 | page_top: 'Page top'
12 | header: Header
13 | search: Search
14 | menu: Menu
15 | help: Help
16 | content: Content
17 | footer: Footer
18 | page_bottom: 'Page bottom'
19 | features:
20 | - favicon
21 | - logo
22 | components:
23 | namespaces:
24 | basic: templates
25 | basic-dist: dist/templates
26 | decanter: dist/templates/decanter
27 | libraries:
28 | - stanford_basic/basic
29 | ckeditor_stylesheets:
30 | - dist/css/ckeditor.css
31 | libraries-override:
32 | jumpstart_ui/base: false
33 |
--------------------------------------------------------------------------------
/templates/block/block--local-actions-block.html.twig:
--------------------------------------------------------------------------------
1 | {% extends "block.html.twig" %}
2 | {#
3 | /**
4 | * @file
5 | * Theme override for local actions (primary admin actions.)
6 | */
7 | #}
8 | {% block content %}
9 | {% if content %}
10 |
{{ content }}
11 | {% endif %}
12 | {% endblock %}
13 |
--------------------------------------------------------------------------------
/templates/block/block--local-tasks-block.html.twig:
--------------------------------------------------------------------------------
1 | {% extends "@block/block.html.twig" %}
2 | {% set attributes = attributes.addClass('block--local-tasks') %}
3 | {#
4 | /**
5 | * @file
6 | * Theme override for tabs.
7 | */
8 | #}
9 | {% block content %}
10 | {% if content %}
11 |
12 | {{ content }}
13 |
14 | {% endif %}
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/templates/block/block--search-form-block.html.twig:
--------------------------------------------------------------------------------
1 | {% set attributes = attributes.addClass('su-site-search') %}
2 |
3 | {% include "@basic-dist/decanter/components/site-search/site-search.twig" with
4 | {
5 | "attributes": attributes|without('class', 'role'),
6 | "modifier_class": attributes.class,
7 | "action": content['#action'],
8 | "method": "get",
9 | "search_label": "Search this site"|t,
10 | "placeholder": "Search this site"|t,
11 | "search_input_name": "keys",
12 | }
13 | %}
14 |
--------------------------------------------------------------------------------
/templates/block/block--system-menu-block--main.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for a menu block.
5 | *
6 | * Available variables:
7 | * - plugin_id: The ID of the block implementation.
8 | * - label: The configured label of the block if visible.
9 | * - configuration: A list of the block's configuration values.
10 | * - label: The configured label for the block.
11 | * - label_display: The display settings for the label.
12 | * - provider: The module or other provider that provided this block plugin.
13 | * - Block plugin specific settings will also be stored here.
14 | * - content: The content of this block.
15 | * - attributes: HTML attributes for the containing element.
16 | * - id: A valid HTML ID and guaranteed unique.
17 | * - title_attributes: HTML attributes for the title element.
18 | * - content_attributes: HTML attributes for the content element.
19 | * - title_prefix: Additional output populated by modules, intended to be
20 | * displayed in front of the main title tag that appears in the template.
21 | * - title_suffix: Additional output populated by modules, intended to be
22 | * displayed after the main title tag that appears in the template.
23 | *
24 | * Headings should be used on navigation menus that consistently appear on
25 | * multiple pages. When this menu block's label is configured to not be
26 | * displayed, it is automatically made invisible using the 'visually-hidden' CSS
27 | * class, which still keeps it visible for screen-readers and assistive
28 | * technology. Headings allow screen-reader and keyboard only users to navigate
29 | * to or skip the links.
30 | * See http://juicystudio.com/article/screen-readers-display-none.php and
31 | * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
32 | */
33 | #}
34 | {# Menu. #}
35 | {% block content %}
36 | {{ content }}
37 | {% endblock %}
38 |
--------------------------------------------------------------------------------
/templates/block/block.html.twig:
--------------------------------------------------------------------------------
1 | {% extends "@block/block.html.twig" %}
2 | {#
3 | /**
4 | * @file
5 | * Theme override to display a block.
6 | *
7 | * Available variables:
8 | * - plugin_id: The ID of the block implementation.
9 | * - label: The configured label of the block if visible.
10 | * - configuration: A list of the block's configuration values.
11 | * - label: The configured label for the block.
12 | * - label_display: The display settings for the label.
13 | * - provider: The module or other provider that provided this block plugin.
14 | * - Block plugin specific settings will also be stored here.
15 | * - content: The content of this block.
16 | * - attributes: array of HTML attributes populated by modules, intended to
17 | * be added to the main container tag of this template.
18 | * - id: A valid HTML ID and guaranteed unique.
19 | * - title_attributes: Same as attributes, except applied to the main title
20 | * tag that appears in the template.
21 | * - title_prefix: Additional output populated by modules, intended to be
22 | * displayed in front of the main title tag that appears in the template.
23 | * - title_suffix: Additional output populated by modules, intended to be
24 | * displayed after the main title tag that appears in the template.
25 | *
26 | * @see template_preprocess_block()
27 | */
28 | #}
29 | {% set attributes = attributes.addClass([
30 | 'block-' ~ configuration.provider|clean_class,
31 | attributes.id
32 | ]) %}
33 | {% set title_attributes = title_attributes.addClass('block__title') %}
34 |
--------------------------------------------------------------------------------
/templates/content/ds-entity-view.html.twig:
--------------------------------------------------------------------------------
1 |
2 | {{ content }}
3 |
4 |
--------------------------------------------------------------------------------
/templates/content/media.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override to display a media item.
5 | *
6 | * Available variables:
7 | * - name: Name of the media.
8 | * - content: Media content.
9 | *
10 | * @see template_preprocess_media()
11 | *
12 | * @ingroup themeable
13 | */
14 | #}
15 |
16 | {{ title_suffix.contextual_links }}
17 | {{ content }}
18 |
19 |
--------------------------------------------------------------------------------
/templates/content/page-title.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for page titles.
5 | *
6 | * Available variables:
7 | * - title_attributes: HTML attributes for the page title element.
8 | * - title_prefix: Additional output populated by modules, intended to be
9 | * displayed in front of the main title tag that appears in the template.
10 | * - title: The page title, for use in the actual content.
11 | * - title_suffix: Additional output populated by modules, intended to be
12 | * displayed after the main title tag that appears in the template.
13 | */
14 | #}
15 | {% if title %}
16 |
17 |
{{ title }}
18 |
19 | {% endif %}
20 |
--------------------------------------------------------------------------------
/templates/contrib/patterns-variant-meta-information.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * UI Pattern variant meta information.
5 | */
6 | #}
7 |
8 | {% if variant is not empty %}
9 |
10 |
11 |
12 | {{ "Variant"|t }}
13 | {{ "Name"|t }}
14 | {{ "Modifier Class"|t }}
15 | {{ "Description"|t }}
16 |
17 |
18 |
19 |
20 | {{ variant.label }}
21 | {{ variant.name }}
22 | {{ variant.modifier_class }}
23 | {{ variant.description }}
24 |
25 |
26 |
27 | {% endif %}
28 |
--------------------------------------------------------------------------------
/templates/core/breadcrumb.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for a breadcrumb trail.
5 | *
6 | * Available variables:
7 | * - breadcrumb: Breadcrumb trail items.
8 | */
9 | #}
10 | {% if breadcrumb %}
11 |
12 | {{ 'Breadcrumb'|t }}
13 |
14 | {% for item in breadcrumb %}
15 |
16 | {% if item.url %}
17 | {{ item.text }}
18 | {% else %}
19 | {{ item.text }}
20 | {% endif %}
21 |
22 | {% endfor %}
23 |
24 |
25 | {% endif %}
26 |
--------------------------------------------------------------------------------
/templates/core/field--comment.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Default theme override for comment fields.
5 | *
6 | * Available variables:
7 | * - attributes: HTML attributes for the containing element.
8 | * - label_hidden: Whether to show the field label or not.
9 | * - title_attributes: HTML attributes for the title.
10 | * - label: The label for the field.
11 | * - title_prefix: Additional output populated by modules, intended to be
12 | * displayed in front of the main title tag that appears in the template.
13 | * - title_suffix: Additional title output populated by modules, intended to
14 | * be displayed after the main title tag that appears in the template.
15 | * - comments: List of comments rendered through comment.html.twig.
16 | * - content_attributes: HTML attributes for the form title.
17 | * - comment_form: The 'Add new comment' form.
18 | * - comment_display_mode: Is the comments are threaded.
19 | * - comment_type: The comment type bundle ID for the comment field.
20 | * - entity_type: The entity type to which the field belongs.
21 | * - field_name: The name of the field.
22 | * - field_type: The type of the field.
23 | * - label_display: The display settings for the label.
24 | *
25 | * @see template_preprocess_field()
26 | * @see comment_preprocess_field()
27 | */
28 | #}
29 |
30 | {% if comments and not label_hidden and (entity.entityType != 'node' or entity.bundle != 'forum') %}
31 | {{ title_prefix }}
32 | {{ label }}
33 | {{ title_suffix }}
34 | {% endif %}
35 |
36 | {{ comments }}
37 |
38 | {% if comment_form %}
39 | {{ 'Add new comment'|t }}
40 | {{ comment_form }}
41 | {% endif %}
42 |
43 |
--------------------------------------------------------------------------------
/templates/core/field.html.twig:
--------------------------------------------------------------------------------
1 | {% extends "@stable9/field/field.html.twig" %}
2 |
3 | {# Create classes array #}
4 | {% set classes = [] %}
5 |
6 | {# BEM inspired class syntax: https://en.bem.info/
7 | Enable this code if you would like field classes like "article__tags", where article is the content type and field_tags is the field name.
8 | {% set classes = classes|merge([
9 | bundle ~ '__' ~ field_name|replace({'field_' : ''})|clean_class
10 | ]) %}
11 | #}
12 |
13 | {% set attributes = attributes.addClass(classes) %}
14 |
--------------------------------------------------------------------------------
/templates/core/views-mini-pager.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for a views mini-pager.
5 | *
6 | * Available variables:
7 | * - items: List of pager items.
8 | *
9 | * @see template_preprocess_views_mini_pager()
10 | */
11 | #}
12 | {% if items.previous or items.next %}
13 |
41 | {% endif %}
42 |
--------------------------------------------------------------------------------
/templates/field/field--node--title.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for the node title field.
5 | *
6 | * This is an override of field.html.twig for the node title field. See that
7 | * template for documentation about its details and overrides.
8 | *
9 | * Available variables:
10 | * - attributes: HTML attributes for the containing span element.
11 | * - items: List of all the field items. Each item contains:
12 | * - attributes: List of HTML attributes for each item.
13 | * - content: The field item content.
14 | * - entity_type: The entity type to which the field belongs.
15 | * - field_name: The name of the field.
16 | * - field_type: The type of the field.
17 | * - label_display: The display settings for the label.
18 | *
19 | * @see field.html.twig
20 | */
21 | #}
22 |
23 | {%- for item in items -%}
24 | {{ item.content }}
25 | {%- endfor -%}
26 |
27 |
--------------------------------------------------------------------------------
/templates/layouts/README.md:
--------------------------------------------------------------------------------
1 | # Put your layouts here.
2 |
--------------------------------------------------------------------------------
/templates/menus/macros/nav-menu.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * Macro for creating nested menus.
4 | */
5 | #}
6 | {% macro nav_menu(items, menu_level, class_prefix) %}
7 | {% import _self as menus %}
8 |
49 | {% endmacro %}
50 |
--------------------------------------------------------------------------------
/templates/menus/menu--main.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Main Navigation Component
5 | *
6 | * A navigation menu for the website.
7 | *
8 | * Available variables:
9 | * - attributes: For additional HTML attributes not already provided.
10 | * - modifier_class: Additional css classes to change look and behaviour of the component.
11 | * - toggle_modifier_class: Additional css classes to change look and behaviour of the toggle.
12 | * - aria_label: Aria label for the
element. Default is "main menu". If there are multiple instances of the component on the same page, use a different aria_label for each instance.
13 | *
14 | */
15 | #}
16 | {% set toggle_text = "Menu"|t %}
17 | {% set attributes = attributes.addClass(['su-multi-menu', 'su-multi-menu--buttons', 'su-multi-menu--right', 'no-js']) %}
18 | {% set attributes = attributes.setAttribute('aria-label', 'main menu') %}
19 | {# Macros #}
20 | {%- import "@basic/menus/macros/nav-menu.twig" as menus -%}
21 |
22 | {% block multimenubutton %}
23 |
24 | {% endblock %}
25 | {% spaceless %}
26 | {% if items is iterable %}
27 | {{ menus.nav_menu(items, 1, 'su-multi-menu') }}
28 | {% else %}
29 | {# If custom markup is provided, emit it as is #}
30 | {{ items }}
31 | {% endif %}
32 | {% endspaceless %}
33 |
34 |
--------------------------------------------------------------------------------
/templates/menus/menu--secondary-nav.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Secondary Navigation Template
5 | *
6 | * A sidebar style navigation.
7 | *
8 | * Available variables:
9 | * - attributes: For additional HTML attributes not already provided.
10 | * - modifier_class: Additional css classes to change look and behaviour of the component.
11 | * - toggle_modifier_class: Additional css classes to change look and behaviour of the toggle.
12 | * - aria_label: Aria label for the element. Default is "main menu". If there are multiple instances of the component on the same page, use a different aria_label for each instance.
13 | *
14 | */
15 | #}
16 |
17 | {% set attributes = attributes.addClass(['su-secondary-nav--light', 'su-secondary-nav', 'su-secondary-nav--static', 'no-js']) %}
18 | {% set attributes = attributes.setAttribute('aria-label', aria_label|default('secondary menu')) %}
19 | {# Macros #}
20 | {%- import "@basic/menus/macros/secondary-nav-menu.twig" as menus -%}
21 | {{ 'Skip to main content'|t }}
22 |
23 | {{ 'Secondary Navigation'|t }}
24 | {% spaceless %}
25 | {% if items is iterable %}
26 | {{ menus.secondary_nav_menu(items, 1, 'su-secondary-nav') }}
27 | {% else %}
28 | {# If custom markup is provided, emit it as is #}
29 | {{ items }}
30 | {% endif %}
31 | {% endspaceless %}
32 |
33 |
--------------------------------------------------------------------------------
/templates/menus/menu-local-task.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Default theme implementation for a local task link.
5 | *
6 | * Available variables:
7 | * - attributes: HTML attributes for the wrapper element.
8 | * - is_active: Whether the task item is an active tab.
9 | * - link: A rendered link element.
10 | *
11 | * Note: This template renders the content for each task item in
12 | * menu-local-tasks.html.twig.
13 | *
14 | * @see template_preprocess_menu_local_task()
15 | *
16 | * @ingroup themeable
17 | */
18 | #}
19 | {{ link }}
20 |
--------------------------------------------------------------------------------
/templates/menus/menu-local-tasks.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Default theme implementation to display primary and secondary local tasks.
5 | *
6 | * Available variables:
7 | * - primary: HTML list items representing primary tasks.
8 | * - secondary: HTML list items representing primary tasks.
9 | *
10 | * Each item in these variables (primary and secondary) can be individually
11 | * themed in menu-local-task.html.twig.
12 | *
13 | * @see template_preprocess_menu_local_tasks()
14 | *
15 | * @ingroup themeable
16 | */
17 | #}
18 | {% if primary %}
19 | {{ 'Primary tabs'|t }}
20 |
21 | {% endif %}
22 | {% if secondary %}
23 | {{ 'Secondary tabs'|t }}
24 |
25 | {% endif %}
26 |
--------------------------------------------------------------------------------
/templates/menus/menu.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override to display a menu.
5 | *
6 | * Available variables:
7 | * - menu_name: The machine name of the menu.
8 | * - items: A nested list of menu items. Each menu item contains:
9 | * - attributes: HTML attributes for the menu item.
10 | * - below: The menu item child items.
11 | * - title: The menu link title.
12 | * - url: The menu link url, instance of \Drupal\Core\Url
13 | * - localized_options: Menu link localized options.
14 | * - is_expanded: TRUE if the link has visible children within the current
15 | * menu tree.
16 | * - is_collapsed: TRUE if the link has children within the current menu tree
17 | * that are not currently visible.
18 | * - in_active_trail: TRUE if the link is in the active trail.
19 | */
20 | #}
21 | {% import _self as menus %}
22 |
23 | {#
24 | We call a macro which calls itself to render the full tree.
25 | @see http://twig.sensiolabs.org/doc/tags/macro.html
26 | #}
27 | {{ menus.menu_links(items, attributes, 0) }}
28 |
29 | {% macro menu_links(items, attributes, menu_level) %}
30 | {% import _self as menus %}
31 | {% if items %}
32 | {% if menu_level == 0 %}
33 |
34 | {% else %}
35 |
54 | {% endif %}
55 | {% endmacro %}
56 |
--------------------------------------------------------------------------------
/templates/navigation/toolbar.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for the administrative toolbar.
5 | *
6 | * Available variables:
7 | * - attributes: HTML attributes for the wrapper.
8 | * - toolbar_attributes: HTML attributes to apply to the toolbar.
9 | * - toolbar_heading: The heading or label for the toolbar.
10 | * - tabs: List of tabs for the toolbar.
11 | * - attributes: HTML attributes for the tab container.
12 | * - link: Link or button for the menu tab.
13 | * - trays: Toolbar tray list, each associated with a tab. Each tray in trays
14 | * contains:
15 | * - attributes: HTML attributes to apply to the tray.
16 | * - label: The tray's label.
17 | * - links: The tray menu links.
18 | * - remainder: Any non-tray, non-tab elements left to be rendered.
19 | *
20 | * @see template_preprocess_toolbar()
21 | */
22 | #}
23 | {% set toolbar_attributes = toolbar_attributes.removeAttribute('role') %}
24 | {% extends '@stable9/navigation/toolbar.html.twig' %}
25 |
--------------------------------------------------------------------------------
/templates/page--user--login.html.twig:
--------------------------------------------------------------------------------
1 | {% extends "page.html.twig" %}
2 |
3 | {# Remove Nav and Search. #}
4 | {%- block block_header -%}
5 | {%- if page.header -%}
6 |
11 | {%- endif -%}
12 | {%- endblock -%}
13 |
14 | {% block block_footer %}
15 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/templates/page.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Main Page Template.
5 | *
6 | * Available variables:
7 | * - page: The content regions for this page.
8 | * - attributes: HTML attributes for the region div.
9 | *
10 | * @see template_preprocess_page()
11 | */
12 | #}
13 |
14 | {# Template Paths #}
15 | {%- if template_brand_bar is empty -%}
16 | {%- set template_brand_bar = "@basic-dist/decanter/components/brand-bar/brand-bar.twig" -%}
17 | {%- endif -%}
18 |
19 | {%- if template_global_footer is empty -%}
20 | {%- set template_global_footer = "@basic-dist/decanter/components/global-footer/global-footer.twig" -%}
21 | {%- endif -%}
22 | {# End Template Paths. #}
23 |
24 | {# Brand Bar #}
25 | {%- block block_brandbar -%}
26 | {%- include template_brand_bar with { modifier_class : brand_bar_variant } -%}
27 | {%- endblock -%}
28 |
29 | {# Help Section #}
30 | {%- block block_help -%}
31 | {{ page.help }}
32 | {%- endblock -%}
33 |
34 | {# Masthead Section. #}
35 | {%- block block_header -%}
36 | {%- if page.header or page.search or page.menu -%}
37 |
44 | {%- endif -%}
45 | {%- endblock -%}
46 |
47 | {# Main Page Content Section #}
48 |
49 | {%- block block_main -%}
50 | {{ page.content }}
51 | {%- endblock -%}
52 |
53 |
54 | {# Footer Section #}
55 | {%- block block_footer -%}
56 |
60 | {%- endblock -%}
61 |
62 |
63 |
64 | Back to Top
65 |
66 |
67 |
--------------------------------------------------------------------------------
/templates/region.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override to display a region.
5 | *
6 | * Available variables:
7 | * - content: The content for this region, typically blocks.
8 | * - attributes: HTML attributes for the region div.
9 | * - region: The name of the region variable as defined in the theme's
10 | * .info.yml file.
11 | *
12 | * @see template_preprocess_region()
13 | */
14 | #}
15 | {{ content }}
16 |
--------------------------------------------------------------------------------
/templates/search/item-list--search-results.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | /**
3 | * @file
4 | * Theme override for an item list.
5 | *
6 | * Available variables:
7 | * - items: A list of items. Each item contains:
8 | * - attributes: HTML attributes to be applied to each list item.
9 | * - value: The content of the list element.
10 | * - title: The title of the list.
11 | * - list_type: The tag for list element ("ul" or "ol").
12 | * - wrapper_attributes: HTML attributes to be applied to the list wrapper.
13 | * - attributes: HTML attributes to be applied to the list.
14 | * - empty: A message to display when there are no items. Allowed value is a
15 | * string or render array.
16 | * - context: A list of contextual data associated with the list. May contain:
17 | * - list_style: The custom list style.
18 | *
19 | * @see template_preprocess_item_list()
20 | */
21 | #}
22 |
23 | {% extends "item-list.html.twig" %}
24 | {%- if items -%}
25 | {%- for item in items -%}
26 | {% set item = item.attributes.addClass("search-result__item") %}
27 | {%- endfor -%}
28 | {%- endif -%}
29 |
--------------------------------------------------------------------------------
/tests/behat/features/brandbar.feature:
--------------------------------------------------------------------------------
1 | Feature: Brandbar
2 | In order to verify that brandbar shows up correctly
3 | As an administrative user
4 | I should be able to change the color variant and see the expected result.
5 |
6 | @api
7 | Scenario: Ensure brandbar exists on the front end
8 | Given I am logged in as a user with the "Administrator" role
9 | Given I am on the homepage
10 | Then I should see 1 ".su-brand-bar" element
11 |
12 | @api
13 | Scenario: Ensure variants work
14 | Given I am logged in as a user with the "Administrator" role
15 | Given I am on "admin/appearance/settings/stanford_basic"
16 | Then I select "Bright" from "Brand Bar Variant"
17 | Then I press the "Save configuration" button
18 | Given I am on the homepage
19 | Then I should see 1 ".su-brand-bar--bright" element
20 | Given I am on "admin/appearance/settings/stanford_basic"
21 | Then I select "Dark" from "Brand Bar Variant"
22 | Then I press the "Save configuration" button
23 | Given I am on the homepage
24 | Then I should see 1 ".su-brand-bar--dark" element
25 | Given I am on "admin/appearance/settings/stanford_basic"
26 | Then I select "White" from "Brand Bar Variant"
27 | Then I press the "Save configuration" button
28 | Given I am on the homepage
29 | Then I should see 1 ".su-brand-bar--white" element
30 |
--------------------------------------------------------------------------------
/tests/behat/features/globalfooter.feature:
--------------------------------------------------------------------------------
1 | Feature: Brandbar
2 | In order to verify that global footer shows up correctly
3 | As an end user
4 | I should be able to see the brand bar at the bottom of each page.
5 |
6 | @api
7 | Scenario: Ensure global footer exists on the front end
8 | Given I am on the homepage
9 | Then I should see 1 ".su-global-footer" element
10 |
--------------------------------------------------------------------------------