@linxin666/dsh-pet 0.3.23 → 0.3.25
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.i18n.yaml +2 -2
- package/README.md +5 -4
- package/README.zh.md +5 -4
- package/icon.svg +3 -0
- package/lib/client.js +522 -194
- package/lib/client.js.map +1 -1
- package/lib/index.js +710 -426
- package/lib/live2d-vendor.js +96 -96
- package/lib/live2d-vendor.js.map +1 -1
- package/lib/types/announce.d.ts +6 -6
- package/lib/types/announce.d.ts.map +1 -1
- package/lib/types/announce.js +5 -5
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +1 -1
- package/lib/types/client/PetSettingsCard.d.ts +20 -9
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +116 -5
- package/lib/types/client/PetSprite.d.ts +6 -0
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +95 -0
- package/lib/types/client/PluginSettingsCard.d.ts +4 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +3 -2
- package/lib/types/client/gameplay-hud.d.ts +10 -1
- package/lib/types/client/gameplay-hud.d.ts.map +1 -1
- package/lib/types/client/gameplay-hud.js +137 -23
- package/lib/types/client/index.d.ts +8 -5
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +61 -27
- package/lib/types/client/main-session.d.ts +33 -0
- package/lib/types/client/main-session.d.ts.map +1 -0
- package/lib/types/client/main-session.js +34 -0
- package/lib/types/client/settings-form.d.ts +17 -17
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +30 -27
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +5 -3
- package/lib/types/gameplay.d.ts +79 -5
- package/lib/types/gameplay.d.ts.map +1 -1
- package/lib/types/gameplay.js +212 -17
- package/lib/types/http.d.ts +18 -1
- package/lib/types/http.d.ts.map +1 -1
- package/lib/types/http.js +22 -1
- package/lib/types/index.d.ts +100 -29
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +113 -64
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +3 -1
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +3 -1
- package/lib/types/service.d.ts +8 -3
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +26 -4
- package/package.json +46 -26
- package/src/announce.ts +6 -6
- package/src/client/PetDockEntry.tsx +1 -0
- package/src/client/PetSettingsCard.test.tsx +103 -0
- package/src/client/PetSettingsCard.tsx +129 -26
- package/src/client/PetSprite.tsx +96 -0
- package/src/client/PluginSettingsCard.tsx +7 -2
- package/src/client/gameplay-hud.test.tsx +106 -8
- package/src/client/gameplay-hud.tsx +143 -28
- package/src/client/index.test.tsx +37 -4
- package/src/client/index.ts +74 -34
- package/src/client/main-session.ts +43 -0
- package/src/client/settings-form.ts +34 -31
- package/src/event-projection.ts +5 -3
- package/src/gameplay.test.ts +138 -1
- package/src/gameplay.ts +253 -16
- package/src/http.ts +23 -1
- package/src/index.test.ts +107 -11
- package/src/index.ts +162 -73
- package/src/persist.ts +3 -1
- package/src/registry.test.ts +3 -2
- package/src/routes.ts +3 -1
- package/src/service.ts +27 -5
package/lib/client.js
CHANGED
|
@@ -124,7 +124,7 @@ window.__ModuleLoader__.load({
|
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
//#endregion
|
|
127
|
-
//#region
|
|
127
|
+
//#region node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
128
128
|
function r(e) {
|
|
129
129
|
var t, f, n = "";
|
|
130
130
|
if ("string" == typeof e || "number" == typeof e) n += e;
|
|
@@ -154,7 +154,7 @@ window.__ModuleLoader__.load({
|
|
|
154
154
|
const size = Number.isFinite(display.size) ? display.size : 160;
|
|
155
155
|
const multiplier = typeof display.bubbleScale === "number" && Number.isFinite(display.bubbleScale) ? display.bubbleScale : 1;
|
|
156
156
|
const scaled = size / 160 * multiplier;
|
|
157
|
-
return Math.round(Math.min(
|
|
157
|
+
return Math.round(Math.min(2, Math.max(10 / 12, scaled)) * 100) / 100;
|
|
158
158
|
}
|
|
159
159
|
//#endregion
|
|
160
160
|
//#region src/announce.ts
|
|
@@ -267,9 +267,9 @@ window.__ModuleLoader__.load({
|
|
|
267
267
|
} };
|
|
268
268
|
}
|
|
269
269
|
//#endregion
|
|
270
|
-
//#region \0dsh-css:
|
|
271
|
-
const css$2 = ".kz2Bea_float{pointer-events:auto;-webkit-user-select:none;user-select:none;will-change:transform;contain:layout style;flex-direction:column;align-items:center;display:flex;position:fixed}.kz2Bea_sprite{image-rendering:auto;touch-action:none;contain:paint}.kz2Bea_spriteWrap{flex:none;position:relative}.kz2Bea_bubble{white-space:nowrap;padding:calc(4px * var(--pet-bubble-scale,1)) calc(10px * var(--pet-bubble-scale,1));font-size:calc(12px * var(--pet-bubble-scale,1));color:#f4f7ff;pointer-events:none;border-radius:999px;margin-bottom:6px;line-height:1.4;animation:2.6s ease-out forwards kz2Bea_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.kz2Bea_bubblePet{background:#4d6bfef2}.kz2Bea_bubbleFeed{background:#0369a1f2}.kz2Bea_bubbleStatus{max-width:min(calc(280px * var(--pet-bubble-scale,1)), calc(100vw - 24px));text-overflow:ellipsis;padding:calc(5px * var(--pet-bubble-scale,1)) calc(12px * var(--pet-bubble-scale,1));backdrop-filter:blur(8px);letter-spacing:.02em;background:linear-gradient(160deg,#131c36e6,#070b1af0);border:1px solid #7e98ff73;animation:.24s ease-out kz2Bea_pet-bubble-in;overflow:hidden;box-shadow:0 4px 12px #02061759,inset 0 1px #e2e8ff1a,0 0 12px #4d6bfe2e}.kz2Bea_bubbleWhisper{letter-spacing:.03em;animation:.32s cubic-bezier(.22,1,.36,1) kz2Bea_pet-whisper-in}.kz2Bea_bubbleWhisper:before{content:\"「\";opacity:.7;margin-right:2px}.kz2Bea_bubbleWhisper:after{content:\"」\";opacity:.7;margin-left:2px}.kz2Bea_bubbleStack{pointer-events:auto;flex-direction:column-reverse;align-items:center;gap:4px;display:flex;position:absolute;bottom:100%}.kz2Bea_bubbleAnchor{display:inline-flex;position:relative}.kz2Bea_bubbleMore{z-index:1;color:#eef2ff;cursor:pointer;background:linear-gradient(160deg,#4a68f5f2,#2f44b8f2);border:1px solid #7e98ff8c;border-radius:999px;justify-content:center;align-items:center;min-width:18px;height:18px;padding:0 5px;font-size:10px;font-weight:600;line-height:1;transition:filter .12s;display:inline-flex;position:absolute;top:-9px;right:-10px;box-shadow:0 2px 6px #02061766}.kz2Bea_bubbleMore:hover{filter:brightness(1.15)}.kz2Bea_bubbleMore:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}.kz2Bea_bubbleStack .kz2Bea_bubble{pointer-events:auto;margin-bottom:0;position:relative;bottom:auto}.kz2Bea_bubbleClickable{cursor:pointer;font:inherit;text-align:center;appearance:none;transition:filter .12s,box-shadow .12s}.kz2Bea_bubbleClickable:hover{filter:brightness(1.12)}.kz2Bea_bubbleClickable:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}@keyframes kz2Bea_pet-bubble-in{0%{opacity:0;transform:translateY(6px)scale(.96)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes kz2Bea_pet-whisper-in{0%{opacity:0;transform:translateY(8px)scale(.9)}60%{transform:translateY(-1px)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes kz2Bea_pet-panel-in{0%{opacity:0;transform:translateY(4px)scale(.97)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes kz2Bea_pet-bubble-pop{0%{opacity:0;transform:translateY(6px)scale(.85)}15%{opacity:1;transform:translateY(0)scale(1.05)}25%{transform:translateY(0)scale(1)}75%{opacity:1}to{opacity:0;transform:translateY(-8px)scale(.95)}}.kz2Bea_panel{color:#e6ebf8;backdrop-filter:blur(10px);transform-origin:50% 0;background:linear-gradient(165deg,#131c36f2,#070b1af7);border:1px solid #7e98ff4d;border-radius:12px;flex-direction:column;gap:7px;min-width:148px;margin-top:8px;padding:10px 12px;font-size:12px;animation:.2s cubic-bezier(.22,1,.36,1) kz2Bea_pet-panel-in;display:flex;position:absolute;top:100%;box-shadow:0 8px 24px #02061773,0 0 0 1px #4d6bfe1a,inset 0 1px #e2e8ff14}.kz2Bea_panel:after{content:\"\";height:14px;position:absolute;bottom:100%;left:0;right:0}.kz2Bea_panelAbove{transform-origin:50% 100%;margin-top:0;margin-bottom:8px;top:auto;bottom:100%}.kz2Bea_panelAbove:after{top:100%;bottom:auto}.kz2Bea_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.kz2Bea_nameCell{letter-spacing:.02em;background:linear-gradient(90deg,#a9c1ff,#6c8bff 60%,#4d6bfe);color:#0000;-webkit-background-clip:text;background-clip:text;font-weight:600}.kz2Bea_statRank{color:#9db4ff;font-weight:600}.kz2Bea_statTreats{color:#7dd3fc;font-weight:600}.kz2Bea_statPoints{color:#fcd34d;font-weight:600}.kz2Bea_renameRow{align-items:center;gap:6px;display:flex}.kz2Bea_nameInput{color:#e6ebf8;background:#131c36e6;border:1px solid #7e98ff80;border-radius:6px;outline:none;flex:1;min-width:0;padding:3px 6px;font-size:12px}.kz2Bea_nameInput:focus{border-color:#4d6bfe;box-shadow:0 0 0 2px #4d6bfe73}.kz2Bea_actions{gap:6px;display:flex}.kz2Bea_action{cursor:pointer;color:#fff;background:linear-gradient(#4a68f5,#3a55e0);border:none;border-radius:6px;flex:1;padding:4px 8px;font-size:12px;font-weight:600;transition:filter .12s,box-shadow .12s,transform .12s;box-shadow:0 2px 6px #4d6bfe4d}.kz2Bea_action:hover{filter:brightness(1.08);transform:translateY(-1px);box-shadow:0 4px 10px #4d6bfe66}.kz2Bea_action:active{filter:brightness(.94);transform:translateY(0);box-shadow:0 1px 4px #4d6bfe4d}.kz2Bea_action:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}.kz2Bea_summon{color:#8ea6ff;cursor:pointer;background:#070b1abf;border:1px dashed #7e98ff99;border-radius:999px;padding:2px 10px;font-size:11px;transition:border-color .12s,color .12s,background .12s,box-shadow .12s}.kz2Bea_summon:hover{color:#c3d3ff;background:#070b1ae6;border-color:#7e98fff2}.kz2Bea_summon:active{color:#8ea6ff;border-color:#7e98ffcc}.kz2Bea_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}@media (prefers-reduced-motion:reduce){.kz2Bea_bubble,.kz2Bea_bubbleStatus,.kz2Bea_bubbleWhisper,.kz2Bea_panel{opacity:1;animation:none}.kz2Bea_action,.kz2Bea_summon,.kz2Bea_bubbleMore{transition:none}}.kz2Bea_gameplayHud{width:0;height:0;position:absolute;bottom:0;left:0}.kz2Bea_gameplayModeChip{color:#cdd7ff;white-space:nowrap;pointer-events:none;background:#7e98ff2e;border-radius:999px;padding:1px 8px;font-size:10px;position:absolute;top:0;left:0;transform:translateY(-100%)translateY(-4px)}.kz2Bea_gameplayCard{color:#dfe6ff;background:#070b1aeb;border:1px solid #7e98ff40;border-radius:10px;min-width:180px;max-height:340px;padding:10px 12px;font-size:12px;position:absolute;bottom:0;left:0;overflow-y:auto;transform:none;box-shadow:0 8px 24px #0006}.kz2Bea_gameplayBars{flex-direction:column;gap:4px;margin-bottom:8px;display:flex}.kz2Bea_gameplayBarRow{align-items:center;gap:6px;display:flex}.kz2Bea_gameplayBarLabel{color:#9aa8d8;flex-shrink:0;width:34px}.kz2Bea_gameplayBarTrack{background:#7e98ff26;border-radius:3px;flex:1;height:6px;overflow:hidden}.kz2Bea_gameplayBarFill{background:linear-gradient(90deg,#7e98ff,#9db4ff);border-radius:3px;height:100%;transition:width .3s;display:block}.kz2Bea_gameplayActions{flex-wrap:wrap;gap:6px;display:flex}.kz2Bea_gameplayShopItems{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:8px;display:grid}.kz2Bea_gameplayShopItem{color:inherit;cursor:pointer;background:#7e98ff14;border:1px solid #7e98ff40;border-radius:8px;flex-direction:column;align-items:center;gap:4px;padding:8px 6px;display:flex}.kz2Bea_gameplayShopItem:hover{background:#7e98ff29;border-color:#7e98ffb3}.kz2Bea_gameplayShopItemImage{object-fit:contain;width:36px;height:36px;image-rendering:pixelated;pointer-events:none}.kz2Bea_gameplayShopItemLabel{text-align:center;font-size:11px}.kz2Bea_gameplayShopItemPrice{color:#ffd27e;font-size:10px}.kz2Bea_gameplaySkinItems{flex-direction:column;gap:6px;margin-bottom:8px;display:flex}.kz2Bea_gameplaySkinItem{width:100%;color:inherit;cursor:pointer;text-align:left;background:#7e98ff14;border:1px solid #7e98ff40;border-radius:8px;padding:8px 10px;font-size:12px;display:block}.kz2Bea_gameplaySkinItem:hover{background:#7e98ff29;border-color:#7e98ffb3}.kz2Bea_gameplaySkinItemActive{background:#7e98ff47;border-color:#7e98ffe6}.kz2Bea_gameplayClose{color:#9aa8d8;cursor:pointer;background:0 0;border:none;padding:0 2px;font-size:14px;position:absolute;top:4px;right:8px}.kz2Bea_gameplayClose:hover{color:#fff}.kz2Bea_gameplayFloat{color:#3a2a00;white-space:nowrap;pointer-events:none;background:#ffd27eeb;border-radius:999px;padding:2px 10px;font-size:11px;animation:1.1s ease-out forwards kz2Bea_pet-gameplay-float;position:absolute;top:-8px;left:50%;transform:translate(-50%)}@keyframes kz2Bea_pet-gameplay-float{0%{opacity:0;transform:translate(-50%)translateY(6px)}20%{opacity:1}to{opacity:0;transform:translate(-50%)translateY(-18px)}}@media (prefers-reduced-motion:reduce){.kz2Bea_gameplayFloat{opacity:1;animation:none}.kz2Bea_gameplayBarFill{transition:none}}.kz2Bea_bubbleUsage{white-space:nowrap;backdrop-filter:blur(8px);letter-spacing:.02em;background:linear-gradient(160deg,#131c36eb,#070b1af2);border:1px solid #7e98ff73;flex-direction:column;align-items:stretch;gap:3px;min-width:128px;max-width:min(280px,100vw - 24px);padding:6px 12px;animation:.28s cubic-bezier(.22,1,.36,1) kz2Bea_pet-usage-in;display:flex;box-shadow:0 4px 12px #02061759,inset 0 1px #e2e8ff1a,0 0 12px #4d6bfe2e}.kz2Bea_bubbleUsageHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.kz2Bea_bubbleUsageTitle{text-overflow:ellipsis;opacity:.85;overflow:hidden}.kz2Bea_bubbleUsageValue{font-variant-numeric:tabular-nums;flex-shrink:0;font-weight:600}.kz2Bea_bubbleUsageNote{text-overflow:ellipsis;opacity:.55;font-size:10px;overflow:hidden}.kz2Bea_bubbleUsageMeter{background:#e2e8ff24;border-radius:999px;height:4px;display:block;overflow:hidden}.kz2Bea_bubbleUsageMeterFill{background:#6ee7b7;border-radius:999px;height:100%;transition:width .3s;display:block}.kz2Bea_bubbleUsageOk{border-color:#7e98ff73}.kz2Bea_bubbleUsageWarn{border-color:#fbbf248c}.kz2Bea_bubbleUsageWarn .kz2Bea_bubbleUsageMeterFill{background:#fbbf24}.kz2Bea_bubbleUsageLow{border-color:#f8717199}.kz2Bea_bubbleUsageLow .kz2Bea_bubbleUsageMeterFill{background:#f87171}@keyframes kz2Bea_pet-usage-in{0%{opacity:0;transform:translateY(6px)scale(.96)}to{opacity:1;transform:translateY(0)scale(1)}}@media (prefers-reduced-motion:reduce){.kz2Bea_bubbleUsage{animation:none}}";
|
|
272
|
-
const tagId$2 = "@linxin666/dsh-pet/
|
|
270
|
+
//#region \0dsh-css:src/client/pet.module.css.mjs
|
|
271
|
+
const css$2 = ".v78Lda_float{pointer-events:auto;-webkit-user-select:none;user-select:none;will-change:transform;contain:layout style;flex-direction:column;align-items:center;display:flex;position:fixed}.v78Lda_sprite{image-rendering:auto;touch-action:none;contain:paint}.v78Lda_spriteWrap{flex:none;position:relative}.v78Lda_bubble{white-space:nowrap;padding:calc(4px * var(--pet-bubble-scale,1)) calc(10px * var(--pet-bubble-scale,1));font-size:calc(12px * var(--pet-bubble-scale,1));color:#f4f7ff;pointer-events:none;border-radius:999px;margin-bottom:6px;line-height:1.4;animation:2.6s ease-out forwards v78Lda_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.v78Lda_bubblePet{background:#4d6bfef2}.v78Lda_bubbleFeed{background:#0369a1f2}.v78Lda_bubbleStatus{max-width:min(calc(280px * var(--pet-bubble-scale,1)), calc(100vw - 24px));text-overflow:ellipsis;padding:calc(5px * var(--pet-bubble-scale,1)) calc(12px * var(--pet-bubble-scale,1));backdrop-filter:blur(8px);letter-spacing:.02em;background:linear-gradient(160deg,#131c36e6,#070b1af0);border:1px solid #7e98ff73;animation:.24s ease-out v78Lda_pet-bubble-in;overflow:hidden;box-shadow:0 4px 12px #02061759,inset 0 1px #e2e8ff1a,0 0 12px #4d6bfe2e}.v78Lda_bubbleWhisper{letter-spacing:.03em;animation:.32s cubic-bezier(.22,1,.36,1) v78Lda_pet-whisper-in}.v78Lda_bubbleWhisper:before{content:\"「\";opacity:.7;margin-right:2px}.v78Lda_bubbleWhisper:after{content:\"」\";opacity:.7;margin-left:2px}.v78Lda_bubbleStack{pointer-events:auto;flex-direction:column-reverse;align-items:center;gap:4px;display:flex;position:absolute;bottom:100%}.v78Lda_bubbleAnchor{display:inline-flex;position:relative}.v78Lda_bubbleMore{z-index:1;color:#eef2ff;cursor:pointer;background:linear-gradient(160deg,#4a68f5f2,#2f44b8f2);border:1px solid #7e98ff8c;border-radius:999px;justify-content:center;align-items:center;min-width:18px;height:18px;padding:0 5px;font-size:10px;font-weight:600;line-height:1;transition:filter .12s;display:inline-flex;position:absolute;top:-9px;right:-10px;box-shadow:0 2px 6px #02061766}.v78Lda_bubbleMore:hover{filter:brightness(1.15)}.v78Lda_bubbleMore:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}.v78Lda_bubbleStack .v78Lda_bubble{pointer-events:auto;margin-bottom:0;position:relative;bottom:auto}.v78Lda_bubbleClickable{cursor:pointer;font:inherit;text-align:center;appearance:none;transition:filter .12s,box-shadow .12s}.v78Lda_bubbleClickable:hover{filter:brightness(1.12)}.v78Lda_bubbleClickable:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}@keyframes v78Lda_pet-bubble-in{0%{opacity:0;transform:translateY(6px)scale(.96)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes v78Lda_pet-whisper-in{0%{opacity:0;transform:translateY(8px)scale(.9)}60%{transform:translateY(-1px)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes v78Lda_pet-panel-in{0%{opacity:0;transform:translateY(4px)scale(.97)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes v78Lda_pet-bubble-pop{0%{opacity:0;transform:translateY(6px)scale(.85)}15%{opacity:1;transform:translateY(0)scale(1.05)}25%{transform:translateY(0)scale(1)}75%{opacity:1}to{opacity:0;transform:translateY(-8px)scale(.95)}}.v78Lda_panel{color:#e6ebf8;backdrop-filter:blur(10px);transform-origin:50% 0;background:linear-gradient(165deg,#131c36f2,#070b1af7);border:1px solid #7e98ff4d;border-radius:12px;flex-direction:column;gap:7px;min-width:148px;margin-top:8px;padding:10px 12px;font-size:12px;animation:.2s cubic-bezier(.22,1,.36,1) v78Lda_pet-panel-in;display:flex;position:absolute;top:100%;box-shadow:0 8px 24px #02061773,0 0 0 1px #4d6bfe1a,inset 0 1px #e2e8ff14}.v78Lda_panel:after{content:\"\";height:14px;position:absolute;bottom:100%;left:0;right:0}.v78Lda_panelAbove{transform-origin:50% 100%;margin-top:0;margin-bottom:8px;top:auto;bottom:100%}.v78Lda_panelAbove:after{top:100%;bottom:auto}.v78Lda_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.v78Lda_nameCell{letter-spacing:.02em;background:linear-gradient(90deg,#a9c1ff,#6c8bff 60%,#4d6bfe);color:#0000;-webkit-background-clip:text;background-clip:text;font-weight:600}.v78Lda_statRank{color:#9db4ff;font-weight:600}.v78Lda_statTreats{color:#7dd3fc;font-weight:600}.v78Lda_statPoints{color:#fcd34d;font-weight:600}.v78Lda_renameRow{align-items:center;gap:6px;display:flex}.v78Lda_nameInput{color:#e6ebf8;background:#131c36e6;border:1px solid #7e98ff80;border-radius:6px;outline:none;flex:1;min-width:0;padding:3px 6px;font-size:12px}.v78Lda_nameInput:focus{border-color:#4d6bfe;box-shadow:0 0 0 2px #4d6bfe73}.v78Lda_actions{gap:6px;display:flex}.v78Lda_action{cursor:pointer;color:#fff;background:linear-gradient(#4a68f5,#3a55e0);border:none;border-radius:6px;flex:1;padding:4px 8px;font-size:12px;font-weight:600;transition:filter .12s,box-shadow .12s,transform .12s;box-shadow:0 2px 6px #4d6bfe4d}.v78Lda_action:hover{filter:brightness(1.08);transform:translateY(-1px);box-shadow:0 4px 10px #4d6bfe66}.v78Lda_action:active{filter:brightness(.94);transform:translateY(0);box-shadow:0 1px 4px #4d6bfe4d}.v78Lda_action:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}.v78Lda_summon{color:#8ea6ff;cursor:pointer;background:#070b1abf;border:1px dashed #7e98ff99;border-radius:999px;padding:2px 10px;font-size:11px;transition:border-color .12s,color .12s,background .12s,box-shadow .12s}.v78Lda_summon:hover{color:#c3d3ff;background:#070b1ae6;border-color:#7e98fff2}.v78Lda_summon:active{color:#8ea6ff;border-color:#7e98ffcc}.v78Lda_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}@media (prefers-reduced-motion:reduce){.v78Lda_bubble,.v78Lda_bubbleStatus,.v78Lda_bubbleWhisper,.v78Lda_panel{opacity:1;animation:none}.v78Lda_action,.v78Lda_summon,.v78Lda_bubbleMore{transition:none}}.v78Lda_gameplayHud{width:0;height:0;position:absolute;bottom:0;left:0}.v78Lda_gameplayModeChip{color:#cdd7ff;white-space:nowrap;pointer-events:none;background:#7e98ff2e;border-radius:999px;padding:1px 8px;font-size:10px;position:absolute;top:0;left:0;transform:translateY(-100%)translateY(-4px)}.v78Lda_gameplayCard{color:#dfe6ff;background:#070b1aeb;border:1px solid #7e98ff40;border-radius:10px;min-width:180px;max-height:340px;padding:10px 12px;font-size:12px;position:absolute;bottom:0;left:0;overflow-y:auto;transform:none;box-shadow:0 8px 24px #0006}.v78Lda_gameplayBars{flex-direction:column;gap:4px;margin-bottom:8px;display:flex}.v78Lda_gameplayBarRow{align-items:center;gap:6px;display:flex}.v78Lda_gameplayBarLabel{color:#9aa8d8;flex-shrink:0;width:34px}.v78Lda_gameplayBarTrack{background:#7e98ff26;border-radius:3px;flex:1;height:6px;overflow:hidden}.v78Lda_gameplayBarFill{background:linear-gradient(90deg,#7e98ff,#9db4ff);border-radius:3px;height:100%;transition:width .3s;display:block}.v78Lda_gameplayActions{flex-wrap:wrap;gap:6px;display:flex}.v78Lda_gameplayShopItems{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:8px;display:grid}.v78Lda_gameplayShopItem{color:inherit;cursor:pointer;background:#7e98ff14;border:1px solid #7e98ff40;border-radius:8px;flex-direction:column;align-items:center;gap:4px;padding:8px 6px;display:flex}.v78Lda_gameplayShopItem:hover{background:#7e98ff29;border-color:#7e98ffb3}.v78Lda_gameplayShopItemImage{object-fit:contain;width:36px;height:36px;image-rendering:pixelated;pointer-events:none}.v78Lda_gameplayShopItemLabel{text-align:center;font-size:11px}.v78Lda_gameplayShopItemPrice{color:#ffd27e;font-size:10px}.v78Lda_gameplaySkinItems{flex-direction:column;gap:6px;margin-bottom:8px;display:flex}.v78Lda_gameplaySkinItem{width:100%;color:inherit;cursor:pointer;text-align:left;background:#7e98ff14;border:1px solid #7e98ff40;border-radius:8px;padding:8px 10px;font-size:12px;display:block}.v78Lda_gameplaySkinItem:hover{background:#7e98ff29;border-color:#7e98ffb3}.v78Lda_gameplaySkinItemActive{background:#7e98ff47;border-color:#7e98ffe6}.v78Lda_gameplayClose{color:#9aa8d8;cursor:pointer;background:0 0;border:none;padding:0 2px;font-size:14px;position:absolute;top:4px;right:8px}.v78Lda_gameplayClose:hover{color:#fff}.v78Lda_gameplayFloat{color:#3a2a00;white-space:nowrap;pointer-events:none;background:#ffd27eeb;border-radius:999px;padding:2px 10px;font-size:11px;animation:1.1s ease-out forwards v78Lda_pet-gameplay-float;position:absolute;top:-8px;left:50%;transform:translate(-50%)}@keyframes v78Lda_pet-gameplay-float{0%{opacity:0;transform:translate(-50%)translateY(6px)}20%{opacity:1}to{opacity:0;transform:translate(-50%)translateY(-18px)}}@media (prefers-reduced-motion:reduce){.v78Lda_gameplayFloat{opacity:1;animation:none}.v78Lda_gameplayBarFill{transition:none}}.v78Lda_bubbleUsage{white-space:nowrap;backdrop-filter:blur(8px);letter-spacing:.02em;background:linear-gradient(160deg,#131c36eb,#070b1af2);border:1px solid #7e98ff73;flex-direction:column;align-items:stretch;gap:3px;min-width:128px;max-width:min(280px,100vw - 24px);padding:6px 12px;animation:.28s cubic-bezier(.22,1,.36,1) v78Lda_pet-usage-in;display:flex;box-shadow:0 4px 12px #02061759,inset 0 1px #e2e8ff1a,0 0 12px #4d6bfe2e}.v78Lda_bubbleUsageHead{justify-content:space-between;align-items:baseline;gap:10px;display:flex}.v78Lda_bubbleUsageTitle{text-overflow:ellipsis;opacity:.85;overflow:hidden}.v78Lda_bubbleUsageValue{font-variant-numeric:tabular-nums;flex-shrink:0;font-weight:600}.v78Lda_bubbleUsageNote{text-overflow:ellipsis;opacity:.55;font-size:10px;overflow:hidden}.v78Lda_bubbleUsageMeter{background:#e2e8ff24;border-radius:999px;height:4px;display:block;overflow:hidden}.v78Lda_bubbleUsageMeterFill{background:#6ee7b7;border-radius:999px;height:100%;transition:width .3s;display:block}.v78Lda_bubbleUsageOk{border-color:#7e98ff73}.v78Lda_bubbleUsageWarn{border-color:#fbbf248c}.v78Lda_bubbleUsageWarn .v78Lda_bubbleUsageMeterFill{background:#fbbf24}.v78Lda_bubbleUsageLow{border-color:#f8717199}.v78Lda_bubbleUsageLow .v78Lda_bubbleUsageMeterFill{background:#f87171}@keyframes v78Lda_pet-usage-in{0%{opacity:0;transform:translateY(6px)scale(.96)}to{opacity:1;transform:translateY(0)scale(1)}}@media (prefers-reduced-motion:reduce){.v78Lda_bubbleUsage{animation:none}}";
|
|
272
|
+
const tagId$2 = "@linxin666/dsh-pet/src/client/pet.module.css";
|
|
273
273
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
274
274
|
const tag = document.createElement("style");
|
|
275
275
|
tag.dataset.plugin = "@linxin666/dsh-pet";
|
|
@@ -278,65 +278,65 @@ window.__ModuleLoader__.load({
|
|
|
278
278
|
document.head.appendChild(tag);
|
|
279
279
|
}
|
|
280
280
|
var pet_module_css_default = {
|
|
281
|
-
"action": "
|
|
282
|
-
"actions": "
|
|
283
|
-
"bubble": "
|
|
284
|
-
"bubbleAnchor": "
|
|
285
|
-
"bubbleClickable": "
|
|
286
|
-
"bubbleFeed": "
|
|
287
|
-
"bubbleMore": "
|
|
288
|
-
"bubblePet": "
|
|
289
|
-
"bubbleStack": "
|
|
290
|
-
"bubbleStatus": "
|
|
291
|
-
"bubbleUsage": "
|
|
292
|
-
"bubbleUsageHead": "
|
|
293
|
-
"bubbleUsageLow": "
|
|
294
|
-
"bubbleUsageMeter": "
|
|
295
|
-
"bubbleUsageMeterFill": "
|
|
296
|
-
"bubbleUsageNote": "
|
|
297
|
-
"bubbleUsageOk": "
|
|
298
|
-
"bubbleUsageTitle": "
|
|
299
|
-
"bubbleUsageValue": "
|
|
300
|
-
"bubbleUsageWarn": "
|
|
301
|
-
"bubbleWhisper": "
|
|
302
|
-
"float": "
|
|
303
|
-
"gameplayActions": "
|
|
304
|
-
"gameplayBarFill": "
|
|
305
|
-
"gameplayBarLabel": "
|
|
306
|
-
"gameplayBarRow": "
|
|
307
|
-
"gameplayBarTrack": "
|
|
308
|
-
"gameplayBars": "
|
|
309
|
-
"gameplayCard": "
|
|
310
|
-
"gameplayClose": "
|
|
311
|
-
"gameplayFloat": "
|
|
312
|
-
"gameplayHud": "
|
|
313
|
-
"gameplayModeChip": "
|
|
314
|
-
"gameplayShopItem": "
|
|
315
|
-
"gameplayShopItemImage": "
|
|
316
|
-
"gameplayShopItemLabel": "
|
|
317
|
-
"gameplayShopItemPrice": "
|
|
318
|
-
"gameplayShopItems": "
|
|
319
|
-
"gameplaySkinItem": "
|
|
320
|
-
"gameplaySkinItemActive": "
|
|
321
|
-
"gameplaySkinItems": "
|
|
322
|
-
"nameCell": "
|
|
323
|
-
"nameInput": "
|
|
324
|
-
"panel": "
|
|
325
|
-
"panelAbove": "
|
|
326
|
-
"pet-bubble-in": "
|
|
327
|
-
"pet-bubble-pop": "
|
|
328
|
-
"pet-gameplay-float": "
|
|
329
|
-
"pet-panel-in": "
|
|
330
|
-
"pet-usage-in": "
|
|
331
|
-
"pet-whisper-in": "
|
|
332
|
-
"rankRow": "
|
|
333
|
-
"renameRow": "
|
|
334
|
-
"sprite": "
|
|
335
|
-
"spriteWrap": "
|
|
336
|
-
"statPoints": "
|
|
337
|
-
"statRank": "
|
|
338
|
-
"statTreats": "
|
|
339
|
-
"summon": "
|
|
281
|
+
"action": "v78Lda_action",
|
|
282
|
+
"actions": "v78Lda_actions",
|
|
283
|
+
"bubble": "v78Lda_bubble",
|
|
284
|
+
"bubbleAnchor": "v78Lda_bubbleAnchor",
|
|
285
|
+
"bubbleClickable": "v78Lda_bubbleClickable",
|
|
286
|
+
"bubbleFeed": "v78Lda_bubbleFeed",
|
|
287
|
+
"bubbleMore": "v78Lda_bubbleMore",
|
|
288
|
+
"bubblePet": "v78Lda_bubblePet",
|
|
289
|
+
"bubbleStack": "v78Lda_bubbleStack",
|
|
290
|
+
"bubbleStatus": "v78Lda_bubbleStatus",
|
|
291
|
+
"bubbleUsage": "v78Lda_bubbleUsage",
|
|
292
|
+
"bubbleUsageHead": "v78Lda_bubbleUsageHead",
|
|
293
|
+
"bubbleUsageLow": "v78Lda_bubbleUsageLow",
|
|
294
|
+
"bubbleUsageMeter": "v78Lda_bubbleUsageMeter",
|
|
295
|
+
"bubbleUsageMeterFill": "v78Lda_bubbleUsageMeterFill",
|
|
296
|
+
"bubbleUsageNote": "v78Lda_bubbleUsageNote",
|
|
297
|
+
"bubbleUsageOk": "v78Lda_bubbleUsageOk",
|
|
298
|
+
"bubbleUsageTitle": "v78Lda_bubbleUsageTitle",
|
|
299
|
+
"bubbleUsageValue": "v78Lda_bubbleUsageValue",
|
|
300
|
+
"bubbleUsageWarn": "v78Lda_bubbleUsageWarn",
|
|
301
|
+
"bubbleWhisper": "v78Lda_bubbleWhisper",
|
|
302
|
+
"float": "v78Lda_float",
|
|
303
|
+
"gameplayActions": "v78Lda_gameplayActions",
|
|
304
|
+
"gameplayBarFill": "v78Lda_gameplayBarFill",
|
|
305
|
+
"gameplayBarLabel": "v78Lda_gameplayBarLabel",
|
|
306
|
+
"gameplayBarRow": "v78Lda_gameplayBarRow",
|
|
307
|
+
"gameplayBarTrack": "v78Lda_gameplayBarTrack",
|
|
308
|
+
"gameplayBars": "v78Lda_gameplayBars",
|
|
309
|
+
"gameplayCard": "v78Lda_gameplayCard",
|
|
310
|
+
"gameplayClose": "v78Lda_gameplayClose",
|
|
311
|
+
"gameplayFloat": "v78Lda_gameplayFloat",
|
|
312
|
+
"gameplayHud": "v78Lda_gameplayHud",
|
|
313
|
+
"gameplayModeChip": "v78Lda_gameplayModeChip",
|
|
314
|
+
"gameplayShopItem": "v78Lda_gameplayShopItem",
|
|
315
|
+
"gameplayShopItemImage": "v78Lda_gameplayShopItemImage",
|
|
316
|
+
"gameplayShopItemLabel": "v78Lda_gameplayShopItemLabel",
|
|
317
|
+
"gameplayShopItemPrice": "v78Lda_gameplayShopItemPrice",
|
|
318
|
+
"gameplayShopItems": "v78Lda_gameplayShopItems",
|
|
319
|
+
"gameplaySkinItem": "v78Lda_gameplaySkinItem",
|
|
320
|
+
"gameplaySkinItemActive": "v78Lda_gameplaySkinItemActive",
|
|
321
|
+
"gameplaySkinItems": "v78Lda_gameplaySkinItems",
|
|
322
|
+
"nameCell": "v78Lda_nameCell",
|
|
323
|
+
"nameInput": "v78Lda_nameInput",
|
|
324
|
+
"panel": "v78Lda_panel",
|
|
325
|
+
"panelAbove": "v78Lda_panelAbove",
|
|
326
|
+
"pet-bubble-in": "v78Lda_pet-bubble-in",
|
|
327
|
+
"pet-bubble-pop": "v78Lda_pet-bubble-pop",
|
|
328
|
+
"pet-gameplay-float": "v78Lda_pet-gameplay-float",
|
|
329
|
+
"pet-panel-in": "v78Lda_pet-panel-in",
|
|
330
|
+
"pet-usage-in": "v78Lda_pet-usage-in",
|
|
331
|
+
"pet-whisper-in": "v78Lda_pet-whisper-in",
|
|
332
|
+
"rankRow": "v78Lda_rankRow",
|
|
333
|
+
"renameRow": "v78Lda_renameRow",
|
|
334
|
+
"sprite": "v78Lda_sprite",
|
|
335
|
+
"spriteWrap": "v78Lda_spriteWrap",
|
|
336
|
+
"statPoints": "v78Lda_statPoints",
|
|
337
|
+
"statRank": "v78Lda_statRank",
|
|
338
|
+
"statTreats": "v78Lda_statTreats",
|
|
339
|
+
"summon": "v78Lda_summon"
|
|
340
340
|
};
|
|
341
341
|
//#endregion
|
|
342
342
|
//#region src/client/PetSprite.tsx
|
|
@@ -618,10 +618,12 @@ window.__ModuleLoader__.load({
|
|
|
618
618
|
st.elapsed -= track.durations[st.index] ?? 0;
|
|
619
619
|
st.index += 1;
|
|
620
620
|
}
|
|
621
|
-
if (st.elapsed >= (track.durations[st.index] ?? 0))
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
621
|
+
if (st.elapsed >= (track.durations[st.index] ?? 0)) {
|
|
622
|
+
if (track.loop) {
|
|
623
|
+
st.elapsed = 0;
|
|
624
|
+
st.index = 0;
|
|
625
|
+
} else st.index = maxIndex;
|
|
626
|
+
}
|
|
625
627
|
const col = track.frames[st.index];
|
|
626
628
|
const pos = framePosition(cell, row, col, scaleRef.current);
|
|
627
629
|
const posStr = pos.x + "px " + pos.y + "px";
|
|
@@ -660,6 +662,7 @@ window.__ModuleLoader__.load({
|
|
|
660
662
|
(0, react.useEffect)(() => () => clearHideTimer(), []);
|
|
661
663
|
const onPointerDown = (e) => {
|
|
662
664
|
if (props.dragDisabled === true) return;
|
|
665
|
+
endWalk(false);
|
|
663
666
|
e.preventDefault();
|
|
664
667
|
e.target.setPointerCapture?.(e.pointerId);
|
|
665
668
|
const current = dragPos ?? {
|
|
@@ -702,6 +705,84 @@ window.__ModuleLoader__.load({
|
|
|
702
705
|
};
|
|
703
706
|
const spriteWidth = Math.round(cell.width * spriteScale);
|
|
704
707
|
const spriteHeight = Math.round(cell.height * spriteScale);
|
|
708
|
+
const [facingRight, setFacingRight] = (0, react.useState)(false);
|
|
709
|
+
const walkRafRef = (0, react.useRef)(0);
|
|
710
|
+
const walkTargetRef = (0, react.useRef)(null);
|
|
711
|
+
const dragPosRef = (0, react.useRef)(dragPos);
|
|
712
|
+
dragPosRef.current = dragPos;
|
|
713
|
+
/** Stop an active walk; `persist` lands the pet on the spot it reached. */
|
|
714
|
+
const endWalk = (persist) => {
|
|
715
|
+
if (walkRafRef.current === 0) return;
|
|
716
|
+
window.cancelAnimationFrame(walkRafRef.current);
|
|
717
|
+
walkRafRef.current = 0;
|
|
718
|
+
setFacingRight(false);
|
|
719
|
+
const settled = walkTargetRef.current;
|
|
720
|
+
walkTargetRef.current = null;
|
|
721
|
+
if (persist && settled !== null) props.onDragEnd(settled.right, settled.bottom);
|
|
722
|
+
};
|
|
723
|
+
(0, react.useEffect)(() => {
|
|
724
|
+
const bus = props.bus;
|
|
725
|
+
if (bus === void 0) return void 0;
|
|
726
|
+
bus.walk = (direction, distance, speed) => {
|
|
727
|
+
if (dragRef.current !== null || walkRafRef.current !== 0) return 0;
|
|
728
|
+
const current = dragPosRef.current ?? {
|
|
729
|
+
right: display.right,
|
|
730
|
+
bottom: display.bottom
|
|
731
|
+
};
|
|
732
|
+
const margin = 8;
|
|
733
|
+
const maxRight = Math.max(margin, window.innerWidth - spriteWidth - margin);
|
|
734
|
+
const maxBottom = Math.max(margin, window.innerHeight - spriteHeight - margin);
|
|
735
|
+
const wanted = { ...current };
|
|
736
|
+
if (direction === "left") wanted.right = current.right + distance;
|
|
737
|
+
else if (direction === "right") wanted.right = current.right - distance;
|
|
738
|
+
else if (direction === "up") wanted.bottom = current.bottom + distance;
|
|
739
|
+
else wanted.bottom = current.bottom - distance;
|
|
740
|
+
const target = {
|
|
741
|
+
right: Math.max(margin, clampOffset(wanted.right, maxRight)),
|
|
742
|
+
bottom: Math.max(margin, clampOffset(wanted.bottom, maxBottom))
|
|
743
|
+
};
|
|
744
|
+
const travelled = direction === "left" ? target.right - current.right : direction === "right" ? current.right - target.right : direction === "up" ? target.bottom - current.bottom : current.bottom - target.bottom;
|
|
745
|
+
if (travelled < 1) return 0;
|
|
746
|
+
const duration = Math.max(150, travelled / Math.max(1, speed) * 1e3);
|
|
747
|
+
const startedAt = performance.now();
|
|
748
|
+
setFacingRight(direction === "right");
|
|
749
|
+
walkTargetRef.current = current;
|
|
750
|
+
const step = (now) => {
|
|
751
|
+
const t = Math.min(1, (now - startedAt) / duration);
|
|
752
|
+
const next = {
|
|
753
|
+
right: current.right + (target.right - current.right) * t,
|
|
754
|
+
bottom: current.bottom + (target.bottom - current.bottom) * t
|
|
755
|
+
};
|
|
756
|
+
walkTargetRef.current = next;
|
|
757
|
+
setDragPos(next);
|
|
758
|
+
if (t < 1) {
|
|
759
|
+
walkRafRef.current = window.requestAnimationFrame(step);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
walkRafRef.current = 0;
|
|
763
|
+
walkTargetRef.current = null;
|
|
764
|
+
setFacingRight(false);
|
|
765
|
+
props.onDragEnd(next.right, next.bottom);
|
|
766
|
+
};
|
|
767
|
+
walkRafRef.current = window.requestAnimationFrame(step);
|
|
768
|
+
return travelled;
|
|
769
|
+
};
|
|
770
|
+
return () => {
|
|
771
|
+
bus.walk = void 0;
|
|
772
|
+
if (walkRafRef.current !== 0) {
|
|
773
|
+
window.cancelAnimationFrame(walkRafRef.current);
|
|
774
|
+
walkRafRef.current = 0;
|
|
775
|
+
}
|
|
776
|
+
setFacingRight(false);
|
|
777
|
+
walkTargetRef.current = null;
|
|
778
|
+
};
|
|
779
|
+
}, [
|
|
780
|
+
props.bus,
|
|
781
|
+
definition.id,
|
|
782
|
+
display.right,
|
|
783
|
+
display.bottom,
|
|
784
|
+
spriteWidth
|
|
785
|
+
]);
|
|
705
786
|
const bubbleScale = bubbleScaleFor(display);
|
|
706
787
|
const sessionBubbles = snapshot?.sessions ?? [];
|
|
707
788
|
const stackOpen = stackPeek || stackPinned;
|
|
@@ -744,7 +825,7 @@ window.__ModuleLoader__.load({
|
|
|
744
825
|
stackOpen,
|
|
745
826
|
feedback
|
|
746
827
|
]);
|
|
747
|
-
|
|
828
|
+
const float = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
748
829
|
ref: floatRef,
|
|
749
830
|
className: pet_module_css_default.float,
|
|
750
831
|
style: {
|
|
@@ -783,7 +864,8 @@ window.__ModuleLoader__.load({
|
|
|
783
864
|
backgroundRepeat: "no-repeat",
|
|
784
865
|
backgroundPosition: "0 0"
|
|
785
866
|
} : {},
|
|
786
|
-
cursor: dragRef.current === null ? "grab" : "grabbing"
|
|
867
|
+
cursor: dragRef.current === null ? "grab" : "grabbing",
|
|
868
|
+
...facingRight ? { transform: "scaleX(-1)" } : {}
|
|
787
869
|
},
|
|
788
870
|
onPointerDown,
|
|
789
871
|
onPointerMove,
|
|
@@ -963,7 +1045,8 @@ window.__ModuleLoader__.load({
|
|
|
963
1045
|
] })
|
|
964
1046
|
})
|
|
965
1047
|
]
|
|
966
|
-
})
|
|
1048
|
+
});
|
|
1049
|
+
return (0, react_dom.createPortal)(float, props.portalTarget ?? document.body);
|
|
967
1050
|
}
|
|
968
1051
|
//#endregion
|
|
969
1052
|
//#region src/client/drag-stream.ts
|
|
@@ -1276,6 +1359,36 @@ window.__ModuleLoader__.load({
|
|
|
1276
1359
|
}
|
|
1277
1360
|
//#endregion
|
|
1278
1361
|
//#region src/gameplay.ts
|
|
1362
|
+
/** Every roam direction, in roll order (equal chance each unless restricted). */
|
|
1363
|
+
const PET_ROAM_DIRECTIONS = [
|
|
1364
|
+
"up",
|
|
1365
|
+
"down",
|
|
1366
|
+
"left",
|
|
1367
|
+
"right"
|
|
1368
|
+
];
|
|
1369
|
+
/**
|
|
1370
|
+
* One declared extra mode, by OWN key only. A plain `modes[id]` lookup also
|
|
1371
|
+
* answers for Object.prototype members ('constructor', 'toString', …), which
|
|
1372
|
+
* would let a crafted mode id pass the "is it declared?" test.
|
|
1373
|
+
*/
|
|
1374
|
+
function declaredModeOf(manifest, mode) {
|
|
1375
|
+
const modes = manifest.modes;
|
|
1376
|
+
if (modes === void 0 || !Object.prototype.hasOwnProperty.call(modes, mode)) return void 0;
|
|
1377
|
+
return modes[mode];
|
|
1378
|
+
}
|
|
1379
|
+
/** Every mode the menu offers, in manifest order (sleep first, then extras). */
|
|
1380
|
+
function declaredModes(manifest) {
|
|
1381
|
+
return [...manifest.sleep === void 0 ? [] : ["sleep"], ...Object.keys(manifest.modes ?? {})];
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* The frames2d track one active mode holds. 'work' is owned by the work loop
|
|
1385
|
+
* (its state, result and fallback are its own), so it resolves to undefined.
|
|
1386
|
+
*/
|
|
1387
|
+
function modeStateOf(manifest, mode) {
|
|
1388
|
+
if (mode === "sleep") return manifest.sleep?.state;
|
|
1389
|
+
if (mode === "work") return manifest.work?.state;
|
|
1390
|
+
return declaredModeOf(manifest, mode)?.state;
|
|
1391
|
+
}
|
|
1279
1392
|
/** The zone one normalized hit-box point lands in, if any. */
|
|
1280
1393
|
function touchZoneAt(touch, yFraction) {
|
|
1281
1394
|
return touch.zones.find((zone) => yFraction >= zone.y0 && yFraction < zone.y1);
|
|
@@ -1299,7 +1412,6 @@ window.__ModuleLoader__.load({
|
|
|
1299
1412
|
const ui = (0, react.useSyncExternalStore)(store.subscribe, store.getSnapshot);
|
|
1300
1413
|
const def = definition.gameplay;
|
|
1301
1414
|
const view = ui.snapshot?.gameplay;
|
|
1302
|
-
const phase = ui.snapshot?.phase ?? "idle";
|
|
1303
1415
|
const persistedSkin = ui.snapshot?.skin;
|
|
1304
1416
|
const [open, setOpen] = (0, react.useState)(false);
|
|
1305
1417
|
const [page, setPage] = (0, react.useState)("root");
|
|
@@ -1311,12 +1423,19 @@ window.__ModuleLoader__.load({
|
|
|
1311
1423
|
const [floats, setFloats] = (0, react.useState)([]);
|
|
1312
1424
|
const modeRef = (0, react.useRef)(view?.mode ?? null);
|
|
1313
1425
|
modeRef.current = view?.mode ?? null;
|
|
1314
|
-
|
|
1315
|
-
|
|
1426
|
+
/** Live gameplay view for the interval loops (def identity is stable, view is not). */
|
|
1427
|
+
const viewRef = (0, react.useRef)(view);
|
|
1428
|
+
viewRef.current = view;
|
|
1316
1429
|
const draggingRef = (0, react.useRef)(false);
|
|
1317
1430
|
const touchLockUntilRef = (0, react.useRef)(0);
|
|
1318
1431
|
const missRef = (0, react.useRef)(0);
|
|
1319
1432
|
const busyRef = (0, react.useRef)(false);
|
|
1433
|
+
/** A roam walk owns the visual right now (the idle director must not steal it). */
|
|
1434
|
+
const roamHeldRef = (0, react.useRef)(false);
|
|
1435
|
+
/** A one-shot idle-director act owns the visual right now (the roam must not cut in). */
|
|
1436
|
+
const actHeldRef = (0, react.useRef)(false);
|
|
1437
|
+
/** Pending release of the roam's walk track (cleared when another owner takes it). */
|
|
1438
|
+
const roamTimerRef = (0, react.useRef)(0);
|
|
1320
1439
|
const tr = props.t;
|
|
1321
1440
|
const statLabel = (name) => tr("pet.gameplay.stat." + name);
|
|
1322
1441
|
const currencyLabel = (name) => tr("pet.gameplay.currency." + name);
|
|
@@ -1333,9 +1452,23 @@ window.__ModuleLoader__.load({
|
|
|
1333
1452
|
const applyResult = (result) => {
|
|
1334
1453
|
if (result.view !== void 0) store.actions.setGameplayView(result.view);
|
|
1335
1454
|
};
|
|
1455
|
+
/**
|
|
1456
|
+
* Give up the roam's claim on the shared track-override slot. Every other
|
|
1457
|
+
* owner (a mode, a touch reaction, a drag) calls this before it takes the
|
|
1458
|
+
* slot, so a walk that is still in flight can never release someone else's
|
|
1459
|
+
* track when its own hold window elapses.
|
|
1460
|
+
*/
|
|
1461
|
+
const yieldRoam = () => {
|
|
1462
|
+
if (roamTimerRef.current !== 0) {
|
|
1463
|
+
window.clearTimeout(roamTimerRef.current);
|
|
1464
|
+
roamTimerRef.current = 0;
|
|
1465
|
+
}
|
|
1466
|
+
roamHeldRef.current = false;
|
|
1467
|
+
};
|
|
1336
1468
|
(0, react.useEffect)(() => {
|
|
1337
1469
|
if (def === void 0) return void 0;
|
|
1338
1470
|
const holdTrack = (track, holdMs) => {
|
|
1471
|
+
yieldRoam();
|
|
1339
1472
|
bus.setTrack?.(track);
|
|
1340
1473
|
touchLockUntilRef.current = Date.now() + holdMs;
|
|
1341
1474
|
window.setTimeout(() => {
|
|
@@ -1354,7 +1487,7 @@ window.__ModuleLoader__.load({
|
|
|
1354
1487
|
};
|
|
1355
1488
|
const trackDuration = (track) => definition.frames2d?.tracks[track]?.durations.reduce((sum, ms) => sum + ms, 0) ?? 0;
|
|
1356
1489
|
bus.tap = (fx, fy) => {
|
|
1357
|
-
if (modeRef.current
|
|
1490
|
+
if (modeRef.current !== null && modeRef.current !== "work") {
|
|
1358
1491
|
api.setMode(null).then(applyResult, () => void 0);
|
|
1359
1492
|
return;
|
|
1360
1493
|
}
|
|
@@ -1440,7 +1573,8 @@ window.__ModuleLoader__.load({
|
|
|
1440
1573
|
(0, react.useEffect)(() => {
|
|
1441
1574
|
return props.drag.subscribe((dragging) => {
|
|
1442
1575
|
draggingRef.current = dragging;
|
|
1443
|
-
if (dragging
|
|
1576
|
+
if (dragging) yieldRoam();
|
|
1577
|
+
if (dragging && modeRef.current !== null && modeRef.current !== "work") api.setMode(null).then(applyResult, () => void 0);
|
|
1444
1578
|
});
|
|
1445
1579
|
}, [props.drag]);
|
|
1446
1580
|
(0, react.useEffect)(() => {
|
|
@@ -1448,10 +1582,12 @@ window.__ModuleLoader__.load({
|
|
|
1448
1582
|
if (def === void 0 || director === void 0) return void 0;
|
|
1449
1583
|
const total = director.idleWeight + director.acts.reduce((sum, act) => sum + act.weight, 0);
|
|
1450
1584
|
if (total <= 0) return void 0;
|
|
1585
|
+
let actTimer = 0;
|
|
1451
1586
|
const timer = window.setInterval(() => {
|
|
1452
|
-
if (phaseRef.current !== "idle") return;
|
|
1453
1587
|
if (modeRef.current !== null || draggingRef.current) return;
|
|
1454
1588
|
if (Date.now() < touchLockUntilRef.current) return;
|
|
1589
|
+
if (roamHeldRef.current) return;
|
|
1590
|
+
if (actHeldRef.current) return;
|
|
1455
1591
|
let pickedAct;
|
|
1456
1592
|
if (missRef.current >= director.maxMiss) {
|
|
1457
1593
|
const actTotal = director.acts.reduce((sum, act) => sum + act.weight, 0);
|
|
@@ -1478,7 +1614,13 @@ window.__ModuleLoader__.load({
|
|
|
1478
1614
|
return;
|
|
1479
1615
|
}
|
|
1480
1616
|
missRef.current = 0;
|
|
1617
|
+
actHeldRef.current = true;
|
|
1481
1618
|
bus.setTrack?.(pickedAct.track);
|
|
1619
|
+
const holdMs = definition.frames2d?.tracks[pickedAct.track]?.durations.reduce((sum, ms) => sum + ms, 0) ?? 0;
|
|
1620
|
+
window.clearTimeout(actTimer);
|
|
1621
|
+
actTimer = window.setTimeout(() => {
|
|
1622
|
+
actHeldRef.current = false;
|
|
1623
|
+
}, holdMs > 0 ? holdMs : 3e3);
|
|
1482
1624
|
if (pickedAct.phrases !== void 0 && pickedAct.phrases.length > 0) {
|
|
1483
1625
|
const phrase = pickedAct.phrases[Math.floor(Math.random() * pickedAct.phrases.length)];
|
|
1484
1626
|
store.actions.setFeedback({
|
|
@@ -1488,7 +1630,11 @@ window.__ModuleLoader__.load({
|
|
|
1488
1630
|
});
|
|
1489
1631
|
}
|
|
1490
1632
|
}, director.intervalMs);
|
|
1491
|
-
return () =>
|
|
1633
|
+
return () => {
|
|
1634
|
+
window.clearInterval(timer);
|
|
1635
|
+
window.clearTimeout(actTimer);
|
|
1636
|
+
actHeldRef.current = false;
|
|
1637
|
+
};
|
|
1492
1638
|
}, [definition.id, def]);
|
|
1493
1639
|
(0, react.useEffect)(() => {
|
|
1494
1640
|
const work = def?.work;
|
|
@@ -1528,10 +1674,13 @@ window.__ModuleLoader__.load({
|
|
|
1528
1674
|
skinId
|
|
1529
1675
|
]);
|
|
1530
1676
|
(0, react.useEffect)(() => {
|
|
1531
|
-
const
|
|
1532
|
-
if (def === void 0 ||
|
|
1533
|
-
const hold = (
|
|
1534
|
-
|
|
1677
|
+
const active = view?.mode;
|
|
1678
|
+
if (def === void 0 || active === void 0 || active === null || active === "work") return void 0;
|
|
1679
|
+
const hold = modeStateOf(def, active);
|
|
1680
|
+
if (hold === void 0) return void 0;
|
|
1681
|
+
const skinGameplay = definition.frames2d?.skins?.find((skin) => skin.id === skinIdRef.current)?.gameplayTracks;
|
|
1682
|
+
yieldRoam();
|
|
1683
|
+
bus.setTrack?.(skinGameplay?.[active] ?? hold);
|
|
1535
1684
|
return () => bus.setTrack?.(void 0);
|
|
1536
1685
|
}, [
|
|
1537
1686
|
definition.id,
|
|
@@ -1539,10 +1688,58 @@ window.__ModuleLoader__.load({
|
|
|
1539
1688
|
view?.mode,
|
|
1540
1689
|
skinId
|
|
1541
1690
|
]);
|
|
1691
|
+
(0, react.useEffect)(() => {
|
|
1692
|
+
const roam = def?.roam;
|
|
1693
|
+
if (def === void 0 || roam === void 0) return void 0;
|
|
1694
|
+
const roll = () => {
|
|
1695
|
+
if (modeRef.current !== null || draggingRef.current) return;
|
|
1696
|
+
if (Date.now() < touchLockUntilRef.current) return;
|
|
1697
|
+
if (roamHeldRef.current || actHeldRef.current) return;
|
|
1698
|
+
if (Math.random() >= roam.probability) return;
|
|
1699
|
+
const span = roam.distanceMax - roam.distanceMin;
|
|
1700
|
+
const distance = roam.distanceMin + Math.random() * span;
|
|
1701
|
+
const directions = roam.directions ?? PET_ROAM_DIRECTIONS;
|
|
1702
|
+
const direction = directions[Math.floor(Math.random() * directions.length)] ?? "left";
|
|
1703
|
+
const travelled = bus.walk?.(direction, distance, roam.speed) ?? 0;
|
|
1704
|
+
if (travelled === 0) return;
|
|
1705
|
+
roamHeldRef.current = true;
|
|
1706
|
+
bus.setTrack?.(roam.state);
|
|
1707
|
+
roamTimerRef.current = window.setTimeout(() => {
|
|
1708
|
+
roamTimerRef.current = 0;
|
|
1709
|
+
if (!roamHeldRef.current) return;
|
|
1710
|
+
roamHeldRef.current = false;
|
|
1711
|
+
bus.setTrack?.(void 0);
|
|
1712
|
+
}, Math.max(150, Math.abs(travelled) / roam.speed * 1e3));
|
|
1713
|
+
};
|
|
1714
|
+
let timer = 0;
|
|
1715
|
+
const lead = window.setTimeout(() => {
|
|
1716
|
+
roll();
|
|
1717
|
+
timer = window.setInterval(roll, roam.intervalMs);
|
|
1718
|
+
}, Math.round(roam.intervalMs / 2));
|
|
1719
|
+
return () => {
|
|
1720
|
+
window.clearTimeout(lead);
|
|
1721
|
+
window.clearInterval(timer);
|
|
1722
|
+
yieldRoam();
|
|
1723
|
+
};
|
|
1724
|
+
}, [definition.id, def]);
|
|
1542
1725
|
if (def === void 0 || view === void 0) return null;
|
|
1543
1726
|
const mode = view.mode;
|
|
1544
1727
|
const stats = def.stats ?? {};
|
|
1545
1728
|
const shop = def.shop;
|
|
1729
|
+
const menuModes = declaredModes(def);
|
|
1730
|
+
/** Action-button label for one mode (active = the button that leaves it). */
|
|
1731
|
+
const modeLabel = (name, active) => {
|
|
1732
|
+
if (name === "sleep") return tr(active ? "pet.gameplay.wake" : "pet.gameplay.sleep");
|
|
1733
|
+
const declared = def.modes?.[name];
|
|
1734
|
+
return (active ? declared?.activeLabel ?? declared?.label : declared?.label) ?? tr("pet.gameplay." + name);
|
|
1735
|
+
};
|
|
1736
|
+
/** Chip label for the mode the pet is in right now. */
|
|
1737
|
+
const modeChip = (name) => {
|
|
1738
|
+
if (name === "work") return tr("pet.gameplay.working");
|
|
1739
|
+
if (name === "sleep") return tr("pet.gameplay.sleeping");
|
|
1740
|
+
const declared = def.modes?.[name];
|
|
1741
|
+
return declared?.activeLabel ?? declared?.label ?? tr("pet.gameplay." + name);
|
|
1742
|
+
};
|
|
1546
1743
|
const buy = (itemId) => {
|
|
1547
1744
|
api.buy(itemId).then((result) => {
|
|
1548
1745
|
applyResult(result);
|
|
@@ -1600,7 +1797,7 @@ window.__ModuleLoader__.load({
|
|
|
1600
1797
|
}, entry.id)),
|
|
1601
1798
|
mode !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1602
1799
|
className: pet_module_css_default.gameplayModeChip,
|
|
1603
|
-
children:
|
|
1800
|
+
children: modeChip(mode)
|
|
1604
1801
|
}),
|
|
1605
1802
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1606
1803
|
ref: cardRef,
|
|
@@ -1629,12 +1826,12 @@ window.__ModuleLoader__.load({
|
|
|
1629
1826
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1630
1827
|
className: pet_module_css_default.gameplayActions,
|
|
1631
1828
|
children: [
|
|
1632
|
-
|
|
1829
|
+
menuModes.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1633
1830
|
type: "button",
|
|
1634
1831
|
className: pet_module_css_default.action,
|
|
1635
|
-
onClick: () => setMode(mode ===
|
|
1636
|
-
children:
|
|
1637
|
-
}),
|
|
1832
|
+
onClick: () => setMode(mode === name ? null : name),
|
|
1833
|
+
children: modeLabel(name, mode === name)
|
|
1834
|
+
}, name)),
|
|
1638
1835
|
shop !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1639
1836
|
type: "button",
|
|
1640
1837
|
className: pet_module_css_default.action,
|
|
@@ -1799,6 +1996,7 @@ window.__ModuleLoader__.load({
|
|
|
1799
1996
|
onFeedbackDone: props.feedbackDone,
|
|
1800
1997
|
portalTarget: props.portalTarget,
|
|
1801
1998
|
dragDisabled: snapshot.gameplay?.mode === "work",
|
|
1999
|
+
...aux === null ? {} : { bus: aux.bus },
|
|
1802
2000
|
...gameplay === void 0 || aux === null ? {} : {
|
|
1803
2001
|
onGameplayTap: (fx, fy) => aux.bus.tap?.(fx, fy),
|
|
1804
2002
|
onGameplayMenu: () => aux.bus.openCard?.(),
|
|
@@ -2513,9 +2711,9 @@ window.__ModuleLoader__.load({
|
|
|
2513
2711
|
teardown?.();
|
|
2514
2712
|
}
|
|
2515
2713
|
//#endregion
|
|
2516
|
-
//#region \0dsh-css:
|
|
2517
|
-
const css$1 = ".
|
|
2518
|
-
const tagId$1 = "@linxin666/dsh-pet/
|
|
2714
|
+
//#region \0dsh-css:src/client/settings-card.module.css.mjs
|
|
2715
|
+
const css$1 = ".KApx_W_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.KApx_W_card:hover{border-color:var(--dsw-alias-label-dimmed)}.KApx_W_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.KApx_W_header{appearance:none;box-sizing:border-box;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.KApx_W_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.KApx_W_headerStatic{box-sizing:border-box;border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.KApx_W_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.KApx_W_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.KApx_W_description{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}.KApx_W_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.KApx_W_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.KApx_W_chevronOpen{transform:rotate(180deg)}.KApx_W_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.KApx_W_readOnly{color:var(--dsw-alias-label-secondary);margin:12px 0 0;font-size:12px;line-height:1.5}.KApx_W_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.KApx_W_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.KApx_W_failed{min-width:0;color:var(--dsw-alias-state-error-primary,#b42318);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.KApx_W_discard,.KApx_W_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.KApx_W_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.KApx_W_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.KApx_W_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.KApx_W_discard:disabled,.KApx_W_save:disabled{opacity:.4;cursor:default}.KApx_W_discard:focus-visible,.KApx_W_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.KApx_W_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.KApx_W_field+.KApx_W_field{border-top:1px solid var(--dsw-alias-border-l2)}.KApx_W_head{align-items:center;gap:8px;display:flex}.KApx_W_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.KApx_W_badges{align-items:center;gap:8px;display:inline-flex}.KApx_W_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.KApx_W_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.KApx_W_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.KApx_W_reset:disabled{cursor:default}.KApx_W_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.KApx_W_input,.KApx_W_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.KApx_W_input:focus-visible,.KApx_W_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.KApx_W_input:disabled,.KApx_W_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.KApx_W_inputInvalid{border:1px solid var(--dsw-alias-state-error-primary,#b42318);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.KApx_W_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-state-error-primary,#b42318);outline-offset:1px;border-color:var(--dsw-alias-state-error-primary,#b42318)}.KApx_W_selectWrap{position:relative}.KApx_W_selectButton{appearance:none;text-align:left;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;width:100%;display:flex}.KApx_W_selectLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.KApx_W_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.KApx_W_selectChevronOpen{transform:rotate(180deg)}.KApx_W_selectPopup{z-index:40;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-height:240px;box-shadow:0 8px 24px var(--dsw-alias-bg-mask-2);opacity:0;border-radius:8px;flex-direction:column;padding:4px;transition:opacity .1s,transform .1s;display:flex;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;transform:translateY(-4px)}.KApx_W_selectPopupOpen{opacity:1;transform:none}.KApx_W_selectPopupClose{opacity:0;pointer-events:none;transform:translateY(-4px)}.KApx_W_selectOption{color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:6px;flex-shrink:0;padding:6px 10px;font-size:13px;line-height:1.5;overflow:hidden}.KApx_W_selectOption:hover,.KApx_W_selectOptionActive{background:var(--dsw-alias-interactive-bg-hover)}.KApx_W_selectOptionSelected{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);font-weight:500}.KApx_W_invalid{color:var(--dsw-alias-state-error-primary,#b42318);margin:0;font-size:12px;line-height:1.5}.KApx_W_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.KApx_W_card,.KApx_W_header,.KApx_W_chevron,.KApx_W_chevronOpen,.KApx_W_discard,.KApx_W_save,.KApx_W_selectChevron,.KApx_W_selectChevronOpen,.KApx_W_selectPopup{transition:none}}";
|
|
2716
|
+
const tagId$1 = "@linxin666/dsh-pet/src/client/settings-card.module.css";
|
|
2519
2717
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
2520
2718
|
const tag = document.createElement("style");
|
|
2521
2719
|
tag.dataset.plugin = "@linxin666/dsh-pet";
|
|
@@ -2524,45 +2722,45 @@ window.__ModuleLoader__.load({
|
|
|
2524
2722
|
document.head.appendChild(tag);
|
|
2525
2723
|
}
|
|
2526
2724
|
var settings_card_module_css_default = {
|
|
2527
|
-
"badge": "
|
|
2528
|
-
"badges": "
|
|
2529
|
-
"body": "
|
|
2530
|
-
"card": "
|
|
2531
|
-
"cardOpen": "
|
|
2532
|
-
"chevron": "
|
|
2533
|
-
"chevronOpen": "
|
|
2534
|
-
"description": "
|
|
2535
|
-
"discard": "
|
|
2536
|
-
"failed": "
|
|
2537
|
-
"field": "
|
|
2538
|
-
"footer": "
|
|
2539
|
-
"head": "
|
|
2540
|
-
"headText": "
|
|
2541
|
-
"header": "
|
|
2542
|
-
"headerStatic": "
|
|
2543
|
-
"hint": "
|
|
2544
|
-
"input": "
|
|
2545
|
-
"inputInvalid": "
|
|
2546
|
-
"invalid": "
|
|
2547
|
-
"label": "
|
|
2548
|
-
"name": "
|
|
2549
|
-
"notExposed": "
|
|
2550
|
-
"pending": "
|
|
2551
|
-
"readOnly": "
|
|
2552
|
-
"reset": "
|
|
2553
|
-
"save": "
|
|
2554
|
-
"select": "
|
|
2555
|
-
"selectButton": "
|
|
2556
|
-
"selectChevron": "
|
|
2557
|
-
"selectChevronOpen": "
|
|
2558
|
-
"selectLabel": "
|
|
2559
|
-
"selectOption": "
|
|
2560
|
-
"selectOptionActive": "
|
|
2561
|
-
"selectOptionSelected": "
|
|
2562
|
-
"selectPopup": "
|
|
2563
|
-
"selectPopupClose": "
|
|
2564
|
-
"selectPopupOpen": "
|
|
2565
|
-
"selectWrap": "
|
|
2725
|
+
"badge": "KApx_W_badge",
|
|
2726
|
+
"badges": "KApx_W_badges",
|
|
2727
|
+
"body": "KApx_W_body",
|
|
2728
|
+
"card": "KApx_W_card",
|
|
2729
|
+
"cardOpen": "KApx_W_cardOpen",
|
|
2730
|
+
"chevron": "KApx_W_chevron",
|
|
2731
|
+
"chevronOpen": "KApx_W_chevronOpen",
|
|
2732
|
+
"description": "KApx_W_description",
|
|
2733
|
+
"discard": "KApx_W_discard",
|
|
2734
|
+
"failed": "KApx_W_failed",
|
|
2735
|
+
"field": "KApx_W_field",
|
|
2736
|
+
"footer": "KApx_W_footer",
|
|
2737
|
+
"head": "KApx_W_head",
|
|
2738
|
+
"headText": "KApx_W_headText",
|
|
2739
|
+
"header": "KApx_W_header",
|
|
2740
|
+
"headerStatic": "KApx_W_headerStatic",
|
|
2741
|
+
"hint": "KApx_W_hint",
|
|
2742
|
+
"input": "KApx_W_input",
|
|
2743
|
+
"inputInvalid": "KApx_W_inputInvalid",
|
|
2744
|
+
"invalid": "KApx_W_invalid",
|
|
2745
|
+
"label": "KApx_W_label",
|
|
2746
|
+
"name": "KApx_W_name",
|
|
2747
|
+
"notExposed": "KApx_W_notExposed",
|
|
2748
|
+
"pending": "KApx_W_pending",
|
|
2749
|
+
"readOnly": "KApx_W_readOnly",
|
|
2750
|
+
"reset": "KApx_W_reset",
|
|
2751
|
+
"save": "KApx_W_save",
|
|
2752
|
+
"select": "KApx_W_select",
|
|
2753
|
+
"selectButton": "KApx_W_selectButton",
|
|
2754
|
+
"selectChevron": "KApx_W_selectChevron",
|
|
2755
|
+
"selectChevronOpen": "KApx_W_selectChevronOpen",
|
|
2756
|
+
"selectLabel": "KApx_W_selectLabel",
|
|
2757
|
+
"selectOption": "KApx_W_selectOption",
|
|
2758
|
+
"selectOptionActive": "KApx_W_selectOptionActive",
|
|
2759
|
+
"selectOptionSelected": "KApx_W_selectOptionSelected",
|
|
2760
|
+
"selectPopup": "KApx_W_selectPopup",
|
|
2761
|
+
"selectPopupClose": "KApx_W_selectPopupClose",
|
|
2762
|
+
"selectPopupOpen": "KApx_W_selectPopupOpen",
|
|
2763
|
+
"selectWrap": "KApx_W_selectWrap"
|
|
2566
2764
|
};
|
|
2567
2765
|
//#endregion
|
|
2568
2766
|
//#region src/client/PluginSettingsCard.tsx
|
|
@@ -2646,17 +2844,20 @@ window.__ModuleLoader__.load({
|
|
|
2646
2844
|
})
|
|
2647
2845
|
]
|
|
2648
2846
|
});
|
|
2649
|
-
if (!state.exposed
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
className:
|
|
2653
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
2654
|
-
className: settings_card_module_css_default.
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2847
|
+
if (!state.exposed && props.renderChildrenWhenNotExposed !== true) {
|
|
2848
|
+
const showNotice = props.hideNotExposedNotice !== true;
|
|
2849
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
2850
|
+
className: cardClass,
|
|
2851
|
+
children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2852
|
+
className: settings_card_module_css_default.body,
|
|
2853
|
+
children: showNotice ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2854
|
+
className: settings_card_module_css_default.notExposed,
|
|
2855
|
+
role: "status",
|
|
2856
|
+
children: props.t("settings.notExposed")
|
|
2857
|
+
}) : null
|
|
2858
|
+
}) : null]
|
|
2859
|
+
});
|
|
2860
|
+
}
|
|
2660
2861
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
2661
2862
|
className: cardClass,
|
|
2662
2863
|
children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2803,9 +3004,11 @@ window.__ModuleLoader__.load({
|
|
|
2803
3004
|
case " ":
|
|
2804
3005
|
event.preventDefault();
|
|
2805
3006
|
if (!open) openPopup();
|
|
2806
|
-
else if (!closing)
|
|
2807
|
-
|
|
2808
|
-
|
|
3007
|
+
else if (!closing) {
|
|
3008
|
+
if (event.key === "ArrowDown") setActiveIndex((index) => (index + 1) % count);
|
|
3009
|
+
else if (event.key === "ArrowUp") setActiveIndex((index) => (index - 1 + count) % count);
|
|
3010
|
+
else commit(activeIndex);
|
|
3011
|
+
}
|
|
2809
3012
|
break;
|
|
2810
3013
|
case "Escape":
|
|
2811
3014
|
if (open) {
|
|
@@ -2814,9 +3017,7 @@ window.__ModuleLoader__.load({
|
|
|
2814
3017
|
close();
|
|
2815
3018
|
}
|
|
2816
3019
|
break;
|
|
2817
|
-
case "Tab":
|
|
2818
|
-
if (open) close();
|
|
2819
|
-
break;
|
|
3020
|
+
case "Tab": if (open) close();
|
|
2820
3021
|
}
|
|
2821
3022
|
};
|
|
2822
3023
|
(0, react.useEffect)(() => () => {
|
|
@@ -3074,31 +3275,31 @@ window.__ModuleLoader__.load({
|
|
|
3074
3275
|
specs;
|
|
3075
3276
|
staged = /* @__PURE__ */ new Map();
|
|
3076
3277
|
listeners = /* @__PURE__ */ new Set();
|
|
3077
|
-
/** The
|
|
3078
|
-
|
|
3278
|
+
/** The form subscription installed in the constructor; released by dispose(). */
|
|
3279
|
+
disposeForm;
|
|
3079
3280
|
disposed = false;
|
|
3080
3281
|
saving = false;
|
|
3081
3282
|
failed = false;
|
|
3082
3283
|
failedReason;
|
|
3083
|
-
/** @param scope - the bound
|
|
3284
|
+
/** @param scope - the bound configuration form for this card's namespace. */
|
|
3084
3285
|
constructor(scope, specs) {
|
|
3085
3286
|
this.scope = scope;
|
|
3086
3287
|
this.specs = new Map(specs.map((spec) => [spec.field, spec]));
|
|
3087
|
-
this.
|
|
3288
|
+
this.disposeForm = scope.subscribe(() => {
|
|
3088
3289
|
this.publish();
|
|
3089
3290
|
});
|
|
3090
3291
|
}
|
|
3091
3292
|
/**
|
|
3092
|
-
* Release the
|
|
3293
|
+
* Release the form subscription and every bound store listener. The card
|
|
3093
3294
|
* must call this on teardown; later calls are no-ops.
|
|
3094
3295
|
*/
|
|
3095
3296
|
dispose() {
|
|
3096
3297
|
if (this.disposed) return;
|
|
3097
3298
|
this.disposed = true;
|
|
3098
|
-
this.
|
|
3299
|
+
this.disposeForm();
|
|
3099
3300
|
this.listeners.clear();
|
|
3100
3301
|
}
|
|
3101
|
-
/** Publish a projection of this form, rebuilt whenever the
|
|
3302
|
+
/** Publish a projection of this form, rebuilt whenever the form or a draft changes. */
|
|
3102
3303
|
bind(project) {
|
|
3103
3304
|
const store = createSnapshotStore(project());
|
|
3104
3305
|
this.listeners.add(() => {
|
|
@@ -3165,19 +3366,19 @@ window.__ModuleLoader__.load({
|
|
|
3165
3366
|
};
|
|
3166
3367
|
}
|
|
3167
3368
|
/**
|
|
3168
|
-
* Write every staged edit in one atomic
|
|
3369
|
+
* Write every staged edit in one atomic form mutation, then re-seed from
|
|
3169
3370
|
* what the Host accepted.
|
|
3170
3371
|
*
|
|
3171
3372
|
* The whole batch rides one mutate, so cross-field validate hooks
|
|
3172
3373
|
* (baseURL+model) judge it as a unit: the Host either applies every write
|
|
3173
|
-
* or refuses the batch. The
|
|
3174
|
-
*
|
|
3175
|
-
*
|
|
3176
|
-
* settled snapshot back
|
|
3177
|
-
* fails the whole save. A
|
|
3178
|
-
*
|
|
3179
|
-
* message. A save that did not land keeps its drafts, so
|
|
3180
|
-
* correct them instead of retyping.
|
|
3374
|
+
* or refuses the batch. The form contract answers a refusal or a skipped
|
|
3375
|
+
* write with `false` (it recovers with a fresh Host view instead of
|
|
3376
|
+
* throwing), so the outcome is judged twice: the answer itself, and then the
|
|
3377
|
+
* settled snapshot read back one planned write at a time. One missed write
|
|
3378
|
+
* fails the whole save. A transport that rejects instead (the dsh-web bridge
|
|
3379
|
+
* controller on a dead connection) reports through the same failure path
|
|
3380
|
+
* with its rejection message. A save that did not land keeps its drafts, so
|
|
3381
|
+
* the user can correct them instead of retyping.
|
|
3181
3382
|
* @returns settlement after the mutation and the read-back.
|
|
3182
3383
|
*/
|
|
3183
3384
|
async save() {
|
|
@@ -3199,12 +3400,13 @@ window.__ModuleLoader__.load({
|
|
|
3199
3400
|
path: [item.field]
|
|
3200
3401
|
});
|
|
3201
3402
|
let failedReason;
|
|
3403
|
+
let accepted = false;
|
|
3202
3404
|
try {
|
|
3203
|
-
await this.scope.mutate(ops);
|
|
3405
|
+
accepted = await this.scope.mutate(ops);
|
|
3204
3406
|
} catch (error) {
|
|
3205
3407
|
failedReason = error instanceof Error ? error.message : String(error);
|
|
3206
3408
|
}
|
|
3207
|
-
const landed = failedReason === void 0 && valid.every((item) => item.judge());
|
|
3409
|
+
const landed = accepted && failedReason === void 0 && valid.every((item) => item.judge());
|
|
3208
3410
|
for (const [field, before] of pending) if (landed && this.staged.get(field) === before) this.staged.delete(field);
|
|
3209
3411
|
this.saving = false;
|
|
3210
3412
|
this.failed = !landed;
|
|
@@ -3310,9 +3512,9 @@ window.__ModuleLoader__.load({
|
|
|
3310
3512
|
}
|
|
3311
3513
|
};
|
|
3312
3514
|
//#endregion
|
|
3313
|
-
//#region \0dsh-css:
|
|
3314
|
-
const css = ".
|
|
3315
|
-
const tagId = "@linxin666/dsh-pet/
|
|
3515
|
+
//#region \0dsh-css:src/client/settings-section.module.css.mjs
|
|
3516
|
+
const css = ".c5M8OW_sectionList{margin:0;padding:0;list-style:none}.c5M8OW_diagnostics{border:1px dashed var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:8px;margin:8px 0;padding:8px 12px;font-size:12px}.c5M8OW_diagnosticsTitle{color:var(--dsw-alias-label-primary);margin-bottom:4px;font-weight:600;display:block}.c5M8OW_diagnostics ul{margin:0;padding-left:16px}.c5M8OW_diagnostics li[data-level=error]{color:var(--dsw-alias-label-error,#c04848)}";
|
|
3517
|
+
const tagId = "@linxin666/dsh-pet/src/client/settings-section.module.css";
|
|
3316
3518
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
3317
3519
|
const tag = document.createElement("style");
|
|
3318
3520
|
tag.dataset.plugin = "@linxin666/dsh-pet";
|
|
@@ -3321,9 +3523,9 @@ window.__ModuleLoader__.load({
|
|
|
3321
3523
|
document.head.appendChild(tag);
|
|
3322
3524
|
}
|
|
3323
3525
|
var settings_section_module_css_default = {
|
|
3324
|
-
"diagnostics": "
|
|
3325
|
-
"diagnosticsTitle": "
|
|
3326
|
-
"sectionList": "
|
|
3526
|
+
"diagnostics": "c5M8OW_diagnostics",
|
|
3527
|
+
"diagnosticsTitle": "c5M8OW_diagnosticsTitle",
|
|
3528
|
+
"sectionList": "c5M8OW_sectionList"
|
|
3327
3529
|
};
|
|
3328
3530
|
//#endregion
|
|
3329
3531
|
//#region src/client/PetSettingsCard.tsx
|
|
@@ -3339,6 +3541,14 @@ window.__ModuleLoader__.load({
|
|
|
3339
3541
|
if (!response.ok) throw new Error("pet diagnostics failed: " + response.status);
|
|
3340
3542
|
return (await response.json()).diagnostics ?? [];
|
|
3341
3543
|
}
|
|
3544
|
+
/** Read the selection from the same persisted state the pet renders. */
|
|
3545
|
+
async function fetchSelectedPetId() {
|
|
3546
|
+
const response = await fetch("/api/pet/state");
|
|
3547
|
+
if (!response.ok) throw new Error("pet state failed: " + response.status);
|
|
3548
|
+
const body = await response.json();
|
|
3549
|
+
if (typeof body.pet?.id !== "string") throw new Error("pet state has no selected pet");
|
|
3550
|
+
return body.pet.id;
|
|
3551
|
+
}
|
|
3342
3552
|
/** Bridges the 'pet' scope onto the card's staged form. */
|
|
3343
3553
|
var PetSettingsCardController = class {
|
|
3344
3554
|
form;
|
|
@@ -3346,12 +3556,16 @@ window.__ModuleLoader__.load({
|
|
|
3346
3556
|
petChoices = [];
|
|
3347
3557
|
petLabels = /* @__PURE__ */ new Map();
|
|
3348
3558
|
diagnostics = [];
|
|
3559
|
+
selectedPetId;
|
|
3560
|
+
stagedPetId;
|
|
3561
|
+
savingPet = false;
|
|
3562
|
+
petSaveFailed = false;
|
|
3349
3563
|
loaded = false;
|
|
3350
3564
|
attempts = 0;
|
|
3351
3565
|
disposed = false;
|
|
3352
3566
|
/** Pending deferred-load or retry timer; cancelled by dispose(). */
|
|
3353
3567
|
pendingTimer;
|
|
3354
|
-
/** @param scope - the bound
|
|
3568
|
+
/** @param scope - the bound configuration form for the 'pet' entry. */
|
|
3355
3569
|
constructor(scope) {
|
|
3356
3570
|
this.form = new CardForm(scope, [
|
|
3357
3571
|
booleanField("enabled"),
|
|
@@ -3369,6 +3583,7 @@ window.__ModuleLoader__.load({
|
|
|
3369
3583
|
if (this.disposed) return;
|
|
3370
3584
|
this.loadPets();
|
|
3371
3585
|
this.loadDiagnostics();
|
|
3586
|
+
this.loadSelectedPet();
|
|
3372
3587
|
}, 0);
|
|
3373
3588
|
}
|
|
3374
3589
|
/** Fetch registry diagnostics once (soft-fail: an empty list on error). */
|
|
@@ -3401,9 +3616,57 @@ window.__ModuleLoader__.load({
|
|
|
3401
3616
|
}, 3e3);
|
|
3402
3617
|
}
|
|
3403
3618
|
}
|
|
3619
|
+
async loadSelectedPet() {
|
|
3620
|
+
try {
|
|
3621
|
+
const petId = await fetchSelectedPetId();
|
|
3622
|
+
if (this.disposed) return;
|
|
3623
|
+
this.selectedPetId = petId;
|
|
3624
|
+
this.store.set(this.projection());
|
|
3625
|
+
} catch {}
|
|
3626
|
+
}
|
|
3627
|
+
fallback() {
|
|
3628
|
+
const shell = this.form.shell();
|
|
3629
|
+
return shell.available && !shell.exposed && this.selectedPetId !== void 0;
|
|
3630
|
+
}
|
|
3631
|
+
async savePetSelection() {
|
|
3632
|
+
const petId = this.stagedPetId;
|
|
3633
|
+
if (petId === void 0 || this.savingPet || !this.petChoices.includes(petId)) return;
|
|
3634
|
+
this.savingPet = true;
|
|
3635
|
+
this.petSaveFailed = false;
|
|
3636
|
+
this.store.set(this.projection());
|
|
3637
|
+
try {
|
|
3638
|
+
const response = await fetch("/api/pet/set-pet", {
|
|
3639
|
+
method: "POST",
|
|
3640
|
+
headers: { "content-type": "application/json" },
|
|
3641
|
+
body: JSON.stringify({ petId })
|
|
3642
|
+
});
|
|
3643
|
+
const result = await response.json();
|
|
3644
|
+
if (!response.ok || result.ok !== true || result.petId !== petId || await fetchSelectedPetId() !== petId) throw new Error("pet selection was not persisted");
|
|
3645
|
+
this.selectedPetId = petId;
|
|
3646
|
+
if (this.stagedPetId === petId) this.stagedPetId = void 0;
|
|
3647
|
+
} catch {
|
|
3648
|
+
this.petSaveFailed = true;
|
|
3649
|
+
} finally {
|
|
3650
|
+
this.savingPet = false;
|
|
3651
|
+
if (!this.disposed) this.store.set(this.projection());
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3404
3654
|
projection() {
|
|
3655
|
+
const fallback = this.fallback();
|
|
3656
|
+
const shell = this.form.shell();
|
|
3657
|
+
const configuredPet = this.form.field("petId");
|
|
3405
3658
|
return {
|
|
3406
|
-
...
|
|
3659
|
+
...shell,
|
|
3660
|
+
...fallback ? {
|
|
3661
|
+
exposed: true,
|
|
3662
|
+
writable: true,
|
|
3663
|
+
dirty: this.stagedPetId !== void 0 && this.stagedPetId !== this.selectedPetId,
|
|
3664
|
+
invalid: this.stagedPetId !== void 0 && !this.petChoices.includes(this.stagedPetId),
|
|
3665
|
+
saving: this.savingPet,
|
|
3666
|
+
failed: this.petSaveFailed,
|
|
3667
|
+
failedReason: void 0
|
|
3668
|
+
} : {},
|
|
3669
|
+
petSelectionFallback: fallback,
|
|
3407
3670
|
enabled: this.form.field("enabled"),
|
|
3408
3671
|
decorationEnabled: this.form.field("decorationEnabled"),
|
|
3409
3672
|
visible: this.form.field("visible"),
|
|
@@ -3411,7 +3674,14 @@ window.__ModuleLoader__.load({
|
|
|
3411
3674
|
right: this.form.field("right"),
|
|
3412
3675
|
bottom: this.form.field("bottom"),
|
|
3413
3676
|
bubbleScale: this.form.field("bubbleScale"),
|
|
3414
|
-
petId:
|
|
3677
|
+
petId: fallback ? {
|
|
3678
|
+
text: this.stagedPetId ?? this.selectedPetId ?? "",
|
|
3679
|
+
overridden: false,
|
|
3680
|
+
invalid: this.stagedPetId !== void 0 && !this.petChoices.includes(this.stagedPetId)
|
|
3681
|
+
} : configuredPet.text === "" && this.selectedPetId !== void 0 ? {
|
|
3682
|
+
...configuredPet,
|
|
3683
|
+
text: this.selectedPetId
|
|
3684
|
+
} : configuredPet,
|
|
3415
3685
|
petChoices: this.petChoices.map((id) => ({
|
|
3416
3686
|
value: id,
|
|
3417
3687
|
label: this.petLabels.get(id) ?? id
|
|
@@ -3424,9 +3694,33 @@ window.__ModuleLoader__.load({
|
|
|
3424
3694
|
* @returns the card's snapshot and its form actions.
|
|
3425
3695
|
*/
|
|
3426
3696
|
inject() {
|
|
3697
|
+
const actions = this.form.actions();
|
|
3427
3698
|
return {
|
|
3428
3699
|
hooks: { petSettingsCard: this.store },
|
|
3429
|
-
|
|
3700
|
+
edit: (field, value) => {
|
|
3701
|
+
if (!this.fallback()) return actions.edit(field, value);
|
|
3702
|
+
if (field !== "petId") return;
|
|
3703
|
+
this.stagedPetId = value === "" ? void 0 : value;
|
|
3704
|
+
this.petSaveFailed = false;
|
|
3705
|
+
this.store.set(this.projection());
|
|
3706
|
+
},
|
|
3707
|
+
resetField: (field) => {
|
|
3708
|
+
if (!this.fallback()) return actions.resetField(field);
|
|
3709
|
+
if (field !== "petId") return;
|
|
3710
|
+
this.stagedPetId = void 0;
|
|
3711
|
+
this.petSaveFailed = false;
|
|
3712
|
+
this.store.set(this.projection());
|
|
3713
|
+
},
|
|
3714
|
+
save: () => {
|
|
3715
|
+
if (this.fallback()) this.savePetSelection();
|
|
3716
|
+
else actions.save();
|
|
3717
|
+
},
|
|
3718
|
+
discard: () => {
|
|
3719
|
+
if (!this.fallback()) return actions.discard();
|
|
3720
|
+
this.stagedPetId = void 0;
|
|
3721
|
+
this.petSaveFailed = false;
|
|
3722
|
+
this.store.set(this.projection());
|
|
3723
|
+
}
|
|
3430
3724
|
};
|
|
3431
3725
|
}
|
|
3432
3726
|
/**
|
|
@@ -3462,12 +3756,13 @@ window.__ModuleLoader__.load({
|
|
|
3462
3756
|
t,
|
|
3463
3757
|
titleKey: "settings.title",
|
|
3464
3758
|
descriptionKey: "settings.description",
|
|
3759
|
+
descriptionNode: state.petSelectionFallback ? t("settings.petHint") : void 0,
|
|
3465
3760
|
state,
|
|
3466
3761
|
onSave: props.save,
|
|
3467
3762
|
onDiscard: props.discard,
|
|
3468
3763
|
alwaysOpen: true,
|
|
3469
3764
|
children: [
|
|
3470
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
3765
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
3471
3766
|
id: "settings-pet-enabled",
|
|
3472
3767
|
label: t("settings.enabled"),
|
|
3473
3768
|
hint: t("settings.enabledHint"),
|
|
@@ -3483,7 +3778,7 @@ window.__ModuleLoader__.load({
|
|
|
3483
3778
|
props.resetField("enabled");
|
|
3484
3779
|
}
|
|
3485
3780
|
}),
|
|
3486
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
3781
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
3487
3782
|
id: "settings-pet-decoration",
|
|
3488
3783
|
label: t("settings.decoration"),
|
|
3489
3784
|
hint: t("settings.decorationHint"),
|
|
@@ -3525,7 +3820,7 @@ window.__ModuleLoader__.load({
|
|
|
3525
3820
|
children: diagnostic.message
|
|
3526
3821
|
}, index)) })]
|
|
3527
3822
|
}),
|
|
3528
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
3823
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
3529
3824
|
id: "settings-pet-visible",
|
|
3530
3825
|
label: t("settings.visible"),
|
|
3531
3826
|
hint: t("settings.visibleHint"),
|
|
@@ -3541,7 +3836,7 @@ window.__ModuleLoader__.load({
|
|
|
3541
3836
|
props.resetField("visible");
|
|
3542
3837
|
}
|
|
3543
3838
|
}),
|
|
3544
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3839
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3545
3840
|
id: "settings-pet-size",
|
|
3546
3841
|
label: t("settings.size"),
|
|
3547
3842
|
hint: t("settings.sizeHint"),
|
|
@@ -3555,7 +3850,7 @@ window.__ModuleLoader__.load({
|
|
|
3555
3850
|
props.resetField("size");
|
|
3556
3851
|
}
|
|
3557
3852
|
}),
|
|
3558
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3853
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3559
3854
|
id: "settings-pet-right",
|
|
3560
3855
|
label: t("settings.right"),
|
|
3561
3856
|
hint: t("settings.rightHint"),
|
|
@@ -3569,7 +3864,7 @@ window.__ModuleLoader__.load({
|
|
|
3569
3864
|
props.resetField("right");
|
|
3570
3865
|
}
|
|
3571
3866
|
}),
|
|
3572
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3867
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3573
3868
|
id: "settings-pet-bottom",
|
|
3574
3869
|
label: t("settings.bottom"),
|
|
3575
3870
|
hint: t("settings.bottomHint"),
|
|
@@ -3583,7 +3878,7 @@ window.__ModuleLoader__.load({
|
|
|
3583
3878
|
props.resetField("bottom");
|
|
3584
3879
|
}
|
|
3585
3880
|
}),
|
|
3586
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3881
|
+
state.petSelectionFallback ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
3587
3882
|
id: "settings-pet-bubble-scale",
|
|
3588
3883
|
label: t("settings.bubbleScale"),
|
|
3589
3884
|
hint: t("settings.bubbleScaleHint"),
|
|
@@ -3806,6 +4101,21 @@ window.__ModuleLoader__.load({
|
|
|
3806
4101
|
return text;
|
|
3807
4102
|
}
|
|
3808
4103
|
//#endregion
|
|
4104
|
+
//#region src/client/main-session.ts
|
|
4105
|
+
/**
|
|
4106
|
+
* Resolve the Session the main view currently shows.
|
|
4107
|
+
*
|
|
4108
|
+
* Reads the catalog's rows rather than a per-id retain-info source: ownership
|
|
4109
|
+
* counts ride the list snapshot, so this neither allocates observers nor opens
|
|
4110
|
+
* history, and a subscription to the list still fires when the selection moves.
|
|
4111
|
+
* @param byId - the session catalog's rows (`SessionListState.byId`), when available.
|
|
4112
|
+
* @returns the main-view session id, or undefined when the main view shows none.
|
|
4113
|
+
*/
|
|
4114
|
+
function mainViewSessionId(byId) {
|
|
4115
|
+
if (byId === void 0 || byId === null) return void 0;
|
|
4116
|
+
for (const row of Object.values(byId)) if (row !== void 0 && (row.retainedBy?.mainView ?? 0) > 0) return row.id;
|
|
4117
|
+
}
|
|
4118
|
+
//#endregion
|
|
3809
4119
|
//#region src/client/telemetry.ts
|
|
3810
4120
|
const VISITOR_KEY = "dsh-web-ui-telemetry-visitor";
|
|
3811
4121
|
const DAY_KEY_PREFIX = "dsh-web-ui-telemetry-day:";
|
|
@@ -3813,7 +4123,7 @@ window.__ModuleLoader__.load({
|
|
|
3813
4123
|
/** The building package's version, when the bundle carries it. */
|
|
3814
4124
|
function bakedVersion() {
|
|
3815
4125
|
try {
|
|
3816
|
-
return "0.3.
|
|
4126
|
+
return "0.3.25";
|
|
3817
4127
|
} catch {
|
|
3818
4128
|
return;
|
|
3819
4129
|
}
|
|
@@ -3904,17 +4214,38 @@ window.__ModuleLoader__.load({
|
|
|
3904
4214
|
};
|
|
3905
4215
|
/** Poll interval for the host snapshot. */
|
|
3906
4216
|
const POLL_MS = 2e3;
|
|
3907
|
-
/** Settings namespace the pet settings
|
|
4217
|
+
/** Settings namespace of the pet's settings page. It is the profile entry id the Host serves a form for. */
|
|
3908
4218
|
const PET_SETTINGS_NS = "pet";
|
|
3909
4219
|
/** Required services (sessions powers bubble-to-session navigation). */
|
|
3910
4220
|
const inject = [
|
|
3911
4221
|
"slots",
|
|
3912
4222
|
"locale",
|
|
3913
4223
|
"connection",
|
|
3914
|
-
"
|
|
4224
|
+
"configForms",
|
|
3915
4225
|
"remote",
|
|
3916
|
-
"sessions"
|
|
4226
|
+
"sessions",
|
|
4227
|
+
"uiWorkspace"
|
|
3917
4228
|
];
|
|
4229
|
+
const PET_ENTRY_IDS = [
|
|
4230
|
+
"web-ui-pet",
|
|
4231
|
+
"ui-pet",
|
|
4232
|
+
PET_SETTINGS_NS
|
|
4233
|
+
];
|
|
4234
|
+
function servedEntryId(forms) {
|
|
4235
|
+
let served;
|
|
4236
|
+
try {
|
|
4237
|
+
served = forms.describe().getSnapshot().view?.namespaces.map((view) => view.ns);
|
|
4238
|
+
} catch {
|
|
4239
|
+
served = void 0;
|
|
4240
|
+
}
|
|
4241
|
+
if (!served || served.length === 0) return PET_SETTINGS_NS;
|
|
4242
|
+
return PET_ENTRY_IDS.find((id) => served.includes(id)) ?? PET_SETTINGS_NS;
|
|
4243
|
+
}
|
|
4244
|
+
function petSettingsForm(ctx) {
|
|
4245
|
+
const binder = ctx.get("webUiSettings");
|
|
4246
|
+
if (binder !== void 0 && typeof binder.bind === "function") return binder.bind({ namespace: PET_SETTINGS_NS });
|
|
4247
|
+
return ctx.configForms.get(servedEntryId(ctx.configForms));
|
|
4248
|
+
}
|
|
3918
4249
|
/**
|
|
3919
4250
|
* Client plugin body: register dictionaries, mount the global pet entry and
|
|
3920
4251
|
* poll loop while the plugin is enabled, and seat the settings card as a
|
|
@@ -3946,12 +4277,12 @@ window.__ModuleLoader__.load({
|
|
|
3946
4277
|
}, "pet: dictionaries");
|
|
3947
4278
|
defaultPetRendererRegistry.register(live2dRenderer);
|
|
3948
4279
|
defaultPetRendererRegistry.register(frames2dRenderer);
|
|
3949
|
-
const
|
|
4280
|
+
const settingsForm = petSettingsForm(ctx);
|
|
3950
4281
|
const enabled = () => {
|
|
3951
|
-
const snapshot =
|
|
4282
|
+
const snapshot = settingsForm.getSnapshot();
|
|
3952
4283
|
return snapshot.status === "ready" ? snapshot.value?.enabled ?? true : snapshot.status === "unavailable";
|
|
3953
4284
|
};
|
|
3954
|
-
const petSettings = new PetSettingsCardController(
|
|
4285
|
+
const petSettings = new PetSettingsCardController(settingsForm);
|
|
3955
4286
|
ctx.slots.inject("settings.section", () => {
|
|
3956
4287
|
try {
|
|
3957
4288
|
const unregister = ctx.slots.register({
|
|
@@ -3989,10 +4320,7 @@ window.__ModuleLoader__.load({
|
|
|
3989
4320
|
const setState = petStore.actions.setState;
|
|
3990
4321
|
const setFeedback = petStore.actions.setFeedback;
|
|
3991
4322
|
const sessions = ctx.sessions;
|
|
3992
|
-
const currentSessionId = () =>
|
|
3993
|
-
const current = sessions.list.getSnapshot().current;
|
|
3994
|
-
return current === void 0 ? void 0 : String(current);
|
|
3995
|
-
};
|
|
4323
|
+
const currentSessionId = () => mainViewSessionId(sessions.list.getSnapshot().byId);
|
|
3996
4324
|
let petsLoaded = false;
|
|
3997
4325
|
let stateSeq = 0;
|
|
3998
4326
|
const pollNow = () => {
|
|
@@ -4041,7 +4369,7 @@ window.__ModuleLoader__.load({
|
|
|
4041
4369
|
}, "pet: current-session watch");
|
|
4042
4370
|
const openSession = (sessionId) => {
|
|
4043
4371
|
if (sessions.list.getSnapshot().byId[sessionId] === void 0) return;
|
|
4044
|
-
|
|
4372
|
+
ctx.uiWorkspace.openSession(sessionId);
|
|
4045
4373
|
};
|
|
4046
4374
|
const injected = () => ({
|
|
4047
4375
|
store: petStore,
|
|
@@ -4144,7 +4472,7 @@ window.__ModuleLoader__.load({
|
|
|
4144
4472
|
disposeUi = void 0;
|
|
4145
4473
|
}
|
|
4146
4474
|
};
|
|
4147
|
-
const unsubscribeSettings =
|
|
4475
|
+
const unsubscribeSettings = settingsForm.subscribe(syncUi);
|
|
4148
4476
|
ctx.effect(() => () => {
|
|
4149
4477
|
unsubscribeSettings();
|
|
4150
4478
|
killUi();
|