@theia/getting-started 1.76.0-next.14 → 1.76.0-next.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/lib/browser/getting-started-frontend-module.d.ts.map +1 -1
- package/lib/browser/getting-started-frontend-module.js +3 -0
- package/lib/browser/getting-started-frontend-module.js.map +1 -1
- package/lib/browser/getting-started-widget.d.ts +0 -7
- package/lib/browser/getting-started-widget.d.ts.map +1 -1
- package/lib/browser/getting-started-widget.js +1 -29
- package/lib/browser/getting-started-widget.js.map +1 -1
- package/lib/browser/walkthrough-section.d.ts +2 -2
- package/lib/browser/walkthrough-section.d.ts.map +1 -1
- package/lib/browser/walkthrough-section.js +7 -5
- package/lib/browser/walkthrough-section.js.map +1 -1
- package/lib/browser/walkthrough-section.spec.js +17 -1
- package/lib/browser/walkthrough-section.spec.js.map +1 -1
- package/lib/browser/walkthrough-service.d.ts +26 -5
- package/lib/browser/walkthrough-service.d.ts.map +1 -1
- package/lib/browser/walkthrough-service.js +77 -22
- package/lib/browser/walkthrough-service.js.map +1 -1
- package/lib/browser/walkthrough-service.spec.js +173 -57
- package/lib/browser/walkthrough-service.spec.js.map +1 -1
- package/lib/common/walkthrough-provider.d.ts +22 -0
- package/lib/common/walkthrough-provider.d.ts.map +1 -0
- package/lib/common/walkthrough-provider.js +27 -0
- package/lib/common/walkthrough-provider.js.map +1 -0
- package/lib/common/walkthrough-types.d.ts +18 -5
- package/lib/common/walkthrough-types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/browser/getting-started-frontend-module.ts +3 -0
- package/src/browser/getting-started-widget.tsx +31 -101
- package/src/browser/style/index.css +69 -35
- package/src/browser/walkthrough-section.spec.tsx +29 -1
- package/src/browser/walkthrough-section.tsx +7 -5
- package/src/browser/walkthrough-service.spec.ts +207 -57
- package/src/browser/walkthrough-service.ts +82 -25
- package/src/common/walkthrough-provider.ts +38 -0
- package/src/common/walkthrough-types.ts +20 -5
|
@@ -53,8 +53,39 @@ body {
|
|
|
53
53
|
height: 100%;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/*
|
|
57
|
+
* Centred in a readable measure instead of stretching across the whole view: with the side bars collapsed the
|
|
58
|
+
* welcome page is as wide as the window, and full-width content drifts apart towards the edges.
|
|
59
|
+
*/
|
|
56
60
|
.gs-content-container {
|
|
57
61
|
padding: 20px;
|
|
62
|
+
box-sizing: border-box;
|
|
63
|
+
width: 100%;
|
|
64
|
+
max-width: 1400px;
|
|
65
|
+
margin: 0 auto;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* The welcome content below the header: the regular sections on the left, the walkthroughs on the right.
|
|
70
|
+
* Both columns keep a sensible minimum width and wrap onto each other in a narrow window.
|
|
71
|
+
*/
|
|
72
|
+
.gs-columns {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
align-items: flex-start;
|
|
76
|
+
gap: calc(var(--theia-ui-padding) * 8);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Even shares, so that the walkthroughs sit next to the sections rather than pushed against the edge. */
|
|
80
|
+
.gs-main-column,
|
|
81
|
+
.gs-side-column {
|
|
82
|
+
flex: 1 1 340px;
|
|
83
|
+
min-width: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Without a walkthrough to offer, the column must not hold on to its share of the width. */
|
|
87
|
+
.gs-side-column:empty {
|
|
88
|
+
display: none;
|
|
58
89
|
}
|
|
59
90
|
|
|
60
91
|
.gs-content-container a {
|
|
@@ -116,46 +147,19 @@ body {
|
|
|
116
147
|
align-items: center;
|
|
117
148
|
}
|
|
118
149
|
|
|
119
|
-
.gs-float {
|
|
120
|
-
float: right;
|
|
121
|
-
width: 50%;
|
|
122
|
-
margin-top: 100px;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.gs-container.gs-aifeature-container {
|
|
126
|
-
border: 1px solid var(--theia-focusBorder);
|
|
127
|
-
padding: 15px;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.shadow-pulse {
|
|
131
|
-
animation: shadowPulse 2s infinite ease-in-out;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@keyframes shadowPulse {
|
|
135
|
-
|
|
136
|
-
0%,
|
|
137
|
-
100% {
|
|
138
|
-
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
50% {
|
|
142
|
-
box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
150
|
/* Walkthrough styles */
|
|
147
151
|
|
|
148
152
|
/* The cards form a quiet single column: card-like blocks, but without borders. */
|
|
149
153
|
.gs-walkthrough-cards {
|
|
150
154
|
display: flex;
|
|
151
155
|
flex-direction: column;
|
|
152
|
-
gap: var(--theia-ui-padding);
|
|
153
|
-
margin-top: var(--theia-ui-padding);
|
|
156
|
+
gap: calc(var(--theia-ui-padding) * 2);
|
|
157
|
+
margin-top: calc(var(--theia-ui-padding) * 2);
|
|
154
158
|
max-width: 640px;
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
.gs-walkthrough-card {
|
|
158
|
-
padding: calc(var(--theia-ui-padding) *
|
|
162
|
+
padding: calc(var(--theia-ui-padding) * 2.5);
|
|
159
163
|
border-radius: calc(var(--theia-ui-padding) / 2);
|
|
160
164
|
cursor: pointer;
|
|
161
165
|
background-color: var(--theia-walkthrough-card-background);
|
|
@@ -203,25 +207,31 @@ body {
|
|
|
203
207
|
object-fit: contain;
|
|
204
208
|
}
|
|
205
209
|
|
|
206
|
-
/*
|
|
210
|
+
/*
|
|
211
|
+
* Wraps, but no further than two lines, so that a description is readable in the narrow side column
|
|
212
|
+
* without any single card growing out of proportion.
|
|
213
|
+
*/
|
|
207
214
|
.gs-walkthrough-card-description {
|
|
208
215
|
color: var(--theia-descriptionForeground);
|
|
209
216
|
font-size: var(--theia-ui-font-size0);
|
|
210
217
|
margin: 0;
|
|
218
|
+
display: -webkit-box;
|
|
219
|
+
-webkit-box-orient: vertical;
|
|
220
|
+
-webkit-line-clamp: 2;
|
|
221
|
+
line-clamp: 2;
|
|
211
222
|
overflow: hidden;
|
|
212
|
-
text-overflow: ellipsis;
|
|
213
|
-
white-space: nowrap;
|
|
214
223
|
}
|
|
215
224
|
|
|
216
225
|
.gs-walkthrough-card-progress {
|
|
217
226
|
display: flex;
|
|
218
227
|
align-items: center;
|
|
219
228
|
gap: var(--theia-ui-padding);
|
|
220
|
-
margin-top: var(--theia-ui-padding);
|
|
229
|
+
margin-top: calc(var(--theia-ui-padding) * 2);
|
|
221
230
|
}
|
|
222
231
|
|
|
232
|
+
/* Uses whatever width the card offers rather than a fixed one, which would leave a gap in a wide card. */
|
|
223
233
|
.gs-walkthrough-progress-bar {
|
|
224
|
-
flex:
|
|
234
|
+
flex: 1 1 auto;
|
|
225
235
|
height: calc(var(--theia-ui-padding) / 3);
|
|
226
236
|
background-color: var(--theia-walkthrough-progress-background);
|
|
227
237
|
border-radius: calc(var(--theia-ui-padding) / 3);
|
|
@@ -242,6 +252,30 @@ body {
|
|
|
242
252
|
white-space: nowrap;
|
|
243
253
|
}
|
|
244
254
|
|
|
255
|
+
/*
|
|
256
|
+
* A link that stands alone in its paragraph is an action rather than a reference, so a step can offer it as a
|
|
257
|
+
* button. Links inside a sentence keep reading as links, which is what the `:only-child` restriction buys.
|
|
258
|
+
*/
|
|
259
|
+
.gs-walkthrough-step-description p > a:only-child {
|
|
260
|
+
display: inline-block;
|
|
261
|
+
padding: calc(var(--theia-ui-padding) / 2) calc(var(--theia-ui-padding) * 2);
|
|
262
|
+
border: var(--theia-border-width) solid var(--theia-button-border);
|
|
263
|
+
border-radius: calc(var(--theia-ui-padding) / 2);
|
|
264
|
+
background-color: var(--theia-button-background);
|
|
265
|
+
color: var(--theia-button-foreground);
|
|
266
|
+
text-decoration: none;
|
|
267
|
+
cursor: pointer;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.gs-walkthrough-step-description p > a:only-child:hover {
|
|
271
|
+
background-color: var(--theia-button-hoverBackground);
|
|
272
|
+
text-decoration: none;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.gs-walkthrough-step-description p > a:only-child:focus {
|
|
276
|
+
outline: var(--theia-border-width) solid var(--theia-focusBorder);
|
|
277
|
+
}
|
|
278
|
+
|
|
245
279
|
.gs-walkthrough-more {
|
|
246
280
|
display: inline-block;
|
|
247
281
|
margin-top: calc(var(--theia-ui-padding) / 2);
|
|
@@ -400,7 +400,9 @@ describe('WalkthroughSection', () => {
|
|
|
400
400
|
}, 50);
|
|
401
401
|
});
|
|
402
402
|
it('should list at most WALKTHROUGH_LIST_LIMIT walkthroughs and delegate More... to the picker', done => {
|
|
403
|
-
|
|
403
|
+
// One more than fits, so that the assertions hold whatever the limit is.
|
|
404
|
+
const walkthroughs = Array.from({ length: WALKTHROUGH_LIST_LIMIT + 1 },
|
|
405
|
+
(_, i) => createMockWalkthrough({ id: `wt${i}`, title: `WT ${i}` }));
|
|
404
406
|
const mockService = createMockWalkthroughService(walkthroughs);
|
|
405
407
|
let showAllCalled = false;
|
|
406
408
|
|
|
@@ -459,6 +461,32 @@ describe('WalkthroughSection', () => {
|
|
|
459
461
|
}, 50);
|
|
460
462
|
});
|
|
461
463
|
|
|
464
|
+
it('should render nothing once every walkthrough is complete', done => {
|
|
465
|
+
const walkthroughs = [createMockWalkthrough({
|
|
466
|
+
id: 'done',
|
|
467
|
+
title: 'Done',
|
|
468
|
+
steps: [createMockStep({ id: 's1', isComplete: true })]
|
|
469
|
+
})];
|
|
470
|
+
const mockService = createMockWalkthroughService(walkthroughs);
|
|
471
|
+
|
|
472
|
+
root.render(
|
|
473
|
+
<WalkthroughSection
|
|
474
|
+
walkthroughService={mockService as unknown as WalkthroughService}
|
|
475
|
+
markdownRenderer={mockRenderer}
|
|
476
|
+
themeService={createMockThemeService()}
|
|
477
|
+
logger={createMockLogger()}
|
|
478
|
+
onShowAll={() => { }}
|
|
479
|
+
/>
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
setTimeout(() => {
|
|
483
|
+
// Not even the heading: the section must not hold on to its place in the welcome page.
|
|
484
|
+
// eslint-disable-next-line no-null/no-null
|
|
485
|
+
assert.strictEqual(container.querySelector('.gs-section'), null, 'Should not render the section');
|
|
486
|
+
done();
|
|
487
|
+
}, 50);
|
|
488
|
+
});
|
|
489
|
+
|
|
462
490
|
it('should not offer More... when every walkthrough is listed', done => {
|
|
463
491
|
const walkthroughs = [1, 2].map(i => createMockWalkthrough({ id: `wt${i}`, title: `WT ${i}` }));
|
|
464
492
|
const mockService = createMockWalkthroughService(walkthroughs);
|
|
@@ -35,8 +35,8 @@ export interface WalkthroughSectionProps {
|
|
|
35
35
|
onShowAll?: () => void;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/** How many walkthroughs are listed on the welcome page
|
|
39
|
-
export const WALKTHROUGH_LIST_LIMIT =
|
|
38
|
+
/** How many walkthroughs are listed on the welcome page; the rest stay behind `More...`. */
|
|
39
|
+
export const WALKTHROUGH_LIST_LIMIT = 5;
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Renders the list of contributed walkthroughs, or the currently selected walkthrough.
|
|
@@ -77,12 +77,14 @@ export function WalkthroughSection(props: WalkthroughSectionProps): React.ReactE
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const walkthroughs = walkthroughService.getWalkthroughs();
|
|
80
|
-
|
|
80
|
+
// A finished walkthrough has nothing left to offer here; it stays reachable through the
|
|
81
|
+
// `walkthrough.open` command. Once none is pending the section renders nothing at all, so that it does not
|
|
82
|
+
// hold on to its place in the welcome page for an empty heading.
|
|
83
|
+
const pending = walkthroughs.filter(walkthrough => walkthrough.steps.some(step => !step.isComplete));
|
|
84
|
+
if (pending.length === 0) {
|
|
81
85
|
return <React.Fragment />;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
// A finished walkthrough has nothing left to offer here; it stays reachable through `onShowAll`.
|
|
85
|
-
const pending = walkthroughs.filter(walkthrough => walkthrough.steps.some(step => !step.isComplete));
|
|
86
88
|
const listed = pending.slice(0, WALKTHROUGH_LIST_LIMIT);
|
|
87
89
|
return (
|
|
88
90
|
<div className='gs-section'>
|