Skip to content

Commit 3f4dfca

Browse files
committed
Adds home preview banner
1 parent 47019fc commit 3f4dfca

File tree

9 files changed

+213
-33
lines changed

9 files changed

+213
-33
lines changed

src/webviews/apps/home/components/home-nav.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { consume } from '@lit/context';
22
import { css, html, LitElement } from 'lit';
33
import { customElement, state } from 'lit/decorators.js';
4-
import { getApplicablePromo } from '../../../../plus/gk/account/promos';
54
import type { State } from '../../../home/protocol';
65
import { linkBase } from '../../shared/components/styles/lit/base.css';
76
import { stateContext } from '../context';
87
import { homeBaseStyles, inlineNavStyles } from '../home.css';
98
import '../../shared/components/code-icon';
109
import '../../shared/components/overlays/tooltip';
11-
import '../../shared/components/promo';
1210

1311
@customElement('gl-home-nav')
1412
export class GlHomeNav extends LitElement {
@@ -29,12 +27,6 @@ export class GlHomeNav extends LitElement {
2927

3028
override render() {
3129
return html`
32-
<gl-promo
33-
.promo=${getApplicablePromo(this._state.subscription.state, 'home')}
34-
class="promo-banner promo-banner--eyebrow"
35-
id="promo"
36-
type="link"
37-
></gl-promo>
3830
<nav class="inline-nav" id="links" aria-label="Help and Resources">
3931
<div class="inline-nav__group">
4032
<gl-tooltip hoist>

src/webviews/apps/home/components/integration-banner.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { consume } from '@lit/context';
2-
import { html, LitElement, nothing } from 'lit';
2+
import { css, html, LitElement, nothing } from 'lit';
33
import { customElement, query, state } from 'lit/decorators.js';
44
import type { State } from '../../../home/protocol';
55
import { CollapseSectionCommand } from '../../../home/protocol';
@@ -20,6 +20,14 @@ export class GlIntegrationBanner extends LitElement {
2020
delegatesFocus: true,
2121
};
2222

23+
static override styles = [
24+
css`
25+
gl-card::part(base) {
26+
margin-block-end: 1.2rem;
27+
}
28+
`,
29+
];
30+
2331
@consume<State>({ context: stateContext, subscribe: true })
2432
@state()
2533
private _state!: State;
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { consume } from '@lit/context';
2+
import { css, html, LitElement, nothing } from 'lit';
3+
import { customElement, query, state } from 'lit/decorators.js';
4+
import type { State } from '../../../home/protocol';
5+
import { CollapseSectionCommand, TogglePreviewEnabledCommand } from '../../../home/protocol';
6+
import { focusOutline } from '../../shared/components/styles/lit/a11y.css';
7+
import { linkBase } from '../../shared/components/styles/lit/base.css';
8+
import { ipcContext } from '../../shared/context';
9+
import type { HostIpc } from '../../shared/ipc';
10+
import { stateContext } from '../context';
11+
import '../../shared/components/button-container';
12+
import '../../shared/components/overlays/tooltip';
13+
14+
export const previewBannerTagName = 'gl-preview-banner';
15+
16+
@customElement(previewBannerTagName)
17+
export class GlPreviewBanner extends LitElement {
18+
static override shadowRootOptions: ShadowRootInit = {
19+
...LitElement.shadowRootOptions,
20+
delegatesFocus: true,
21+
};
22+
23+
static override styles = [
24+
linkBase,
25+
css`
26+
.text-button,
27+
.feedback {
28+
padding: 0.4rem 0.8rem;
29+
}
30+
31+
.text-button {
32+
appearance: none;
33+
background: none;
34+
border: none;
35+
color: inherit;
36+
text-align: end;
37+
cursor: pointer;
38+
width: 100%;
39+
}
40+
.text-button:hover,
41+
.text-button:focus-within {
42+
background-color: var(--gl-card-background);
43+
}
44+
.text-button:focus-visible {
45+
${focusOutline}
46+
}
47+
48+
gl-card::part(base) {
49+
margin-block-end: 1.2rem;
50+
}
51+
`,
52+
];
53+
54+
@consume<State>({ context: stateContext, subscribe: true })
55+
@state()
56+
private _state!: State;
57+
58+
@consume<HostIpc>({ context: ipcContext, subscribe: true })
59+
@state()
60+
private _ipc!: HostIpc;
61+
62+
@state()
63+
private closed = false;
64+
65+
@query('button')
66+
private _button!: HTMLButtonElement;
67+
68+
override render() {
69+
if (this._state.previewEnabled === true) {
70+
return html`
71+
<gl-card>
72+
<p><strong>Welcome to the new Home View!</strong></p>
73+
<p>
74+
We're reinventing GitLens' Home to be a more helpful daily workflow tool. We'll continue to
75+
refine this view and welcome your
76+
<a href="https://github.com/gitkraken/vscode-gitlens/discussions/3721">feedback</a>.
77+
</p>
78+
<button-container>
79+
<gl-button appearance="secondary" @click=${() => this.togglePreview()} full
80+
><code-icon icon="arrow-left"></code-icon> Revert to Old Home View</gl-button
81+
>
82+
</button-container>
83+
<gl-button
84+
slot="actions"
85+
appearance="toolbar"
86+
tooltip="Dismiss Welcome"
87+
@click=${() => this.onClose()}
88+
><code-icon icon="close"></code-icon
89+
></gl-button>
90+
</gl-card>
91+
`;
92+
}
93+
94+
if (this.closed || this._state.previewCollapsed === true) {
95+
return nothing;
96+
}
97+
98+
return html`
99+
<gl-tooltip placement="bottom">
100+
<button class="text-button text-button--end" @click=${() => this.togglePreview()}>
101+
New Home View <code-icon icon="arrow-right"></code-icon>
102+
</button>
103+
<p slot="content">
104+
<strong>Switch to the new Home View!</strong><br />
105+
We're reinventing GitLens' Home to be a more helpful daily workflow tool. We'll continue to refine
106+
this view and welcome your feedback.
107+
</p>
108+
</gl-tooltip>
109+
`;
110+
}
111+
112+
private togglePreview() {
113+
this._ipc.sendCommand(TogglePreviewEnabledCommand);
114+
}
115+
116+
private onClose() {
117+
this.closed = true;
118+
119+
this._ipc.sendCommand(CollapseSectionCommand, {
120+
section: 'newHomePreview',
121+
collapsed: true,
122+
});
123+
}
124+
125+
override focus() {
126+
this._button?.focus();
127+
}
128+
}
129+
130+
declare global {
131+
interface HTMLElementTagNameMap {
132+
[previewBannerTagName]: GlPreviewBanner;
133+
}
134+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { consume } from '@lit/context';
2+
import { css, html, LitElement, nothing } from 'lit';
3+
import { customElement, state } from 'lit/decorators.js';
4+
import { getApplicablePromo } from '../../../../plus/gk/account/promos';
5+
import type { State } from '../../../home/protocol';
6+
import { stateContext } from '../context';
7+
import '../../shared/components/promo';
8+
9+
@customElement('gl-promo-banner')
10+
export class GlPromoBanner extends LitElement {
11+
static override styles = [
12+
css`
13+
:host {
14+
display: block;
15+
}
16+
.promo-banner {
17+
text-align: center;
18+
margin-bottom: 1rem;
19+
}
20+
.promo-banner--eyebrow {
21+
color: var(--color-foreground--50);
22+
margin-bottom: 0.2rem;
23+
}
24+
.promo-banner:not([has-promo]) {
25+
display: none;
26+
}
27+
`,
28+
];
29+
30+
@consume<State>({ context: stateContext, subscribe: true })
31+
@state()
32+
private _state!: State;
33+
34+
override render() {
35+
const promo = getApplicablePromo(this._state.subscription.state, 'home');
36+
if (!promo) {
37+
return nothing;
38+
}
39+
40+
return html`
41+
<gl-promo .promo=${promo} class="promo-banner promo-banner--eyebrow" id="promo" type="link"></gl-promo>
42+
`;
43+
}
44+
}

src/webviews/apps/home/home.css.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ export const homeStyles = css`
5555
.home__main > *:last-child {
5656
margin-bottom: 0;
5757
}
58-
.home__nav {
59-
flex: none;
60-
}
58+
.home__aux,
6159
.home__footer {
6260
flex: none;
6361
}
@@ -133,18 +131,6 @@ export const inlineNavStyles = css`
133131
margin-left: 0.2rem;
134132
}
135133
}
136-
137-
.promo-banner {
138-
text-align: center;
139-
margin-bottom: 1rem;
140-
}
141-
.promo-banner--eyebrow {
142-
color: var(--color-foreground--50);
143-
margin-bottom: 0.2rem;
144-
}
145-
.promo-banner:not([has-promo]) {
146-
display: none;
147-
}
148134
`;
149135

150136
export const buttonStyles = css`

src/webviews/apps/home/home.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import './components/feature-nav';
2222
import './components/home-nav';
2323
import './components/integration-banner';
2424
import './components/onboarding';
25+
import './components/preview-banner';
26+
import './components/promo-banner';
2527
import './components/repo-alerts';
2628

2729
@customElement('gl-home-app')
@@ -66,13 +68,23 @@ export class GlHomeApp extends GlApp<State> {
6668
override render() {
6769
return html`
6870
<div class="home scrollable">
69-
<gl-home-nav class="home__nav"></gl-home-nav>
71+
<aside class="home__aux">
72+
<gl-promo-banner></gl-promo-banner>
73+
${when(
74+
!this.state.previewEnabled,
75+
() => html`
76+
<gl-preview-banner></gl-preview-banner>
77+
<gl-home-nav></gl-home-nav>
78+
`,
79+
)}
80+
</aside>
7081
<gl-repo-alerts class="home__header"></gl-repo-alerts>
7182
<main class="home__main scrollable" id="main">
7283
<gl-onboarding></gl-onboarding>
7384
${when(
7485
this.state?.previewEnabled === true,
7586
() => html`
87+
<gl-preview-banner></gl-preview-banner>
7688
<gl-integration-banner></gl-integration-banner>
7789
<gl-active-work></gl-active-work>
7890
<gl-launchpad></gl-launchpad>

src/webviews/apps/shared/components/card/card.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ export class GlCard extends LitElement {
2121

2222
override render() {
2323
if (this.href != null) {
24-
return html`<a class="card${this.active ? ' is-active' : ''}" href=${this.href}
24+
return html`<a part="base" class="card${this.active ? ' is-active' : ''}" href=${this.href}
2525
>${this.renderContent()}</a
2626
>`;
2727
}
2828

29-
return html`<div class="card${this.active ? ' is-active' : ''}">${this.renderContent()}</div>`;
29+
return html`<div part="base" class="card${this.active ? ' is-active' : ''}">${this.renderContent()}</div>`;
3030
}
3131

3232
private renderContent() {

src/webviews/home/homeWebview.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
GetOverview,
5656
GetOverviewFilterState,
5757
SetOverviewFilter,
58+
TogglePreviewEnabledCommand,
5859
} from './protocol';
5960
import type { HomeWebviewShowingArgs } from './registration';
6061

@@ -235,6 +236,9 @@ export class HomeWebviewProvider implements WebviewProvider<State, State, HomeWe
235236
await this.onChooseRepository();
236237
void this.host.respond(ChangeOverviewRepository, e, undefined);
237238
break;
239+
case TogglePreviewEnabledCommand.is(e):
240+
configuration.updateEffective('home.preview.enabled', !this.getPreviewEnabled());
241+
break;
238242
}
239243
}
240244

@@ -256,8 +260,6 @@ export class HomeWebviewProvider implements WebviewProvider<State, State, HomeWe
256260
}
257261

258262
private onCollapseSection(params: CollapseSectionParams) {
259-
void this.container.storage.delete('home:walkthrough:dismissed');
260-
261263
const collapsed = this.container.storage.get('home:sections:collapsed');
262264
if (collapsed == null) {
263265
if (params.collapsed === true) {
@@ -293,8 +295,8 @@ export class HomeWebviewProvider implements WebviewProvider<State, State, HomeWe
293295
return Boolean(this.container.storage.get('home:walkthrough:dismissed'));
294296
}
295297

296-
private getWalkthroughCollapsed() {
297-
return this.container.storage.get('home:sections:collapsed')?.includes('walkthrough') ?? false;
298+
private getPreviewCollapsed() {
299+
return this.container.storage.get('home:sections:collapsed')?.includes('newHomePreview') ?? false;
298300
}
299301

300302
private getIntegrationBannerCollapsed() {
@@ -328,7 +330,7 @@ export class HomeWebviewProvider implements WebviewProvider<State, State, HomeWe
328330
avatar: subResult.avatar,
329331
organizationsCount: subResult.organizationsCount,
330332
orgSettings: this.getOrgSettings(),
331-
walkthroughCollapsed: this.getWalkthroughCollapsed(),
333+
previewCollapsed: this.getPreviewCollapsed(),
332334
integrationBannerCollapsed: this.getIntegrationBannerCollapsed(),
333335
hasAnyIntegrationConnected: this.isAnyIntegrationConnected(),
334336
walkthroughProgress: {

src/webviews/home/protocol.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface State extends WebviewState {
1313
orgSettings: {
1414
drafts: boolean;
1515
};
16-
walkthroughCollapsed: boolean;
16+
previewCollapsed: boolean;
1717
integrationBannerCollapsed: boolean;
1818
hasAnyIntegrationConnected: boolean;
1919
avatar?: string;
@@ -126,6 +126,8 @@ export const ChangeOverviewRepository = new IpcRequest<undefined, undefined>(sco
126126

127127
// COMMANDS
128128

129+
export const TogglePreviewEnabledCommand = new IpcCommand<void>(scope, 'previewEnabled/toggle');
130+
129131
export interface CollapseSectionParams {
130132
section: string;
131133
collapsed: boolean;

0 commit comments

Comments
 (0)