Не подтверждена Коммит 110c6a9b создал по автору Bhavya U's avatar Bhavya U Зафиксировано автором GitHub
Просмотр файлов

update welcome experience (#246836)

владелец 705045f9
......@@ -286,6 +286,27 @@ registerAction2(class extends Action2 {
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'welcome.showNewWelcome',
title: localize2('welcome.showNewWelcome', 'Open New Welcome Experience'),
f1: true,
});
}
async run(accessor: ServicesAccessor) {
const editorService = accessor.get(IEditorService);
const options: GettingStartedEditorOptions = { selectedCategory: 'Setup', showNewExperience: true };
editorService.openEditor({
resource: GettingStartedInput.RESOURCE,
options
});
}
});
CommandsRegistry.registerCommand({
id: 'welcome.newWorkspaceChat',
handler: (accessor, stepID: string) => {
......
......@@ -925,13 +925,21 @@ export class GettingStartedPage extends EditorPane {
this.gettingStartedCategories = this.gettingStartedService.getWalkthroughs();
this.currentWalkthrough = this.gettingStartedCategories.find(category => category.id === this.editorInput.selectedCategory);
if (this.currentWalkthrough) {
this.buildCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedStep);
if (this.editorInput.showNewExperience === true) {
this.buildNewCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedStep);
} else {
this.buildCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedStep);
}
this.setSlide('details');
return;
}
}
else {
this.buildCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedStep);
if (this.editorInput.showNewExperience === true) {
this.buildNewCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedStep);
} else {
this.buildCategorySlide(this.editorInput.selectedCategory, this.editorInput.selectedStep);
}
this.setSlide('details');
return;
}
......@@ -1394,6 +1402,235 @@ export class GettingStartedPage extends EditorPane {
super.clearInput();
}
// Helper method to navigate between steps
private navigateStep(direction: number, steps: IResolvedWalkthroughStep[]) {
if (!this.editorInput.selectedStep) { return; }
const currentIndex = steps.findIndex(step => step.id === this.editorInput.selectedStep);
if (currentIndex === -1) { return; }
const newIndex = Math.max(0, Math.min(steps.length - 1, currentIndex + direction));
if (newIndex !== currentIndex) {
this.selectStepByIndex(newIndex, steps, direction);
}
}
private selectStepByIndex(newIndex: number, steps: IResolvedWalkthroughStep[], direction: number) {
const currentIndex = steps.findIndex(step => step.id === this.editorInput.selectedStep);
const slidesContainer = this.stepsContent.querySelector('.step-slides-container') as HTMLElement;
if (slidesContainer) {
// Apply the transform to move the slides
const slides = slidesContainer.querySelectorAll('.step-slide');
// First make all slides visible for the animation
slides.forEach((slide, index) => {
const slideElement = slide as HTMLElement;
// Position all slides in their starting positions
if (index === currentIndex) {
slideElement.style.display = 'block';
slideElement.style.transform = 'translateX(0)';
} else if (index === newIndex) {
slideElement.style.display = 'block';
slideElement.style.transform = `translateX(${direction < 0 ? '-100%' : '100%'})`;
} else {
slideElement.style.display = 'none';
}
});
// Force a reflow to ensure the initial positions are applied
slidesContainer.getBoundingClientRect();
// Now animate to the final positions
setTimeout(() => {
slides.forEach((slide, index) => {
const slideElement = slide as HTMLElement;
if (index === currentIndex) {
slideElement.style.transform = `translateX(${direction > 0 ? '-100%' : '100%'})`;
setTimeout(() => {
slideElement.style.display = 'none';
}, SLIDE_TRANSITION_TIME_MS);
} else if (index === newIndex) {
slideElement.style.transform = 'translateX(0)';
}
});
}, 20);
// Update the active dot
const dots = this.stepsContent.querySelectorAll('.step-dot');
dots.forEach((dot, index) => {
if (index === newIndex) {
dot.classList.add('active');
} else {
dot.classList.remove('active');
}
});
// Update the selected step and build its media
this.selectSlide(steps[newIndex].id);
}
}
private buildNewCategorySlide(categoryID: string, selectedStep?: string) {
this.container.classList.add('newSlide');
if (this.detailsScrollbar) { this.detailsScrollbar.dispose(); }
this.detailsPageDisposables.clear();
this.mediaDisposables.clear();
const category = this.gettingStartedCategories.find(category => category.id === categoryID);
if (!category) {
throw Error('could not find category with ID ' + categoryID);
}
// Filter steps based on when context
const steps = category.steps.filter(step => this.contextService.contextMatchesRules(step.when));
// Create the slide container that will hold all step slides
const slidesContainer = $('.step-slides-container');
// Create the dots navigation
const dotsContainer = $('.step-dots-container');
// For each step, create a slide
steps.forEach((step, index) => {
// Create the slide
const slideElement = $('.step-slide', { 'data-step': step.id });
// Create the content container with flex layout
const slideContent = $('.step-slide-content');
// Text content column
const textContent = $('.step-text-content');
// Create step title
const titleElement = $('h3.step-title', { 'x-step-title-for': step.id });
reset(titleElement, ...renderLabelWithIcons(step.title));
textContent.appendChild(titleElement);
// Create step description container
const descriptionContainer = $('.step-description', { 'x-step-description-for': step.id });
this.buildMarkdownDescription(descriptionContainer, step.description);
textContent.appendChild(descriptionContainer);
// Add buttons container if needed
const actionsContainer = $('.step-actions');
textContent.appendChild(actionsContainer);
// Append text content to the slide
slideContent.appendChild(textContent);
// Add completed slide to the slides container
slideElement.appendChild(slideContent);
slidesContainer.appendChild(slideElement);
// Create a dot for this slide in the navigation - now with click handlers
const dot = $('button.step-dot', {
'data-step-dot-index': `${index}`,
'aria-label': localize('goToStep', "Go to step {0}", step.title),
'role': 'button'
});
if ((!selectedStep && index === 0) || (selectedStep === step.id)) {
dot.classList.add('active');
}
// Add event listeners directly to the dots
this.detailsPageDisposables.add(addDisposableListener(dot, 'click', () => {
const currentIndex = steps.findIndex(step => step.id === this.editorInput.selectedStep);
if (currentIndex !== index) {
const direction = index > currentIndex ? 1 : -1;
this.selectStepByIndex(index, steps, direction);
}
}));
dotsContainer.appendChild(dot);
});
// Handle initial selected step
let initialStepIndex = 0;
if (selectedStep) {
initialStepIndex = steps.findIndex(step => step.id === selectedStep);
if (initialStepIndex === -1) { initialStepIndex = 0; }
}
// Set the current walkthrough and step
this.currentWalkthrough = category;
this.editorInput.selectedCategory = categoryID;
this.editorInput.selectedStep = steps[initialStepIndex].id;
// Search through slidesContainer for slideElement with data-step attribute matching selectedStep.id
// then fetch the slideContent and append mediaComponent to it
const selectedSlide = slidesContainer.querySelector(`.step-slide[data-step="${steps[initialStepIndex].id}"]`);
if (selectedSlide) {
const selectedSlideContent = selectedSlide.querySelector('.step-slide-content');
this.buildMediaComponent(steps[initialStepIndex].id);
selectedSlideContent?.appendChild(this.stepMediaComponent);
}
// Category title and description
const categoryHeader = $('.category-header');
const categoryTitle = $('h2.category-title', { 'x-category-title-for': category.id });
reset(categoryTitle, ...renderLabelWithIcons(category.title));
categoryHeader.appendChild(categoryTitle);
// Build the container for the whole slide deck
const stepsContainer = $('.getting-started-steps-container', {},
categoryHeader,
slidesContainer,
dotsContainer
);
// Set up the scroll container
this.detailsScrollbar = this._register(new DomScrollableElement(stepsContainer, { className: 'steps-container' }));
const stepListComponent = this.detailsScrollbar.getDomNode();
// Append to the content area
reset(this.stepsContent, stepListComponent);
// Add keyboard navigation
this.detailsPageDisposables.add(addDisposableListener(dotsContainer, 'keydown', (e) => {
const event = new StandardKeyboardEvent(e);
if (event.keyCode === KeyCode.RightArrow) {
this.navigateStep(1, steps);
} else if (event.keyCode === KeyCode.LeftArrow) {
this.navigateStep(-1, steps);
}
}));
// Register listeners for step selection
this.registerDispatchListeners();
// Add handler for the step selection event
this.detailsPageDisposables.add(this.stepDisposables);
this.detailsScrollbar.scanDomNode();
this.detailsPageScrollbar?.scanDomNode();
}
private selectSlide(stepId: string) {
this.editorInput.selectedStep = stepId;
const step = this.currentWalkthrough?.steps.find(step => step.id === stepId);
if (!step) { return; }
const selectedSlide = this.stepsContent.querySelector(`.step-slide[data-step="${stepId}"]`);
if (selectedSlide) {
const selectedSlideContent = selectedSlide.querySelector('.step-slide-content');
this.mediaDisposables.clear();
this.stepDisposables.clear();
this.buildMediaComponent(this.editorInput.selectedStep);
selectedSlideContent?.appendChild(this.stepMediaComponent);
setTimeout(() => (selectedSlideContent as HTMLElement).focus(), 0);
}
this.gettingStartedService.progressByEvent('stepSelected:' + stepId);
this.detailsPageScrollbar?.scanDomNode();
this.detailsScrollbar?.scanDomNode();
}
private buildCategorySlide(categoryID: string, selectedStep?: string) {
if (this.detailsScrollbar) { this.detailsScrollbar.dispose(); }
......@@ -1627,8 +1864,12 @@ export class GettingStartedPage extends EditorPane {
const prevButton = this.container.querySelector<HTMLButtonElement>('.prev-button.button-link');
prevButton!.style.display = this.editorInput.showWelcome || this.prevWalkthrough ? 'block' : 'none';
const moreTextElement = prevButton!.querySelector('.moreText');
moreTextElement!.textContent = firstLaunch ? localize('welcome', "Welcome") : localize('goBack', "Go Back");
if (this.editorInput.showNewExperience) {
prevButton!.style.display = 'none';
} else {
const moreTextElement = prevButton!.querySelector('.moreText');
moreTextElement!.textContent = firstLaunch ? localize('welcome', "Welcome") : localize('goBack', "Go Back");
}
this.container.querySelector('.gettingStartedSlideDetails')!.querySelectorAll('button').forEach(button => button.disabled = false);
this.container.querySelector('.gettingStartedSlideCategories')!.querySelectorAll('button').forEach(button => button.disabled = true);
......
......@@ -19,6 +19,7 @@ export interface GettingStartedEditorOptions extends IEditorOptions {
showTelemetryNotice?: boolean;
showWelcome?: boolean;
walkthroughPageTitle?: string;
showNewExperience?: boolean;
}
export class GettingStartedInput extends EditorInput {
......@@ -29,6 +30,8 @@ export class GettingStartedInput extends EditorInput {
private _selectedStep: string | undefined;
private _showTelemetryNotice: boolean;
private _showWelcome: boolean;
private _showNewExperience: boolean;
private _walkthroughPageTitle: string | undefined;
override get typeId(): string {
......@@ -72,6 +75,7 @@ export class GettingStartedInput extends EditorInput {
this._showTelemetryNotice = !!options.showTelemetryNotice;
this._showWelcome = options.showWelcome ?? true;
this._walkthroughPageTitle = options.walkthroughPageTitle;
this._showNewExperience = options.showNewExperience ?? false;
}
override getName() {
......@@ -118,4 +122,12 @@ export class GettingStartedInput extends EditorInput {
set walkthroughPageTitle(value: string | undefined) {
this._walkthroughPageTitle = value;
}
get showNewExperience(): boolean {
return this._showNewExperience;
}
set showNewExperience(value: boolean) {
this._showNewExperience = value;
}
}
......@@ -134,7 +134,8 @@
grid-template-areas: "left-column" "right-column" "footer";
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.width-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header, .monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header {
.monaco-workbench .part.editor > .content .gettingStartedContainer.width-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header,
.monaco-workbench .part.editor > .content .gettingStartedContainer.height-constrained .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .header {
display: none;
}
......@@ -142,7 +143,8 @@
display: none;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.noWalkthroughs .gettingStartedSlideCategories li.showWalkthroughsEntry, .gettingStartedContainer.noExtensions {
.monaco-workbench .part.editor > .content .gettingStartedContainer.noWalkthroughs .gettingStartedSlideCategories li.showWalkthroughsEntry,
.gettingStartedContainer.noExtensions {
display: unset;
}
......@@ -299,7 +301,7 @@
font-size: 16px;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content:not(:empty){
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-category .description-content:not(:empty) {
margin-bottom: 8px;
}
......@@ -360,6 +362,7 @@
position: relative;
top: auto;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-category img.category-icon {
margin-right: 10px;
margin-left: 10px;
......@@ -583,7 +586,7 @@
grid-area: steps-start / media-start / footer-start / media-end;
align-self: self-start;
display: flex;
justify-content:center ;
justify-content: center;
height: 100%;
width: 100%;
}
......@@ -655,7 +658,7 @@
display: inline;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.noWalkthroughs .index-list.getting-started {
.monaco-workbench .part.editor > .content .gettingStartedContainer.noWalkthroughs .index-list.getting-started {
display: none;
}
......@@ -810,7 +813,8 @@
background: transparent;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .openAWalkthrough > button, .monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .showOnStartup {
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .openAWalkthrough > button,
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .showOnStartup {
text-align: center;
display: flex;
justify-content: center;
......@@ -829,7 +833,7 @@
}
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox.codicon:not(.checked)::before {
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox.codicon:not(.checked)::before {
opacity: 0;
}
......@@ -867,7 +871,8 @@
line-height: 1.3em;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container .monaco-button, .monaco-workbench .part.editor > .content .gettingStartedContainer .max-lines-3 {
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideDetails .getting-started-step .step-description-container .monaco-button,
.monaco-workbench .part.editor > .content .gettingStartedContainer .max-lines-3 {
/* Supported everywhere: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp#browser_compatibility */
-webkit-line-clamp: 3;
display: -webkit-box;
......@@ -936,7 +941,7 @@
outline-color: var(--vscode-contrastActiveBorder, var(--vscode-focusBorder));
}
.monaco-workbench .part.editor > .content .gettingStartedContainer button.expanded:hover {
.monaco-workbench .part.editor > .content .gettingStartedContainer button.expanded:hover {
background: var(--vscode-welcomePage-tileBackground);
}
......@@ -974,7 +979,7 @@
color: var(--vscode-textLink-activeForeground);
}
.monaco-workbench .part.editor > .content .gettingStartedContainer a:not(.hide-category-button):active {
.monaco-workbench .part.editor > .content .gettingStartedContainer a:not(.hide-category-button):active {
color: var(--vscode-textLink-activeForeground);
}
......@@ -994,7 +999,7 @@
border: 1px solid var(--vscode-contrastBorder);
}
.monaco-workbench .part.editor > .content .gettingStartedContainer button.button-link {
.monaco-workbench .part.editor > .content .gettingStartedContainer button.button-link {
border: inherit;
}
......@@ -1029,3 +1034,208 @@
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlide .getting-started-checkbox {
border-color: var(--vscode-checkbox-border) !important;
}
/* Full width layout for the new slide design */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .gettingStartedDetailsContent {
height: 100%;
width: 100%;
max-width: 100%;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
}
/* Back button position */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .gettingStartedDetailsContent > .prev-button {
padding: 16px 32px 0;
position: static;
margin: 0;
}
/* Title area */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-category,
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .category-header {
padding: 16px 32px;
border-bottom: 1px solid var(--vscode-welcomePage-tileBorder);
text-align: center;
align-self: center;
max-width: 800px;
margin: 0 auto;
}
/* Steps container - takes most of the space */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .gettingStartedDetailsContent > .steps-container {
flex: 1;
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Hide the default media container */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-media {
display: none;
}
/* Getting Started Steps Container */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .getting-started-steps-container {
padding: 20px;
max-width: 1000px;
margin: 0 auto;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
/* Step slides container */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-slides-container {
display: flex;
overflow: hidden;
margin: 30px 0;
position: relative;
flex: 1;
width: 100%;
transition: transform 0.6s ease;
}
/* Individual slide styling */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-slide {
min-width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
transition: transform 0.6s ease;
padding: 0 32px;
}
/* Two-column layout for slide content */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-slide-content {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: "text media";
max-width: 1200px;
width: 100%;
height: 100%;
gap: 40px;
}
/* Left column - text content only */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-text-content {
grid-area: text;
display: flex;
flex-direction: column;
justify-content: center;
padding-right: 16px;
min-height: 300px;
height: 100%;
}
/* Right column - for media content */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-media-content {
grid-area: media;
display: flex;
align-items: center;
justify-content: center;
min-height: 300px;
height: 100%;
}
/* Navigation dots */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-dots-container {
display: flex;
justify-content: center;
gap: 6px;
margin: 12px 0;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-dot {
width: 8px;
height: 8px;
background-color: var(--vscode-button-secondaryBackground);
border: none;
border-radius: 50%;
cursor: pointer;
padding: 0;
transition: transform 0.2s ease, background-color 0.2s ease;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-dot:hover {
transform: scale(1.2);
background-color: var(--vscode-button-secondaryHoverBackground);
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-dot.active {
background-color: var(--vscode-button-background);
width: 9px;
height: 9px;
}
/* Footer area */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .gettingStartedDetailsContent > .getting-started-footer,
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .getting-started-footer {
padding: 16px 0;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
border-top: 1px solid var(--vscode-welcomePage-tileBorder);
}
/* Step title styling */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide h3.step-title {
font-size: 1.5em;
margin: 0 0 16px 0;
padding: 0;
}
/* Responsive design - stack on smaller screens */
@media (max-width: 900px) {
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-slide-content {
grid-template-columns: 1fr;
grid-template-areas:
"text"
"media";
gap: 24px;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-text-content {
padding-right: 0;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-media-content {
min-height: 200px;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-slide {
padding: 0 16px;
}
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-text-content,
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .step-media-content {
min-height: unset;
height: auto;
}
}
/* Animation for slide transitions */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide.animatable .step-slides-container {
transition: transform 0.25s ease;
}
/* Low motion preference */
.monaco-workbench.reduce-motion .part.editor > .content .gettingStartedContainer.newSlide .step-slides-container {
transition: none;
}
/* Hide moreText and prev-button in newSlide scenarios */
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .moreText,
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .prev-button,
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .prev-button.button-link,
.monaco-workbench .part.editor > .content .gettingStartedContainer.newSlide .gettingStartedSlideDetails .prev-button {
display: none;
}
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать