Add field settings

This commit is contained in:
Misode
2020-12-17 22:09:09 +01:00
parent acb6978d48
commit 6a3c7aac42
11 changed files with 232 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
import { CollectionRegistry, DataModel, ObjectNode, PathError, SchemaRegistry } from '@mcschema/core';
import { CollectionRegistry, DataModel, ObjectNode, SchemaRegistry } from '@mcschema/core';
import * as java16 from '@mcschema/java-1.16'
import * as java17 from '@mcschema/java-1.17'
import { LocalStorageProperty } from './state/LocalStorageProperty';
@@ -11,6 +11,7 @@ import { DecoratorPreview } from './preview/DecoratorPreview';
import config from '../config.json';
import { locale, Locales } from './Locales';
import { Tracker } from './Tracker';
import { Settings } from './Settings';
const Versions: {
[versionId: string]: {
@@ -54,6 +55,7 @@ export const App = {
localesLoaded: new Property(false),
loaded: new Property(false),
mobilePanel: new Property('tree'),
settings: new Settings('generator_settings')
}
App.version.watchRun(async (value) => {

View File

@@ -1,6 +1,7 @@
import { App, Models } from './App';
import { View } from './views/View';
import { Home } from './views/Home'
import { FieldSettings } from './views/FieldSettings'
import { Generator } from './views/Generator'
import { locale } from './Locales';
import { Tracker } from './Tracker';
@@ -19,6 +20,8 @@ const router = async () => {
if (urlParts.length === 0){
App.model.set({ id: '', name: 'Data Pack', category: true})
target.innerHTML = Home(view)
} else if (urlParts[0] === 'settings' && urlParts[1] === 'fields') {
target.innerHTML = FieldSettings(view)
} else if (urlParts.length === 1 && categories.map(m => m.id).includes(urlParts[0])) {
App.model.set(categories.find(m => m.id === urlParts[0])!)
target.innerHTML = Home(view)

22
src/app/Settings.ts Normal file
View File

@@ -0,0 +1,22 @@
type FieldSetting = {
path?: string
name?: string
hidden?: boolean
}
export class Settings {
fields: FieldSetting[]
constructor(private local_storage: string) {
const settings = JSON.parse(localStorage.getItem(local_storage) ?? '{}')
if (!Array.isArray(settings.fields)) settings.fields = []
this.fields = settings.fields
this.save()
}
save() {
const settings = JSON.stringify({ fields: this.fields })
localStorage.setItem(this.local_storage, settings)
this.fields = [...this.fields.filter(v => v?.path), {}]
}
}

View File

@@ -17,6 +17,11 @@ export const Header = (view: View, title: string, homeLink = '/', panelToggleVis
<ul>
<li>${Dropdown(view, 'globe', languages.map(l => [l.code, l.name]), App.language, Tracker.setLanguage)}</li>
<li>${Toggle(view, [['dark', 'sun'], ['light', 'moon']], App.theme, Tracker.setTheme)}</li>
<li>
<a data-link href="/settings/fields/">
${Octicon.gear}
</a>
</li>
<li class="dimmed">
<a href="https://github.com/misode/misode.github.io" target="_blank">
${Octicon.mark_github}

View File

@@ -8,6 +8,8 @@ export const Octicon = {
code: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4.72 3.22a.75.75 0 011.06 1.06L2.06 8l3.72 3.72a.75.75 0 11-1.06 1.06L.47 8.53a.75.75 0 010-1.06l4.25-4.25zm6.56 0a.75.75 0 10-1.06 1.06L13.94 8l-3.72 3.72a.75.75 0 101.06 1.06l4.25-4.25a.75.75 0 000-1.06l-4.25-4.25z"></path></svg>',
dash: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2 8a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 8z"></path></svg>',
download: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.47 10.78a.75.75 0 001.06 0l3.75-3.75a.75.75 0 00-1.06-1.06L8.75 8.44V1.75a.75.75 0 00-1.5 0v6.69L4.78 5.97a.75.75 0 00-1.06 1.06l3.75 3.75zM3.75 13a.75.75 0 000 1.5h8.5a.75.75 0 000-1.5h-8.5z"></path></svg>',
eye: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path></svg>',
eye_closed: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M.143 2.31a.75.75 0 011.047-.167l14.5 10.5a.75.75 0 11-.88 1.214l-2.248-1.628C11.346 13.19 9.792 14 8 14c-1.981 0-3.67-.992-4.933-2.078C1.797 10.832.88 9.577.43 8.9a1.618 1.618 0 010-1.797c.353-.533.995-1.42 1.868-2.305L.31 3.357A.75.75 0 01.143 2.31zm3.386 3.378a14.21 14.21 0 00-1.85 2.244.12.12 0 00-.022.068c0 .021.006.045.022.068.412.621 1.242 1.75 2.366 2.717C5.175 11.758 6.527 12.5 8 12.5c1.195 0 2.31-.488 3.29-1.191L9.063 9.695A2 2 0 016.058 7.52l-2.53-1.832zM8 3.5c-.516 0-1.017.09-1.499.251a.75.75 0 11-.473-1.423A6.23 6.23 0 018 2c1.981 0 3.67.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.619 1.619 0 010 1.798c-.11.166-.248.365-.41.587a.75.75 0 11-1.21-.887c.148-.201.272-.382.371-.53a.119.119 0 000-.137c-.412-.621-1.242-1.75-2.366-2.717C10.825 4.242 9.473 3.5 8 3.5z"></path></svg>',
gear: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.429 1.525a6.593 6.593 0 011.142 0c.036.003.108.036.137.146l.289 1.105c.147.56.55.967.997 1.189.174.086.341.183.501.29.417.278.97.423 1.53.27l1.102-.303c.11-.03.175.016.195.046.219.31.41.641.573.989.014.031.022.11-.059.19l-.815.806c-.411.406-.562.957-.53 1.456a4.588 4.588 0 010 .582c-.032.499.119 1.05.53 1.456l.815.806c.08.08.073.159.059.19a6.494 6.494 0 01-.573.99c-.02.029-.086.074-.195.045l-1.103-.303c-.559-.153-1.112-.008-1.529.27-.16.107-.327.204-.5.29-.449.222-.851.628-.998 1.189l-.289 1.105c-.029.11-.101.143-.137.146a6.613 6.613 0 01-1.142 0c-.036-.003-.108-.037-.137-.146l-.289-1.105c-.147-.56-.55-.967-.997-1.189a4.502 4.502 0 01-.501-.29c-.417-.278-.97-.423-1.53-.27l-1.102.303c-.11.03-.175-.016-.195-.046a6.492 6.492 0 01-.573-.989c-.014-.031-.022-.11.059-.19l.815-.806c.411-.406.562-.957.53-1.456a4.587 4.587 0 010-.582c.032-.499-.119-1.05-.53-1.456l-.815-.806c-.08-.08-.073-.159-.059-.19a6.44 6.44 0 01.573-.99c.02-.029.086-.075.195-.045l1.103.303c.559.153 1.112.008 1.529-.27.16-.107.327-.204.5-.29.449-.222.851-.628.998-1.189l.289-1.105c.029-.11.101-.143.137-.146zM8 0c-.236 0-.47.01-.701.03-.743.065-1.29.615-1.458 1.261l-.29 1.106c-.017.066-.078.158-.211.224a5.994 5.994 0 00-.668.386c-.123.082-.233.09-.3.071L3.27 2.776c-.644-.177-1.392.02-1.82.63a7.977 7.977 0 00-.704 1.217c-.315.675-.111 1.422.363 1.891l.815.806c.05.048.098.147.088.294a6.084 6.084 0 000 .772c.01.147-.038.246-.088.294l-.815.806c-.474.469-.678 1.216-.363 1.891.2.428.436.835.704 1.218.428.609 1.176.806 1.82.63l1.103-.303c.066-.019.176-.011.299.071.213.143.436.272.668.386.133.066.194.158.212.224l.289 1.106c.169.646.715 1.196 1.458 1.26a8.094 8.094 0 001.402 0c.743-.064 1.29-.614 1.458-1.26l.29-1.106c.017-.066.078-.158.211-.224a5.98 5.98 0 00.668-.386c.123-.082.233-.09.3-.071l1.102.302c.644.177 1.392-.02 1.82-.63.268-.382.505-.789.704-1.217.315-.675.111-1.422-.364-1.891l-.814-.806c-.05-.048-.098-.147-.088-.294a6.1 6.1 0 000-.772c-.01-.147.039-.246.088-.294l.814-.806c.475-.469.679-1.216.364-1.891a7.992 7.992 0 00-.704-1.218c-.428-.609-1.176-.806-1.82-.63l-1.103.303c-.066.019-.176.011-.299-.071a5.991 5.991 0 00-.668-.386c-.133-.066-.194-.158-.212-.224L10.16 1.29C9.99.645 9.444.095 8.701.031A8.094 8.094 0 008 0zm1.5 8a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM11 8a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>',
globe: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.543 7.25h2.733c.144-2.074.866-3.756 1.58-4.948.12-.197.237-.381.353-.552a6.506 6.506 0 00-4.666 5.5zm2.733 1.5H1.543a6.506 6.506 0 004.666 5.5 11.13 11.13 0 01-.352-.552c-.715-1.192-1.437-2.874-1.581-4.948zm1.504 0h4.44a9.637 9.637 0 01-1.363 4.177c-.306.51-.612.919-.857 1.215a9.978 9.978 0 01-.857-1.215A9.637 9.637 0 015.78 8.75zm4.44-1.5H5.78a9.637 9.637 0 011.363-4.177c.306-.51.612-.919.857-1.215.245.296.55.705.857 1.215A9.638 9.638 0 0110.22 7.25zm1.504 1.5c-.144 2.074-.866 3.756-1.58 4.948-.12.197-.237.381-.353.552a6.506 6.506 0 004.666-5.5h-2.733zm2.733-1.5h-2.733c-.144-2.074-.866-3.756-1.58-4.948a11.738 11.738 0 00-.353-.552 6.506 6.506 0 014.666 5.5zM8 0a8 8 0 100 16A8 8 0 008 0z"></path></svg>',
history: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.643 3.143L.427 1.927A.25.25 0 000 2.104V5.75c0 .138.112.25.25.25h3.646a.25.25 0 00.177-.427L2.715 4.215a6.5 6.5 0 11-1.18 4.458.75.75 0 10-1.493.154 8.001 8.001 0 101.6-5.684zM7.75 4a.75.75 0 01.75.75v2.992l2.028.812a.75.75 0 01-.557 1.392l-2.5-1A.75.75 0 017 8.25v-3.5A.75.75 0 017.75 4z"></path></svg>',

View File

@@ -84,6 +84,9 @@ export const TreePanel = (view: View, model: DataModel) => {
<div class="btn" data-id="${view.onClick(() => {Tracker.redo(); model.redo()})}">
${Octicon.arrow_right}<span data-i18n="redo"></span>
</div>
<div class="btn">
${Octicon.gear}<a data-link href="/settings/fields/" data-i18n="fields"></a>
</div>
</div>
</div>
</div>

View File

@@ -4,6 +4,7 @@ import { Mounter } from '../views/View'
import { hexId, htmlEncode } from '../Utils'
import { suffixInjector } from './suffixInjector'
import { Octicon } from '../components/Octicon'
import { App } from '../App'
/**
* Secondary model used to remember the keys of a map
@@ -167,8 +168,11 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = {
.filter(k => activeFields[k].enabled(path))
.map(k => {
const field = activeFields[k]
if (field.hidden && field.hidden()) return ''
const childPath = getChildModelPath(path, k)
const context = childPath.getContext().join('.')
const fieldSettings = App.settings.fields.find(f => f?.path && context.endsWith(f.path))
if ((field.hidden && field.hidden()) || fieldSettings?.hidden) return ''
const category = field.category(childPath)
const [cPrefix, cSuffix, cBody] = field.hook(this, childPath, value[k], mounter)
return `<div class="node ${field.type(childPath)}-node" ${category ? `data-category="${htmlEncode(category)}"` : ''}>
@@ -176,7 +180,7 @@ export const renderHtml: Hook<[any, Mounter], [string, string, string]> = {
${error(childPath, mounter)}
${help(childPath, mounter)}
${cPrefix}
<label>${htmlEncode(pathLocale(childPath))}</label>
<label>${htmlEncode(fieldSettings?.name ?? pathLocale(childPath))}</label>
${cSuffix}
</div>
${cBody ? `<div class="node-body">${cBody}</div>` : ''}

View File

@@ -0,0 +1,59 @@
import { App } from '../App'
import { Header } from '../components/Header'
import { Octicon } from '../components/Octicon'
import { View } from './View'
export const FieldSettings = (view: View): string => {
const fieldListId = view.register(fieldList => {
const getFields = () => {
const fields = App.settings.fields
return fields.map((f, i) => {
const pathInput = view.register(el => {
(el as HTMLInputElement).value = f.path ?? ''
el.addEventListener('change', () => {
fields[i] = {...f, path: (el as HTMLSelectElement).value}
App.settings.save()
view.mount(fieldList, getFields(), false)
})
})
const nameInput = view.register(el => {
(el as HTMLInputElement).value = f.name ?? ''
el.addEventListener('change', () => {
fields[i] = {...f, name: (el as HTMLSelectElement).value}
App.settings.save()
view.mount(fieldList, getFields(), false)
})
})
return `<li>
<div class="field-prop">
<label>Path</label><input size="30" data-id="${pathInput}">
</div>
<div class="field-prop">
<label>Name</label><input data-id="${nameInput}">
</div>
<div class="field-prop">
<span ${f?.hidden ? 'class="hidden"' : ''} data-id="${view.onClick(() => {
fields[i].hidden = f?.hidden ? undefined : true
App.settings.save()
view.mount(fieldList, getFields(), false)
})}">${f.hidden ? Octicon.eye_closed : Octicon.eye}</span>
<span class="dimmed" data-id="${view.onClick(() => {
fields.splice(i, 1)
App.settings.save()
view.mount(fieldList, getFields(), false)
})}">${Octicon.trashcan}</span>
</div>
</li>`
}).join('')
}
view.mount(fieldList, getFields(), false)
})
return `${Header(view, 'Field Settings')}
<div class="settings">
<p>
Customize advanced field settings
</p>
<ul class="field-list" data-id="${fieldListId}"></ul>
</div>`
}

View File

@@ -4,6 +4,7 @@
"dimension-type": "Dimension Type",
"dimension": "Dimension",
"download": "Download",
"fields": "Fields",
"item-modifier": "Item Modifier",
"language": "Language",
"loot-table": "Loot Table",

View File

@@ -57,7 +57,7 @@ header {
padding: 10px;
height: 56px;
border-bottom: 2px solid var(--border);
transition: border-color var(--style-transition);
transition: border-color var(--style-transition), background-color var(--style-transition);
}
.header-title {
@@ -356,6 +356,11 @@ nav > .toggle span {
width: 100px;
}
.btn a {
color: var(--btn-text);
text-decoration: none;
}
.errors {
position: fixed;
display: flex;
@@ -437,6 +442,85 @@ nav > .toggle span {
margin-left: 10px;
}
.settings {
padding: 20px;
}
.settings p {
color: var(--nav);
padding: 8px;
border-bottom: 2px solid var(--border);
transition: border-color var(--style-transition), color var(--style-transition);
}
.field-list {
width: 100%;
border-collapse: collapse;
list-style-type: none;
}
.field-list li {
display: flex;
justify-content: space-between;
padding: 4px 0;
border-bottom: 1px solid var(--border);
transition: border-color var(--style-transition);
}
.field-prop {
display: inline-flex;
align-items: center;
max-width: 100%;
margin: 4px;
}
.field-prop > label,
.field-prop > input {
height: 34px;
color: var(--text);
margin-right: -1px;
border: 1px solid;
border-color: var(--nav-faded-hover);
transition: all var(--style-transition);
}
.field-prop label {
padding: 0 9px;
line-height: 1.94rem;
background-color: var(--node-background-label);
white-space: nowrap;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.field-prop input {
width: 100%;
line-height: 1.6rem;
background-color: var(--node-background-input);
color: var(--text);
padding-left: 9px;
font-size: 18px;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.field-prop svg {
padding: 4px;
margin: 0 4px;
height: 28px;
width: 28px;
fill: var(--nav);
cursor: pointer;
}
.field-prop .hidden svg {
fill: #be4b2e;
}
.field-prop .dimmed svg {
fill: var(--nav-faded);
}
.spinner {
margin: 40px auto 0;
width: 80px;
@@ -475,26 +559,37 @@ nav > .toggle span {
}
@media screen and (max-width: 580px) {
body {
overflow-y: hidden;
}
header {
flex-direction: column;
height: 92px;
width: 100%;
background-color: var(--background);
z-index: 5;
position: fixed;
}
nav {
align-self: flex-end;
}
.content,
.source textarea {
height: calc(100vh - 92px);
.home,
.settings,
.content {
padding-top: 92px;
}
.content {
height: unset;
/* min-height: calc(100vh - 92px); */
min-height: 100%;
}
textarea.source {
height: calc(100vh - 98px);
}
.tree {
padding-top: 50px;
padding-top: 44px;
}
.tree-panel + .gutter {
@@ -506,6 +601,12 @@ nav > .toggle span {
width: 100% !important;
}
.tree-panel .panel-controls {
top: 97px;
right: 5px;
position: fixed;
}
nav > .toggle {
display: flex;
position: absolute;
@@ -521,9 +622,21 @@ nav > .toggle span {
}
.home {
padding: 5px;
padding: 117px 5px 5px;
justify-content: center;
}
.field-list li {
flex-direction: column;
}
.field-prop {
width: 100%;
}
.field-prop input {
width: 100%;
}
}
@media screen and (max-width: 480px) {

View File

@@ -42,6 +42,11 @@ module.exports = (env, argv) => ({
filename: 'index.html',
template: 'src/index.html'
}),
new HtmlWebpackPlugin({
title: 'Data Pack Generators Minecraft 1.16, 1.17',
filename: 'settings/fields/index.html',
template: 'src/index.html'
}),
new HtmlWebpackPlugin({
title: 'Data Pack Generators Minecraft 1.16, 1.17',
filename: '404.html',