Skip to content

Commit 088c1a6

Browse files
committed
feat: add support for terminals
1 parent 85ef186 commit 088c1a6

53 files changed

Lines changed: 1749 additions & 521 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
24

docs/reference/packages.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
| **@eclipse-docks/extension-media-viewer** | Media (image, etc.) viewer. |
1414
| **@eclipse-docks/extension-notebook** | Notebook runtime and UI. |
1515
| **@eclipse-docks/extension-python-runtime** | Python runtime (e.g. Pyodide). |
16-
| **@eclipse-docks/extension-linuxterminal** | Terminal. |
1716
| **@eclipse-docks/extension-webllm** | Web LLM integration. |
1817
| **@eclipse-docks/extension-in-browser-ml** | In-browser ML (e.g. transformers). |
1918
| **@eclipse-docks/extension-rag-system** | RAG (retrieval-augmented generation) and document indexing. |

package-lock.json

Lines changed: 30 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
"workspaces": [
1313
"packages/*"
1414
],
15+
"engines": {
16+
"node": ">=20.12.0"
17+
},
1518
"publishConfig": {
1619
"access": "public"
1720
},
@@ -23,6 +26,7 @@
2326
"build:app-e2e": "npm run build -w @eclipse-docks/core && npm run build -w @eclipse-docks/app-e2e",
2427
"preview": "npm run preview -w @eclipse-docks/app",
2528
"type-check": "npm run type-check -w @eclipse-docks/core",
29+
"pretest": "node scripts/check-node-version.cjs",
2630
"test": "npm run test --workspaces --if-present",
2731
"test:e2e": "npm run test:e2e -w @eclipse-docks/app-e2e",
2832
"test:e2e:stories": "npm run test:e2e:stories -w @eclipse-docks/app-e2e",

packages/app/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@
1414
"@eclipse-docks/extension-ai-system": "*",
1515
"@eclipse-docks/extension-catalog": "*",
1616
"@eclipse-docks/extension-command-palette": "*",
17-
"@eclipse-docks/extension-command-shell": "*",
17+
"@eclipse-docks/extension-terminal": "*",
1818
"@eclipse-docks/extension-cereusdb": "*",
1919
"@eclipse-docks/extension-dataviewer": "*",
2020
"@eclipse-docks/extension-duckdb": "*",
2121
"@eclipse-docks/extension-github-service": "*",
2222
"@eclipse-docks/extension-howto-system": "*",
2323
"@eclipse-docks/extension-in-browser-ml": "*",
24-
"@eclipse-docks/extension-linuxterminal": "*",
2524
"@eclipse-docks/extension-md-editor": "*",
2625
"@eclipse-docks/extension-media-viewer": "*",
2726
"@eclipse-docks/extension-memory-usage": "*",

