Skip to content

Commit 65b8d63

Browse files
committed
Updates loading states on home sections
1 parent fb1f067 commit 65b8d63

File tree

4 files changed

+62
-11
lines changed

4 files changed

+62
-11
lines changed

src/webviews/apps/plus/home/components/active-work.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { stateContext } from '../../../home/context';
1111
import { ipcContext } from '../../../shared/context';
1212
import type { HostIpc } from '../../../shared/ipc';
1313
import { linkStyles } from '../../shared/components/vscode.css';
14+
import { branchCardStyles, createCommandLink } from './branch-section';
1415
import type { Overview, OverviewState } from './overviewState';
1516
import { overviewStateContext } from './overviewState';
1617
import '../../../shared/components/button';
@@ -31,7 +32,6 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
3132
static override styles = [
3233
linkStyles,
3334
branchCardStyles,
34-
headingLoaderStyles,
3535
css`
3636
[hidden] {
3737
display: none;
@@ -91,7 +91,7 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
9191
private renderLoader() {
9292
return html`
9393
<gl-section>
94-
<skeleton-loader slot="heading" class="heading-loader" lines="1"></skeleton-loader>
94+
<skeleton-loader slot="heading" lines="1"></skeleton-loader>
9595
<skeleton-loader lines="3"></skeleton-loader>
9696
</gl-section>
9797
`;
@@ -110,7 +110,7 @@ export class GlActiveWork extends SignalWatcher(LitElement) {
110110
if (!activeBranches) return html`<span>None</span>`;
111111

112112
return html`
113-
<gl-section>
113+
<gl-section ?loading=${isFetching}>
114114
<span slot="heading">${this.renderRepositoryIcon(repo.provider)} ${repo.name}</span>
115115
<span slot="heading-actions"
116116
><gl-button

src/webviews/apps/plus/home/components/branch-section.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { GetOverviewBranch, OpenInGraphParams } from '../../../../home/prot
77
import { srOnlyStyles } from '../../../shared/components/styles/lit/a11y.css';
88
import { linkStyles } from '../../shared/components/vscode.css';
99
import '../../../shared/components/code-icon';
10+
import '../../../shared/components/progress';
1011
import '../../../shared/components/avatar/avatar';
1112
import '../../../shared/components/avatar/avatar-list';
1213
import '../../../shared/components/card/card';
@@ -26,26 +27,50 @@ export class GlSection extends LitElement {
2627
.section {
2728
margin-bottom: 1.2rem;
2829
}
29-
.section__heading {
30+
.section__header {
31+
position: relative;
3032
display: flex;
3133
justify-content: space-between;
3234
gap: 8px;
3335
margin-block: 0 0.8rem;
36+
}
37+
.section__heading {
38+
flex: 1;
3439
font-size: 1.3rem;
3540
}
3641
.section__headline {
3742
font-weight: normal;
3843
text-transform: uppercase;
3944
}
45+
46+
.section__actions {
47+
margin-inline-start: auto;
48+
}
49+
50+
.section__loader {
51+
position: absolute;
52+
left: 0;
53+
bottom: 0;
54+
}
4055
`,
4156
];
4257

58+
@property({ type: Boolean })
59+
loading = false;
60+
61+
@property({ attribute: 'heading-level' })
62+
headingLevel: ARIAMixin['ariaLevel'] = '3';
63+
4364
override render() {
4465
return html`
4566
<div class="section">
46-
<h3 class="section__heading section__heading--actions">
47-
<slot name="heading" class="section__headline"></slot><slot name="heading-actions"></slot>
48-
</h3>
67+
<header class="section__header">
68+
<div class="section__heading" role="heading" aria-level=${this.headingLevel}>
69+
<slot name="heading" class="section__headline"></slot>
70+
</div>
71+
<slot name="heading-actions" class="section__actions"></slot>
72+
<progress-indicator class="section__loader" ?active="${this.loading}"></progress-indicator>
73+
</header>
4974
<slot></slot>
5075
</div>
5176
`;
@@ -69,7 +94,7 @@ export class GlBranchSection extends LitElement {
6994

7095
override render() {
7196
return html`
72-
<gl-section>
97+
<gl-section ?loading=${this.isFetching}>
7398
<span slot="heading">${this.renderSectionLabel()}</span>
7499
<span slot="heading-actions"><slot name="heading-actions"></slot></span>
75100
${when(

src/webviews/apps/plus/home/components/overview.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class GlOverview extends SignalWatcher(LitElement) {
6565
private renderLoader() {
6666
return html`
6767
<gl-section>
68-
<skeleton-loader slot="heading" class="heading-loader" lines="1"></skeleton-loader>
68+
<skeleton-loader slot="heading" lines="1"></skeleton-loader>
6969
<skeleton-loader lines="3"></skeleton-loader>
7070
</gl-section>
7171
`;

src/webviews/apps/shared/components/signal-utils.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { signal } from '@lit-labs/signals';
22
import { AsyncComputed } from 'signal-utils/async-computed';
3+
import type { Deferrable } from '../../../../system/function';
4+
import { debounce } from '../../../../system/function';
35

46
export const renderAsyncComputed = <T, R = unknown>(
57
v: AsyncComputed<T>,
@@ -28,11 +30,12 @@ export const renderAsyncComputed = <T, R = unknown>(
2830
};
2931

3032
export class AsyncComputedState<T, R = unknown> {
33+
private _debounce = 500;
3134
private _invalidate = signal(0);
3235
private _computed?: AsyncComputed<T>;
3336
private _state = signal<T | undefined>(undefined);
3437
get state() {
35-
this.computed.run();
38+
this._run();
3639
return this._state.get();
3740
}
3841

@@ -60,21 +63,44 @@ export class AsyncComputedState<T, R = unknown> {
6063
options?: {
6164
autoRun?: boolean;
6265
initial?: T;
66+
debounce?: number;
6367
},
6468
) {
6569
if (options != null) {
6670
this._state.set(options.initial);
6771

72+
if (options.debounce != null) {
73+
this._debounce = options.debounce;
74+
}
75+
6876
if (options.autoRun === true) {
6977
this.run();
7078
}
7179
}
7280
}
81+
private _runCore() {
82+
this.computed.run();
83+
}
84+
85+
private _runDebounced: Deferrable<() => void> | undefined;
86+
protected _run(immediate = false) {
87+
if (immediate) {
88+
this._runCore();
89+
return;
90+
}
91+
92+
if (this._runDebounced == null) {
93+
this._runDebounced = debounce(this._runCore.bind(this), this._debounce);
94+
}
95+
96+
this._runDebounced();
97+
}
7398
run(force = false) {
7499
if (force) {
75100
this.invalidate();
76101
}
77-
this.computed.run();
102+
103+
this._run();
78104
}
79105

80106
invalidate() {

0 commit comments

Comments
 (0)