Compare commits
No commits in common. "c63cada6e710ea5599125beb0da84a069072b63e" and "481e7000872f3ae66b30c74149d6f73a5e1ddb3f" have entirely different histories.
c63cada6e7
...
481e700087
16
index.html
16
index.html
|
|
@ -12,10 +12,8 @@
|
||||||
<button data-alt="n" data-button="file:new">New</button>
|
<button data-alt="n" data-button="file:new">New</button>
|
||||||
<button data-alt="o" data-button="file:load">Open</button>
|
<button data-alt="o" data-button="file:load">Open</button>
|
||||||
<button data-alt="s" data-button="file:save">Save</button>
|
<button data-alt="s" data-button="file:save">Save</button>
|
||||||
<div data-section="Configuiration" data-alt="c">
|
<div data-section="Recent Files" data-alt="r">
|
||||||
<button data-alt="d" data-button="load-configuration" data-configuration="default">Default</button>
|
<button disabled>-</button>
|
||||||
<button data-alt="e" data-button="load-configuration" data-configuration="e2ee">E2EE</button>
|
|
||||||
<button data-alt="s" data-button="load-configuration">Select file...</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div data-section="Edit" data-alt="e">
|
<div data-section="Edit" data-alt="e">
|
||||||
|
|
@ -183,15 +181,5 @@
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog hidden dialog--error" data-dialog="error:user">
|
|
||||||
<section>
|
|
||||||
<header>Error</header>
|
|
||||||
<main data-text="error">
|
|
||||||
</main>
|
|
||||||
<footer>
|
|
||||||
<button data-dialog-action="cancel">Close</button>
|
|
||||||
</footer>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ export async function buildAtlas(data) {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (textures.length === 0) {
|
if (textures.length === 0) {
|
||||||
throw new UserError("Configuration processing failed - no textured blocks found");
|
throw new Error("Configuration processing failed - no textured blocks found");
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(textures.map(getTextureSize));
|
await Promise.all(textures.map(getTextureSize));
|
||||||
|
|
@ -97,7 +97,7 @@ export async function buildAtlas(data) {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
for (const t of Object.values(Object.groupBy(textures, t => t.size.toString()))) {
|
for (const t of Object.values(Object.groupBy(textures, t => t.size.toString()))) {
|
||||||
if (t[0].size[0] !== t[0].size[1]) {
|
if (t[0].size[0] !== t[0].size[1]) {
|
||||||
throw new UserError("Configuration processing failed - textures must be square");
|
throw new Error("Configuration processing failed - textures must be square");
|
||||||
}
|
}
|
||||||
|
|
||||||
const dedupTextureMap = new Map();
|
const dedupTextureMap = new Map();
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,9 @@
|
||||||
import { buildAtlas } from "./atlas.js";
|
import { buildAtlas } from "./atlas.js";
|
||||||
import { emitEvent } from "./events.js";
|
import { emitEvent } from "./events.js";
|
||||||
import { setState, STATE } from "./state.js";
|
import { setState, STATE } from "./state.js";
|
||||||
import { registerLoadCallback } from "./main.js";
|
|
||||||
import { addEventToButton } from "./dom-utils.js";
|
|
||||||
import { showOpenFileDialog } from "./files.js";
|
|
||||||
import { DevError, UserError } from "./errors.js";
|
|
||||||
|
|
||||||
export let configuration = {};
|
export let configuration = {};
|
||||||
|
|
||||||
registerLoadCallback(() => {
|
|
||||||
addEventToButton("load-configuration", "click", loadConfiguration);
|
|
||||||
});
|
|
||||||
|
|
||||||
export async function loadConfiguration(event) {
|
export async function loadConfiguration(event) {
|
||||||
setState(STATE.initialization);
|
setState(STATE.initialization);
|
||||||
|
|
||||||
|
|
@ -20,16 +12,12 @@ export async function loadConfiguration(event) {
|
||||||
if (typeof event === "string") {
|
if (typeof event === "string") {
|
||||||
configData = await fetch(`./configurations/${event}.ncpf.json`)
|
configData = await fetch(`./configurations/${event}.ncpf.json`)
|
||||||
.then(data => data.json());
|
.then(data => data.json());
|
||||||
} else if (event.currentTarget?.dataset?.configuration) {
|
} else if (event.target.dataset.configuration) {
|
||||||
const configuration = event.currentTarget.dataset.configuration;
|
const configuration = event.target.dataset.configuration;
|
||||||
console.log(configuration);
|
console.log(configuration);
|
||||||
configData = await fetch(`./configurations/${configuration}.ncpf.json`)
|
configData = await fetch(`./configurations/${configuration}.ncpf.json`)
|
||||||
.then(data => data.json());
|
.then(data => data.json());
|
||||||
} else if (event.currentTarget?.tagName === "BUTTON") {
|
} else if (event.target.files[0]) {
|
||||||
const { data } = await new Promise(resolve => showOpenFileDialog(resolve));
|
|
||||||
console.log(data);
|
|
||||||
configData = data;
|
|
||||||
} else if (event?.target?.files && event.target.files[0]) {
|
|
||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
configData = await new Promise(resolve => {
|
configData = await new Promise(resolve => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
@ -39,11 +27,11 @@ export async function loadConfiguration(event) {
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new DevError("Configuration load failed - unrecognised event");
|
throw new Error("Configuration load failed - unrecognised event");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((configData.designs ?? []).length > 0) {
|
if ((configData.designs ?? []).length > 0) {
|
||||||
throw new UserError("Configuration load failed - contains designs, not a full configuration!");
|
throw new Error("Configuration load failed - contains designs, likely not full configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
emitEvent("config:load:end");
|
emitEvent("config:load:end");
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ registerLoadCallback(() => {
|
||||||
listenTo("dialogs:welcome", () => welcomeDialog(true));
|
listenTo("dialogs:welcome", () => welcomeDialog(true));
|
||||||
listenTo("fileLoad:chooseDesign", designChoiceDialog);
|
listenTo("fileLoad:chooseDesign", designChoiceDialog);
|
||||||
listenTo("fileSave:nameDesign", designNameDialog);
|
listenTo("fileSave:nameDesign", designNameDialog);
|
||||||
listenTo("error:user", errorDialog);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function initializeDialog(dialogName, endEvent, { emptyValue, onDismiss } = {}) {
|
function initializeDialog(dialogName, endEvent, { emptyValue, onDismiss } = {}) {
|
||||||
|
|
@ -89,8 +88,3 @@ function designNameDialog() {
|
||||||
dismiss(new FormData(e.detail.target).get("name"));
|
dismiss(new FormData(e.detail.target).get("name"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function errorDialog(e) {
|
|
||||||
const { dialog } = initializeDialog("error:user", "error:dialog:close");
|
|
||||||
dialog.querySelectorAll('[data-text="error"]').forEach(elem => elem.innerText = e.detail);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { emitEvent } from "./events.js";
|
|
||||||
|
|
||||||
export class UserError extends Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
emitEvent("error:user", message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DevError extends Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
emitEvent("error:dev", message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -10,15 +10,14 @@ import {
|
||||||
import { getAtlasIndexFromMetadata, getAtlasMetadata } from "./atlas.js";
|
import { getAtlasIndexFromMetadata, getAtlasMetadata } from "./atlas.js";
|
||||||
import { getSolverMetadata, resetSolver } from "./solver.js";
|
import { getSolverMetadata, resetSolver } from "./solver.js";
|
||||||
import { registerLoadCallback } from "./main.js";
|
import { registerLoadCallback } from "./main.js";
|
||||||
import { DevError, UserError } from "./errors.js";
|
|
||||||
|
|
||||||
registerLoadCallback(() => {
|
registerLoadCallback(() => {
|
||||||
listenTo("file:load", () => showOpenFileDialog(({ data, filename }) => loadFile(data, filename)));
|
listenTo("file:load", () => showOpenFileDialog());
|
||||||
listenTo("file:new", () => {});
|
listenTo("file:new", () => {});
|
||||||
listenTo("file:save", () => saveFile());
|
listenTo("file:save", () => saveFile());
|
||||||
});
|
});
|
||||||
|
|
||||||
export function showOpenFileDialog(callback) {
|
export function showOpenFileDialog() {
|
||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.type = "file";
|
input.type = "file";
|
||||||
input.accept = ".ncpf.json";
|
input.accept = ".ncpf.json";
|
||||||
|
|
@ -32,7 +31,7 @@ export function showOpenFileDialog(callback) {
|
||||||
});
|
});
|
||||||
reader.readAsText(input.files[0]);
|
reader.readAsText(input.files[0]);
|
||||||
});
|
});
|
||||||
callback({ data, filename });
|
void loadFile(data, filename);
|
||||||
});
|
});
|
||||||
input.click();
|
input.click();
|
||||||
}
|
}
|
||||||
|
|
@ -45,8 +44,8 @@ export async function loadExampleFile(filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadFile(data, name) {
|
export async function loadFile(data, name) {
|
||||||
if (!data.designs) throw new UserError("File must contain a list of designs!");
|
if (!data.designs) throw new Error("invalid file");
|
||||||
if (data.designs.length === 0) throw new UserError("Fils must contain at least one design!");
|
if (data.designs.length === 0) throw new Error("no designs");
|
||||||
|
|
||||||
let design = data.designs[0];
|
let design = data.designs[0];
|
||||||
if (data.designs.length > 1) {
|
if (data.designs.length > 1) {
|
||||||
|
|
@ -56,7 +55,7 @@ export async function loadFile(data, name) {
|
||||||
design = data.designs[res.detail];
|
design = data.designs[res.detail];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!design) throw new DevError("Must choose a design");
|
if (!design) throw new Error("no design");
|
||||||
|
|
||||||
const blocks = data.configuration[design.type].blocks
|
const blocks = data.configuration[design.type].blocks
|
||||||
.map(block => getAtlasIndexFromMetadata(block, design.type, "blocks"));
|
.map(block => getAtlasIndexFromMetadata(block, design.type, "blocks"));
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@ import "./block-picker.js";
|
||||||
import { loadConfiguration } from "./configuration.js";
|
import { loadConfiguration } from "./configuration.js";
|
||||||
import "./dialogs.js";
|
import "./dialogs.js";
|
||||||
import "./dom-list.js";
|
import "./dom-list.js";
|
||||||
import { debounce, getElements } from "./dom-utils.js";
|
import { addEventToButton, addEventToInput, debounce, getElements } from "./dom-utils.js";
|
||||||
import "./errors.js";
|
import { awaitEvent, emitEvent, listenTo } from "./events.js";
|
||||||
import { emitEvent, listenTo } from "./events.js";
|
import "./files.js"
|
||||||
import { loadExampleFile } from "./files.js"
|
|
||||||
import "./js-utils.js"
|
import "./js-utils.js"
|
||||||
import "./menu-bar.js";
|
import "./menu-bar.js";
|
||||||
import "./ncpf-utils.js";
|
import "./ncpf-utils.js";
|
||||||
|
|
@ -17,6 +16,7 @@ import "./solver.js";
|
||||||
import { getState, setState, STATE } from "./state.js";
|
import { getState, setState, STATE } from "./state.js";
|
||||||
import "./storage.js";
|
import "./storage.js";
|
||||||
import "./tooltip.js";
|
import "./tooltip.js";
|
||||||
|
import { loadExampleFile } from "./files.js";
|
||||||
|
|
||||||
let loadCallbacks = [];
|
let loadCallbacks = [];
|
||||||
export function registerLoadCallback(cb) {
|
export function registerLoadCallback(cb) {
|
||||||
|
|
@ -38,16 +38,6 @@ window.addEventListener("load", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
listenTo("state", () => {
|
|
||||||
console.log("State changed", getState());
|
|
||||||
getElements("state", "*").forEach(e => {
|
|
||||||
e.classList.add("hidden");
|
|
||||||
if (e.dataset.state === getState()) {
|
|
||||||
e.classList.remove("hidden");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
getElements("button", "*").forEach(elem => {
|
getElements("button", "*").forEach(elem => {
|
||||||
elem.addEventListener("click", e => {
|
elem.addEventListener("click", e => {
|
||||||
emitEvent(elem.dataset.button, e);
|
emitEvent(elem.dataset.button, e);
|
||||||
|
|
@ -77,6 +67,19 @@ window.addEventListener("load", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addEventToInput("configuration", "input", loadConfiguration);
|
||||||
|
addEventToButton("load-configuration", "click", loadConfiguration);
|
||||||
|
|
||||||
|
listenTo("state", () => {
|
||||||
|
console.log("State changed", getState());
|
||||||
|
getElements("state", "*").forEach(e => {
|
||||||
|
e.classList.add("hidden");
|
||||||
|
if (e.dataset.state === getState()) {
|
||||||
|
e.classList.remove("hidden");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
listenTo("config:end", () => setState(STATE.planning));
|
listenTo("config:end", () => setState(STATE.planning));
|
||||||
|
|
||||||
runLoadCallbacks();
|
runLoadCallbacks();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { configuration } from "./configuration.js";
|
import { configuration } from "./configuration.js";
|
||||||
import { objectKeepKeys } from "./js-utils.js";
|
import { objectKeepKeys } from "./js-utils.js";
|
||||||
import { DevError } from "./errors.js";
|
|
||||||
|
|
||||||
export function checkEquivalence(a, b) {
|
export function checkEquivalence(a, b) {
|
||||||
if (!a || !b || !a.type || !b.type || a.type !== b.type) return false;
|
if (!a || !b || !a.type || !b.type || a.type !== b.type) return false;
|
||||||
|
|
@ -32,7 +31,7 @@ export function checkEquivalence(a, b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stripEntryToMinimums(entry) {
|
export function stripEntryToMinimums(entry) {
|
||||||
if (!entry.type) throw new DevError("must have a type");
|
if (!entry.type) throw new Error("must have a type");
|
||||||
switch (entry.type) {
|
switch (entry.type) {
|
||||||
case "legacy_block":
|
case "legacy_block":
|
||||||
return objectKeepKeys(entry, "type", "name", "metadata", "blockstate");
|
return objectKeepKeys(entry, "type", "name", "metadata", "blockstate");
|
||||||
|
|
@ -49,7 +48,7 @@ export function stripEntryToMinimums(entry) {
|
||||||
elements: entry.elements.map(stripEntryToMinimums),
|
elements: entry.elements.map(stripEntryToMinimums),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
throw new DevError(`unknown entry type ${entry.type}`);
|
throw new Error(`unknown entry type ${entry.type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findFullEntry(type, entry, { configurationHint, all = false } = {}) {
|
export function findFullEntry(type, entry, { configurationHint, all = false } = {}) {
|
||||||
|
|
|
||||||
|
|
@ -308,11 +308,6 @@ function* getRecipeTooltip(recipe, metadata) {
|
||||||
console.log("unknown recipe", recipe, metadata);
|
console.log("unknown recipe", recipe, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metadata) {
|
|
||||||
console.trace("no metadata for recipe", recipe, metadata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata.configurationAddon) {
|
if (metadata.configurationAddon) {
|
||||||
yield {
|
yield {
|
||||||
type: "italics",
|
type: "italics",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue