feat(v2): chat command history + smart auto-scroll
Command history: - Up/Down arrow keys browse sent command history (like bash/console) - 50 commands stored per character in localStorage - Persists across page reloads and browser sessions - Current input preserved when browsing (restored on Down past end) - Duplicates kept (matches user preference) Smart auto-scroll: - New messages only auto-scroll if user is already at the bottom - If user has scrolled up to read history, it stays put - Sending a message snaps back to bottom - 30px threshold for "at bottom" detection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8a2d0e1a72
commit
0b64c6ccff
23 changed files with 214 additions and 29 deletions
|
|
@ -1,6 +1,5 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
||||
import { DraggableWindow } from './DraggableWindow';
|
||||
import { wsUrl } from '../../api/client';
|
||||
|
||||
interface ChatMsg {
|
||||
text: string;
|
||||
|
|
@ -14,6 +13,22 @@ const CHAT_COLORS: Record<number, string> = {
|
|||
21:'#FF8888', 22:'#FFAA66',
|
||||
};
|
||||
|
||||
const MAX_HISTORY = 50;
|
||||
const HISTORY_KEY = (name: string) => `mo-chat-history-${name}`;
|
||||
|
||||
function loadHistory(charName: string): string[] {
|
||||
try {
|
||||
const raw = localStorage.getItem(HISTORY_KEY(charName));
|
||||
return raw ? JSON.parse(raw) : [];
|
||||
} catch { return []; }
|
||||
}
|
||||
|
||||
function saveHistory(charName: string, history: string[]) {
|
||||
try {
|
||||
localStorage.setItem(HISTORY_KEY(charName), JSON.stringify(history.slice(-MAX_HISTORY)));
|
||||
} catch { /* quota exceeded — ignore */ }
|
||||
}
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
charName: string;
|
||||
|
|
@ -25,23 +40,78 @@ interface Props {
|
|||
export const ChatWindow: React.FC<Props> = ({ id, charName, zIndex, messages, socket }) => {
|
||||
const msgsRef = useRef<HTMLDivElement>(null);
|
||||
const [input, setInput] = useState('');
|
||||
const historyRef = useRef<string[]>(loadHistory(charName));
|
||||
const historyIndexRef = useRef(-1); // -1 = not browsing history
|
||||
const savedInputRef = useRef(''); // preserves current input when browsing history
|
||||
const userScrolledRef = useRef(false);
|
||||
|
||||
// Auto-scroll only if user is already at the bottom
|
||||
useEffect(() => {
|
||||
if (msgsRef.current) msgsRef.current.scrollTop = msgsRef.current.scrollHeight;
|
||||
const el = msgsRef.current;
|
||||
if (!el) return;
|
||||
if (!userScrolledRef.current) {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
}, [messages.length]);
|
||||
|
||||
const handleSend = (e: React.FormEvent) => {
|
||||
// Track whether user has scrolled up from bottom
|
||||
const handleScroll = useCallback(() => {
|
||||
const el = msgsRef.current;
|
||||
if (!el) return;
|
||||
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 30;
|
||||
userScrolledRef.current = !atBottom;
|
||||
}, []);
|
||||
|
||||
const handleSend = useCallback((e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const text = input.trim();
|
||||
if (!text || !socket || socket.readyState !== WebSocket.OPEN) return;
|
||||
// v1 envelope: { player_name, command }
|
||||
socket.send(JSON.stringify({ player_name: charName, command: text }));
|
||||
|
||||
// Add to history
|
||||
historyRef.current.push(text);
|
||||
if (historyRef.current.length > MAX_HISTORY) historyRef.current.shift();
|
||||
saveHistory(charName, historyRef.current);
|
||||
historyIndexRef.current = -1;
|
||||
savedInputRef.current = '';
|
||||
|
||||
setInput('');
|
||||
};
|
||||
|
||||
// Snap back to bottom on send
|
||||
userScrolledRef.current = false;
|
||||
}, [input, socket, charName]);
|
||||
|
||||
const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const history = historyRef.current;
|
||||
if (history.length === 0) return;
|
||||
|
||||
if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
if (historyIndexRef.current === -1) {
|
||||
// Starting to browse — save current input
|
||||
savedInputRef.current = input;
|
||||
historyIndexRef.current = history.length - 1;
|
||||
} else if (historyIndexRef.current > 0) {
|
||||
historyIndexRef.current--;
|
||||
}
|
||||
setInput(history[historyIndexRef.current]);
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
if (historyIndexRef.current === -1) return; // not browsing
|
||||
if (historyIndexRef.current < history.length - 1) {
|
||||
historyIndexRef.current++;
|
||||
setInput(history[historyIndexRef.current]);
|
||||
} else {
|
||||
// Past the end — restore saved input
|
||||
historyIndexRef.current = -1;
|
||||
setInput(savedInputRef.current);
|
||||
}
|
||||
}
|
||||
}, [input]);
|
||||
|
||||
return (
|
||||
<DraggableWindow id={id} title={`Chat: ${charName}`} zIndex={zIndex} width={600} height={300}>
|
||||
<div className="ml-chat-messages" ref={msgsRef}>
|
||||
<div className="ml-chat-messages" ref={msgsRef} onScroll={handleScroll}>
|
||||
{messages.map((m, i) => (
|
||||
<div key={i} className="ml-chat-line" style={{ color: CHAT_COLORS[m.color ?? 2] ?? '#ddd' }}>
|
||||
{m.text}
|
||||
|
|
@ -49,7 +119,8 @@ export const ChatWindow: React.FC<Props> = ({ id, charName, zIndex, messages, so
|
|||
))}
|
||||
</div>
|
||||
<form className="ml-chat-form" onSubmit={handleSend}>
|
||||
<input className="ml-chat-input" value={input} onChange={e => setInput(e.target.value)} placeholder="Enter chat..." />
|
||||
<input className="ml-chat-input" value={input} onChange={e => setInput(e.target.value)}
|
||||
onKeyDown={handleKeyDown} placeholder="Enter chat..." />
|
||||
</form>
|
||||
</DraggableWindow>
|
||||
);
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
import{u as c,j as r,D as d}from"./index-BNR09N5o.js";import"./react-DlyoauG8.js";const p=({id:n,zIndex:i,characters:a})=>{const{openWindow:s}=c(),e=Array.from(a.keys()).sort();return r.jsx(d,{id:n,title:"Combat Stats — Select Character",zIndex:i,width:300,height:400,children:r.jsx("div",{style:{flex:1,overflowY:"auto",padding:6},children:e.length===0?r.jsx("div",{style:{padding:12,color:"#666",textAlign:"center",fontSize:"0.8rem"},children:"No characters online"}):e.map(o=>r.jsx("div",{style:{padding:"5px 8px",cursor:"pointer",borderBottom:"1px solid #222",color:"#ccc",fontSize:"0.82rem"},onMouseEnter:t=>t.currentTarget.style.background="#2a2a2a",onMouseLeave:t=>t.currentTarget.style.background="",onClick:()=>s(`combat-${o}`,`Combat: ${o}`,o),children:o},o))})})};export{p as CombatPickerWindow};
|
||||
import{u as c,j as r,D as d}from"./index-BZJ3WwmC.js";import"./react-DlyoauG8.js";const p=({id:n,zIndex:i,characters:a})=>{const{openWindow:s}=c(),e=Array.from(a.keys()).sort();return r.jsx(d,{id:n,title:"Combat Stats — Select Character",zIndex:i,width:300,height:400,children:r.jsx("div",{style:{flex:1,overflowY:"auto",padding:6},children:e.length===0?r.jsx("div",{style:{padding:12,color:"#666",textAlign:"center",fontSize:"0.8rem"},children:"No characters online"}):e.map(o=>r.jsx("div",{style:{padding:"5px 8px",cursor:"pointer",borderBottom:"1px solid #222",color:"#ccc",fontSize:"0.82rem"},onMouseEnter:t=>t.currentTarget.style.background="#2a2a2a",onMouseLeave:t=>t.currentTarget.style.background="",onClick:()=>s(`combat-${o}`,`Combat: ${o}`,o),children:o},o))})})};export{p as CombatPickerWindow};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
import{r as o,j as t,D as d}from"./index-BNR09N5o.js";import"./react-DlyoauG8.js";const c=[{title:"Kills per Hour",id:1},{title:"Memory (MB)",id:2},{title:"CPU (%)",id:3},{title:"Mem Handles",id:4}],m=[{label:"1H",value:"now-1h"},{label:"6H",value:"now-6h"},{label:"24H",value:"now-24h"},{label:"7D",value:"now-7d"}],v=({id:s,charName:a,zIndex:i})=>{const[l,r]=o.useState("now-24h"),n=e=>`/grafana/d-solo/dereth-tracker/dereth-tracker-dashboard?panelId=${e}&var-character=${encodeURIComponent(a)}&from=${l}&to=now&theme=light`;return t.jsxs(d,{id:s,title:`Stats: ${a}`,zIndex:i,width:750,height:480,children:[t.jsx("div",{className:"ml-stats-controls",children:m.map(e=>t.jsx("button",{className:`ml-stats-range-btn ${l===e.value?"active":""}`,onClick:()=>r(e.value),children:e.label},e.value))}),t.jsx("div",{className:"ml-stats-grid",children:c.map(e=>t.jsx("div",{className:"ml-stats-panel",children:t.jsx("iframe",{src:n(e.id),width:"100%",height:"100%",frameBorder:"0",title:e.title})},e.id))})]})};export{v as StatsWindow};
|
||||
import{r as o,j as t,D as d}from"./index-BZJ3WwmC.js";import"./react-DlyoauG8.js";const c=[{title:"Kills per Hour",id:1},{title:"Memory (MB)",id:2},{title:"CPU (%)",id:3},{title:"Mem Handles",id:4}],m=[{label:"1H",value:"now-1h"},{label:"6H",value:"now-6h"},{label:"24H",value:"now-24h"},{label:"7D",value:"now-7d"}],v=({id:s,charName:a,zIndex:i})=>{const[l,r]=o.useState("now-24h"),n=e=>`/grafana/d-solo/dereth-tracker/dereth-tracker-dashboard?panelId=${e}&var-character=${encodeURIComponent(a)}&from=${l}&to=now&theme=light`;return t.jsxs(d,{id:s,title:`Stats: ${a}`,zIndex:i,width:750,height:480,children:[t.jsx("div",{className:"ml-stats-controls",children:m.map(e=>t.jsx("button",{className:`ml-stats-range-btn ${l===e.value?"active":""}`,onClick:()=>r(e.value),children:e.label},e.value))}),t.jsx("div",{className:"ml-stats-grid",children:c.map(e=>t.jsx("div",{className:"ml-stats-panel",children:t.jsx("iframe",{src:n(e.id),width:"100%",height:"100%",frameBorder:"0",title:e.title})},e.id))})]})};export{v as StatsWindow};
|
||||
|
|
@ -1 +1 @@
|
|||
import{r as n,j as t,D as x,a as m}from"./index-BNR09N5o.js";import"./react-DlyoauG8.js";const v=({id:o,zIndex:c})=>{const[a,d]=n.useState([]);n.useEffect(()=>{const e=async()=>{try{const s=await m("/vital-sharing/peers");d(s.peers??[])}catch{}};e();const l=setInterval(e,5e3);return()=>clearInterval(l)},[]);const h=(e,l)=>l>0?Math.min(100,e/l*100):0;return t.jsx(x,{id:o,title:"Vital Sharing Network",zIndex:c,width:520,height:450,children:t.jsx("div",{style:{flex:1,overflowY:"auto",padding:6,fontSize:"0.75rem"},children:a.length===0?t.jsx("div",{style:{padding:16,color:"#666",textAlign:"center"},children:"No vital-sharing peers connected"}):a.map(e=>{var l,s,r;return t.jsxs("div",{style:{padding:"6px 8px",marginBottom:4,background:"#1f1f1f",borderRadius:3,border:"1px solid #333"},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:3},children:[t.jsx("span",{style:{color:e.plugin_connected?"#4c4":"#a33",fontSize:"0.8rem"},children:"●"}),t.jsx("strong",{style:{flex:1},children:e.character_name}),e.subscribed&&t.jsx("span",{style:{color:"#6bf",fontSize:"0.65rem"},children:"[subscribed]"})]}),t.jsxs("div",{style:{color:"#666",fontSize:"0.68rem",marginBottom:3},children:["tags: ",((l=e.tags)==null?void 0:l.join(", "))||"none"]}),e.vitals&&e.vitals.max_health>0&&t.jsx("div",{style:{display:"flex",flexDirection:"column",gap:2},children:[{label:"HP",cur:e.vitals.current_health,max:e.vitals.max_health,bg:"#330000",fill:"#c44"},{label:"STA",cur:e.vitals.current_stamina,max:e.vitals.max_stamina,bg:"#331a00",fill:"#ca0"},{label:"MANA",cur:e.vitals.current_mana,max:e.vitals.max_mana,bg:"#001433",fill:"#48f"}].map(i=>t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[t.jsx("span",{style:{width:32,color:"#888",fontSize:"0.65rem"},children:i.label}),t.jsx("div",{style:{flex:1,height:6,background:i.bg,borderRadius:3,overflow:"hidden"},children:t.jsx("div",{style:{width:`${h(i.cur,i.max)}%`,height:"100%",background:i.fill,borderRadius:3}})}),t.jsxs("span",{style:{width:60,textAlign:"right",fontSize:"0.65rem",color:"#888"},children:[i.cur,"/",i.max]})]},i.label))}),e.position&&t.jsxs("div",{style:{color:"#555",fontSize:"0.65rem",marginTop:2},children:[(s=e.position.ns)==null?void 0:s.toFixed(1),"N, ",(r=e.position.ew)==null?void 0:r.toFixed(1),"E"]})]},e.character_name)})})})};export{v as VitalSharingWindow};
|
||||
import{r as n,j as t,D as x,a as m}from"./index-BZJ3WwmC.js";import"./react-DlyoauG8.js";const v=({id:o,zIndex:c})=>{const[a,d]=n.useState([]);n.useEffect(()=>{const e=async()=>{try{const s=await m("/vital-sharing/peers");d(s.peers??[])}catch{}};e();const l=setInterval(e,5e3);return()=>clearInterval(l)},[]);const h=(e,l)=>l>0?Math.min(100,e/l*100):0;return t.jsx(x,{id:o,title:"Vital Sharing Network",zIndex:c,width:520,height:450,children:t.jsx("div",{style:{flex:1,overflowY:"auto",padding:6,fontSize:"0.75rem"},children:a.length===0?t.jsx("div",{style:{padding:16,color:"#666",textAlign:"center"},children:"No vital-sharing peers connected"}):a.map(e=>{var l,s,r;return t.jsxs("div",{style:{padding:"6px 8px",marginBottom:4,background:"#1f1f1f",borderRadius:3,border:"1px solid #333"},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:3},children:[t.jsx("span",{style:{color:e.plugin_connected?"#4c4":"#a33",fontSize:"0.8rem"},children:"●"}),t.jsx("strong",{style:{flex:1},children:e.character_name}),e.subscribed&&t.jsx("span",{style:{color:"#6bf",fontSize:"0.65rem"},children:"[subscribed]"})]}),t.jsxs("div",{style:{color:"#666",fontSize:"0.68rem",marginBottom:3},children:["tags: ",((l=e.tags)==null?void 0:l.join(", "))||"none"]}),e.vitals&&e.vitals.max_health>0&&t.jsx("div",{style:{display:"flex",flexDirection:"column",gap:2},children:[{label:"HP",cur:e.vitals.current_health,max:e.vitals.max_health,bg:"#330000",fill:"#c44"},{label:"STA",cur:e.vitals.current_stamina,max:e.vitals.max_stamina,bg:"#331a00",fill:"#ca0"},{label:"MANA",cur:e.vitals.current_mana,max:e.vitals.max_mana,bg:"#001433",fill:"#48f"}].map(i=>t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[t.jsx("span",{style:{width:32,color:"#888",fontSize:"0.65rem"},children:i.label}),t.jsx("div",{style:{flex:1,height:6,background:i.bg,borderRadius:3,overflow:"hidden"},children:t.jsx("div",{style:{width:`${h(i.cur,i.max)}%`,height:"100%",background:i.fill,borderRadius:3}})}),t.jsxs("span",{style:{width:60,textAlign:"right",fontSize:"0.65rem",color:"#888"},children:[i.cur,"/",i.max]})]},i.label))}),e.position&&t.jsxs("div",{style:{color:"#555",fontSize:"0.65rem",marginTop:2},children:[(s=e.position.ns)==null?void 0:s.toFixed(1),"N, ",(r=e.position.ew)==null?void 0:r.toFixed(1),"E"]})]},e.character_name)})})})};export{v as VitalSharingWindow};
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -8,7 +8,7 @@
|
|||
<link rel="preload" as="image" href="/dereth.png" />
|
||||
<link rel="preload" as="image" href="/icons/0600127E.png" />
|
||||
<link rel="preload" as="fetch" href="/dungeon_tiles.json" crossorigin="anonymous" />
|
||||
<script type="module" crossorigin src="/assets/index-BNR09N5o.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BZJ3WwmC.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/react-DlyoauG8.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DODaoLcJ.css">
|
||||
</head>
|
||||
|
|
|
|||
1
static/v2/assets/CharacterWindow-CiLMD28w.js
Normal file
1
static/v2/assets/CharacterWindow-CiLMD28w.js
Normal file
File diff suppressed because one or more lines are too long
1
static/v2/assets/CombatPickerWindow-Bmi4B-3k.js
Normal file
1
static/v2/assets/CombatPickerWindow-Bmi4B-3k.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{u as c,j as r,D as d}from"./index-BZJ3WwmC.js";import"./react-DlyoauG8.js";const p=({id:n,zIndex:i,characters:a})=>{const{openWindow:s}=c(),e=Array.from(a.keys()).sort();return r.jsx(d,{id:n,title:"Combat Stats — Select Character",zIndex:i,width:300,height:400,children:r.jsx("div",{style:{flex:1,overflowY:"auto",padding:6},children:e.length===0?r.jsx("div",{style:{padding:12,color:"#666",textAlign:"center",fontSize:"0.8rem"},children:"No characters online"}):e.map(o=>r.jsx("div",{style:{padding:"5px 8px",cursor:"pointer",borderBottom:"1px solid #222",color:"#ccc",fontSize:"0.82rem"},onMouseEnter:t=>t.currentTarget.style.background="#2a2a2a",onMouseLeave:t=>t.currentTarget.style.background="",onClick:()=>s(`combat-${o}`,`Combat: ${o}`,o),children:o},o))})})};export{p as CombatPickerWindow};
|
||||
1
static/v2/assets/CombatStatsWindow-D6fqr6jG.js
Normal file
1
static/v2/assets/CombatStatsWindow-D6fqr6jG.js
Normal file
File diff suppressed because one or more lines are too long
72
static/v2/assets/DashboardView-BMWyZp8i.js
Normal file
72
static/v2/assets/DashboardView-BMWyZp8i.js
Normal file
File diff suppressed because one or more lines are too long
1
static/v2/assets/InventoryWindow-YrfX2_z_.js
Normal file
1
static/v2/assets/InventoryWindow-YrfX2_z_.js
Normal file
File diff suppressed because one or more lines are too long
1
static/v2/assets/IssuesWindow-BEI81Xoa.js
Normal file
1
static/v2/assets/IssuesWindow-BEI81Xoa.js
Normal file
File diff suppressed because one or more lines are too long
1
static/v2/assets/RadarWindow-BPc2UYRl.js
Normal file
1
static/v2/assets/RadarWindow-BPc2UYRl.js
Normal file
File diff suppressed because one or more lines are too long
1
static/v2/assets/StatsWindow-BAJauTIA.js
Normal file
1
static/v2/assets/StatsWindow-BAJauTIA.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{r as o,j as t,D as d}from"./index-BZJ3WwmC.js";import"./react-DlyoauG8.js";const c=[{title:"Kills per Hour",id:1},{title:"Memory (MB)",id:2},{title:"CPU (%)",id:3},{title:"Mem Handles",id:4}],m=[{label:"1H",value:"now-1h"},{label:"6H",value:"now-6h"},{label:"24H",value:"now-24h"},{label:"7D",value:"now-7d"}],v=({id:s,charName:a,zIndex:i})=>{const[l,r]=o.useState("now-24h"),n=e=>`/grafana/d-solo/dereth-tracker/dereth-tracker-dashboard?panelId=${e}&var-character=${encodeURIComponent(a)}&from=${l}&to=now&theme=light`;return t.jsxs(d,{id:s,title:`Stats: ${a}`,zIndex:i,width:750,height:480,children:[t.jsx("div",{className:"ml-stats-controls",children:m.map(e=>t.jsx("button",{className:`ml-stats-range-btn ${l===e.value?"active":""}`,onClick:()=>r(e.value),children:e.label},e.value))}),t.jsx("div",{className:"ml-stats-grid",children:c.map(e=>t.jsx("div",{className:"ml-stats-panel",children:t.jsx("iframe",{src:n(e.id),width:"100%",height:"100%",frameBorder:"0",title:e.title})},e.id))})]})};export{v as StatsWindow};
|
||||
1
static/v2/assets/VitalSharingWindow-elpXhvta.js
Normal file
1
static/v2/assets/VitalSharingWindow-elpXhvta.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{r as n,j as t,D as x,a as m}from"./index-BZJ3WwmC.js";import"./react-DlyoauG8.js";const v=({id:o,zIndex:c})=>{const[a,d]=n.useState([]);n.useEffect(()=>{const e=async()=>{try{const s=await m("/vital-sharing/peers");d(s.peers??[])}catch{}};e();const l=setInterval(e,5e3);return()=>clearInterval(l)},[]);const h=(e,l)=>l>0?Math.min(100,e/l*100):0;return t.jsx(x,{id:o,title:"Vital Sharing Network",zIndex:c,width:520,height:450,children:t.jsx("div",{style:{flex:1,overflowY:"auto",padding:6,fontSize:"0.75rem"},children:a.length===0?t.jsx("div",{style:{padding:16,color:"#666",textAlign:"center"},children:"No vital-sharing peers connected"}):a.map(e=>{var l,s,r;return t.jsxs("div",{style:{padding:"6px 8px",marginBottom:4,background:"#1f1f1f",borderRadius:3,border:"1px solid #333"},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:3},children:[t.jsx("span",{style:{color:e.plugin_connected?"#4c4":"#a33",fontSize:"0.8rem"},children:"●"}),t.jsx("strong",{style:{flex:1},children:e.character_name}),e.subscribed&&t.jsx("span",{style:{color:"#6bf",fontSize:"0.65rem"},children:"[subscribed]"})]}),t.jsxs("div",{style:{color:"#666",fontSize:"0.68rem",marginBottom:3},children:["tags: ",((l=e.tags)==null?void 0:l.join(", "))||"none"]}),e.vitals&&e.vitals.max_health>0&&t.jsx("div",{style:{display:"flex",flexDirection:"column",gap:2},children:[{label:"HP",cur:e.vitals.current_health,max:e.vitals.max_health,bg:"#330000",fill:"#c44"},{label:"STA",cur:e.vitals.current_stamina,max:e.vitals.max_stamina,bg:"#331a00",fill:"#ca0"},{label:"MANA",cur:e.vitals.current_mana,max:e.vitals.max_mana,bg:"#001433",fill:"#48f"}].map(i=>t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[t.jsx("span",{style:{width:32,color:"#888",fontSize:"0.65rem"},children:i.label}),t.jsx("div",{style:{flex:1,height:6,background:i.bg,borderRadius:3,overflow:"hidden"},children:t.jsx("div",{style:{width:`${h(i.cur,i.max)}%`,height:"100%",background:i.fill,borderRadius:3}})}),t.jsxs("span",{style:{width:60,textAlign:"right",fontSize:"0.65rem",color:"#888"},children:[i.cur,"/",i.max]})]},i.label))}),e.position&&t.jsxs("div",{style:{color:"#555",fontSize:"0.65rem",marginTop:2},children:[(s=e.position.ns)==null?void 0:s.toFixed(1),"N, ",(r=e.position.ew)==null?void 0:r.toFixed(1),"E"]})]},e.character_name)})})})};export{v as VitalSharingWindow};
|
||||
34
static/v2/assets/index-BZJ3WwmC.js
Normal file
34
static/v2/assets/index-BZJ3WwmC.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -8,7 +8,7 @@
|
|||
<link rel="preload" as="image" href="/dereth.png" />
|
||||
<link rel="preload" as="image" href="/icons/0600127E.png" />
|
||||
<link rel="preload" as="fetch" href="/dungeon_tiles.json" crossorigin="anonymous" />
|
||||
<script type="module" crossorigin src="/assets/index-BNR09N5o.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BZJ3WwmC.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/react-DlyoauG8.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DODaoLcJ.css">
|
||||
</head>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue