@theia/getting-started 1.76.0-next.16 → 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.
Files changed (36) hide show
  1. package/README.md +44 -0
  2. package/lib/browser/getting-started-frontend-module.d.ts.map +1 -1
  3. package/lib/browser/getting-started-frontend-module.js +3 -0
  4. package/lib/browser/getting-started-frontend-module.js.map +1 -1
  5. package/lib/browser/getting-started-widget.d.ts +0 -7
  6. package/lib/browser/getting-started-widget.d.ts.map +1 -1
  7. package/lib/browser/getting-started-widget.js +1 -29
  8. package/lib/browser/getting-started-widget.js.map +1 -1
  9. package/lib/browser/walkthrough-section.d.ts +2 -2
  10. package/lib/browser/walkthrough-section.d.ts.map +1 -1
  11. package/lib/browser/walkthrough-section.js +7 -5
  12. package/lib/browser/walkthrough-section.js.map +1 -1
  13. package/lib/browser/walkthrough-section.spec.js +17 -1
  14. package/lib/browser/walkthrough-section.spec.js.map +1 -1
  15. package/lib/browser/walkthrough-service.d.ts +26 -5
  16. package/lib/browser/walkthrough-service.d.ts.map +1 -1
  17. package/lib/browser/walkthrough-service.js +77 -22
  18. package/lib/browser/walkthrough-service.js.map +1 -1
  19. package/lib/browser/walkthrough-service.spec.js +173 -57
  20. package/lib/browser/walkthrough-service.spec.js.map +1 -1
  21. package/lib/common/walkthrough-provider.d.ts +22 -0
  22. package/lib/common/walkthrough-provider.d.ts.map +1 -0
  23. package/lib/common/walkthrough-provider.js +27 -0
  24. package/lib/common/walkthrough-provider.js.map +1 -0
  25. package/lib/common/walkthrough-types.d.ts +18 -5
  26. package/lib/common/walkthrough-types.d.ts.map +1 -1
  27. package/package.json +8 -8
  28. package/src/browser/getting-started-frontend-module.ts +3 -0
  29. package/src/browser/getting-started-widget.tsx +31 -101
  30. package/src/browser/style/index.css +69 -35
  31. package/src/browser/walkthrough-section.spec.tsx +29 -1
  32. package/src/browser/walkthrough-section.tsx +7 -5
  33. package/src/browser/walkthrough-service.spec.ts +207 -57
  34. package/src/browser/walkthrough-service.ts +82 -25
  35. package/src/common/walkthrough-provider.ts +38 -0
  36. 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) * 1.5) calc(var(--theia-ui-padding) * 2);
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
- /* Kept to a single line so that every card stays the same height. */
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: 0 1 180px;
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
- const walkthroughs = [1, 2, 3, 4, 5].map(i => createMockWalkthrough({ id: `wt${i}`, title: `WT ${i}` }));
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 = 2;
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
- if (walkthroughs.length === 0) {
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'>