• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / d9ae709b-3c27-4b69-b125-b8b80b54f90b

pending completion
d9ae709b-3c27-4b69-b125-b8b80b54f90b

Pull #2757

circleci

mengshuicmq
fix: fix code review
Pull Request #2757: feat(color-picker): color-picker support disabled (#INFR-8645)

98 of 6315 branches covered (1.55%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2392 of 13661 relevant lines covered (17.51%)

83.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.21
/src/layout/sidebar.component.ts
1
import { NgClass, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
2
import {
3
    Component,
4
    ElementRef,
5
    EventEmitter,
6
    Host,
7
    HostBinding,
8
    HostListener,
9
    Input,
10
    OnDestroy,
11
    OnInit,
12
    Optional,
1✔
13
    Output,
1✔
14
    TemplateRef
15
} from '@angular/core';
16
import { ThyHotkeyDispatcher } from '@tethys/cdk/hotkey';
17
import { isMacPlatform } from '@tethys/cdk/is';
18
import { InputBoolean, InputNumber } from 'ngx-tethys/core';
19
import { ThyIconComponent } from 'ngx-tethys/icon';
1✔
20
import { ThyResizableDirective, ThyResizeEvent, ThyResizeHandleComponent } from 'ngx-tethys/resizable';
21
import { ThyTooltipDirective } from 'ngx-tethys/tooltip';
×
22
import { coerceBooleanProperty } from 'ngx-tethys/util';
×
23
import { Subscription } from 'rxjs';
24
import { ThyLayoutComponent } from './layout.component';
25

×
26
const LG_WIDTH = 300;
27
const SIDEBAR_DEFAULT_WIDTH = 240;
28

29
export type ThySidebarTheme = 'white' | 'light' | 'dark';
×
30

31
/**
32
 * 布局侧边栏组件
×
33
 * @name thy-sidebar
34
 * @order 20
35
 */
×
36
@Component({
×
37
    selector: 'thy-sidebar',
38
    preserveWhitespaces: false,
×
39
    template: `
40
        <ng-content></ng-content>
41
        <div
×
42
            thyResizable
43
            class="sidebar-drag"
44
            *ngIf="thyDraggable"
×
45
            thyBounds="window"
46
            [thyMaxWidth]="thyDragMaxWidth"
47
            [thyMinWidth]="thyCollapsedWidth"
×
48
            (thyResize)="resizeHandler($event)"
49
            (thyResizeStart)="resizeStart()"
50
            (thyResizeEnd)="resizeEnd()"
×
51
            [style.display]="!isResizable ? 'contents' : null">
52
            <thy-resize-handle
53
                *ngIf="!thyCollapsed"
×
54
                [thyDirection]="directionRight ? 'left' : 'right'"
×
55
                class="sidebar-resize-handle"
×
56
                thyLine="true"
57
                (mouseenter)="toggleResizable($event, 'enter')"
58
                (mouseleave)="toggleResizable($event, 'leave')"
×
59
                (dblclick)="restoreToDefaultWidth()">
60
            </thy-resize-handle>
61
        </div>
62
        <div *ngIf="thyCollapsible" class="sidebar-collapse-line"></div>
×
63
        <div
64
            *ngIf="thyCollapsible && thyTrigger !== null"
65
            class="sidebar-collapse"
×
66
            [ngClass]="{ 'collapse-visible': collapseVisible, 'collapse-hidden': collapseHidden }"
67
            (click)="toggleCollapse($event)"
68
            [thyTooltip]="!thyTrigger && collapseTip">
×
69
            <ng-template [ngTemplateOutlet]="thyTrigger || defaultTrigger"></ng-template>
70
            <ng-template #defaultTrigger>
71
                <thy-icon class="sidebar-collapse-icon" [thyIconName]="this.thyCollapsed ? 'indent' : 'outdent'"></thy-icon>
×
72
            </ng-template>
×
73
        </div>
74
    `,
×
75
    standalone: true,
×
76
    imports: [
77
        NgTemplateOutlet,
78
        NgIf,
79
        ThyResizeHandleComponent,
×
80
        ThyResizableDirective,
81
        ThyIconComponent,
82
        ThyTooltipDirective,
×
83
        NgClass,
84
        NgStyle
85
    ]
×
86
})
×
87
export class ThySidebarComponent implements OnInit, OnDestroy {
×
88
    @HostBinding('class.thy-layout-sidebar') thyLayoutSidebarClass = true;
×
89

×
90
    @HostBinding('class.thy-layout-sidebar--clear-border-right') thyLayoutSidebarClearBorderRightClass = false;
×
91

×
92
    @HostBinding('class.thy-layout-sidebar--clear-border-left') thyLayoutSidebarClearBorderLeftClass = false;
×
93

×
94
    @HostBinding('class.sidebar-theme-light') sidebarThemeLight = false;
×
95

×
96
    @HostBinding('class.sidebar-theme-dark') sidebarThemeDark = false;
×
97

×
98
    @HostBinding('class.thy-layout-sidebar-right') directionRight = false;
×
99

×
100
    thyLayoutSidebarWidth: number;
×
101

×
102
    @HostBinding('style.width.px') get sidebarWidth() {
103
        if (this.thyCollapsible && this.thyCollapsed) {
104
            return this.thyCollapsedWidth;
×
105
        } else {
×
106
            return this.thyLayoutSidebarWidth;
107
        }
×
108
    }
×
109

110
    @HostBinding('class.thy-layout-sidebar-isolated') sidebarIsolated = false;
×
111

112
    @HostListener('mouseenter', ['$event'])
113
    mouseenter($event: MouseEvent) {
×
114
        this.resizeHandleHover($event, 'enter');
×
115
    }
116

117
    @HostListener('mouseleave', ['$event'])
118
    mouseleave($event: MouseEvent) {
×
119
        this.resizeHandleHover($event, 'leave');
×
120
    }
121

122
    /**
×
123
     * 宽度,默认是 240px,传入 `lg` 大小时宽度是300px
×
124
     * @default 240px
125
     */
×
126
    @Input('thyWidth')
×
127
    set thyWidth(value: any) {
128
        if (value === 'lg') {
×
129
            value = LG_WIDTH;
×
130
        }
×
131
        this.thyLayoutSidebarWidth = value || SIDEBAR_DEFAULT_WIDTH;
×
132
    }
×
133

×
134
    /**
×
135
     * sidebar位置,默认在左侧
136
     * @default 'left'
×
137
     */
×
138
    @Input('thyDirection')
139
    set thyDirection(value: 'left' | 'right') {
140
        this.directionRight = value === 'right' ? true : false;
×
141
    }
×
142

×
143
    /**
144
     * 右侧是否有边框
145
     * @default true
×
146
     */
×
147
    @Input('thyHasBorderRight')
148
    set thyHasBorderRight(value: string) {
149
        this.thyLayoutSidebarClearBorderRightClass = !coerceBooleanProperty(value);
×
150
    }
151

152
    /**
×
153
     * 左侧是否有边框
×
154
     * @default true
×
155
     */
156
    @Input('thyHasBorderLeft')
157
    set thyHasBorderLeft(value: string) {
×
158
        this.thyLayoutSidebarClearBorderLeftClass = !coerceBooleanProperty(value);
159
    }
160

×
161
    /**
×
162
     * 是否和右侧 /左侧隔离,当为 true 时距右侧 /左侧会有 margin,同时边框会去掉
163
     * @default false
×
164
     */
×
165
    @Input('thyIsolated')
166
    set thyIsolated(value: string) {
167
        this.sidebarIsolated = coerceBooleanProperty(value);
×
168
    }
169

1✔
170
    /**
171
     * 宽度是否可以拖拽
172
     * @default false
173
     */
174
    @Input() @InputBoolean() thyDraggable: boolean = false;
1✔
175

176
    /**
177
     * 拖拽的最大宽度
178
     */
179
    @Input() @InputNumber() thyDragMaxWidth: number;
180

181
    /**
182
     * 展示收起的触发器自定义模板,默认显示展开收起的圆形图标,设置为 null 表示不展示触发元素,手动控制展开收起状态
183
     * @type null | undefined | TemplateRef<any>
184
     * @default undefined
185
     */
186
    @Input() thyTrigger: null | undefined | TemplateRef<any> = undefined;
187

188
    /**
189
     * 收起状态改变后的事件
190
     */
191
    @Output()
192
    thyCollapsedChange = new EventEmitter<boolean>();
193

194
    /**
195
     * 拖拽宽度的修改事件
196
     */
197
    @Output()
198
    thyDragWidthChange = new EventEmitter<number>();
199

200
    /**
201
     * 开启收起/展开功能
202
     * @default false
203
     */
204
    @Input() @InputBoolean() set thyCollapsible(collapsible: boolean) {
1✔
205
        this.collapsible = collapsible;
206
        if (this.collapsible) {
207
            this.subscribeHotkeyEvent();
208
        } else {
1✔
209
            this.hotkeySubscription?.unsubscribe();
210
        }
211
    }
212

1✔
213
    get thyCollapsible() {
214
        return this.collapsible;
215
    }
216

217
    /**
1✔
218
     * 是否是收起
219
     * @default false
220
     */
221
    @Input() @InputBoolean() set thyCollapsed(value: boolean) {
222
        this.isCollapsed = value;
1✔
223
    }
224

225
    get thyCollapsed() {
226
        return this.isCollapsed;
1✔
227
    }
228

229
    /**
230
     * 收起后的宽度
231
     */
232
    @Input() @InputNumber() thyCollapsedWidth = 20;
233

234
    /**
235
     * 主题
236
     * @type white | light | dark
237
     * @default white
238
     */
239
    @Input()
240
    set thyTheme(value: ThySidebarTheme) {
241
        if (value === 'light') {
242
            this.sidebarThemeLight = true;
243
        } else if (value === 'dark') {
244
            this.sidebarThemeDark = true;
245
        }
246
    }
247

248
    /**
249
     * 默认宽度,双击后可恢复到此宽度,默认是 240px,传入 lg 大小时宽度是300px
250
     */
251
    @Input() thyDefaultWidth: string | number;
252

253
    @HostBinding('class.sidebar-collapse-show')
254
    get collapseVisibility() {
255
        return this.thyCollapsed;
256
    }
257

258
    @HostBinding('class.remove-transition')
259
    get removeTransition() {
260
        return this.isRemoveTransition;
261
    }
262

263
    collapseTip: string;
264

265
    collapsible: boolean;
266

267
    isCollapsed = false;
268

269
    originWidth: number = SIDEBAR_DEFAULT_WIDTH;
270

271
    collapseVisible: boolean;
272

273
    collapseHidden: boolean;
274

275
    isRemoveTransition: boolean;
276

277
    isResizable: boolean;
278

279
    private hotkeySubscription: Subscription;
280

281
    constructor(
282
        @Optional() @Host() private thyLayoutComponent: ThyLayoutComponent,
283
        public elementRef: ElementRef,
284
        private hotkeyDispatcher: ThyHotkeyDispatcher
285
    ) {}
286

287
    ngOnInit() {
288
        if (this.thyLayoutComponent) {
289
            this.thyLayoutComponent.hasSidebar = true;
290
        }
291
        if (this.directionRight) {
292
            this.thyLayoutComponent.isSidebarRight = true;
293
        }
294
        this.updateCollapseTip();
295
    }
296

297
    private subscribeHotkeyEvent() {
298
        this.hotkeySubscription = this.hotkeyDispatcher.keydown(['Control+/', 'Meta+/']).subscribe(() => {
299
            this.toggleCollapse();
300
        });
301
    }
302

303
    private updateCollapseTip() {
304
        this.collapseTip = this.thyCollapsed ? '展开' : '收起';
305
        this.collapseTip = this.collapseTip + (isMacPlatform() ? `(⌘ + /)` : `(Ctrl + /)`);
306
    }
307

308
    resizeHandler({ width }: ThyResizeEvent) {
309
        if (width === this.thyLayoutSidebarWidth) {
310
            return;
311
        }
312
        if (this.thyCollapsible && width < this.thyCollapsedWidth) {
313
            return;
314
        }
315
        if (this.thyCollapsible && width === this.thyCollapsedWidth) {
316
            this.thyCollapsed = true;
317
            setTimeout(() => this.updateCollapseTip(), 200);
318
            this.thyCollapsedChange.emit(this.isCollapsed);
319
            this.thyLayoutSidebarWidth = this.originWidth;
320
            this.collapseVisible = false;
321
            return;
322
        }
323
        this.thyLayoutSidebarWidth = width;
324
        this.thyDragWidthChange.emit(width);
325
    }
326

327
    resizeStart() {
328
        this.originWidth = this.thyLayoutSidebarWidth;
329
        this.collapseHidden = true;
330
        this.isRemoveTransition = true;
331
    }
332

333
    resizeEnd() {
334
        this.collapseHidden = false;
335
        this.isRemoveTransition = false;
336
    }
337

338
    resizeHandleHover(event: MouseEvent, type: 'enter' | 'leave') {
339
        this.collapseVisible = type === 'enter' && !this.thyCollapsed ? true : false;
340
    }
341

342
    toggleCollapse(event?: MouseEvent) {
343
        this.thyCollapsed = !this.thyCollapsed;
344
        setTimeout(() => this.updateCollapseTip(), 200);
345
        this.thyCollapsedChange.emit(this.isCollapsed);
346
    }
347

348
    public toggleResizable(event: MouseEvent, type: 'enter' | 'leave') {
349
        this.isResizable = type === 'enter' ? true : false;
350
    }
351

352
    restoreToDefaultWidth() {
353
        if (this.thyDefaultWidth === 'lg') {
354
            this.thyDefaultWidth = LG_WIDTH;
355
        }
356
        this.thyLayoutSidebarWidth = (this.thyDefaultWidth as number) || SIDEBAR_DEFAULT_WIDTH;
357
        this.thyDragWidthChange.emit(this.thyLayoutSidebarWidth);
358
    }
359

360
    ngOnDestroy(): void {
361
        this.hotkeySubscription?.unsubscribe();
362
    }
363
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc