dsh-ui-tweaks 0.10.2 → 0.10.3
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/LICENSE +21 -21
- package/cordis.patch.yml +12 -12
- package/lib/client.js +176 -121
- package/lib/client.js.map +1 -1
- package/lib/git-web.js +6 -1
- package/lib/git-web.js.map +1 -1
- package/lib/types/client/gitbar.d.ts.map +1 -1
- package/lib/types/git-web.d.ts.map +1 -1
- package/package.json +2 -2
- package/vendor/addon-fit.js +1 -1
- package/vendor/xterm.css +218 -218
- package/vendor/xterm.js +1 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 dsh-ui-tweaks contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-ui-tweaks contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/cordis.patch.yml
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# dsh-ui-tweaks bundle patch
|
|
2
|
-
#
|
|
3
|
-
# Declared by `dsh.bundle.patch` in package.json: when the plugin is installed
|
|
4
|
-
# through the official CLI —
|
|
5
|
-
#
|
|
6
|
-
# dsh plugin --profile <name> add dsh-ui-tweaks
|
|
7
|
-
#
|
|
8
|
-
# — the command appends `dsh-ui-tweaks` to the profile's bundle stack and this
|
|
9
|
-
# patch mounts the server-side plugin row.
|
|
10
|
-
- insert:
|
|
11
|
-
- id: ui-tweaks
|
|
12
|
-
name: 'dsh-ui-tweaks'
|
|
1
|
+
# dsh-ui-tweaks bundle patch
|
|
2
|
+
#
|
|
3
|
+
# Declared by `dsh.bundle.patch` in package.json: when the plugin is installed
|
|
4
|
+
# through the official CLI —
|
|
5
|
+
#
|
|
6
|
+
# dsh plugin --profile <name> add dsh-ui-tweaks
|
|
7
|
+
#
|
|
8
|
+
# — the command appends `dsh-ui-tweaks` to the profile's bundle stack and this
|
|
9
|
+
# patch mounts the server-side plugin row.
|
|
10
|
+
- insert:
|
|
11
|
+
- id: ui-tweaks
|
|
12
|
+
name: 'dsh-ui-tweaks'
|
package/lib/client.js
CHANGED
|
@@ -107,27 +107,27 @@ function relativeTime(ms, now, formatter) {
|
|
|
107
107
|
return formatter.format(Math.round(diffSeconds / 86400), 'day');
|
|
108
108
|
return formatter.format(Math.round(diffSeconds / 604800), 'week');
|
|
109
109
|
}
|
|
110
|
-
exports.ARCHIVE_CSS = `
|
|
111
|
-
.dut-arc{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
|
|
112
|
-
.dut-arc-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
|
|
113
|
-
.dut-arc-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
|
|
114
|
-
.dut-arc-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
|
|
115
|
-
.dut-arc-spacer{flex:1}
|
|
116
|
-
.dut-arc-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
|
|
117
|
-
.dut-arc-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
118
|
-
.dut-arc-btn:disabled{opacity:.5;cursor:default}
|
|
119
|
-
.dut-arc-btn.dut-arc-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
|
|
120
|
-
.dut-arc-btn.dut-arc-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
|
|
121
|
-
.dut-arc-body{display:grid;gap:2px;margin-top:4px}
|
|
122
|
-
.dut-arc-row{display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:12px}
|
|
123
|
-
.dut-arc-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
124
|
-
.dut-arc-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;text-align:left;background:transparent;border:none;padding:0;cursor:default;color:var(--dsw-alias-label-primary);font:inherit}
|
|
125
|
-
.dut-arc-title{font-size:13.5px;font-weight:600;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
126
|
-
.dut-arc-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
127
|
-
.dut-arc-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
|
|
128
|
-
.dut-arc-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
129
|
-
.dut-arc-off{padding:20px 16px;display:grid;gap:12px}
|
|
130
|
-
.dut-arc-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
|
|
110
|
+
exports.ARCHIVE_CSS = `
|
|
111
|
+
.dut-arc{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
|
|
112
|
+
.dut-arc-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
|
|
113
|
+
.dut-arc-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
|
|
114
|
+
.dut-arc-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
|
|
115
|
+
.dut-arc-spacer{flex:1}
|
|
116
|
+
.dut-arc-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
|
|
117
|
+
.dut-arc-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
118
|
+
.dut-arc-btn:disabled{opacity:.5;cursor:default}
|
|
119
|
+
.dut-arc-btn.dut-arc-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
|
|
120
|
+
.dut-arc-btn.dut-arc-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
|
|
121
|
+
.dut-arc-body{display:grid;gap:2px;margin-top:4px}
|
|
122
|
+
.dut-arc-row{display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:12px}
|
|
123
|
+
.dut-arc-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
124
|
+
.dut-arc-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;text-align:left;background:transparent;border:none;padding:0;cursor:default;color:var(--dsw-alias-label-primary);font:inherit}
|
|
125
|
+
.dut-arc-title{font-size:13.5px;font-weight:600;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
126
|
+
.dut-arc-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
127
|
+
.dut-arc-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
|
|
128
|
+
.dut-arc-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
129
|
+
.dut-arc-off{padding:20px 16px;display:grid;gap:12px}
|
|
130
|
+
.dut-arc-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
|
|
131
131
|
`;
|
|
132
132
|
/** Install the Archive stylesheet once (idempotent); returns the disposer. */
|
|
133
133
|
function installArchiveStyles() {
|
|
@@ -909,7 +909,12 @@ function warmGitStatus(target) {
|
|
|
909
909
|
if (key === '' || snapshotCache.has(key) || warmInflight.has(key))
|
|
910
910
|
return;
|
|
911
911
|
const flight = apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`)
|
|
912
|
-
.then(next => {
|
|
912
|
+
.then(next => {
|
|
913
|
+
// An unresolved answer (host still starting up) must not poison the
|
|
914
|
+
// cache as a final "not a repo"; the mounting chip re-fetches anyway.
|
|
915
|
+
if (!next.unresolved)
|
|
916
|
+
snapshotCache.set(key, next);
|
|
917
|
+
})
|
|
913
918
|
.catch(() => {
|
|
914
919
|
// Warmup is best-effort; the mounting chip re-fetches anyway.
|
|
915
920
|
})
|
|
@@ -924,6 +929,12 @@ function GitWarmup({ sessionId }) {
|
|
|
924
929
|
}, [sessionId]);
|
|
925
930
|
return null;
|
|
926
931
|
}
|
|
932
|
+
/** Fast retry steps (ms) for the startup race: right after a restart the host
|
|
933
|
+
* has not materialized its session/workspace store yet, so the first /status
|
|
934
|
+
* answers `unresolved`. Without these the UI sat blank for a full POLL_MS. */
|
|
935
|
+
const RETRY_DELAYS_MS = [400, 800, 1600, 3200];
|
|
936
|
+
/** Upper bound on fast retries before falling back to the steady poll. */
|
|
937
|
+
const FAST_RETRY_MAX = 6;
|
|
927
938
|
/** Load the git snapshot on session change, then poll; returns [snapshot, refresh]. */
|
|
928
939
|
function useGitStatus(enabled, target) {
|
|
929
940
|
const key = target.session ?? target.ws ?? '';
|
|
@@ -937,27 +948,63 @@ function useGitStatus(enabled, target) {
|
|
|
937
948
|
// A remount (panel open) must not regress to blank when the cache is warm.
|
|
938
949
|
setSnapshot(snapshotCache.get(key) ?? null);
|
|
939
950
|
let cancelled = false;
|
|
940
|
-
let
|
|
941
|
-
|
|
951
|
+
let pollTimer;
|
|
952
|
+
let retryTimer;
|
|
953
|
+
let attempt = 0;
|
|
954
|
+
// Whether a resolved snapshot exists for this target (cache or fetched).
|
|
955
|
+
// Drives the cold-start chase: fast backoff only while it is false.
|
|
956
|
+
let haveGood = snapshotCache.has(key);
|
|
957
|
+
/** Store one fetch result. An `unresolved` answer is transient — never
|
|
958
|
+
* cached, never regressing an already-good snapshot. Returns whether a
|
|
959
|
+
* resolved answer landed. */
|
|
960
|
+
const apply = (next) => {
|
|
961
|
+
if (next.unresolved === true) {
|
|
962
|
+
if (!cancelled && !haveGood)
|
|
963
|
+
setSnapshot(null);
|
|
964
|
+
return false;
|
|
965
|
+
}
|
|
966
|
+
haveGood = true;
|
|
967
|
+
attempt = 0;
|
|
968
|
+
snapshotCache.set(key, next);
|
|
969
|
+
if (!cancelled)
|
|
970
|
+
setSnapshot(next);
|
|
971
|
+
return true;
|
|
972
|
+
};
|
|
973
|
+
const refreshOnce = async () => {
|
|
942
974
|
try {
|
|
943
|
-
|
|
944
|
-
snapshotCache.set(key, next);
|
|
945
|
-
if (!cancelled)
|
|
946
|
-
setSnapshot(next);
|
|
975
|
+
return apply(await apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`));
|
|
947
976
|
}
|
|
948
977
|
catch {
|
|
949
|
-
//
|
|
978
|
+
// Transport/transient git failure: chase it too while no good snapshot
|
|
979
|
+
// exists; afterwards keep showing the old one until the next poll.
|
|
980
|
+
return haveGood;
|
|
950
981
|
}
|
|
951
982
|
};
|
|
952
|
-
|
|
953
|
-
|
|
983
|
+
/** Cold-start chase: short backoff instead of idling a whole poll period. */
|
|
984
|
+
const scheduleRetry = () => {
|
|
985
|
+
if (cancelled || haveGood || attempt >= FAST_RETRY_MAX)
|
|
986
|
+
return;
|
|
987
|
+
const delay = RETRY_DELAYS_MS[Math.min(attempt, RETRY_DELAYS_MS.length - 1)] ?? 3200;
|
|
988
|
+
attempt += 1;
|
|
989
|
+
retryTimer = window.setTimeout(() => {
|
|
990
|
+
if (cancelled)
|
|
991
|
+
return;
|
|
992
|
+
void refreshOnce().then(settled => { if (!settled)
|
|
993
|
+
scheduleRetry(); });
|
|
994
|
+
}, delay);
|
|
995
|
+
};
|
|
996
|
+
void refreshOnce().then(settled => { if (!settled)
|
|
997
|
+
scheduleRetry(); });
|
|
998
|
+
pollTimer = window.setInterval(() => {
|
|
954
999
|
if (document.visibilityState === 'visible')
|
|
955
|
-
void
|
|
1000
|
+
void refreshOnce();
|
|
956
1001
|
}, POLL_MS);
|
|
957
1002
|
return () => {
|
|
958
1003
|
cancelled = true;
|
|
959
|
-
if (
|
|
960
|
-
clearInterval(
|
|
1004
|
+
if (pollTimer !== undefined)
|
|
1005
|
+
clearInterval(pollTimer);
|
|
1006
|
+
if (retryTimer !== undefined)
|
|
1007
|
+
clearTimeout(retryTimer);
|
|
961
1008
|
};
|
|
962
1009
|
}, [enabled, key]);
|
|
963
1010
|
const refresh = (0, react_1.useCallback)(async () => {
|
|
@@ -965,8 +1012,12 @@ function useGitStatus(enabled, target) {
|
|
|
965
1012
|
return;
|
|
966
1013
|
try {
|
|
967
1014
|
const next = await apiGet(`${GIT_ROUTE}/status?${targetQuery(target)}`);
|
|
968
|
-
|
|
969
|
-
|
|
1015
|
+
// Same rule as the hook body: an unresolved answer is transient and must
|
|
1016
|
+
// not evict a good snapshot or enter the cache.
|
|
1017
|
+
if (!next.unresolved) {
|
|
1018
|
+
snapshotCache.set(key, next);
|
|
1019
|
+
setSnapshot(next);
|
|
1020
|
+
}
|
|
970
1021
|
}
|
|
971
1022
|
catch {
|
|
972
1023
|
// Keep the previous snapshot on transient failures.
|
|
@@ -1156,13 +1207,17 @@ function BranchChipEntry({ sessionId, sessionsService, controller, t }) {
|
|
|
1156
1207
|
}, [branchOpen]);
|
|
1157
1208
|
if (!enabled || sessionStr === undefined)
|
|
1158
1209
|
return null;
|
|
1159
|
-
|
|
1210
|
+
// A genuine non-repo directory hides the chip entirely. An UNRESOLVED target
|
|
1211
|
+
// (host still materializing sessions right after a restart) is transient:
|
|
1212
|
+
// fall through to the folder-only paint below instead of going blank.
|
|
1213
|
+
if (snapshot !== null && snapshot.unresolved !== true && !snapshot.isRepo)
|
|
1160
1214
|
return null;
|
|
1161
|
-
// While the first /status round-trip is in flight
|
|
1162
|
-
//
|
|
1163
|
-
//
|
|
1164
|
-
// moment the
|
|
1165
|
-
|
|
1215
|
+
// While the first /status round-trip is in flight — or while the host has
|
|
1216
|
+
// not resolved this session yet — paint the folder alone straight off the
|
|
1217
|
+
// sessions-list feed (the sidebar's own rows — zero network, so it appears
|
|
1218
|
+
// the moment the sidebar row does); the branch capsule joins as soon as the
|
|
1219
|
+
// backoff chase lands a real snapshot.
|
|
1220
|
+
if (snapshot === null || snapshot.unresolved === true) {
|
|
1166
1221
|
if (feedCwd === undefined || feedCwd === '')
|
|
1167
1222
|
return null;
|
|
1168
1223
|
return ((0, jsx_runtime_1.jsx)("span", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: (0, jsx_runtime_1.jsxs)("span", { className: "gbar-fchip", title: feedCwd, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M1.5 4A1.5 1.5 0 0 1 3 2.5h3l1.5 2H13A1.5 1.5 0 0 1 14.5 6v6A1.5 1.5 0 0 1 13 13.5H3A1.5 1.5 0 0 1 1.5 12V4Z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-folder", children: basenameOf(feedCwd) })] }) }));
|
|
@@ -3296,63 +3351,63 @@ function linesToRecord(text, separator) {
|
|
|
3296
3351
|
function recordToLines(record, separator) {
|
|
3297
3352
|
return Object.entries(record).map(([key, value]) => `${key}${separator}${value}`).join('\n');
|
|
3298
3353
|
}
|
|
3299
|
-
exports.MCP_CSS = `
|
|
3300
|
-
.dut-mcp{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
|
|
3301
|
-
.dut-mcp-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
|
|
3302
|
-
.dut-mcp-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
|
|
3303
|
-
.dut-mcp-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
|
|
3304
|
-
.dut-mcp-spacer{flex:1}
|
|
3305
|
-
.dut-mcp-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
|
|
3306
|
-
.dut-mcp-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
3307
|
-
.dut-mcp-btn:disabled{opacity:.5;cursor:default}
|
|
3308
|
-
.dut-mcp-btn.dut-mcp-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
|
|
3309
|
-
.dut-mcp-btn.dut-mcp-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
|
|
3310
|
-
.dut-mcp-body{display:grid;gap:2px;margin-top:4px}
|
|
3311
|
-
.dut-mcp-row{display:grid;gap:6px;padding:10px 16px;border-radius:12px}
|
|
3312
|
-
.dut-mcp-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
3313
|
-
.dut-mcp-row-main{display:flex;align-items:center;gap:8px;min-width:0}
|
|
3314
|
-
.dut-mcp-name{font-size:13.5px;font-weight:600;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
3315
|
-
.dut-mcp-badge{flex:none;font-size:11px;line-height:1;padding:4px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
|
|
3316
|
-
.dut-mcp-badge.dut-mcp-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-success-primary)}
|
|
3317
|
-
.dut-mcp-badge.dut-mcp-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-error-primary)}
|
|
3318
|
-
.dut-mcp-badge.dut-mcp-warn{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 14%,transparent);border-color:transparent;color:var(--dsw-alias-state-warn-label)}
|
|
3319
|
-
.dut-mcp-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
3320
|
-
.dut-mcp-toggle{flex:none;font-size:11.5px;color:var(--dsw-alias-label-tertiary);background:transparent;border:none;padding:0;cursor:pointer;text-align:left}
|
|
3321
|
-
.dut-mcp-toggle:hover{color:var(--dsw-alias-label-primary)}
|
|
3322
|
-
.dut-mcp-tools{margin-left:2px;display:flex;flex-wrap:wrap;gap:4px}
|
|
3323
|
-
.dut-mcp-tool{font-size:11px;line-height:1;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
|
|
3324
|
-
.dut-mcp-note{margin:2px 16px 0;padding:8px 12px;border-radius:10px;font-size:11.5px;line-height:1.55;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
|
|
3325
|
-
.dut-mcp-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
|
|
3326
|
-
.dut-mcp-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
3327
|
-
.dut-mcp-notice{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}
|
|
3328
|
-
.dut-mcp-off{padding:20px 16px;display:grid;gap:12px}
|
|
3329
|
-
.dut-mcp-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
|
|
3330
|
-
.dut-mcp-overlay{z-index:1100;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}
|
|
3331
|
-
.dut-mcp-mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}
|
|
3332
|
-
.dut-mcp-panel{z-index:1;background:var(--dsw-alias-bg-layer-2);box-sizing:border-box;width:720px;max-width:calc(100vw - 48px);height:min(700px,100vh - 48px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;display:flex;flex-direction:column;overflow:hidden}
|
|
3333
|
-
.dut-mcp-panel-head{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:10px;height:52px;padding:0 12px 0 20px}
|
|
3334
|
-
.dut-mcp-panel-head h2{margin:0;font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
|
|
3335
|
-
.dut-mcp-panel-close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-primary);background:transparent;border:none;border-radius:28px;display:inline-flex;justify-content:center;align-items:center;padding:0;font-size:13px}
|
|
3336
|
-
.dut-mcp-panel-close:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
3337
|
-
.dut-mcp-tabs{flex:none;display:inline-flex;padding:3px;gap:3px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2);margin:0 20px 10px;align-self:flex-start}
|
|
3338
|
-
.dut-mcp-tabs button{border:none;border-radius:7px;padding:5px 14px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer}
|
|
3339
|
-
.dut-mcp-tabs button.dut-mcp-tab-on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}
|
|
3340
|
-
.dut-mcp-form{flex:1;min-height:0;overflow-y:auto;padding:0 20px 20px;display:grid;gap:12px;align-content:start}
|
|
3341
|
-
.dut-mcp-field{display:grid;gap:6px}
|
|
3342
|
-
.dut-mcp-field>span{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary)}
|
|
3343
|
-
.dut-mcp-field small{font-size:11px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}
|
|
3344
|
-
.dut-mcp-input{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border-radius:9px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
|
|
3345
|
-
.dut-mcp-input:focus{outline:none;border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 55%,transparent)}
|
|
3346
|
-
.dut-mcp-input:disabled{opacity:.55;cursor:not-allowed}
|
|
3347
|
-
textarea.dut-mcp-input{height:auto;min-height:72px;padding:8px 10px;line-height:1.5;resize:vertical;font-family:var(--dsw-font-markdown-code-block-font-family, Consolas, monospace);font-size:12px}
|
|
3348
|
-
textarea.dut-mcp-input-lg{min-height:120px}
|
|
3349
|
-
textarea.dut-mcp-yaml{min-height:320px}
|
|
3350
|
-
.dut-mcp-row2{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
|
|
3351
|
-
.dut-mcp-field .dut-seg{width:fit-content}
|
|
3352
|
-
.dut-mcp-row2 .dut-seg{height:34px;box-sizing:border-box;align-items:center}
|
|
3353
|
-
.dut-mcp-row2 .dut-seg button{flex:none;white-space:nowrap;padding:0 16px;height:26px}
|
|
3354
|
-
.dut-mcp-foot{flex:none;display:flex;align-items:center;gap:8px;justify-content:flex-end;padding:12px 20px 16px;border-top:1px solid var(--dsw-alias-border-l1)}
|
|
3355
|
-
.dut-mcp-error{margin:0 20px 10px;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
3354
|
+
exports.MCP_CSS = `
|
|
3355
|
+
.dut-mcp{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px}
|
|
3356
|
+
.dut-mcp-head{display:flex;align-items:center;gap:10px;padding:14px 16px 0}
|
|
3357
|
+
.dut-mcp-head h2{margin:0;font-size:15px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
|
|
3358
|
+
.dut-mcp-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);padding:2px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
|
|
3359
|
+
.dut-mcp-spacer{flex:1}
|
|
3360
|
+
.dut-mcp-btn{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
|
|
3361
|
+
.dut-mcp-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
3362
|
+
.dut-mcp-btn:disabled{opacity:.5;cursor:default}
|
|
3363
|
+
.dut-mcp-btn.dut-mcp-del:hover{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
|
|
3364
|
+
.dut-mcp-btn.dut-mcp-confirm{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 55%,transparent);color:var(--dsw-alias-state-error-primary);font-weight:600}
|
|
3365
|
+
.dut-mcp-body{display:grid;gap:2px;margin-top:4px}
|
|
3366
|
+
.dut-mcp-row{display:grid;gap:6px;padding:10px 16px;border-radius:12px}
|
|
3367
|
+
.dut-mcp-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
3368
|
+
.dut-mcp-row-main{display:flex;align-items:center;gap:8px;min-width:0}
|
|
3369
|
+
.dut-mcp-name{font-size:13.5px;font-weight:600;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
3370
|
+
.dut-mcp-badge{flex:none;font-size:11px;line-height:1;padding:4px 9px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
|
|
3371
|
+
.dut-mcp-badge.dut-mcp-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-success-primary)}
|
|
3372
|
+
.dut-mcp-badge.dut-mcp-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);border-color:transparent;color:var(--dsw-alias-state-error-primary)}
|
|
3373
|
+
.dut-mcp-badge.dut-mcp-warn{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 14%,transparent);border-color:transparent;color:var(--dsw-alias-state-warn-label)}
|
|
3374
|
+
.dut-mcp-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
|
|
3375
|
+
.dut-mcp-toggle{flex:none;font-size:11.5px;color:var(--dsw-alias-label-tertiary);background:transparent;border:none;padding:0;cursor:pointer;text-align:left}
|
|
3376
|
+
.dut-mcp-toggle:hover{color:var(--dsw-alias-label-primary)}
|
|
3377
|
+
.dut-mcp-tools{margin-left:2px;display:flex;flex-wrap:wrap;gap:4px}
|
|
3378
|
+
.dut-mcp-tool{font-size:11px;line-height:1;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary)}
|
|
3379
|
+
.dut-mcp-note{margin:2px 16px 0;padding:8px 12px;border-radius:10px;font-size:11.5px;line-height:1.55;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1)}
|
|
3380
|
+
.dut-mcp-empty{padding:32px 16px;text-align:center;font-size:12.5px;color:var(--dsw-alias-label-secondary)}
|
|
3381
|
+
.dut-mcp-alert{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
3382
|
+
.dut-mcp-notice{margin:8px 16px 0;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}
|
|
3383
|
+
.dut-mcp-off{padding:20px 16px;display:grid;gap:12px}
|
|
3384
|
+
.dut-mcp-off p{margin:0;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-label-secondary)}
|
|
3385
|
+
.dut-mcp-overlay{z-index:1100;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}
|
|
3386
|
+
.dut-mcp-mask{background:var(--dsw-alias-bg-mask-1);backdrop-filter:var(--dsw-mask-blur);position:absolute;inset:0}
|
|
3387
|
+
.dut-mcp-panel{z-index:1;background:var(--dsw-alias-bg-layer-2);box-sizing:border-box;width:720px;max-width:calc(100vw - 48px);height:min(700px,100vh - 48px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:20px;display:flex;flex-direction:column;overflow:hidden}
|
|
3388
|
+
.dut-mcp-panel-head{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:10px;height:52px;padding:0 12px 0 20px}
|
|
3389
|
+
.dut-mcp-panel-head h2{margin:0;font-size:16px;font-weight:600;letter-spacing:-.01em;color:var(--dsw-alias-label-primary)}
|
|
3390
|
+
.dut-mcp-panel-close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-primary);background:transparent;border:none;border-radius:28px;display:inline-flex;justify-content:center;align-items:center;padding:0;font-size:13px}
|
|
3391
|
+
.dut-mcp-panel-close:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
3392
|
+
.dut-mcp-tabs{flex:none;display:inline-flex;padding:3px;gap:3px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2);margin:0 20px 10px;align-self:flex-start}
|
|
3393
|
+
.dut-mcp-tabs button{border:none;border-radius:7px;padding:5px 14px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer}
|
|
3394
|
+
.dut-mcp-tabs button.dut-mcp-tab-on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}
|
|
3395
|
+
.dut-mcp-form{flex:1;min-height:0;overflow-y:auto;padding:0 20px 20px;display:grid;gap:12px;align-content:start}
|
|
3396
|
+
.dut-mcp-field{display:grid;gap:6px}
|
|
3397
|
+
.dut-mcp-field>span{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary)}
|
|
3398
|
+
.dut-mcp-field small{font-size:11px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}
|
|
3399
|
+
.dut-mcp-input{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border-radius:9px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}
|
|
3400
|
+
.dut-mcp-input:focus{outline:none;border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 55%,transparent)}
|
|
3401
|
+
.dut-mcp-input:disabled{opacity:.55;cursor:not-allowed}
|
|
3402
|
+
textarea.dut-mcp-input{height:auto;min-height:72px;padding:8px 10px;line-height:1.5;resize:vertical;font-family:var(--dsw-font-markdown-code-block-font-family, Consolas, monospace);font-size:12px}
|
|
3403
|
+
textarea.dut-mcp-input-lg{min-height:120px}
|
|
3404
|
+
textarea.dut-mcp-yaml{min-height:320px}
|
|
3405
|
+
.dut-mcp-row2{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start}
|
|
3406
|
+
.dut-mcp-field .dut-seg{width:fit-content}
|
|
3407
|
+
.dut-mcp-row2 .dut-seg{height:34px;box-sizing:border-box;align-items:center}
|
|
3408
|
+
.dut-mcp-row2 .dut-seg button{flex:none;white-space:nowrap;padding:0 16px;height:26px}
|
|
3409
|
+
.dut-mcp-foot{flex:none;display:flex;align-items:center;gap:8px;justify-content:flex-end;padding:12px 20px 16px;border-top:1px solid var(--dsw-alias-border-l1)}
|
|
3410
|
+
.dut-mcp-error{margin:0 20px 10px;padding:8px 12px;border-radius:10px;font-size:12px;line-height:1.5;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
3356
3411
|
`;
|
|
3357
3412
|
/** Install the MCP stylesheet once (idempotent); returns the disposer. */
|
|
3358
3413
|
function installMcpStyles() {
|
|
@@ -4442,28 +4497,28 @@ const WHALE_VIEW_H = 17.04;
|
|
|
4442
4497
|
// ---------------------------------------------------------------------------
|
|
4443
4498
|
// Styles — resident (translucent, still) vs working (opaque, swimming).
|
|
4444
4499
|
// ---------------------------------------------------------------------------
|
|
4445
|
-
exports.WHALE_CSS = `
|
|
4446
|
-
.duwi-row{box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance, 0px));margin:0 auto;padding:0 calc(var(--dsh-composer-side-clearance, 0px) + 14px) 0 var(--dsh-composer-side-clearance, 0px);display:flex;align-items:flex-end;justify-content:flex-end;height:27px;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
|
4447
|
-
.duwi-stack{display:flex;flex-direction:column;align-items:center;transform:translateY(6px)}
|
|
4448
|
-
.duwi-whale{display:block;color:var(--dsw-alias-label-primary);transform-origin:50% 60%;pointer-events:auto;cursor:pointer}
|
|
4449
|
-
.duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:duwi-swim 1.9s ease-in-out infinite}
|
|
4450
|
-
.duwi-waves{display:block;width:26px;height:9px;margin-top:-3px;overflow:hidden}
|
|
4451
|
-
.duwi-wave-back{stroke:#3d8bfd;opacity:.35}
|
|
4452
|
-
.duwi-wave-front{stroke:#3d8bfd;opacity:.8}
|
|
4453
|
-
.duwi-wave-front,.duwi-wave-back{animation:duwi-drift-front 1.9s linear infinite}
|
|
4454
|
-
.duwi-wave-back{animation-duration:3.4s;animation-direction:reverse}
|
|
4455
|
-
@keyframes duwi-swim{
|
|
4456
|
-
0%,100%{transform:translateY(0) rotate(-4deg)}
|
|
4457
|
-
50%{transform:translateY(-3.5px) rotate(4deg)}
|
|
4458
|
-
}
|
|
4459
|
-
@keyframes duwi-drift-front{
|
|
4460
|
-
from{transform:translateX(0)}
|
|
4461
|
-
to{transform:translateX(-8px)}
|
|
4462
|
-
}
|
|
4463
|
-
@media (prefers-reduced-motion:reduce){
|
|
4464
|
-
.duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:none}
|
|
4465
|
-
.duwi-wave-front,.duwi-wave-back{animation:none}
|
|
4466
|
-
}
|
|
4500
|
+
exports.WHALE_CSS = `
|
|
4501
|
+
.duwi-row{box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance, 0px));margin:0 auto;padding:0 calc(var(--dsh-composer-side-clearance, 0px) + 14px) 0 var(--dsh-composer-side-clearance, 0px);display:flex;align-items:flex-end;justify-content:flex-end;height:27px;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
|
4502
|
+
.duwi-stack{display:flex;flex-direction:column;align-items:center;transform:translateY(6px)}
|
|
4503
|
+
.duwi-whale{display:block;color:var(--dsw-alias-label-primary);transform-origin:50% 60%;pointer-events:auto;cursor:pointer}
|
|
4504
|
+
.duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:duwi-swim 1.9s ease-in-out infinite}
|
|
4505
|
+
.duwi-waves{display:block;width:26px;height:9px;margin-top:-3px;overflow:hidden}
|
|
4506
|
+
.duwi-wave-back{stroke:#3d8bfd;opacity:.35}
|
|
4507
|
+
.duwi-wave-front{stroke:#3d8bfd;opacity:.8}
|
|
4508
|
+
.duwi-wave-front,.duwi-wave-back{animation:duwi-drift-front 1.9s linear infinite}
|
|
4509
|
+
.duwi-wave-back{animation-duration:3.4s;animation-direction:reverse}
|
|
4510
|
+
@keyframes duwi-swim{
|
|
4511
|
+
0%,100%{transform:translateY(0) rotate(-4deg)}
|
|
4512
|
+
50%{transform:translateY(-3.5px) rotate(4deg)}
|
|
4513
|
+
}
|
|
4514
|
+
@keyframes duwi-drift-front{
|
|
4515
|
+
from{transform:translateX(0)}
|
|
4516
|
+
to{transform:translateX(-8px)}
|
|
4517
|
+
}
|
|
4518
|
+
@media (prefers-reduced-motion:reduce){
|
|
4519
|
+
.duwi-row.duwi-swim .duwi-whale,.duwi-whale:hover{animation:none}
|
|
4520
|
+
.duwi-wave-front,.duwi-wave-back{animation:none}
|
|
4521
|
+
}
|
|
4467
4522
|
`;
|
|
4468
4523
|
/** Idempotent installer for the indicator styles (same pattern as the other features). */
|
|
4469
4524
|
function installWhaleStyles() {
|