@jlab-enhanced/favorites 3.3.0 → 3.4.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/lib/components.js +62 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +20 -3
- package/lib/manager.d.ts +2 -0
- package/lib/manager.js +21 -5
- package/lib/starPrompt.d.ts +7 -3
- package/lib/starPrompt.js +91 -3
- package/lib/token.d.ts +7 -0
- package/lib/token.js +4 -0
- package/package.json +13 -4
- package/schema/favorites.json +17 -0
- package/style/base.css +11 -0
package/lib/components.js
CHANGED
|
@@ -2,6 +2,7 @@ import { folderIcon, LabIcon, fileIcon, ReactWidget, UseSignal } from '@jupyterl
|
|
|
2
2
|
import { Signal } from '@lumino/signaling';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { getFavoritesIcon, getName, getPinnerActionDescription, mergePaths } from './utils';
|
|
5
|
+
import { Drag } from '@lumino/dragdrop';
|
|
5
6
|
/**
|
|
6
7
|
* The parent node class for Favorites content.
|
|
7
8
|
*/
|
|
@@ -38,6 +39,10 @@ const FILEBROWSER_HEADER_CLASS = 'jp-FileBrowser-header';
|
|
|
38
39
|
* This icon is overlaid on top of the FileBrowser content via CSS.
|
|
39
40
|
*/
|
|
40
41
|
const FAVORITE_BREADCRUMB_ICON_CLASS = 'jp-Favorites-BreadCrumbs-Icon';
|
|
42
|
+
/**
|
|
43
|
+
* The spacing from the bottom of the FileBrowser to leave when resizing the Favorites container.
|
|
44
|
+
*/
|
|
45
|
+
const BOTTOM_SPACING = 100;
|
|
41
46
|
const FavoriteComponent = (props) => {
|
|
42
47
|
const { favorite, handleClick } = props;
|
|
43
48
|
let [displayName, dirname] = getName(favorite.path);
|
|
@@ -85,6 +90,62 @@ export const FavoritesBreadCrumbs = (props) => {
|
|
|
85
90
|
React.createElement(icon.react, { className: FAVORITE_BREADCRUMB_ICON_CLASS, tag: "span" })));
|
|
86
91
|
}));
|
|
87
92
|
};
|
|
93
|
+
function FavoritesContainer({ visibleFavorites, manager }) {
|
|
94
|
+
const containerRef = React.useRef(null);
|
|
95
|
+
const [isResizing, setIsResizing] = React.useState(false);
|
|
96
|
+
const cursorDisposableRef = React.useRef(null);
|
|
97
|
+
const handleMouseDown = () => {
|
|
98
|
+
setIsResizing(true);
|
|
99
|
+
cursorDisposableRef.current = Drag.overrideCursor('ns-resize');
|
|
100
|
+
};
|
|
101
|
+
const handleMouseMove = React.useCallback((e) => {
|
|
102
|
+
if (!isResizing) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const container = containerRef.current;
|
|
106
|
+
if (!container) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Height of filebrowser widget
|
|
110
|
+
const parentElement = container.closest('.jp-FileBrowser');
|
|
111
|
+
const parentRect = parentElement === null || parentElement === void 0 ? void 0 : parentElement.getBoundingClientRect();
|
|
112
|
+
if (!parentRect) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const rect = container.getBoundingClientRect();
|
|
116
|
+
const newHeight = e.clientY - rect.top;
|
|
117
|
+
const maxHeight = parentRect.height - BOTTOM_SPACING;
|
|
118
|
+
if (newHeight > 24 && newHeight < maxHeight) {
|
|
119
|
+
container.style.maxHeight = maxHeight + 'px'; // To ensure default max-height of css is overridden
|
|
120
|
+
container.style.height = newHeight + 'px';
|
|
121
|
+
}
|
|
122
|
+
}, [isResizing]);
|
|
123
|
+
const handleMouseUp = React.useCallback(() => {
|
|
124
|
+
var _a;
|
|
125
|
+
setIsResizing(false);
|
|
126
|
+
(_a = cursorDisposableRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
127
|
+
cursorDisposableRef.current = null;
|
|
128
|
+
}, []);
|
|
129
|
+
React.useEffect(() => {
|
|
130
|
+
if (isResizing) {
|
|
131
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
132
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
133
|
+
return () => {
|
|
134
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
135
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}, [isResizing, handleMouseMove, handleMouseUp]);
|
|
139
|
+
React.useEffect(() => {
|
|
140
|
+
return () => {
|
|
141
|
+
var _a;
|
|
142
|
+
(_a = cursorDisposableRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
143
|
+
};
|
|
144
|
+
}, []);
|
|
145
|
+
return (React.createElement(React.Fragment, null,
|
|
146
|
+
React.createElement("div", { ref: containerRef, className: FAVORITE_CONTAINER_CLASS }, (visibleFavorites !== null && visibleFavorites !== void 0 ? visibleFavorites : []).map(f => (React.createElement(FavoriteComponent, { key: `favorites-item-${f.path}`, favorite: f, handleClick: manager.handleClick.bind(manager) })))),
|
|
147
|
+
React.createElement("div", { className: "jp-Favorites-resize-handle", onMouseDown: handleMouseDown })));
|
|
148
|
+
}
|
|
88
149
|
export class FavoritesWidget extends ReactWidget {
|
|
89
150
|
constructor(manager, filebrowser) {
|
|
90
151
|
super();
|
|
@@ -101,7 +162,7 @@ export class FavoritesWidget extends ReactWidget {
|
|
|
101
162
|
return (React.createElement(UseSignal, { signal: this.manager.favoritesChanged, initialSender: this.manager, initialArgs: this.manager.visibleFavorites() }, (manager, visibleFavorites) => (React.createElement("div", null,
|
|
102
163
|
React.createElement(UseSignal, { signal: manager.visibilityChanged, initialSender: manager, initialArgs: manager.isVisible() }, (manager, isVisible) => isVisible && (React.createElement(React.Fragment, null,
|
|
103
164
|
React.createElement("div", { className: FAVORITE_HEADER_CLASS }, "Favorites"),
|
|
104
|
-
React.createElement(
|
|
165
|
+
React.createElement(FavoritesContainer, { visibleFavorites: visibleFavorites, manager: manager }),
|
|
105
166
|
React.createElement("div", { className: FILEBROWSER_HEADER_CLASS }, "File Browser"))))))));
|
|
106
167
|
}
|
|
107
168
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export { IFavorites, FAVORITE_TAG } from './token';
|
|
|
6
6
|
* Plugin that provides the custom notebook factory with star icons
|
|
7
7
|
*/
|
|
8
8
|
export declare const notebookFactoryPlugin: JupyterFrontEndPlugin<NotebookPanel.IContentFactory>;
|
|
9
|
-
declare const _default: (JupyterFrontEndPlugin<
|
|
9
|
+
declare const _default: (JupyterFrontEndPlugin<NotebookPanel.IContentFactory> | JupyterFrontEndPlugin<IFavorites>)[];
|
|
10
10
|
export default _default;
|
package/lib/index.js
CHANGED
|
@@ -253,7 +253,7 @@ const favorites = {
|
|
|
253
253
|
okLabel: 'Rename',
|
|
254
254
|
placeholder: 'Display name'
|
|
255
255
|
});
|
|
256
|
-
displayName = result.button.accept ? (_a = result.value) !== null && _a !== void 0 ? _a : '' : '';
|
|
256
|
+
displayName = result.button.accept ? ((_a = result.value) !== null && _a !== void 0 ? _a : '') : '';
|
|
257
257
|
}
|
|
258
258
|
if (!displayName) {
|
|
259
259
|
return;
|
|
@@ -360,11 +360,28 @@ export const notebookFactoryPlugin = {
|
|
|
360
360
|
provides: NotebookPanel.IContentFactory,
|
|
361
361
|
requires: [IEditorServices],
|
|
362
362
|
autoStart: true,
|
|
363
|
-
activate: (app, editorServices) => {
|
|
363
|
+
activate: async (app, editorServices) => {
|
|
364
|
+
var _a, _b;
|
|
365
|
+
let mystFactory;
|
|
366
|
+
if (app.hasPlugin('jupyterlab-myst:content-factory')) {
|
|
367
|
+
const mystPlugins = (await import('jupyterlab-myst')).default;
|
|
368
|
+
const mystPlugin = mystPlugins.filter(plugin => plugin.provides === NotebookPanel.IContentFactory)[0];
|
|
369
|
+
if (mystPlugin) {
|
|
370
|
+
const dependencies = await Promise.all([
|
|
371
|
+
...((_a = mystPlugin.requires) !== null && _a !== void 0 ? _a : []).map(token => app.resolveRequiredService(token)),
|
|
372
|
+
...((_b = mystPlugin.optional) !== null && _b !== void 0 ? _b : []).map(token => app.resolveOptionalService(token))
|
|
373
|
+
]);
|
|
374
|
+
mystFactory = (await mystPlugin.activate(app, ...dependencies));
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
console.error('jupyterlab-favorites found jupyterlab-myst:content-factory plugin, but could not activate content factory for compatibility fix');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
364
380
|
const editorFactory = editorServices.factoryService.newInlineEditor;
|
|
365
381
|
const factory = new StarredNotebookContentFactory({
|
|
366
382
|
editorFactory,
|
|
367
|
-
app
|
|
383
|
+
app,
|
|
384
|
+
mystFactory
|
|
368
385
|
});
|
|
369
386
|
return factory;
|
|
370
387
|
}
|
package/lib/manager.d.ts
CHANGED
package/lib/manager.js
CHANGED
|
@@ -8,6 +8,8 @@ export class FavoritesManager {
|
|
|
8
8
|
this.visibilityChanged = new Signal(this);
|
|
9
9
|
this._favorites = [];
|
|
10
10
|
this._showWidget = false;
|
|
11
|
+
this._sortOrder = 'name';
|
|
12
|
+
this._groupByType = true;
|
|
11
13
|
this._showWidget = true;
|
|
12
14
|
this._serverRoot = serverRoot;
|
|
13
15
|
this._commandRegistry = commands;
|
|
@@ -124,15 +126,24 @@ export class FavoritesManager {
|
|
|
124
126
|
}
|
|
125
127
|
visibleFavorites(sort = true) {
|
|
126
128
|
const filtered = this.favorites.filter(f => !f.hidden);
|
|
127
|
-
if (!sort) {
|
|
129
|
+
if (!sort || this._sortOrder === 'unsorted') {
|
|
128
130
|
return filtered;
|
|
129
131
|
}
|
|
130
132
|
return filtered.sort((a, b) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
// Group by content type first if enabled
|
|
134
|
+
if (this._groupByType && a.contentType !== b.contentType) {
|
|
135
|
+
return a.contentType < b.contentType ? -1 : 1;
|
|
136
|
+
}
|
|
137
|
+
// Sort by selected criterion using locale-aware comparison
|
|
138
|
+
if (this._sortOrder === 'name') {
|
|
139
|
+
// Use custom display name if set, otherwise fall back to basename
|
|
140
|
+
const nameA = a.name || getName(a.path)[0];
|
|
141
|
+
const nameB = b.name || getName(b.path)[0];
|
|
142
|
+
return nameA.localeCompare(nameB);
|
|
133
143
|
}
|
|
134
144
|
else {
|
|
135
|
-
|
|
145
|
+
// sortOrder === 'path'
|
|
146
|
+
return a.path.localeCompare(b.path);
|
|
136
147
|
}
|
|
137
148
|
});
|
|
138
149
|
}
|
|
@@ -148,9 +159,14 @@ export class FavoritesManager {
|
|
|
148
159
|
this.overwriteSettings({ favorites: defaultFavorites });
|
|
149
160
|
}
|
|
150
161
|
async loadFavorites() {
|
|
151
|
-
var _a;
|
|
162
|
+
var _a, _b, _c;
|
|
152
163
|
const setting = await this._settingsRegistry.get(SettingIDs.favorites, 'favorites');
|
|
153
164
|
const favorites = ((_a = setting.composite) !== null && _a !== void 0 ? _a : []);
|
|
165
|
+
// Load sort settings
|
|
166
|
+
const sortOrderSetting = await this._settingsRegistry.get(SettingIDs.favorites, 'sortOrder');
|
|
167
|
+
this._sortOrder = ((_b = sortOrderSetting.composite) !== null && _b !== void 0 ? _b : 'name');
|
|
168
|
+
const groupByTypeSetting = await this._settingsRegistry.get(SettingIDs.favorites, 'groupByType');
|
|
169
|
+
this._groupByType = ((_c = groupByTypeSetting.composite) !== null && _c !== void 0 ? _c : true);
|
|
154
170
|
this.favorites = favorites.map(favorite => {
|
|
155
171
|
var _a;
|
|
156
172
|
return { ...favorite, root: (_a = favorite.root) !== null && _a !== void 0 ? _a : this.serverRoot };
|
package/lib/starPrompt.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JupyterFrontEnd } from '@jupyterlab/application';
|
|
2
2
|
import { Widget } from '@lumino/widgets';
|
|
3
|
-
import { Cell, IInputPrompt } from '@jupyterlab/cells';
|
|
4
|
-
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
3
|
+
import { Cell, IInputPrompt, MarkdownCell } from '@jupyterlab/cells';
|
|
4
|
+
import { Notebook, NotebookPanel } from '@jupyterlab/notebook';
|
|
5
5
|
export declare class StarredInputPrompt extends Widget implements IInputPrompt {
|
|
6
6
|
private _app;
|
|
7
7
|
private _executionCount;
|
|
@@ -15,10 +15,14 @@ export declare class StarredInputPrompt extends Widget implements IInputPrompt {
|
|
|
15
15
|
export declare namespace StarredNotebookContentFactory {
|
|
16
16
|
interface IOptions extends Cell.ContentFactory.IOptions {
|
|
17
17
|
app: JupyterFrontEnd;
|
|
18
|
+
mystFactory?: NotebookPanel.IContentFactory;
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
export declare class StarredNotebookContentFactory extends NotebookPanel.ContentFactory {
|
|
21
|
-
private _app;
|
|
22
22
|
constructor(options: StarredNotebookContentFactory.IOptions);
|
|
23
23
|
createInputPrompt(): StarredInputPrompt;
|
|
24
|
+
createMarkdownCell(options: MarkdownCell.IOptions): MarkdownCell;
|
|
25
|
+
createNotebook(options: Notebook.IOptions): Notebook;
|
|
26
|
+
private _app;
|
|
27
|
+
private _mystFactory?;
|
|
24
28
|
}
|
package/lib/starPrompt.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BoxLayout, Widget } from '@lumino/widgets';
|
|
2
|
-
import { CommandIDs } from './token';
|
|
3
|
-
import { InputPrompt } from '@jupyterlab/cells';
|
|
2
|
+
import { CommandIDs, FAVORITE_FILTER_CLASS, FAVORITE_TAG } from './token';
|
|
3
|
+
import { InputPrompt, MarkdownCell } from '@jupyterlab/cells';
|
|
4
4
|
import { ToolbarButton } from '@jupyterlab/ui-components';
|
|
5
5
|
import { filledStarIcon, starIcon } from './icons';
|
|
6
|
-
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
6
|
+
import { Notebook, NotebookPanel } from '@jupyterlab/notebook';
|
|
7
7
|
const INPUT_PROMPT_CLASS = 'jp-InputPrompt';
|
|
8
8
|
const INPUT_PROMPT_NUMBER_CLASS = 'jp-Favorites-InputPromptNumber';
|
|
9
9
|
const FAVORITE_ICON_ON_CLASS = 'jp-Favorites-star-class';
|
|
@@ -50,12 +50,100 @@ export class StarredInputPrompt extends Widget {
|
|
|
50
50
|
this._promptIndicator.executionCount = value;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
class FavoritesNotebook extends Notebook {
|
|
54
|
+
constructor(options) {
|
|
55
|
+
super(options);
|
|
56
|
+
}
|
|
57
|
+
get activeCellIndex() {
|
|
58
|
+
if (!this.model) {
|
|
59
|
+
return -1;
|
|
60
|
+
}
|
|
61
|
+
return this.widgets.length ? super.activeCellIndex : -1;
|
|
62
|
+
}
|
|
63
|
+
set activeCellIndex(newValue) {
|
|
64
|
+
const oldValue = super.activeCellIndex;
|
|
65
|
+
// Validate bounds
|
|
66
|
+
if (!this.model || !this.widgets.length) {
|
|
67
|
+
newValue = -1;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
newValue = Math.max(newValue, 0);
|
|
71
|
+
newValue = Math.min(newValue, this.widgets.length - 1);
|
|
72
|
+
}
|
|
73
|
+
// If favorites filter is not active, use default behavior
|
|
74
|
+
if (!this._isFavoritesFilterActive()) {
|
|
75
|
+
super.activeCellIndex = newValue;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// If target cell is favorite, use default behavior
|
|
79
|
+
if (this._isCellFavorite(newValue)) {
|
|
80
|
+
super.activeCellIndex = newValue;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Target cell is not a favorite, find nearest favorite
|
|
84
|
+
const direction = newValue > oldValue ? 1 : -1;
|
|
85
|
+
const nearestFavoriteIndex = this._findNearestFavoriteCell(newValue, direction);
|
|
86
|
+
if (nearestFavoriteIndex !== -1) {
|
|
87
|
+
super.activeCellIndex = nearestFavoriteIndex;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// At the edges, stick the nearest favourite cell in any direction;
|
|
92
|
+
// this also helps when the favorite cell is moved around as it will
|
|
93
|
+
// snap back to it, rather than leaving the index on a now hidden cell.
|
|
94
|
+
const alternative = this._findNearestFavoriteCell(newValue, direction > 0 ? -1 : 1);
|
|
95
|
+
super.activeCellIndex = alternative;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if a cell at the given index is marked as favorite
|
|
100
|
+
*/
|
|
101
|
+
_isCellFavorite(cellIndex) {
|
|
102
|
+
if (cellIndex < 0 || cellIndex >= this.widgets.length) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const cell = this.widgets[cellIndex];
|
|
106
|
+
const tags = cell.model.getMetadata('tags');
|
|
107
|
+
return Array.isArray(tags) && tags.includes(FAVORITE_TAG);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if the favorites filter is currently active
|
|
111
|
+
*/
|
|
112
|
+
_isFavoritesFilterActive() {
|
|
113
|
+
return this.node.classList.contains(FAVORITE_FILTER_CLASS);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Find the nearest favorite cell in a given direction
|
|
117
|
+
* @param startIndex - Index to start searching from
|
|
118
|
+
* @param direction - 1 for down, -1 for up
|
|
119
|
+
*/
|
|
120
|
+
_findNearestFavoriteCell(startIndex, direction) {
|
|
121
|
+
let currentIndex = startIndex + direction;
|
|
122
|
+
while (currentIndex >= 0 && currentIndex < this.widgets.length) {
|
|
123
|
+
if (this._isCellFavorite(currentIndex)) {
|
|
124
|
+
return currentIndex;
|
|
125
|
+
}
|
|
126
|
+
currentIndex += direction;
|
|
127
|
+
}
|
|
128
|
+
return -1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
53
131
|
export class StarredNotebookContentFactory extends NotebookPanel.ContentFactory {
|
|
54
132
|
constructor(options) {
|
|
55
133
|
super(options);
|
|
56
134
|
this._app = options.app;
|
|
135
|
+
this._mystFactory = options.mystFactory;
|
|
57
136
|
}
|
|
58
137
|
createInputPrompt() {
|
|
59
138
|
return new StarredInputPrompt(this._app);
|
|
60
139
|
}
|
|
140
|
+
createMarkdownCell(options) {
|
|
141
|
+
if (this._mystFactory) {
|
|
142
|
+
return this._mystFactory.createMarkdownCell(options);
|
|
143
|
+
}
|
|
144
|
+
return new MarkdownCell(options).initializeState();
|
|
145
|
+
}
|
|
146
|
+
createNotebook(options) {
|
|
147
|
+
return new FavoritesNotebook(options);
|
|
148
|
+
}
|
|
61
149
|
}
|
package/lib/token.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare namespace PluginIDs {
|
|
|
4
4
|
const notebookFactory = "favorites-notebook-factory";
|
|
5
5
|
}
|
|
6
6
|
export type ShowStarsTypes = 'allCells' | 'onlyFavoriteCells' | 'never';
|
|
7
|
+
export type SortOrder = 'unsorted' | 'name' | 'path';
|
|
7
8
|
export declare namespace CommandIDs {
|
|
8
9
|
const addOrRemoveFavorite: string;
|
|
9
10
|
const removeFavorite: string;
|
|
@@ -33,6 +34,8 @@ export declare namespace IFavorites {
|
|
|
33
34
|
type FavoritesSettings = {
|
|
34
35
|
favorites?: Array<IFavorites.Favorite>;
|
|
35
36
|
showWidget?: boolean;
|
|
37
|
+
sortOrder?: SortOrder;
|
|
38
|
+
groupByType?: boolean;
|
|
36
39
|
};
|
|
37
40
|
}
|
|
38
41
|
export declare const IFavorites: Token<IFavorites>;
|
|
@@ -43,3 +46,7 @@ export interface IFavorites {
|
|
|
43
46
|
* Cell tag used to mark cell as favorite
|
|
44
47
|
*/
|
|
45
48
|
export declare const FAVORITE_TAG = "favorite";
|
|
49
|
+
/**
|
|
50
|
+
* Class set to notebook when filtering cells by favorite is enabled
|
|
51
|
+
*/
|
|
52
|
+
export declare const FAVORITE_FILTER_CLASS = "jp-favorites-filter-active";
|
package/lib/token.js
CHANGED
|
@@ -27,3 +27,7 @@ export const IFavorites = new Token('jupyterlab-favorites:IFavorites');
|
|
|
27
27
|
* Cell tag used to mark cell as favorite
|
|
28
28
|
*/
|
|
29
29
|
export const FAVORITE_TAG = 'favorite';
|
|
30
|
+
/**
|
|
31
|
+
* Class set to notebook when filtering cells by favorite is enabled
|
|
32
|
+
*/
|
|
33
|
+
export const FAVORITE_FILTER_CLASS = 'jp-favorites-filter-active';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jlab-enhanced/favorites",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Add the ability to save favorite folders to JupyterLab for quicker browsing",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -65,7 +65,9 @@
|
|
|
65
65
|
},
|
|
66
66
|
"resolutions": {
|
|
67
67
|
"react-dom": "^18.2.0",
|
|
68
|
-
"react": "^18.2.0"
|
|
68
|
+
"react": "^18.2.0",
|
|
69
|
+
"lib0": "0.2.111",
|
|
70
|
+
"mermaid": "11.12.2"
|
|
69
71
|
},
|
|
70
72
|
"dependencies": {
|
|
71
73
|
"@jupyterlab/application": "^4.0.5",
|
|
@@ -82,11 +84,13 @@
|
|
|
82
84
|
"@lumino/commands": "^2.0.1",
|
|
83
85
|
"@lumino/coreutils": "^2.0.1",
|
|
84
86
|
"@lumino/signaling": "^2.0.0",
|
|
85
|
-
"@lumino/widgets": "^2.0.1"
|
|
87
|
+
"@lumino/widgets": "^2.0.1",
|
|
88
|
+
"jupyterlab-myst": "^2.4.0"
|
|
86
89
|
},
|
|
87
90
|
"devDependencies": {
|
|
88
91
|
"@jupyterlab/builder": "^4.0.0",
|
|
89
92
|
"@types/json-schema": "^7.0.11",
|
|
93
|
+
"@types/node": "^20.11.27",
|
|
90
94
|
"@types/react": "^18.0.26",
|
|
91
95
|
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
92
96
|
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
|
@@ -111,7 +115,12 @@
|
|
|
111
115
|
"jupyterlab": {
|
|
112
116
|
"extension": true,
|
|
113
117
|
"outputDir": "jupyterlab_favorites/labextension",
|
|
114
|
-
"schemaDir": "schema"
|
|
118
|
+
"schemaDir": "schema",
|
|
119
|
+
"sharedPackages": {
|
|
120
|
+
"jupyterlab-myst": {
|
|
121
|
+
"bundled": false
|
|
122
|
+
}
|
|
123
|
+
}
|
|
115
124
|
},
|
|
116
125
|
"styleModule": "style/index.js",
|
|
117
126
|
"prettier": {
|
package/schema/favorites.json
CHANGED
|
@@ -97,6 +97,23 @@
|
|
|
97
97
|
{ "const": "onlyFavoriteCells", "title": "Only favorite Cells" },
|
|
98
98
|
{ "const": "never", "title": "Never" }
|
|
99
99
|
]
|
|
100
|
+
},
|
|
101
|
+
"sortOrder": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"title": "Sort Order",
|
|
104
|
+
"description": "How to sort favorites in the list.",
|
|
105
|
+
"default": "name",
|
|
106
|
+
"oneOf": [
|
|
107
|
+
{ "const": "unsorted", "title": "By Creation Order" },
|
|
108
|
+
{ "const": "name", "title": "By Display Name" },
|
|
109
|
+
{ "const": "path", "title": "By Path" }
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
"groupByType": {
|
|
113
|
+
"type": "boolean",
|
|
114
|
+
"title": "Group by Type",
|
|
115
|
+
"description": "Group directories before files when sorting.",
|
|
116
|
+
"default": true
|
|
100
117
|
}
|
|
101
118
|
},
|
|
102
119
|
"title": "Favorites",
|
package/style/base.css
CHANGED
|
@@ -45,6 +45,17 @@
|
|
|
45
45
|
max-height: 120px;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
.jp-Favorites-resize-handle {
|
|
49
|
+
height: 4px;
|
|
50
|
+
background: transparent;
|
|
51
|
+
cursor: ns-resize;
|
|
52
|
+
user-select: none;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.jp-Favorites-resize-handle:hover {
|
|
56
|
+
background: var(--jp-border-color1);
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
.jp-Favorites {
|
|
49
60
|
flex: 0 0 auto;
|
|
50
61
|
overflow: visible;
|