Skip to content

Commit

Permalink
Add theme properties for default navigation bar buttons
Browse files Browse the repository at this point in the history
* Allow controlling width of buttons and icon size. Center icons in
  buttons.

* Allow controlling inline padding of navigation bar.

* Allow replacing mobile menu button with custom theme icon.

REDMINE-20674
  • Loading branch information
tf committed Jul 30, 2024
1 parent 21e90c1 commit fe97e9a
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ System](https://material.io/design/color/the-color-system.html#color-theme-creat
| Name | Description |
| ---- | ----------- |
| `default_navigation_bar_height` | Height of the navigation bar excluding the progress bar. |
| `default_navigation_padding_inline` | Space on the left and right inside the navigation bar. |
| `default_navigation_button_width` | Width of buttons like the mobile menu, share or unmute. |
| `default_navigation_button_icon_size` | Size of SVG icons inside buttons. |
| `default_navigation_scroller_top` | Position of the horizontal scroller containing the chapter list. |
| `default_navigation_scroll_button_top` | Position of the left/right scroll buttons visible when the chapter list overflows horizontally. |
| `default_navigation_chapter_link_height` | Height of the links inside the horizontal chapter list. |
Expand Down
15 changes: 11 additions & 4 deletions entry_types/scrolled/doc/creating_themes/custom_icons.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,21 @@ The following icons can be customized:

| Name | Description |
| ---- | ----------- |
| arrowLeft | Arrow used for scroll indicators (e.g., in chapter scroller or image gallery). |
| arrowRight | Arrow used for scroll indicators (e.g., in chapter scroller or image gallery). |
| copyright | Used in inline file rights. |
| close | Used for overlay close buttons. |
| email | Used in share box. |
| expand | Arrow icon displayed in FAQ content elements. |
| facebook | Used in share box. |
| gear | Used for quality menu in video players. |
| information | Used for button to toggle credits box in navigation bars and third party consent tooltips. |
| linkedIn | Used in share box. |
| menu | Used in place of the animated burger menu item in the mobile navigation. |
| muted | Used for button to unmute sound in navigation bar and sound disclaimer content element. |
| share | Used for share button in navigation bar. |
| unmuted | Used button to mute sound in navigation bar and sound disclaimer content element. |
| email | Used in share box. |
| facebook | Used in share box. |
| linkedIn | Used in share box. |
| telegram | Used in share box. |
| twitter | Used in share box. |
| unmuted | Used button to mute sound in navigation bar and sound disclaimer content element. |
| world | Used for translations menu. |
| whatsApp | Used in share box. |
28 changes: 28 additions & 0 deletions entry_types/scrolled/package/spec/frontend/ThemeIcon-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,32 @@ describe("ThemeIcon", () => {

expect(svg).toHaveAttribute('xlink:href', '/path/to/custom-share.svg#icon')
});

it('supports fallback render prop', () => {
const {queryByText} = renderInEntry(
<ThemeIcon name="menu"
renderFallback={() => <div>Menu</div> } />
);

expect(queryByText('Menu')).not.toBeNull();
});

it('prefers custom theme icon over fallback render prop', () => {
const {queryByText, container} = renderInEntry(
<ThemeIcon name="menu"
renderFallback={() => <div>Menu</div> } />,
{
seed: {
themeAssets: {
icons: {menu: '/path/to/custom-menu.svg'}
}
}
}
);

const svg = container.querySelector('svg use');

expect(svg).toHaveAttribute('xlink:href', '/path/to/custom-menu.svg#icon')
expect(queryByText('Menu')).toBeNull();
});
});
12 changes: 8 additions & 4 deletions entry_types/scrolled/package/src/frontend/ThemeIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,19 @@ const icons = {
*
* @param {Object} props
* @param {string} props.name -
* Either: copyright, expand, gear, information, muted, share, unmuted, close,
* email, facebook, linkedIn, telegram, twitter, whatsApp,
* Either: arrowLeft, arrowRight, copyright, close, email, expand, facebook,
* gear, information, linkedIn, menu, muted, share, telegram, twitter,
* unmuted, world, whatsApp,
* arrowLeft, arrowRight, world
* @params {number} [props.width] - Image width.
* @params {number} [props.height] - Image height.
*/
export function ThemeIcon({name, width, height}) {
export function ThemeIcon({name, width, height, renderFallback}) {
const theme = useTheme();
const FallbackIcon = icons[name];
const themeAsset = theme.assets.icons[name];

if (!FallbackIcon) {
if (!FallbackIcon && !renderFallback) {
throw(new Error(
`Unknown icon '${name}'. Available options: ${Object.keys(icons).join(', ')}.`
));
Expand All @@ -70,6 +71,9 @@ export function ThemeIcon({name, width, height}) {
<use xlinkHref={`${themeAsset}#icon`} />
</svg>
}
else if (renderFallback) {
return renderFallback();
}
else {
return <FallbackIcon width={width} height={height} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
--default-navigation-bar-height:
var(--theme-default-navigation-bar-height, 50px);

--default-navigation-padding-inline:
var(--theme-default-navigation-padding-inline, 12px);

--default-navigation-scroller-top:
var(--theme-default-navigation-scroller-top, 0);

Expand Down Expand Up @@ -52,17 +55,32 @@
padding-top: var(--default-navigation-scroller-top);
}

.button {
composes: unstyledButton from '../../frontend/utils.module.css';
display: flex;
align-items: center;
justify-content: center;
width: var(--theme-default-navigation-button-width, 40px);
height: var(--default-navigation-bar-height);
cursor: pointer;
}

.button svg {
width: var(--theme-default-navigation-button-icon-size, 35px);
height: var(--theme-default-navigation-button-icon-size, 35px);
}

.menuIcon {
composes: button;
position: absolute;
top: 0;
left: 12px;
height: var(--default-navigation-bar-height);
left: var(--default-navigation-padding-inline);
}

.contextIcons {
position: absolute;
top: 0px;
right: 12px;
right: var(--default-navigation-padding-inline);
display: flex;
}

Expand All @@ -71,21 +89,12 @@
}

.contextIcon {
composes: unstyledButton from '../../frontend/utils.module.css';
cursor: pointer;
width: 40px;
height: var(--default-navigation-bar-height);
composes: button;
color: var(--theme-widget-secondary-color);
fill: currentcolor;
stroke: currentColor;
}

.contextIcon svg {
width: 35px;
height: 35px;
margin: 7px 2px;
}

div:focus-within > .contextIcon,
.contextIcon:hover {
color: var(--theme-widget-primary-color);
Expand All @@ -94,6 +103,7 @@ div:focus-within > .contextIcon,
.logo {
display: flex;
align-items: center;
position: absolute;
top: 0;
left: 15px;
height: 100%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@ import classNames from 'classnames';
import headerStyles from "./DefaultNavigation.module.css";
import styles from "./HamburgerIcon.module.css";
import hamburgerIconStyles from "./HamburgerIcons.module.css";
import {useI18n, useTheme} from 'pageflow-scrolled/frontend';
import {useI18n, useTheme, ThemeIcon} from 'pageflow-scrolled/frontend';

export function HamburgerIcon(props) {
export function HamburgerIcon({mobileNavHidden, onClick}) {
const theme = useTheme();
const {t} = useI18n();

return (
<div className={styles.burgerMenuIconContainer}>
<button className={classNames(headerStyles.menuIcon,
styles.burgerMenuIcon,
hamburgerIconStyles.hamburger,
hamburgerIconStyles['hamburger--collapse'],
{[styles.small]:
theme.options.defaultNavigationMenuIconVariant === 'small'},
{[hamburgerIconStyles['is-active']]: !props.mobileNavHidden})}
title={props.mobileNavHidden ?
<button className={headerStyles.menuIcon}
title={mobileNavHidden ?
t('pageflow_scrolled.public.navigation.open_mobile_menu') :
t('pageflow_scrolled.public.navigation.close_mobile_menu')}
type="button"
onClick={props.onClick}>
<span className={hamburgerIconStyles['hamburger-box']}>
<span className={hamburgerIconStyles['hamburger-inner']}></span>
</span>
onClick={onClick}>
<ThemeIcon name="menu"
renderFallback={() =>
<span className={classNames(hamburgerIconStyles.hamburger,
hamburgerIconStyles['hamburger--collapse'],
{[styles.small]:
theme.options.defaultNavigationMenuIconVariant === 'small'},
{[hamburgerIconStyles['is-active']]: !mobileNavHidden})}>
<span className={hamburgerIconStyles['hamburger-box']}>
<span className={hamburgerIconStyles['hamburger-inner']}></span>
</span>
</span>
} />
</button>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
}
}

.burgerMenuIcon {
outline: none;
}

.small {
--hamburger-icon-transform: scale(0.7);
--hamburger-icon-line-width: 3px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,9 @@
* @link https://github.com/jonsuh/hamburgers
*/
.hamburger {
display: inline-block;
cursor: pointer;
transition-property: opacity, filter;
transition-duration: 0.15s;
transition-timing-function: linear;
font: inherit;
color: inherit;
text-transform: none;
background-color: transparent;
border: 0;
margin: 0;
overflow: visible;
}

.hamburger.is-active .hamburger-inner,
Expand All @@ -27,7 +18,7 @@
}

.hamburger-box {
width: 40px;
width: 30px;
height: 24px;
display: inline-block;
position: relative;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export function Logo() {
rel="noopener noreferrer"
href={theme.options.logoUrl}
className={classNames(
styles.menuIcon,
styles.logo,
{[styles.centerMobileLogo]:
theme.options.defaultNavigationMobileLogoPosition === 'center'}
Expand Down

0 comments on commit fe97e9a

Please sign in to comment.