@matdata/yasgui 5.17.0 → 5.18.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/build/ts/src/Tab.js +6 -0
- package/build/ts/src/Tab.js.map +1 -1
- package/build/ts/src/TabContextMenu.d.ts +1 -0
- package/build/ts/src/TabContextMenu.js +42 -0
- package/build/ts/src/TabContextMenu.js.map +1 -1
- package/build/ts/src/TabSettingsModal.d.ts +0 -1
- package/build/ts/src/TabSettingsModal.js +22 -25
- package/build/ts/src/TabSettingsModal.js.map +1 -1
- package/build/ts/src/index.d.ts +6 -0
- package/build/ts/src/index.js +42 -0
- package/build/ts/src/index.js.map +1 -1
- package/build/ts/src/prefixUtils.d.ts +1 -0
- package/build/ts/src/prefixUtils.js +23 -0
- package/build/ts/src/prefixUtils.js.map +1 -0
- package/build/ts/src/queryManagement/QueryBrowser.d.ts +8 -0
- package/build/ts/src/queryManagement/QueryBrowser.js +283 -116
- package/build/ts/src/queryManagement/QueryBrowser.js.map +1 -1
- package/build/ts/src/queryManagement/QueryHistoryModal.d.ts +35 -0
- package/build/ts/src/queryManagement/QueryHistoryModal.js +266 -0
- package/build/ts/src/queryManagement/QueryHistoryModal.js.map +1 -0
- package/build/ts/src/queryManagement/WorkspaceSettingsForm.js +8 -5
- package/build/ts/src/queryManagement/WorkspaceSettingsForm.js.map +1 -1
- package/build/ts/src/queryManagement/backends/GitWorkspaceBackend.d.ts +1 -0
- package/build/ts/src/queryManagement/backends/GitWorkspaceBackend.js +33 -0
- package/build/ts/src/queryManagement/backends/GitWorkspaceBackend.js.map +1 -1
- package/build/ts/src/queryManagement/backends/SparqlWorkspaceBackend.d.ts +1 -0
- package/build/ts/src/queryManagement/backends/SparqlWorkspaceBackend.js +3 -0
- package/build/ts/src/queryManagement/backends/SparqlWorkspaceBackend.js.map +1 -1
- package/build/ts/src/queryManagement/backends/WorkspaceBackend.d.ts +1 -0
- package/build/ts/src/queryManagement/countManagedQueries.d.ts +2 -0
- package/build/ts/src/queryManagement/countManagedQueries.js +35 -0
- package/build/ts/src/queryManagement/countManagedQueries.js.map +1 -0
- package/build/ts/src/tabNavigationHistory.d.ts +3 -0
- package/build/ts/src/tabNavigationHistory.js +13 -0
- package/build/ts/src/tabNavigationHistory.js.map +1 -0
- package/build/ts/src/version.d.ts +1 -1
- package/build/ts/src/version.js +1 -1
- package/build/yasgui.min.css +1 -1
- package/build/yasgui.min.css.map +3 -3
- package/build/yasgui.min.js +169 -169
- package/build/yasgui.min.js.map +4 -4
- package/package.json +1 -1
- package/src/Tab.ts +9 -0
- package/src/TabContextMenu.ts +42 -0
- package/src/TabSettingsModal.ts +22 -29
- package/src/index.ts +50 -0
- package/src/prefixUtils.ts +26 -0
- package/src/queryManagement/QueryBrowser.scss +85 -0
- package/src/queryManagement/QueryBrowser.ts +429 -213
- package/src/queryManagement/QueryHistoryModal.scss +239 -0
- package/src/queryManagement/QueryHistoryModal.ts +346 -0
- package/src/queryManagement/WorkspaceSettingsForm.ts +8 -5
- package/src/queryManagement/backends/GitWorkspaceBackend.ts +39 -0
- package/src/queryManagement/backends/SparqlWorkspaceBackend.ts +5 -0
- package/src/queryManagement/backends/WorkspaceBackend.ts +8 -0
- package/src/queryManagement/countManagedQueries.ts +28 -0
- package/src/tabNavigationHistory.ts +17 -0
- package/src/themes.scss +2 -0
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/Tab.ts
CHANGED
|
@@ -436,6 +436,15 @@ export class Tab extends EventEmitter {
|
|
|
436
436
|
private handleKeyDown = (event: KeyboardEvent) => {
|
|
437
437
|
if (event.defaultPrevented) return;
|
|
438
438
|
|
|
439
|
+
// Ctrl+, → backward (less recently used), Ctrl+Alt+, → forward (more recently used)
|
|
440
|
+
// Ctrl+Tab / Ctrl+Shift+Tab cannot be used: the browser intercepts them before keydown fires
|
|
441
|
+
const isTabSwitchShortcut = (event.ctrlKey || event.metaKey) && !event.shiftKey && event.key === ",";
|
|
442
|
+
if (isTabSwitchShortcut) {
|
|
443
|
+
event.preventDefault();
|
|
444
|
+
this.yasgui.selectRecentlyUsedTab(event.altKey ? "forward" : "backward");
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
439
448
|
const saveModalOpen = !!document.querySelector(".saveManagedQueryModalOverlay.open");
|
|
440
449
|
if (!saveModalOpen) {
|
|
441
450
|
const isSaveShortcut =
|
package/src/TabContextMenu.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { default as Yasgui, getRandomId } from "./";
|
|
|
3
3
|
import Tab from "./Tab";
|
|
4
4
|
import { TabListEl } from "./TabElements";
|
|
5
5
|
import { cloneDeep } from "lodash-es";
|
|
6
|
+
import { getWorkspaceBackend } from "./queryManagement/backends/getWorkspaceBackend";
|
|
7
|
+
import type { GitQueryRef, SparqlQueryRef } from "./queryManagement/types";
|
|
6
8
|
import "./TabContextMenu.scss";
|
|
7
9
|
export interface TabContextConfig {
|
|
8
10
|
name: string;
|
|
@@ -17,6 +19,7 @@ export default class TabContextMenu {
|
|
|
17
19
|
private duplicateTabEl!: HTMLElement;
|
|
18
20
|
private saveManagedQueryEl!: HTMLElement;
|
|
19
21
|
private saveAsRqFileEl!: HTMLElement;
|
|
22
|
+
private copyManagedQueryUriEl!: HTMLElement;
|
|
20
23
|
private closeTabEl!: HTMLElement;
|
|
21
24
|
private closeOtherTabsEl!: HTMLElement;
|
|
22
25
|
private reOpenOldTab!: HTMLElement;
|
|
@@ -55,6 +58,8 @@ export default class TabContextMenu {
|
|
|
55
58
|
|
|
56
59
|
this.saveAsRqFileEl = this.getMenuItemEl("Save as .rq file");
|
|
57
60
|
|
|
61
|
+
this.copyManagedQueryUriEl = this.getMenuItemEl("Copy URI");
|
|
62
|
+
|
|
58
63
|
this.closeTabEl = this.getMenuItemEl("Close Tab");
|
|
59
64
|
|
|
60
65
|
this.closeOtherTabsEl = this.getMenuItemEl("Close other tabs");
|
|
@@ -67,6 +72,7 @@ export default class TabContextMenu {
|
|
|
67
72
|
dropDownList.appendChild(this.duplicateTabEl);
|
|
68
73
|
dropDownList.appendChild(this.saveManagedQueryEl);
|
|
69
74
|
dropDownList.appendChild(this.saveAsRqFileEl);
|
|
75
|
+
dropDownList.appendChild(this.copyManagedQueryUriEl);
|
|
70
76
|
// Add divider
|
|
71
77
|
dropDownList.appendChild(document.createElement("hr"));
|
|
72
78
|
dropDownList.appendChild(this.closeTabEl);
|
|
@@ -125,6 +131,42 @@ export default class TabContextMenu {
|
|
|
125
131
|
this.closeConfigMenu();
|
|
126
132
|
};
|
|
127
133
|
|
|
134
|
+
// Copy URI for managed query tabs
|
|
135
|
+
const meta = tab?.getManagedQueryMetadata();
|
|
136
|
+
if (meta) {
|
|
137
|
+
const workspaceConfig = this.yasgui.persistentConfig?.getWorkspaces().find((w) => w.id === meta.workspaceId);
|
|
138
|
+
if (workspaceConfig) {
|
|
139
|
+
const queryId =
|
|
140
|
+
meta.backendType === "git"
|
|
141
|
+
? (meta.queryRef as GitQueryRef).path
|
|
142
|
+
: (meta.queryRef as SparqlQueryRef).managedQueryIri;
|
|
143
|
+
if (queryId) {
|
|
144
|
+
const backend = getWorkspaceBackend(workspaceConfig, {
|
|
145
|
+
persistentConfig: this.yasgui.persistentConfig,
|
|
146
|
+
});
|
|
147
|
+
const uri = backend.getQueryUri?.(queryId);
|
|
148
|
+
if (uri) {
|
|
149
|
+
this.copyManagedQueryUriEl.onclick = async () => {
|
|
150
|
+
try {
|
|
151
|
+
await navigator.clipboard.writeText(uri);
|
|
152
|
+
} catch {
|
|
153
|
+
window.prompt("Copy this URI:", uri);
|
|
154
|
+
}
|
|
155
|
+
this.closeConfigMenu();
|
|
156
|
+
};
|
|
157
|
+
} else {
|
|
158
|
+
addClass(this.copyManagedQueryUriEl, "disabled");
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
addClass(this.copyManagedQueryUriEl, "disabled");
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
addClass(this.copyManagedQueryUriEl, "disabled");
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
addClass(this.copyManagedQueryUriEl, "disabled");
|
|
168
|
+
}
|
|
169
|
+
|
|
128
170
|
// Close tab functionality
|
|
129
171
|
this.closeTabEl.onclick = () => tab?.close();
|
|
130
172
|
|
package/src/TabSettingsModal.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as ConfigExportImport from "./ConfigExportImport";
|
|
|
5
5
|
import { VERSION } from "./version";
|
|
6
6
|
import * as OAuth2Utils from "./OAuth2Utils";
|
|
7
7
|
import PersistentConfig from "./PersistentConfig";
|
|
8
|
+
import { deduplicatePrefixes } from "./prefixUtils";
|
|
8
9
|
import { WorkspaceSettingsForm } from "./queryManagement/WorkspaceSettingsForm";
|
|
9
10
|
|
|
10
11
|
const AcceptOptionsMap: { key: string; value: string }[] = [
|
|
@@ -847,7 +848,12 @@ export default class TabSettingsModal {
|
|
|
847
848
|
|
|
848
849
|
private renderEndpointsList(container: HTMLElement) {
|
|
849
850
|
container.innerHTML = "";
|
|
850
|
-
const configs = this.tab.yasgui.persistentConfig.getEndpointConfigs();
|
|
851
|
+
const configs = [...this.tab.yasgui.persistentConfig.getEndpointConfigs()];
|
|
852
|
+
configs.sort((a, b) => {
|
|
853
|
+
const aKey = (a.label || a.endpoint).toLowerCase();
|
|
854
|
+
const bKey = (b.label || b.endpoint).toLowerCase();
|
|
855
|
+
return aKey.localeCompare(bKey);
|
|
856
|
+
});
|
|
851
857
|
|
|
852
858
|
// Create table (even if empty, we'll show add form)
|
|
853
859
|
const table = document.createElement("table");
|
|
@@ -1687,7 +1693,7 @@ export default class TabSettingsModal {
|
|
|
1687
1693
|
const autoCapture = this.autoCaptureCheckbox.checked;
|
|
1688
1694
|
|
|
1689
1695
|
// Parse and deduplicate prefixes
|
|
1690
|
-
const deduplicated =
|
|
1696
|
+
const deduplicated = deduplicatePrefixes(prefixText);
|
|
1691
1697
|
this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
|
|
1692
1698
|
this.tab.yasgui.persistentConfig.setAutoCaptureEnabled(autoCapture);
|
|
1693
1699
|
|
|
@@ -1798,32 +1804,6 @@ export default class TabSettingsModal {
|
|
|
1798
1804
|
this.close();
|
|
1799
1805
|
}
|
|
1800
1806
|
|
|
1801
|
-
private deduplicatePrefixes(prefixText: string): string {
|
|
1802
|
-
const lines = prefixText.split("\n");
|
|
1803
|
-
const seen = new Map<string, string>();
|
|
1804
|
-
const result: string[] = [];
|
|
1805
|
-
|
|
1806
|
-
for (const line of lines) {
|
|
1807
|
-
const trimmed = line.trim();
|
|
1808
|
-
if (!trimmed) continue;
|
|
1809
|
-
|
|
1810
|
-
// Extract prefix label from line
|
|
1811
|
-
const match = trimmed.match(/^\s*PREFIX\s+(\w+):\s*<(.+)>\s*$/i);
|
|
1812
|
-
if (match) {
|
|
1813
|
-
const label = match[1].toLowerCase();
|
|
1814
|
-
if (!seen.has(label)) {
|
|
1815
|
-
seen.set(label, trimmed);
|
|
1816
|
-
result.push(trimmed);
|
|
1817
|
-
}
|
|
1818
|
-
} else {
|
|
1819
|
-
// Keep non-prefix lines as-is
|
|
1820
|
-
result.push(trimmed);
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
return result.join("\n");
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
1807
|
private insertPrefixesIntoQuery() {
|
|
1828
1808
|
const yasqe = this.tab.getYasqe();
|
|
1829
1809
|
if (!yasqe) return;
|
|
@@ -1885,7 +1865,7 @@ export default class TabSettingsModal {
|
|
|
1885
1865
|
// Merge with existing prefixes
|
|
1886
1866
|
const existingPrefixes = this.tab.yasgui.persistentConfig.getPrefixes();
|
|
1887
1867
|
const combined = existingPrefixes + "\n" + newPrefixLines.join("\n");
|
|
1888
|
-
const deduplicated =
|
|
1868
|
+
const deduplicated = deduplicatePrefixes(combined);
|
|
1889
1869
|
|
|
1890
1870
|
this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
|
|
1891
1871
|
}
|
|
@@ -2078,6 +2058,19 @@ export default class TabSettingsModal {
|
|
|
2078
2058
|
{ keys: ["Esc"], description: "Exit fullscreen mode" },
|
|
2079
2059
|
],
|
|
2080
2060
|
},
|
|
2061
|
+
{
|
|
2062
|
+
category: "YASGUI Tabs",
|
|
2063
|
+
shortcuts: [
|
|
2064
|
+
{
|
|
2065
|
+
keys: ["Ctrl+Alt+Tab", "Cmd+Alt+Tab"],
|
|
2066
|
+
description: "Switch to previously used YASGUI tab",
|
|
2067
|
+
},
|
|
2068
|
+
{
|
|
2069
|
+
keys: ["Ctrl+Alt+Shift+Tab", "Cmd+Alt+Shift+Tab"],
|
|
2070
|
+
description: "Switch to next YASGUI tab in recently used order",
|
|
2071
|
+
},
|
|
2072
|
+
],
|
|
2073
|
+
},
|
|
2081
2074
|
];
|
|
2082
2075
|
|
|
2083
2076
|
shortcutsData.forEach((section) => {
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { addClass, removeClass } from "@matdata/yasgui-utils";
|
|
|
13
13
|
import GeoPlugin from "yasgui-geo-tg";
|
|
14
14
|
import GraphPlugin from "@matdata/yasgui-graph-plugin";
|
|
15
15
|
import TablePlugin from "@matdata/yasgui-table-plugin";
|
|
16
|
+
import { moveTabIdToFront, removeTabId } from "./tabNavigationHistory";
|
|
16
17
|
import "@matdata/yasgui-graph-plugin/dist/yasgui-graph-plugin.min.css";
|
|
17
18
|
import "@matdata/yasgui-table-plugin/dist/yasgui-table-plugin.min.css";
|
|
18
19
|
import { ThemeManager, Theme } from "./ThemeManager";
|
|
@@ -155,6 +156,9 @@ export class Yasgui extends EventEmitter {
|
|
|
155
156
|
public persistentConfig: PersistentConfig;
|
|
156
157
|
public themeManager: ThemeManager;
|
|
157
158
|
public queryBrowser: QueryBrowser;
|
|
159
|
+
private recentTabIds: string[] = [];
|
|
160
|
+
private navigationSnapshot: string[] | null = null;
|
|
161
|
+
private navigationCursor = 0;
|
|
158
162
|
public static Tab = Tab;
|
|
159
163
|
constructor(parent: HTMLElement, config: PartialConfig) {
|
|
160
164
|
super();
|
|
@@ -185,6 +189,9 @@ export class Yasgui extends EventEmitter {
|
|
|
185
189
|
this.tabPanelsEl = document.createElement("div");
|
|
186
190
|
|
|
187
191
|
this.queryBrowser = new QueryBrowser(this);
|
|
192
|
+
this.on("tabClose", (_yasgui, tab) => {
|
|
193
|
+
this.removeTabFromRecentHistory(tab.getId());
|
|
194
|
+
});
|
|
188
195
|
|
|
189
196
|
this.rootEl.appendChild(this.tabElements.drawTabsList());
|
|
190
197
|
this.rootEl.appendChild(this.tabPanelsEl);
|
|
@@ -227,6 +234,7 @@ export class Yasgui extends EventEmitter {
|
|
|
227
234
|
const newTab = this.addTab(true);
|
|
228
235
|
this.persistentConfig.setActive(newTab.getId());
|
|
229
236
|
this.emit("tabChange", this, newTab);
|
|
237
|
+
this.recordTabInRecentHistory(newTab.getId());
|
|
230
238
|
} else {
|
|
231
239
|
for (const tabId of tabs) {
|
|
232
240
|
this._tabs[tabId] = new Tab(this, this.persistentConfig.getTab(tabId));
|
|
@@ -237,6 +245,7 @@ export class Yasgui extends EventEmitter {
|
|
|
237
245
|
const activeTabId = this.persistentConfig.getActiveId();
|
|
238
246
|
if (activeTabId) {
|
|
239
247
|
this.markTabSelected(activeTabId);
|
|
248
|
+
this.recordTabInRecentHistory(activeTabId);
|
|
240
249
|
if (executeIdAfterInit && executeIdAfterInit === activeTabId) {
|
|
241
250
|
(this.getTab(activeTabId) as Tab).query().catch(() => {});
|
|
242
251
|
}
|
|
@@ -300,6 +309,7 @@ export class Yasgui extends EventEmitter {
|
|
|
300
309
|
const tab = this.getTab();
|
|
301
310
|
if (tab && tab.getId() !== tabId) {
|
|
302
311
|
if (this.markTabSelected(tabId)) {
|
|
312
|
+
this.recordTabInRecentHistory(tabId);
|
|
303
313
|
//emit
|
|
304
314
|
this.emit("tabSelect", this, tabId);
|
|
305
315
|
this.persistentConfig.setActive(tabId);
|
|
@@ -307,6 +317,45 @@ export class Yasgui extends EventEmitter {
|
|
|
307
317
|
}
|
|
308
318
|
return tab;
|
|
309
319
|
}
|
|
320
|
+
private recordTabInRecentHistory(tabId: string) {
|
|
321
|
+
// Any non-navigation selection commits the navigation and ends navigation mode.
|
|
322
|
+
this.navigationSnapshot = null;
|
|
323
|
+
this.recentTabIds = moveTabIdToFront(this.recentTabIds, tabId);
|
|
324
|
+
}
|
|
325
|
+
private removeTabFromRecentHistory(tabId: string) {
|
|
326
|
+
this.recentTabIds = removeTabId(this.recentTabIds, tabId);
|
|
327
|
+
}
|
|
328
|
+
public selectRecentlyUsedTab(direction: "backward" | "forward" = "backward"): void {
|
|
329
|
+
const activeTab = this.getTab();
|
|
330
|
+
if (!activeTab) return;
|
|
331
|
+
const activeTabId = activeTab.getId();
|
|
332
|
+
|
|
333
|
+
// Initialize (or re-initialize) the navigation snapshot when starting a new navigation
|
|
334
|
+
// sequence or when the active tab no longer matches the cursor position.
|
|
335
|
+
// Snapshotting the history order lets repeated presses cycle through all tabs
|
|
336
|
+
// instead of ping-ponging between the two most-recently-used ones.
|
|
337
|
+
if (this.navigationSnapshot === null || this.navigationSnapshot[this.navigationCursor] !== activeTabId) {
|
|
338
|
+
this.navigationSnapshot = [...this.recentTabIds];
|
|
339
|
+
const activeIdx = this.navigationSnapshot.indexOf(activeTabId);
|
|
340
|
+
this.navigationCursor = activeIdx >= 0 ? activeIdx : 0;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (direction === "backward") {
|
|
344
|
+
this.navigationCursor = Math.min(this.navigationCursor + 1, this.navigationSnapshot.length - 1);
|
|
345
|
+
} else {
|
|
346
|
+
this.navigationCursor = Math.max(this.navigationCursor - 1, 0);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const nextTabId = this.navigationSnapshot[this.navigationCursor];
|
|
350
|
+
if (!nextTabId || nextTabId === activeTabId) return;
|
|
351
|
+
|
|
352
|
+
// Select the tab without updating recentTabIds. The history is committed when the
|
|
353
|
+
// user performs any non-navigation action that calls recordTabInRecentHistory.
|
|
354
|
+
if (this.markTabSelected(nextTabId)) {
|
|
355
|
+
this.emit("tabSelect", this, nextTabId);
|
|
356
|
+
this.persistentConfig.setActive(nextTabId);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
310
359
|
/**
|
|
311
360
|
* Checks if two persistent tab configuration are the same based.
|
|
312
361
|
* It isnt a strict equality, as falsy values (e.g. a header that isnt set in one tabjson) isnt taken into consideration
|
|
@@ -417,6 +466,7 @@ export class Yasgui extends EventEmitter {
|
|
|
417
466
|
if (setActive) {
|
|
418
467
|
this.persistentConfig.setActive(tabId);
|
|
419
468
|
this._tabs[tabId].show();
|
|
469
|
+
this.recordTabInRecentHistory(tabId);
|
|
420
470
|
}
|
|
421
471
|
return this._tabs[tabId];
|
|
422
472
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function deduplicatePrefixes(prefixText: string): string {
|
|
2
|
+
const lines = prefixText.split("\n");
|
|
3
|
+
const seen = new Set<string>();
|
|
4
|
+
const result: string[] = [];
|
|
5
|
+
|
|
6
|
+
for (const line of lines) {
|
|
7
|
+
const trimmed = line.trim();
|
|
8
|
+
if (!trimmed) continue;
|
|
9
|
+
|
|
10
|
+
// Allow an empty prefix label so the default prefix form `PREFIX : <...>` is
|
|
11
|
+
// deduplicated together with named prefixes, while keeping the original
|
|
12
|
+
// word-character restriction for named labels.
|
|
13
|
+
const match = trimmed.match(/^\s*PREFIX\s+(\w*):\s*<([^>]+)>\s*$/i);
|
|
14
|
+
if (match) {
|
|
15
|
+
const label = match[1].toLowerCase();
|
|
16
|
+
if (!seen.has(label)) {
|
|
17
|
+
seen.add(label);
|
|
18
|
+
result.push(trimmed);
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
result.push(trimmed);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result.join("\n");
|
|
26
|
+
}
|
|
@@ -325,6 +325,91 @@
|
|
|
325
325
|
white-space: nowrap;
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
&__context-menu {
|
|
329
|
+
position: fixed;
|
|
330
|
+
z-index: 10001;
|
|
331
|
+
list-style: none;
|
|
332
|
+
padding: 4px 0;
|
|
333
|
+
margin: 0;
|
|
334
|
+
min-width: 140px;
|
|
335
|
+
background: var(--yasgui-bg-primary, white);
|
|
336
|
+
border: 1px solid var(--yasgui-border-color, #e0e0e0);
|
|
337
|
+
border-radius: 4px;
|
|
338
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
&__context-menu-item {
|
|
342
|
+
padding: 7px 16px;
|
|
343
|
+
cursor: pointer;
|
|
344
|
+
white-space: nowrap;
|
|
345
|
+
color: var(--yasgui-text-primary, #000);
|
|
346
|
+
font-size: 13px;
|
|
347
|
+
line-height: 1.4;
|
|
348
|
+
|
|
349
|
+
&:hover {
|
|
350
|
+
background: var(--yasgui-bg-secondary, #f5f5f5);
|
|
351
|
+
color: var(--yasgui-button-hover, #000);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
&--danger {
|
|
355
|
+
color: var(--yasgui-error-color, #c00);
|
|
356
|
+
|
|
357
|
+
&:hover {
|
|
358
|
+
background: var(--yasgui-bg-secondary, #f5f5f5);
|
|
359
|
+
color: var(--yasgui-error-color, #c00);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
&__rename-input {
|
|
365
|
+
flex: 1;
|
|
366
|
+
min-width: 0;
|
|
367
|
+
font: inherit;
|
|
368
|
+
font-size: 13px;
|
|
369
|
+
color: var(--yasgui-text-primary, #000);
|
|
370
|
+
background: var(--yasgui-bg-primary, white);
|
|
371
|
+
border: 1px solid var(--yasgui-accent-color, #337ab7);
|
|
372
|
+
border-radius: 3px;
|
|
373
|
+
padding: 1px 4px;
|
|
374
|
+
outline: none;
|
|
375
|
+
box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.25);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
&__inline-confirm {
|
|
379
|
+
flex: 1;
|
|
380
|
+
font-size: 13px;
|
|
381
|
+
color: var(--yasgui-text-primary, #000);
|
|
382
|
+
white-space: nowrap;
|
|
383
|
+
overflow: hidden;
|
|
384
|
+
text-overflow: ellipsis;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
&__inline-confirm-btn {
|
|
388
|
+
appearance: none;
|
|
389
|
+
background: transparent;
|
|
390
|
+
border: 1px solid var(--yasgui-border-color, #e0e0e0);
|
|
391
|
+
border-radius: 3px;
|
|
392
|
+
padding: 1px 8px;
|
|
393
|
+
font: inherit;
|
|
394
|
+
font-size: 12px;
|
|
395
|
+
cursor: pointer;
|
|
396
|
+
color: var(--yasgui-text-primary, #000);
|
|
397
|
+
flex-shrink: 0;
|
|
398
|
+
|
|
399
|
+
&:hover {
|
|
400
|
+
background: var(--yasgui-bg-secondary, #f5f5f5);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
&--danger {
|
|
404
|
+
color: var(--yasgui-error-color, #c00);
|
|
405
|
+
border-color: var(--yasgui-error-color, #c00);
|
|
406
|
+
|
|
407
|
+
&:hover {
|
|
408
|
+
background: rgba(204, 0, 0, 0.08);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
328
413
|
&__tree-meta {
|
|
329
414
|
padding: 4px 8px;
|
|
330
415
|
font-size: 13px;
|