Compare commits

..

No commits in common. "7da053eb9cae72e794585145719d2f3c2b3600f2" and "ddd74a262c1560c44ee90c9e5efbe5d4402dd95e" have entirely different histories.

9 changed files with 39 additions and 241 deletions

View File

@ -1,7 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JSCodeStyleSettings version="0">
<option name="USE_EXPLICIT_JS_EXTENSION" value="ALWAYS_JS" />
</JSCodeStyleSettings>
</code_scheme>
</component>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -82,15 +82,15 @@
</main> </main>
<aside id="right-menu"> <aside id="right-menu">
<span data-resize="right-menu"></span> <span data-resize="right-menu"></span>
<section id="recipe-selector" data-state="planning" data-retain-tooltip-hover> <section id="recipe-selector" data-state="planning">
<template id="recipe-selector:template"> <template id="recipe-selector:template">
<div> <div>
<header data-text="recipe:type"></header> <header data-text="recipe:type"></header>
<div class="recipe recipe--selected"> <div class="recipe">
<div data-atlas="recipe:selected"></div> <div data-atlas="recipe:selected"></div>
<div data-text="recipe:selected"></div> <div data-text="recipe:selected"></div>
</div> </div>
<input placeholder="Filter" type="text" data-input="recipe:filter" autofocus> <input placeholder="Filter" type="text" data-input="recipe:filter">
<div class="select"> <div class="select">
<template> <template>
<div class="recipe"> <div class="recipe">

View File

@ -81,10 +81,11 @@ export async function saveFile(name = undefined) {
emitEvent("fileSave:nameDesign"); emitEvent("fileSave:nameDesign");
const nameEvent = await awaitEvent("fileSave:nameDesign:named"); const nameEvent = await awaitEvent("fileSave:nameDesign:named");
name = nameEvent.detail; name = nameEvent.detail;
console.log(nameEvent)
} }
if (!name) { if (!name) {
return; name = "unnamed";
} }
const multiblockType = getPlannerMultiblockType(); const multiblockType = getPlannerMultiblockType();

View File

@ -30,12 +30,9 @@ export class Filter {
} }
static fromInput(dataValue) { static fromInput(dataValue) {
if (typeof dataValue === "string") {
const elem = document.querySelector(`[data-input='${dataValue}']`); const elem = document.querySelector(`[data-input='${dataValue}']`);
return new Filter(elem.value); return new Filter(elem.value);
} }
return new Filter(dataValue.value);
}
test(...data) { test(...data) {
for (const datum of data) { for (const datum of data) {

View File

@ -47,7 +47,7 @@ export function stripEntryToMinimums(entry) {
throw new Error(`unknown entry type ${entry.type}`); throw new Error(`unknown entry type ${entry.type}`);
} }
export function findFullEntry(type, entry, { configurationHint } = {}) { export function findFullEntry(type, entry, { configurationHint }) {
const possibleEntries = [ const possibleEntries = [
...Object.entries(configuration.configuration), ...Object.entries(configuration.configuration),
...configuration.addons.flatMap(a => Object.entries(a.configuration)), ...configuration.addons.flatMap(a => Object.entries(a.configuration)),
@ -57,23 +57,6 @@ export function findFullEntry(type, entry, { configurationHint } = {}) {
return possibleEntries.find(other => checkEquivalence(entry, other)); return possibleEntries.find(other => checkEquivalence(entry, other));
} }
export function findFullEntryAnywhere(entry, { configurationHint } = {}) {
const possibleEntries = [
...Object.entries(configuration.configuration),
...configuration.addons.flatMap(a => Object.entries(a.configuration)),
]
.filter(([k]) => (!configurationHint || k === configurationHint))
.flatMap(([, v]) => Object.entries(v)
.flatMap(([k, v]) => k === "modules" ? [
...("plannerator:global_elements" in v
? [["plannerator:global_elements", v["plannerator:global_elements"].elements]]
: []),
] : [[k, v]]))
.flatMap(([t, v]) => v.map(e => [t, e]));
const [ type, foundEntry ] = possibleEntries.find(([, other]) => checkEquivalence(entry, other));
return { type, entry: foundEntry };
}
export function resolveBlockName(block, { configurationHint }) { export function resolveBlockName(block, { configurationHint }) {
if (block.type === "module") { if (block.type === "module") {

View File

@ -3,12 +3,9 @@ import { listenTo } from "./events.js";
import { configuration } from "./configuration.js"; import { configuration } from "./configuration.js";
import { getPlannerDom, getPlannerMultiblockType } from "./planner.js"; import { getPlannerDom, getPlannerMultiblockType } from "./planner.js";
import { DomList } from "./dom-list.js"; import { DomList } from "./dom-list.js";
import { getAtlasIndexFromMetadata, getAtlasMetadata, makeAtlasImage } from "./atlas.js"; import { getAtlasIndexFromMetadata, makeAtlasImage } from "./atlas.js";
import { getSolverMetadata, setSolverMetadata } from "./solver.js"; import { getSolverMetadata, setSolverMetadata } from "./solver.js";
import { findFullEntry, findFullEntryAnywhere, lookupFromMetadata } from "./ncpf-utils.js"; import { findFullEntry } from "./ncpf-utils.js";
import { createTooltip, setTooltip, tooltipDataToPlain } from "./tooltip.js";
import { Filter } from "./filter.js";
import { debounce } from "./dom-utils.js";
const defaultRecipes = { const defaultRecipes = {
["nuclearcraft:overhaul_sfr"]: { ["nuclearcraft:overhaul_sfr"]: {
@ -62,30 +59,13 @@ function rescanDesignRecipes() {
} }
selectedRecipe = findFullEntry("coolant_recipes", selectedRecipe, { configurationHint: multiblockType }); selectedRecipe = findFullEntry("coolant_recipes", selectedRecipe, { configurationHint: multiblockType });
function updateSelectedRecipe() {
const selectedRecipeName = selectedRecipe.modules["plannerator:display_name"].display_name; const selectedRecipeName = selectedRecipe.modules["plannerator:display_name"].display_name;
const selectedAtlasId = getAtlasIndexFromMetadata(selectedRecipe, multiblockType, "coolant_recipes"); const selectedAtlasId = getAtlasIndexFromMetadata(selectedRecipe, multiblockType, "coolant_recipes");
const metadata = getAtlasMetadata(selectedAtlasId);
designItem.querySelectorAll('[data-text="recipe:selected"]') designItem.querySelectorAll('[data-text="recipe:selected"]')
.forEach(e => e.innerText = selectedRecipeName); .forEach(e => e.innerText = selectedRecipeName);
designItem.querySelectorAll('[data-atlas="recipe:selected"]') designItem.querySelectorAll('[data-atlas="recipe:selected"]')
.forEach(e => e.replaceChildren(makeAtlasImage(selectedAtlasId))); .forEach(e => e.appendChild(makeAtlasImage(selectedAtlasId)));
designItem.querySelectorAll('.recipe--selected')
.forEach(e => setTooltip(e, [...getRecipeTooltip(selectedRecipe, metadata)]));
}
updateSelectedRecipe();
function handleDismiss() {
console.log("dismiss");
designItem.classList.remove("selecting");
window.removeEventListener("click", handleDismiss);
}
designItem.addEventListener("click", e => e.stopPropagation());
const filterElem = designItem.querySelector('[data-input="recipe:filter"]');
function updateRecipeList() {
const filter = Filter.fromInput(filterElem);
const recipeList = new DomList(designItem.querySelector(":scope > .select")); const recipeList = new DomList(designItem.querySelector(":scope > .select"));
recipeList.clear(); recipeList.clear();
for (let i = 0; i < coolantRecipes.length; i++) { for (let i = 0; i < coolantRecipes.length; i++) {
@ -94,75 +74,16 @@ function rescanDesignRecipes() {
const recipeName = recipe.modules["plannerator:display_name"].display_name; const recipeName = recipe.modules["plannerator:display_name"].display_name;
const atlasId = getAtlasIndexFromMetadata(recipe, multiblockType, "coolant_recipes"); const atlasId = getAtlasIndexFromMetadata(recipe, multiblockType, "coolant_recipes");
const metadata = getAtlasMetadata(atlasId);
recipeItem.querySelectorAll('[data-text="recipe:item"]') recipeItem.querySelectorAll('[data-text="recipe:item"]')
.forEach(e => e.innerText = recipeName); .forEach(e => e.innerText = recipeName);
recipeItem.querySelectorAll('[data-atlas="recipe:item"]') recipeItem.querySelectorAll('[data-atlas="recipe:item"]')
.forEach(e => e.replaceChildren(makeAtlasImage(atlasId))); .forEach(e => e.appendChild(makeAtlasImage(atlasId)));
recipeItem.addEventListener("click", () => {
handleDismiss();
selectedRecipe = recipe;
updateSelectedRecipe();
setSolverMetadata(plannerDom, {
coolant_recipe: selectedRecipe,
});
});
const tooltipData = [...getRecipeTooltip(recipe, metadata)];
setTooltip(recipeItem, tooltipData);
if (!filter.test(recipeName, ...tooltipDataToPlain(tooltipData))) {
recipeItem.classList.add("hidden");
}
console.log(recipe, recipeItem, atlasId);
recipeList.addItem(recipeItem); recipeList.addItem(recipeItem);
} }
}
updateRecipeList();
filterElem.addEventListener("input", debounce(updateRecipeList));
designItem.querySelectorAll(':scope > .recipe--selected').forEach(e => {
e.addEventListener("click", () => {
designItem.classList.add("selecting");
designItem.querySelector('[autofocus]').focus();
window.addEventListener("click", handleDismiss);
});
});
designRecipes.addItem(designItem); designRecipes.addItem(designItem);
} }
} }
function* getRecipeTooltip(recipe, metadata) {
const multiblockType = getPlannerMultiblockType();
let hasAdditionalData = false;
if ("nuclearcraft:overhaul_sfr:coolant_recipe_stats" in recipe.modules) {
hasAdditionalData = true;
const stats = recipe.modules["nuclearcraft:overhaul_sfr:coolant_recipe_stats"];
const { entry: output, type } = findFullEntryAnywhere(stats.output, { configurationHint: multiblockType });
const outputName = output.modules["plannerator:display_name"].display_name;
const atlasId = getAtlasIndexFromMetadata(output, multiblockType, type);
yield `Heat: ${stats.heat}`;
yield `Output:`
yield `Ratio ${stats.output_ratio}`;
yield {
type: "item",
atlasIndex: atlasId,
name: outputName,
};
}
if (!hasAdditionalData) {
console.log("unknown recipe", recipe, metadata);
}
yield {
type: "italics",
text: metadata.configurationAddon.name,
};
}

View File

@ -1,7 +1,6 @@
import { debounce } from "./dom-utils.js"; import { debounce } from "./dom-utils.js";
import { emitEvent, listenTo } from "./events.js"; import { emitEvent, listenTo } from "./events.js";
import { registerLoadCallback } from "./main.js"; import { registerLoadCallback } from "./main.js";
import { makeAtlasImage } from "./atlas.js";
const tooltips = {}; const tooltips = {};
let tooltipsCounter = 0; let tooltipsCounter = 0;
@ -40,7 +39,6 @@ registerLoadCallback(() => {
document.addEventListener("keydown", e => { document.addEventListener("keydown", e => {
if (e.key === "T") { if (e.key === "T") {
suppressTooltips = !suppressTooltips; suppressTooltips = !suppressTooltips;
console.log("suppressing tooltips", suppressTooltips);
} }
}); });
}); });
@ -53,13 +51,6 @@ export function createTooltip(data) {
} }
export function getTooltip(id) { export function getTooltip(id) {
if (typeof id === "object") {
// assume DOM element
if (id.dataset && id.dataset.tooltip) {
return getTooltip(id.dataset.tooltip);
}
return null;
}
return tooltips[id]; return tooltips[id];
} }
@ -67,14 +58,6 @@ export function deleteTooltip(id) {
delete tooltips[id]; delete tooltips[id];
} }
export function setTooltip(element, data) {
if (element.dataset.tooltip) {
tooltips[Number(element.dataset.tooltip)] = data;
return;
}
element.dataset.tooltip = createTooltip(data).toString(10);
}
export function positionAsTooltip(mainElement, tooltipElement, { horizontal = "left", vertical = "bottom" } = {}) { export function positionAsTooltip(mainElement, tooltipElement, { horizontal = "left", vertical = "bottom" } = {}) {
const targetRect = mainElement.getBoundingClientRect(); const targetRect = mainElement.getBoundingClientRect();
const domRect = tooltipElement.getBoundingClientRect(); const domRect = tooltipElement.getBoundingClientRect();
@ -88,11 +71,9 @@ function showTooltip() {
if (!lastCoordinates) return; if (!lastCoordinates) return;
if (activeTooltipTarget) hideTooltip(); if (activeTooltipTarget) hideTooltip();
let target = document.elementFromPoint(lastCoordinates.x, lastCoordinates.y); const target = document.elementFromPoint(lastCoordinates.x, lastCoordinates.y);
while (target && !target.dataset.tooltip) {
target = target.parentElement;
}
if (!target) return; if (!target) return;
if (!target.dataset.tooltip) return;
const dom = createTooltipDom(target.dataset.tooltip); const dom = createTooltipDom(target.dataset.tooltip);
if (!dom) return; if (!dom) return;
@ -135,21 +116,9 @@ function createTooltipDom(id) {
throw row; throw row;
} }
// TODO: support richer tooltips // TODO: support richer tooltips
switch (row.type) { if (row.type === "italics") {
case "italics":
rowElem.innerText = row.text; rowElem.innerText = row.text;
rowElem.classList.add("italics"); rowElem.classList.add("italics");
break;
case "item":
rowElem.appendChild(makeAtlasImage(row.atlasIndex));
rowElem.appendChild(document.createTextNode(row.name));
rowElem.classList.add("tooltip--item");
break;
default:
console.warn("unknown tooltip type", row);
break;
} }
} }
@ -168,7 +137,6 @@ export function tooltipDataToPlain(data) {
if (typeof row === "string") return row; if (typeof row === "string") return row;
if (!row.type) return []; if (!row.type) return [];
if (row.text) return row.text; if (row.text) return row.text;
if (row.type === "item") return row.name;
return []; return [];
}) })
} }

View File

@ -18,8 +18,6 @@
--menu-border-color: #666; --menu-border-color: #666;
--resize-handle-color: #666; --resize-handle-color: #666;
--resize-handle-width: 3px; --resize-handle-width: 3px;
--recipe-select-border-color: #888a;
} }
[data-state].hidden { [data-state].hidden {
@ -264,57 +262,7 @@ input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
outline: calc(var(--scale-factor) * 1px) solid var(--block-hover-outline-color, #6666); outline: calc(var(--scale-factor) * 1px) solid var(--block-hover-outline-color, #6666);
} }
.recipe-selector .recipe { #recipe-selector {}
/*background: red;*/
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: .25em;
/*--scale-factor: 1.5;*/
cursor: pointer;
}
.recipe-selector .recipe > [data-text] {
flex-grow: 1;
}
.recipe-selector .recipe--selected {
border-radius: .25em;
border: 1px solid var(--recipe-select-border-color, #444);
}
.recipe-selector .recipe--selected::after {
padding-right: .25em;
content: '▼';
}
.recipe-selector > div:not(.selecting) > input, .recipe-selector > div:not(.selecting) > .select {
display: none;
}
.recipe-selector > div.selecting .recipe--selected {
display: none;
}
.recipe-selector > div {
position: relative;
}
.recipe-selector > div > [data-input="recipe:filter"] {
border: 1px solid var(--recipe-select-border-color, #444);
}
.recipe-selector > div > .select {
position: static;
left: 0;
right: 0;
max-height: calc(var(--scale-factor) * var(--recipe-select-item-count, 4));
overflow: auto;
z-index: 10;
border: 1px solid var(--recipe-select-border-color, #444);
border-top: none;
border-bottom-left-radius: .25em;
border-bottom-right-radius: .25em;
}
.recipe-selector .select > .recipe:hover {
background-color: var(--recipe-select-hover-bg, #4444);
}
.recipe-selector .select > .hidden {
display: none;
}
[data-tooltip] { [data-tooltip] {
position: relative; position: relative;
@ -331,14 +279,6 @@ input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
border: var(--tooltip-border-size, 1px) solid var(--tooltip-border-color, #fff); border: var(--tooltip-border-size, 1px) solid var(--tooltip-border-color, #fff);
/*max-width: var(--tooltip-width, 200px);*/ /*max-width: var(--tooltip-width, 200px);*/
} }
.tooltip > .tooltip--item {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: .25em;
--scale-factor: 1;
}
.menu-bar { .menu-bar {
user-select: none; user-select: none;