mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-27 16:58:46 +00:00
Show validation errors
This commit is contained in:
17
src/app/ErrorsView.ts
Normal file
17
src/app/ErrorsView.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { AbstractView, Path, locale } from "minecraft-schemas";
|
||||
|
||||
export class ErrorsView extends AbstractView {
|
||||
render(): void {
|
||||
this.target.style.display = this.model.errors.count() > 0 ? 'flex' : 'none'
|
||||
|
||||
const errors = this.model.errors.get(new Path())
|
||||
this.target.children[0].innerHTML = errors.map(err =>
|
||||
`<div class="error">
|
||||
<svg class="error-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="18" height="18"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>
|
||||
<span class="error-path">${err.path.toString()}</span>
|
||||
<span>-</span>
|
||||
<span class="error-message">${locale(err.error, err.params)}</span>
|
||||
</div>`
|
||||
).join('')
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import Split from 'split.js'
|
||||
|
||||
import { SandboxSchema } from './Sandbox'
|
||||
import { ErrorsView } from './ErrorsView'
|
||||
|
||||
const LOCAL_STORAGE_THEME = 'theme'
|
||||
|
||||
@@ -51,6 +52,12 @@ const registries = [
|
||||
'structure_feature'
|
||||
]
|
||||
|
||||
const treeViewObserver = (el: HTMLElement) => {
|
||||
el.querySelectorAll('.node-header[data-error]').forEach(e => {
|
||||
e.insertAdjacentHTML('beforeend', `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>`)
|
||||
})
|
||||
}
|
||||
|
||||
const publicPath = process.env.NODE_ENV === 'production' ? '/dev/' : '/';
|
||||
Promise.all([
|
||||
fetch(publicPath + 'locales/schema/en.json').then(r => r.json()),
|
||||
@@ -60,13 +67,15 @@ Promise.all([
|
||||
LOCALES.register('en', {...responses[0], ...responses[1]})
|
||||
|
||||
const selectedModel = document.getElementById('selected-model')!
|
||||
const modelSelector = (document.getElementById('model-selector') as HTMLInputElement)
|
||||
const modelSelector = document.getElementById('model-selector')!
|
||||
const modelSelectorMenu = document.getElementById('model-selector-menu')!
|
||||
const languageSelector = document.getElementById('language-selector')!
|
||||
const languageSelectorMenu = document.getElementById('language-selector-menu')!
|
||||
const themeSelector = document.getElementById('theme-selector')!
|
||||
const treeViewEl = document.getElementById('tree-view')!
|
||||
const sourceViewEl = document.getElementById('source-view')!
|
||||
const errorsViewEl = document.getElementById('errors-view')!
|
||||
const errorsToggle = document.getElementById('errors-toggle')!
|
||||
const sourceViewOutput = (document.getElementById('source-view-output') as HTMLTextAreaElement)
|
||||
const sourceControlsToggle = document.getElementById('source-controls-toggle')!
|
||||
const sourceControlsMenu = document.getElementById('source-controls-menu')!
|
||||
@@ -86,8 +95,14 @@ Promise.all([
|
||||
}
|
||||
|
||||
const views: { [key: string]: IView } = {
|
||||
'tree': new TreeView(models[selected], treeViewEl),
|
||||
'source': new SourceView(models[selected], sourceViewOutput, {indentation: 2})
|
||||
'tree': new TreeView(models[selected], treeViewEl, {
|
||||
showErrors: true,
|
||||
observer: treeViewObserver
|
||||
}),
|
||||
'source': new SourceView(models[selected], sourceViewOutput, {
|
||||
indentation: 2
|
||||
}),
|
||||
'errors': new ErrorsView(models[selected], errorsViewEl)
|
||||
}
|
||||
|
||||
const updateModel = (newModel: string) => {
|
||||
@@ -208,5 +223,15 @@ Promise.all([
|
||||
downloadAnchor.click()
|
||||
})
|
||||
|
||||
errorsToggle.addEventListener('click', evt => {
|
||||
if (errorsViewEl.classList.contains('hidden')) {
|
||||
errorsViewEl.classList.remove('hidden')
|
||||
errorsToggle.classList.remove('toggled')
|
||||
} else {
|
||||
errorsViewEl.classList.add('hidden')
|
||||
errorsToggle.classList.add('toggled')
|
||||
}
|
||||
})
|
||||
|
||||
document.body.style.visibility = 'initial'
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="header-title">
|
||||
<h2 id="selected-model">Loot Table Generator</h2>
|
||||
<h2 id="selected-model"></h2>
|
||||
<div class="nav-selector">
|
||||
<svg id="model-selector" class="btn model-selector" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="32" height="32"><path fill-rule="evenodd" d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"></path></svg>
|
||||
<div class="nav-selector-menu btn-group" id="model-selector-menu"></div>
|
||||
@@ -61,6 +61,13 @@
|
||||
<textarea id="source-view-output" spellcheck="false" autocorrect="off" autocapitalize="off"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="errors-view" class="errors" style="display: none;">
|
||||
<div class="error-list"></div>
|
||||
<div id="errors-toggle" class="toggle">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="24" height="24"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9 3a1 1 0 11-2 0 1 1 0 012 0zm-.25-6.25a.75.75 0 00-1.5 0v3.5a.75.75 0 001.5 0v-3.5z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="32" height="32"><path fill-rule="evenodd" d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -111,6 +111,7 @@ body {
|
||||
-o-tab-size: 4;
|
||||
-webkit-tab-size: 4;
|
||||
outline: none;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.source-controls {
|
||||
@@ -168,6 +169,41 @@ body {
|
||||
border-top-left-radius: 0px;
|
||||
}
|
||||
|
||||
.errors {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 17px;
|
||||
margin: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.errors.hidden .error-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.error span {
|
||||
padding-left: 11px;
|
||||
}
|
||||
|
||||
.errors .toggle {
|
||||
padding: 2px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
align-self: flex-end;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.errors .toggle.toggled {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
body {
|
||||
overflow-y: hidden;
|
||||
@@ -293,6 +329,12 @@ body {
|
||||
background-color: #5d5f5fa6;
|
||||
}
|
||||
|
||||
.errors {
|
||||
background-color: #f13000c5;
|
||||
color: #000000cc;
|
||||
fill: #000000cc;
|
||||
}
|
||||
|
||||
/* DARK MODE */
|
||||
|
||||
body[data-style=dark] .container,
|
||||
@@ -350,3 +392,9 @@ body[data-style=dark] .btn.selected {
|
||||
body[data-style=dark] .btn:hover {
|
||||
background-color: #383838a6;
|
||||
}
|
||||
|
||||
body[data-style=dark] .errors {
|
||||
background-color: #f13000c5;
|
||||
color: #ffffffcc;
|
||||
fill: #ffffffcc;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
.node-header > *:last-child {
|
||||
.node-header > *:last-child,
|
||||
.node-header[data-error] > *:nth-last-child(2) {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
@@ -120,6 +121,13 @@ button.remove::before {
|
||||
content: url('./images/trash.svg');
|
||||
}
|
||||
|
||||
.node-header[data-error] > svg {
|
||||
border: none;
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.node-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -175,6 +183,10 @@ button.remove {
|
||||
background-color: #e76f51;
|
||||
}
|
||||
|
||||
.node-header[data-error] > svg {
|
||||
fill: #e76f51;
|
||||
}
|
||||
|
||||
.node-body {
|
||||
border-color: #b9b9b9 !important;
|
||||
transition: border-color var(--style-transition);
|
||||
@@ -239,6 +251,10 @@ body[data-style=dark] button.remove {
|
||||
background-color: #b64023;
|
||||
}
|
||||
|
||||
body[data-style=dark] .node-header[data-error] > svg {
|
||||
fill: #b64023;
|
||||
}
|
||||
|
||||
body[data-style=dark] .node-body {
|
||||
border-color: #454749 !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user