Skip to content

Commit 3ebf9c3

Browse files
committed
adds banner support on the home view
1 parent be6ef59 commit 3ebf9c3

File tree

8 files changed

+176
-4
lines changed

8 files changed

+176
-4
lines changed

src/storage.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ export interface GlobalStorage {
142142
status: {
143143
pinned?: boolean;
144144
};
145+
banners: {
146+
dismissed?: string[];
147+
};
145148
};
146149
pendingWelcomeOnFocus?: boolean;
147150
pendingWhatsNewOnFocus?: boolean;

src/webviews/apps/home/home.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,32 @@
8383
.gl-plus-banner {
8484
background-image: url(#{webroot}/media/gitlens-backdrop-opacity.webp);
8585
}
86+
.vscode-high-contrast .ribbon-banner,
87+
.vscode-dark .ribbon-banner {
88+
background-image: url(#{webroot}/media/cyber-week-banner-dark.webp);
89+
}
90+
.vscode-high-contrast-light .ribbon-banner,
91+
.vscode-light .ribbon-banner {
92+
background-image: url(#{webroot}/media/cyber-week-banner-light.webp);
93+
}
8694
</style>
95+
<div class="ribbon-banner-container" data-banner="cyberweek2022" hidden>
96+
<a href="#" class="ribbon-banner">
97+
<h2>
98+
<strong>50% off</strong>
99+
<span class="ribbon-banner__subtext">GitLens Pro &amp; all GitKraken products!</span>
100+
</h2>
101+
<p>Expires Dec 5, 2022 11:59pm PT</p>
102+
</a>
103+
<a
104+
href="#"
105+
class="ribbon-banner-dismiss"
106+
data-banner-dismiss="cyberweek2022"
107+
title="Dismiss"
108+
aria-label="Dismiss"
109+
><code-icon icon="close"></code-icon
110+
></a>
111+
</div>
87112
<div class="stepped-sections">
88113
<stepped-section id="welcome">
89114
<span slot="heading">Welcome to GitLens 13</span>

src/webviews/apps/home/home.scss

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
visibility: hidden;
3535
}
3636

37+
[hidden] {
38+
display: none !important;
39+
}
40+
3741
html {
3842
height: 100%;
3943
font-size: 62.5%;
@@ -605,6 +609,81 @@ vscode-button {
605609
}
606610
}
607611

612+
.ribbon-banner {
613+
&-container {
614+
position: relative;
615+
}
616+
617+
&-dismiss {
618+
position: absolute;
619+
top: 0;
620+
right: 0;
621+
622+
display: inline-flex;
623+
justify-content: center;
624+
align-items: center;
625+
width: 2.2rem;
626+
height: 2.2rem;
627+
color: var(--color-foreground--75);
628+
&:hover {
629+
color: var(--color-foreground--75);
630+
text-decoration: none;
631+
}
632+
}
633+
634+
.vscode-high-contrast &,
635+
.vscode-dark & {
636+
background-color: var(--color-background--lighten-10);
637+
background-position: right -7rem center;
638+
background-size: auto 140px;
639+
}
640+
.vscode-high-contrast-light &,
641+
.vscode-light & {
642+
background-color: var(--color-background--darken-10);
643+
background-position: right 2.5rem center;
644+
background-size: auto 28px;
645+
}
646+
647+
background-repeat: no-repeat;
648+
display: block;
649+
text-align: left;
650+
color: inherit;
651+
padding: 1.2rem 9.3rem 1.2rem 1.4rem;
652+
line-height: 1.1;
653+
margin-top: -2rem;
654+
margin-bottom: 1rem;
655+
border-radius: 0.4rem;
656+
mix-blend-mode: luminosity;
657+
opacity: 0.8;
658+
transition: opacity ease 250ms, mix-blend-mode ease 250ms;
659+
660+
&:focus,
661+
&:hover {
662+
color: inherit;
663+
text-decoration: none;
664+
mix-blend-mode: normal;
665+
opacity: 1;
666+
}
667+
668+
h2 {
669+
font-size: 1.2rem;
670+
font-weight: inherit;
671+
margin: 0 0 0.8rem 0;
672+
}
673+
p {
674+
font-size: 1rem;
675+
margin: 0;
676+
opacity: 0.8;
677+
}
678+
strong {
679+
font-weight: 800;
680+
opacity: 1;
681+
}
682+
&__subtext {
683+
opacity: 0.8;
684+
}
685+
}
686+
608687
@media (max-width: 280px) {
609688
.not-small {
610689
display: none;

src/webviews/apps/home/home.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
DidChangeExtensionEnabledType,
1111
DidChangeLayoutType,
1212
DidChangeSubscriptionNotificationType,
13+
DismissBannerCommandType,
1314
DismissSectionCommandType,
1415
DismissStatusCommandType,
1516
} from '../../home/protocol';
@@ -72,6 +73,9 @@ export class HomeApp extends App<State> {
7273
this.onStatusDismissed(e, target),
7374
),
7475
);
76+
disposables.push(
77+
DOM.on('[data-banner-dismiss]', 'click', (e, target: HTMLElement) => this.onBannerDismissed(e, target)),
78+
);
7579

7680
return disposables;
7781
}
@@ -143,6 +147,17 @@ export class HomeApp extends App<State> {
143147
this.updateHeader();
144148
}
145149

150+
private onBannerDismissed(_e: MouseEvent, target: HTMLElement) {
151+
const key = target.getAttribute('data-banner-dismiss');
152+
if (key == null || this.state.dismissedBanners?.includes(key)) {
153+
return;
154+
}
155+
this.state.dismissedBanners = this.state.dismissedBanners ?? [];
156+
this.state.dismissedBanners.push(key);
157+
this.sendCommand(DismissBannerCommandType, { id: key });
158+
this.updateBanners();
159+
}
160+
146161
private onDataActionClicked(_e: MouseEvent, target: HTMLElement) {
147162
const action = target.dataset.action;
148163
this.onActionClickedCore(action);
@@ -209,6 +224,28 @@ export class HomeApp extends App<State> {
209224
}
210225
}
211226

227+
private updateBanners() {
228+
const $banners = [...document.querySelectorAll('[data-banner]')];
229+
if (!$banners.length) {
230+
return;
231+
}
232+
233+
const { subscription, dismissedBanners } = this.state;
234+
const isPaid = subscription.state === SubscriptionState.Paid;
235+
$banners.forEach($el => {
236+
const key = $el.getAttribute('data-banner');
237+
if (
238+
isPaid ||
239+
(key !== null && dismissedBanners?.includes(key)) ||
240+
(key === 'cyberweek2022' && !showCyberWeek())
241+
) {
242+
$el.setAttribute('hidden', 'true');
243+
} else {
244+
$el.removeAttribute('hidden');
245+
}
246+
});
247+
}
248+
212249
private updateNoRepo() {
213250
const { extensionEnabled } = this.state;
214251

@@ -305,6 +342,7 @@ export class HomeApp extends App<State> {
305342
this.updateSteps(forceShowPlus);
306343

307344
this.updateSections();
345+
this.updateBanners();
308346
}
309347
}
310348

@@ -319,4 +357,9 @@ function toggleArrayItem(list: string[] = [], item: string, add = true) {
319357
return list;
320358
}
321359

360+
const cyberweekEnding = Date.parse('2022-12-06T00:00:00.000-08:00');
361+
function showCyberWeek() {
362+
return Date.now() < cyberweekEnding;
363+
}
364+
322365
new HomeApp();
129 KB
Loading
2.91 KB
Loading

src/webviews/home/homeWebviewView.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ import { debounce } from '../../system/function';
1717
import type { IpcMessage } from '../protocol';
1818
import { onIpc } from '../protocol';
1919
import { WebviewViewBase } from '../webviewViewBase';
20-
import type { CompleteStepParams, DismissSectionParams, State } from './protocol';
20+
import type { CompleteStepParams, DismissBannerParams, DismissSectionParams, State } from './protocol';
2121
import {
2222
CompletedActions,
2323
CompleteStepCommandType,
2424
DidChangeConfigurationType,
2525
DidChangeExtensionEnabledType,
2626
DidChangeLayoutType,
2727
DidChangeSubscriptionNotificationType,
28+
DismissBannerCommandType,
2829
DismissSectionCommandType,
2930
DismissStatusCommandType,
3031
} from './protocol';
@@ -136,6 +137,9 @@ export class HomeWebviewView extends WebviewViewBase<State> {
136137
case DismissStatusCommandType.method:
137138
onIpc(DismissStatusCommandType, e, _params => this.dismissPinStatus());
138139
break;
140+
case DismissBannerCommandType.method:
141+
onIpc(DismissBannerCommandType, e, params => this.dismissBanner(params));
142+
break;
139143
}
140144
}
141145