packages/app/src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ appLoaderService.registerApp(
4141
releaseHistory: fetchReleases,
4242
extensions: [
4343
'@eclipse-docks/extension-command-palette',
44-
'@eclipse-docks/extension-command-shell',
44+
'@eclipse-docks/extension-terminal',
45+
'@eclipse-docks/extension-python-runtime',
4546
'@eclipse-docks/extension-catalog',
4647
'@eclipse-docks/extension-md-editor',
4748
'@eclipse-docks/extension-plain-editor',

packages/core/src/core/contributionregistry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ export interface TabContribution extends Contribution {
7979
* when any of them becomes the active editor in the main editor area. Omitted or empty = no auto-reveal.
8080
*/
8181
coupledEditors?: string[];
82+
/** Return false to cancel tab close (after dirty-tab prompt, if any). */
83+
beforeClose?: () => boolean | Promise<boolean>;
8284
component?: (id: string) => TemplateResult;
8385
}
8486

packages/core/src/layouts/standard-layout.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,11 @@ export class DocksStandardLayout extends DocksContainer {
139139
id="left-sidebar-split"
140140
orientation="vertical"
141141
sizes="50%, 50%">
142-
<docks-tabs id="${SIDEBAR_MAIN}" placement="start" icon-only with-toolbar></docks-tabs>
142+
<docks-tabs id="${SIDEBAR_MAIN}" placement="start" icon-only with-toolbar item-size="large"></docks-tabs>
143143
<docks-tabs id="${SIDEBAR_MAIN_BOTTOM}" placement="start" icon-only></docks-tabs>
144144
</docks-resizable-grid>
145145
`
146-
: html`<docks-tabs id="${SIDEBAR_MAIN}" placement="start" icon-only with-toolbar></docks-tabs>`
146+
: html`<docks-tabs id="${SIDEBAR_MAIN}" placement="start" icon-only with-toolbar item-size="large"></docks-tabs>`
147147
}
148148
`
149149
: nothing

packages/core/src/parts/part.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import { ifDefined } from "lit/directives/if-defined.js";
99
import { DocksContextMenu } from "./contextmenu";
1010

1111
export abstract class DocksPart extends DocksContainer {
12-
protected scrollMode: 'scroller' | 'native' = 'scroller';
12+
/** `scroller`: wrap content in wa-scroller; `native`: overflow on part-content; `none`: no outer scroll (child manages scroll). */
13+
protected scrollMode: 'scroller' | 'native' | 'none' = 'scroller';
1314

1415
@property()
1516
private dirty: boolean = false

packages/core/src/parts/tabs.ts

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export class DocksTabs extends DocksContainer {
4444
@property({ type: Boolean, reflect: true, attribute: 'hide-tabs' })
4545
hideTabs: boolean = false;
4646

47+
/** Tab and nav-toolbar control sizing (`small` | `medium` | `large`). */
48+
@property({ reflect: true, attribute: 'item-size' })
49+
itemSize: 'small' | 'medium' | 'large' = 'medium';
50+
4751
/** Tab contributions for this container */
4852
@state()
4953
private contributions: TabContribution[] = [];
@@ -158,6 +162,14 @@ export class DocksTabs extends DocksContainer {
158162
await this.tryCloseTab(tabName, true);
159163
}
160164

165+
updateTabLabel(tabName: string, label: string): void {
166+
const contribution = this.contributions.find((c) => c.name === tabName);
167+
if (!contribution) return;
168+
contribution.label = label;
169+
this.contributions = [...this.contributions];
170+
this.requestUpdate();
171+
}
172+
161173
/**
162174
* Closes every tab in this group. Returns false if the user cancels a dirty-tab prompt.
163175
*/
@@ -186,6 +198,11 @@ export class DocksTabs extends DocksContainer {
186198
const contribution = this.contributions.find(c => c.name === tabName);
187199
if (!contribution) return true;
188200

201+
if (contribution.beforeClose) {
202+
const ok = await contribution.beforeClose();
203+
if (!ok) return false;
204+
}
205+
189206
this.cleanupTabInstance(tabPanel);
190207
this.clearActiveSignalsIfPartInPanel(tabPanel);
191208

@@ -367,6 +384,20 @@ export class DocksTabs extends DocksContainer {
367384
return this.placement === "start" || this.placement === "end" ? "vertical" : "horizontal";
368385
}
369386

387+
private renderNavToolbar(navToolbarId: string) {
388+
if (!this.withToolbar || !navToolbarId) return nothing;
389+
return html`
390+
<div class="nav-toolbar-spacer" slot="nav" aria-hidden="true"></div>
391+
<docks-toolbar
392+
slot="nav"
393+
id=${navToolbarId}
394+
orientation=${this.withToolbarOrientation()}
395+
align="center"
396+
size=${this.itemSize}
397+
></docks-toolbar>
398+
`;
399+
}
400+
370401
private renderEmptyState() {
371402
const currentApp = appLoaderService.getCurrentApp();
372403
return html`
@@ -389,10 +420,22 @@ export class DocksTabs extends DocksContainer {
389420
}
390421

391422
render() {
392-
if (this.contributions.length === 0) {
423+
const containerId = this.containerId ?? this.getAttribute('id');
424+
const navToolbarId = containerId ? `${containerId}-toolbar` : '';
425+
const hasToolbar = this.withToolbar && !!navToolbarId;
426+
427+
if (this.contributions.length === 0 && !hasToolbar) {
393428
return this.renderEmptyState();
394429
}
395-
const navToolbarId = this.containerId ? `${this.containerId}-toolbar` : '';
430+
431+
if (this.contributions.length === 0) {
432+
return html`
433+
<wa-tab-group ${ref(this.tabGroup)} placement=${this.placement}>
434+
${this.renderNavToolbar(navToolbarId)}
435+
</wa-tab-group>
436+
`;
437+
}
438+
396439
return html`
397440
<wa-tab-group ${ref(this.tabGroup)} placement=${this.placement}>
398441
${repeat(
@@ -417,18 +460,7 @@ export class DocksTabs extends DocksContainer {
417460
`;
418461
}
419462
)}
420-
${this.withToolbar && navToolbarId
421-
? html`
422-
<div class="nav-toolbar-spacer" slot="nav" aria-hidden="true"></div>
423-
<docks-toolbar
424-
slot="nav"
425-
id=${navToolbarId}
426-
orientation=${this.withToolbarOrientation()}
427-
align="center"
428-
size="large"
429-
></docks-toolbar>
430-
`
431-
: nothing}
463+
${this.renderNavToolbar(navToolbarId)}
432464
</wa-tab-group>
433465
`;
434466
}
@@ -513,6 +545,17 @@ export class DocksTabs extends DocksContainer {
513545
514546
wa-tab::part(base) {
515547
padding: 3px 0.5rem;
548+
font-size: var(--wa-font-size-s);
549+
}
550+
551+
:host([item-size="small"]) wa-tab::part(base) {
552+
padding: 2px 0.375rem;
553+
font-size: var(--wa-font-size-xs);
554+
}
555+
556+
:host([item-size="large"]) wa-tab::part(base) {
557+
padding: var(--wa-space-s) 0.75rem;
558+
font-size: var(--wa-font-size-m);
516559
}
517560
518561
:host([icon-only]) wa-tab::part(base) {
@@ -523,15 +566,39 @@ export class DocksTabs extends DocksContainer {
523566
padding: var(--wa-space-s);
524567
}
525568
569+
:host([icon-only][item-size="small"]:is([placement="top"], [placement="bottom"])) wa-tab::part(base) {
570+
padding: var(--wa-space-xs);
571+
}
572+
573+
:host([icon-only][item-size="large"]:is([placement="top"], [placement="bottom"])) wa-tab::part(base) {
574+
padding: var(--wa-space-m);
575+
}
576+
526577
:host([icon-only]:is([placement="start"], [placement="end"])) wa-tab::part(base) {
527578
padding-inline: 0;
528579
padding-block: var(--wa-space-s);
529580
}
530581
582+
:host([icon-only][item-size="small"]:is([placement="start"], [placement="end"])) wa-tab::part(base) {
583+
padding-block: var(--wa-space-xs);
584+
}
585+
586+
:host([icon-only][item-size="large"]:is([placement="start"], [placement="end"])) wa-tab::part(base) {
587+
padding-block: var(--wa-space-m);
588+
}
589+
531590
:host([icon-only]) wa-tab wa-icon {
532591
font-size: var(--wa-font-size-l);
533592
}
534593
594+
:host([icon-only][item-size="small"]) wa-tab wa-icon {
595+
font-size: var(--wa-font-size-m);
596+
}
597+
598+
:host([icon-only][item-size="large"]) wa-tab wa-icon {
599+
font-size: var(--wa-font-size-xl);
600+
}
601+
535602
:host([icon-only]:is([placement="start"], [placement="end"])) wa-tab-group::part(nav),
536603
:host([icon-only]:is([placement="start"], [placement="end"])) wa-tab-group::part(tabs) {
537604
padding: 0;

0 commit comments

Comments
 (0)