Skip to content

Commit 480c541

Browse files
authored
Merge pull request #59 from s1m4ne/58-quick-settings-context-menu
Add quick settings context menu and reorganize settings (Issue #58)
2 parents fe84d9a + 9ff6e4b commit 480c541

File tree

8 files changed

+425
-95
lines changed

8 files changed

+425
-95
lines changed

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "workspace-plus-plus",
33
"name": "Workspace++",
4-
"version": "0.7.5",
4+
"version": "0.7.6",
55
"minAppVersion": "1.11.0",
66
"description": "Workspace session manager with a native-feeling UI/UX.",
77
"author": "s1m4ne",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-workspace-plus",
3-
"version": "0.7.5",
3+
"version": "0.7.6",
44
"description": "Workspace session manager for Obsidian",
55
"main": "main.js",
66
"scripts": {

src/i18n.js

Lines changed: 164 additions & 70 deletions
Large diffs are not rendered by default.

src/modals/session-manager-modal.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var formatRelativeTime = require('./format-relative-time');
88
var groupTabUi = require('../group-tab-ui');
99
var utils = require('../utils');
1010
var sessionContextMenu = require('../session-context-menu');
11+
var settingsContextMenu = require('../settings-context-menu');
1112
var sessionListActions = require('../session-list-actions');
1213

1314
// ============================================================
@@ -121,6 +122,25 @@ var SessionManagerModal = /** @class */ (function (_super) {
121122
footer.createDiv({ text: L.footerDragToGroup });
122123
}
123124

125+
// Right-click on empty area → settings context menu
126+
contentEl.addEventListener('contextmenu', function (e) {
127+
if (e.target.closest('.wpp-session-item')) return;
128+
if (e.target.closest('.wpp-save-container')) return;
129+
if (e.target.closest('.wpp-filter-container')) return;
130+
if (e.target.closest('.wpp-bulk-actions')) return;
131+
if (e.target.closest('.wpp-group-tab')) return;
132+
e.preventDefault();
133+
settingsContextMenu.openSettingsContextMenu({
134+
plugin: self.plugin,
135+
app: self.app,
136+
event: e,
137+
onChanged: function () {
138+
self.renderGroupTabs();
139+
self.renderList();
140+
},
141+
});
142+
});
143+
124144
// Keyboard handling: Enter activation + directional arrow traversal.
125145
this.modalKeyHandler = function (e) {
126146
if (document.querySelector('.wpp-confirm-buttons')) return;

src/plugin/methods/overlays.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var formatRelativeTime = require('../../modals/format-relative-time');
77
var groupTabUi = require('../../group-tab-ui');
88
var utils = require('../../utils');
99
var sessionContextMenu = require('../../session-context-menu');
10+
var settingsContextMenu = require('../../settings-context-menu');
1011
var sessionListActions = require('../../session-list-actions');
1112

1213
function hasBlockingModal() {
@@ -954,6 +955,33 @@ function attachOverlayMethods(WorkspacePlusPlus) {
954955
self.persistData();
955956
});
956957

958+
// Right-click on empty area → settings context menu
959+
overlay.addEventListener('contextmenu', function (e) {
960+
if (e.target.closest('.wpp-switch-item')) return;
961+
if (e.target.closest('.wpp-search-input')) return;
962+
if (e.target.closest('.wpp-search-close')) return;
963+
if (e.target.closest('.wpp-qs-action-btn')) return;
964+
if (e.target.closest('.wpp-group-tab')) return;
965+
e.preventDefault();
966+
settingsContextMenu.openSettingsContextMenu({
967+
plugin: self,
968+
app: self.app,
969+
event: e,
970+
showResetOverlay: true,
971+
onResetOverlay: function () {
972+
resetSize();
973+
positionToAnchor();
974+
self.data.searchOverlayPosition = null;
975+
self.data.searchOverlaySize = null;
976+
self.persistData();
977+
},
978+
onChanged: function () {
979+
renderGroupTabs();
980+
refreshOrderedSessions();
981+
},
982+
});
983+
});
984+
957985
// Resize via corner handles
958986
overlay.addEventListener('mousedown', function (e) {
959987
var cornerEl = e.target.closest('.wpp-resize-corner');

src/settings-context-menu.js

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
'use strict';
2+
3+
var obsidian = require('obsidian');
4+
var i18n = require('./i18n');
5+
6+
/**
7+
* Open a settings context menu on empty area of Session Manager / Quick Switcher.
8+
*
9+
* @param {Object} options
10+
* @param {Object} options.plugin - plugin instance
11+
* @param {Object} options.app - Obsidian app
12+
* @param {MouseEvent} options.event - right-click event
13+
* @param {boolean} [options.showResetOverlay] - show "Reset position and size" (Quick Switcher only)
14+
* @param {Function} [options.onResetOverlay] - callback for reset position/size
15+
* @param {Function} [options.onChanged] - callback after any setting toggled (for UI refresh)
16+
*/
17+
function openSettingsContextMenu(options) {
18+
var L = i18n.L;
19+
options = options || {};
20+
var plugin = options.plugin;
21+
var app = options.app || (plugin ? plugin.app : null);
22+
if (!plugin || !app) return;
23+
24+
var menu = new obsidian.Menu();
25+
26+
// --- Auto-save section ---
27+
var autoSaveOn = plugin.isAutoSaveOnSwitchEnabled();
28+
29+
menu.addItem(function (mi) {
30+
mi.setTitle(L.settingsAutoSaveOnSwitch);
31+
mi.setIcon('save');
32+
if (autoSaveOn) mi.setChecked(true);
33+
mi.onClick(function () {
34+
plugin.setAutoSaveOnSwitch(!autoSaveOn, { notify: true }).then(function () {
35+
if (typeof options.onChanged === 'function') options.onChanged();
36+
});
37+
});
38+
});
39+
40+
if (!autoSaveOn) {
41+
menu.addItem(function (mi) {
42+
mi.setTitle(L.settingsWarnUnsavedSwitch);
43+
mi.setIcon('alert-triangle');
44+
if (plugin.isWarnOnUnsavedSwitchEnabled()) mi.setChecked(true);
45+
mi.onClick(function () {
46+
plugin.data.warnOnUnsavedSwitch = !plugin.isWarnOnUnsavedSwitchEnabled();
47+
plugin.persistData();
48+
if (typeof options.onChanged === 'function') options.onChanged();
49+
});
50+
});
51+
52+
menu.addItem(function (mi) {
53+
mi.setTitle(L.settingsConfirmQuickActions);
54+
mi.setIcon('check-circle');
55+
if (plugin.data.confirmQuickActions) mi.setChecked(true);
56+
mi.onClick(function () {
57+
plugin.data.confirmQuickActions = !plugin.data.confirmQuickActions;
58+
plugin.persistData();
59+
if (typeof options.onChanged === 'function') options.onChanged();
60+
});
61+
});
62+
}
63+
64+
menu.addItem(function (mi) {
65+
mi.setTitle(L.settingsConfirmDelete);
66+
mi.setIcon('shield');
67+
if (plugin.data.confirmDeleteByHotkey !== false) mi.setChecked(true);
68+
mi.onClick(function () {
69+
plugin.data.confirmDeleteByHotkey = !(plugin.data.confirmDeleteByHotkey !== false);
70+
plugin.persistData();
71+
if (typeof options.onChanged === 'function') options.onChanged();
72+
});
73+
});
74+
75+
menu.addSeparator();
76+
77+
// --- Feature toggles ---
78+
menu.addItem(function (mi) {
79+
mi.setTitle(L.settingsVersionHistoryEnabled);
80+
mi.setIcon('history');
81+
if (plugin.isVersionHistoryEnabled()) mi.setChecked(true);
82+
mi.onClick(function () {
83+
var next = !plugin.isVersionHistoryEnabled();
84+
plugin.data.versionHistoryEnabled = next;
85+
plugin.persistData();
86+
if (next) {
87+
plugin.startHistorySnapshotTimer();
88+
} else {
89+
plugin.stopHistorySnapshotTimer();
90+
}
91+
if (typeof options.onChanged === 'function') options.onChanged();
92+
});
93+
});
94+
95+
menu.addItem(function (mi) {
96+
mi.setTitle(L.contextToggleGroups);
97+
mi.setIcon('folder');
98+
if (plugin.isGroupFeatureEnabled()) mi.setChecked(true);
99+
mi.onClick(function () {
100+
plugin.setGroupFeatureEnabled(!plugin.isGroupFeatureEnabled()).then(function () {
101+
if (typeof options.onChanged === 'function') options.onChanged();
102+
});
103+
});
104+
});
105+
106+
menu.addSeparator();
107+
108+
// --- Actions ---
109+
menu.addItem(function (mi) {
110+
mi.setTitle(L.rotationBackupCreate);
111+
mi.setIcon('archive');
112+
mi.onClick(function () {
113+
var sessionData = plugin.extractSessionData(plugin.data);
114+
sessionData._wppSavedAt = Date.now();
115+
plugin.ensureDir(plugin.getBackupsDirPath())
116+
.then(function () {
117+
return plugin.copyFileIfExists(
118+
plugin.getRotationBackupPath(2),
119+
plugin.getRotationBackupPath(3)
120+
);
121+
})
122+
.then(function () {
123+
return plugin.copyFileIfExists(
124+
plugin.getRotationBackupPath(1),
125+
plugin.getRotationBackupPath(2)
126+
);
127+
})
128+
.then(function () {
129+
return plugin.writeJson(
130+
plugin.getRotationBackupPath(1),
131+
sessionData
132+
);
133+
})
134+
.then(function () {
135+
plugin._lastRotationBackupAt = Date.now();
136+
new obsidian.Notice(L.rotationBackupCreated);
137+
})
138+
.catch(function () {
139+
new obsidian.Notice(L.rotationBackupFailed);
140+
});
141+
});
142+
});
143+
144+
menu.addItem(function (mi) {
145+
mi.setTitle(L.settingsHotkeysBtn);
146+
mi.setIcon('keyboard');
147+
mi.onClick(function () {
148+
app.setting.open();
149+
app.setting.openTabById('hotkeys');
150+
var sc = app.setting.activeTab.searchComponent;
151+
var pluginName = (plugin.manifest && plugin.manifest.name)
152+
? plugin.manifest.name
153+
: 'Workspace++';
154+
sc.setValue(pluginName);
155+
sc.inputEl.dispatchEvent(new Event('input'));
156+
});
157+
});
158+
159+
menu.addItem(function (mi) {
160+
mi.setTitle(L.contextOpenSettings);
161+
mi.setIcon('settings');
162+
mi.onClick(function () {
163+
app.setting.open();
164+
app.setting.openTabById(plugin.manifest.id);
165+
});
166+
});
167+
168+
// --- Quick Switcher only: Reset position ---
169+
if (options.showResetOverlay) {
170+
menu.addSeparator();
171+
menu.addItem(function (mi) {
172+
mi.setTitle(L.contextResetOverlayPosition);
173+
mi.setIcon('rotate-ccw');
174+
mi.onClick(function () {
175+
if (typeof options.onResetOverlay === 'function') options.onResetOverlay();
176+
});
177+
});
178+
}
179+
180+
menu.showAtMouseEvent(options.event);
181+
}
182+
183+
module.exports = {
184+
openSettingsContextMenu: openSettingsContextMenu,
185+
};

src/settings.js

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,29 @@ var WorkspacePlusPlusSettingTab = /** @class */ (function (_super) {
256256
});
257257
});
258258

259-
addToggleSetting(contentEl, {
260-
name: L.settingsWarnUnsavedSwitch,
261-
desc: L.settingsWarnUnsavedSwitchDesc,
262-
value: self.plugin.isWarnOnUnsavedSwitchEnabled(),
263-
disabled: autoSaveOnSwitch,
264-
onChange: function (value) {
265-
self.plugin.data.warnOnUnsavedSwitch = value;
266-
self.plugin.persistData();
267-
},
268-
});
259+
if (!autoSaveOnSwitch) {
260+
addToggleSetting(contentEl, {
261+
name: L.settingsWarnUnsavedSwitch,
262+
desc: L.settingsWarnUnsavedSwitchDesc,
263+
value: self.plugin.isWarnOnUnsavedSwitchEnabled(),
264+
onChange: function (value) {
265+
self.plugin.data.warnOnUnsavedSwitch = value;
266+
self.plugin.persistData();
267+
},
268+
});
269+
270+
addToggleSetting(contentEl, {
271+
name: L.settingsConfirmQuickActions,
272+
desc: L.settingsConfirmQuickActionsDesc,
273+
value: !!self.plugin.data.confirmQuickActions,
274+
onChange: function (value) {
275+
self.plugin.data.confirmQuickActions = value;
276+
self.plugin.persistData();
277+
},
278+
});
279+
}
280+
281+
addSection(L.settingsSectionSwitchPreview);
269282

270283
// Preview before switching — master toggle with nested sub-toggles
271284
var allOn = !!self.plugin.data.previewNext && !!self.plugin.data.previewPrevious;
@@ -319,16 +332,6 @@ var WorkspacePlusPlusSettingTab = /** @class */ (function (_super) {
319332
},
320333
});
321334

322-
addToggleSetting(contentEl, {
323-
name: L.settingsConfirmQuickActions,
324-
desc: L.settingsConfirmQuickActionsDesc,
325-
value: !!self.plugin.data.confirmQuickActions,
326-
onChange: function (value) {
327-
self.plugin.data.confirmQuickActions = value;
328-
self.plugin.persistData();
329-
},
330-
});
331-
332335
// --- Version History ---
333336
addSection(L.historyTitle);
334337

styles.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
.wpp-save-container {
88
display: flex;
99
gap: 8px;
10-
margin-bottom: 16px;
10+
margin-bottom: 8px;
1111
}
1212

1313
.wpp-save-input {
1414
flex: 1;
1515
}
1616

1717
.wpp-filter-container {
18-
margin-bottom: 10px;
18+
margin-bottom: 8px;
1919
}
2020

2121
.wpp-filter-input {
@@ -26,7 +26,7 @@
2626
.wpp-session-list {
2727
display: flex;
2828
flex-direction: column;
29-
gap: 2px;
29+
gap: 4px;
3030
max-height: 60vh;
3131
overflow-y: auto;
3232
}

0 commit comments

Comments
 (0)