@a83/orbiter-admin 0.3.46 → 0.3.48
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/README.md +88 -2
- package/package.json +1 -1
- package/public/account.html +287 -0
- package/public/xfce.js +6 -11
package/README.md
CHANGED
|
@@ -165,9 +165,95 @@ For **External links**, use the External link tab in the image picker. Orbiter m
|
|
|
165
165
|
|
|
166
166
|
---
|
|
167
167
|
|
|
168
|
-
##
|
|
168
|
+
## Space Station mode
|
|
169
|
+
|
|
170
|
+
A distinct admin layout — dark glassmorphism, floating magnification dock, and a full keyboard-driven interface. Enable in **Settings → Interface → Layout → Space Station**.
|
|
171
|
+
|
|
172
|
+
### Command palette `⌘K` or `/`
|
|
173
|
+
|
|
174
|
+
Opens full-screen over any page. Shows the 7 most recent entries on open (no typing required). Type to fuzzy-search pages and collections.
|
|
175
|
+
|
|
176
|
+
**Command mode** — prefix with `>`:
|
|
177
|
+
|
|
178
|
+
| Command | Action |
|
|
179
|
+
|---------|--------|
|
|
180
|
+
| `> ls` | List all collections |
|
|
181
|
+
| `> go <page\|collection>` | Navigate |
|
|
182
|
+
| `> new <collection>` | Create new entry |
|
|
183
|
+
| `> search <term>` | Full-text search |
|
|
184
|
+
| `> build` | Trigger site build |
|
|
185
|
+
| `> export <col> [--md] [--drafts]` | Download collection |
|
|
186
|
+
| `> random` | Jump to a random published entry |
|
|
187
|
+
| `> = <expr>` | Evaluate a math expression (`2^10 * 3`) |
|
|
188
|
+
| `> info` | Pod & version info |
|
|
189
|
+
| `> help` | Show all commands |
|
|
190
|
+
|
|
191
|
+
Command history with ↑/↓. Output rendered inline in the palette.
|
|
192
|
+
|
|
193
|
+
### Keyboard shortcuts
|
|
194
|
+
|
|
195
|
+
| Key | Action |
|
|
196
|
+
|-----|--------|
|
|
197
|
+
| `⌘K` / `/` | Open command palette |
|
|
198
|
+
| `?` | Shortcut cheatsheet |
|
|
199
|
+
| `⌘⇧F` | Zen / focus mode (hides dock + status bar) |
|
|
200
|
+
| `⌘⇧L` | Switch back to Glass mode |
|
|
201
|
+
| `1`–`9` | Jump to nth dock item |
|
|
202
|
+
| `g` + `d` | Dashboard |
|
|
203
|
+
| `g` + `m` | Media |
|
|
204
|
+
| `g` + `u` | Users |
|
|
205
|
+
| `g` + `s` | Settings |
|
|
206
|
+
| `g` + `b` | Build |
|
|
207
|
+
| `g` + `i` | Import |
|
|
208
|
+
| `g` + `c` | Schema |
|
|
209
|
+
| `g` + `h` | Toggle HUD panel |
|
|
210
|
+
| `g` + `a` | Account |
|
|
211
|
+
|
|
212
|
+
A `g ›` badge pulses in the status bar while waiting for the second key.
|
|
213
|
+
|
|
214
|
+
### Status bar
|
|
215
|
+
|
|
216
|
+
- **Left** — Orbiter logo, site name
|
|
217
|
+
- **Center** — page title; breadcrumb (`Collection › Entries`) when inside a collection
|
|
218
|
+
- **Right** — vim `g ›` indicator · bell (notification center) · `?` cheatsheet · `⌘` palette · last build time · username · logout · clock
|
|
219
|
+
|
|
220
|
+
Build indicator shows `◉ building…` with a pulse animation while a build runs, polling `/api/build/status` every 4 seconds.
|
|
221
|
+
|
|
222
|
+
### Notification center
|
|
169
223
|
|
|
170
|
-
|
|
224
|
+
Every save, build trigger, and export is logged automatically. Click the bell `○` in the status bar to open the dropdown. Unread count badge clears on open. "Clear all" resets the log.
|
|
225
|
+
|
|
226
|
+
### HUD panel `g h`
|
|
227
|
+
|
|
228
|
+
Side panel with:
|
|
229
|
+
- **Pod** — file name, versions, collection count
|
|
230
|
+
- **Collections** — published/draft counts per collection
|
|
231
|
+
- **Drafts** — last 10 draft entries, clickable to editor
|
|
232
|
+
- **Activity** — last 8 events (saves, builds, exports) as a live timeline
|
|
233
|
+
- **Navigation** — all pages
|
|
234
|
+
|
|
235
|
+
### Dock
|
|
236
|
+
|
|
237
|
+
Floating bottom bar (or left sidebar — toggle in the Tools popup). Magnification effect on hover. Items:
|
|
238
|
+
|
|
239
|
+
- **Nav group** — Dashboard, Media, Users
|
|
240
|
+
- **Collections group** — one item per collection; draft count badge; hover shows preview card with 3 recent entries and quick-action buttons
|
|
241
|
+
- **Workspace** — Notes scratchpad, To-do list
|
|
242
|
+
- **Tools** — Schema, Build, Import (popup)
|
|
243
|
+
- **Settings** — direct link
|
|
244
|
+
- **HUD** — toggle button
|
|
245
|
+
|
|
246
|
+
### Hover preview cards
|
|
247
|
+
|
|
248
|
+
Hovering a collection dock item after 280 ms shows a card with the 3 most recent entries (title + date) and an action row: `+ new entry · ◫ view all · ↓ export`.
|
|
249
|
+
|
|
250
|
+
### Zen mode `⌘⇧F`
|
|
251
|
+
|
|
252
|
+
Hides the dock and status bar entirely. Smooth CSS transition. Persists across reloads (stored in `localStorage`). A toast hint shows "Focus mode on — ⌘⇧F to exit" on enter.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Themes
|
|
171
257
|
|
|
172
258
|
| Theme | Dark | Light |
|
|
173
259
|
|-------|------|-------|
|
package/package.json
CHANGED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Orbiter Admin — Account</title>
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500&family=Space+Grotesk:wght@300;400;500;600&family=Noto+Serif+JP:wght@200;300&family=DM+Mono:wght@300;400&display=swap" rel="stylesheet">
|
|
10
|
+
<link rel="stylesheet" href="/style.css" />
|
|
11
|
+
<script src="/theme.js"></script>
|
|
12
|
+
<style>
|
|
13
|
+
.account-wrap { max-width: 640px; padding-bottom: 40px; }
|
|
14
|
+
|
|
15
|
+
.settings-group {
|
|
16
|
+
background: var(--bg2);
|
|
17
|
+
border: 1px solid var(--line);
|
|
18
|
+
border-radius: 10px;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
margin-bottom: 12px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.group-header {
|
|
24
|
+
padding: 10px 24px;
|
|
25
|
+
font-size: 10px;
|
|
26
|
+
letter-spacing: 0.18em;
|
|
27
|
+
text-transform: uppercase;
|
|
28
|
+
color: var(--muted);
|
|
29
|
+
border-bottom: 1px solid var(--line);
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: 7px;
|
|
33
|
+
}
|
|
34
|
+
.group-header::before { content: "◆"; color: var(--gold); font-size: 5px; line-height: 1; }
|
|
35
|
+
|
|
36
|
+
.setting-row {
|
|
37
|
+
display: grid;
|
|
38
|
+
grid-template-columns: 1fr 252px;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: 24px;
|
|
41
|
+
padding: 18px 24px;
|
|
42
|
+
border-bottom: 1px solid var(--line2);
|
|
43
|
+
}
|
|
44
|
+
.setting-row:last-child { border-bottom: none; }
|
|
45
|
+
.setting-label { font-size: 13px; color: var(--text); margin-bottom: 3px; }
|
|
46
|
+
.setting-desc { font-size: 11px; color: var(--muted); line-height: 1.55; }
|
|
47
|
+
|
|
48
|
+
.account-wrap .input {
|
|
49
|
+
width: 100%;
|
|
50
|
+
background: var(--bg0);
|
|
51
|
+
border: 1px solid var(--line);
|
|
52
|
+
border-radius: 6px;
|
|
53
|
+
padding: 7px 11px;
|
|
54
|
+
color: var(--heading);
|
|
55
|
+
font-family: var(--mono);
|
|
56
|
+
font-size: 12px;
|
|
57
|
+
outline: none;
|
|
58
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
59
|
+
}
|
|
60
|
+
.account-wrap .input:focus {
|
|
61
|
+
border-color: var(--accent);
|
|
62
|
+
box-shadow: 0 0 0 3px var(--accent-bg);
|
|
63
|
+
}
|
|
64
|
+
.account-wrap .input[readonly] {
|
|
65
|
+
color: var(--muted);
|
|
66
|
+
cursor: default;
|
|
67
|
+
background: var(--bg1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.save-row {
|
|
71
|
+
display: flex;
|
|
72
|
+
justify-content: flex-end;
|
|
73
|
+
align-items: center;
|
|
74
|
+
padding: 14px 24px;
|
|
75
|
+
border-top: 1px solid var(--line);
|
|
76
|
+
gap: 10px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.banner {
|
|
80
|
+
padding: 10px 20px;
|
|
81
|
+
font-size: 11px;
|
|
82
|
+
display: none;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: 8px;
|
|
85
|
+
border-radius: 8px;
|
|
86
|
+
margin-bottom: 12px;
|
|
87
|
+
}
|
|
88
|
+
.banner-ok { background: var(--jade-bg); color: var(--jade); border: 1px solid rgba(45,139,106,.2); }
|
|
89
|
+
.banner-err { background: var(--red-bg); color: var(--red); border: 1px solid rgba(240,112,128,.18); }
|
|
90
|
+
|
|
91
|
+
.role-badge {
|
|
92
|
+
display: inline-block;
|
|
93
|
+
font-family: var(--mono);
|
|
94
|
+
font-size: 9px;
|
|
95
|
+
letter-spacing: 0.1em;
|
|
96
|
+
text-transform: uppercase;
|
|
97
|
+
padding: 2px 8px;
|
|
98
|
+
border-radius: 4px;
|
|
99
|
+
background: var(--accent-bg);
|
|
100
|
+
color: var(--accent);
|
|
101
|
+
border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@media (max-width: 600px) {
|
|
105
|
+
.setting-row { grid-template-columns: 1fr; gap: 10px; }
|
|
106
|
+
}
|
|
107
|
+
</style>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<div class="app">
|
|
111
|
+
<header class="topbar">
|
|
112
|
+
<a class="logo" href="/dashboard.html"><div class="logo-mark">OR</div>Orbiter</a>
|
|
113
|
+
<div class="topbar-right">
|
|
114
|
+
<button class="search-trigger" id="search-btn" title="Search (⌘K)">
|
|
115
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
|
|
116
|
+
Search <kbd>⌘K</kbd>
|
|
117
|
+
</button>
|
|
118
|
+
<button class="scheme-toggle" id="scheme-toggle" title="Toggle scheme">◐</button>
|
|
119
|
+
<span class="user" id="topbar-user"></span>
|
|
120
|
+
<span class="logout" id="logout-btn">Sign out</span>
|
|
121
|
+
</div>
|
|
122
|
+
</header>
|
|
123
|
+
<nav class="sidebar">
|
|
124
|
+
<div class="nav-section">Content</div>
|
|
125
|
+
<a class="nav-item" href="/dashboard.html"><span class="nav-icon">◈</span>Dashboard</a>
|
|
126
|
+
<a class="nav-item" href="/collections.html"><span class="nav-icon">⊞</span>Collections</a>
|
|
127
|
+
<div class="nav-section">Assets</div>
|
|
128
|
+
<a class="nav-item" href="/media.html"><span class="nav-icon">⊟</span>Media</a>
|
|
129
|
+
<div class="nav-section">System</div>
|
|
130
|
+
<a class="nav-item" href="/schema.html"><span class="nav-icon">◈</span>Schema</a>
|
|
131
|
+
<a class="nav-item" href="/build.html"><span class="nav-icon">▲</span>Build</a>
|
|
132
|
+
<a class="nav-item" href="/settings.html"><span class="nav-icon">◎</span>Settings</a>
|
|
133
|
+
<a class="nav-item admin-only" href="/users.html" style="display:none"><span class="nav-icon">◉</span>Users</a>
|
|
134
|
+
<div class="sidebar-footer">
|
|
135
|
+
<div class="pod-name" id="pod-name">content.pod</div>
|
|
136
|
+
<div class="pod-info" id="pod-info"></div>
|
|
137
|
+
<div class="pod-version" id="pod-version"></div>
|
|
138
|
+
<div class="pod-status"><span class="pod-dot"></span>pod synced</div>
|
|
139
|
+
</div>
|
|
140
|
+
</nav>
|
|
141
|
+
<main class="main">
|
|
142
|
+
<div class="page-header glass-card">
|
|
143
|
+
<h1 class="page-title">Account</h1>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div class="account-wrap">
|
|
147
|
+
|
|
148
|
+
<!-- Profile -->
|
|
149
|
+
<div id="banner-profile" class="banner"></div>
|
|
150
|
+
<div class="settings-group">
|
|
151
|
+
<div class="group-header">Profile</div>
|
|
152
|
+
<div class="setting-row">
|
|
153
|
+
<div>
|
|
154
|
+
<div class="setting-label">Role</div>
|
|
155
|
+
<div class="setting-desc">Your permission level in this pod.</div>
|
|
156
|
+
</div>
|
|
157
|
+
<div><span class="role-badge" id="role-badge">—</span></div>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="setting-row">
|
|
160
|
+
<div>
|
|
161
|
+
<div class="setting-label">Username</div>
|
|
162
|
+
<div class="setting-desc">The name you log in with. Must be unique.</div>
|
|
163
|
+
</div>
|
|
164
|
+
<input class="input" id="new-username" type="text" autocomplete="username" spellcheck="false" />
|
|
165
|
+
</div>
|
|
166
|
+
<div class="setting-row">
|
|
167
|
+
<div>
|
|
168
|
+
<div class="setting-label">Current password</div>
|
|
169
|
+
<div class="setting-desc">Required to confirm the username change.</div>
|
|
170
|
+
</div>
|
|
171
|
+
<input class="input" id="pw-for-username" type="password" autocomplete="current-password" />
|
|
172
|
+
</div>
|
|
173
|
+
<div class="save-row">
|
|
174
|
+
<button class="btn-save" id="save-username-btn">Save username</button>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<!-- Password -->
|
|
179
|
+
<div id="banner-password" class="banner"></div>
|
|
180
|
+
<div class="settings-group">
|
|
181
|
+
<div class="group-header">Change password</div>
|
|
182
|
+
<div class="setting-row">
|
|
183
|
+
<div>
|
|
184
|
+
<div class="setting-label">Current password</div>
|
|
185
|
+
</div>
|
|
186
|
+
<input class="input" id="cur-password" type="password" autocomplete="current-password" />
|
|
187
|
+
</div>
|
|
188
|
+
<div class="setting-row">
|
|
189
|
+
<div>
|
|
190
|
+
<div class="setting-label">New password</div>
|
|
191
|
+
<div class="setting-desc">Minimum 8 characters.</div>
|
|
192
|
+
</div>
|
|
193
|
+
<input class="input" id="new-password" type="password" autocomplete="new-password" />
|
|
194
|
+
</div>
|
|
195
|
+
<div class="setting-row">
|
|
196
|
+
<div>
|
|
197
|
+
<div class="setting-label">Confirm new password</div>
|
|
198
|
+
</div>
|
|
199
|
+
<input class="input" id="confirm-password" type="password" autocomplete="new-password" />
|
|
200
|
+
</div>
|
|
201
|
+
<div class="save-row">
|
|
202
|
+
<button class="btn-save" id="save-password-btn">Change password</button>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
</div><!-- /.account-wrap -->
|
|
207
|
+
</main>
|
|
208
|
+
</div><!-- /.app -->
|
|
209
|
+
|
|
210
|
+
<script type="module">
|
|
211
|
+
const me = await fetch('/api/auth/me', { credentials: 'include' }).then(r => r.json()).catch(() => null);
|
|
212
|
+
if (!me?.user) { location.replace('/login.html'); }
|
|
213
|
+
|
|
214
|
+
const { username, role } = me.user;
|
|
215
|
+
document.getElementById('topbar-user').textContent = username;
|
|
216
|
+
document.getElementById('new-username').value = username;
|
|
217
|
+
document.getElementById('role-badge').textContent = role;
|
|
218
|
+
if (role === 'admin') document.querySelectorAll('.admin-only').forEach(el => el.style.display = '');
|
|
219
|
+
|
|
220
|
+
document.getElementById('logout-btn').addEventListener('click', async () => {
|
|
221
|
+
await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' });
|
|
222
|
+
location.replace('/login.html');
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
function showBanner(id, ok, text) {
|
|
226
|
+
const el = document.getElementById(id);
|
|
227
|
+
el.className = 'banner ' + (ok ? 'banner-ok' : 'banner-err');
|
|
228
|
+
el.textContent = (ok ? '✓ ' : '✕ ') + text;
|
|
229
|
+
el.style.display = 'flex';
|
|
230
|
+
setTimeout(() => el.style.display = 'none', 3500);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
document.getElementById('save-username-btn').addEventListener('click', async () => {
|
|
234
|
+
const newUsername = document.getElementById('new-username').value.trim();
|
|
235
|
+
const currentPassword = document.getElementById('pw-for-username').value;
|
|
236
|
+
if (!newUsername || !currentPassword) {
|
|
237
|
+
showBanner('banner-profile', false, 'Fill in username and current password.');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const res = await fetch('/api/account/username', {
|
|
241
|
+
method: 'PUT', credentials: 'include',
|
|
242
|
+
headers: { 'Content-Type': 'application/json' },
|
|
243
|
+
body: JSON.stringify({ newUsername, currentPassword }),
|
|
244
|
+
}).then(r => r.json()).catch(() => ({ error: 'Network error' }));
|
|
245
|
+
|
|
246
|
+
if (res.ok) {
|
|
247
|
+
document.getElementById('topbar-user').textContent = newUsername;
|
|
248
|
+
document.getElementById('pw-for-username').value = '';
|
|
249
|
+
showBanner('banner-profile', true, 'Username updated.');
|
|
250
|
+
} else {
|
|
251
|
+
showBanner('banner-profile', false, res.error || 'Failed to update username.');
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
document.getElementById('save-password-btn').addEventListener('click', async () => {
|
|
256
|
+
const currentPassword = document.getElementById('cur-password').value;
|
|
257
|
+
const newPassword = document.getElementById('new-password').value;
|
|
258
|
+
const confirm = document.getElementById('confirm-password').value;
|
|
259
|
+
if (!currentPassword || !newPassword) {
|
|
260
|
+
showBanner('banner-password', false, 'Fill in all password fields.');
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (newPassword !== confirm) {
|
|
264
|
+
showBanner('banner-password', false, 'New passwords do not match.');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const res = await fetch('/api/account/password', {
|
|
268
|
+
method: 'PUT', credentials: 'include',
|
|
269
|
+
headers: { 'Content-Type': 'application/json' },
|
|
270
|
+
body: JSON.stringify({ currentPassword, newPassword }),
|
|
271
|
+
}).then(r => r.json()).catch(() => ({ error: 'Network error' }));
|
|
272
|
+
|
|
273
|
+
if (res.ok) {
|
|
274
|
+
document.getElementById('cur-password').value = '';
|
|
275
|
+
document.getElementById('new-password').value = '';
|
|
276
|
+
document.getElementById('confirm-password').value = '';
|
|
277
|
+
showBanner('banner-password', true, 'Password changed.');
|
|
278
|
+
} else {
|
|
279
|
+
showBanner('banner-password', false, res.error || 'Failed to change password.');
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
</script>
|
|
283
|
+
<script src="/sidebar.js"></script>
|
|
284
|
+
<script src="/search.js"></script>
|
|
285
|
+
<script src="/xfce.js" type="module"></script>
|
|
286
|
+
</body>
|
|
287
|
+
</html>
|
package/public/xfce.js
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
'</div>',
|
|
65
65
|
'<div class="xfce-sb-center" id="xfce-sb-title"></div>',
|
|
66
66
|
'<div class="xfce-sb-right">',
|
|
67
|
-
'<span id="xfce-sb-g-ind" class="xfce-sb-g-ind" style="display:none" title="g mode: d=dashboard m=media s=settings u=users b=build i=import
|
|
67
|
+
'<span id="xfce-sb-g-ind" class="xfce-sb-g-ind" style="display:none" title="g mode: d=dashboard m=media s=settings u=users b=build i=import c=schema h=HUD a=account">g ›</span>',
|
|
68
68
|
'<button id="xfce-sb-bell" class="xfce-sb-bell" title="Notifications"><span id="xfce-sb-bell-icon">○</span><span id="xfce-sb-bell-badge" class="xfce-sb-bell-badge" style="display:none"></span></button>',
|
|
69
69
|
'<span class="xfce-sb-div">·</span>',
|
|
70
70
|
'<button id="xfce-sb-cheat" class="xfce-sb-cheat" title="Shortcuts (?)">?</button>',
|
|
@@ -1516,13 +1516,13 @@
|
|
|
1516
1516
|
cheatRow('g + s', 'Settings'),
|
|
1517
1517
|
cheatRow('g + b', 'Build'),
|
|
1518
1518
|
cheatRow('g + i', 'Import'),
|
|
1519
|
-
cheatRow('g +
|
|
1519
|
+
cheatRow('g + c', 'Schema'),
|
|
1520
|
+
cheatRow('g + h', 'Toggle HUD'),
|
|
1520
1521
|
cheatRow('g + a', 'Account'),
|
|
1521
1522
|
cheatRow('1 – 9', 'Jump to nth dock item'),
|
|
1522
1523
|
'</div>',
|
|
1523
1524
|
'<div class="xfce-cheat-col">',
|
|
1524
1525
|
'<div class="xfce-cheat-section">Panels</div>',
|
|
1525
|
-
cheatRow('⌘⇧D', 'Toggle HUD'),
|
|
1526
1526
|
cheatRow('⌘⇧F', 'Focus / Zen mode'),
|
|
1527
1527
|
cheatRow('⌘⇧L', 'Switch to Glass mode'),
|
|
1528
1528
|
cheatRow('?', 'This cheatsheet'),
|
|
@@ -1568,7 +1568,7 @@
|
|
|
1568
1568
|
var _gPending = false, _gTimer = null;
|
|
1569
1569
|
var G_MAP = { d: '/dashboard.html', m: '/media.html', s: '/settings.html',
|
|
1570
1570
|
u: '/users.html', b: '/build.html', i: '/import.html',
|
|
1571
|
-
|
|
1571
|
+
c: '/schema.html', a: '/account.html' };
|
|
1572
1572
|
|
|
1573
1573
|
function setGMode(on) {
|
|
1574
1574
|
_gPending = on;
|
|
@@ -1614,16 +1614,11 @@
|
|
|
1614
1614
|
}
|
|
1615
1615
|
if (_gPending && !isEditing(e.target)) {
|
|
1616
1616
|
clearTimeout(_gTimer); setGMode(false);
|
|
1617
|
-
if (
|
|
1617
|
+
if (e.key === 'h') { e.preventDefault(); toggleHUD(); }
|
|
1618
|
+
else if (G_MAP[e.key]) { e.preventDefault(); location.href = G_MAP[e.key]; }
|
|
1618
1619
|
return;
|
|
1619
1620
|
}
|
|
1620
1621
|
|
|
1621
|
-
// ⌘⇧D — toggle HUD
|
|
1622
|
-
if (mod && e.shiftKey && (e.key === 'd' || e.key === 'D')) {
|
|
1623
|
-
e.preventDefault();
|
|
1624
|
-
toggleHUD();
|
|
1625
|
-
return;
|
|
1626
|
-
}
|
|
1627
1622
|
|
|
1628
1623
|
// ⌘⇧F — zen / focus mode
|
|
1629
1624
|
if (mod && e.shiftKey && (e.key === 'f' || e.key === 'F')) {
|