From 8b4bae88bb97f5b38e57b38dce23d4f90c12ef44 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Mon, 1 Dec 2025 18:46:20 +0100 Subject: [PATCH 01/21] Adds welcome page webview for first-time installs (#4769, #4773, PLG-138) --- contributions.json | 5 ++ docs/telemetry-events.md | 39 +++++++++ package.json | 10 +++ src/constants.commands.generated.ts | 1 + src/constants.views.ts | 2 +- src/container.ts | 4 + src/extension.ts | 6 ++ src/webviews/apps/welcome/context.ts | 4 + src/webviews/apps/welcome/stateProvider.ts | 16 ++++ src/webviews/apps/welcome/welcome.html | 26 ++++++ src/webviews/apps/welcome/welcome.scss | 1 + src/webviews/apps/welcome/welcome.ts | 95 ++++++++++++++++++++++ src/webviews/welcome/protocol.ts | 7 ++ src/webviews/welcome/registration.ts | 34 ++++++++ src/webviews/welcome/welcomeWebview.ts | 41 ++++++++++ webpack.config.mjs | 1 + 16 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/webviews/apps/welcome/context.ts create mode 100644 src/webviews/apps/welcome/stateProvider.ts create mode 100644 src/webviews/apps/welcome/welcome.html create mode 100644 src/webviews/apps/welcome/welcome.scss create mode 100644 src/webviews/apps/welcome/welcome.ts create mode 100644 src/webviews/welcome/protocol.ts create mode 100644 src/webviews/welcome/registration.ts create mode 100644 src/webviews/welcome/welcomeWebview.ts diff --git a/contributions.json b/contributions.json index ef7198fb0acb0..ccfb636a4f6d6 100644 --- a/contributions.json +++ b/contributions.json @@ -5767,6 +5767,11 @@ "label": "Show Visual File History View", "commandPalette": "gitlens:enabled" }, + "gitlens.showWelcomePage": { + "label": "Show Welcome", + "icon": "$(heart)", + "commandPalette": "gitlens:enabled" + }, "gitlens.showWorkspacesView": { "label": "Show Cloud Workspaces View", "commandPalette": "gitlens:enabled && !gitlens:hasVirtualFolders" diff --git a/docs/telemetry-events.md b/docs/telemetry-events.md index 55a4ad5aadb41..3b0e7b84b3e53 100644 --- a/docs/telemetry-events.md +++ b/docs/telemetry-events.md @@ -3597,3 +3597,42 @@ or } ``` +### welcome/closed + +```typescript +{ + [`context.${string}`]: string | number | boolean, + 'context.webview.host': 'view' | 'editor', + 'context.webview.id': string, + 'context.webview.instanceId': string, + 'context.webview.type': string +} +``` + +### welcome/showAborted + +```typescript +{ + 'context.webview.host': 'view' | 'editor', + 'context.webview.id': string, + 'context.webview.instanceId': string, + 'context.webview.type': string, + 'duration': number, + 'loading': boolean +} +``` + +### welcome/shown + +```typescript +{ + [`context.${string}`]: string | number | boolean, + 'context.webview.host': 'view' | 'editor', + 'context.webview.id': string, + 'context.webview.instanceId': string, + 'context.webview.type': string, + 'duration': number, + 'loading': boolean +} +``` + diff --git a/package.json b/package.json index 6d859f44b92cc..8f63b4c9b6cac 100644 --- a/package.json +++ b/package.json @@ -8425,6 +8425,12 @@ "title": "Show Visual File History View", "category": "GitLens" }, + { + "command": "gitlens.showWelcomePage", + "title": "Show Welcome", + "category": "GitLens", + "icon": "$(heart)" + }, { "command": "gitlens.showWorkspacesView", "title": "Show Cloud Workspaces View", @@ -13301,6 +13307,10 @@ "command": "gitlens.showTimelineView", "when": "gitlens:enabled" }, + { + "command": "gitlens.showWelcomePage", + "when": "gitlens:enabled" + }, { "command": "gitlens.showWorkspacesView", "when": "gitlens:enabled && !gitlens:hasVirtualFolders" diff --git a/src/constants.commands.generated.ts b/src/constants.commands.generated.ts index 8b5bbdaba1ac5..636128bf4a907 100644 --- a/src/constants.commands.generated.ts +++ b/src/constants.commands.generated.ts @@ -1010,6 +1010,7 @@ export type ContributedPaletteCommands = | 'gitlens.showTagsView' | 'gitlens.showTimelinePage' | 'gitlens.showTimelineView' + | 'gitlens.showWelcomePage' | 'gitlens.showWorkspacesView' | 'gitlens.showWorktreesView' | 'gitlens.startWork' diff --git a/src/constants.views.ts b/src/constants.views.ts index cac195cb613e7..eb050b733fa8f 100644 --- a/src/constants.views.ts +++ b/src/constants.views.ts @@ -43,7 +43,7 @@ export type GroupableTreeViewTypes = Extract< >; export type GroupableTreeViewIds = TreeViewIds; -export type WebviewTypes = 'composer' | 'graph' | 'patchDetails' | 'settings' | 'timeline'; +export type WebviewTypes = 'composer' | 'graph' | 'patchDetails' | 'settings' | 'timeline' | 'welcome'; export type WebviewIds = `gitlens.${WebviewTypes}`; export type WebviewViewTypes = 'commitDetails' | 'graph' | 'graphDetails' | 'home' | 'patchDetails' | 'timeline'; diff --git a/src/container.ts b/src/container.ts index 42b2d8d4fd452..65b98d25121a0 100644 --- a/src/container.ts +++ b/src/container.ts @@ -79,6 +79,7 @@ import { RebaseEditorProvider } from './webviews/rebase/rebaseEditor'; import { registerSettingsWebviewCommands, registerSettingsWebviewPanel } from './webviews/settings/registration'; import { WebviewCommandRegistrar } from './webviews/webviewCommandRegistrar'; import { WebviewsController } from './webviews/webviewsController'; +import { registerWelcomeWebviewPanel } from './webviews/welcome/registration'; export type Environment = 'dev' | 'staging' | 'production'; @@ -261,6 +262,9 @@ export class Container { this._disposables.push(settingsPanels); this._disposables.push(registerSettingsWebviewCommands(settingsPanels)); + const welcomePanels = registerWelcomeWebviewPanel(webviews); + this._disposables.push(welcomePanels); + this._disposables.push(new ViewFileDecorationProvider()); const patchDetailsPanels = registerPatchDetailsWebviewPanel(webviews); diff --git a/src/extension.ts b/src/extension.ts index be844d156207a..e92c14013b265 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -366,6 +366,12 @@ async function showWhatsNew( if (previousVersion == null) { Logger.log(`GitLens first-time install; window.focused=${window.state.focused}`); + // Show welcome webview on first install for IDEs that don't support walkthroughs (e.g., Cursor) + // For IDEs that support walkthroughs, the walkthrough will be shown instead + if (window.state.focused && !container.walkthrough.isWalkthroughSupported) { + void executeCommand('gitlens.showWelcomePage'); + } + return; } diff --git a/src/webviews/apps/welcome/context.ts b/src/webviews/apps/welcome/context.ts new file mode 100644 index 0000000000000..23e34c3ce6190 --- /dev/null +++ b/src/webviews/apps/welcome/context.ts @@ -0,0 +1,4 @@ +import { createContext } from '@lit/context'; +import type { State } from '../../welcome/protocol'; + +export const stateContext = createContext('state'); diff --git a/src/webviews/apps/welcome/stateProvider.ts b/src/webviews/apps/welcome/stateProvider.ts new file mode 100644 index 0000000000000..d75615aff6433 --- /dev/null +++ b/src/webviews/apps/welcome/stateProvider.ts @@ -0,0 +1,16 @@ +import { ContextProvider } from '@lit/context'; +import type { IpcMessage } from '../../protocol'; +import type { State } from '../../welcome/protocol'; +import type { ReactiveElementHost } from '../shared/appHost'; +import { StateProviderBase } from '../shared/stateProviderBase'; +import { stateContext } from './context'; + +export class WelcomeStateProvider extends StateProviderBase { + protected override createContextProvider(state: State): ContextProvider { + return new ContextProvider(this.host, { context: stateContext, initialValue: state }); + } + + protected override onMessageReceived(_msg: IpcMessage): void { + // Welcome webview doesn't need to handle any messages + } +} diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html new file mode 100644 index 0000000000000..b72c8c2f8c41f --- /dev/null +++ b/src/webviews/apps/welcome/welcome.html @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/src/webviews/apps/welcome/welcome.scss b/src/webviews/apps/welcome/welcome.scss new file mode 100644 index 0000000000000..fbfa976037705 --- /dev/null +++ b/src/webviews/apps/welcome/welcome.scss @@ -0,0 +1 @@ +@use '../shared/styles/theme'; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts new file mode 100644 index 0000000000000..9ffe5c3032db4 --- /dev/null +++ b/src/webviews/apps/welcome/welcome.ts @@ -0,0 +1,95 @@ +/*global*/ +import './welcome.scss'; +import { html } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import type { State } from '../../welcome/protocol'; +import { GlAppHost } from '../shared/appHost'; +import { scrollableBase } from '../shared/components/styles/lit/base.css'; +import type { LoggerContext } from '../shared/contexts/logger'; +import type { HostIpc } from '../shared/ipc'; +import { WelcomeStateProvider } from './stateProvider'; +import '../shared/components/gitlens-logo'; + +@customElement('gl-welcome-app') +export class GlWelcomeApp extends GlAppHost { + static override styles = [scrollableBase]; + + protected override createStateProvider( + bootstrap: string, + ipc: HostIpc, + logger: LoggerContext, + ): WelcomeStateProvider { + return new WelcomeStateProvider(this, bootstrap, ipc, logger); + } + + override render(): unknown { + return html` +
+
+

+

Supercharge Git in Cursor with GitLens

+
+ +
+

🚀 Getting Started

+

+ GitLens is now installed and ready to help you visualize code authorship, navigate Git history, + and collaborate more effectively. +

+
+ +
+

✨ Key Features

+
    +
  • + 📝 + Blame Annotations - See who changed each line and when +
  • +
  • + 📊 + Commit Graph - Visualize your repository's history +
  • +
  • + 🔍 + File History - Track changes to any file over time +
  • +
  • + 🌿 + Branch Management - Easily manage branches and remotes +
  • +
  • + 🤖 + AI Features - Generate commit messages and explanations +
  • +
+
+ +
+

🎯 Next Steps

+
    +
  • + 1. + Open the GitLens Home view in the sidebar to see your active work +
  • +
  • + 2. + Try the Commit Graph to visualize your repository +
  • +
  • + 3. + Hover over any line to see inline blame information +
  • +
  • + 4. + Explore the Command Palette (Cmd/Ctrl+Shift+P) and search for "GitLens" +
  • +
+
+ +
+

GitLens ${this.state?.version ?? ''} is ready to use!

+
+
+ `; + } +} diff --git a/src/webviews/welcome/protocol.ts b/src/webviews/welcome/protocol.ts new file mode 100644 index 0000000000000..da42f89197426 --- /dev/null +++ b/src/webviews/welcome/protocol.ts @@ -0,0 +1,7 @@ +import type { IpcScope, WebviewState } from '../protocol'; + +export const scope: IpcScope = 'welcome'; + +export interface State extends WebviewState<'gitlens.welcome'> { + version: string; +} diff --git a/src/webviews/welcome/registration.ts b/src/webviews/welcome/registration.ts new file mode 100644 index 0000000000000..20fe4c5466c9a --- /dev/null +++ b/src/webviews/welcome/registration.ts @@ -0,0 +1,34 @@ +import { ViewColumn } from 'vscode'; +import type { WebviewPanelsProxy, WebviewsController } from '../webviewsController'; +import type { State } from './protocol'; + +export type WelcomeWebviewShowingArgs = []; + +export function registerWelcomeWebviewPanel( + controller: WebviewsController, +): WebviewPanelsProxy<'gitlens.welcome', WelcomeWebviewShowingArgs, State> { + return controller.registerWebviewPanel<'gitlens.welcome', State, State, WelcomeWebviewShowingArgs>( + { id: 'gitlens.showWelcomePage' }, + { + id: 'gitlens.welcome', + fileName: 'welcome.html', + iconPath: 'images/gitlens-icon.png', + title: 'Welcome to GitLens', + contextKeyPrefix: `gitlens:webview:welcome`, + trackingFeature: 'welcomeWebview', + type: 'welcome', + plusFeature: false, + column: ViewColumn.Active, + webviewHostOptions: { + retainContextWhenHidden: false, + enableFindWidget: false, + }, + }, + async (container, host) => { + const { WelcomeWebviewProvider } = await import( + /* webpackChunkName: "webview-welcome" */ './welcomeWebview' + ); + return new WelcomeWebviewProvider(container, host); + }, + ); +} diff --git a/src/webviews/welcome/welcomeWebview.ts b/src/webviews/welcome/welcomeWebview.ts new file mode 100644 index 0000000000000..c193519455f29 --- /dev/null +++ b/src/webviews/welcome/welcomeWebview.ts @@ -0,0 +1,41 @@ +import { Disposable } from 'vscode'; +import type { WebviewTelemetryContext } from '../../constants.telemetry'; +import type { Container } from '../../container'; +import type { WebviewHost, WebviewProvider } from '../webviewProvider'; +import type { State } from './protocol'; +import type { WelcomeWebviewShowingArgs } from './registration'; + +export class WelcomeWebviewProvider implements WebviewProvider { + private readonly _disposable: Disposable; + + constructor( + private readonly container: Container, + private readonly host: WebviewHost<'gitlens.welcome'>, + ) { + this.host.title = 'Welcome to GitLens'; + this._disposable = Disposable.from(); + } + + dispose(): void { + this._disposable.dispose(); + } + + getTelemetryContext(): WebviewTelemetryContext { + return { + ...this.host.getTelemetryContext(), + }; + } + + includeBootstrap(): State { + return this.getState(); + } + + private getState(): State { + return { + webviewId: 'gitlens.welcome', + webviewInstanceId: this.host.instanceId, + timestamp: Date.now(), + version: this.container.version, + }; + } +} diff --git a/webpack.config.mjs b/webpack.config.mjs index 7074299e6939e..29900f9e3ce8e 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -390,6 +390,7 @@ function getWebviewsConfigs(mode, env) { settings: { entry: './settings/settings.ts' }, timeline: { entry: './plus/timeline/timeline.ts', plus: true }, patchDetails: { entry: './plus/patchDetails/patchDetails.ts', plus: true }, + welcome: { entry: './welcome/welcome.ts' }, }; if (env.webviews) { From 11de6151b17120f38e84373ca3cde39f1773abda Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Tue, 2 Dec 2025 18:20:28 +0100 Subject: [PATCH 02/21] Layout of the header of the welcome page (#4769, #4773, PLG-138) --- src/webviews/apps/welcome/welcome.css.ts | 51 ++++++++++++++++++++++++ src/webviews/apps/welcome/welcome.ts | 20 +++++----- 2 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 src/webviews/apps/welcome/welcome.css.ts diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts new file mode 100644 index 0000000000000..45bac9ab2a681 --- /dev/null +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -0,0 +1,51 @@ +import { css } from 'lit'; + +export const welcomeStyles = css` + .welcome::before { + content: ' '; + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%) translateY(-40%); + z-index: -1; + + width: 620px; + height: 517px; + max-width: 100%; + + border-radius: 100%; + background: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); + opacity: 0.25; + mix-blend-mode: color; + filter: blur(53px); + } + .welcome__section { + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; + text-align: center; + } + .welcome__section p { + font-size: larger; + max-width: calc(620px * 0.75); + } + + .welcome__header { + margin-top: 5rem; + margin-bottom: 2rem; + max-width: 620px; + margin-left: auto; + margin-right: auto; + } + .welcome__header gitlens-logo { + transform: translateX(-0.75rem); + } + .welcome__header h1 { + margin-bottom: 0; + } + + .welcome__accent { + color: #cb64ff; + } +`; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 9ffe5c3032db4..3175188ac80db 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -9,10 +9,11 @@ import type { LoggerContext } from '../shared/contexts/logger'; import type { HostIpc } from '../shared/ipc'; import { WelcomeStateProvider } from './stateProvider'; import '../shared/components/gitlens-logo'; +import { welcomeStyles } from './welcome.css'; @customElement('gl-welcome-app') export class GlWelcomeApp extends GlAppHost { - static override styles = [scrollableBase]; + static override styles = [scrollableBase, welcomeStyles]; protected override createStateProvider( bootstrap: string, @@ -25,18 +26,17 @@ export class GlWelcomeApp extends GlAppHost { override render(): unknown { return html`
-
-

-

Supercharge Git in Cursor with GitLens

-
- -
-

🚀 Getting Started

+
+ +

GitLens is now installed in Cursor

- GitLens is now installed and ready to help you visualize code authorship, navigate Git history, - and collaborate more effectively. + Understand every line of code — instantly. GitLens reveals authorship, activity, and history + inside the editor

+
+

With PRO subscription you get more

+

✨ Key Features

From 4598f70515004967bf5f9308d10a01592edb9e7a Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Thu, 4 Dec 2025 14:25:57 +0100 Subject: [PATCH 03/21] Add interactive features carousel to Welcome view (#4769, #4773, PLG-138) --- src/webviews/apps/media/feature-timeline.svg | 48 ++++++ .../welcome/components/feature-carousel.ts | 147 ++++++++++++++++++ src/webviews/apps/welcome/welcome.css.ts | 34 +++- src/webviews/apps/welcome/welcome.html | 7 +- src/webviews/apps/welcome/welcome.ts | 33 +++- 5 files changed, 256 insertions(+), 13 deletions(-) create mode 100644 src/webviews/apps/media/feature-timeline.svg create mode 100644 src/webviews/apps/welcome/components/feature-carousel.ts diff --git a/src/webviews/apps/media/feature-timeline.svg b/src/webviews/apps/media/feature-timeline.svg new file mode 100644 index 0000000000000..eca1dfba8500b --- /dev/null +++ b/src/webviews/apps/media/feature-timeline.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/webviews/apps/welcome/components/feature-carousel.ts b/src/webviews/apps/welcome/components/feature-carousel.ts new file mode 100644 index 0000000000000..3bb2cfd4a88ea --- /dev/null +++ b/src/webviews/apps/welcome/components/feature-carousel.ts @@ -0,0 +1,147 @@ +import { css, html, LitElement } from 'lit'; +import { customElement, queryAssignedElements, state } from 'lit/decorators.js'; +import '../../shared/components/button'; +import '../../shared/components/code-icon'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-feature-carousel': GlFeatureCarousel; + 'gl-feature-card': GlFeatureCard; + } +} + +@customElement('gl-feature-carousel') +export class GlFeatureCarousel extends LitElement { + static override styles = [ + css` + :host { + display: block; + width: 100%; + } + + .carousel { + display: flex; + gap: 1rem; + justify-content: center; + } + + .button { + display: flex; + align-items: center; + } + + .content { + flex: 1; + max-width: 520px; + display: flex; + align-items: center; + justify-content: center; + } + + + ::slotted(*) { + display: none; + } + + ::slotted([data-active]) { + display: flex; + width: 100%; + } + `, + ]; + + @queryAssignedElements({ flatten: true }) + private cards!: HTMLElement[]; + + @state() + private currentIndex = 0; + + override firstUpdated(): void { + this.updateActiveCard(); + } + + private updateActiveCard(): void { + this.cards.forEach((card, index) => { + if (index === this.currentIndex) { + card.setAttribute('data-active', ''); + } else { + card.removeAttribute('data-active'); + } + }); + } + + private handlePrevious(): void { + if (this.cards.length === 0) return; + this.currentIndex = (this.currentIndex - 1 + this.cards.length) % this.cards.length; + this.updateActiveCard(); + } + + private handleNext(): void { + if (this.cards.length === 0) return; + this.currentIndex = (this.currentIndex + 1) % this.cards.length; + this.updateActiveCard(); + } + + private handleSlotChange(): void { + this.currentIndex = 0; + this.updateActiveCard(); + } + + override render(): unknown { + return html` + + `; + } +} + +@customElement('gl-feature-card') +export class GlFeatureCard extends LitElement { + static override styles = [ + css` + :host { + display: flex; + } + + .image { + } + .content { + } + ::slotted(img) { + } + + ::slotted(h1) { + } + + ::slotted(p) { + } + `, + ]; + + override render(): unknown { + return html` +
+ +
+
+ +
+ `; + } +} diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 45bac9ab2a681..7a622ab92912c 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -1,6 +1,12 @@ import { css } from 'lit'; -export const welcomeStyles = css` +const colorScheme = css` + :host { + --accent-color: #cb64ff; + } +`; + +const heroGradient = css` .welcome::before { content: ' '; position: absolute; @@ -19,33 +25,45 @@ export const welcomeStyles = css` mix-blend-mode: color; filter: blur(53px); } - .welcome__section { +`; + +const section = css` + .section { display: flex; flex-flow: column; justify-content: center; align-items: center; text-align: center; } - .welcome__section p { + .section p { font-size: larger; max-width: calc(620px * 0.75); } +`; - .welcome__header { +const header = css` + .header { margin-top: 5rem; margin-bottom: 2rem; max-width: 620px; margin-left: auto; margin-right: auto; } - .welcome__header gitlens-logo { + .header gitlens-logo { transform: translateX(-0.75rem); } - .welcome__header h1 { + .header h1 { margin-bottom: 0; } +`; - .welcome__accent { - color: #cb64ff; +const typography = css` + .accent { + color: var(--accent-color); } `; + +export const welcomeStyles = css` + ${colorScheme} + ${heroGradient} ${section} ${header} ${typography} +`; diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html index b72c8c2f8c41f..4bca43a8dc78f 100644 --- a/src/webviews/apps/welcome/welcome.html +++ b/src/webviews/apps/welcome/welcome.html @@ -21,6 +21,11 @@ data-placement="#{placement}" data-vscode-context='{ "webview": "#{webviewId}", "webviewInstance": "#{webviewInstanceId}" }' > - + diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 3175188ac80db..09da0ee455dd5 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -1,7 +1,7 @@ /*global*/ import './welcome.scss'; import { html } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { customElement, property } from 'lit/decorators.js'; import type { State } from '../../welcome/protocol'; import { GlAppHost } from '../shared/appHost'; import { scrollableBase } from '../shared/components/styles/lit/base.css'; @@ -10,6 +10,7 @@ import type { HostIpc } from '../shared/ipc'; import { WelcomeStateProvider } from './stateProvider'; import '../shared/components/gitlens-logo'; import { welcomeStyles } from './welcome.css'; +import './components/feature-carousel'; @customElement('gl-welcome-app') export class GlWelcomeApp extends GlAppHost { @@ -23,10 +24,13 @@ export class GlWelcomeApp extends GlAppHost { return new WelcomeStateProvider(this, bootstrap, ipc, logger); } + @property({ type: String }) + webroot?: string; + override render(): unknown { return html`
-
+

GitLens is now installed in Cursor

@@ -34,8 +38,29 @@ export class GlWelcomeApp extends GlAppHost { inside the editor

-
-

With PRO subscription you get more

+
+

With PRO subscription you get more

+
+ +
+ + + Commit Graph +

Commit Graph

+

Visualize your repository's history and interact with commits

+

Open Commit Graph

+
+ + Visual File History +

Visual File History

+

Track changes to any file over time

+

Open Visual File History

+
+
From 237928ea02aec4760b6b741a0d12645022043426 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Thu, 4 Dec 2025 17:00:36 +0100 Subject: [PATCH 04/21] Makes header of the welcome page responsive to the panel width (#4769, #4773, PLG-138) --- src/webviews/apps/welcome/welcome.css.ts | 64 ++++++++++++++++++------ src/webviews/apps/welcome/welcome.ts | 2 +- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 7a622ab92912c..2c6314fc25d99 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -3,6 +3,22 @@ import { css } from 'lit'; const colorScheme = css` :host { --accent-color: #cb64ff; + + --hero-gradient: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); + } +`; + +const typography = css` + :host { + --h1-font-size: 1.4rem; + --p-font-size: 1rem; + } + + @media (max-width: 640px) { + :host { + --h1-font-size: 0.75rem; + --p-font-size: 0.7rem; + } } `; @@ -15,15 +31,20 @@ const heroGradient = css` transform: translateX(-50%) translateY(-40%); z-index: -1; + background: var(--hero-gradient); + border-radius: 100%; + opacity: 0.25; + filter: blur(53px); + width: 620px; height: 517px; max-width: 100%; + } - border-radius: 100%; - background: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); - opacity: 0.25; - mix-blend-mode: color; - filter: blur(53px); + @media (max-width: 640px) { + .welcome::before { + height: 273px; + } } `; @@ -34,17 +55,29 @@ const section = css` justify-content: center; align-items: center; text-align: center; + font-size: var(--p-font-size); } .section p { - font-size: larger; - max-width: calc(620px * 0.75); + max-width: 30em; + } + .section .accent { + color: var(--accent-color); } `; const header = css` + .logo { + transform: scale(0.7); + } + @media (max-width: 640px) { + .logo { + transform: scale(0.5); + } + } + .header { - margin-top: 5rem; - margin-bottom: 2rem; + margin-top: 3em; + margin-bottom: 1em; max-width: 620px; margin-left: auto; margin-right: auto; @@ -54,16 +87,15 @@ const header = css` } .header h1 { margin-bottom: 0; - } -`; -const typography = css` - .accent { - color: var(--accent-color); + font-size: var(--h1-font-size); + } + .header p { + color: var(--vscode-descriptionForeground); } `; export const welcomeStyles = css` - ${colorScheme} - ${heroGradient} ${section} ${header} ${typography} + ${colorScheme} ${typography} + ${heroGradient} ${section} ${header} `; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 09da0ee455dd5..4305d9c566670 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -31,7 +31,7 @@ export class GlWelcomeApp extends GlAppHost { return html`
- +

GitLens is now installed in Cursor

Understand every line of code — instantly. GitLens reveals authorship, activity, and history From d5f05052cf3b7a17cfcef9ab90ba6a1638d6ce59 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Thu, 4 Dec 2025 20:36:55 +0100 Subject: [PATCH 05/21] Refines features carousel styling. Updates carousel styles for better visual consistency, including layout improvements, typography, and theming with VSCode variables. Enhances maintainability and prepares for future feature image integration. (#4769, #4773, PLG-138) --- src/webviews/apps/media/feature-graph.svg | 11 +++++ .../welcome/components/feature-carousel.ts | 26 +++++++----- src/webviews/apps/welcome/welcome.css.ts | 40 ++++++++++++++++++- 3 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 src/webviews/apps/media/feature-graph.svg diff --git a/src/webviews/apps/media/feature-graph.svg b/src/webviews/apps/media/feature-graph.svg new file mode 100644 index 0000000000000..ab40260a2541a --- /dev/null +++ b/src/webviews/apps/media/feature-graph.svg @@ -0,0 +1,11 @@ + + + + + Commit Graph Placeholder + + + Replace with actual feature image + + + diff --git a/src/webviews/apps/welcome/components/feature-carousel.ts b/src/webviews/apps/welcome/components/feature-carousel.ts index 3bb2cfd4a88ea..76022695a664d 100644 --- a/src/webviews/apps/welcome/components/feature-carousel.ts +++ b/src/webviews/apps/welcome/components/feature-carousel.ts @@ -15,6 +15,10 @@ export class GlFeatureCarousel extends LitElement { static override styles = [ css` :host { + --gl-carousel-border-radius: 0; + --gl-carousel-background-color: transparent; + --gl-carousel-padding: 1rem; + display: block; width: 100%; } @@ -36,8 +40,11 @@ export class GlFeatureCarousel extends LitElement { display: flex; align-items: center; justify-content: center; - } + border-radius: var(--gl-carousel-border-radius); + background-color: var(--gl-carousel-background-color); + padding: var(--gl-carousel-padding); + } ::slotted(*) { display: none; @@ -117,19 +124,20 @@ export class GlFeatureCard extends LitElement { css` :host { display: flex; + gap: 1rem; } .image { - } - .content { - } - ::slotted(img) { - } - - ::slotted(h1) { + flex: 1 1 50%; + width: 50%; } - ::slotted(p) { + .content { + margin-top: 0.5rem; + flex: 1 0 50%; + display: flex; + flex-direction: column; + gap: 0.5rem; } `, ]; diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 2c6314fc25d99..3d008a75e30b8 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -3,6 +3,9 @@ import { css } from 'lit'; const colorScheme = css` :host { --accent-color: #cb64ff; + --text-color: var(--vscode-descriptionForeground); + --em-color: var(--vscode-editor-foreground); + --link-color: var(--vscode-textLink-foreground); --hero-gradient: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); } @@ -12,12 +15,14 @@ const typography = css` :host { --h1-font-size: 1.4rem; --p-font-size: 1rem; + --card-font-size: var(--vscode-font-size); } @media (max-width: 640px) { :host { --h1-font-size: 0.75rem; --p-font-size: 0.7rem; + --card-font-size: var(--vscode-editor-font-size); } } `; @@ -89,13 +94,46 @@ const header = css` margin-bottom: 0; font-size: var(--h1-font-size); + color: var(--em-text-color); } .header p { - color: var(--vscode-descriptionForeground); + color: var(--text-color); + } +`; + +const carousel = css` + gl-feature-carousel { + text-align: initial; + --gl-carousel-border-radius: 0.65rem; + --gl-carousel-background-color: var(--vscode-textBlockQuote-background); + } + + gl-feature-carousel h1 { + margin: 0; + font-size: var(--card-font-size); + color: var(--em-color); + } + + gl-feature-carousel p { + margin: 0.4em 0; + font-size: var(--card-font-size); + color: var(--text-color); + } + + gl-feature-carousel img { + max-width: 100%; + height: auto; + border-radius: 0.4rem; + } + + gl-feature-carousel a { + color: var(--link-color); + text-decoration: none; } `; export const welcomeStyles = css` ${colorScheme} ${typography} ${heroGradient} ${section} ${header} + ${carousel} `; From 7304c4ae56b8cb75292608878bc71f3da9e0dd9a Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Fri, 5 Dec 2025 15:32:01 +0100 Subject: [PATCH 06/21] Enhances welcome UI for better scaling and narrow view support Refines font sizing and spacing units from rem to em to improve consistency and responsiveness across devices. Updates carousel and feature card layouts for better display on small screens, including improved media queries and more flexible padding. Adjusts section and header styling to ensure readability and visual alignment, especially on mobile. (#4769, #4773, PLG-138) --- .../welcome/components/feature-carousel.ts | 30 ++++++++++-- src/webviews/apps/welcome/welcome.css.ts | 48 ++++++++++++++----- src/webviews/apps/welcome/welcome.ts | 4 +- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/webviews/apps/welcome/components/feature-carousel.ts b/src/webviews/apps/welcome/components/feature-carousel.ts index 76022695a664d..137fc93f2603f 100644 --- a/src/webviews/apps/welcome/components/feature-carousel.ts +++ b/src/webviews/apps/welcome/components/feature-carousel.ts @@ -17,7 +17,7 @@ export class GlFeatureCarousel extends LitElement { :host { --gl-carousel-border-radius: 0; --gl-carousel-background-color: transparent; - --gl-carousel-padding: 1rem; + --gl-carousel-padding: 1em; display: block; width: 100%; @@ -25,7 +25,7 @@ export class GlFeatureCarousel extends LitElement { .carousel { display: flex; - gap: 1rem; + gap: 1em; justify-content: center; } @@ -124,7 +124,7 @@ export class GlFeatureCard extends LitElement { css` :host { display: flex; - gap: 1rem; + gap: 1em; } .image { @@ -133,11 +133,31 @@ export class GlFeatureCard extends LitElement { } .content { - margin-top: 0.5rem; + margin-top: 0.5em; flex: 1 0 50%; display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.5em; + } + + @media (max-width: 640px) { + :host { + flex-direction: column; + } + + .image { + width: 100%; + } + + .content { + margin-top: 0; + margin-left: 0.3em; + margin-right: 0.3em; + } + + ::slotted(*) { + width: 100%; + } } `, ]; diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 3d008a75e30b8..2bc80a97eed8a 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -13,16 +13,25 @@ const colorScheme = css` const typography = css` :host { - --h1-font-size: 1.4rem; - --p-font-size: 1rem; - --card-font-size: var(--vscode-font-size); + font-size: var(--vscode-font-size); + + --h1-font-size: 1.7em; + --p-font-size: 1.23em; + --card-font-size: 1em; } @media (max-width: 640px) { :host { - --h1-font-size: 0.75rem; - --p-font-size: 0.7rem; - --card-font-size: var(--vscode-editor-font-size); + font-size: var(--vscode-editor-font-size); + --h1-font-size: 1em; + --p-font-size: 1em; + --card-font-size: 1em; + } + } + + @media (max-width: 300px) { + :host { + font-size: calc(var(--vscode-editor-font-size) * 0.8); } } `; @@ -60,14 +69,15 @@ const section = css` justify-content: center; align-items: center; text-align: center; - font-size: var(--p-font-size); - } - .section p { - max-width: 30em; } .section .accent { color: var(--accent-color); } + + .section.plain p { + max-width: 30em; + font-size: var(--p-font-size); + } `; const header = css` @@ -104,10 +114,23 @@ const header = css` const carousel = css` gl-feature-carousel { text-align: initial; - --gl-carousel-border-radius: 0.65rem; + --gl-carousel-border-radius: 0.63em; + --gl-carousel-padding: 1.8em; --gl-carousel-background-color: var(--vscode-textBlockQuote-background); } + @media (max-width: 640px) { + gl-feature-carousel { + --gl-carousel-padding: 1em; + } + } + + @media (max-width: 300px) { + gl-feature-carousel { + --gl-carousel-padding: 0.5em; + } + } + gl-feature-carousel h1 { margin: 0; font-size: var(--card-font-size); @@ -115,7 +138,7 @@ const carousel = css` } gl-feature-carousel p { - margin: 0.4em 0; + margin: 0.4em 0 0; font-size: var(--card-font-size); color: var(--text-color); } @@ -123,7 +146,6 @@ const carousel = css` gl-feature-carousel img { max-width: 100%; height: auto; - border-radius: 0.4rem; } gl-feature-carousel a { diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 4305d9c566670..3837645c84446 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -30,7 +30,7 @@ export class GlWelcomeApp extends GlAppHost { override render(): unknown { return html`

-
+

GitLens is now installed in Cursor

@@ -38,7 +38,7 @@ export class GlWelcomeApp extends GlAppHost { inside the editor

-
+

With PRO subscription you get more

From 86d0569a9f064742e9a107ea70897470e5cf3bec Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Fri, 5 Dec 2025 18:43:56 +0100 Subject: [PATCH 07/21] Separates feature card to a new file (#4769, #4773, PLG-138) --- .../apps/welcome/components/feature-card.ts | 66 +++++++++++++++++++ .../welcome/components/feature-carousel.ts | 57 ---------------- src/webviews/apps/welcome/welcome.ts | 1 + 3 files changed, 67 insertions(+), 57 deletions(-) create mode 100644 src/webviews/apps/welcome/components/feature-card.ts diff --git a/src/webviews/apps/welcome/components/feature-card.ts b/src/webviews/apps/welcome/components/feature-card.ts new file mode 100644 index 0000000000000..7d54dc8b65f8f --- /dev/null +++ b/src/webviews/apps/welcome/components/feature-card.ts @@ -0,0 +1,66 @@ +import { css, html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import '../../shared/components/button'; +import '../../shared/components/code-icon'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-feature-card': GlFeatureCard; + } +} + +@customElement('gl-feature-card') +export class GlFeatureCard extends LitElement { + static override styles = [ + css` + :host { + display: flex; + gap: 1em; + } + + .image { + flex: 1 1 50%; + width: 50%; + } + + .content { + margin-top: 0.5em; + flex: 1 0 50%; + display: flex; + flex-direction: column; + gap: 0.5em; + } + + @media (max-width: 640px) { + :host { + flex-direction: column; + } + + .image { + width: 100%; + } + + .content { + margin-top: 0; + margin-left: 0.3em; + margin-right: 0.3em; + } + + ::slotted(*) { + width: 100%; + } + } + `, + ]; + + override render(): unknown { + return html` +
+ +
+
+ +
+ `; + } +} diff --git a/src/webviews/apps/welcome/components/feature-carousel.ts b/src/webviews/apps/welcome/components/feature-carousel.ts index 137fc93f2603f..14a135f4a9dfe 100644 --- a/src/webviews/apps/welcome/components/feature-carousel.ts +++ b/src/webviews/apps/welcome/components/feature-carousel.ts @@ -6,7 +6,6 @@ import '../../shared/components/code-icon'; declare global { interface HTMLElementTagNameMap { 'gl-feature-carousel': GlFeatureCarousel; - 'gl-feature-card': GlFeatureCard; } } @@ -117,59 +116,3 @@ export class GlFeatureCarousel extends LitElement { `; } } - -@customElement('gl-feature-card') -export class GlFeatureCard extends LitElement { - static override styles = [ - css` - :host { - display: flex; - gap: 1em; - } - - .image { - flex: 1 1 50%; - width: 50%; - } - - .content { - margin-top: 0.5em; - flex: 1 0 50%; - display: flex; - flex-direction: column; - gap: 0.5em; - } - - @media (max-width: 640px) { - :host { - flex-direction: column; - } - - .image { - width: 100%; - } - - .content { - margin-top: 0; - margin-left: 0.3em; - margin-right: 0.3em; - } - - ::slotted(*) { - width: 100%; - } - } - `, - ]; - - override render(): unknown { - return html` -
- -
-
- -
- `; - } -} diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 3837645c84446..1cd534b9e2272 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -11,6 +11,7 @@ import { WelcomeStateProvider } from './stateProvider'; import '../shared/components/gitlens-logo'; import { welcomeStyles } from './welcome.css'; import './components/feature-carousel'; +import './components/feature-card'; @customElement('gl-welcome-app') export class GlWelcomeApp extends GlAppHost { From 7ff936233b7b398d261663ad2bdba677854ca590 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Fri, 5 Dec 2025 17:51:43 +0100 Subject: [PATCH 08/21] Adds Pro trial action button for welcome webview Introduces a new "Start GitLens Pro Trial" button to the welcome webview and tracks user interactions with a dedicated telemetry event. Updates telemetry documentation and types to include "welcome" as a source and to describe the new "welcome/action" event, enabling better insight into user engagement with onboarding and trial features. (#4769, #4773, PLG-138) --- docs/telemetry-events.md | 72 ++++++++++++++++-------- src/constants.telemetry.ts | 10 ++++ src/webviews/apps/welcome/welcome.css.ts | 20 +++++++ src/webviews/apps/welcome/welcome.ts | 20 +++++++ 4 files changed, 98 insertions(+), 24 deletions(-) diff --git a/docs/telemetry-events.md b/docs/telemetry-events.md index 3b0e7b84b3e53..08452894d7211 100644 --- a/docs/telemetry-events.md +++ b/docs/telemetry-events.md @@ -581,7 +581,7 @@ void 'attempts': number, 'autoInstall': boolean, 'error.message': string, - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -593,7 +593,7 @@ void { 'attempts': number, 'autoInstall': boolean, - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -605,7 +605,7 @@ void { 'attempts': number, 'autoInstall': boolean, - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'version': string } ``` @@ -1027,7 +1027,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1082,7 +1082,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1137,7 +1137,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1192,7 +1192,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1247,7 +1247,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1302,7 +1302,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1357,7 +1357,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1412,7 +1412,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1467,7 +1467,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1522,7 +1522,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1577,7 +1577,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1632,7 +1632,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1699,7 +1699,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1754,7 +1754,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1836,7 +1836,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -1891,7 +1891,7 @@ or 'context.operations.undo.count': number, 'context.session.duration': number, 'context.session.start': string, - 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', + 'context.source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees', 'context.warnings.indexChanged': boolean, 'context.warnings.workingDirectoryChanged': boolean, 'context.webview.host': 'view' | 'editor', @@ -2823,7 +2823,7 @@ void 'cli.version': string, 'error.message': string, 'reason': string, - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -2835,7 +2835,7 @@ void { 'cli.version': string, 'requiresUserCompletion': boolean, - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -2848,7 +2848,7 @@ void 'cli.version': string, 'error.message': string, 'reason': string, - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -2858,7 +2858,7 @@ void ```typescript { - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -2895,7 +2895,7 @@ void 'repoPrivacy': 'private' | 'public' | 'local', 'repository.visibility': 'private' | 'public' | 'local', // Provided for compatibility with other GK surfaces - 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' + 'source': 'account' | 'subscription' | 'graph' | 'composer' | 'patchDetails' | 'settings' | 'timeline' | 'welcome' | 'home' | 'rebaseEditor' | 'ai' | 'ai:markdown-preview' | 'ai:markdown-editor' | 'ai:picker' | 'associateIssueWithBranch' | 'cloud-patches' | 'code-suggest' | 'commandPalette' | 'deeplink' | 'editor:hover' | 'feature-badge' | 'feature-gate' | 'gk-cli-integration' | 'gk-mcp-provider' | 'inspect' | 'inspect-overview' | 'integrations' | 'launchpad' | 'launchpad-indicator' | 'launchpad-view' | 'mcp' | 'mcp-welcome-message' | 'merge-target' | 'notification' | 'prompt' | 'quick-wizard' | 'remoteProvider' | 'scm' | 'scm-input' | 'startWork' | 'statusbar:hover' | 'trial-indicator' | 'view' | 'view:hover' | 'walkthrough' | 'whatsnew' | 'worktrees' } ``` @@ -3597,6 +3597,30 @@ or } ``` +### welcome/action + +> Sent when an action is taken in the welcome webview + +```typescript +{ + 'command': string, + 'detail': string, + 'name': 'plus/sign-up', + 'type': 'command' +} +``` + +or + +```typescript +{ + 'detail': string, + 'name': 'plus/sign-up', + 'type': 'url', + 'url': string +} +``` + ### welcome/closed ```typescript diff --git a/src/constants.telemetry.ts b/src/constants.telemetry.ts index 8f258e43bb21b..0ca04c3423e25 100644 --- a/src/constants.telemetry.ts +++ b/src/constants.telemetry.ts @@ -363,6 +363,9 @@ export interface TelemetryEvents extends WebviewShowAbortedEvents, WebviewShownE /** Sent when the walkthrough is opened */ 'walkthrough/action': WalkthroughActionEvent; 'walkthrough/completion': WalkthroughCompletionEvent; + + /** Sent when an action is taken in the welcome webview */ + 'welcome/action': WelcomeActionEvent; } type WebviewShowAbortedEvents = { @@ -1220,6 +1223,12 @@ interface WalkthroughCompletionEvent { 'context.key': WalkthroughContextKeys; } +type WelcomeActionNames = 'plus/sign-up'; + +type WelcomeActionEvent = + | { type: 'command'; name: WelcomeActionNames; command: string; detail?: string } + | { type: 'url'; name: WelcomeActionNames; url: string; detail?: string }; + type WebviewContextEventData = { 'context.webview.id': string; 'context.webview.type': string; @@ -1302,6 +1311,7 @@ export type Sources = | 'view' | 'view:hover' | 'walkthrough' + | 'welcome' | 'whatsnew' | 'worktrees'; diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 2bc80a97eed8a..c44117cc84802 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -8,6 +8,7 @@ const colorScheme = css` --link-color: var(--vscode-textLink-foreground); --hero-gradient: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); + --trial-button-gradient: linear-gradient(90deg, #7900c9 0%, #196fff 100%); } `; @@ -78,6 +79,25 @@ const section = css` max-width: 30em; font-size: var(--p-font-size); } + + .section.start-trial { + margin: 2em 3.1em; + } + .section.start-trial p { + width: 100%; + } + .section.start-trial gl-button { + background: var(--trial-button-gradient); + border: none; + width: 100%; + } + + @media (min-width: 640px) { + .section.start-trial gl-button { + --button-padding: 0.4em 4em; + width: initial; + } + } `; const header = css` diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 1cd534b9e2272..065f706988e66 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -2,6 +2,8 @@ import './welcome.scss'; import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import type { GlCommands } from '../../../constants.commands'; +import { ExecuteCommand } from '../../protocol'; import type { State } from '../../welcome/protocol'; import { GlAppHost } from '../shared/appHost'; import { scrollableBase } from '../shared/components/styles/lit/base.css'; @@ -28,6 +30,20 @@ export class GlWelcomeApp extends GlAppHost { @property({ type: String }) webroot?: string; + private onStartTrial() { + const command: GlCommands = 'gitlens.plus.signUp'; + this._telemetry.sendEvent({ + name: 'welcome/action', + data: { + type: 'command', + name: 'plus/sign-up', + command: command, + }, + source: { source: 'welcome' }, + }); + this._ipc.sendCommand(ExecuteCommand, { command: command, args: [{ source: 'welcome' }] }); + } + override render(): unknown { return html`
@@ -64,6 +80,10 @@ export class GlWelcomeApp extends GlAppHost {
+
+ this.onStartTrial()}>Start GitLens Pro Trial +
+

✨ Key Features

    From 2efd6ecf705203e498d7f0556464ca888d14ebe8 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Fri, 5 Dec 2025 18:02:20 +0100 Subject: [PATCH 09/21] Removes dummy text from welcome screen (#4769, #4773, PLG-138) --- src/webviews/apps/welcome/welcome.ts | 48 ---------------------------- 1 file changed, 48 deletions(-) diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 065f706988e66..8c4ed92ef76f5 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -84,54 +84,6 @@ export class GlWelcomeApp extends GlAppHost { this.onStartTrial()}>Start GitLens Pro Trial
-
-

✨ Key Features

-
    -
  • - 📝 - Blame Annotations - See who changed each line and when -
  • -
  • - 📊 - Commit Graph - Visualize your repository's history -
  • -
  • - 🔍 - File History - Track changes to any file over time -
  • -
  • - 🌿 - Branch Management - Easily manage branches and remotes -
  • -
  • - 🤖 - AI Features - Generate commit messages and explanations -
  • -
-
- -
-

🎯 Next Steps

-
    -
  • - 1. - Open the GitLens Home view in the sidebar to see your active work -
  • -
  • - 2. - Try the Commit Graph to visualize your repository -
  • -
  • - 3. - Hover over any line to see inline blame information -
  • -
  • - 4. - Explore the Command Palette (Cmd/Ctrl+Shift+P) and search for "GitLens" -
  • -
-
-

GitLens ${this.state?.version ?? ''} is ready to use!

From 98225aad9fdb470b11348416b5d291ff1286b00c Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Fri, 5 Dec 2025 18:41:58 +0100 Subject: [PATCH 10/21] Improves typography styling (#4769, #4773, PLG-138) --- src/webviews/apps/welcome/welcome.css.ts | 27 +++++++++++++----------- src/webviews/apps/welcome/welcome.ts | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index c44117cc84802..97f8b8ab4ee93 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -71,9 +71,24 @@ const section = css` align-items: center; text-align: center; } + .section h1 { + color: var(--em-color); + } + .section h2 { + color: var(--em-color); + font-weight: normal; + font-size: var(--p-font-size); + } + .section p { + color: var(--text-color); + } .section .accent { color: var(--accent-color); } + .section a { + color: var(--link-color); + text-decoration: none; + } .section.plain p { max-width: 30em; @@ -122,12 +137,7 @@ const header = css` } .header h1 { margin-bottom: 0; - font-size: var(--h1-font-size); - color: var(--em-text-color); - } - .header p { - color: var(--text-color); } `; @@ -154,24 +164,17 @@ const carousel = css` gl-feature-carousel h1 { margin: 0; font-size: var(--card-font-size); - color: var(--em-color); } gl-feature-carousel p { margin: 0.4em 0 0; font-size: var(--card-font-size); - color: var(--text-color); } gl-feature-carousel img { max-width: 100%; height: auto; } - - gl-feature-carousel a { - color: var(--link-color); - text-decoration: none; - } `; export const welcomeStyles = css` diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 8c4ed92ef76f5..68de133a9cba1 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -56,7 +56,7 @@ export class GlWelcomeApp extends GlAppHost {

-

With PRO subscription you get more

+

With PRO subscription you get more

From 491fc274cf8b52c8ca0dc4c43c4a1f62d129bee5 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Fri, 5 Dec 2025 19:41:50 +0100 Subject: [PATCH 11/21] Refines cards layout (#4769, #4773, PLG-138) --- .../welcome/components/feature-carousel.ts | 8 ------ src/webviews/apps/welcome/welcome.css.ts | 27 +++++++++---------- src/webviews/apps/welcome/welcome.ts | 4 +-- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/webviews/apps/welcome/components/feature-carousel.ts b/src/webviews/apps/welcome/components/feature-carousel.ts index 14a135f4a9dfe..60161f6e20813 100644 --- a/src/webviews/apps/welcome/components/feature-carousel.ts +++ b/src/webviews/apps/welcome/components/feature-carousel.ts @@ -14,10 +14,6 @@ export class GlFeatureCarousel extends LitElement { static override styles = [ css` :host { - --gl-carousel-border-radius: 0; - --gl-carousel-background-color: transparent; - --gl-carousel-padding: 1em; - display: block; width: 100%; } @@ -39,10 +35,6 @@ export class GlFeatureCarousel extends LitElement { display: flex; align-items: center; justify-content: center; - - border-radius: var(--gl-carousel-border-radius); - background-color: var(--gl-carousel-background-color); - padding: var(--gl-carousel-padding); } ::slotted(*) { diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 97f8b8ab4ee93..89b6099c87c56 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -141,44 +141,43 @@ const header = css` } `; -const carousel = css` - gl-feature-carousel { +const cards = css` + .card { + border-radius: 0.63em; + background-color: var(--vscode-textBlockQuote-background); + padding: 1.8em; text-align: initial; - --gl-carousel-border-radius: 0.63em; - --gl-carousel-padding: 1.8em; - --gl-carousel-background-color: var(--vscode-textBlockQuote-background); } @media (max-width: 640px) { - gl-feature-carousel { - --gl-carousel-padding: 1em; + .card { + padding: 1em; } } @media (max-width: 300px) { - gl-feature-carousel { - --gl-carousel-padding: 0.5em; + .card { + padding: 0.5em 0.5em 1em; } } - gl-feature-carousel h1 { + .card h1 { margin: 0; font-size: var(--card-font-size); } - gl-feature-carousel p { + .card p { margin: 0.4em 0 0; font-size: var(--card-font-size); } - gl-feature-carousel img { + .card img { max-width: 100%; - height: auto; } `; export const welcomeStyles = css` ${colorScheme} ${typography} ${heroGradient} ${section} ${header} - ${carousel} + ${cards} `; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 68de133a9cba1..4c1db30c856f2 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -61,13 +61,13 @@ export class GlWelcomeApp extends GlAppHost {
- + Commit Graph

Commit Graph

Visualize your repository's history and interact with commits

Open Commit Graph

- + Date: Fri, 5 Dec 2025 19:54:17 +0100 Subject: [PATCH 12/21] Adds initial layout of scrollable cards (#4769, #4773, PLG-138) --- .../apps/welcome/components/feature-card.ts | 6 +- .../welcome/components/feature-narrow-card.ts | 57 +++++++++++++ src/webviews/apps/welcome/welcome.css.ts | 20 ++++- src/webviews/apps/welcome/welcome.ts | 82 ++++++++++++++++++- 4 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 src/webviews/apps/welcome/components/feature-narrow-card.ts diff --git a/src/webviews/apps/welcome/components/feature-card.ts b/src/webviews/apps/welcome/components/feature-card.ts index 7d54dc8b65f8f..3a401f0783fb9 100644 --- a/src/webviews/apps/welcome/components/feature-card.ts +++ b/src/webviews/apps/welcome/components/feature-card.ts @@ -26,12 +26,10 @@ export class GlFeatureCard extends LitElement { .content { margin-top: 0.5em; flex: 1 0 50%; - display: flex; - flex-direction: column; - gap: 0.5em; + display: block; } - @media (max-width: 640px) { + @media (max-width: 400px) { :host { flex-direction: column; } diff --git a/src/webviews/apps/welcome/components/feature-narrow-card.ts b/src/webviews/apps/welcome/components/feature-narrow-card.ts new file mode 100644 index 0000000000000..7c84ea75c7182 --- /dev/null +++ b/src/webviews/apps/welcome/components/feature-narrow-card.ts @@ -0,0 +1,57 @@ +import { css, html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import '../../shared/components/button'; +import '../../shared/components/code-icon'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-feature-narrow-card': GlFeatureNarrowCard; + } +} + +@customElement('gl-feature-narrow-card') +export class GlFeatureNarrowCard extends LitElement { + static override styles = [ + css` + :host { + display: flex; + flex-direction: column; + gap: 0.7em; + width: 12em; + min-width: 12em; + text-align: initial; + } + + .image ::slotted(img) { + max-height: 2.23em; + border-radius: 0.6em; + } + + ::slotted(p:last-child) { + margin-top: 0.5em; + } + + .content { + display: block; + } + + @media (max-width: 400px) { + .content { + margin-left: 0.3em; + margin-right: 0.3em; + } + } + `, + ]; + + override render(): unknown { + return html` +
+ +
+
+ +
+ `; + } +} diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 89b6099c87c56..5270404b4468d 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -56,7 +56,7 @@ const heroGradient = css` max-width: 100%; } - @media (max-width: 640px) { + @media (max-width: 400px) { .welcome::before { height: 273px; } @@ -167,17 +167,33 @@ const cards = css` } .card p { - margin: 0.4em 0 0; + margin: 0.5em 0 0; font-size: var(--card-font-size); } + .card p:last-child { + margin: 1em 0 0; + } + .card img { max-width: 100%; } `; +const scrollableFeatures = css` + gl-scrollable-features { + display: flex; + gap: 1em; + max-width: 100%; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; + } +`; + export const welcomeStyles = css` ${colorScheme} ${typography} ${heroGradient} ${section} ${header} + ${scrollableFeatures} ${cards} `; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 4c1db30c856f2..9a125f9d67086 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -14,6 +14,7 @@ import '../shared/components/gitlens-logo'; import { welcomeStyles } from './welcome.css'; import './components/feature-carousel'; import './components/feature-card'; +import './components/feature-narrow-card'; @customElement('gl-welcome-app') export class GlWelcomeApp extends GlAppHost { @@ -84,8 +85,85 @@ export class GlWelcomeApp extends GlAppHost { this.onStartTrial()}>Start GitLens Pro Trial
-
-

GitLens ${this.state?.version ?? ''} is ready to use!

+
+

You also get these free features

+
+ +
+ + + Commit Graph +

Commit Graph

+

Visualize your repository's history and interact with commits

+

Open Commit Graph

+
+ + Visual File History +

Visual File History

+

Track changes to any file over time

+

Open Visual File History

+
+ + Commit Graph +

Commit Graph

+

Visualize your repository's history and interact with commits

+

Open Commit Graph

+
+ + Visual File History +

Visual File History

+

Track changes to any file over time

+

Open Visual File History

+
+ + Commit Graph +

Commit Graph

+

Visualize your repository's history and interact with commits

+

Open Commit Graph

+
+ + Visual File History +

Visual File History

+

Track changes to any file over time

+

Open Visual File History

+
+
`; From f500dbe436291ace62b3577d783d8e1979df41e3 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Tue, 9 Dec 2025 14:16:07 +0100 Subject: [PATCH 13/21] Adds shadows to the sides of the scrollable narrow feature cards (#4769, #4773, PLG-138) --- .../welcome/components/scrollable-features.ts | 56 +++++++++++++++++++ src/webviews/apps/welcome/welcome.css.ts | 12 ++-- src/webviews/apps/welcome/welcome.ts | 3 +- 3 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 src/webviews/apps/welcome/components/scrollable-features.ts diff --git a/src/webviews/apps/welcome/components/scrollable-features.ts b/src/webviews/apps/welcome/components/scrollable-features.ts new file mode 100644 index 0000000000000..b2dc3da6003a4 --- /dev/null +++ b/src/webviews/apps/welcome/components/scrollable-features.ts @@ -0,0 +1,56 @@ +import { css, html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import '../../shared/components/button'; +import '../../shared/components/code-icon'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-scrollable-features': GlScrollableFeatures; + } +} + +@customElement('gl-scrollable-features') +export class GlScrollableFeatures extends LitElement { + static override styles = [ + css` + :host { + --side-shadowed-padding: 1em; + + position: relative; + max-width: 100%; + } + + :host::before, + :host::after { + content: ' '; + position: absolute; + top: 0; + width: var(--side-shadowed-padding); + height: 100%; + } + + :host::before { + left: 0; + background: linear-gradient(to left, transparent 0%, var(--vscode-editor-background) 83%); + } + :host::after { + right: 0; + background: linear-gradient(to right, transparent 0%, var(--vscode-editor-background) 83%); + } + + .content { + box-sizing: border-box; + padding: 0 var(--side-shadowed-padding); + display: flex; + gap: 1em; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; + } + `, + ]; + + override render(): unknown { + return html`
`; + } +} diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 5270404b4468d..ed07b5255aed5 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -113,6 +113,11 @@ const section = css` width: initial; } } + + .section.wide { + margin-left: -20px; + margin-right: -20px; + } `; const header = css` @@ -182,12 +187,7 @@ const cards = css` const scrollableFeatures = css` gl-scrollable-features { - display: flex; - gap: 1em; - max-width: 100%; - overflow-x: auto; - overflow-y: hidden; - scrollbar-width: none; + --side-shadowed-padding: 20px; } `; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 9a125f9d67086..89421321deeff 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -15,6 +15,7 @@ import { welcomeStyles } from './welcome.css'; import './components/feature-carousel'; import './components/feature-card'; import './components/feature-narrow-card'; +import './components/scrollable-features'; @customElement('gl-welcome-app') export class GlWelcomeApp extends GlAppHost { @@ -89,7 +90,7 @@ export class GlWelcomeApp extends GlAppHost {

You also get these free features

-
+
Date: Tue, 9 Dec 2025 15:55:55 +0100 Subject: [PATCH 14/21] Revamps welcome UI with new feature cards and visuals Enhances the welcome experience by updating feature card titles and descriptions for clarity and engagement, introducing Launchpad as a highlighted feature, and adding new SVG and icon assets for a more polished and informative look. Improves visual consistency and modernizes the feature showcase, making key tools like Commit Graph, Visual File History, Git Blame, and Launchpad more discoverable and appealing to users. (#4769, #4773, PLG-138) --- src/webviews/apps/media/feature-graph.svg | 63 ++++++++++-- .../apps/media/feature-icon-compass.svg | 4 + src/webviews/apps/media/feature-icon-pr.svg | 9 ++ src/webviews/apps/media/feature-launchpad.svg | 29 ++++++ .../welcome/components/feature-narrow-card.ts | 1 + src/webviews/apps/welcome/welcome.ts | 99 ++++++------------- 6 files changed, 127 insertions(+), 78 deletions(-) create mode 100644 src/webviews/apps/media/feature-icon-compass.svg create mode 100644 src/webviews/apps/media/feature-icon-pr.svg create mode 100644 src/webviews/apps/media/feature-launchpad.svg diff --git a/src/webviews/apps/media/feature-graph.svg b/src/webviews/apps/media/feature-graph.svg index ab40260a2541a..c6adf986bafd8 100644 --- a/src/webviews/apps/media/feature-graph.svg +++ b/src/webviews/apps/media/feature-graph.svg @@ -1,11 +1,56 @@ - - - - Commit Graph Placeholder - - - Replace with actual feature image - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/src/webviews/apps/media/feature-icon-compass.svg b/src/webviews/apps/media/feature-icon-compass.svg new file mode 100644 index 0000000000000..e6475f52ae1f7 --- /dev/null +++ b/src/webviews/apps/media/feature-icon-compass.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/webviews/apps/media/feature-icon-pr.svg b/src/webviews/apps/media/feature-icon-pr.svg new file mode 100644 index 0000000000000..2cb296aa2c3ce --- /dev/null +++ b/src/webviews/apps/media/feature-icon-pr.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/webviews/apps/media/feature-launchpad.svg b/src/webviews/apps/media/feature-launchpad.svg new file mode 100644 index 0000000000000..fe1782a802af7 --- /dev/null +++ b/src/webviews/apps/media/feature-launchpad.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/webviews/apps/welcome/components/feature-narrow-card.ts b/src/webviews/apps/welcome/components/feature-narrow-card.ts index 7c84ea75c7182..6b9743aaf8de2 100644 --- a/src/webviews/apps/welcome/components/feature-narrow-card.ts +++ b/src/webviews/apps/welcome/components/feature-narrow-card.ts @@ -25,6 +25,7 @@ export class GlFeatureNarrowCard extends LitElement { .image ::slotted(img) { max-height: 2.23em; border-radius: 0.6em; + /* background: rgba(255, 255, 255, 0.04);*/ } ::slotted(p:last-child) { diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 89421321deeff..31cc1136ff05d 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -17,6 +17,11 @@ import './components/feature-card'; import './components/feature-narrow-card'; import './components/scrollable-features'; +const helpBlameUrl = + 'https://www.gitkraken.com/gitlens?utm_source=gitlens-extension&utm_medium=in-app-links#Visual-Repository-Intelligence'; +const helpLaunchpadUrl = + 'https://www.gitkraken.com/gitlens?utm_source=gitlens-extension&utm_medium=in-app-links#Visual-Repository-Intelligence'; + @customElement('gl-welcome-app') export class GlWelcomeApp extends GlAppHost { static override styles = [scrollableBase, welcomeStyles]; @@ -65,8 +70,8 @@ export class GlWelcomeApp extends GlAppHost { Commit Graph -

Commit Graph

-

Visualize your repository's history and interact with commits

+

Navigate Complex Repository Structures

+

by unlocking the full potential of the interactive Commit Graph.

Open Commit Graph

@@ -75,10 +80,20 @@ export class GlWelcomeApp extends GlAppHost { src="${this.webroot ?? ''}/media/feature-timeline.webp" alt="Visual File History" /> -

Visual File History

-

Track changes to any file over time

+

Accelereate Code Reviews

+

Visual File History provides context into the most important changes.

Open Visual File History

+ + Launchpad +

Streamline Pull Request Management

+

Launchpad integrates PR workflows directly into your editor.

+

Open Launchpad

+
@@ -95,74 +110,20 @@ export class GlWelcomeApp extends GlAppHost { Commit Graph -

Commit Graph

-

Visualize your repository's history and interact with commits

-

Open Commit Graph

-
- - Visual File History -

Visual File History

-

Track changes to any file over time

-

Open Visual File History

-
- - Commit Graph -

Commit Graph

-

Visualize your repository's history and interact with commits

-

Open Commit Graph

+

Git Blame

+

Understand the context behind every line with inline blame annotations

+

+ Learn more +

- Visual File History -

Visual File History

-

Track changes to any file over time

-

Open Visual File History

-
- - Commit Graph -

Commit Graph

-

Visualize your repository's history and interact with commits

-

Open Commit Graph

-
- - Visual File History -

Visual File History

-

Track changes to any file over time

-

Open Visual File History

+ Launchpad +

Launchpad

+

Your personalized command center for managing pull requests and issues

+

Learn more

From 55443378a62ba37a4e67e69ab1c3c9129e482b27 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Tue, 9 Dec 2025 22:14:55 +0100 Subject: [PATCH 15/21] Adds light and dark theme support for feature images Introduces separate light and dark variants for feature SVG/WebP images and updates the UI to dynamically switch image sources based on the current theme. Improves accessibility and visual consistency for both light and dark VS Code themes. Also enhances CSS theming for high contrast modes and streamlines feature card background handling. (#4769, #4773, PLG-138) --- ...ature-graph.svg => feature-graph-dark.svg} | 0 .../apps/media/feature-graph-light.svg | 56 +++++++++++++++++++ ...pass.svg => feature-icon-compass-dark.svg} | 2 +- .../apps/media/feature-icon-compass-light.svg | 4 ++ ...e-icon-pr.svg => feature-icon-pr-dark.svg} | 2 +- .../apps/media/feature-icon-pr-light.svg | 9 +++ ...unchpad.svg => feature-launchpad-dark.svg} | 0 .../apps/media/feature-launchpad-light.svg | 29 ++++++++++ ...timeline.svg => feature-timeline-dark.svg} | 0 .../apps/media/feature-timeline-light.svg | 48 ++++++++++++++++ .../welcome/components/feature-narrow-card.ts | 1 - .../welcome/components/scrollable-features.ts | 5 +- src/webviews/apps/welcome/welcome.css.ts | 27 ++++++++- src/webviews/apps/welcome/welcome.scss | 13 +++++ src/webviews/apps/welcome/welcome.ts | 29 ++++++++-- 15 files changed, 213 insertions(+), 12 deletions(-) rename src/webviews/apps/media/{feature-graph.svg => feature-graph-dark.svg} (100%) create mode 100644 src/webviews/apps/media/feature-graph-light.svg rename src/webviews/apps/media/{feature-icon-compass.svg => feature-icon-compass-dark.svg} (99%) create mode 100644 src/webviews/apps/media/feature-icon-compass-light.svg rename src/webviews/apps/media/{feature-icon-pr.svg => feature-icon-pr-dark.svg} (99%) create mode 100644 src/webviews/apps/media/feature-icon-pr-light.svg rename src/webviews/apps/media/{feature-launchpad.svg => feature-launchpad-dark.svg} (100%) create mode 100644 src/webviews/apps/media/feature-launchpad-light.svg rename src/webviews/apps/media/{feature-timeline.svg => feature-timeline-dark.svg} (100%) create mode 100644 src/webviews/apps/media/feature-timeline-light.svg diff --git a/src/webviews/apps/media/feature-graph.svg b/src/webviews/apps/media/feature-graph-dark.svg similarity index 100% rename from src/webviews/apps/media/feature-graph.svg rename to src/webviews/apps/media/feature-graph-dark.svg diff --git a/src/webviews/apps/media/feature-graph-light.svg b/src/webviews/apps/media/feature-graph-light.svg new file mode 100644 index 0000000000000..61127b91486b1 --- /dev/null +++ b/src/webviews/apps/media/feature-graph-light.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/webviews/apps/media/feature-icon-compass.svg b/src/webviews/apps/media/feature-icon-compass-dark.svg similarity index 99% rename from src/webviews/apps/media/feature-icon-compass.svg rename to src/webviews/apps/media/feature-icon-compass-dark.svg index e6475f52ae1f7..06f6328323a4c 100644 --- a/src/webviews/apps/media/feature-icon-compass.svg +++ b/src/webviews/apps/media/feature-icon-compass-dark.svg @@ -1,4 +1,4 @@ - + diff --git a/src/webviews/apps/media/feature-icon-compass-light.svg b/src/webviews/apps/media/feature-icon-compass-light.svg new file mode 100644 index 0000000000000..d9bb1dc52a8bc --- /dev/null +++ b/src/webviews/apps/media/feature-icon-compass-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/webviews/apps/media/feature-icon-pr.svg b/src/webviews/apps/media/feature-icon-pr-dark.svg similarity index 99% rename from src/webviews/apps/media/feature-icon-pr.svg rename to src/webviews/apps/media/feature-icon-pr-dark.svg index 2cb296aa2c3ce..e3a2abf2d1026 100644 --- a/src/webviews/apps/media/feature-icon-pr.svg +++ b/src/webviews/apps/media/feature-icon-pr-dark.svg @@ -1,5 +1,5 @@ - + diff --git a/src/webviews/apps/media/feature-icon-pr-light.svg b/src/webviews/apps/media/feature-icon-pr-light.svg new file mode 100644 index 0000000000000..3f413922080c7 --- /dev/null +++ b/src/webviews/apps/media/feature-icon-pr-light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/webviews/apps/media/feature-launchpad.svg b/src/webviews/apps/media/feature-launchpad-dark.svg similarity index 100% rename from src/webviews/apps/media/feature-launchpad.svg rename to src/webviews/apps/media/feature-launchpad-dark.svg diff --git a/src/webviews/apps/media/feature-launchpad-light.svg b/src/webviews/apps/media/feature-launchpad-light.svg new file mode 100644 index 0000000000000..afa7031dc5c75 --- /dev/null +++ b/src/webviews/apps/media/feature-launchpad-light.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/webviews/apps/media/feature-timeline.svg b/src/webviews/apps/media/feature-timeline-dark.svg similarity index 100% rename from src/webviews/apps/media/feature-timeline.svg rename to src/webviews/apps/media/feature-timeline-dark.svg diff --git a/src/webviews/apps/media/feature-timeline-light.svg b/src/webviews/apps/media/feature-timeline-light.svg new file mode 100644 index 0000000000000..f6dea6f39e788 --- /dev/null +++ b/src/webviews/apps/media/feature-timeline-light.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/webviews/apps/welcome/components/feature-narrow-card.ts b/src/webviews/apps/welcome/components/feature-narrow-card.ts index 6b9743aaf8de2..7c84ea75c7182 100644 --- a/src/webviews/apps/welcome/components/feature-narrow-card.ts +++ b/src/webviews/apps/welcome/components/feature-narrow-card.ts @@ -25,7 +25,6 @@ export class GlFeatureNarrowCard extends LitElement { .image ::slotted(img) { max-height: 2.23em; border-radius: 0.6em; - /* background: rgba(255, 255, 255, 0.04);*/ } ::slotted(p:last-child) { diff --git a/src/webviews/apps/welcome/components/scrollable-features.ts b/src/webviews/apps/welcome/components/scrollable-features.ts index b2dc3da6003a4..df52630c4daca 100644 --- a/src/webviews/apps/welcome/components/scrollable-features.ts +++ b/src/webviews/apps/welcome/components/scrollable-features.ts @@ -15,6 +15,7 @@ export class GlScrollableFeatures extends LitElement { css` :host { --side-shadowed-padding: 1em; + --background-color: var(--vscode-editor-background); position: relative; max-width: 100%; @@ -31,11 +32,11 @@ export class GlScrollableFeatures extends LitElement { :host::before { left: 0; - background: linear-gradient(to left, transparent 0%, var(--vscode-editor-background) 83%); + background: linear-gradient(to left, transparent 0%, var(--background-color) 83%); } :host::after { right: 0; - background: linear-gradient(to right, transparent 0%, var(--vscode-editor-background) 83%); + background: linear-gradient(to right, transparent 0%, var(--background-color) 83%); } .content { diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index ed07b5255aed5..68b8220435602 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -9,6 +9,30 @@ const colorScheme = css` --hero-gradient: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); --trial-button-gradient: linear-gradient(90deg, #7900c9 0%, #196fff 100%); + --trial-button-border: none; + --trial-button-text-color: #fff; + } + + :host-context(.vscode-light) { + --hero-gradient: radial-gradient(62.4% 62.4% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); + } + + :host-context(.vscode-dark) { + --hero-gradient: radial-gradient(76.32% 76.32% at 50% 7.24%, #7b00ff 29.72%, rgba(255, 0, 242, 0) 100%); + } + + :host-context(.vscode-high-contrast) { + --hero-gradient: transparent; + --trial-button-gradient: var(--color-button-background); + --trial-button-border: 1px solid var(--vscode-button-border); + --trial-button-text-color: var(--color-button-foreground); + } + + :host-context(.vscode-high-contrast-light) { + --accent-color: #500070; + } + :host-context(.vscode-high-contrast:not(.vscode-high-contrast-light)) { + --accent-color: #ffc0ff; } `; @@ -103,7 +127,8 @@ const section = css` } .section.start-trial gl-button { background: var(--trial-button-gradient); - border: none; + border: var(--trial-button-border); + color: var(--trial-button-text-color); width: 100%; } diff --git a/src/webviews/apps/welcome/welcome.scss b/src/webviews/apps/welcome/welcome.scss index fbfa976037705..675bab88d0bc3 100644 --- a/src/webviews/apps/welcome/welcome.scss +++ b/src/webviews/apps/welcome/welcome.scss @@ -1 +1,14 @@ +// @use '../shared/styles/utils'; @use '../shared/styles/theme'; + +// :root { +// --bg-color: green; +// } + +// @include utils.dark-theme() { +// --bg-color: red; +// } + +// @include utils.light-theme() { +// --bg-color: yellow; +// } diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index 31cc1136ff05d..e8004f8cfae64 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -1,7 +1,7 @@ /*global*/ import './welcome.scss'; import { html } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import type { GlCommands } from '../../../constants.commands'; import { ExecuteCommand } from '../../protocol'; import type { State } from '../../welcome/protocol'; @@ -9,6 +9,7 @@ import { GlAppHost } from '../shared/appHost'; import { scrollableBase } from '../shared/components/styles/lit/base.css'; import type { LoggerContext } from '../shared/contexts/logger'; import type { HostIpc } from '../shared/ipc'; +import type { ThemeChangeEvent } from '../shared/theme'; import { WelcomeStateProvider } from './stateProvider'; import '../shared/components/gitlens-logo'; import { welcomeStyles } from './welcome.css'; @@ -37,6 +38,13 @@ export class GlWelcomeApp extends GlAppHost { @property({ type: String }) webroot?: string; + @state() + private isLightTheme = false; + + protected override onThemeUpdated(e: ThemeChangeEvent): void { + this.isLightTheme = e.isLightTheme; + } + private onStartTrial() { const command: GlCommands = 'gitlens.plus.signUp'; this._telemetry.sendEvent({ @@ -52,6 +60,7 @@ export class GlWelcomeApp extends GlAppHost { } override render(): unknown { + const themeSuffix = this.isLightTheme ? 'light' : 'dark'; return html`
@@ -69,7 +78,11 @@ export class GlWelcomeApp extends GlAppHost {
- Commit Graph + Commit Graph

Navigate Complex Repository Structures

by unlocking the full potential of the interactive Commit Graph.

Open Commit Graph

@@ -77,7 +90,7 @@ export class GlWelcomeApp extends GlAppHost { Visual File History

Accelereate Code Reviews

@@ -87,7 +100,7 @@ export class GlWelcomeApp extends GlAppHost { Launchpad

Streamline Pull Request Management

@@ -110,7 +123,7 @@ export class GlWelcomeApp extends GlAppHost { Git Blame

Git Blame

@@ -120,7 +133,11 @@ export class GlWelcomeApp extends GlAppHost {

- Launchpad + Launchpad

Launchpad

Your personalized command center for managing pull requests and issues

Learn more

From 3d473e82f8325585113be82ab75d1d220e8ced79 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Wed, 10 Dec 2025 15:09:17 +0100 Subject: [PATCH 16/21] Implements welcome overlay over Homve View for new users in Cursor and other IDEs without walkthrough support. Adds a welcome overlay to the home webview for new users to improve the first-time user experience. The overlay is displayed only on the first install and when the walkthrough is not supported. It can be dismissed, and its state is persisted. (#4769, #4773, PLG-138) --- src/extension.ts | 10 +-- .../apps/home/components/welcome-overlay.ts | 74 +++++++++++++++++++ src/webviews/apps/home/home.ts | 2 + src/webviews/home/homeWebview.ts | 5 ++ src/webviews/home/protocol.ts | 1 + 5 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 src/webviews/apps/home/components/welcome-overlay.ts diff --git a/src/extension.ts b/src/extension.ts index e92c14013b265..ed3f84e7d0096 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -366,11 +366,11 @@ async function showWhatsNew( if (previousVersion == null) { Logger.log(`GitLens first-time install; window.focused=${window.state.focused}`); - // Show welcome webview on first install for IDEs that don't support walkthroughs (e.g., Cursor) - // For IDEs that support walkthroughs, the walkthrough will be shown instead - if (window.state.focused && !container.walkthrough.isWalkthroughSupported) { - void executeCommand('gitlens.showWelcomePage'); - } + // // Show welcome webview on first install for IDEs that don't support walkthroughs (e.g., Cursor) + // // For IDEs that support walkthroughs, the walkthrough will be shown instead + // if (window.state.focused && !container.walkthrough.isWalkthroughSupported) { + // void executeCommand('gitlens.showWelcomePage'); + // } return; } diff --git a/src/webviews/apps/home/components/welcome-overlay.ts b/src/webviews/apps/home/components/welcome-overlay.ts new file mode 100644 index 0000000000000..968e5e215b5e8 --- /dev/null +++ b/src/webviews/apps/home/components/welcome-overlay.ts @@ -0,0 +1,74 @@ +import { consume } from '@lit/context'; +import { css, html, LitElement, nothing } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import type { State } from '../../../home/protocol'; +import { CollapseSectionCommand } from '../../../home/protocol'; +import { ipcContext } from '../../shared/contexts/ipc'; +import type { HostIpc } from '../../shared/ipc'; +import { stateContext } from '../context'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-welcome-overlay': GlWelcomeOverlay; + } +} + +@customElement('gl-welcome-overlay') +export class GlWelcomeOverlay extends LitElement { + static override shadowRootOptions: ShadowRootInit = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static override styles = [ + css` + .overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + background-color: #007acc; + color: white; + } + `, + ]; + + @consume({ context: stateContext, subscribe: true }) + @state() + private _state!: State; + + @consume({ context: ipcContext, subscribe: true }) + @state() + private _ipc!: HostIpc; + + @state() + private closed = false; + + override render(): unknown { + const { welcomeOverlayCollapsed, walkthroughSupported, newInstall } = this._state; + if (this.closed || welcomeOverlayCollapsed || walkthroughSupported || !newInstall) { + return nothing; + } + + return html` +
+

Welcome!!!

+ +
+ `; + } + + private onClose() { + this.closed = true; + + this._ipc.sendCommand(CollapseSectionCommand, { + section: 'welcomeOverlay', + collapsed: true, + }); + } +} diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index 24060a3f93fc8..5dd2404540ab6 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -29,6 +29,7 @@ import './components/ai-all-access-banner'; import './components/ama-banner'; import './components/integration-banner'; import './components/preview-banner'; +import './components/welcome-overlay'; import '../shared/components/mcp-banner'; import './components/repo-alerts'; import '../shared/components/banner/banner'; @@ -111,6 +112,7 @@ export class GlHomeApp extends GlAppHost { `, )} +
`; } diff --git a/src/webviews/home/homeWebview.ts b/src/webviews/home/homeWebview.ts index 74b79cb06a2c1..5ed14ab20ad9f 100644 --- a/src/webviews/home/homeWebview.ts +++ b/src/webviews/home/homeWebview.ts @@ -803,6 +803,10 @@ export class HomeWebviewProvider implements WebviewProvider { previewEnabled: boolean; newInstall: boolean; amaBannerCollapsed: boolean; + welcomeOverlayCollapsed: boolean; } export interface IntegrationState extends IntegrationDescriptor { From 9c1c08ca40c9eba887fdb2e086f3918cd911d967 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Wed, 10 Dec 2025 21:25:39 +0100 Subject: [PATCH 17/21] Uses Welcome View as an overlay over the Home View. Fixes layout of some of its elements. (#4769, #4773, PLG-138) --- .../apps/home/components/welcome-overlay.ts | 25 +++++++++++++------ .../welcome/components/scrollable-features.ts | 13 +++++----- src/webviews/apps/welcome/welcome.css.ts | 24 +++++++++++++++--- src/webviews/apps/welcome/welcome.scss | 4 +++ src/webviews/apps/welcome/welcome.ts | 18 +++++++++++++ 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/webviews/apps/home/components/welcome-overlay.ts b/src/webviews/apps/home/components/welcome-overlay.ts index 968e5e215b5e8..f60f0cd347bcd 100644 --- a/src/webviews/apps/home/components/welcome-overlay.ts +++ b/src/webviews/apps/home/components/welcome-overlay.ts @@ -6,6 +6,7 @@ import { CollapseSectionCommand } from '../../../home/protocol'; import { ipcContext } from '../../shared/contexts/ipc'; import type { HostIpc } from '../../shared/ipc'; import { stateContext } from '../context'; +import '../../welcome/welcome'; declare global { interface HTMLElementTagNameMap { @@ -22,6 +23,9 @@ export class GlWelcomeOverlay extends LitElement { static override styles = [ css` + :host { + --background-color: var(--vscode-editor-background); + } .overlay { position: fixed; top: 0; @@ -29,11 +33,12 @@ export class GlWelcomeOverlay extends LitElement { right: 0; bottom: 0; z-index: 1000; - display: flex; - align-items: center; - justify-content: center; - background-color: #007acc; - color: white; + display: block; + background-color: var(--background-color); + } + + gl-welcome-app { + --page-background-color: var(--background-color); } `, ]; @@ -57,8 +62,14 @@ export class GlWelcomeOverlay extends LitElement { return html`
-

Welcome!!!

- + this.onClose()} + >
`; } diff --git a/src/webviews/apps/welcome/components/scrollable-features.ts b/src/webviews/apps/welcome/components/scrollable-features.ts index df52630c4daca..e51e681c15547 100644 --- a/src/webviews/apps/welcome/components/scrollable-features.ts +++ b/src/webviews/apps/welcome/components/scrollable-features.ts @@ -14,9 +14,10 @@ export class GlScrollableFeatures extends LitElement { static override styles = [ css` :host { - --side-shadowed-padding: 1em; - --background-color: var(--vscode-editor-background); + --side-shadow-padding: 1em; + --side-shadow-color: transparent; + --final-side-shadow-padding: max(var(--side-shadow-padding), 1em); position: relative; max-width: 100%; } @@ -26,22 +27,22 @@ export class GlScrollableFeatures extends LitElement { content: ' '; position: absolute; top: 0; - width: var(--side-shadowed-padding); + width: var(--final-side-shadow-padding); height: 100%; } :host::before { left: 0; - background: linear-gradient(to left, transparent 0%, var(--background-color) 83%); + background: linear-gradient(to left, transparent 0%, var(--side-shadow-color) 83%); } :host::after { right: 0; - background: linear-gradient(to right, transparent 0%, var(--background-color) 83%); + background: linear-gradient(to right, transparent 0%, var(--side-shadow-color) 83%); } .content { box-sizing: border-box; - padding: 0 var(--side-shadowed-padding); + padding: 0 var(--final-side-shadow-padding); display: flex; gap: 1em; overflow-x: auto; diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/welcome/welcome.css.ts index 68b8220435602..496c4c5088622 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/welcome/welcome.css.ts @@ -2,6 +2,7 @@ import { css } from 'lit'; const colorScheme = css` :host { + --side-shadow-color: transparent; --accent-color: #cb64ff; --text-color: var(--vscode-descriptionForeground); --em-color: var(--vscode-editor-foreground); @@ -61,6 +62,20 @@ const typography = css` } `; +const main = css` + :host { + --page-margin: 0px; + max-width: 100%; + } + + .close-button { + position: absolute; + right: 1em; + top: 1em; + z-index: 1; + } +`; + const heroGradient = css` .welcome::before { content: ' '; @@ -140,8 +155,8 @@ const section = css` } .section.wide { - margin-left: -20px; - margin-right: -20px; + margin-left: calc(-1 * var(--page-margin)); + margin-right: calc(-1 * var(--page-margin)); } `; @@ -212,12 +227,13 @@ const cards = css` const scrollableFeatures = css` gl-scrollable-features { - --side-shadowed-padding: 20px; + --side-shadow-padding: var(--page-margin); + --side-shadow-color: var(--page-background-color); } `; export const welcomeStyles = css` - ${colorScheme} ${typography} + ${colorScheme} ${typography} ${main} ${heroGradient} ${section} ${header} ${scrollableFeatures} ${cards} diff --git a/src/webviews/apps/welcome/welcome.scss b/src/webviews/apps/welcome/welcome.scss index 675bab88d0bc3..c5d7179dbb3c9 100644 --- a/src/webviews/apps/welcome/welcome.scss +++ b/src/webviews/apps/welcome/welcome.scss @@ -12,3 +12,7 @@ // @include utils.light-theme() { // --bg-color: yellow; // } +gl-welcome-app { + --page-margin: 20px; + --page-background-color: var(--vscode-editor-background); +} diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/welcome/welcome.ts index e8004f8cfae64..6d24bfc0fdb07 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/welcome/welcome.ts @@ -12,6 +12,8 @@ import type { HostIpc } from '../shared/ipc'; import type { ThemeChangeEvent } from '../shared/theme'; import { WelcomeStateProvider } from './stateProvider'; import '../shared/components/gitlens-logo'; +import '../shared/components/button'; +import '../shared/components/code-icon'; import { welcomeStyles } from './welcome.css'; import './components/feature-carousel'; import './components/feature-card'; @@ -38,6 +40,9 @@ export class GlWelcomeApp extends GlAppHost { @property({ type: String }) webroot?: string; + @property({ type: Boolean }) + closeable = false; + @state() private isLightTheme = false; @@ -59,10 +64,23 @@ export class GlWelcomeApp extends GlAppHost { this._ipc.sendCommand(ExecuteCommand, { command: command, args: [{ source: 'welcome' }] }); } + private onClose() { + this.dispatchEvent(new CustomEvent('close')); + } + override render(): unknown { const themeSuffix = this.isLightTheme ? 'light' : 'dark'; return html`
+ ${this.closeable + ? html` this.onClose()} + >` + : ''}

GitLens is now installed in Cursor

From b735a4d8e583dfe39839daf05f7e3134c91c89d8 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Thu, 11 Dec 2025 02:23:11 +0100 Subject: [PATCH 18/21] Removes welcome webview and integrates into home Consolidates the welcome webview functionality into the home webview. This change removes the dedicated welcome webview and integrates its components directly into the home webview as an overlay. This simplifies the webview structure and reduces redundancy. It also moves the feature cards to shared welcome parts for better reusability. (#4769, #4773, PLG-138) --- src/container.ts | 4 - .../apps/home/components/welcome-overlay.ts | 20 +- .../components/welcome-page.css.ts} | 10 +- .../components/welcome-page.ts} | 66 ++--- .../apps/home/components/welcome-parts.ts | 262 ++++++++++++++++++ src/webviews/apps/home/home.html | 2 +- src/webviews/apps/home/home.ts | 15 +- .../apps/welcome/components/feature-card.ts | 64 ----- .../welcome/components/feature-carousel.ts | 110 -------- .../welcome/components/feature-narrow-card.ts | 57 ---- .../welcome/components/scrollable-features.ts | 58 ---- src/webviews/apps/welcome/context.ts | 4 - src/webviews/apps/welcome/stateProvider.ts | 16 -- src/webviews/apps/welcome/welcome.html | 31 --- src/webviews/apps/welcome/welcome.scss | 18 -- src/webviews/welcome/protocol.ts | 7 - src/webviews/welcome/registration.ts | 34 --- src/webviews/welcome/welcomeWebview.ts | 41 --- webpack.config.mjs | 1 - 19 files changed, 326 insertions(+), 494 deletions(-) rename src/webviews/apps/{welcome/welcome.css.ts => home/components/welcome-page.css.ts} (97%) rename src/webviews/apps/{welcome/welcome.ts => home/components/welcome-page.ts} (75%) create mode 100644 src/webviews/apps/home/components/welcome-parts.ts delete mode 100644 src/webviews/apps/welcome/components/feature-card.ts delete mode 100644 src/webviews/apps/welcome/components/feature-carousel.ts delete mode 100644 src/webviews/apps/welcome/components/feature-narrow-card.ts delete mode 100644 src/webviews/apps/welcome/components/scrollable-features.ts delete mode 100644 src/webviews/apps/welcome/context.ts delete mode 100644 src/webviews/apps/welcome/stateProvider.ts delete mode 100644 src/webviews/apps/welcome/welcome.html delete mode 100644 src/webviews/apps/welcome/welcome.scss delete mode 100644 src/webviews/welcome/protocol.ts delete mode 100644 src/webviews/welcome/registration.ts delete mode 100644 src/webviews/welcome/welcomeWebview.ts diff --git a/src/container.ts b/src/container.ts index 65b98d25121a0..42b2d8d4fd452 100644 --- a/src/container.ts +++ b/src/container.ts @@ -79,7 +79,6 @@ import { RebaseEditorProvider } from './webviews/rebase/rebaseEditor'; import { registerSettingsWebviewCommands, registerSettingsWebviewPanel } from './webviews/settings/registration'; import { WebviewCommandRegistrar } from './webviews/webviewCommandRegistrar'; import { WebviewsController } from './webviews/webviewsController'; -import { registerWelcomeWebviewPanel } from './webviews/welcome/registration'; export type Environment = 'dev' | 'staging' | 'production'; @@ -262,9 +261,6 @@ export class Container { this._disposables.push(settingsPanels); this._disposables.push(registerSettingsWebviewCommands(settingsPanels)); - const welcomePanels = registerWelcomeWebviewPanel(webviews); - this._disposables.push(welcomePanels); - this._disposables.push(new ViewFileDecorationProvider()); const patchDetailsPanels = registerPatchDetailsWebviewPanel(webviews); diff --git a/src/webviews/apps/home/components/welcome-overlay.ts b/src/webviews/apps/home/components/welcome-overlay.ts index f60f0cd347bcd..38efc24f179c2 100644 --- a/src/webviews/apps/home/components/welcome-overlay.ts +++ b/src/webviews/apps/home/components/welcome-overlay.ts @@ -1,12 +1,12 @@ import { consume } from '@lit/context'; import { css, html, LitElement, nothing } from 'lit'; -import { customElement, state } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import type { State } from '../../../home/protocol'; import { CollapseSectionCommand } from '../../../home/protocol'; import { ipcContext } from '../../shared/contexts/ipc'; import type { HostIpc } from '../../shared/ipc'; import { stateContext } from '../context'; -import '../../welcome/welcome'; +import './welcome-page'; declare global { interface HTMLElementTagNameMap { @@ -37,12 +37,18 @@ export class GlWelcomeOverlay extends LitElement { background-color: var(--background-color); } - gl-welcome-app { + gl-welcome-page { --page-background-color: var(--background-color); } `, ]; + @property({ type: String }) + webroot?: string; + + @property({ type: Boolean }) + private isLightTheme = false; + @consume({ context: stateContext, subscribe: true }) @state() private _state!: State; @@ -62,11 +68,9 @@ export class GlWelcomeOverlay extends LitElement { return html`
- this.onClose()} > diff --git a/src/webviews/apps/welcome/welcome.css.ts b/src/webviews/apps/home/components/welcome-page.css.ts similarity index 97% rename from src/webviews/apps/welcome/welcome.css.ts rename to src/webviews/apps/home/components/welcome-page.css.ts index 496c4c5088622..81cb309b6f2ba 100644 --- a/src/webviews/apps/welcome/welcome.css.ts +++ b/src/webviews/apps/home/components/welcome-page.css.ts @@ -68,10 +68,16 @@ const main = css` max-width: 100%; } + .welcome { + max-height: 100%; + overflow: auto; + position: relative; + } + .close-button { position: absolute; - right: 1em; - top: 1em; + right: 2px; + top: 2px; z-index: 1; } `; diff --git a/src/webviews/apps/welcome/welcome.ts b/src/webviews/apps/home/components/welcome-page.ts similarity index 75% rename from src/webviews/apps/welcome/welcome.ts rename to src/webviews/apps/home/components/welcome-page.ts index 6d24bfc0fdb07..268067e9e3b75 100644 --- a/src/webviews/apps/welcome/welcome.ts +++ b/src/webviews/apps/home/components/welcome-page.ts @@ -1,54 +1,48 @@ -/*global*/ -import './welcome.scss'; -import { html } from 'lit'; -import { customElement, property, state } from 'lit/decorators.js'; -import type { GlCommands } from '../../../constants.commands'; -import { ExecuteCommand } from '../../protocol'; -import type { State } from '../../welcome/protocol'; -import { GlAppHost } from '../shared/appHost'; -import { scrollableBase } from '../shared/components/styles/lit/base.css'; -import type { LoggerContext } from '../shared/contexts/logger'; -import type { HostIpc } from '../shared/ipc'; -import type { ThemeChangeEvent } from '../shared/theme'; -import { WelcomeStateProvider } from './stateProvider'; -import '../shared/components/gitlens-logo'; -import '../shared/components/button'; -import '../shared/components/code-icon'; -import { welcomeStyles } from './welcome.css'; -import './components/feature-carousel'; -import './components/feature-card'; -import './components/feature-narrow-card'; -import './components/scrollable-features'; +import { consume } from '@lit/context'; +import { html, LitElement } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import type { GlCommands } from '../../../../constants.commands'; +import { ExecuteCommand } from '../../../protocol'; +import { scrollableBase } from '../../shared/components/styles/lit/base.css'; +import { ipcContext } from '../../shared/contexts/ipc'; +import type { TelemetryContext } from '../../shared/contexts/telemetry'; +import { telemetryContext } from '../../shared/contexts/telemetry'; +import { welcomeStyles } from './welcome-page.css'; +import '../../shared/components/gitlens-logo'; +import '../../shared/components/button'; +import '../../shared/components/code-icon'; +import './welcome-parts'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-welcome-page': GlWelcomePage; + } +} const helpBlameUrl = 'https://www.gitkraken.com/gitlens?utm_source=gitlens-extension&utm_medium=in-app-links#Visual-Repository-Intelligence'; const helpLaunchpadUrl = 'https://www.gitkraken.com/gitlens?utm_source=gitlens-extension&utm_medium=in-app-links#Visual-Repository-Intelligence'; -@customElement('gl-welcome-app') -export class GlWelcomeApp extends GlAppHost { +@customElement('gl-welcome-page') +export class GlWelcomePage extends LitElement { static override styles = [scrollableBase, welcomeStyles]; + //static override styles = welcomeStyles; - protected override createStateProvider( - bootstrap: string, - ipc: HostIpc, - logger: LoggerContext, - ): WelcomeStateProvider { - return new WelcomeStateProvider(this, bootstrap, ipc, logger); - } + @property({ type: Boolean }) + closeable = false; @property({ type: String }) webroot?: string; @property({ type: Boolean }) - closeable = false; - - @state() private isLightTheme = false; - protected override onThemeUpdated(e: ThemeChangeEvent): void { - this.isLightTheme = e.isLightTheme; - } + @consume({ context: ipcContext }) + _ipc!: typeof ipcContext.__context__; + + @consume({ context: telemetryContext as { __context__: TelemetryContext } }) + _telemetry!: TelemetryContext; private onStartTrial() { const command: GlCommands = 'gitlens.plus.signUp'; diff --git a/src/webviews/apps/home/components/welcome-parts.ts b/src/webviews/apps/home/components/welcome-parts.ts new file mode 100644 index 0000000000000..aa1c04f50f710 --- /dev/null +++ b/src/webviews/apps/home/components/welcome-parts.ts @@ -0,0 +1,262 @@ +import { css, html, LitElement } from 'lit'; +import { customElement, queryAssignedElements, state } from 'lit/decorators.js'; +import '../../shared/components/button'; +import '../../shared/components/code-icon'; + +declare global { + interface HTMLElementTagNameMap { + 'gl-feature-card': GlFeatureCard; + 'gl-feature-carousel': GlFeatureCarousel; + 'gl-feature-narrow-card': GlFeatureNarrowCard; + 'gl-scrollable-features': GlScrollableFeatures; + } +} + +@customElement('gl-feature-carousel') +export class GlFeatureCarousel extends LitElement { + static override styles = [ + css` + :host { + display: block; + width: 100%; + } + + .carousel { + display: flex; + gap: 1em; + justify-content: center; + } + + .button { + display: flex; + align-items: center; + } + + .content { + flex: 1; + max-width: 520px; + display: flex; + align-items: center; + justify-content: center; + } + + ::slotted(*) { + display: none; + } + + ::slotted([data-active]) { + display: flex; + width: 100%; + } + `, + ]; + + @queryAssignedElements({ flatten: true }) + private cards!: HTMLElement[]; + + @state() + private currentIndex = 0; + + override firstUpdated(): void { + this.updateActiveCard(); + } + + private updateActiveCard(): void { + this.cards.forEach((card, index) => { + if (index === this.currentIndex) { + card.setAttribute('data-active', ''); + } else { + card.removeAttribute('data-active'); + } + }); + } + + private handlePrevious(): void { + if (this.cards.length === 0) return; + this.currentIndex = (this.currentIndex - 1 + this.cards.length) % this.cards.length; + this.updateActiveCard(); + } + + private handleNext(): void { + if (this.cards.length === 0) return; + this.currentIndex = (this.currentIndex + 1) % this.cards.length; + this.updateActiveCard(); + } + + private handleSlotChange(): void { + this.currentIndex = 0; + this.updateActiveCard(); + } + + override render(): unknown { + return html` + + `; + } +} + +@customElement('gl-feature-card') +export class GlFeatureCard extends LitElement { + static override styles = [ + css` + :host { + display: flex; + gap: 1em; + } + + .image { + flex: 1 1 50%; + width: 50%; + } + + .content { + margin-top: 0.5em; + flex: 1 0 50%; + display: block; + } + + @media (max-width: 400px) { + :host { + flex-direction: column; + } + + .image { + width: 100%; + } + + .content { + margin-top: 0; + margin-left: 0.3em; + margin-right: 0.3em; + } + + ::slotted(*) { + width: 100%; + } + } + `, + ]; + + override render(): unknown { + return html` +
+ +
+
+ +
+ `; + } +} + +@customElement('gl-feature-narrow-card') +export class GlFeatureNarrowCard extends LitElement { + static override styles = [ + css` + :host { + display: flex; + flex-direction: column; + gap: 0.7em; + width: 12em; + min-width: 12em; + text-align: initial; + } + + .image ::slotted(img) { + max-height: 2.23em; + border-radius: 0.6em; + } + + ::slotted(p:last-child) { + margin-top: 0.5em; + } + + .content { + display: block; + } + + @media (max-width: 400px) { + .content { + margin-left: 0.3em; + margin-right: 0.3em; + } + } + `, + ]; + + override render(): unknown { + return html` +
+ +
+
+ +
+ `; + } +} + +@customElement('gl-scrollable-features') +export class GlScrollableFeatures extends LitElement { + static override styles = [ + css` + :host { + --side-shadow-padding: 1em; + --side-shadow-color: transparent; + + --final-side-shadow-padding: max(var(--side-shadow-padding), 1em); + position: relative; + max-width: 100%; + } + + :host::before, + :host::after { + content: ' '; + position: absolute; + top: 0; + width: var(--final-side-shadow-padding); + height: 100%; + } + + :host::before { + left: 0; + background: linear-gradient(to left, transparent 0%, var(--side-shadow-color) 83%); + } + :host::after { + right: 0; + background: linear-gradient(to right, transparent 0%, var(--side-shadow-color) 83%); + } + + .content { + box-sizing: border-box; + padding: 0 var(--final-side-shadow-padding); + display: flex; + gap: 1em; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; + } + `, + ]; + + override render(): unknown { + return html`
`; + } +} diff --git a/src/webviews/apps/home/home.html b/src/webviews/apps/home/home.html index ae2ca4cb107f4..a4b1a167f1e6e 100644 --- a/src/webviews/apps/home/home.html +++ b/src/webviews/apps/home/home.html @@ -21,6 +21,6 @@ data-placement="#{placement}" data-vscode-context='{ "webview": "#{webviewId}", "webviewInstance": "#{webviewInstanceId}" }' > - + diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index 5dd2404540ab6..505dc409b236b 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -2,7 +2,7 @@ import './home.scss'; import { provide } from '@lit/context'; import { html } from 'lit'; -import { customElement, query } from 'lit/decorators.js'; +import { customElement, property, query, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; import type { State } from '../../home/protocol'; import { DidChangeSubscription, DidFocusAccount } from '../../home/protocol'; @@ -17,6 +17,7 @@ import { GlAppHost } from '../shared/appHost'; import { scrollableBase } from '../shared/components/styles/lit/base.css'; import type { LoggerContext } from '../shared/contexts/logger'; import type { HostIpc } from '../shared/ipc'; +import type { ThemeChangeEvent } from '../shared/theme'; import type { GlAiAllAccessBanner } from './components/ai-all-access-banner'; import { homeBaseStyles, homeStyles } from './home.css'; import { HomeStateProvider } from './stateProvider'; @@ -77,6 +78,16 @@ export class GlHomeApp extends GlAppHost { ); } + @property({ type: String }) + webroot?: string; + + @state() + private isLightTheme = false; + + protected override onThemeUpdated(e: ThemeChangeEvent): void { + this.isLightTheme = e.isLightTheme; + } + override render(): unknown { return html`
@@ -112,7 +123,7 @@ export class GlHomeApp extends GlAppHost { `, )} - +
`; } diff --git a/src/webviews/apps/welcome/components/feature-card.ts b/src/webviews/apps/welcome/components/feature-card.ts deleted file mode 100644 index 3a401f0783fb9..0000000000000 --- a/src/webviews/apps/welcome/components/feature-card.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import '../../shared/components/button'; -import '../../shared/components/code-icon'; - -declare global { - interface HTMLElementTagNameMap { - 'gl-feature-card': GlFeatureCard; - } -} - -@customElement('gl-feature-card') -export class GlFeatureCard extends LitElement { - static override styles = [ - css` - :host { - display: flex; - gap: 1em; - } - - .image { - flex: 1 1 50%; - width: 50%; - } - - .content { - margin-top: 0.5em; - flex: 1 0 50%; - display: block; - } - - @media (max-width: 400px) { - :host { - flex-direction: column; - } - - .image { - width: 100%; - } - - .content { - margin-top: 0; - margin-left: 0.3em; - margin-right: 0.3em; - } - - ::slotted(*) { - width: 100%; - } - } - `, - ]; - - override render(): unknown { - return html` -
- -
-
- -
- `; - } -} diff --git a/src/webviews/apps/welcome/components/feature-carousel.ts b/src/webviews/apps/welcome/components/feature-carousel.ts deleted file mode 100644 index 60161f6e20813..0000000000000 --- a/src/webviews/apps/welcome/components/feature-carousel.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { css, html, LitElement } from 'lit'; -import { customElement, queryAssignedElements, state } from 'lit/decorators.js'; -import '../../shared/components/button'; -import '../../shared/components/code-icon'; - -declare global { - interface HTMLElementTagNameMap { - 'gl-feature-carousel': GlFeatureCarousel; - } -} - -@customElement('gl-feature-carousel') -export class GlFeatureCarousel extends LitElement { - static override styles = [ - css` - :host { - display: block; - width: 100%; - } - - .carousel { - display: flex; - gap: 1em; - justify-content: center; - } - - .button { - display: flex; - align-items: center; - } - - .content { - flex: 1; - max-width: 520px; - display: flex; - align-items: center; - justify-content: center; - } - - ::slotted(*) { - display: none; - } - - ::slotted([data-active]) { - display: flex; - width: 100%; - } - `, - ]; - - @queryAssignedElements({ flatten: true }) - private cards!: HTMLElement[]; - - @state() - private currentIndex = 0; - - override firstUpdated(): void { - this.updateActiveCard(); - } - - private updateActiveCard(): void { - this.cards.forEach((card, index) => { - if (index === this.currentIndex) { - card.setAttribute('data-active', ''); - } else { - card.removeAttribute('data-active'); - } - }); - } - - private handlePrevious(): void { - if (this.cards.length === 0) return; - this.currentIndex = (this.currentIndex - 1 + this.cards.length) % this.cards.length; - this.updateActiveCard(); - } - - private handleNext(): void { - if (this.cards.length === 0) return; - this.currentIndex = (this.currentIndex + 1) % this.cards.length; - this.updateActiveCard(); - } - - private handleSlotChange(): void { - this.currentIndex = 0; - this.updateActiveCard(); - } - - override render(): unknown { - return html` - - `; - } -} diff --git a/src/webviews/apps/welcome/components/feature-narrow-card.ts b/src/webviews/apps/welcome/components/feature-narrow-card.ts deleted file mode 100644 index 7c84ea75c7182..0000000000000 --- a/src/webviews/apps/welcome/components/feature-narrow-card.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import '../../shared/components/button'; -import '../../shared/components/code-icon'; - -declare global { - interface HTMLElementTagNameMap { - 'gl-feature-narrow-card': GlFeatureNarrowCard; - } -} - -@customElement('gl-feature-narrow-card') -export class GlFeatureNarrowCard extends LitElement { - static override styles = [ - css` - :host { - display: flex; - flex-direction: column; - gap: 0.7em; - width: 12em; - min-width: 12em; - text-align: initial; - } - - .image ::slotted(img) { - max-height: 2.23em; - border-radius: 0.6em; - } - - ::slotted(p:last-child) { - margin-top: 0.5em; - } - - .content { - display: block; - } - - @media (max-width: 400px) { - .content { - margin-left: 0.3em; - margin-right: 0.3em; - } - } - `, - ]; - - override render(): unknown { - return html` -
- -
-
- -
- `; - } -} diff --git a/src/webviews/apps/welcome/components/scrollable-features.ts b/src/webviews/apps/welcome/components/scrollable-features.ts deleted file mode 100644 index e51e681c15547..0000000000000 --- a/src/webviews/apps/welcome/components/scrollable-features.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import '../../shared/components/button'; -import '../../shared/components/code-icon'; - -declare global { - interface HTMLElementTagNameMap { - 'gl-scrollable-features': GlScrollableFeatures; - } -} - -@customElement('gl-scrollable-features') -export class GlScrollableFeatures extends LitElement { - static override styles = [ - css` - :host { - --side-shadow-padding: 1em; - --side-shadow-color: transparent; - - --final-side-shadow-padding: max(var(--side-shadow-padding), 1em); - position: relative; - max-width: 100%; - } - - :host::before, - :host::after { - content: ' '; - position: absolute; - top: 0; - width: var(--final-side-shadow-padding); - height: 100%; - } - - :host::before { - left: 0; - background: linear-gradient(to left, transparent 0%, var(--side-shadow-color) 83%); - } - :host::after { - right: 0; - background: linear-gradient(to right, transparent 0%, var(--side-shadow-color) 83%); - } - - .content { - box-sizing: border-box; - padding: 0 var(--final-side-shadow-padding); - display: flex; - gap: 1em; - overflow-x: auto; - overflow-y: hidden; - scrollbar-width: none; - } - `, - ]; - - override render(): unknown { - return html`
`; - } -} diff --git a/src/webviews/apps/welcome/context.ts b/src/webviews/apps/welcome/context.ts deleted file mode 100644 index 23e34c3ce6190..0000000000000 --- a/src/webviews/apps/welcome/context.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createContext } from '@lit/context'; -import type { State } from '../../welcome/protocol'; - -export const stateContext = createContext('state'); diff --git a/src/webviews/apps/welcome/stateProvider.ts b/src/webviews/apps/welcome/stateProvider.ts deleted file mode 100644 index d75615aff6433..0000000000000 --- a/src/webviews/apps/welcome/stateProvider.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ContextProvider } from '@lit/context'; -import type { IpcMessage } from '../../protocol'; -import type { State } from '../../welcome/protocol'; -import type { ReactiveElementHost } from '../shared/appHost'; -import { StateProviderBase } from '../shared/stateProviderBase'; -import { stateContext } from './context'; - -export class WelcomeStateProvider extends StateProviderBase { - protected override createContextProvider(state: State): ContextProvider { - return new ContextProvider(this.host, { context: stateContext, initialValue: state }); - } - - protected override onMessageReceived(_msg: IpcMessage): void { - // Welcome webview doesn't need to handle any messages - } -} diff --git a/src/webviews/apps/welcome/welcome.html b/src/webviews/apps/welcome/welcome.html deleted file mode 100644 index 4bca43a8dc78f..0000000000000 --- a/src/webviews/apps/welcome/welcome.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - diff --git a/src/webviews/apps/welcome/welcome.scss b/src/webviews/apps/welcome/welcome.scss deleted file mode 100644 index c5d7179dbb3c9..0000000000000 --- a/src/webviews/apps/welcome/welcome.scss +++ /dev/null @@ -1,18 +0,0 @@ -// @use '../shared/styles/utils'; -@use '../shared/styles/theme'; - -// :root { -// --bg-color: green; -// } - -// @include utils.dark-theme() { -// --bg-color: red; -// } - -// @include utils.light-theme() { -// --bg-color: yellow; -// } -gl-welcome-app { - --page-margin: 20px; - --page-background-color: var(--vscode-editor-background); -} diff --git a/src/webviews/welcome/protocol.ts b/src/webviews/welcome/protocol.ts deleted file mode 100644 index da42f89197426..0000000000000 --- a/src/webviews/welcome/protocol.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { IpcScope, WebviewState } from '../protocol'; - -export const scope: IpcScope = 'welcome'; - -export interface State extends WebviewState<'gitlens.welcome'> { - version: string; -} diff --git a/src/webviews/welcome/registration.ts b/src/webviews/welcome/registration.ts deleted file mode 100644 index 20fe4c5466c9a..0000000000000 --- a/src/webviews/welcome/registration.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ViewColumn } from 'vscode'; -import type { WebviewPanelsProxy, WebviewsController } from '../webviewsController'; -import type { State } from './protocol'; - -export type WelcomeWebviewShowingArgs = []; - -export function registerWelcomeWebviewPanel( - controller: WebviewsController, -): WebviewPanelsProxy<'gitlens.welcome', WelcomeWebviewShowingArgs, State> { - return controller.registerWebviewPanel<'gitlens.welcome', State, State, WelcomeWebviewShowingArgs>( - { id: 'gitlens.showWelcomePage' }, - { - id: 'gitlens.welcome', - fileName: 'welcome.html', - iconPath: 'images/gitlens-icon.png', - title: 'Welcome to GitLens', - contextKeyPrefix: `gitlens:webview:welcome`, - trackingFeature: 'welcomeWebview', - type: 'welcome', - plusFeature: false, - column: ViewColumn.Active, - webviewHostOptions: { - retainContextWhenHidden: false, - enableFindWidget: false, - }, - }, - async (container, host) => { - const { WelcomeWebviewProvider } = await import( - /* webpackChunkName: "webview-welcome" */ './welcomeWebview' - ); - return new WelcomeWebviewProvider(container, host); - }, - ); -} diff --git a/src/webviews/welcome/welcomeWebview.ts b/src/webviews/welcome/welcomeWebview.ts deleted file mode 100644 index c193519455f29..0000000000000 --- a/src/webviews/welcome/welcomeWebview.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Disposable } from 'vscode'; -import type { WebviewTelemetryContext } from '../../constants.telemetry'; -import type { Container } from '../../container'; -import type { WebviewHost, WebviewProvider } from '../webviewProvider'; -import type { State } from './protocol'; -import type { WelcomeWebviewShowingArgs } from './registration'; - -export class WelcomeWebviewProvider implements WebviewProvider { - private readonly _disposable: Disposable; - - constructor( - private readonly container: Container, - private readonly host: WebviewHost<'gitlens.welcome'>, - ) { - this.host.title = 'Welcome to GitLens'; - this._disposable = Disposable.from(); - } - - dispose(): void { - this._disposable.dispose(); - } - - getTelemetryContext(): WebviewTelemetryContext { - return { - ...this.host.getTelemetryContext(), - }; - } - - includeBootstrap(): State { - return this.getState(); - } - - private getState(): State { - return { - webviewId: 'gitlens.welcome', - webviewInstanceId: this.host.instanceId, - timestamp: Date.now(), - version: this.container.version, - }; - } -} diff --git a/webpack.config.mjs b/webpack.config.mjs index 29900f9e3ce8e..7074299e6939e 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -390,7 +390,6 @@ function getWebviewsConfigs(mode, env) { settings: { entry: './settings/settings.ts' }, timeline: { entry: './plus/timeline/timeline.ts', plus: true }, patchDetails: { entry: './plus/patchDetails/patchDetails.ts', plus: true }, - welcome: { entry: './welcome/welcome.ts' }, }; if (env.webviews) { From b822922fef4927363a62cde788b48374b21b8a04 Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Thu, 11 Dec 2025 17:41:31 +0100 Subject: [PATCH 19/21] Improves layout of the welcome page in the sidebar (Home View) (#4769, #4773, PLG-138) --- src/webviews/apps/home/components/welcome-overlay.ts | 8 +++++++- src/webviews/apps/home/components/welcome-page.css.ts | 9 +++++---- src/webviews/apps/home/components/welcome-page.ts | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/webviews/apps/home/components/welcome-overlay.ts b/src/webviews/apps/home/components/welcome-overlay.ts index 38efc24f179c2..79e5383ed0ce0 100644 --- a/src/webviews/apps/home/components/welcome-overlay.ts +++ b/src/webviews/apps/home/components/welcome-overlay.ts @@ -39,6 +39,12 @@ export class GlWelcomeOverlay extends LitElement { gl-welcome-page { --page-background-color: var(--background-color); + --page-margin-left: 1rem; + --page-margin-right: 0.5rem; + } + + gl-welcome-page::part(page) { + padding: 0 0.5rem 0 1rem; } `, ]; @@ -73,7 +79,7 @@ export class GlWelcomeOverlay extends LitElement { .isLightTheme=${this.isLightTheme} closeable @close=${() => this.onClose()} - > + >
`; } diff --git a/src/webviews/apps/home/components/welcome-page.css.ts b/src/webviews/apps/home/components/welcome-page.css.ts index 81cb309b6f2ba..0153a4f1e2b10 100644 --- a/src/webviews/apps/home/components/welcome-page.css.ts +++ b/src/webviews/apps/home/components/welcome-page.css.ts @@ -64,7 +64,8 @@ const typography = css` const main = css` :host { - --page-margin: 0px; + --page-margin-left: 0px; + --page-margin-right: 0px; max-width: 100%; } @@ -161,8 +162,8 @@ const section = css` } .section.wide { - margin-left: calc(-1 * var(--page-margin)); - margin-right: calc(-1 * var(--page-margin)); + margin-left: calc(-1 * var(--page-margin-left)); + margin-right: calc(-1 * var(--page-margin-right)); } `; @@ -233,7 +234,7 @@ const cards = css` const scrollableFeatures = css` gl-scrollable-features { - --side-shadow-padding: var(--page-margin); + --side-shadow-padding: max(var(--page-margin-left), var(--page-margin-right)); --side-shadow-color: var(--page-background-color); } `; diff --git a/src/webviews/apps/home/components/welcome-page.ts b/src/webviews/apps/home/components/welcome-page.ts index 268067e9e3b75..e8dff65cfebe5 100644 --- a/src/webviews/apps/home/components/welcome-page.ts +++ b/src/webviews/apps/home/components/welcome-page.ts @@ -65,7 +65,7 @@ export class GlWelcomePage extends LitElement { override render(): unknown { const themeSuffix = this.isLightTheme ? 'light' : 'dark'; return html` -
+
${this.closeable ? html` Date: Thu, 11 Dec 2025 18:19:43 +0100 Subject: [PATCH 20/21] Upgrades carousel layout for narrow views to make it more "vertically oriented" (#4769, #4773, PLG-138) --- .../apps/home/components/welcome-parts.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/webviews/apps/home/components/welcome-parts.ts b/src/webviews/apps/home/components/welcome-parts.ts index aa1c04f50f710..1d92a2ba6430d 100644 --- a/src/webviews/apps/home/components/welcome-parts.ts +++ b/src/webviews/apps/home/components/welcome-parts.ts @@ -48,6 +48,25 @@ export class GlFeatureCarousel extends LitElement { display: flex; width: 100%; } + + @media (max-width: 400px) { + .carousel { + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: 1fr 1fr; + gap: 0.5em; + } + .content { + grid-column: 1; + grid-row: 1 / span 2; + } + .button { + grid-column: 2; + } + .button code-icon { + transform: rotate(90deg); + } + } `, ]; From aa5c4e9440a7f6af71c45bb6744df83ce040af4a Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Thu, 11 Dec 2025 19:51:48 +0100 Subject: [PATCH 21/21] Makes scrollable features vertically oriented on narrow sizes (#4769, #4773, PLG-138) --- .../apps/home/components/welcome-parts.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/webviews/apps/home/components/welcome-parts.ts b/src/webviews/apps/home/components/welcome-parts.ts index 1d92a2ba6430d..d13c31dbdaa94 100644 --- a/src/webviews/apps/home/components/welcome-parts.ts +++ b/src/webviews/apps/home/components/welcome-parts.ts @@ -249,6 +249,7 @@ export class GlScrollableFeatures extends LitElement { :host::after { content: ' '; position: absolute; + display: block; top: 0; width: var(--final-side-shadow-padding); height: 100%; @@ -272,6 +273,36 @@ export class GlScrollableFeatures extends LitElement { overflow-y: hidden; scrollbar-width: none; } + + @media (max-width: 400px) { + :host { + --final-side-shadow-padding: max(var(--side-shadow-padding), 2em); + margin-top: -1em; + } + :host::before, + :host::after { + height: var(--final-side-shadow-padding); + width: 100%; + left: 0; + right: 0; + } + :host::before { + position: sticky; + top: 0; + background: linear-gradient(to top, transparent 0%, var(--side-shadow-color) 83%); + } + :host::after { + position: fixed; + top: auto; + bottom: 0; + background: linear-gradient(to bottom, transparent 0%, var(--side-shadow-color) 83%); + } + .content { + flex-direction: column; + gap: 0.5em; + padding: 0; + } + } `, ];