xtralab 0.4.0 → 0.5.0

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/style/git.css CHANGED
@@ -1,272 +1,10 @@
1
1
  /*
2
- * Styles for the git changes panel and the diff viewer. The panel mirrors
3
- * the visual rhythm of the default JupyterLab side panels so it does not
4
- * stand out from the rest of the UI.
2
+ * Styles for xtralab's @pierre/diffs viewer. The same surface is used by
3
+ * the launcher dashboard's own diff tab and by the jupyterlab-git diff
4
+ * providers, so these rules cover both hosts. (xtralab no longer ships a
5
+ * git changes panel — the upstream jupyterlab-git panel is reused.)
5
6
  */
6
7
 
7
- .jp-xtralab-GitPanel {
8
- display: flex;
9
- flex-direction: column;
10
- min-width: 240px;
11
- background-color: var(--jp-layout-color1);
12
- color: var(--jp-ui-font-color1);
13
- font-family: var(--jp-ui-font-family);
14
- font-size: var(--jp-ui-font-size1);
15
- overflow: hidden;
16
- }
17
-
18
- .jp-xtralab-GitPanel-content {
19
- display: flex;
20
- flex-direction: column;
21
- flex: 1 1 auto;
22
- min-height: 0;
23
- overflow-y: auto;
24
- }
25
-
26
- .jp-xtralab-GitPanel-header {
27
- display: flex;
28
- align-items: flex-start;
29
- gap: 8px;
30
- padding: 8px 12px;
31
- border-bottom: 1px solid var(--jp-border-color2);
32
- }
33
-
34
- .jp-xtralab-GitPanel-headerInfo {
35
- display: flex;
36
- flex-direction: column;
37
- gap: 2px;
38
- flex: 1 1 auto;
39
- min-width: 0;
40
- }
41
-
42
- .jp-xtralab-GitPanel-repo {
43
- font-weight: 600;
44
- white-space: nowrap;
45
- overflow: hidden;
46
- text-overflow: ellipsis;
47
- }
48
-
49
- .jp-xtralab-GitPanel-branch {
50
- color: var(--jp-ui-font-color2);
51
- font-size: var(--jp-ui-font-size0);
52
- }
53
-
54
- .jp-xtralab-GitPanel-error {
55
- margin: 12px;
56
- padding: 8px;
57
- border-radius: 4px;
58
- background-color: var(
59
- --jp-error-color3,
60
- var(--jp-rendermime-error-background)
61
- );
62
- color: var(--jp-ui-font-color1);
63
- font-size: var(--jp-ui-font-size1);
64
- white-space: pre-wrap;
65
- }
66
-
67
- .jp-xtralab-GitPanel-empty {
68
- margin: 12px;
69
- color: var(--jp-ui-font-color2);
70
- font-style: italic;
71
- text-align: center;
72
- }
73
-
74
- .jp-xtralab-GitPanel-section {
75
- display: flex;
76
- flex-direction: column;
77
- }
78
-
79
- /*
80
- * Section headers and rows place their hover actions between the label
81
- * and the trailing count/badge, so the count stays pinned to the right
82
- * edge regardless of whether the section has any bulk actions. Reserving
83
- * the action width via `visibility: hidden` keeps the layout from
84
- * shifting when the cursor enters and leaves.
85
- */
86
- .jp-xtralab-GitPanel-sectionHeader {
87
- display: flex;
88
- align-items: center;
89
- gap: 4px;
90
- height: 28px;
91
- padding: 0 12px;
92
- cursor: pointer;
93
- user-select: none;
94
- text-transform: uppercase;
95
- font-size: var(--jp-ui-font-size0);
96
- font-weight: 600;
97
- letter-spacing: 0.04em;
98
- color: var(--jp-ui-font-color2);
99
- }
100
-
101
- .jp-xtralab-GitPanel-sectionHeader:hover {
102
- background-color: var(--jp-layout-color2);
103
- }
104
-
105
- .jp-xtralab-GitPanel-sectionChevron {
106
- width: 12px;
107
- text-align: center;
108
- font-size: 10px;
109
- }
110
-
111
- .jp-xtralab-GitPanel-sectionLabel {
112
- flex: 1 1 auto;
113
- }
114
-
115
- .jp-xtralab-GitPanel-sectionCount {
116
- display: inline-flex;
117
- align-items: center;
118
- justify-content: center;
119
- min-width: 18px;
120
- height: 16px;
121
- padding: 0 4px;
122
- background-color: var(--jp-layout-color3);
123
- color: var(--jp-ui-font-color1);
124
- border-radius: 8px;
125
- font-size: var(--jp-ui-font-size0);
126
- font-weight: 500;
127
- line-height: 1;
128
- }
129
-
130
- .jp-xtralab-GitPanel-sectionActions {
131
- display: inline-flex;
132
- align-items: center;
133
- gap: 4px;
134
- visibility: hidden;
135
- }
136
-
137
- .jp-xtralab-GitPanel-sectionHeader:hover .jp-xtralab-GitPanel-sectionActions {
138
- visibility: visible;
139
- }
140
-
141
- .jp-xtralab-GitPanel-sectionBody {
142
- display: flex;
143
- flex-direction: column;
144
- }
145
-
146
- /*
147
- * Three-column row layout: the label group on the left grows, the actions
148
- * column has a fixed reserved width that fits the worst-case button count,
149
- * and the badge column is auto-sized on the right edge. Reserving the
150
- * action column keeps the badge horizontally pinned regardless of the
151
- * row's hover state.
152
- */
153
- .jp-xtralab-GitPanel-row {
154
- display: flex;
155
- align-items: center;
156
- gap: 6px;
157
- height: 26px;
158
- padding: 0 12px;
159
- cursor: pointer;
160
- user-select: none;
161
- }
162
-
163
- .jp-xtralab-GitPanel-row:hover {
164
- background-color: var(--jp-layout-color2);
165
- }
166
-
167
- .jp-xtralab-GitPanel-rowLabel {
168
- display: flex;
169
- align-items: baseline;
170
- gap: 6px;
171
- flex: 1 1 auto;
172
- min-width: 0;
173
- overflow: hidden;
174
- }
175
-
176
- .jp-xtralab-GitPanel-rowName {
177
- white-space: nowrap;
178
- overflow: hidden;
179
- text-overflow: ellipsis;
180
- flex: 0 1 auto;
181
- }
182
-
183
- .jp-xtralab-GitPanel-rowPath {
184
- color: var(--jp-ui-font-color2);
185
- font-size: var(--jp-ui-font-size0);
186
- white-space: nowrap;
187
- overflow: hidden;
188
- text-overflow: ellipsis;
189
- flex: 0 1 auto;
190
- }
191
-
192
- .jp-xtralab-GitPanel-rowActions {
193
- /*
194
- * Reserved width matches the worst case of two 20px buttons + a 2px
195
- * gap. Staged rows only host the unstage button, but pinning the
196
- * column width keeps the trailing badge horizontally aligned across
197
- * the staged and unstaged sections.
198
- */
199
- display: inline-flex;
200
- align-items: center;
201
- justify-content: flex-end;
202
- gap: 2px;
203
- flex: 0 0 42px;
204
- visibility: hidden;
205
- }
206
-
207
- .jp-xtralab-GitPanel-row:hover .jp-xtralab-GitPanel-rowActions,
208
- .jp-xtralab-GitPanel-rowActions[data-pending='true'] {
209
- visibility: visible;
210
- }
211
-
212
- .jp-xtralab-GitPanel-rowBadge {
213
- display: inline-flex;
214
- align-items: center;
215
- justify-content: center;
216
- flex: 0 0 16px;
217
- width: 16px;
218
- height: 16px;
219
- border-radius: 2px;
220
- font-size: var(--jp-ui-font-size0);
221
- font-weight: 600;
222
- font-family: var(--jp-code-font-family);
223
- }
224
-
225
- .jp-xtralab-GitPanel-rowBadge[data-status='modified'] {
226
- color: var(--jp-warn-color1);
227
- }
228
-
229
- .jp-xtralab-GitPanel-rowBadge[data-status='added'],
230
- .jp-xtralab-GitPanel-rowBadge[data-status='untracked'] {
231
- color: var(--jp-success-color1);
232
- }
233
-
234
- .jp-xtralab-GitPanel-rowBadge[data-status='deleted'] {
235
- color: var(--jp-error-color1);
236
- }
237
-
238
- .jp-xtralab-GitPanel-rowBadge[data-status='renamed'] {
239
- color: var(--jp-info-color1, var(--jp-brand-color1));
240
- }
241
-
242
- .jp-xtralab-GitPanel-rowBadge[data-status='unmerged'] {
243
- color: var(--jp-error-color1);
244
- }
245
-
246
- .jp-xtralab-GitPanel-iconButton {
247
- display: inline-flex;
248
- align-items: center;
249
- justify-content: center;
250
- width: 20px;
251
- height: 20px;
252
- border: none;
253
- background: transparent;
254
- color: var(--jp-ui-font-color1);
255
- cursor: pointer;
256
- border-radius: 2px;
257
- font-size: var(--jp-ui-font-size1);
258
- line-height: 1;
259
- }
260
-
261
- .jp-xtralab-GitPanel-iconButton:hover {
262
- background-color: var(--jp-layout-color3);
263
- }
264
-
265
- .jp-xtralab-GitPanel-iconButton:disabled {
266
- opacity: 0.4;
267
- cursor: default;
268
- }
269
-
270
8
  /*
271
9
  * Diff viewer (main area). The `MainAreaWidget` holding the React content
272
10
  * gets sized by JupyterLab's box layout; the inner content div fills it
@@ -763,3 +501,157 @@
763
501
  white-space: pre-wrap;
764
502
  word-break: break-word;
765
503
  }
504
+
505
+ /*
506
+ * Image diff (raster files). xtralab's replacement for the upstream
507
+ * jupyterlab-git image diff: a sticky mode selector (reusing the diff
508
+ * segmented-control styling) over the 2-up / swipe / onion-skin views.
509
+ *
510
+ * Every mode is sized to *fit the widget*: the images are contained
511
+ * within the available area (never upscaled past their natural size, and
512
+ * scaled down to fit when larger) so nothing overflows. In particular the
513
+ * swipe/onion slider stays on screen even when the two revisions have very
514
+ * different dimensions. A neutral checkerboard sits behind each image so
515
+ * transparency reads clearly in both light and dark themes.
516
+ */
517
+ .jp-xtralab-ImageDiff {
518
+ display: flex;
519
+ flex-direction: column;
520
+ width: 100%;
521
+ height: 100%;
522
+ }
523
+
524
+ .jp-xtralab-ImageDiff-header {
525
+ flex: 0 0 auto;
526
+ display: flex;
527
+ justify-content: center;
528
+ padding: 8px;
529
+ background-color: var(--jp-layout-color1);
530
+ border-bottom: 1px solid var(--jp-border-color2);
531
+ }
532
+
533
+ /*
534
+ * The body fills the remaining height and never scrolls — each view is a
535
+ * flex child that fits inside it (`min-height: 0` lets the flex/grid
536
+ * children shrink below their intrinsic size so `max-height` on the
537
+ * images can take effect).
538
+ */
539
+ .jp-xtralab-ImageDiff-body {
540
+ flex: 1 1 auto;
541
+ min-height: 0;
542
+ display: flex;
543
+ overflow: hidden;
544
+ padding: 16px;
545
+ }
546
+
547
+ .jp-xtralab-ImageDiff-twoUp {
548
+ flex: 1 1 auto;
549
+ min-height: 0;
550
+ display: flex;
551
+ gap: 16px;
552
+ }
553
+
554
+ .jp-xtralab-ImageDiff-col {
555
+ flex: 1 1 0;
556
+ min-width: 0;
557
+ min-height: 0;
558
+ display: flex;
559
+ flex-direction: column;
560
+ align-items: center;
561
+ gap: 8px;
562
+ margin: 0;
563
+ }
564
+
565
+ .jp-xtralab-ImageDiff-frame,
566
+ .jp-xtralab-ImageDiff-stack {
567
+ /* Checkerboard so transparent regions are obvious; theme-neutral. */
568
+ background-color: #fff;
569
+ background-image:
570
+ linear-gradient(45deg, #c8c8c8 25%, transparent 25%),
571
+ linear-gradient(-45deg, #c8c8c8 25%, transparent 25%),
572
+ linear-gradient(45deg, transparent 75%, #c8c8c8 75%),
573
+ linear-gradient(-45deg, transparent 75%, #c8c8c8 75%);
574
+ background-size: 16px 16px;
575
+ background-position:
576
+ 0 0,
577
+ 0 8px,
578
+ 8px -8px,
579
+ -8px 0;
580
+ border: 1px solid var(--jp-border-color2);
581
+ }
582
+
583
+ .jp-xtralab-ImageDiff-frame {
584
+ flex: 1 1 auto;
585
+ min-height: 0;
586
+ width: 100%;
587
+ display: flex;
588
+ align-items: center;
589
+ justify-content: center;
590
+ padding: 4px;
591
+ }
592
+
593
+ .jp-xtralab-ImageDiff-img {
594
+ display: block;
595
+ max-width: 100%;
596
+ max-height: 100%;
597
+ width: auto;
598
+ height: auto;
599
+ object-fit: contain;
600
+ }
601
+
602
+ .jp-xtralab-ImageDiff-empty {
603
+ padding: 32px 24px;
604
+ color: var(--jp-ui-font-color2);
605
+ font-size: var(--jp-ui-font-size1);
606
+ font-style: italic;
607
+ }
608
+
609
+ .jp-xtralab-ImageDiff-caption {
610
+ flex: 0 0 auto;
611
+ color: var(--jp-ui-font-color2);
612
+ font-size: var(--jp-ui-font-size0);
613
+ font-family: var(--jp-code-font-family);
614
+ text-align: center;
615
+ word-break: break-word;
616
+ }
617
+
618
+ .jp-xtralab-ImageDiff-interactive {
619
+ flex: 1 1 auto;
620
+ min-height: 0;
621
+ display: flex;
622
+ flex-direction: column;
623
+ align-items: center;
624
+ gap: 12px;
625
+ }
626
+
627
+ /*
628
+ * Both revisions occupy the same grid cell so swipe/onion can overlay
629
+ * them. `place-items: center` keeps each image at its own size (no
630
+ * stretching the smaller revision up to the larger one's box) while
631
+ * `max-height/width` scale either one down to fit the available space.
632
+ */
633
+ .jp-xtralab-ImageDiff-stack {
634
+ flex: 1 1 auto;
635
+ min-height: 0;
636
+ width: 100%;
637
+ display: grid;
638
+ place-items: center;
639
+ padding: 4px;
640
+ }
641
+
642
+ .jp-xtralab-ImageDiff-stackImg {
643
+ grid-area: 1 / 1;
644
+ display: block;
645
+ max-width: 100%;
646
+ max-height: 100%;
647
+ width: auto;
648
+ height: auto;
649
+ object-fit: contain;
650
+ }
651
+
652
+ .jp-xtralab-ImageDiff-slider {
653
+ flex: 0 0 auto;
654
+ width: min(480px, 100%);
655
+ accent-color: var(--jp-brand-color1);
656
+ cursor: ew-resize;
657
+ }
@@ -1,14 +0,0 @@
1
- import { LabIcon } from '@jupyterlab/ui-components';
2
- /**
3
- * The branch glyph used as the git panel's sidebar tab icon. Defined as a
4
- * `LabIcon` (rather than a CSS-only mask) so it picks up JupyterLab's icon
5
- * recoloring and inverse-color sidebar painting automatically.
6
- *
7
- * Source: `git-branch` from SVG Repo (https://www.svgrepo.com/svg/377352/git-branch),
8
- * part of the same Pixelarticons family as the xtralab file browser's `file-tree`
9
- * icon, so the two sidebar tab glyphs read as a matched set. The original
10
- * `fill="#000000"` is replaced with `fill="currentColor"` and the root element
11
- * is given the `jp-icon3` class so the icon picks up JupyterLab's theme color
12
- * and the sidebar's inverse-color painting automatically.
13
- */
14
- export declare const gitIcon: LabIcon;
package/lib/git/icons.js DELETED
@@ -1,19 +0,0 @@
1
- import { LabIcon } from '@jupyterlab/ui-components';
2
- /**
3
- * The branch glyph used as the git panel's sidebar tab icon. Defined as a
4
- * `LabIcon` (rather than a CSS-only mask) so it picks up JupyterLab's icon
5
- * recoloring and inverse-color sidebar painting automatically.
6
- *
7
- * Source: `git-branch` from SVG Repo (https://www.svgrepo.com/svg/377352/git-branch),
8
- * part of the same Pixelarticons family as the xtralab file browser's `file-tree`
9
- * icon, so the two sidebar tab glyphs read as a matched set. The original
10
- * `fill="#000000"` is replaced with `fill="currentColor"` and the root element
11
- * is given the `jp-icon3` class so the icon picks up JupyterLab's theme color
12
- * and the sidebar's inverse-color painting automatically.
13
- */
14
- export const gitIcon = new LabIcon({
15
- name: 'xtralab:git',
16
- svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="jp-icon3" fill="currentColor">
17
- <path d="M5 2h2v12h3v3h7v-7h-3V2h8v8h-3v9h-9v3H2v-8h3V2zm15 6V4h-4v4h4zM8 19v-3H4v4h4v-1z"/>
18
- </svg>`
19
- });
@@ -1,29 +0,0 @@
1
- import * as React from 'react';
2
- import { ReactWidget } from '@jupyterlab/ui-components';
3
- import { ISignal } from '@lumino/signaling';
4
- import { IGitPanelHandlers } from './panelComponent';
5
- /**
6
- * The id and CSS class used for the git panel widget. The id ends up as the
7
- * sidebar tab id (so layout restoration can find the widget) and the CSS
8
- * class lets per-panel styles attach without leaking to other widgets.
9
- */
10
- export declare const GIT_PANEL_ID = "xtralab:git-panel";
11
- export declare const GIT_PANEL_CSS_CLASS = "jp-xtralab-GitPanel";
12
- /**
13
- * The lumino host widget for the git changes panel. Owns the `refresh`
14
- * signal that the React component listens to, and exposes a typed callback
15
- * surface (`handlers`) the React component uses to react to user actions.
16
- */
17
- export declare class GitPanel extends ReactWidget {
18
- constructor(handlers: IGitPanelHandlers);
19
- /**
20
- * Public refresh hook called by the plugin when something happened that
21
- * invalidates the current view (the user clicked the toolbar refresh, the
22
- * file browser refreshed, a focused notebook saved, …).
23
- */
24
- refresh(): void;
25
- get refreshRequested(): ISignal<this, void>;
26
- protected render(): React.ReactElement;
27
- private _handlers;
28
- private _refreshRequested;
29
- }
package/lib/git/panel.js DELETED
@@ -1,42 +0,0 @@
1
- import * as React from 'react';
2
- import { ReactWidget } from '@jupyterlab/ui-components';
3
- import { Signal } from '@lumino/signaling';
4
- import { gitIcon } from './icons';
5
- import { GitPanelComponent } from './panelComponent';
6
- /**
7
- * The id and CSS class used for the git panel widget. The id ends up as the
8
- * sidebar tab id (so layout restoration can find the widget) and the CSS
9
- * class lets per-panel styles attach without leaking to other widgets.
10
- */
11
- export const GIT_PANEL_ID = 'xtralab:git-panel';
12
- export const GIT_PANEL_CSS_CLASS = 'jp-xtralab-GitPanel';
13
- /**
14
- * The lumino host widget for the git changes panel. Owns the `refresh`
15
- * signal that the React component listens to, and exposes a typed callback
16
- * surface (`handlers`) the React component uses to react to user actions.
17
- */
18
- export class GitPanel extends ReactWidget {
19
- constructor(handlers) {
20
- super();
21
- this._refreshRequested = new Signal(this);
22
- this.id = GIT_PANEL_ID;
23
- this.title.icon = gitIcon;
24
- this.title.caption = 'Git Changes';
25
- this.addClass(GIT_PANEL_CSS_CLASS);
26
- this._handlers = handlers;
27
- }
28
- /**
29
- * Public refresh hook called by the plugin when something happened that
30
- * invalidates the current view (the user clicked the toolbar refresh, the
31
- * file browser refreshed, a focused notebook saved, …).
32
- */
33
- refresh() {
34
- this._refreshRequested.emit();
35
- }
36
- get refreshRequested() {
37
- return this._refreshRequested;
38
- }
39
- render() {
40
- return (React.createElement(GitPanelComponent, { handlers: this._handlers, refreshSignal: this._refreshRequested }));
41
- }
42
- }
@@ -1,28 +0,0 @@
1
- import * as React from 'react';
2
- import { ISignal } from '@lumino/signaling';
3
- import { IFileChange } from './tokens';
4
- /**
5
- * Callbacks the panel needs to delegate to (so the React component stays
6
- * free of any JupyterLab application coupling). The plugin wires these up
7
- * with the actual `JupyterFrontEnd` reference.
8
- */
9
- export interface IGitPanelHandlers {
10
- /** Open a diff viewer for the given file in the main area. */
11
- openDiff(change: IFileChange, options?: {
12
- pin?: boolean;
13
- }): void;
14
- /** Show a confirmation dialog. Returns true when the user accepted. */
15
- confirm(title: string, body: string, accept: string): Promise<boolean>;
16
- /** Show an error dialog. */
17
- showError(title: string, error: Error): Promise<void>;
18
- }
19
- /**
20
- * Top-level React component rendered inside the {@link GitPanel} widget.
21
- * Owns the polling + refresh wiring around the `/git/status` endpoint and
22
- * the small bit of UI state that controls section collapse and the
23
- * in-flight per-file action spinners.
24
- */
25
- export declare function GitPanelComponent(props: {
26
- handlers: IGitPanelHandlers;
27
- refreshSignal: ISignal<unknown, void>;
28
- }): React.ReactElement;