diff --git a/src/core/cli/.gitignore b/src/core/cli/.gitignore
index b28ef90182..2a1d409afc 100644
--- a/src/core/cli/.gitignore
+++ b/src/core/cli/.gitignore
@@ -22,10 +22,6 @@ application/files/__sourcedir__/test.ts
application/files/__sourcedir__/tsconfig.app.json
application/files/__sourcedir__/tsconfig.spec.json
application/files/__sourcedir__/typings.d.ts
-application/other-files/layout
-!application/other-files/layout/layout.module.ts
-!application/other-files/layout/default/default.component.html
-!application/other-files/layout/default/header/header.component.html
application/other-files/core/i18n
application/other-files/core/net
application/other-files/core/module-import-guard.ts
@@ -35,3 +31,9 @@ application/other-files/routes/callback
application/other-files/routes/exception
application/other-files/routes/passport
utility
+class
+directive
+enum
+interface
+pipe
+service
diff --git a/src/core/cli/application/other-files/layout/default/default.component.html b/src/core/cli/application/other-files/layout/default/default.component.html
new file mode 100644
index 0000000000..ac5a74d5fc
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/default.component.html
@@ -0,0 +1,8 @@
+
diff --git a/src/core/cli/application/other-files/layout/default/default.component.spec.ts b/src/core/cli/application/other-files/layout/default/default.component.spec.ts
new file mode 100644
index 0000000000..cd26602a0f
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/default.component.spec.ts
@@ -0,0 +1,17 @@
+import { TestBed, TestModuleMetadata } from '@angular/core/testing';
+
+import { setUpTestBed } from '@testing/common.spec';
+
+import { LayoutDefaultComponent } from './default.component';
+
+describe('Layout', () => {
+ setUpTestBed({
+ declarations: [LayoutDefaultComponent]
+ });
+
+ it('should create an instance', () => {
+ const fixture = TestBed.createComponent(LayoutDefaultComponent);
+ const comp = fixture.debugElement.componentInstance;
+ expect(comp).toBeTruthy();
+ });
+});
diff --git a/src/core/cli/application/other-files/layout/default/default.component.ts b/src/core/cli/application/other-files/layout/default/default.component.ts
new file mode 100644
index 0000000000..2055b6c8b8
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/default.component.ts
@@ -0,0 +1,38 @@
+import { Component } from '@angular/core';
+import { Router, NavigationEnd, RouteConfigLoadStart, NavigationError } from '@angular/router';
+import { NzMessageService } from 'ng-zorro-antd';
+import { ScrollService, MenuService, SettingsService } from '@delon/theme';
+
+@Component({
+ selector: 'layout-default',
+ templateUrl: './default.component.html'
+})
+export class LayoutDefaultComponent {
+ isFetching = false;
+
+ constructor(
+ router: Router,
+ scroll: ScrollService,
+ private _message: NzMessageService,
+ public menuSrv: MenuService,
+ public settings: SettingsService) {
+ // scroll to top in change page
+ router.events.subscribe(evt => {
+ if (!this.isFetching && evt instanceof RouteConfigLoadStart) {
+ this.isFetching = true;
+ }
+ if (evt instanceof NavigationError) {
+ this.isFetching = false;
+ _message.error(`无法加载${evt.url}路由`, { nzDuration: 1000 * 3 });
+ return;
+ }
+ if (!(evt instanceof NavigationEnd)) {
+ return;
+ }
+ setTimeout(() => {
+ scroll.scrollToTop();
+ this.isFetching = false;
+ }, 100);
+ });
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/fullscreen.component.ts b/src/core/cli/application/other-files/layout/default/header/components/fullscreen.component.ts
new file mode 100644
index 0000000000..d513b98d0f
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/fullscreen.component.ts
@@ -0,0 +1,22 @@
+import { Component, HostListener } from '@angular/core';
+import * as screenfull from 'screenfull';
+
+@Component({
+ selector: 'header-fullscreen',
+ template: `
+
+ <% if (!delonI18n) { %>{{ status ? '退出全屏' : '全屏' }}<% } %><% if (delonI18n) { %>{{(status ? 'fullscreen-exit' : 'fullscreen') | translate }}<% } %>
+ `
+})
+export class HeaderFullScreenComponent {
+
+ status = false;
+
+ @HostListener('click')
+ _click() {
+ if (screenfull.enabled) {
+ screenfull.toggle();
+ }
+ this.status = !screenfull.isFullscreen;
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/icon.component.ts b/src/core/cli/application/other-files/layout/default/header/components/icon.component.ts
new file mode 100644
index 0000000000..e56b58a832
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/icon.component.ts
@@ -0,0 +1,59 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'header-icon',
+ template: `
+
+
+
+
+
+
+
+
+
+ Calendar
+
+
+
+ Files
+
+
+
+ Cloud
+
+
+
+ Star
+
+
+
+ Team
+
+
+
+ QR
+
+
+
+ Pay
+
+
+
+ Print
+
+
+
+
+
+ `
+})
+export class HeaderIconComponent {
+
+ loading = true;
+
+ change() {
+ setTimeout(() => this.loading = false, 500);
+ }
+
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/langs.component.ts b/src/core/cli/application/other-files/layout/default/header/components/langs.component.ts
new file mode 100644
index 0000000000..0963186685
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/langs.component.ts
@@ -0,0 +1,41 @@
+<% if (delonI18n) { %>import { Component } from '@angular/core';
+import { SettingsService, MenuService } from '@delon/theme';
+import { I18NService } from '@core/i18n/i18n.service';
+
+@Component({
+ selector: 'header-langs',
+ template: `
+
+
+
+ {{ 'language' | translate}}
+
+
+
+
+ `
+})
+export class HeaderLangsComponent {
+
+ langs: any[];
+
+ constructor(
+ private menuService: MenuService,
+ public settings: SettingsService,
+ public tsServ: I18NService
+ ) {
+ this.langs = this.tsServ.getLangs();
+ }
+
+ change(lang: string) {
+ this.tsServ.use(lang, false).subscribe(() => {
+ this.menuService.resume();
+ });
+ this.settings.setLayout('lang', lang);
+ }
+}
+<% } %>
\ No newline at end of file
diff --git a/src/core/cli/application/other-files/layout/default/header/components/notify.component.ts b/src/core/cli/application/other-files/layout/default/header/components/notify.component.ts
new file mode 100644
index 0000000000..54cec04145
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/notify.component.ts
@@ -0,0 +1,163 @@
+import { NzMessageService } from 'ng-zorro-antd';
+import { Component, OnInit, Input } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import { ArrayObservable } from 'rxjs/observable/ArrayObservable';
+import { map, groupBy, concatMap, mergeMap, flatMap, delay, tap, toArray } from 'rxjs/operators';
+import * as moment from 'moment';
+import { NoticeItem } from '@delon/abc';
+import { SettingsService } from '@delon/theme';
+
+/**
+ * 菜单通知
+ */
+@Component({
+ selector: 'header-notify',
+ template: `
+
+ `
+})
+export class HeaderNotifyComponent implements OnInit {
+
+ data: NoticeItem[] = [
+ { title: '通知', list: [], emptyText: '你已查看所有通知', emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg' },
+ { title: '消息', list: [], emptyText: '您已读完所有消息', emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg' },
+ { title: '待办', list: [], emptyText: '你已完成所有待办', emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg' }
+ ];
+ count = 0;
+ loading = false;
+
+ constructor(private msg: NzMessageService, private settings: SettingsService) {}
+
+ ngOnInit() {
+ // mock data
+ this.count = this.settings.user.notifyCount || 12;
+ }
+
+ private parseGroup(data: Observable) {
+ console.log('parseGroup');
+ data.pipe(
+ concatMap((i: any) => i),
+ map((i: any) => {
+ if (i.datetime) i.datetime = moment(i.datetime).fromNow();
+ // change to color
+ if (i.status) {
+ i.color = ({
+ todo: '',
+ processing: 'blue',
+ urgent: 'red',
+ doing: 'gold',
+ })[i.status];
+ }
+ return i;
+ }),
+ groupBy((x: any) => x.type),
+ mergeMap(g => g.pipe(toArray())),
+ tap((ls: any) => {
+ this.data.find(w => w.title === ls[0].type).list = ls;
+ })
+ ).subscribe(res => this.loading = false);
+ }
+
+ loadData(res) {
+ if (!res || this.loading) return;
+ this.loading = true;
+ // region: mock http request
+ this.parseGroup(ArrayObservable.of([{
+ id: '000000001',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
+ title: '你收到了 14 份新周报',
+ datetime: '2017-08-09',
+ type: '通知',
+ }, {
+ id: '000000002',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
+ title: '你推荐的 曲妮妮 已通过第三轮面试',
+ datetime: '2017-08-08',
+ type: '通知',
+ }, {
+ id: '000000003',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
+ title: '这种模板可以区分多种通知类型',
+ datetime: '2017-08-07',
+ read: true,
+ type: '通知',
+ }, {
+ id: '000000004',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
+ title: '左侧图标用于区分不同的类型',
+ datetime: '2017-08-07',
+ type: '通知',
+ }, {
+ id: '000000005',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
+ title: '内容不要超过两行字,超出时自动截断',
+ datetime: '2017-08-07',
+ type: '通知',
+ }, {
+ id: '000000006',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+ title: '曲丽丽 评论了你',
+ description: '描述信息描述信息描述信息',
+ datetime: '2017-08-07',
+ type: '消息',
+ }, {
+ id: '000000007',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+ title: '朱偏右 回复了你',
+ description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
+ datetime: '2017-08-07',
+ type: '消息',
+ }, {
+ id: '000000008',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+ title: '标题',
+ description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
+ datetime: '2017-08-07',
+ type: '消息',
+ }, {
+ id: '000000009',
+ title: '任务名称',
+ description: '任务需要在 2017-01-12 20:00 前启动',
+ extra: '未开始',
+ status: 'todo',
+ type: '待办',
+ }, {
+ id: '000000010',
+ title: '第三方紧急代码变更',
+ description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
+ extra: '马上到期',
+ status: 'urgent',
+ type: '待办',
+ }, {
+ id: '000000011',
+ title: '信息安全考试',
+ description: '指派竹尔于 2017-01-09 前完成更新并发布',
+ extra: '已耗时 8 天',
+ status: 'doing',
+ type: '待办',
+ }, {
+ id: '000000012',
+ title: 'ABCD 版本发布',
+ description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
+ extra: '进行中',
+ status: 'processing',
+ type: '待办',
+ }
+ ]).pipe(delay(1000)));
+ // endregion
+ }
+
+ clear(type: string) {
+ this.msg.success(`清空了 ${type}`);
+ }
+
+ select(res: any) {
+ this.msg.success(`点击了 ${res.title} 的 ${res.item.title}`);
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/search.component.ts b/src/core/cli/application/other-files/layout/default/header/components/search.component.ts
new file mode 100644
index 0000000000..6a5446e798
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/search.component.ts
@@ -0,0 +1,49 @@
+import { Component, HostBinding, ViewChild, Input, OnInit, ElementRef, AfterViewInit } from '@angular/core';
+
+@Component({
+ selector: 'header-search',
+ template: `
+
+
+
+
+
+ `
+})
+export class HeaderSearchComponent implements AfterViewInit {
+
+ q: string;
+
+ qIpt: HTMLInputElement;
+
+ @HostBinding('class.header-search__focus')
+ focus = false;
+
+ @HostBinding('class.header-search__toggled')
+ searchToggled = false;
+
+ @Input()
+ set toggleChange(value: boolean) {
+ if (typeof value === 'undefined') return;
+ console.log('toggleChange', value);
+ this.searchToggled = true;
+ this.focus = true;
+ setTimeout(() => this.qIpt.focus(), 300);
+ }
+
+ constructor(private el: ElementRef) {}
+
+ ngAfterViewInit() {
+ this.qIpt = (this.el.nativeElement as HTMLElement).querySelector('.ant-input') as HTMLInputElement;
+ }
+
+ qFocus() {
+ this.focus = true;
+ }
+
+ qBlur() {
+ this.focus = false;
+ this.searchToggled = false;
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/storage.component.ts b/src/core/cli/application/other-files/layout/default/header/components/storage.component.ts
new file mode 100644
index 0000000000..62e27ea08d
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/storage.component.ts
@@ -0,0 +1,29 @@
+import { Component, HostListener } from '@angular/core';
+import { NzModalService, NzMessageService } from 'ng-zorro-antd';
+
+@Component({
+ selector: 'header-storage',
+ template: `
+
+ <% if (!delonI18n) { %>清除本地缓存<% } %><% if (delonI18n) { %>{{ 'clear-local-storage' | translate}}<% } %>
+ `
+})
+export class HeaderStorageComponent {
+
+ constructor(
+ private confirmServ: NzModalService,
+ private messageServ: NzMessageService
+ ) {
+ }
+
+ @HostListener('click')
+ _click() {
+ this.confirmServ.confirm({
+ title: 'Make sure clear all local storage?',
+ onOk: () => {
+ localStorage.clear();
+ this.messageServ.success('Clear Finished!');
+ }
+ });
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/task.component.ts b/src/core/cli/application/other-files/layout/default/header/components/task.component.ts
new file mode 100644
index 0000000000..507c0ff6f3
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/task.component.ts
@@ -0,0 +1,80 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'header-task',
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
cipchk
+
Please tell me what happened in a few words, don't go into details.
+
+
+
+
+
+
+
+
+
+
Kent
+
Please tell me what happened in a few words, don't go into details.
+
+
+
+
+
+
+
+
Jefferson
+
Please tell me what happened in a few words, don't go into details.
+
+
+
+
+
+
+ `
+})
+export class HeaderTaskComponent {
+
+ loading = true;
+
+ change() {
+ setTimeout(() => this.loading = false, 500);
+ }
+
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/theme.component.ts b/src/core/cli/application/other-files/layout/default/header/components/theme.component.ts
new file mode 100644
index 0000000000..49c3f4b08e
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/theme.component.ts
@@ -0,0 +1,44 @@
+import { Component } from '@angular/core';
+import { SettingsService, ThemesService, ThemeType } from '@delon/theme';
+
+@Component({
+ selector: 'header-theme',
+ template: `
+ <% if (!delonI18n) { %>切换主题<% } %><% if (delonI18n) { %>{{ 'theme-switch' | translate}}<% } %>
+
+ `
+})
+export class HeaderThemeComponent {
+
+ themes: { l: ThemeType, bg: string, nav: string, con: string }[] = [
+ { l: 'A', bg: '#108ee9', nav: '#fff', con: '#f5f7fa' },
+ { l: 'B', bg: '#00a2ae', nav: '#fff', con: '#f5f7fa' },
+ { l: 'C', bg: '#00a854', nav: '#fff', con: '#f5f7fa' },
+ { l: 'D', bg: '#f04134', nav: '#fff', con: '#f5f7fa' },
+ { l: 'E', bg: '#373d41', nav: '#fff', con: '#f5f7fa' },
+ { l: 'F', bg: '#108ee9', nav: '#404040', con: '#f5f7fa' },
+ { l: 'G', bg: '#00a2ae', nav: '#404040', con: '#f5f7fa' },
+ { l: 'H', bg: '#00a854', nav: '#404040', con: '#f5f7fa' },
+ { l: 'I', bg: '#f04134', nav: '#404040', con: '#f5f7fa' },
+ { l: 'J', bg: '#373d41', nav: '#404040', con: '#f5f7fa' }
+ ];
+
+ constructor(
+ public settings: SettingsService,
+ private themeServ: ThemesService
+ ) {
+ }
+
+ changeTheme(theme: ThemeType) {
+ this.themeServ.setTheme(theme);
+ this.settings.setLayout('theme', theme);
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/components/user.component.ts b/src/core/cli/application/other-files/layout/default/header/components/user.component.ts
new file mode 100644
index 0000000000..618337335e
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/components/user.component.ts
@@ -0,0 +1,47 @@
+import { Component, OnInit, Inject } from '@angular/core';
+import { Router } from '@angular/router';
+import { SettingsService } from '@delon/theme';
+import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
+
+@Component({
+ selector: 'header-user',
+ template: `
+
+
+
+ {{settings.user.name}}
+
+
+
+ `
+})
+export class HeaderUserComponent implements OnInit {
+ constructor(
+ public settings: SettingsService,
+ private router: Router,
+ @Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
+
+ ngOnInit(): void {
+ this.tokenService.change().subscribe((res: any) => {
+ this.settings.setUser(res);
+ });
+ // mock
+ const token = this.tokenService.get() || {
+ token: 'nothing',
+ name: 'Admin',
+ avatar: './assets/img/zorro.svg',
+ email: 'cipchk@qq.com'
+ };
+ this.tokenService.set(token);
+ }
+
+ logout() {
+ this.tokenService.clear();
+ this.router.navigateByUrl(this.tokenService.login_url);
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/header.component.html b/src/core/cli/application/other-files/layout/default/header/header.component.html
new file mode 100644
index 0000000000..9afca08b58
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/header.component.html
@@ -0,0 +1,68 @@
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<% if (delonI18n) { %>
+
+
+
<% } %>
+
+
+
+ -
+
+
+
+
diff --git a/src/core/cli/application/other-files/layout/default/header/header.component.spec.ts b/src/core/cli/application/other-files/layout/default/header/header.component.spec.ts
new file mode 100644
index 0000000000..4305fe53ba
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/header.component.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed, TestModuleMetadata } from '@angular/core/testing';
+import { setUpTestBed } from '@testing/common.spec';
+
+import { HeaderComponent } from './header.component';
+
+describe('Layout: Header', () => {
+ setUpTestBed({
+ declarations: [ HeaderComponent ]
+ });
+
+ it('should create an instance', () => {
+ const fixture = TestBed.createComponent(HeaderComponent);
+ const comp = fixture.debugElement.componentInstance;
+ expect(comp).toBeTruthy();
+ });
+});
diff --git a/src/core/cli/application/other-files/layout/default/header/header.component.ts b/src/core/cli/application/other-files/layout/default/header/header.component.ts
new file mode 100644
index 0000000000..0a759e8485
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/header.component.ts
@@ -0,0 +1,21 @@
+import { Component, ViewChild } from '@angular/core';
+import { SettingsService } from '@delon/theme';
+
+@Component({
+ selector: 'app-header',
+ templateUrl: './header.component.html'
+})
+export class HeaderComponent {
+ searchToggleStatus: boolean;
+
+ constructor(public settings: SettingsService) { }
+
+ toggleCollapsedSideabar() {
+ this.settings.setLayout('collapsed', !this.settings.layout.collapsed);
+ }
+
+ searchToggleChange() {
+ this.searchToggleStatus = !this.searchToggleStatus;
+ }
+
+}
diff --git a/src/core/cli/application/other-files/layout/default/header/index.md b/src/core/cli/application/other-files/layout/default/header/index.md
new file mode 100644
index 0000000000..aead1c5382
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/header/index.md
@@ -0,0 +1,20 @@
+---
+component: app-header
+title: 顶部菜单
+---
+
+顶部菜单组件允许通过 `components` 目录下的组件进行按需组装。
+
+## 组件列表
+
+组件名 | 说明
+----|------
+`header-fullscreen` | 全屏切换
+`header-icon` | 应用图标
+`header-langs` | 语言切换
+`header-notify` | 菜单通知
+`header-search` | 搜索框
+`header-storage` | 清除 LocalStorage 缓存
+`header-task` | 任务通知
+`header-theme` | 主题切换
+`header-user` | 用户菜单
diff --git a/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.html b/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.html
new file mode 100644
index 0000000000..72b6251701
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
{{settings.user.name}}
+
{{settings.user.email}}
+
+
+
+ - <% if (!delonI18n) { %>个人资料<% } %><% if (delonI18n) { %>{{ 'profile' | translate }}<% } %>
+ - <% if (!delonI18n) { %>设置<% } %><% if (delonI18n) { %>{{ 'settings' | translate }}<% } %>
+ - <% if (!delonI18n) { %>登出<% } %><% if (delonI18n) { %>{{ 'logout' | translate }}<% } %>
+
+
+
+
diff --git a/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.spec.ts b/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.spec.ts
new file mode 100644
index 0000000000..1afa67e38f
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed, TestModuleMetadata } from '@angular/core/testing';
+import { setUpTestBed } from '@testing/common.spec';
+
+import { SidebarComponent } from './sidebar.component';
+
+describe('Layout: Sidebar', () => {
+ setUpTestBed({
+ declarations: [ SidebarComponent ]
+ });
+
+ it('should create an instance', () => {
+ const fixture = TestBed.createComponent(SidebarComponent);
+ const comp = fixture.debugElement.componentInstance;
+ expect(comp).toBeTruthy();
+ });
+});
diff --git a/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.ts b/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.ts
new file mode 100644
index 0000000000..92182e99c2
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/default/sidebar/sidebar.component.ts
@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+import { NzMessageService } from 'ng-zorro-antd';
+import { SettingsService } from '@delon/theme';
+
+@Component({
+ selector : 'app-sidebar',
+ templateUrl: './sidebar.component.html'
+})
+export class SidebarComponent {
+ constructor(public settings: SettingsService, public msgSrv: NzMessageService) {
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/fullscreen/fullscreen.component.html b/src/core/cli/application/other-files/layout/fullscreen/fullscreen.component.html
new file mode 100644
index 0000000000..0680b43f9c
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/fullscreen/fullscreen.component.html
@@ -0,0 +1 @@
+
diff --git a/src/core/cli/application/other-files/layout/fullscreen/fullscreen.component.ts b/src/core/cli/application/other-files/layout/fullscreen/fullscreen.component.ts
new file mode 100644
index 0000000000..0da593bd1c
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/fullscreen/fullscreen.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'layout-fullscreen',
+ templateUrl: './fullscreen.component.html'
+})
+export class LayoutFullScreenComponent {
+
+}
diff --git a/src/core/cli/application/other-files/layout/layout.module.ts b/src/core/cli/application/other-files/layout/layout.module.ts
new file mode 100644
index 0000000000..ae5da1f272
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/layout.module.ts
@@ -0,0 +1,56 @@
+import { NgModule } from '@angular/core';
+import { SharedModule } from '@shared/shared.module';
+
+import { LayoutDefaultComponent } from './default/default.component';
+import { LayoutFullScreenComponent } from './fullscreen/fullscreen.component';
+import { HeaderComponent } from './default/header/header.component';
+import { SidebarComponent } from './default/sidebar/sidebar.component';
+import { HeaderSearchComponent } from './default/header/components/search.component';
+import { HeaderThemeComponent } from './default/header/components/theme.component';
+import { HeaderNotifyComponent } from './default/header/components/notify.component';
+import { HeaderTaskComponent } from './default/header/components/task.component';
+import { HeaderIconComponent } from './default/header/components/icon.component';
+import { HeaderFullScreenComponent } from './default/header/components/fullscreen.component';<% if (delonI18n) { %>
+import { HeaderLangsComponent } from './default/header/components/langs.component';<% } %>
+import { HeaderStorageComponent } from './default/header/components/storage.component';
+import { HeaderUserComponent } from './default/header/components/user.component';
+
+const COMPONENTS = [
+ LayoutDefaultComponent,
+ LayoutFullScreenComponent,
+ HeaderComponent,
+ SidebarComponent
+];
+
+const HEADERCOMPONENTS = [
+ HeaderSearchComponent,
+ HeaderNotifyComponent,
+ HeaderTaskComponent,
+ HeaderIconComponent,
+ HeaderFullScreenComponent,
+ HeaderThemeComponent,<% if (delonI18n) { %>
+ HeaderLangsComponent,<% } %>
+ HeaderStorageComponent,
+ HeaderUserComponent
+];
+
+// passport
+import { LayoutPassportComponent } from './passport/passport.component';
+const PASSPORT = [
+ LayoutPassportComponent
+];
+
+@NgModule({
+ imports: [SharedModule],
+ providers: [],
+ declarations: [
+ ...COMPONENTS,
+ ...HEADERCOMPONENTS,
+ ...PASSPORT
+ ],
+ exports: [
+ ...COMPONENTS,
+ ...PASSPORT
+ ]
+})
+export class LayoutModule { }
diff --git a/src/core/cli/application/other-files/layout/passport/passport.component.html b/src/core/cli/application/other-files/layout/passport/passport.component.html
new file mode 100644
index 0000000000..187cf13d15
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/passport/passport.component.html
@@ -0,0 +1,17 @@
+
+
+
+
武林中最有影响力的《葵花宝典》;欲练神功,挥刀自宫
+
+
+
+
+ Copyright 2017 卡色出品
+
+
+
diff --git a/src/core/cli/application/other-files/layout/passport/passport.component.less b/src/core/cli/application/other-files/layout/passport/passport.component.less
new file mode 100644
index 0000000000..b3dc2f6b24
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/passport/passport.component.less
@@ -0,0 +1,58 @@
+@import '~@delon/theme/styles/antd/themes/default.less';
+
+:host {
+ ::ng-deep {
+
+ .container {
+ background: #f0f2f5;
+ background-image: url("https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg");
+ width: 100%;
+ min-height: 100%;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: 100%;
+ padding: 110px 0 144px;
+ position: relative;
+ }
+
+ .top {
+ text-align: center;
+ }
+
+ .head {
+ height: 44px;
+ line-height: 44px;
+ a {
+ text-decoration: none;
+ }
+ }
+
+ .logo {
+ height: 44px;
+ vertical-align: top;
+ margin-right: 16px;
+ }
+
+ .title {
+ font-size: 33px;
+ color: @heading-color;
+ font-family: "Myriad Pro", "Helvetica Neue", Arial, Helvetica, sans-serif;
+ font-weight: 600;
+ position: relative;
+ top: 2px;
+ }
+
+ .desc {
+ font-size: @font-size-base;
+ color: @text-color-secondary;
+ margin-top: 12px;
+ margin-bottom: 40px;
+ }
+
+ .footer {
+ position: absolute;
+ width: 100%;
+ bottom: 0;
+ }
+ }
+}
diff --git a/src/core/cli/application/other-files/layout/passport/passport.component.ts b/src/core/cli/application/other-files/layout/passport/passport.component.ts
new file mode 100644
index 0000000000..f16be06723
--- /dev/null
+++ b/src/core/cli/application/other-files/layout/passport/passport.component.ts
@@ -0,0 +1,23 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'layout-passport',
+ templateUrl: './passport.component.html',
+ styleUrls: ['./passport.component.less']
+})
+export class LayoutPassportComponent {
+ links = [
+ {
+ title: '帮助',
+ href: ''
+ },
+ {
+ title: '隐私',
+ href: ''
+ },
+ {
+ title: '条款',
+ href: ''
+ }
+ ];
+}
diff --git a/tools/gulp/tasks/build.ts b/tools/gulp/tasks/build.ts
index e0db949255..7054c85ea3 100644
--- a/tools/gulp/tasks/build.ts
+++ b/tools/gulp/tasks/build.ts
@@ -74,9 +74,11 @@ function copySources() {
function cliResources() {
// others
+
src([
- `node_modules/@schematics/angular/utility/**`
- ], { base: 'node_modules/@schematics/angular/' }).pipe(dest('./src/core/cli'));
+ 'utility', 'class', 'directive', 'enum', 'interface', 'pipe', 'service'
+ ].map(v => `node_modules/@schematics/angular/${v}/**`),
+ { base: 'node_modules/@schematics/angular/' }).pipe(dest('./src/core/cli'));
// .vscode
src([
`${paths.scaffold}.vscode/**`
@@ -113,25 +115,19 @@ function cliResources() {
], { base: paths.scaffoldSrc }).pipe(dest('./src/core/cli/application/files/__sourcedir__/'));
// app
src([
- `${paths.scaffoldApp}/layout/**`,
`${paths.scaffoldApp}/core/net/**`,
`${paths.scaffoldApp}/core/module-import-guard.ts`,
`${paths.scaffoldApp}/core/README.md`,
`${paths.scaffoldApp}/shared/README.md`,
`${paths.scaffoldApp}/routes/callback/**`,
`${paths.scaffoldApp}/routes/exception/**`,
- `${paths.scaffoldApp}/routes/passport/**`,
- `!${paths.scaffoldApp}/layout/layout.module.ts`,
- `!${paths.scaffoldApp}/layout/default/default.component.html`,
- `!${paths.scaffoldApp}/layout/default/header/components/langs.component.ts`,
- `!${paths.scaffoldApp}/layout/default/header/header.component.html`
+ `${paths.scaffoldApp}/routes/passport/**`
], { base: paths.scaffoldApp }).pipe(dest('./src/core/cli/application/other-files/'));
}
function cliI18n() {
// file wrap
src([
- `${paths.scaffoldApp}/layout/default/header/components/langs.component.ts`,
`${paths.scaffoldApp}/core/i18n/**`
], { base: paths.scaffoldApp })
.pipe(wrap('<%= "\\<% if (delonI18n) { %\\>" %><%= contents %><%= "\\<% } %\\>" %>'))