@@ -153,14 +157,24 @@ export class HomeWebviewView extends WebviewViewBase<State> {
153157

154158
private dismissSection(params: DismissSectionParams) {
155159
const sections = this.container.storage.get('home:sections:dismissed', []);
156-
157-
if (!sections.includes(params.id)) {
158-
sections.push(params.id);
160+
if (sections.includes(params.id)) {
161+
return;
159162
}
160163

164+
sections.push(params.id);
161165
void this.container.storage.store('home:sections:dismissed', sections);
162166
}
163167

168+
private dismissBanner(params: DismissBannerParams) {
169+
const banners = this.container.storage.get('home:banners:dismissed', []);
170+
171+
if (!banners.includes(params.id)) {
172+
banners.push(params.id);
173+
}
174+
175+
void this.container.storage.store('home:banners:dismissed', banners);
176+
}
177+
164178
private dismissPinStatus() {
165179
void this.container.storage.store('home:status:pinned', false);
166180
}
@@ -209,6 +223,7 @@ export class HomeWebviewView extends WebviewViewBase<State> {
209223
const subscriptionState = await this.getSubscription(subscription);
210224
const steps = this.container.storage.get('home:steps:completed', []);
211225
const sections = this.container.storage.get('home:sections:dismissed', []);
226+
const dismissedBanners = this.container.storage.get('home:banners:dismissed', []);
212227

213228
return {
214229
extensionEnabled: this.getExtensionEnabled(),
@@ -222,6 +237,7 @@ export class HomeWebviewView extends WebviewViewBase<State> {
222237
avatar: subscriptionState.avatar,
223238
layout: this.getLayout(),
224239
pinStatus: this.getPinStatus(),
240+
dismissedBanners: dismissedBanners,
225241
};
226242
}
227243

src/webviews/home/protocol.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface State {
1414
subscription: Subscription;
1515
completedActions: CompletedActions[];
1616
completedSteps?: string[];
17+
dismissedBanners?: string[];
1718
dismissedSections?: string[];
1819
plusEnabled: boolean;
1920
visibility: RepositoriesVisibility;
@@ -35,6 +36,11 @@ export const DismissSectionCommandType = new IpcCommandType<DismissSectionParams
3536

3637
export const DismissStatusCommandType = new IpcCommandType<undefined>('home/status/dismiss');
3738

39+
export interface DismissBannerParams {
40+
id: string;
41+
}
42+
export const DismissBannerCommandType = new IpcCommandType<DismissBannerParams>('home/banner/dismiss');
43+
3844
export interface DidChangeSubscriptionParams {
3945
subscription: Subscription;
4046
completedActions: CompletedActions[];

0 commit comments

Comments
 (0)