mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-30 09:42:44 +00:00
Add homepage
This commit is contained in:
@@ -1,19 +1,14 @@
|
||||
import { IView, locale, DataModel, ModelListener } from "minecraft-schemas";
|
||||
import { locale, DataModel, ModelListener } from "minecraft-schemas";
|
||||
import { Errors } from "minecraft-schemas/lib/model/Errors";
|
||||
|
||||
export class ErrorsView implements ModelListener, IView {
|
||||
export class ErrorsView implements ModelListener {
|
||||
model: DataModel
|
||||
target: HTMLElement
|
||||
|
||||
constructor(model: DataModel, target: HTMLElement) {
|
||||
this.model = model
|
||||
this.target = target
|
||||
}
|
||||
|
||||
setModel(newModel: DataModel) {
|
||||
this.model.removeListener(this)
|
||||
this.model = newModel
|
||||
this.model.addListener(this)
|
||||
model.addListener(this)
|
||||
}
|
||||
|
||||
errors(errors: Errors): void {
|
||||
|
||||
114
src/app/app.ts
114
src/app/app.ts
@@ -1,7 +1,6 @@
|
||||
import Split from 'split.js'
|
||||
import {
|
||||
DataModel,
|
||||
IView,
|
||||
TreeView,
|
||||
SourceView,
|
||||
ConditionSchema,
|
||||
@@ -11,7 +10,8 @@ import {
|
||||
DimensionTypeSchema,
|
||||
LOCALES,
|
||||
locale,
|
||||
COLLECTIONS
|
||||
COLLECTIONS,
|
||||
ModelListener
|
||||
} from 'minecraft-schemas'
|
||||
import { RegistryFetcher } from './RegistryFetcher'
|
||||
import { SandboxSchema } from './Sandbox'
|
||||
@@ -19,6 +19,8 @@ import { ErrorsView } from './ErrorsView'
|
||||
|
||||
const LOCAL_STORAGE_THEME = 'theme'
|
||||
|
||||
const publicPath = process.env.NODE_ENV === 'production' ? '/dev/' : '/';
|
||||
|
||||
const modelFromPath = (p: string) => p.split('/').filter(e => e.length !== 0).pop() ?? ''
|
||||
|
||||
const addChecked = (el: HTMLElement) => {
|
||||
@@ -35,6 +37,15 @@ const languages: { [key: string]: string } = {
|
||||
'zh-CN': '简体中文'
|
||||
}
|
||||
|
||||
const models: { [key: string]: DataModel } = {
|
||||
'loot-table': new DataModel(LootTableSchema),
|
||||
'predicate': new DataModel(ConditionSchema),
|
||||
'advancement': new DataModel(AdvancementSchema),
|
||||
'dimension': new DataModel(DimensionSchema),
|
||||
'dimension-type': new DataModel(DimensionTypeSchema),
|
||||
'sandbox': new DataModel(SandboxSchema)
|
||||
}
|
||||
|
||||
const registries = [
|
||||
'attribute',
|
||||
'biome',
|
||||
@@ -60,12 +71,9 @@ const treeViewObserver = (el: HTMLElement) => {
|
||||
e.insertAdjacentHTML('afterbegin', `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"></path></svg>`)
|
||||
})
|
||||
el.querySelectorAll('.collapse.open, button.remove').forEach(e => {
|
||||
e.insertAdjacentHTML('afterbegin', `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.5 1.75a.25.25 0 01.25-.25h2.5a.25.25 0 01.25.25V3h-3V1.75zm4.5 0V3h2.25a.75.75 0 010 1.5H2.75a.75.75 0 010-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75zM4.496 6.675a.75.75 0 10-1.492.15l.66 6.6A1.75 1.75 0 005.405 15h5.19c.9 0 1.652-.681 1.741-1.576l.66-6.6a.75.75 0 00-1.492-.149l-.66 6.6a.25.25 0 01-.249.225h-5.19a.25.25 0 01-.249-.225l-.66-6.6z"></path></svg>
|
||||
`)
|
||||
e.insertAdjacentHTML('afterbegin', `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.5 1.75a.25.25 0 01.25-.25h2.5a.25.25 0 01.25.25V3h-3V1.75zm4.5 0V3h2.25a.75.75 0 010 1.5H2.75a.75.75 0 010-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75zM4.496 6.675a.75.75 0 10-1.492.15l.66 6.6A1.75 1.75 0 005.405 15h5.19c.9 0 1.652-.681 1.741-1.576l.66-6.6a.75.75 0 00-1.492-.149l-.66 6.6a.25.25 0 01-.249.225h-5.19a.25.25 0 01-.249-.225l-.66-6.6z"></path></svg>`)
|
||||
})
|
||||
}
|
||||
|
||||
const publicPath = process.env.NODE_ENV === 'production' ? '/dev/' : '/';
|
||||
Promise.all([
|
||||
fetch(publicPath + 'locales/schema/en.json').then(r => r.json()),
|
||||
fetch(publicPath + 'locales/app/en.json').then(r => r.json()),
|
||||
@@ -73,6 +81,8 @@ Promise.all([
|
||||
]).then(responses => {
|
||||
LOCALES.register('en', {...responses[0], ...responses[1]})
|
||||
|
||||
const homeLink = document.getElementById('home-link')!
|
||||
const homeGenerators = document.getElementById('home-generators')!
|
||||
const selectedModel = document.getElementById('selected-model')!
|
||||
const modelSelector = document.getElementById('model-selector')!
|
||||
const modelSelectorMenu = document.getElementById('model-selector-menu')!
|
||||
@@ -82,6 +92,7 @@ Promise.all([
|
||||
const treeViewEl = document.getElementById('tree-view')!
|
||||
const sourceViewEl = document.getElementById('source-view')!
|
||||
const errorsViewEl = document.getElementById('errors-view')!
|
||||
const homeViewEl = document.getElementById('home-view')!
|
||||
const errorsToggle = document.getElementById('errors-toggle')!
|
||||
const sourceViewOutput = (document.getElementById('source-view-output') as HTMLTextAreaElement)
|
||||
const treeViewOutput = document.getElementById('tree-view-output')!
|
||||
@@ -98,48 +109,33 @@ Promise.all([
|
||||
const treeControlsUndo = document.getElementById('tree-controls-undo')!
|
||||
const treeControlsRedo = document.getElementById('tree-controls-redo')!
|
||||
|
||||
let selected = modelFromPath(location.pathname)
|
||||
if (selected.length === 0) {
|
||||
selected = 'loot-table'
|
||||
}
|
||||
let selected = ''
|
||||
|
||||
const models: { [key: string]: DataModel } = {
|
||||
'loot-table': new DataModel(LootTableSchema),
|
||||
'predicate': new DataModel(ConditionSchema),
|
||||
'advancement': new DataModel(AdvancementSchema),
|
||||
'dimension': new DataModel(DimensionSchema),
|
||||
'dimension-type': new DataModel(DimensionTypeSchema),
|
||||
'sandbox': new DataModel(SandboxSchema)
|
||||
}
|
||||
const updateModel = () => {
|
||||
if (models[selected] === undefined) {
|
||||
selectedModel.textContent = locale(`title.home`)
|
||||
} else {
|
||||
selectedModel.textContent = locale(`title.${selected}`)
|
||||
new TreeView(models[selected], treeViewOutput, {
|
||||
showErrors: true,
|
||||
observer: treeViewObserver
|
||||
}),
|
||||
new SourceView(models[selected], sourceViewOutput, {
|
||||
indentation: 2
|
||||
}),
|
||||
new ErrorsView(models[selected], errorsViewEl)
|
||||
|
||||
const views: IView[] = [
|
||||
new TreeView(models[selected], treeViewOutput, {
|
||||
showErrors: true,
|
||||
observer: treeViewObserver
|
||||
}),
|
||||
new SourceView(models[selected], sourceViewOutput, {
|
||||
indentation: 2
|
||||
}),
|
||||
new ErrorsView(models[selected], errorsViewEl)
|
||||
]
|
||||
models[selected].invalidate()
|
||||
}
|
||||
|
||||
const updateModel = (newModel: string) => {
|
||||
selected = newModel
|
||||
views.forEach(v => v.setModel(models[selected]))
|
||||
selectedModel.textContent = locale(`title.${selected}`)
|
||||
|
||||
modelSelectorMenu.innerHTML = ''
|
||||
Object.keys(models).forEach(m => {
|
||||
modelSelectorMenu.insertAdjacentHTML('beforeend',
|
||||
`<div class="btn${m === selected ? ' selected' : ''}">${locale(m)}</div>`)
|
||||
modelSelectorMenu.lastChild?.addEventListener('click', evt => {
|
||||
updateModel(m)
|
||||
history.pushState({model: m}, m, publicPath + m)
|
||||
modelSelectorMenu.style.visibility = 'hidden'
|
||||
reload(publicPath + m)
|
||||
})
|
||||
})
|
||||
|
||||
models[selected].invalidate()
|
||||
}
|
||||
|
||||
const updateLanguage = (key: string) => {
|
||||
@@ -159,14 +155,17 @@ Promise.all([
|
||||
})
|
||||
})
|
||||
|
||||
updateModel(selected)
|
||||
updateModel()
|
||||
}
|
||||
updateLanguage('en')
|
||||
|
||||
Split([treeViewEl, sourceViewEl], {
|
||||
sizes: [66, 34]
|
||||
})
|
||||
|
||||
homeLink.addEventListener('click', evt => {
|
||||
reload(publicPath)
|
||||
})
|
||||
|
||||
modelSelector.addEventListener('click', evt => {
|
||||
modelSelectorMenu.style.visibility = 'visible'
|
||||
document.body.addEventListener('click', evt => {
|
||||
@@ -175,7 +174,7 @@ Promise.all([
|
||||
})
|
||||
|
||||
window.onpopstate = (evt: PopStateEvent) => {
|
||||
updateModel(modelFromPath(location.pathname))
|
||||
reload(location.pathname)
|
||||
}
|
||||
|
||||
sourceToggle.addEventListener('click', evt => {
|
||||
@@ -284,5 +283,38 @@ Promise.all([
|
||||
}
|
||||
})
|
||||
|
||||
const reload = (target: string) => {
|
||||
selected = modelFromPath(target) ?? ''
|
||||
if (target) {
|
||||
history.pushState(target, 'Change Page', target)
|
||||
}
|
||||
|
||||
const panels = [treeViewEl, sourceViewEl, errorsViewEl]
|
||||
if (models[selected] === undefined) {
|
||||
homeViewEl.style.display = '';
|
||||
(document.querySelector('.gutter') as HTMLElement).style.display = 'none'
|
||||
modelSelector.style.display = 'none'
|
||||
panels.forEach(v => v.style.display = 'none')
|
||||
homeGenerators.innerHTML = ''
|
||||
Object.keys(models).forEach(m => {
|
||||
homeGenerators.insertAdjacentHTML('beforeend',
|
||||
`<div class="home-generator-card">
|
||||
${locale(m)}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.22 3.22a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 010-1.06z"></path></svg>
|
||||
</div>`)
|
||||
homeGenerators.lastChild?.addEventListener('click', evt => {
|
||||
reload(publicPath + m)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
homeViewEl.style.display = 'none';
|
||||
(document.querySelector('.gutter') as HTMLElement).style.display = ''
|
||||
modelSelector.style.display = ''
|
||||
panels.forEach(v => v.style.display = '')
|
||||
}
|
||||
updateModel()
|
||||
updateLanguage('en')
|
||||
}
|
||||
reload(location.pathname)
|
||||
document.body.style.visibility = 'initial'
|
||||
})
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="header-title">
|
||||
<div id="home-link" class="nav-item">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="24" height="24"><path fill-rule="evenodd" d="M8.156 1.835a.25.25 0 00-.312 0l-5.25 4.2a.25.25 0 00-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 01.75-.75h3.5a.75.75 0 01.75.75v5.25h2.75a.25.25 0 00.25-.25V6.23a.25.25 0 00-.094-.195l-5.25-4.2zM6.906.664a1.75 1.75 0 012.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0113.25 15h-3.5a.75.75 0 01-.75-.75V9H7v5.25a.75.75 0 01-.75.75h-3.5A1.75 1.75 0 011 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2h-.001z"></path></svg>
|
||||
</div>
|
||||
<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>
|
||||
@@ -31,9 +34,7 @@
|
||||
<svg id="theme-selection-dark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="24" height="24"><path fill-rule="evenodd" d="M9.598 1.591a.75.75 0 01.785-.175 7 7 0 11-8.967 8.967.75.75 0 01.961-.96 5.5 5.5 0 007.046-7.046.75.75 0 01.175-.786zm1.616 1.945a7 7 0 01-7.678 7.678 5.5 5.5 0 107.678-7.678z"></path></svg>
|
||||
</div>
|
||||
<div id="github-link" class="nav-item">
|
||||
<a href="https://github.com/misode/minecraft-schemas" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="24" height="24"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||
</a>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="24" height="24"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,8 +95,11 @@
|
||||
</div>
|
||||
<textarea id="source-view-output" spellcheck="false" autocorrect="off" autocapitalize="off"></textarea>
|
||||
</div>
|
||||
<div id="home-view" class="home">
|
||||
<div id="home-generators" class="home-generators"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="errors-view" class="errors" style="display: none;">
|
||||
<div id="errors-view" class="errors">
|
||||
<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>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"title.home": "Minecraft Generators",
|
||||
"title.loot-table": "Loot Table Generator",
|
||||
"title.predicate": "Predicate Generator",
|
||||
"title.advancement": "Advancement Generator",
|
||||
|
||||
@@ -74,6 +74,10 @@ body {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.header-title .nav-item {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -294,6 +298,39 @@ body {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.home {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.home-generators {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.home-generator-card {
|
||||
margin: 5px 0;
|
||||
padding: 8px 15px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border-radius: 3px;
|
||||
background-color: var(--nav-faded);
|
||||
color: var(--text);
|
||||
fill: var(--text);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.home-generator-card:hover {
|
||||
background-color: var(--nav-faded-hover);
|
||||
}
|
||||
|
||||
.home-generator-card svg {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
body {
|
||||
overflow-y: hidden;
|
||||
@@ -352,7 +389,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 410px) {
|
||||
.header-title h2 {
|
||||
font-size: 18px;
|
||||
|
||||
Reference in New Issue
Block a user