Skip to content

Commit

Permalink
feat(module:sidebar-nav): add icon more properties (#263)
Browse files Browse the repository at this point in the history
* feat(module:sidebar-nav): add icon more properties

- add nav image width & height
  • Loading branch information
cipchk committed Nov 7, 2018
1 parent d001642 commit 5b696f5
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 93 deletions.
51 changes: 31 additions & 20 deletions packages/abc/sidebar-nav/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,34 @@ ng-alain 左边主菜单,依赖于 `@delon/theme`。

### Menu

参数 | 类型 | 说明
----|------|-----
text | `string` | 文本,必填项
i18n | `string` | i18n主键
group | `string` | 是否显示分组名,默认:`true`,指[示例](//ng-alain.github.io/ng-alain/)中的【主导航】字样
link | `string` | 路由,`link``externalLink` 二选其一
linkExact | `boolean` | 路由是否精准匹配,默认:`false` [#344](https://github.com/ng-alain/ng-alain/issues/344)
externalLink | `string` | 外部链接,`link``externalLink` 二选其一
target | `_blank,_self,_parent,_top` | 链接 target
icon | `string` | 图标,指[示例](//ng-alain.github.io/ng-alain/)中的【仪表盘】前图标,只对一级菜单有效
badge | `number` | 徽标数,展示的数字,指[示例](//ng-alain.github.io/ng-alain/)中的【小部件】后的红色块。(注:`group:true` 时无效)
badgeDot | `boolean` | 徽标数,显示小红点
badgeStatus | `string` | 徽标 Badge 颜色 (默认:error, 所有[颜色值](https://next.ng-alain.com/theme/tools#%E8%89%B2%E5%BD%A9)
hide | `boolean` | 是否隐藏菜单
hideInBreadcrumb | `boolean` | 隐藏面包屑,指 `page-header` 组件的自动生成面包屑时有效
acl | `any` | ACL配置,若导入 `@delon/acl` 时自动有效,等同于 `ACLService.can(roleOrAbility: ACLCanType)` 参数值
shortcut | `boolean` | 是否快捷菜单项
shortcutRoot | `boolean` | 快捷菜单根节点
reuse | `boolean` | 是否允许复用,需配合 `reuse-tab` 组件
children | `Menu[]` | 子菜单
参数 | 说明 | 类型 | 默认值
----|------|-----|------
text | 文本,必填项 | `string` | -
i18n | i18n主键 | `string` | -
group | 是否显示分组名,默认:`true`,指[示例](//ng-alain.github.io/ng-alain/)中的【主导航】字样 | `string` | -
link | 路由,`link``externalLink` 二选其一 | `string` | -
linkExact | 路由是否精准匹配,默认:`false` [#344](https://github.com/ng-alain/ng-alain/issues/344) | `boolean` | -
externalLink | 外部链接,`link``externalLink` 二选其一 | `string` | -
target | 链接 target | `_blank,_self,_parent,_top` | -
icon | 图标,指[示例](//ng-alain.github.io/ng-alain/)中的【仪表盘】前图标,只对一级菜单有效 | `string | MenuIcon` | -
badge | 徽标数,展示的数字,指[示例](//ng-alain.github.io/ng-alain/)中的【小部件】后的红色块。(注:`group:true` 时无效) | `number` | -
badgeDot | 徽标数,显示小红点 | `boolean` | -
badgeStatus | 徽标 Badge 颜色 (默认:error, 所有[颜色值](https://next.ng-alain.com/theme/tools#%E8%89%B2%E5%BD%A9) | `string` | -
hide | 是否隐藏菜单 | `boolean` | -
hideInBreadcrumb | 隐藏面包屑,指 `page-header` 组件的自动生成面包屑时有效 | `boolean` | -
acl | ACL配置,若导入 `@delon/acl` 时自动有效,等同于 `ACLService.can(roleOrAbility: ACLCanType)` 参数值 | `any` | -
shortcut | 是否快捷菜单项 | `boolean` | -
shortcutRoot | 快捷菜单根节点 | `boolean` | -
reuse | 是否允许复用,需配合 `reuse-tab` 组件 | `boolean` | -
children | 子菜单 | `Menu[]` | -

### MenuIcon

参数 | 说明 | 类型 | 默认值
----|------|-----|------
`[type]` | 类型 | `class,icon,img` | `icon`
`[value]` | 值,包含:类名、图标 `type`、图像 | `string` | -
`[theme]` | 图标主题风格 | `outline,twotone,fill` | `outline`
`[spin]` | 是否有旋转动画 | `boolean` | `false`
`[twoToneColor]` | 仅适用双色图标,设置双色图标的主要颜色,仅对当前 icon 生效 | `string` | -
`[iconfont]` | 指定来自 IconFont 的图标类型 | `string` | -
4 changes: 2 additions & 2 deletions packages/abc/sidebar-nav/sidebar-nav.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<ng-template #icon let-i>
<ng-container *ngIf="i" [ngSwitch]="i.type">
<i *ngSwitchCase="'icon'" nz-icon [type]="i.value" class="sidebar-nav__item-icon"></i>
<img *ngSwitchCase="'img'" src="{{ i.value }}" class="sidebar-nav__item-icon">
<i *ngSwitchCase="'icon'" class="sidebar-nav__item-icon" nz-icon [type]="i.value" [theme]="i.theme" [spin]="i.spin" [twoToneColor]="i.twoToneColor" [iconfont]="i.iconfont"></i>
<img *ngSwitchCase="'img'" src="{{ i.value }}" class="sidebar-nav__item-icon sidebar-nav__item-img">
<i *ngSwitchDefault class="sidebar-nav__item-icon {{ i.value }}"></i>
</ng-container>
</ng-template>
Expand Down
181 changes: 116 additions & 65 deletions packages/abc/sidebar-nav/sidebar-nav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import { By } from '@angular/platform-browser';
import { RouterModule, Router } from '@angular/router';
import { APP_BASE_HREF, DOCUMENT } from '@angular/common';

import { AlainThemeModule, MenuService, SettingsService } from '@delon/theme';
import {
AlainThemeModule,
MenuService,
SettingsService,
MenuIcon,
} from '@delon/theme';
import { deepCopy } from '@delon/util';

import { SidebarNavModule } from './sidebar-nav.module';
Expand All @@ -29,7 +34,11 @@ const MOCKMENUS = <Nav[]>[
{ text: 'v1', link: '/v1' },
{ text: 'v2', link: '#/v2', i18n: 'v2-i18n' },
{ text: 'v3' },
{ text: 'externalLink', externalLink: '//ng-alain.com', target: '_blank' },
{
text: 'externalLink',
externalLink: '//ng-alain.com',
target: '_blank',
},
],
},
],
Expand Down Expand Up @@ -181,6 +190,50 @@ describe('abc: sidebar-nav', () => {
});
});

describe('#icon', () => {
function updateIcon(icon: string | MenuIcon) {
createComp();

menuSrv.add(<Nav[]>[
{
text: '',
group: true,
children: [
{
text: '',
icon,
},
],
},
]);

fixture.detectChanges();
}
describe('with icon', () => {
it('when is string and includes [anticon-]', () => {
updateIcon('anticon-edit');
const el = page.getEl('.sidebar-nav__item-icon') as HTMLElement;
expect(el.classList).toContain('anticon-edit');
});
it('when is string and http prefix', () => {
updateIcon('http://ng-alain/1.jpg');
page.checkCount('.sidebar-nav__item-img', 1);
});
it('when is class string', () => {
updateIcon('demo-class');
page.checkCount('.demo-class', 1);
});
});
it('with className', () => {
updateIcon({ type: 'class', value: 'demo-class' });
page.checkCount('.demo-class', 1);
});
it('with img', () => {
updateIcon({ type: 'img', value: '1.jpg' });
page.checkCount('.sidebar-nav__item-img', 1);
});
});

describe('[collapsed]', () => {
describe('#default', () => {
beforeEach(() => {
Expand All @@ -197,8 +250,14 @@ describe('abc: sidebar-nav', () => {
page.showSubMenu();
});
it('should be displayed full submenu', () => {
const clientHeight = spyOnProperty(doc.documentElement, 'clientHeight').and.returnValue(0);
spyOnProperty(doc.querySelector('body'), 'clientHeight').and.returnValue(0);
const clientHeight = spyOnProperty(
doc.documentElement,
'clientHeight',
).and.returnValue(0);
spyOnProperty(
doc.querySelector('body'),
'clientHeight',
).and.returnValue(0);
expect(clientHeight).not.toHaveBeenCalled();
page.showSubMenu();
expect(clientHeight).toHaveBeenCalled();
Expand Down Expand Up @@ -240,9 +299,9 @@ describe('abc: sidebar-nav', () => {
setSrv.layout.collapsed = true;
fixture.detectChanges();
page.showSubMenu();
page.getEl<HTMLElement>(floatingShowCls, true).dispatchEvent(
new Event('mouseleave'),
);
page
.getEl<HTMLElement>(floatingShowCls, true)
.dispatchEvent(new Event('mouseleave'));
fixture.detectChanges();
expect(page.getEl<HTMLElement>(floatingShowCls, true)).toBeNull();
});
Expand Down Expand Up @@ -288,65 +347,56 @@ describe('abc: sidebar-nav', () => {
});

describe('[underPad]', () => {
it(
'should be auto collapsed when less than pad',
fakeAsync(() => {
// create test component
TestBed.overrideTemplate(
TestComponent,
`<sidebar-nav #comp [autoCloseUnderPad]="true"></sidebar-nav>`,
);
const defaultCollapsed = false;
createComp(false, () => {
spyOnProperty(window, 'innerWidth').and.returnValue(767);
setSrv.layout.collapsed = defaultCollapsed;
fixture.detectChanges();
});
router.navigateByUrl('/');
fixture.detectChanges();
tick(20);
expect(setSrv.layout.collapsed).toBe(!defaultCollapsed);
}),
);
it(
`should be won't collapsed when more than pad`,
fakeAsync(() => {
// create test component
TestBed.overrideTemplate(
TestComponent,
`<sidebar-nav #comp [autoCloseUnderPad]="true"></sidebar-nav>`,
);
const defaultCollapsed = false;
createComp(false, () => {
spyOnProperty(window, 'innerWidth').and.returnValue(769);
setSrv.layout.collapsed = defaultCollapsed;
fixture.detectChanges();
});
router.navigateByUrl('/');
fixture.detectChanges();
tick(20);
expect(setSrv.layout.collapsed).toBe(defaultCollapsed);
}),
);
it(
'should be auto expaned when less than pad trigger click',
fakeAsync(() => {
// create test component
TestBed.overrideTemplate(
TestComponent,
`<sidebar-nav #comp [autoCloseUnderPad]="true"></sidebar-nav>`,
);
createComp();
setSrv.layout.collapsed = true;
fixture.detectChanges();
it('should be auto collapsed when less than pad', fakeAsync(() => {
// create test component
TestBed.overrideTemplate(
TestComponent,
`<sidebar-nav #comp [autoCloseUnderPad]="true"></sidebar-nav>`,
);
const defaultCollapsed = false;
createComp(false, () => {
spyOnProperty(window, 'innerWidth').and.returnValue(767);
expect(setSrv.layout.collapsed).toBe(true);
page.getEl<HTMLElement>('.sidebar-nav').click();
setSrv.layout.collapsed = defaultCollapsed;
fixture.detectChanges();
tick(20);
expect(setSrv.layout.collapsed).toBe(false);
}),
);
});
router.navigateByUrl('/');
fixture.detectChanges();
tick(20);
expect(setSrv.layout.collapsed).toBe(!defaultCollapsed);
}));
it(`should be won't collapsed when more than pad`, fakeAsync(() => {
// create test component
TestBed.overrideTemplate(
TestComponent,
`<sidebar-nav #comp [autoCloseUnderPad]="true"></sidebar-nav>`,
);
const defaultCollapsed = false;
createComp(false, () => {
spyOnProperty(window, 'innerWidth').and.returnValue(769);
setSrv.layout.collapsed = defaultCollapsed;
fixture.detectChanges();
});
router.navigateByUrl('/');
fixture.detectChanges();
tick(20);
expect(setSrv.layout.collapsed).toBe(defaultCollapsed);
}));
it('should be auto expaned when less than pad trigger click', fakeAsync(() => {
// create test component
TestBed.overrideTemplate(
TestComponent,
`<sidebar-nav #comp [autoCloseUnderPad]="true"></sidebar-nav>`,
);
createComp();
setSrv.layout.collapsed = true;
fixture.detectChanges();
spyOnProperty(window, 'innerWidth').and.returnValue(767);
expect(setSrv.layout.collapsed).toBe(true);
page.getEl<HTMLElement>('.sidebar-nav').click();
fixture.detectChanges();
tick(20);
expect(setSrv.layout.collapsed).toBe(false);
}));
});

class PageObject {
Expand Down Expand Up @@ -399,7 +449,8 @@ describe('abc: sidebar-nav', () => {
`,
})
class TestComponent {
@ViewChild('comp') comp: SidebarNavComponent;
@ViewChild('comp')
comp: SidebarNavComponent;
autoCloseUnderPad = false;
select() {}
}
Expand Down
9 changes: 9 additions & 0 deletions packages/theme/src/services/menu/interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
export interface MenuIcon {
type: 'class' | 'icon' | 'img';
/** 值,包含:类名、图标 `type`、图像 */
value: string;
/** 图标主题风格,默认:`outline` */
theme?: 'outline' | 'twotone' | 'fill';
/** 是否有旋转动画,默认:`false` */
spin?: boolean;
/** 仅适用双色图标,设置双色图标的主要颜色,仅对当前 icon 生效 */
twoToneColor?: string;
/** 指定来自 IconFont 的图标类型 */
iconfont?: string;
}

export interface Menu {
Expand Down
3 changes: 3 additions & 0 deletions packages/theme/src/services/menu/menu.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ export class MenuService implements OnDestroy {
}
item.icon = { type, value } as any;
}
if (item.icon != null) {
item.icon = Object.assign({ theme: 'outline', spin: false }, item.icon);
}

// shortcut
if (parent && item.shortcut === true && parent.shortcutRoot !== true)
Expand Down
21 changes: 15 additions & 6 deletions packages/theme/styles/layout/default/fix/sidebar-nav.less
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Main Nav
@sidebar-nav-prefix-cls: sidebar-nav;
@sidebar-nav-prefix-cls: sidebar-nav;

.@{sidebar-nav-prefix-cls} {
display: block;
Expand All @@ -12,13 +12,14 @@
transition: border-left-color 0.4s ease;
&-link {
color: @alain-default-aside-nav-text-color;
text-decoration: none;
text-decoration: none !important;
padding: @alain-default-aside-nav-padding-top-bottom @layout-gutter * 2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: relative;
display: block;
display: flex;
align-items: center;
user-select: none;
&:hover {
color: @alain-default-aside-nav-text-hover-color;
Expand All @@ -30,6 +31,10 @@
margin-right: @layout-gutter;
transition: font-size 0.15s @ease-out, margin 0.3s @ease-in-out;
}
&-img {
height: @alain-default-aside-nav-img-wh;
width: @alain-default-aside-nav-img-wh;
}
&-text {
transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out;
opacity: 1;
Expand Down Expand Up @@ -183,13 +188,17 @@
.@{sidebar-nav-prefix-cls}__item {
border: none;
&-link {
text-align: center;
justify-content: center;
padding: (@layout-gutter * 3) 0;
i {
.@{sidebar-nav-prefix-cls}__item-icon {
margin-right: 0;
font-size: @alain-default-aside-collapsed-nav-fs;
}
> span {
.@{sidebar-nav-prefix-cls}__item-img {
width: @alain-default-aside-collapsed-nav-img-wh;
height: @alain-default-aside-collapsed-nav-img-wh;
}
.@{sidebar-nav-prefix-cls}__item-text {
opacity: 0;
display: none;
}
Expand Down
3 changes: 3 additions & 0 deletions packages/theme/styles/layout/default/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ The default layout all parameters are prefixed with `@alain-default-`.
| `@alain-default-aside-scrollbar-track-color` | `transparent` | Scrollbar track color of aside |
| `@alain-default-aside-scrollbar-thumb-color` | `transparent` | Scrollbar thumb color of aside |
| `@alain-default-aside-nav-fs` | `14px` | Font size of nav name |
| `@alain-default-aside-nav-icon-width` | `14px` | Width of nav icon |
| `@alain-default-aside-nav-img-wh` | `14px` | Width & height of nav image |
| `@alain-default-aside-nav-padding-top-bottom` | `@layout-gutter` | Vertical padding of nav |
| `@alain-default-aside-nav-item-height` | `38px` | Item height of nav |
| `@alain-default-aside-nav-text-color` | `rgba(0, 0, 0, 0.65)` | Nav text color |
Expand All @@ -33,6 +35,7 @@ The default layout all parameters are prefixed with `@alain-default-`.
| `@alain-default-aside-nav-selected-bg` | `#fcfcfc` | Nav selected background color |
| `@alain-default-aside-collapsed-wd` | `@layout-gutter * 8` | Width of aside collapsed |
| `@alain-default-aside-collapsed-nav-fs` | `24px` | Font size of aside collapsed |
| `@alain-default-aside-collapsed-nav-img-wh` | `24px` | Width & height nav image of aside collapsed |
| `@alain-default-content-heading-bg` | `#fafbfc` | Heading background color of content area |
| `@alain-default-content-heading-border` | `#efe3e5` | Heading bottom border color of content area |
| `@alain-default-content-padding` | `@layout-gutter * 3` | Padding of content area |
Expand Down
Loading

0 comments on commit 5b696f5

Please sign in to comment.