mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 10:21:05 +00:00
Merge pull request #166 from mfeitoza/master
feat: Component based UIShell
This commit is contained in:
commit
3eb5893b51
32 changed files with 633 additions and 1151 deletions
|
@ -1,40 +1,42 @@
|
||||||
<script>
|
<script>
|
||||||
export let type = undefined;
|
export let type = undefined;
|
||||||
export let icon = undefined;
|
export let icon = undefined;
|
||||||
export let content = undefined;
|
|
||||||
export let componentIsActive = undefined;
|
export let componentIsActive = undefined;
|
||||||
|
|
||||||
|
let elRigthPanel = undefined;
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
import { cx } from '../../../lib';
|
||||||
import Icon from '../../Icon/Icon.svelte';
|
import Icon from '../../Icon/Icon.svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
|
|
||||||
|
function mouseUp({ target }) {
|
||||||
|
if (target && elRigthPanel) {
|
||||||
|
if (!elRigthPanel.contains(target)) {
|
||||||
|
componentIsActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<svelte:window on:mouseup={mouseUp} />
|
||||||
.component-form {
|
|
||||||
margin: 1rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="right-panel-action-component">
|
<div id="right-panel-action-component">
|
||||||
<button
|
<button
|
||||||
aria-label={type}
|
aria-label={type}
|
||||||
class={cx('--header__action', componentIsActive && '--header__action--active')}
|
class={cx('--header__action', componentIsActive && '--header__action--active')}
|
||||||
type="button"
|
type="button"
|
||||||
on:keydown={({ key }) => {
|
on:click={() => {
|
||||||
if (key === 'Enter') {
|
componentIsActive = true;
|
||||||
componentIsActive = !componentIsActive;
|
|
||||||
}
|
|
||||||
}}>
|
}}>
|
||||||
<Icon {...icon[0]} render={icon[0].render} />
|
<Icon {...icon} />
|
||||||
</button>
|
</button>
|
||||||
{#if componentIsActive}
|
{#if componentIsActive}
|
||||||
<div
|
<div
|
||||||
|
bind:this={elRigthPanel}
|
||||||
id="right-panel-action-component-form"
|
id="right-panel-action-component-form"
|
||||||
class={cx('--header-panel', '--header-panel--expanded')}
|
class={cx('--header-panel', '--header-panel--expanded')}
|
||||||
transition:slide={{ duration: 200 }}>
|
transition:slide={{ duration: 200 }}>
|
||||||
<div class="component-form">
|
<slot />
|
||||||
<svelte:component this={content} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
32
src/components/UIShell/GlobalHeader/HeaderActionLink.svelte
Normal file
32
src/components/UIShell/GlobalHeader/HeaderActionLink.svelte
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<script>
|
||||||
|
export let href = undefined;
|
||||||
|
export let type = undefined;
|
||||||
|
export let icon = undefined;
|
||||||
|
export let linkIsActive = undefined;
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
import Icon from '../../Icon/Icon.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.action-link {
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
.subject-divider {
|
||||||
|
color: #525252;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
border-bottom: 1px solid #525252;
|
||||||
|
margin: 32px 1rem 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<a
|
||||||
|
aria-label={type}
|
||||||
|
class={cx('--header__action', linkIsActive && '--header__action--active')}
|
||||||
|
class:action-link={true}
|
||||||
|
{href}>
|
||||||
|
<Icon {...icon} />
|
||||||
|
</a>
|
207
src/components/UIShell/GlobalHeader/HeaderActionSearch.svelte
Normal file
207
src/components/UIShell/GlobalHeader/HeaderActionSearch.svelte
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
<script>
|
||||||
|
export let searchIsActive = undefined;
|
||||||
|
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
import Icon from '../../Icon/Icon.svelte';
|
||||||
|
import { closeIcon, searchIcon } from '../constants';
|
||||||
|
import searchStore from '../searchStore';
|
||||||
|
|
||||||
|
let searchTabIndex = '0';
|
||||||
|
let closeTabIndex = '-1';
|
||||||
|
let elInput = undefined;
|
||||||
|
let elTypeSearch = undefined;
|
||||||
|
let isSearchFocus = false;
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
function dispatchInputs(event) {
|
||||||
|
const params = {
|
||||||
|
action: 'search',
|
||||||
|
textInput: event.target.value
|
||||||
|
};
|
||||||
|
dispatch('inputSearch', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUp({ target }) {
|
||||||
|
if (target && elTypeSearch) {
|
||||||
|
if (!elTypeSearch.contains(target)) {
|
||||||
|
searchIsActive = false;
|
||||||
|
isSearchFocus = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (!searchIsActive) {
|
||||||
|
if (elInput) {
|
||||||
|
elInput.value = '';
|
||||||
|
}
|
||||||
|
searchStore.clear();
|
||||||
|
}
|
||||||
|
$: if (searchIsActive) {
|
||||||
|
searchTabIndex = '-1';
|
||||||
|
closeTabIndex = '0';
|
||||||
|
} else {
|
||||||
|
searchTabIndex = '0';
|
||||||
|
closeTabIndex = '-1';
|
||||||
|
}
|
||||||
|
$: if (isSearchFocus) {
|
||||||
|
elInput.focus();
|
||||||
|
}
|
||||||
|
$: showResults = $searchStore ? true : false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.search-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
max-width: 28rem;
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
height: 3rem;
|
||||||
|
background-color: #393939;
|
||||||
|
color: #fff;
|
||||||
|
transition: max-width 0.11s cubic-bezier(0.2, 0, 0.38, 0.9),
|
||||||
|
background 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
||||||
|
}
|
||||||
|
.search-wrapper-hidden {
|
||||||
|
max-width: 3rem;
|
||||||
|
background-color: #161616;
|
||||||
|
}
|
||||||
|
.search-focus {
|
||||||
|
outline: 2px solid #fff;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
.search-wrapper-2 {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
border-bottom: 1px solid #393939;
|
||||||
|
}
|
||||||
|
.btn-search {
|
||||||
|
width: 3rem;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 1;
|
||||||
|
transition: background-color 0.11s cubic-bezier(0.2, 0, 0.38, 0.9),
|
||||||
|
opacity 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
||||||
|
}
|
||||||
|
.btn-search-disabled {
|
||||||
|
border: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.input-search {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.375rem;
|
||||||
|
letter-spacing: 0;
|
||||||
|
color: #fff;
|
||||||
|
caret-color: #fff;
|
||||||
|
background-color: initial;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 3rem;
|
||||||
|
padding: 0;
|
||||||
|
transition: opacity 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
||||||
|
}
|
||||||
|
.input-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.btn-clear {
|
||||||
|
width: 3rem;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 1;
|
||||||
|
display: block;
|
||||||
|
transition: background-color 0.11s cubic-bezier(0.2, 0, 0.38, 0.9),
|
||||||
|
opacity 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
||||||
|
}
|
||||||
|
.btn-clear:hover {
|
||||||
|
background-color: #4c4c4c;
|
||||||
|
}
|
||||||
|
.btn-clear-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.search-list {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
padding: 1rem 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 3rem;
|
||||||
|
background-color: #161616;
|
||||||
|
border: 1px solid #393939;
|
||||||
|
border-top: none;
|
||||||
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<svelte:window on:mouseup={mouseUp} />
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={elTypeSearch}
|
||||||
|
class="search-wrapper"
|
||||||
|
class:search-wrapper-hidden={!searchIsActive}
|
||||||
|
class:search-focus={isSearchFocus || searchIsActive}
|
||||||
|
role="search">
|
||||||
|
<div
|
||||||
|
id="right-panel-action-search"
|
||||||
|
class="search-wrapper-2"
|
||||||
|
role="combobox"
|
||||||
|
aria-expanded={searchIsActive}>
|
||||||
|
<button
|
||||||
|
tabindex={searchTabIndex}
|
||||||
|
aria-label="Search"
|
||||||
|
class={cx('--header__action')}
|
||||||
|
class:btn-search={true}
|
||||||
|
class:btn-search-disabled={searchIsActive}
|
||||||
|
on:click={() => {
|
||||||
|
isSearchFocus = true;
|
||||||
|
searchIsActive = true;
|
||||||
|
dispatch('focusInputSearch');
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
on:keydown={({ key }) => {
|
||||||
|
if (key === 'Enter') {
|
||||||
|
searchIsActive = !searchIsActive;
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<Icon {...searchIcon} />
|
||||||
|
</button>
|
||||||
|
<input
|
||||||
|
bind:this={elInput}
|
||||||
|
id="input-search-field"
|
||||||
|
type="text"
|
||||||
|
autocomplete="off"
|
||||||
|
tabindex={closeTabIndex}
|
||||||
|
class="input-search"
|
||||||
|
class:input-hidden={!searchIsActive}
|
||||||
|
placeholder="Search"
|
||||||
|
on:focus={() => dispatch('focusInputSearch')}
|
||||||
|
on:focusout={() => dispatch('focusOutInputSearch')}
|
||||||
|
on:input={dispatchInputs} />
|
||||||
|
<button
|
||||||
|
id="right-panel-close-search"
|
||||||
|
tabindex={closeTabIndex}
|
||||||
|
class={cx('--header__action')}
|
||||||
|
class:btn-clear={true}
|
||||||
|
class:btn-clear-hidden={!searchIsActive}
|
||||||
|
type="button"
|
||||||
|
aria-label="Clear search"
|
||||||
|
on:click={() => {
|
||||||
|
isSearchFocus = false;
|
||||||
|
searchIsActive = false;
|
||||||
|
searchStore.clear();
|
||||||
|
}}
|
||||||
|
on:keydown={({ key }) => {
|
||||||
|
if (key === 'Enter') {
|
||||||
|
searchIsActive = !searchIsActive;
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<Icon {...closeIcon} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,6 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
export let ariaLabel = undefined;
|
export let ariaLabel = undefined;
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
import { cx } from '../../../lib';
|
||||||
</script>
|
</script>
|
||||||
|
|
23
src/components/UIShell/GlobalHeader/HeaderNavItem.svelte
Normal file
23
src/components/UIShell/GlobalHeader/HeaderNavItem.svelte
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script>
|
||||||
|
export let href = undefined;
|
||||||
|
export let text = undefined;
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class={cx('--header__menu-item')}
|
||||||
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
on:click
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:keyup
|
||||||
|
on:keydown
|
||||||
|
on:focus
|
||||||
|
on:blur
|
||||||
|
{href}>
|
||||||
|
<span class={cx('--text-truncate--end')}>{text}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
|
@ -1,16 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
export let href = undefined;
|
|
||||||
export let text = undefined;
|
export let text = undefined;
|
||||||
export let subMenu = undefined;
|
|
||||||
export let iconDescription = 'Expand/Collapse';
|
export let iconDescription = 'Expand/Collapse';
|
||||||
export let expanded = false;
|
export let expanded = false;
|
||||||
|
|
||||||
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
|
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
|
||||||
import { cx } from '../../../lib';
|
import { cx } from '../../../lib';
|
||||||
|
|
||||||
let listItemSubMenu = undefined;
|
let listItemSubMenu = undefined;
|
||||||
|
|
||||||
window.addEventListener('mouseup', ({ target }) => {
|
const mouseUp = ({ target }) => {
|
||||||
if (listItemSubMenu) {
|
if (listItemSubMenu) {
|
||||||
if (listItemSubMenu.contains(target) || target === listItemSubMenu) {
|
if (listItemSubMenu.contains(target) || target === listItemSubMenu) {
|
||||||
expanded = !expanded;
|
expanded = !expanded;
|
||||||
|
@ -20,9 +17,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:mouseup={mouseUp} />
|
||||||
|
|
||||||
<li class={cx('--header__submenu')} title={iconDescription}>
|
<li class={cx('--header__submenu')} title={iconDescription}>
|
||||||
<a
|
<a
|
||||||
bind:this={listItemSubMenu}
|
bind:this={listItemSubMenu}
|
||||||
|
@ -49,25 +48,7 @@
|
||||||
{text}
|
{text}
|
||||||
<ChevronDown16 class={cx('--header__menu-arrow')} aria-label={iconDescription} />
|
<ChevronDown16 class={cx('--header__menu-arrow')} aria-label={iconDescription} />
|
||||||
</a>
|
</a>
|
||||||
<ul aria-label={href} class={cx('--header__menu')} role="menu">
|
<ul aria-label={text} class={cx('--header__menu')} role="menu">
|
||||||
{#each subMenu as item}
|
<slot />
|
||||||
<li role="none">
|
|
||||||
<a
|
|
||||||
href={item.href}
|
|
||||||
class={cx('--header__menu-item')}
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
on:click
|
|
||||||
on:mouseover
|
|
||||||
on:mouseenter
|
|
||||||
on:mouseleave
|
|
||||||
on:keyup
|
|
||||||
on:keydown
|
|
||||||
on:focus
|
|
||||||
on:blur>
|
|
||||||
<span class={cx('--text-truncate--end')}>{item.text}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<style>
|
||||||
|
.subject-divider {
|
||||||
|
color: #525252;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
border-bottom: 1px solid #525252;
|
||||||
|
margin: 32px 1rem 8px;
|
||||||
|
}
|
||||||
|
.subject-divider span {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1rem;
|
||||||
|
letter-spacing: 0.32px;
|
||||||
|
color: #c6c6c6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<li class="subject-divider">
|
||||||
|
<span>
|
||||||
|
<slot />
|
||||||
|
</span>
|
||||||
|
</li>
|
11
src/components/UIShell/GlobalHeader/HeaderPanelLink.svelte
Normal file
11
src/components/UIShell/GlobalHeader/HeaderPanelLink.svelte
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<script>
|
||||||
|
export let href;
|
||||||
|
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li class={cx('--switcher__item')}>
|
||||||
|
<a class={cx('--switcher__item-link')} {href}>
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
|
</li>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<script>
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class={cx('--switcher__item')}>
|
||||||
|
<slot />
|
||||||
|
</ul>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<script>
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={cx('--header__global')}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
|
@ -12,9 +12,7 @@
|
||||||
<nav
|
<nav
|
||||||
class={cx('--side-nav__navigation', '--side-nav', '--side-nav--ux', isOpen && '--side-nav--expanded')}
|
class={cx('--side-nav__navigation', '--side-nav', '--side-nav--ux', isOpen && '--side-nav--expanded')}
|
||||||
aria-label={ariaLabel}>
|
aria-label={ariaLabel}>
|
||||||
<ul class={cx('--side-nav__items')}>
|
|
||||||
<slot />
|
<slot />
|
||||||
</ul>
|
|
||||||
<footer class={cx('--side-nav__footer')}>
|
<footer class={cx('--side-nav__footer')}>
|
||||||
<button class={cx('--side-nav__toggle')} type="button" title="Open">
|
<button class={cx('--side-nav__toggle')} type="button" title="Open">
|
||||||
<div class={cx('--side-nav__icon')}>
|
<div class={cx('--side-nav__icon')}>
|
7
src/components/UIShell/SideNav/SideNavItems.svelte
Normal file
7
src/components/UIShell/SideNav/SideNavItems.svelte
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script>
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class={cx('--side-nav__items')}>
|
||||||
|
<slot />
|
||||||
|
</ul>
|
24
src/components/UIShell/SideNav/SideNavLink.svelte
Normal file
24
src/components/UIShell/SideNav/SideNavLink.svelte
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<script>
|
||||||
|
export let href = undefined;
|
||||||
|
export let text = undefined;
|
||||||
|
export let icon = undefined;
|
||||||
|
export let isSelected = false;
|
||||||
|
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
import Icon from '../../Icon/Icon.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li class={cx('--side-nav__item')}>
|
||||||
|
<a
|
||||||
|
{href}
|
||||||
|
class={cx('--side-nav__link', isSelected && '--side-nav__link--current')}
|
||||||
|
aria-current={isSelected ? 'page' : ''}
|
||||||
|
on:click>
|
||||||
|
<div class={cx('--side-nav__icon', '--side-nav__icon--small')}>
|
||||||
|
{#if icon}
|
||||||
|
<Icon {...icon} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<span class={cx('--side-nav__link-text')}>{text}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
43
src/components/UIShell/SideNav/SideNavMenu.svelte
Normal file
43
src/components/UIShell/SideNav/SideNavMenu.svelte
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<script>
|
||||||
|
export let text = undefined;
|
||||||
|
export let icon = undefined;
|
||||||
|
export let expanded = false;
|
||||||
|
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
import Icon from '../../Icon/Icon.svelte';
|
||||||
|
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
|
||||||
|
|
||||||
|
let iconProps = {
|
||||||
|
class: undefined,
|
||||||
|
skeleton: false,
|
||||||
|
render: ChevronDown16,
|
||||||
|
title: 'Open Menu',
|
||||||
|
tabindex: '0',
|
||||||
|
focusable: false,
|
||||||
|
style: undefined
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li class={cx('--side-nav__item', '--side-nav__item--icon')}>
|
||||||
|
<button
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded={expanded}
|
||||||
|
class={cx('--side-nav__submenu')}
|
||||||
|
type="button"
|
||||||
|
on:click={() => {
|
||||||
|
expanded = !expanded;
|
||||||
|
}}>
|
||||||
|
<div class={cx('--side-nav__icon')}>
|
||||||
|
{#if icon}
|
||||||
|
<Icon {...icon} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<span class={cx('--side-nav__submenu-title')}>{text}</span>
|
||||||
|
<div class={cx('--side-nav__icon', '--side-nav__icon--small', '--side-nav__submenu-chevron')}>
|
||||||
|
<Icon {...iconProps} />
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<ul class={cx('--side-nav__menu')} role="menu">
|
||||||
|
<slot />
|
||||||
|
</ul>
|
||||||
|
</li>
|
18
src/components/UIShell/SideNav/SideNavMenuItem.svelte
Normal file
18
src/components/UIShell/SideNav/SideNavMenuItem.svelte
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<script>
|
||||||
|
export let href = undefined;
|
||||||
|
export let text = undefined;
|
||||||
|
export let isSelected = undefined;
|
||||||
|
|
||||||
|
import { cx } from '../../../lib';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li class={cx('--side-nav__menu-item')} role="none">
|
||||||
|
<a
|
||||||
|
{href}
|
||||||
|
class={cx('--side-nav__link')}
|
||||||
|
role="menuitem"
|
||||||
|
aria-current={isSelected ? 'page' : ''}
|
||||||
|
on:click>
|
||||||
|
<span class={cx('--side-nav__link-text')}>{text}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
|
@ -2,222 +2,33 @@
|
||||||
export let story = undefined;
|
export let story = undefined;
|
||||||
|
|
||||||
import UIShell from './UIShell.svelte';
|
import UIShell from './UIShell.svelte';
|
||||||
import FormTest from './FormTest.svelte';
|
|
||||||
import SettingsAdjust20 from 'carbon-icons-svelte/lib/SettingsAdjust20';
|
import SettingsAdjust20 from 'carbon-icons-svelte/lib/SettingsAdjust20';
|
||||||
|
import Help20 from 'carbon-icons-svelte/lib/Help20';
|
||||||
import ChangeCatalog16 from 'carbon-icons-svelte/lib/ChangeCatalog16';
|
import ChangeCatalog16 from 'carbon-icons-svelte/lib/ChangeCatalog16';
|
||||||
import ManageProtection16 from 'carbon-icons-svelte/lib/ManageProtection16';
|
import ManageProtection16 from 'carbon-icons-svelte/lib/ManageProtection16';
|
||||||
import Recommend16 from 'carbon-icons-svelte/lib/Recommend16';
|
import Notification20 from 'carbon-icons-svelte/lib/Notification20';
|
||||||
import Settings16 from 'carbon-icons-svelte/lib/Settings16';
|
import UserAvatar20 from 'carbon-icons-svelte/lib/UserAvatar20';
|
||||||
import { leftPanelActions, leftPanelTypes } from './constants';
|
import AppSwitcher20 from 'carbon-icons-svelte/lib/AppSwitcher20';
|
||||||
import searchStore from './searchStore';
|
|
||||||
import isNavItemSelectedStore from './UIShellSideNav/isNavItemSelectedStore';
|
|
||||||
|
|
||||||
const navMenu = [
|
import SideNav from './SideNav/SideNav.svelte';
|
||||||
{
|
import SideNavItems from './SideNav/SideNavItems.svelte';
|
||||||
href: '#',
|
import SideNavMenu from './SideNav/SideNavMenu.svelte';
|
||||||
text: 'Link 1',
|
import SideNavMenuItem from './SideNav/SideNavMenuItem.svelte';
|
||||||
subMenu: undefined
|
import SideNavLink from './SideNav/SideNavLink.svelte';
|
||||||
},
|
import HeaderNav from './GlobalHeader/HeaderNav.svelte';
|
||||||
{
|
import HeaderNavItem from './GlobalHeader/HeaderNavItem.svelte';
|
||||||
href: '#',
|
import HeaderNavMenu from './GlobalHeader/HeaderNavMenu.svelte';
|
||||||
text: 'Link 2',
|
import HeaderUtilities from './GlobalHeader/HeaderUtilities.svelte';
|
||||||
subMenu: undefined
|
import HeaderActionSearch from './GlobalHeader/HeaderActionSearch.svelte';
|
||||||
},
|
import HeaderActionLink from './GlobalHeader/HeaderActionLink.svelte';
|
||||||
{
|
import HeaderAction from './GlobalHeader/HeaderAction.svelte';
|
||||||
href: '#',
|
import HeaderPanelDivider from './GlobalHeader/HeaderPanelDivider.svelte';
|
||||||
text: 'Link 3',
|
import HeaderPanelLink from './GlobalHeader/HeaderPanelLink.svelte';
|
||||||
subMenu: undefined
|
import HeaderPanelLinks from './GlobalHeader/HeaderPanelLinks.svelte';
|
||||||
},
|
|
||||||
{
|
|
||||||
href: undefined,
|
|
||||||
text: 'Link 4',
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Sub-link 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Sub-link 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Sub-link 3'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
/*
|
let isSideNavOpen = undefined;
|
||||||
Format:
|
|
||||||
|
|
||||||
action: will be place on the aria-label, use to identify the action from the others. Predifined actions: 'search', 'help', 'notification', 'account', 'switcher'
|
let iCatalog = {
|
||||||
|
|
||||||
type: search-> will open an inputText to start a search.
|
|
||||||
|
|
||||||
component-> when specifying this property, content will expect a .svelte file.
|
|
||||||
|
|
||||||
link-> when specifying this property, content will expect for just 1 href and text
|
|
||||||
|
|
||||||
links-> when specifying this property, content will expect for an array of objects with property subject and another array of objects with href and text
|
|
||||||
|
|
||||||
icon: you need to specify the properties specified in carbon-icons-svelte components as shown in the example below.
|
|
||||||
|
|
||||||
content: what will be shown on the component, could vary the information depending on the type property.
|
|
||||||
|
|
||||||
*** actions 'search' and 'switcher' doesnt need to specify type and icon because those are predefined actions in the component.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const rightPanel = [
|
|
||||||
{
|
|
||||||
action: leftPanelActions.search.actionString,
|
|
||||||
type: leftPanelTypes.search,
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: 'customsettings',
|
|
||||||
type: leftPanelTypes.component,
|
|
||||||
icon: [
|
|
||||||
{
|
|
||||||
class: undefined,
|
|
||||||
skeleton: false,
|
|
||||||
render: SettingsAdjust20,
|
|
||||||
title: 'Settings',
|
|
||||||
tabindex: '0',
|
|
||||||
focusable: false,
|
|
||||||
style: undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
content: FormTest,
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: leftPanelActions.help.actionString,
|
|
||||||
type: leftPanelTypes.link,
|
|
||||||
content: {
|
|
||||||
href: '#',
|
|
||||||
text: leftPanelActions.help.actionString
|
|
||||||
},
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: leftPanelActions.notifications.actionString,
|
|
||||||
type: leftPanelTypes.links,
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
subject: 'Notification subject 1',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Notification item 1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
subject: 'Notification subject 2',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Notification item 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Notification item 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Notification item 3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Notification item 4'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: leftPanelActions.switcher.actionString,
|
|
||||||
type: leftPanelTypes.links,
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
subject: 'Switcher subject 1',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
subject: 'Switcher subject 2',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 4'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
subject: 'Switcher subject 3',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Switcher item 2'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: leftPanelActions.account.actionString,
|
|
||||||
type: leftPanelTypes.link,
|
|
||||||
content: {
|
|
||||||
href: '#',
|
|
||||||
text: leftPanelActions.account.actionString
|
|
||||||
},
|
|
||||||
isVisible: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const sideNavMenu = [
|
|
||||||
{
|
|
||||||
href: undefined,
|
|
||||||
text: 'Category 1',
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Cat 1 Sub-link 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Cat 1 Sub-link 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Cat 1 Sub-link 3'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
icon: [
|
|
||||||
{
|
|
||||||
class: undefined,
|
class: undefined,
|
||||||
skeleton: false,
|
skeleton: false,
|
||||||
render: ChangeCatalog16,
|
render: ChangeCatalog16,
|
||||||
|
@ -225,89 +36,138 @@
|
||||||
tabindex: '0',
|
tabindex: '0',
|
||||||
focusable: false,
|
focusable: false,
|
||||||
style: undefined
|
style: undefined
|
||||||
}
|
};
|
||||||
]
|
|
||||||
},
|
let iHelp = {
|
||||||
{
|
class: undefined,
|
||||||
href: '#',
|
skeleton: false,
|
||||||
text: 'Link 2',
|
render: Help20,
|
||||||
subMenu: undefined,
|
title: 'Help',
|
||||||
icon: [
|
tabindex: '0',
|
||||||
{
|
focusable: false,
|
||||||
|
style: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
let iAdjust = {
|
||||||
|
class: undefined,
|
||||||
|
skeleton: false,
|
||||||
|
render: SettingsAdjust20,
|
||||||
|
title: 'Catalog',
|
||||||
|
tabindex: '0',
|
||||||
|
focusable: false,
|
||||||
|
style: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
let iProtection = {
|
||||||
class: undefined,
|
class: undefined,
|
||||||
skeleton: false,
|
skeleton: false,
|
||||||
render: ManageProtection16,
|
render: ManageProtection16,
|
||||||
title: 'Protection',
|
title: 'Catalog',
|
||||||
tabindex: '0',
|
tabindex: '0',
|
||||||
focusable: false,
|
focusable: false,
|
||||||
style: undefined
|
style: undefined
|
||||||
}
|
};
|
||||||
]
|
|
||||||
},
|
let iSwitcher = {
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Link 3',
|
|
||||||
subMenu: undefined,
|
|
||||||
icon: [
|
|
||||||
{
|
|
||||||
class: undefined,
|
class: undefined,
|
||||||
skeleton: false,
|
skeleton: false,
|
||||||
render: Recommend16,
|
render: AppSwitcher20,
|
||||||
title: 'Recommend',
|
title: 'App Switcher',
|
||||||
tabindex: '0',
|
tabindex: '0',
|
||||||
focusable: false,
|
focusable: false,
|
||||||
style: undefined
|
style: undefined
|
||||||
}
|
};
|
||||||
]
|
|
||||||
},
|
let iAccount = {
|
||||||
{
|
|
||||||
href: undefined,
|
|
||||||
text: 'Category 2',
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Cat 2 Sub-link 1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Cat 2 Sub-link 2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#',
|
|
||||||
text: 'Cat 2 Sub-link 3'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
icon: [
|
|
||||||
{
|
|
||||||
class: undefined,
|
class: undefined,
|
||||||
skeleton: false,
|
skeleton: false,
|
||||||
render: Settings16,
|
render: UserAvatar20,
|
||||||
|
title: 'Account',
|
||||||
|
tabindex: '0',
|
||||||
|
focusable: false,
|
||||||
|
style: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
let iNotifications = {
|
||||||
|
class: undefined,
|
||||||
|
skeleton: false,
|
||||||
|
render: Notification20,
|
||||||
|
title: 'Notifications',
|
||||||
|
tabindex: '0',
|
||||||
|
focusable: false,
|
||||||
|
style: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
let iSettings = {
|
||||||
|
class: undefined,
|
||||||
|
skeleton: false,
|
||||||
|
render: SettingsAdjust20,
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
tabindex: '0',
|
tabindex: '0',
|
||||||
focusable: false,
|
focusable: false,
|
||||||
style: undefined
|
style: undefined
|
||||||
}
|
};
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
isNavItemSelectedStore.setStoreValues(sideNavMenu);
|
|
||||||
|
|
||||||
function searchInStore(event) {
|
|
||||||
if (event.detail.action === leftPanelActions.search.actionString) {
|
|
||||||
searchStore.search(event.detail.textInput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if story === 'with-nav'}
|
{#if story === 'with-nav'}
|
||||||
<UIShell {...$$props} {navMenu} />
|
<UIShell {...$$props}>
|
||||||
|
<HeaderNav>
|
||||||
|
<HeaderNavItem href="/" text="Link 1" />
|
||||||
|
<HeaderNavItem href="/" text="Link 2" />
|
||||||
|
<HeaderNavItem href="/" text="Link 3" />
|
||||||
|
<HeaderNavMenu text="Sub Menu">
|
||||||
|
<HeaderNavItem href="/" text="Link 1" />
|
||||||
|
<HeaderNavItem href="/" text="Link 2" />
|
||||||
|
<HeaderNavItem href="/" text="Link 3" />
|
||||||
|
</HeaderNavMenu>
|
||||||
|
</HeaderNav>
|
||||||
|
</UIShell>
|
||||||
{:else if story === 'with-actions'}
|
{:else if story === 'with-actions'}
|
||||||
<UIShell {...$$props} {rightPanel} on:inputSearch={searchInStore} />
|
<UIShell {...$$props}>
|
||||||
{:else if story === 'with-actions-nav'}
|
<HeaderUtilities>
|
||||||
<UIShell {...$$props} {navMenu} {rightPanel} on:inputSearch={searchInStore} />
|
<HeaderActionSearch />
|
||||||
{:else if story === 'with-actions-sidenav'}
|
<HeaderAction type="Settings" icon={iSettings}>
|
||||||
<UIShell {...$$props} {sideNavMenu} {rightPanel} on:inputSearch={searchInStore} />
|
<p>Settings</p>
|
||||||
|
</HeaderAction>
|
||||||
|
<HeaderActionLink type="Help" icon={iHelp} />
|
||||||
|
<HeaderAction type="Notifications" icon={iNotifications}>
|
||||||
|
<p>Notifications</p>
|
||||||
|
</HeaderAction>
|
||||||
|
<HeaderActionLink type="Account" icon={iAccount} />
|
||||||
|
<HeaderAction type="Switcher" icon={iSwitcher}>
|
||||||
|
<HeaderPanelLinks>
|
||||||
|
<HeaderPanelDivider>Switcher subject 1</HeaderPanelDivider>
|
||||||
|
<HeaderPanelLink>Switecher item 1</HeaderPanelLink>
|
||||||
|
<HeaderPanelDivider>Switcher subject 2</HeaderPanelDivider>
|
||||||
|
<HeaderPanelLink>Switecher item 1</HeaderPanelLink>
|
||||||
|
<HeaderPanelLink>Switecher item 2</HeaderPanelLink>
|
||||||
|
<HeaderPanelLink>Switecher item 3</HeaderPanelLink>
|
||||||
|
<HeaderPanelLink>Switecher item 4</HeaderPanelLink>
|
||||||
|
<HeaderPanelLink>Switecher item 5</HeaderPanelLink>
|
||||||
|
</HeaderPanelLinks>
|
||||||
|
</HeaderAction>
|
||||||
|
</HeaderUtilities>
|
||||||
|
</UIShell>
|
||||||
|
{:else if story === 'with-sidenav'}
|
||||||
|
<UIShell bind:isSideNavOpen {...$$props}>
|
||||||
|
<SideNav isOpen={isSideNavOpen}>
|
||||||
|
<SideNavItems>
|
||||||
|
<SideNavMenu text="Menu 01" icon={iCatalog}>
|
||||||
|
<SideNavMenuItem text="Sub 01" href="/" />
|
||||||
|
<SideNavMenuItem text="Sub 02" href="/" />
|
||||||
|
<SideNavMenuItem text="Sub 03" href="/" />
|
||||||
|
<SideNavMenuItem text="Sub 04" href="/" />
|
||||||
|
</SideNavMenu>
|
||||||
|
<SideNavMenu text="Menu 02" icon={iAdjust}>
|
||||||
|
<SideNavMenuItem text="Sub 01" href="/" />
|
||||||
|
<SideNavMenuItem text="Sub 02" href="/" />
|
||||||
|
<SideNavMenuItem text="Sub 03" href="/" />
|
||||||
|
<SideNavMenuItem text="Sub 04" href="/" />
|
||||||
|
</SideNavMenu>
|
||||||
|
<SideNavLink text="Menu 03" href="/" icon={iProtection} />
|
||||||
|
</SideNavItems>
|
||||||
|
</SideNav>
|
||||||
|
</UIShell>
|
||||||
{:else}
|
{:else}
|
||||||
<UIShell {...$$props} />
|
<UIShell {...$$props} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,16 +3,6 @@ import Component from './UIShell.Story.svelte';
|
||||||
|
|
||||||
export default { title: 'UIShell', decorators: [withKnobs] };
|
export default { title: 'UIShell', decorators: [withKnobs] };
|
||||||
|
|
||||||
export const Default = () => ({
|
|
||||||
Component,
|
|
||||||
props: {
|
|
||||||
story: 'default',
|
|
||||||
href: text('The link href (href)', '#'),
|
|
||||||
company: text('Company name', 'IBM'),
|
|
||||||
platformName: text('Platform name', 'Platform Name')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const WithNav = () => ({
|
export const WithNav = () => ({
|
||||||
Component,
|
Component,
|
||||||
props: {
|
props: {
|
||||||
|
@ -33,20 +23,10 @@ export const WithActions = () => ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WithActionsAndNav = () => ({
|
|
||||||
Component,
|
|
||||||
props: {
|
|
||||||
story: 'with-actions-nav',
|
|
||||||
href: text('The link href (href)', '#'),
|
|
||||||
company: text('Company name', 'IBM'),
|
|
||||||
platformName: text('Platform name', 'Platform Name')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const WithActionsAndSidenav = () => ({
|
export const WithActionsAndSidenav = () => ({
|
||||||
Component,
|
Component,
|
||||||
props: {
|
props: {
|
||||||
story: 'with-actions-sidenav',
|
story: 'with-sidenav',
|
||||||
href: text('The link href (href)', '#'),
|
href: text('The link href (href)', '#'),
|
||||||
company: text('Company name', 'IBM'),
|
company: text('Company name', 'IBM'),
|
||||||
platformName: text('Platform name', 'Platform Name')
|
platformName: text('Platform name', 'Platform Name')
|
||||||
|
|
|
@ -3,21 +3,13 @@
|
||||||
export let href = undefined;
|
export let href = undefined;
|
||||||
export let company = undefined;
|
export let company = undefined;
|
||||||
export let platformName = undefined;
|
export let platformName = undefined;
|
||||||
export let navMenu = undefined;
|
export let isSideNavOpen = undefined;
|
||||||
export let rightPanel = undefined;
|
|
||||||
export let sideNavMenu = undefined;
|
|
||||||
|
|
||||||
import { cx } from '../../lib';
|
import { cx } from '../../lib';
|
||||||
import UIShellNavWrapper from './UIShellNav/UIShellNavWrapper.svelte';
|
import HamburgerMenu from './SideNav/HamburgerMenu.svelte';
|
||||||
import UIShellNavItem from './UIShellNav/UIShellNavItem.svelte';
|
|
||||||
import UIShellRightPanel from './UIShellRightPanel/UIShellRightPanel.svelte';
|
|
||||||
import UIShellSideNavWrapper from './UIShellSideNav/UIShellSideNavWrapper.svelte';
|
|
||||||
import UIShellSideNavItem from './UIShellSideNav/UIShellSideNavItem.svelte';
|
|
||||||
import HamburgerMenu from './UIShellSideNav/HamburgerMenu.svelte';
|
|
||||||
|
|
||||||
let isSideNavOpen = undefined;
|
|
||||||
let winWidth = undefined;
|
let winWidth = undefined;
|
||||||
$: isSideNavOpen = winWidth >= 1056
|
$: isSideNavOpen = winWidth >= 1056;
|
||||||
|
|
||||||
$: ariaLabel = company + (uiShellAriaLabel || $$props['aria-label'] || platformName);
|
$: ariaLabel = company + (uiShellAriaLabel || $$props['aria-label'] || platformName);
|
||||||
</script>
|
</script>
|
||||||
|
@ -32,21 +24,5 @@
|
||||||
<span class={cx('--header__name--prefix')}>{company}</span>
|
<span class={cx('--header__name--prefix')}>{company}</span>
|
||||||
{platformName}
|
{platformName}
|
||||||
</a>
|
</a>
|
||||||
{#if navMenu}
|
<slot />
|
||||||
<UIShellNavWrapper ariaLabel>
|
|
||||||
{#each navMenu as itemMenu}
|
|
||||||
<UIShellNavItem {...itemMenu} />
|
|
||||||
{/each}
|
|
||||||
</UIShellNavWrapper>
|
|
||||||
{/if}
|
|
||||||
{#if rightPanel}
|
|
||||||
<UIShellRightPanel {rightPanel} on:inputSearch />
|
|
||||||
{/if}
|
|
||||||
{#if sideNavMenu}
|
|
||||||
<UIShellSideNavWrapper bind:isOpen={isSideNavOpen} bind:winWidth>
|
|
||||||
{#each sideNavMenu as itemSideMenu}
|
|
||||||
<UIShellSideNavItem {...itemSideMenu} />
|
|
||||||
{/each}
|
|
||||||
</UIShellSideNavWrapper>
|
|
||||||
{/if}
|
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
<script>
|
|
||||||
export let href = undefined;
|
|
||||||
export let text = undefined;
|
|
||||||
export let subMenu = undefined;
|
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
|
||||||
import UIShellSubmenu from './UIShellNavSubmenu.svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if href}
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
class={cx('--header__menu-item')}
|
|
||||||
role="menuitem"
|
|
||||||
tabindex="0"
|
|
||||||
on:click
|
|
||||||
on:mouseover
|
|
||||||
on:mouseenter
|
|
||||||
on:mouseleave
|
|
||||||
on:keyup
|
|
||||||
on:keydown
|
|
||||||
on:focus
|
|
||||||
on:blur
|
|
||||||
{href}>
|
|
||||||
<span class={cx('--text-truncate--end')}>{text}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{:else}
|
|
||||||
<UIShellSubmenu
|
|
||||||
{href}
|
|
||||||
{text}
|
|
||||||
{subMenu}
|
|
||||||
on:click
|
|
||||||
on:mouseover
|
|
||||||
on:mouseenter
|
|
||||||
on:mouseleave
|
|
||||||
on:keyup
|
|
||||||
on:keydown
|
|
||||||
on:focus
|
|
||||||
on:blur />
|
|
||||||
{/if}
|
|
|
@ -1,138 +0,0 @@
|
||||||
<script>
|
|
||||||
export let action = undefined;
|
|
||||||
|
|
||||||
import ActionLink from './ActionLink.svelte';
|
|
||||||
import ActionComponent from './ActionComponent.svelte';
|
|
||||||
import ActionSearch from './ActionSearch.svelte';
|
|
||||||
import { leftPanelTypes } from '../constants';
|
|
||||||
import { isChildOf } from '../helpers';
|
|
||||||
|
|
||||||
let typeComponent = undefined;
|
|
||||||
let componentIsActive = false;
|
|
||||||
let typeSearch = undefined;
|
|
||||||
let searchIsActive = false;
|
|
||||||
let typeLink = undefined;
|
|
||||||
let linkIsActive = false;
|
|
||||||
|
|
||||||
let isSearchFocus = false;
|
|
||||||
|
|
||||||
window.addEventListener('mouseup', ({ target }) => {
|
|
||||||
checkForClicksTypeComponent(target, typeComponent);
|
|
||||||
checkForClicksTypeSearch(target, typeSearch);
|
|
||||||
checkForClicksTypeLink(target, typeLink);
|
|
||||||
});
|
|
||||||
|
|
||||||
function checkForClicksTypeComponent(target, component) {
|
|
||||||
if (component && target) {
|
|
||||||
if (
|
|
||||||
!isChildOf(target, 'right-panel-action-component') ||
|
|
||||||
!isChildOf(target, 'right-panel-action-component-form')
|
|
||||||
) {
|
|
||||||
if (component.contains(target) || target === component) {
|
|
||||||
componentIsActive = !componentIsActive;
|
|
||||||
} else {
|
|
||||||
if (componentIsActive) {
|
|
||||||
componentIsActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkForClicksTypeSearch(target, component) {
|
|
||||||
if (component && target) {
|
|
||||||
if (!isChildOf(target, 'right-panel-action-search')) {
|
|
||||||
if (component.contains(target) || target === component) {
|
|
||||||
searchIsActive = !searchIsActive;
|
|
||||||
} else {
|
|
||||||
if (searchIsActive) {
|
|
||||||
searchIsActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!searchIsActive && target.id !== 'right-panel-close-search') {
|
|
||||||
searchIsActive = true;
|
|
||||||
} else if (searchIsActive && isChildOf(target, 'right-panel-close-search')) {
|
|
||||||
searchIsActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkForClicksTypeLink(target, component) {
|
|
||||||
if (component && target) {
|
|
||||||
if (component.contains(target) || target === component) {
|
|
||||||
linkIsActive = !linkIsActive;
|
|
||||||
} else {
|
|
||||||
if (linkIsActive) {
|
|
||||||
linkIsActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.search-wrapper {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
max-width: 28rem;
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
height: 3rem;
|
|
||||||
background-color: #393939;
|
|
||||||
color: #fff;
|
|
||||||
transition: max-width 0.11s cubic-bezier(0.2, 0, 0.38, 0.9),
|
|
||||||
background 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-wrapper-hidden {
|
|
||||||
max-width: 3rem;
|
|
||||||
background-color: #161616;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-focus {
|
|
||||||
outline: 2px solid #fff;
|
|
||||||
outline-offset: -2px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{#if action.isVisible}
|
|
||||||
{#if action.type === leftPanelTypes.component}
|
|
||||||
<div bind:this={typeComponent}>
|
|
||||||
<ActionComponent
|
|
||||||
icon={action.icon ? action.icon : undefined}
|
|
||||||
content={action.content}
|
|
||||||
bind:componentIsActive />
|
|
||||||
</div>
|
|
||||||
{:else if action.type === leftPanelTypes.search}
|
|
||||||
<div
|
|
||||||
bind:this={typeSearch}
|
|
||||||
class="search-wrapper"
|
|
||||||
class:search-wrapper-hidden={!searchIsActive}
|
|
||||||
class:search-focus={isSearchFocus || searchIsActive}
|
|
||||||
role="search">
|
|
||||||
<ActionSearch
|
|
||||||
action={action.action}
|
|
||||||
icon={action.icon ? action.icon : undefined}
|
|
||||||
content={action.content}
|
|
||||||
bind:searchIsActive
|
|
||||||
focusInputSearch={() => {
|
|
||||||
isSearchFocus = true;
|
|
||||||
}}
|
|
||||||
focusOutInputSearch={() => {
|
|
||||||
isSearchFocus = false;
|
|
||||||
}}
|
|
||||||
on:inputSearch />
|
|
||||||
</div>
|
|
||||||
{:else if action.type === leftPanelTypes.link || action.type === leftPanelTypes.links}
|
|
||||||
<div bind:this={typeLink}>
|
|
||||||
<ActionLink
|
|
||||||
action={action.action}
|
|
||||||
type={action.type}
|
|
||||||
icon={action.icon ? action.icon : undefined}
|
|
||||||
content={action.content}
|
|
||||||
bind:linkIsActive />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
|
@ -1,99 +0,0 @@
|
||||||
<script>
|
|
||||||
export let action = undefined;
|
|
||||||
export let type = undefined;
|
|
||||||
export let icon = undefined;
|
|
||||||
export let content = undefined;
|
|
||||||
export let linkIsActive = undefined;
|
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
|
||||||
import Icon from '../../Icon/Icon.svelte';
|
|
||||||
import { leftPanelActions, leftPanelTypes } from '../constants';
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
|
|
||||||
let href = undefined;
|
|
||||||
|
|
||||||
if (type === leftPanelTypes.link) {
|
|
||||||
href = content.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!icon) {
|
|
||||||
const actionsArray = Object.entries(leftPanelActions);
|
|
||||||
|
|
||||||
for (const definedAction of actionsArray) {
|
|
||||||
for (const content of definedAction) {
|
|
||||||
if (typeof content === 'object') {
|
|
||||||
if (content.actionString === action) {
|
|
||||||
icon = content.iconProps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.action-link {
|
|
||||||
text-align: center;
|
|
||||||
align-items: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
justify-content: center;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subject-divider {
|
|
||||||
color: #525252;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
border-bottom: 1px solid #525252;
|
|
||||||
margin: 32px 1rem 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subject-divider span {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1rem;
|
|
||||||
letter-spacing: 0.32px;
|
|
||||||
color: #c6c6c6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{#if type === leftPanelTypes.link}
|
|
||||||
<a
|
|
||||||
aria-label={type}
|
|
||||||
class={cx('--header__action', linkIsActive && '--header__action--active')}
|
|
||||||
class:action-link={true}
|
|
||||||
{href}>
|
|
||||||
<Icon {...icon} />
|
|
||||||
</a>
|
|
||||||
{:else}
|
|
||||||
<button
|
|
||||||
aria-label={type}
|
|
||||||
class={cx('--header__action', linkIsActive && '--header__action--active')}
|
|
||||||
type="button"
|
|
||||||
on:keydown={({ key }) => {
|
|
||||||
if (key === 'Enter') {
|
|
||||||
linkIsActive = !linkIsActive;
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Icon {...icon} />
|
|
||||||
</button>
|
|
||||||
{#if linkIsActive && type === leftPanelTypes.links}
|
|
||||||
<div
|
|
||||||
class={cx('--header-panel', '--header-panel--expanded')}
|
|
||||||
transition:slide={{ duration: 200 }}>
|
|
||||||
<ul class={cx('--switcher__item')}>
|
|
||||||
{#each content as subject}
|
|
||||||
{#if subject.subject}
|
|
||||||
<li class="subject-divider">
|
|
||||||
<span>{subject.subject}</span>
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
||||||
{#each subject.items as link}
|
|
||||||
<li class={cx('--switcher__item')}>
|
|
||||||
<a class={cx('--switcher__item-link')} href={link.href}>{link.text}</a>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
|
@ -1,191 +0,0 @@
|
||||||
<script>
|
|
||||||
export let action = undefined;
|
|
||||||
export let icon = undefined;
|
|
||||||
export let searchIsActive = undefined;
|
|
||||||
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { cx } from '../../../lib';
|
|
||||||
import Icon from '../../Icon/Icon.svelte';
|
|
||||||
import { leftPanelActions, closeIcon } from '../constants';
|
|
||||||
import searchStore from '../searchStore';
|
|
||||||
import ActionSearchResult from './ActionSearchResult.svelte';
|
|
||||||
|
|
||||||
let searchTabIndex = '0';
|
|
||||||
let closeTabIndex = '-1';
|
|
||||||
let inputSearchField = undefined;
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
if (!icon) {
|
|
||||||
const actionsArray = Object.entries(leftPanelActions);
|
|
||||||
|
|
||||||
for (const definedAction of actionsArray) {
|
|
||||||
for (const content of definedAction) {
|
|
||||||
if (typeof content === 'object') {
|
|
||||||
if (content.actionString === action) {
|
|
||||||
icon = content.iconProps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dispatchInputs(event) {
|
|
||||||
const params = {
|
|
||||||
action: action,
|
|
||||||
textInput: event.target.value
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch('inputSearch', params);
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (!searchIsActive) {
|
|
||||||
if (inputSearchField) {
|
|
||||||
inputSearchField.value = '';
|
|
||||||
}
|
|
||||||
searchStore.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (searchIsActive) {
|
|
||||||
searchTabIndex = '-1';
|
|
||||||
closeTabIndex = '0';
|
|
||||||
} else {
|
|
||||||
searchTabIndex = '0';
|
|
||||||
closeTabIndex = '-1';
|
|
||||||
}
|
|
||||||
|
|
||||||
$: showResults = $searchStore ? true : false;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.search-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
border-bottom: 1px solid #393939;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-search {
|
|
||||||
width: 3rem;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
opacity: 1;
|
|
||||||
transition: background-color 0.11s cubic-bezier(0.2, 0, 0.38, 0.9),
|
|
||||||
opacity 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-search-disabled {
|
|
||||||
border: none;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-search {
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.375rem;
|
|
||||||
letter-spacing: 0;
|
|
||||||
color: #fff;
|
|
||||||
caret-color: #fff;
|
|
||||||
background-color: initial;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
width: 100%;
|
|
||||||
height: 3rem;
|
|
||||||
padding: 0;
|
|
||||||
transition: opacity 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-hidden {
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-clear {
|
|
||||||
width: 3rem;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
opacity: 1;
|
|
||||||
display: block;
|
|
||||||
transition: background-color 0.11s cubic-bezier(0.2, 0, 0.38, 0.9),
|
|
||||||
opacity 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-clear:hover {
|
|
||||||
background-color: #4c4c4c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-clear-hidden {
|
|
||||||
opacity: 0;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-list {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10000;
|
|
||||||
padding: 1rem 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 3rem;
|
|
||||||
background-color: #161616;
|
|
||||||
border: 1px solid #393939;
|
|
||||||
border-top: none;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div
|
|
||||||
id="right-panel-action-search"
|
|
||||||
class="search-wrapper"
|
|
||||||
role="combobox"
|
|
||||||
aria-expanded={searchIsActive}>
|
|
||||||
<button
|
|
||||||
tabindex={searchTabIndex}
|
|
||||||
aria-label={action}
|
|
||||||
class={cx('--header__action')}
|
|
||||||
class:btn-search={true}
|
|
||||||
class:btn-search-disabled={searchIsActive}
|
|
||||||
on:click={() => dispatch('focusInputSearch')}
|
|
||||||
type="button"
|
|
||||||
on:keydown={({ key }) => {
|
|
||||||
if (key === 'Enter') {
|
|
||||||
searchIsActive = !searchIsActive;
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Icon {...icon} />
|
|
||||||
</button>
|
|
||||||
<input
|
|
||||||
bind:this={inputSearchField}
|
|
||||||
id="input-search-field"
|
|
||||||
type="text"
|
|
||||||
autocomplete="off"
|
|
||||||
tabindex={closeTabIndex}
|
|
||||||
class="input-search"
|
|
||||||
class:input-hidden={!searchIsActive}
|
|
||||||
placeholder="Search"
|
|
||||||
on:focus={() => dispatch('focusInputSearch')}
|
|
||||||
on:focusout={() => dispatch('focusOutInputSearch')}
|
|
||||||
on:input={dispatchInputs} />
|
|
||||||
<button
|
|
||||||
id="right-panel-close-search"
|
|
||||||
tabindex={closeTabIndex}
|
|
||||||
class={cx('--header__action')}
|
|
||||||
class:btn-clear={true}
|
|
||||||
class:btn-clear-hidden={!searchIsActive}
|
|
||||||
type="button"
|
|
||||||
aria-label="Clear search"
|
|
||||||
on:click={() => searchStore.clear()}
|
|
||||||
on:keydown={({ key }) => {
|
|
||||||
if (key === 'Enter') {
|
|
||||||
searchIsActive = !searchIsActive;
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Icon {...closeIcon} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{#if showResults}
|
|
||||||
<ul aria-labelledby="search-label" role="menu" id="search-menu" class="search-list">
|
|
||||||
{#each $searchStore as searchItem, index}
|
|
||||||
<ActionSearchResult {searchItem} {index} />
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
{/if}
|
|
|
@ -1,72 +0,0 @@
|
||||||
<script>
|
|
||||||
export let searchItem = undefined;
|
|
||||||
export let index = undefined;
|
|
||||||
|
|
||||||
let onHover = false;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.search-list-item {
|
|
||||||
padding: 6px 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.125rem;
|
|
||||||
letter-spacing: 0.16px;
|
|
||||||
transition: all 70ms cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
color: #c6c6c6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-list-item-menu {
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-list-item-description {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1rem;
|
|
||||||
letter-spacing: 0.32px;
|
|
||||||
text-transform: lowercase;
|
|
||||||
color: #c6c6c6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-list-item-active {
|
|
||||||
background-color: #353535;
|
|
||||||
color: #f4f4f4;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{#if index === 0}
|
|
||||||
<li role="none">
|
|
||||||
<a
|
|
||||||
tabindex="-1"
|
|
||||||
id={`menu-item-${index}`}
|
|
||||||
role="menuitem"
|
|
||||||
class="search-list-item search-list-item-active"
|
|
||||||
href={searchItem.href}>
|
|
||||||
{searchItem.title}
|
|
||||||
<span class="search-list-item-menu">→ {searchItem.menu}</span>
|
|
||||||
<span class="search-list-item-description">{searchItem.description}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{:else}
|
|
||||||
<li role="none" on:mouseover={() => (onHover = true)} on:mouseleave={() => (onHover = false)}>
|
|
||||||
<a
|
|
||||||
tabindex="-1"
|
|
||||||
id={`menu-item-${index}`}
|
|
||||||
role="menuitem"
|
|
||||||
class="search-list-item"
|
|
||||||
class:search-list-item-active={onHover}
|
|
||||||
href={searchItem.href}>
|
|
||||||
{searchItem.title}
|
|
||||||
<span class="search-list-item-menu">→ {searchItem.menu}</span>
|
|
||||||
<span class="search-list-item-description">{searchItem.description}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
|
@ -1,50 +0,0 @@
|
||||||
<script>
|
|
||||||
export let rightPanel = undefined;
|
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
|
||||||
import ActionGeneric from './ActionGeneric.svelte';
|
|
||||||
import { leftPanelActions } from '../constants';
|
|
||||||
|
|
||||||
let orderedRightPanel = [];
|
|
||||||
let customActions = 1;
|
|
||||||
|
|
||||||
rightPanel.forEach((item, index) => {
|
|
||||||
orderedRightPanel[index] = undefined;
|
|
||||||
if (item.action) {
|
|
||||||
if (
|
|
||||||
Object.keys(leftPanelActions).indexOf(
|
|
||||||
item.action.charAt(0).toLowerCase() + item.action.slice(1)
|
|
||||||
) === -1
|
|
||||||
) {
|
|
||||||
orderedRightPanel[customActions] = rightPanel[index];
|
|
||||||
customActions += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rightPanel.forEach((item, index) => {
|
|
||||||
if (item.action) {
|
|
||||||
if (item.action === leftPanelActions.search.actionString) {
|
|
||||||
orderedRightPanel[0] = rightPanel[index];
|
|
||||||
} else if (item.action === leftPanelActions.help.actionString) {
|
|
||||||
orderedRightPanel[customActions] = rightPanel[index];
|
|
||||||
} else if (item.action === leftPanelActions.notifications.actionString) {
|
|
||||||
orderedRightPanel[customActions + 1] = rightPanel[index];
|
|
||||||
} else if (item.action === leftPanelActions.account.actionString) {
|
|
||||||
orderedRightPanel[customActions + 2] = rightPanel[index];
|
|
||||||
} else if (item.action === leftPanelActions.switcher.actionString) {
|
|
||||||
orderedRightPanel[customActions + 3] = rightPanel[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
orderedRightPanel = orderedRightPanel.filter(item => {
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class={cx('--header__global')}>
|
|
||||||
{#each orderedRightPanel as action, index}
|
|
||||||
<ActionGeneric {action} on:inputSearch />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
|
@ -1,81 +0,0 @@
|
||||||
<script>
|
|
||||||
export let href = undefined;
|
|
||||||
export let text = undefined;
|
|
||||||
export let subMenu = undefined;
|
|
||||||
export let icon = undefined;
|
|
||||||
export let expanded = false;
|
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
|
||||||
import { onDestroy } from 'svelte';
|
|
||||||
import Icon from '../../Icon/Icon.svelte';
|
|
||||||
import ChevronDown16 from 'carbon-icons-svelte/lib/ChevronDown16';
|
|
||||||
import isNavItemSelectedStore from './isNavItemSelectedStore';
|
|
||||||
import UIShellSideNavSubMenu from './UIShellSideNavSubMenu.svelte';
|
|
||||||
|
|
||||||
let isSelected = undefined;
|
|
||||||
|
|
||||||
const unsubscribe = isNavItemSelectedStore.subscribe(values => {
|
|
||||||
values.forEach(item => {
|
|
||||||
if (item.id === text) {
|
|
||||||
isSelected = item.isSelected;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let iconProps = {
|
|
||||||
class: undefined,
|
|
||||||
skeleton: false,
|
|
||||||
render: ChevronDown16,
|
|
||||||
title: 'Open Menu',
|
|
||||||
tabindex: '0',
|
|
||||||
focusable: false,
|
|
||||||
style: undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
unsubscribe();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if href}
|
|
||||||
<li class={cx('--side-nav__item')}>
|
|
||||||
<a
|
|
||||||
{href}
|
|
||||||
class={cx('--side-nav__link', isSelected && '--side-nav__link--current')}
|
|
||||||
aria-current={isSelected ? 'page' : ''}
|
|
||||||
on:click={() => isNavItemSelectedStore.setSelected(text)}>
|
|
||||||
<div class={cx('--side-nav__icon', '--side-nav__icon--small')}>
|
|
||||||
{#if icon}
|
|
||||||
<Icon {...icon[0]} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<span class={cx('--side-nav__link-text')}>{text}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{:else}
|
|
||||||
<li class={cx('--side-nav__item', '--side-nav__item--icon')}>
|
|
||||||
<button
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded={expanded}
|
|
||||||
class={cx('--side-nav__submenu')}
|
|
||||||
type="button"
|
|
||||||
on:click={() => {
|
|
||||||
expanded = !expanded;
|
|
||||||
}}>
|
|
||||||
<div class={cx('--side-nav__icon')}>
|
|
||||||
<Icon {...icon[0]} />
|
|
||||||
</div>
|
|
||||||
<span class={cx('--side-nav__submenu-title')}>{text}</span>
|
|
||||||
<div class={cx('--side-nav__icon', '--side-nav__icon--small', '--side-nav__submenu-chevron')}>
|
|
||||||
{#if icon}
|
|
||||||
<Icon {...iconProps} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<ul class={cx('--side-nav__menu')} role="menu">
|
|
||||||
{#each subMenu as menuItem}
|
|
||||||
<UIShellSideNavSubMenu {...menuItem} />
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
|
@ -1,33 +0,0 @@
|
||||||
<script>
|
|
||||||
export let href = undefined;
|
|
||||||
export let text = undefined;
|
|
||||||
|
|
||||||
import { cx } from '../../../lib';
|
|
||||||
import { onDestroy } from 'svelte';
|
|
||||||
import isNavItemSelectedStore from './isNavItemSelectedStore';
|
|
||||||
|
|
||||||
let isSelected = undefined;
|
|
||||||
|
|
||||||
const unsubscribe = isNavItemSelectedStore.subscribe(values => {
|
|
||||||
values.forEach(item => {
|
|
||||||
if (item.id === text) {
|
|
||||||
isSelected = item.isSelected;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
unsubscribe();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<li class={cx('--side-nav__menu-item')} role="none">
|
|
||||||
<a
|
|
||||||
{href}
|
|
||||||
class={cx('--side-nav__link')}
|
|
||||||
role="menuitem"
|
|
||||||
aria-current={isSelected ? 'page' : ''}
|
|
||||||
on:click={() => isNavItemSelectedStore.setSelected(text)}>
|
|
||||||
<span class={cx('--side-nav__link-text')}>{text}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
|
@ -1,60 +0,0 @@
|
||||||
import { writable } from 'svelte/store';
|
|
||||||
|
|
||||||
const isSelectedStore = writable([undefined]);
|
|
||||||
|
|
||||||
const store = {
|
|
||||||
subscribe: isSelectedStore.subscribe,
|
|
||||||
setStoreValues: arrayOfObjs => {
|
|
||||||
let storeNewData = [];
|
|
||||||
arrayOfObjs.forEach(element => {
|
|
||||||
let newItem = {};
|
|
||||||
if (element.href) {
|
|
||||||
newItem = {
|
|
||||||
id: element.text,
|
|
||||||
isSelected: false
|
|
||||||
};
|
|
||||||
|
|
||||||
storeNewData.push(newItem);
|
|
||||||
} else {
|
|
||||||
element.subMenu.forEach(subelement => {
|
|
||||||
newItem = {
|
|
||||||
id: subelement.text,
|
|
||||||
isSelected: false
|
|
||||||
};
|
|
||||||
|
|
||||||
storeNewData.push(newItem);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
isSelectedStore.set(storeNewData);
|
|
||||||
},
|
|
||||||
setSelected: id => {
|
|
||||||
isSelectedStore.update(values => {
|
|
||||||
const newValues = values.map(item => {
|
|
||||||
if (item.id === id) {
|
|
||||||
item.isSelected = true;
|
|
||||||
return item;
|
|
||||||
} else {
|
|
||||||
item.isSelected = false;
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return newValues;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deselectAll: () => {
|
|
||||||
isSelectedStore.update(values => {
|
|
||||||
values.forEach(item => {
|
|
||||||
item.isSelected = false;
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
clear: () => {
|
|
||||||
isSelectedStore.set(undefined);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default store;
|
|
|
@ -84,3 +84,13 @@ export const closeIcon = {
|
||||||
focusable: false,
|
focusable: false,
|
||||||
style: undefined
|
style: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const searchIcon = {
|
||||||
|
class: undefined,
|
||||||
|
skeleton: false,
|
||||||
|
render: Search20,
|
||||||
|
title: 'Search',
|
||||||
|
tabindex: '0',
|
||||||
|
focusable: false,
|
||||||
|
style: undefined
|
||||||
|
};
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
import UIShell from './UIShell.svelte';
|
import UIShell from './UIShell.svelte';
|
||||||
|
|
||||||
export default UIShell;
|
export default UIShell;
|
||||||
|
|
||||||
|
export { default as SideNav } from './SideNav/SideNav.svelte';
|
||||||
|
export { default as SideNavItems } from './SideNav/SideNavItems.svelte';
|
||||||
|
export { default as SideNavLink } from './SideNav/SideNavLink.svelte';
|
||||||
|
export { default as SideNavMenu } from './SideNav/SideNavMenu.svelte';
|
||||||
|
export { default as SideNavMenuItem } from './SideNav/SideNavMenuItem.svelte';
|
||||||
|
export { default as HeaderNav } from './GlobalHeader/HeaderNav.svelte';
|
||||||
|
export { default as HeaderNavItem } from './GlobalHeader/HeaderNavItem.svelte';
|
||||||
|
export { default as HeaderNavMenu } from './GlobalHeader/HeaderNavMenu.svelte';
|
||||||
|
export { default as HeaderUtilities } from './GlobalHeader/HeaderUtilities.svelte';
|
||||||
|
export { default as HeaderAction } from './GlobalHeader/HeaderAction.svelte';
|
||||||
|
export { default as HeaderActionLink } from './GlobalHeader/HeaderActionLink.svelte';
|
||||||
|
export { default as HeaderActionSearch } from './GlobalHeader/HeaderActionSearch.svelte';
|
||||||
|
export { default as HeaderPanelDivider } from './GlobalHeader/HeaderPanelDivider.svelte';
|
||||||
|
export { default as HeaderPanelLink } from './GlobalHeader/HeaderPanelLink.svelte';
|
||||||
|
export { default as HeaderPanelLinks } from './GlobalHeader/HeaderPanelLinks.svelte';
|
||||||
|
|
27
src/index.js
27
src/index.js
|
@ -78,7 +78,20 @@ import ToggleSmall, { ToggleSmallSkeleton } from './components/ToggleSmall';
|
||||||
import Tooltip from './components/Tooltip';
|
import Tooltip from './components/Tooltip';
|
||||||
import TooltipDefinition from './components/TooltipDefinition';
|
import TooltipDefinition from './components/TooltipDefinition';
|
||||||
import TooltipIcon from './components/TooltipIcon';
|
import TooltipIcon from './components/TooltipIcon';
|
||||||
import UIShell from './components/UIShell';
|
import UIShell, {
|
||||||
|
SideNav,
|
||||||
|
SideNavItems,
|
||||||
|
SideNavLink,
|
||||||
|
SideNavMenu,
|
||||||
|
SideNavMenuItem,
|
||||||
|
HeaderNav,
|
||||||
|
HeaderNavItem,
|
||||||
|
HeaderNavMenu,
|
||||||
|
HeaderUtilities,
|
||||||
|
HeaderAction,
|
||||||
|
HeaderActionLink,
|
||||||
|
HeaderActionSearch
|
||||||
|
} from './components/UIShell';
|
||||||
import UnorderedList from './components/UnorderedList';
|
import UnorderedList from './components/UnorderedList';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -194,5 +207,17 @@ export {
|
||||||
TooltipDefinition,
|
TooltipDefinition,
|
||||||
TooltipIcon,
|
TooltipIcon,
|
||||||
UIShell,
|
UIShell,
|
||||||
|
SideNav,
|
||||||
|
SideNavItems,
|
||||||
|
SideNavLink,
|
||||||
|
SideNavMenu,
|
||||||
|
SideNavMenuItem,
|
||||||
|
HeaderNav,
|
||||||
|
HeaderNavItem,
|
||||||
|
HeaderNavMenu,
|
||||||
|
HeaderUtilities,
|
||||||
|
HeaderAction,
|
||||||
|
HeaderActionLink,
|
||||||
|
HeaderActionSearch,
|
||||||
UnorderedList
|
UnorderedList
|
||||||
};
|
};
|
||||||
|
|
|
@ -5184,9 +5184,9 @@ eslint-visitor-keys@^1.1.0:
|
||||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
||||||
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
||||||
|
|
||||||
eslint@^6.7.2:
|
eslint@^6.8.0:
|
||||||
version "6.8.0"
|
version "6.8.0"
|
||||||
resolved "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
|
||||||
integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
|
integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.0.0"
|
"@babel/code-frame" "^7.0.0"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue