stuff & things, add more UI

This commit is contained in:
MeowcaTheoRange 2024-06-02 22:54:02 -05:00
parent bb0991ef21
commit d652568628
12 changed files with 328 additions and 27 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 B

View file

@ -7,7 +7,8 @@ export class FloorManager {
floors = new Map([]); floors = new Map([]);
rooms = new Map([]); rooms = new Map([]);
currentFloor = ""; #currentFloor = "";
#currentRoom = "";
constructor(map, ui, gameobj, events, lang) { constructor(map, ui, gameobj, events, lang) {
this.map = map; this.map = map;
@ -20,6 +21,38 @@ export class FloorManager {
this.lang = lang; this.lang = lang;
} }
set currentFloor(floor) {
this.#currentFloor = floor;
}
get currentFloor() {
return this.#currentFloor;
}
get currentFloorItem() {
return this.floors.get(this.#currentFloor);
}
setCurrentRoom(room, maximize = true) {
this.#currentRoom = room;
this.ui.__updateEvents();
if (maximize) this.ui.eventsMaximize();
if (room == "") this.gameobj.zoomToFloor();
else this.gameobj.zoomToRoom(room);
}
get currentRoom() {
return this.#currentRoom;
}
get currentRoomItem() {
return this.currentFloorRooms.get(this.#currentRoom);
}
get currentFloorRooms() {
return this.rooms.get(this.#currentFloor);
}
async getFloors() { async getFloors() {
let allFloorsReqSend = fetch(`/data/${this.lang}/map`); let allFloorsReqSend = fetch(`/data/${this.lang}/map`);
@ -51,7 +84,10 @@ export class FloorManager {
let allRooms; let allRooms;
if (allRoomsReq.ok) allRooms = await allRoomsReq.json(); if (allRoomsReq.ok) allRooms = await allRoomsReq.json();
this.rooms.set(id, allRooms); const roomMap = new Map([]);
allRooms.forEach((room) => roomMap.set(room.id, room));
this.rooms.set(id, roomMap);
this.ui.setLoading(false); this.ui.setLoading(false);
@ -60,7 +96,7 @@ export class FloorManager {
async changeFloor(id) { async changeFloor(id) {
const floor = this.floors.get(id); const floor = this.floors.get(id);
if (floor != null) this.currentFloor = id; if (floor != null) this.#currentFloor = id;
if (this.ui.floorsEmpty) this.ui.__updateFloorsHard(); if (this.ui.floorsEmpty) this.ui.__updateFloorsHard();
else this.ui.__updateFloorsSoft(); else this.ui.__updateFloorsSoft();
@ -77,6 +113,8 @@ export class FloorManager {
this.ui.__updateEvents(); this.ui.__updateEvents();
this.setCurrentRoom("", false);
this.ui.setLoading(false); this.ui.setLoading(false);
return floor; return floor;

View file

@ -4,7 +4,6 @@ export class GameObjManager {
floorObject; floorObject;
roomObjects = new Map([]); roomObjects = new Map([]);
currentRoom;
constructor(map) { constructor(map) {
this.map = map; this.map = map;
@ -55,6 +54,21 @@ export class GameObjManager {
this.map.zoomToAbs(this.map.opts.minZoomLevel, bounds.center()); this.map.zoomToAbs(this.map.opts.minZoomLevel, bounds.center());
} }
zoomToFloor() {
const objectBounds = this.floorObject.renderArea().bbox();
this.map.zoomToAbs(this.map.opts.minZoomLevel, objectBounds.center());
}
zoomToRoom(id) {
const selectedObject = this.roomObjects.get(id);
if (selectedObject == null) return;
const objectBounds = selectedObject.renderArea().bbox();
this.map.zoomToAbs(this.map.opts.minZoomLevel + 1, objectBounds.center());
}
generateRooms() { generateRooms() {
if (this.roomObjects.size > 0) { if (this.roomObjects.size > 0) {
this.roomObjects.forEach((x) => x.destroy()); this.roomObjects.forEach((x) => x.destroy());
@ -78,7 +92,7 @@ export class GameObjManager {
this.map.kp.pos(), this.map.kp.pos(),
this.map.kp.z(6), this.map.kp.z(6),
{ {
clickForgiveness: 1, clickForgiveness: 5,
startClickPosition: null, startClickPosition: null,
}, },
]); ]);
@ -108,7 +122,7 @@ export class GameObjManager {
obj.startClickPosition && obj.startClickPosition &&
obj.startClickPosition.dist(endClickPosition) < obj.clickForgiveness obj.startClickPosition.dist(endClickPosition) < obj.clickForgiveness
) { ) {
this.currentRoom = room.id; this.floormanager.setCurrentRoom(room.id);
} }
obj.color = this.map.kp.Color.fromHex("505050"); obj.color = this.map.kp.Color.fromHex("505050");
this.map.clearMouseMode(); this.map.clearMouseMode();

View file

@ -4,7 +4,7 @@ export class KaplayMap {
minZoomLevel: 2, minZoomLevel: 2,
maxZoomLevel: 5, maxZoomLevel: 5,
dblClickDuration: 0.2, // s dblClickDuration: 0.2, // s
dblClickForgiveness: 30, // px dblClickForgiveness: 100, // px
}; };
uiLayer; uiLayer;

View file

@ -0,0 +1,20 @@
export default new Map([
[
"en_US",
{
date_starting: "Starting",
date_started: "Started",
floors_header: "Floors",
date_summary: (prefix, time) => `${prefix} ${time}`,
parenthesis: (content) => `(${content})`,
hours_long: (hours) =>
hours == 1 ? `${hours} hour long` : `${hours} hours long`,
minutes_long: (hours) =>
hours == 1 ? `${hours} minute long` : `${hours} minutes long`,
events_in: (name) => `Events (${name})`,
view_events_in: (name) => `Return to events in ${name}`,
minimize: "Hide events panel",
maximize: "Show events panel",
},
],
]);

View file

@ -1,3 +1,9 @@
import {
getMinutesDifference,
getRelativeTime,
} from "../modules/relative_time.js";
import localization from "./localization.js";
export class UIManager { export class UIManager {
ui; ui;
map; map;
@ -21,6 +27,9 @@ export class UIManager {
// Floors // Floors
this.uiElements.floors = this.ui.querySelector("#floors"); this.uiElements.floors = this.ui.querySelector("#floors");
this.uiElements.floorsHeading = this.ui.querySelector(
"#floors .widget-heading"
);
this.uiElements.floorButtons = this.uiElements.floorButtons =
this.uiElements.floors.querySelector("#floor-buttons"); this.uiElements.floors.querySelector("#floor-buttons");
@ -29,10 +38,26 @@ export class UIManager {
this.ui.querySelector("#events-container"); this.ui.querySelector("#events-container");
this.uiElements.events = this.uiElements.events =
this.uiElements.eventsContainer.querySelector("#events"); this.uiElements.eventsContainer.querySelector("#events");
this.uiElements.eventsBackButton = this.uiElements.events.querySelector(
"#events-header #back"
);
this.uiElements.eventsRoomName = this.uiElements.events.querySelector(
"#events-header #room-name"
);
this.uiElements.eventsRoomDescription =
this.uiElements.events.querySelector("#events-header #room-description");
this.uiElements.eventList = this.uiElements.eventList =
this.uiElements.events.querySelector("#event-list"); this.uiElements.events.querySelector("#event-list");
this.uiElements.eventsMinimized = this.uiElements.eventsMinimized =
this.uiElements.eventsContainer.querySelector("#events-minimized"); this.uiElements.eventsContainer.querySelector("#events-minimized");
this.uiElements.eventsMinimizedBackButton =
this.uiElements.eventsMinimized.querySelector("#back");
this.uiElements.minimizeButton = this.uiElements.events.querySelector(
"#footer #footer-buttons #minimize"
);
this.uiElements.maximizeButton =
this.uiElements.eventsMinimized.querySelector("#maximize");
// Loading // Loading
this.uiElements.loading = this.ui.querySelector("#loading"); this.uiElements.loading = this.ui.querySelector("#loading");
@ -64,33 +89,163 @@ export class UIManager {
}); });
} }
toggleEventsMinimized() {
this.uiElements.eventsContainer.classList.toggle("minimized");
}
eventsMinimize() {
this.uiElements.eventsContainer.classList.add("minimized");
}
eventsMaximize() {
this.uiElements.eventsContainer.classList.remove("minimized");
}
__updateAll() {
this.__updateEvents();
this.__updateFloorsHard();
}
__initEvents() { __initEvents() {
const minimizeButton = this.uiElements.events.querySelector( this.uiElements.eventsBackButton.addEventListener("click", () => {
"#footer #footer-buttons #minimize" this.floormanager.setCurrentRoom("");
); });
minimizeButton.addEventListener("click", () => { this.uiElements.eventsMinimizedBackButton.addEventListener("click", () => {
this.floormanager.setCurrentRoom("", false);
});
this.uiElements.minimizeButton.addEventListener("click", () => {
this.uiElements.eventsContainer.classList.add("minimized"); this.uiElements.eventsContainer.classList.add("minimized");
}); });
const maximizeButton = this.uiElements.maximizeButton.addEventListener("click", () => {
this.uiElements.eventsMinimized.querySelector("#maximize");
maximizeButton.addEventListener("click", () => {
this.uiElements.eventsContainer.classList.remove("minimized"); this.uiElements.eventsContainer.classList.remove("minimized");
}); });
} }
__updateEvents() { __updateEvents() {
const currentLocalization = localization.get(this.floormanager.lang);
this.uiElements.minimizeButton.title = currentLocalization.minimize;
this.uiElements.maximizeButton.title = currentLocalization.maximize;
// Figure out header
if (this.floormanager.currentRoomItem != null) {
this.uiElements.eventsRoomName.textContent =
currentLocalization.events_in(this.floormanager.currentRoomItem.name);
this.uiElements.eventsRoomDescription.textContent =
this.floormanager.currentRoomItem.description;
this.uiElements.eventsBackButton.disabled = false;
this.uiElements.eventsBackButton.title =
currentLocalization.view_events_in(
this.floormanager.currentFloorItem.name
);
this.uiElements.eventsMinimizedBackButton.disabled = false;
this.uiElements.eventsMinimizedBackButton.title =
currentLocalization.view_events_in(
this.floormanager.currentFloorItem.name
);
} else {
this.uiElements.eventsRoomName.textContent =
currentLocalization.events_in(this.floormanager.currentFloorItem.name);
this.uiElements.eventsRoomDescription.textContent =
this.floormanager.currentFloorItem.description;
this.uiElements.eventsBackButton.disabled = true;
this.uiElements.eventsBackButton.title = "";
this.uiElements.eventsMinimizedBackButton.disabled = true;
this.uiElements.eventsMinimizedBackButton.title = "";
}
// Remove all children // Remove all children
this.uiElements.eventList.replaceChildren(); this.uiElements.eventList.replaceChildren();
console.log(this.eventmanager.events);
// Put them back // Put them back
const currentDate = new Date();
this.eventmanager.events.forEach((event, id) => { this.eventmanager.events.forEach((event, id) => {
if (
this.floormanager.currentRoomItem &&
event.where != this.floormanager.currentRoom
)
return; // Don't display this event
const eventFloor = this.floormanager.currentFloorRooms.get(event.where);
const eventDateStart = new Date(event.when.start);
const eventDateEnd = new Date(event.when.end);
const eventStarted = currentDate > eventDateStart;
const eventEnded = currentDate > eventDateEnd;
let datePrefix;
if (eventEnded) {
return; // Don't display this event
} else if (eventStarted) {
datePrefix = currentLocalization.date_started;
} else {
datePrefix = currentLocalization.date_starting;
}
const eventListContainer = document.createElement("details"); const eventListContainer = document.createElement("details");
eventListContainer.classList.add("event-list-container"); eventListContainer.classList.add("event-list-container");
eventListContainer.id = "event-" + id; eventListContainer.id = "event-" + id;
const eventListContainerSummary = document.createElement("summary"); const eventListContainerSummary = document.createElement("summary");
eventListContainerSummary.textContent = event.name;
const eventListContainerSummaryName = document.createElement("b");
eventListContainerSummaryName.textContent = event.name;
eventListContainerSummary.appendChild(eventListContainerSummaryName);
eventListContainerSummary.appendChild(document.createTextNode(" "));
if (this.floormanager.currentRoomItem == null) {
const eventListContainerSummaryRoom = document.createElement("button");
eventListContainerSummaryRoom.classList.add("link");
eventListContainerSummaryRoom.addEventListener("click", () => {
this.floormanager.setCurrentRoom(eventFloor.id);
});
eventListContainerSummaryRoom.textContent =
currentLocalization.parenthesis(eventFloor.name);
eventListContainerSummary.appendChild(eventListContainerSummaryRoom);
}
eventListContainerSummary.appendChild(document.createElement("br"));
const eventListContainerSummarySmall = document.createElement("small");
const eventListContainerSummaryTime = document.createElement("span");
eventListContainerSummaryTime.classList.add("clarification");
eventListContainerSummaryTime.title = eventDateStart.toLocaleString(
this.floormanager.lang.replace(/_/g, "-")
);
eventListContainerSummaryTime.textContent =
currentLocalization.date_summary(
datePrefix,
getRelativeTime(
eventDateStart,
currentDate,
this.floormanager.lang.replace(/_/g, "-")
)
);
eventListContainerSummarySmall.appendChild(eventListContainerSummaryTime);
eventListContainerSummarySmall.appendChild(document.createTextNode(" "));
const eventListContainerSummaryLength = document.createElement("span");
eventListContainerSummaryLength.textContent =
currentLocalization.parenthesis(
currentLocalization.minutes_long(
getMinutesDifference(eventDateStart, eventDateEnd)
)
);
eventListContainerSummarySmall.appendChild(
eventListContainerSummaryLength
);
eventListContainerSummary.appendChild(eventListContainerSummarySmall);
eventListContainer.appendChild(eventListContainerSummary); eventListContainer.appendChild(eventListContainerSummary);
@ -120,8 +275,11 @@ export class UIManager {
} }
__updateFloorsHard() { __updateFloorsHard() {
const currentLocalization = localization.get(this.floormanager.lang);
// Remove all children // Remove all children
this.uiElements.floorButtons.replaceChildren(); this.uiElements.floorButtons.replaceChildren();
this.uiElements.floorsHeading.textContent =
currentLocalization.floors_header;
// Put them back // Put them back
this.floormanager.floors.forEach(({ name }, id) => { this.floormanager.floors.forEach(({ name }, id) => {
@ -148,6 +306,11 @@ export class UIManager {
} }
__updateFloorsSoft() { __updateFloorsSoft() {
const currentLocalization = localization.get(this.floormanager.lang);
this.uiElements.floorsHeading.textContent =
currentLocalization.floors_header;
this.floormanager.floors.forEach(({ name }, id) => { this.floormanager.floors.forEach(({ name }, id) => {
const child = this.uiElements.floorButtons.querySelector("#floor-" + id); const child = this.uiElements.floorButtons.querySelector("#floor-" + id);
if (id === this.floormanager.currentFloor) if (id === this.floormanager.currentFloor)

View file

@ -0,0 +1,26 @@
// in miliseconds
export const units = {
year: 24 * 60 * 60 * 1000 * 365,
month: (24 * 60 * 60 * 1000 * 365) / 12,
day: 24 * 60 * 60 * 1000,
hour: 60 * 60 * 1000,
minute: 60 * 1000,
second: 1000,
};
export function getRelativeTime(d1, d2, locale) {
let rtf = new Intl.RelativeTimeFormat(locale, {
numeric: "auto",
});
let elapsed = d1 - d2;
// "Math.abs" accounts for both "past" & "future" scenarios
for (var u in units)
if (Math.abs(elapsed) > units[u] || u == "second")
return rtf.format(Math.round(elapsed / units[u]), u);
}
export function getMinutesDifference(d1, d2) {
return (d2.getTime() - d1.getTime()) / units.minute;
}

View file

@ -28,7 +28,7 @@ p.widget-description {
padding-bottom: 2px; */ padding-bottom: 2px; */
} }
button { button:not(.link) {
background-color: transparent; background-color: transparent;
border: none; border: none;
color: inherit; color: inherit;
@ -39,16 +39,31 @@ button {
border: 1px solid #0008; border: 1px solid #0008;
} }
button:hover { button:not(.link):hover {
background-color: #0004; background-color: #0004;
} }
button:active { button:not(.link):active {
background-color: #0008; background-color: #0008;
} }
button:disabled { button:not(.link):disabled {
background-color: #8884; background-color: #8884;
color: #808080;
}
button.link {
background: none !important;
border: none;
padding: 0;
font: inherit;
color: currentColor;
text-decoration: underline;
cursor: pointer;
}
.clarification {
text-decoration: dotted underline;
} }
#map { #map {
@ -147,7 +162,7 @@ button:disabled {
#map-ui #events-container #events { #map-ui #events-container #events {
left: 16px; left: 16px;
width: 300px; width: 400px;
} }
#map-ui #events-container.minimized #events { #map-ui #events-container.minimized #events {
@ -168,8 +183,20 @@ button:disabled {
gap: 8px; gap: 8px;
} }
#map-ui #events-container #events #events-header p {
margin-bottom: 0;
}
#map-ui #events-container #events #events-header {
display: grid;
grid-template-columns: 36px auto;
gap: 8px;
margin-bottom: 8px;
align-items: center;
}
#map-ui #events-container #events #event-list { #map-ui #events-container #events #event-list {
min-height: 100px; min-height: 200px;
max-height: calc(50% - 16px); max-height: calc(50% - 16px);
margin: 8px 0; margin: 8px 0;
padding: 8px; padding: 8px;
@ -184,6 +211,7 @@ button:disabled {
white-space: pre-line; white-space: pre-line;
} }
#map-ui #events-container #events #events-header button,
#map-ui #events-container #footer #footer-buttons button, #map-ui #events-container #footer #footer-buttons button,
#map-ui #events-container #events-minimized button { #map-ui #events-container #events-minimized button {
width: 36px; width: 36px;

8
package-lock.json generated
View file

@ -9,7 +9,8 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"express": "^4.19.2" "express": "^4.19.2",
"https": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.1" "nodemon": "^3.1.1"
@ -499,6 +500,11 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
"integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg=="
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",

View file

@ -10,7 +10,8 @@
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"express": "^4.19.2" "express": "^4.19.2",
"https": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.1" "nodemon": "^3.1.1"

View file

@ -26,20 +26,25 @@
</div> </div>
<div id="events-container"> <div id="events-container">
<div id="events"> <div id="events">
<h1 class="widget-heading" id="room-name">Events</h1> <div id="events-header">
<p class="widget-description" id="room-description">Lorem ipsum dolor sit amet.</p> <button id="back" disabled></button>
<div>
<h1 class="widget-heading" id="room-name">Events</h1>
<p class="widget-description" id="room-description">Lorem ipsum dolor sit amet.</p>
</div>
</div>
<div id="event-list"> <div id="event-list">
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-buttons"> <div id="footer-buttons">
<button id="minimize">_</button> <button id="minimize">_</button>
<button id="back" disabled></button>
</div> </div>
</div> </div>
</div> </div>
<div id="events-minimized"> <div id="events-minimized">
<button id="maximize">+</button> <button id="maximize">+</button>
<button id="back" disabled></button>
</div> </div>
</div> </div>
<div id="loading"> <div id="loading">