powergrid-viewer 2.1.0 → 2.1.2
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/package.json
CHANGED
package/src/components/Game.vue
CHANGED
|
@@ -32,6 +32,7 @@ export default class InlineLog extends Vue {
|
|
|
32
32
|
@Prop({ default: () => [] }) entries!: string[];
|
|
33
33
|
@Prop({ default: '' }) mapName!: string;
|
|
34
34
|
follow = true;
|
|
35
|
+
private feedObserver?: ResizeObserver;
|
|
35
36
|
get illustratedEntries() {
|
|
36
37
|
return this.entries.map((entry) => {
|
|
37
38
|
const parts: { html?: string; plant?: PowerPlant }[] = [];
|
|
@@ -54,8 +55,15 @@ export default class InlineLog extends Vue {
|
|
|
54
55
|
} cities`;
|
|
55
56
|
}
|
|
56
57
|
mounted() {
|
|
58
|
+
this.feedObserver = new ResizeObserver(() => {
|
|
59
|
+
if (this.follow) this.scrollToLatest();
|
|
60
|
+
});
|
|
61
|
+
this.feedObserver.observe(this.$refs.feed as HTMLElement);
|
|
57
62
|
this.scrollToLatest();
|
|
58
63
|
}
|
|
64
|
+
beforeDestroy() {
|
|
65
|
+
this.feedObserver?.disconnect();
|
|
66
|
+
}
|
|
59
67
|
@Watch('entries') changed() {
|
|
60
68
|
if (this.follow) {
|
|
61
69
|
this.$nextTick(this.scrollToLatest);
|
|
@@ -63,13 +71,13 @@ export default class InlineLog extends Vue {
|
|
|
63
71
|
}
|
|
64
72
|
scrollToLatest() {
|
|
65
73
|
const feed = this.$refs.feed as HTMLElement;
|
|
66
|
-
if (feed) {
|
|
74
|
+
if (feed?.clientHeight) {
|
|
67
75
|
feed.scrollTop = feed.scrollHeight;
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
onScroll() {
|
|
71
79
|
const feed = this.$refs.feed as HTMLElement;
|
|
72
|
-
this.follow = feed.scrollHeight - feed.scrollTop - feed.clientHeight < 32;
|
|
80
|
+
if (feed.clientHeight) this.follow = feed.scrollHeight - feed.scrollTop - feed.clientHeight < 32;
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
</script>
|
package/src/game-chat.ts
CHANGED
|
@@ -32,6 +32,14 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
32
32
|
.bgs-game-chat .chat-status:empty{display:none}
|
|
33
33
|
.chat-shortcut{position:fixed;left:16px;bottom:max(16px,env(safe-area-inset-bottom));z-index:900;padding:7px 12px;border:1px solid #6a8589;border-radius:3px;background:#263521;color:#fff;font:600 14px Arial,sans-serif;cursor:pointer;box-shadow:0 2px 6px #0003}
|
|
34
34
|
.chat-shortcut[hidden]{display:none}
|
|
35
|
+
.game-feed-tabs{display:none}
|
|
36
|
+
@media(max-width:700px){
|
|
37
|
+
.game-feed-tabs{display:flex;gap:4px;margin-top:8px}
|
|
38
|
+
.game-feed-tabs button{border:1px solid #a2aa82;border-radius:3px 3px 0 0;padding:7px 14px;background:#e7ead7;color:#263521;font:600 14px Arial,sans-serif;cursor:pointer}
|
|
39
|
+
.game-feed-tabs button[aria-pressed="true"]{background:#f3f0dc;border-bottom:3px solid #526f32}
|
|
40
|
+
.game-feed-tabs button:focus-visible{outline:2px solid #247d8c;outline-offset:2px}
|
|
41
|
+
.journal-and-chat[data-feed="chat"]>.inline-game-log,.journal-and-chat[data-feed="journal"]>.chat-host{display:none}
|
|
42
|
+
}
|
|
35
43
|
.chat-shortcut:hover{background:#315966}
|
|
36
44
|
.chat-shortcut:focus-visible{outline:2px solid #fff;outline-offset:2px}
|
|
37
45
|
|
|
@@ -40,6 +48,29 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
40
48
|
const slot = host.querySelector('.chat-host');
|
|
41
49
|
if (slot) slot.append(panel);
|
|
42
50
|
else host.insertAdjacentElement('afterend', panel);
|
|
51
|
+
const feeds = host.querySelector('.journal-and-chat') as HTMLElement | null;
|
|
52
|
+
const tabs = document.createElement('nav');
|
|
53
|
+
tabs.className = 'game-feed-tabs';
|
|
54
|
+
tabs.setAttribute('aria-label', 'Chat and journal');
|
|
55
|
+
const chatTab = document.createElement('button');
|
|
56
|
+
const journalTab = document.createElement('button');
|
|
57
|
+
chatTab.type = journalTab.type = 'button';
|
|
58
|
+
chatTab.textContent = 'Chat';
|
|
59
|
+
journalTab.textContent = 'Journal';
|
|
60
|
+
tabs.append(chatTab, journalTab);
|
|
61
|
+
if (feeds) feeds.insertAdjacentElement('beforebegin', tabs);
|
|
62
|
+
function selectFeed(feed: 'chat' | 'journal'): void {
|
|
63
|
+
if (feeds) feeds.dataset.feed = feed;
|
|
64
|
+
chatTab.setAttribute('aria-pressed', String(feed === 'chat'));
|
|
65
|
+
journalTab.setAttribute('aria-pressed', String(feed === 'journal'));
|
|
66
|
+
}
|
|
67
|
+
selectFeed('chat');
|
|
68
|
+
chatTab.onclick = () => {
|
|
69
|
+
selectFeed('chat');
|
|
70
|
+
panel.open = true;
|
|
71
|
+
requestAnimationFrame(read);
|
|
72
|
+
};
|
|
73
|
+
journalTab.onclick = () => selectFeed('journal');
|
|
43
74
|
const list = panel.querySelector('.chat-messages') as HTMLDivElement;
|
|
44
75
|
const input = panel.querySelector('input') as HTMLInputElement;
|
|
45
76
|
const button = panel.querySelector('button') as HTMLButtonElement;
|
|
@@ -70,7 +101,7 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
70
101
|
shortcut.type = 'button';
|
|
71
102
|
shortcut.className = 'chat-shortcut';
|
|
72
103
|
shortcut.hidden = true;
|
|
73
|
-
panel.insertAdjacentElement('afterend', shortcut);
|
|
104
|
+
(feeds || panel).insertAdjacentElement('afterend', shortcut);
|
|
74
105
|
let chatVisible = false;
|
|
75
106
|
function updateShortcut(): void {
|
|
76
107
|
const count = unread.size;
|
|
@@ -78,9 +109,11 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
78
109
|
shortcut.textContent = label;
|
|
79
110
|
shortcut.setAttribute('aria-label', `Open ${label}`);
|
|
80
111
|
summary.textContent = label;
|
|
112
|
+
chatTab.textContent = label;
|
|
81
113
|
shortcut.hidden = chatVisible;
|
|
82
114
|
}
|
|
83
115
|
shortcut.onclick = () => {
|
|
116
|
+
selectFeed('chat');
|
|
84
117
|
panel.open = true;
|
|
85
118
|
requestAnimationFrame(() => {
|
|
86
119
|
const firstUnread = Array.from(list.children).find((row) =>
|
|
@@ -117,6 +150,7 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
117
150
|
return;
|
|
118
151
|
}
|
|
119
152
|
const bounds = list.getBoundingClientRect();
|
|
153
|
+
if (!bounds.width || !bounds.height) return;
|
|
120
154
|
const visible = Array.from(list.children).filter((el) => {
|
|
121
155
|
const r = el.getBoundingClientRect();
|
|
122
156
|
return r.bottom <= Math.min(bounds.bottom, window.innerHeight) + 1 && r.top >= Math.max(bounds.top, 0);
|
|
@@ -267,7 +301,7 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
267
301
|
}
|
|
268
302
|
};
|
|
269
303
|
list.onscroll = () => {
|
|
270
|
-
following = list.scrollHeight - list.scrollTop - list.clientHeight < 32;
|
|
304
|
+
if (list.clientHeight) following = list.scrollHeight - list.scrollTop - list.clientHeight < 32;
|
|
271
305
|
read();
|
|
272
306
|
};
|
|
273
307
|
panel.ontoggle = () => {
|
|
@@ -280,10 +314,12 @@ export function mountGameChat(emitter: ChatEmitter, host: Element): void {
|
|
|
280
314
|
window.addEventListener('focus', read);
|
|
281
315
|
window.addEventListener('resize', read);
|
|
282
316
|
const sizing = new ResizeObserver(() => {
|
|
317
|
+
if (following && list.clientHeight) list.scrollTop = list.scrollHeight;
|
|
283
318
|
updateShortcut();
|
|
284
319
|
read();
|
|
285
320
|
});
|
|
286
321
|
sizing.observe(panel);
|
|
322
|
+
sizing.observe(list);
|
|
287
323
|
document.addEventListener('visibilitychange', read);
|
|
288
324
|
status.textContent = reason;
|
|
289
325
|
controls();
|