Default types and templates
This commit is contained in:
parent
8fb7494464
commit
a7337bd33a
@ -1,8 +1,6 @@
|
||||
import { FC, useCallback, useEffect } from 'react'
|
||||
import { FieldType, FieldTypes, fieldTypeOptions, fieldTypesWithValues } from '../../types/schema'
|
||||
import { useObjectStateWrapper } from '../../hooks/useObjectState';
|
||||
import { FieldTypeInput } from './field-type-input';
|
||||
import { InputBinder } from '../../types/inputBinder';
|
||||
import { ValueField } from './value-field';
|
||||
import { HelpPopper } from '../Poppables/help';
|
||||
|
||||
@ -13,7 +11,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
export const FieldEditor: FC<IProps> = ({ update, field, fieldName }) => {
|
||||
const { update: updateField, bindProperty, bindPropertyCheck } = useObjectStateWrapper(field, (e) => update(typeof e === 'function' ? e(field) : e))
|
||||
const { bindProperty, bindPropertyCheck } = useObjectStateWrapper(field, (e) => update(typeof e === 'function' ? e(field) : e))
|
||||
|
||||
const shouldShowValueField = useCallback(() => fieldTypesWithValues.includes(field.type) || field.isConstant, [field.isConstant, field.type]);
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { useRecoilValue } from 'recoil';
|
||||
import { SchemaEditAtom } from '../../recoil/atoms/schema';
|
||||
import { FCC } from '../../types'
|
||||
import { InputBinder } from '../../types/inputBinder'
|
||||
import { TEMPLATE_TYPES } from '../../constants/TemplateTypes';
|
||||
|
||||
interface IProps {
|
||||
bind: InputBinder
|
||||
@ -11,13 +12,17 @@ export const FieldTypeInput: FCC<IProps> = ({ bind }) => {
|
||||
const Schema = useRecoilValue(SchemaEditAtom);
|
||||
|
||||
return (
|
||||
<>
|
||||
<label className="w-min">
|
||||
Type:
|
||||
<input type="text" {...bind} list="type-editor-type-list" />
|
||||
<optgroup id="type-editor-type-list">
|
||||
<datalist id="type-editor-type-list">
|
||||
{Object.keys(TEMPLATE_TYPES).map(k => (
|
||||
<option className="capitalize" value={k}>{k}</option>
|
||||
))}
|
||||
{Object.keys(Schema.types).map(k => (
|
||||
<option className="capitalize" value={k}>{k}</option>
|
||||
))}
|
||||
</optgroup>
|
||||
</>
|
||||
</datalist>
|
||||
</label>
|
||||
)
|
||||
}
|
@ -2,12 +2,13 @@ import { FC, useCallback, useEffect, useState } from 'react'
|
||||
import AnimatedPageContainer from '../AnimatedPageContainer';
|
||||
import { TypeEditor } from './type-editor';
|
||||
import { useObjectState, useObjectStateWrapper } from '../../hooks/useObjectState';
|
||||
import { Schema, TypeType } from '../../types/schema';
|
||||
import { FieldTypes, Schema, Template, TypeType } from '../../types/schema';
|
||||
import { useInput } from '../../hooks/useInput';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { SchemaEditAtom } from '../../recoil/atoms/schema';
|
||||
import { GameSystemsService } from '../../services/game-systems';
|
||||
import { SchemaViewer } from './schema-viewer';
|
||||
import { TemplateEditor } from './template-editor';
|
||||
|
||||
|
||||
export const SchemaBuilder: FC = () => {
|
||||
@ -25,6 +26,7 @@ export const SchemaBuilder: FC = () => {
|
||||
if (result.status !== 200) return;
|
||||
const fetchedSchema = await result.json();
|
||||
// if (fetchedSchema.name === schema.name) return;
|
||||
if (!fetchedSchema.templates) fetchedSchema.templates = {}
|
||||
setSchema(fetchedSchema);
|
||||
setLastSaved(fetchedSchema);
|
||||
}, [setSchema])
|
||||
@ -58,12 +60,43 @@ export const SchemaBuilder: FC = () => {
|
||||
setPageNumber(1);
|
||||
}, [])
|
||||
|
||||
const { value: templateName, bind: bindTemplateName, reset: resetTemplateName } = useInput('');
|
||||
const addTemplate = useCallback(() => {
|
||||
updateSchema(s => ({
|
||||
templates: {
|
||||
...s.templates,
|
||||
[templateName]: {
|
||||
publishable: false,
|
||||
type: FieldTypes.any
|
||||
}
|
||||
}
|
||||
}));
|
||||
resetTemplateName();
|
||||
}, [resetTemplateName, templateName, updateSchema])
|
||||
|
||||
const updateTemplate = useCallback((key: string, template: Template) => {
|
||||
updateSchema(s => ({
|
||||
templates: {
|
||||
...s.templates,
|
||||
[key]: template
|
||||
}
|
||||
}))
|
||||
}, [updateSchema])
|
||||
|
||||
return (
|
||||
<div className="container flex gap-4 p-8">
|
||||
<div className="panel w-2/3 h-full">
|
||||
<p className="subheader">Add a template</p>
|
||||
<input type="text" {...bindTemplateName} />
|
||||
<button onClick={addTemplate} disabled={!templateName}>Add</button>
|
||||
<ul>
|
||||
{Object.entries(schema.templates).map(([templateKey, template]) => (
|
||||
<TemplateEditor templateKey={templateKey} template={template} update={updateTemplate} />
|
||||
))}
|
||||
</ul>
|
||||
<AnimatedPageContainer currentPage={pageNumber}>
|
||||
<div>
|
||||
<p className="subheader">Add A Type</p>
|
||||
<p className="subheader">Add a type</p>
|
||||
<input type="text" {...bindTypeName} />
|
||||
<button className="interactive" disabled={!typeName} onClick={() => setPageNumber(1)}>Configure</button>
|
||||
</div>
|
||||
|
@ -14,8 +14,8 @@ export const SchemaViewer: FC<IProps> = ({ schema, onTypeClick }) => {
|
||||
return 'Constant value:'
|
||||
}
|
||||
switch (field.type) {
|
||||
case FieldTypes.type: return 'Type'
|
||||
case FieldTypes.dice: return 'Dice'
|
||||
case FieldTypes.type: return 'Type:'
|
||||
case FieldTypes.dice: return 'Dice:'
|
||||
default: return '';
|
||||
}
|
||||
}, [])
|
||||
@ -25,6 +25,19 @@ export const SchemaViewer: FC<IProps> = ({ schema, onTypeClick }) => {
|
||||
{/* <div className="whitespace-pre-wrap">{JSON.stringify(schema, null, 2)}</div> */}
|
||||
<div>
|
||||
<p className="font-bold text-lg">{schema.name}</p>
|
||||
<hr />
|
||||
<p className="font-bold italic">Templates</p>
|
||||
<ul>
|
||||
{Object.entries(schema.templates).map(([templateKey, template]) => (
|
||||
<li>
|
||||
<p className="font-bold">{templateKey}</p>
|
||||
<p className="font-thin text-xs">{template.type}</p>
|
||||
{template.publishable && <p className="font-thin text-xs">This template can create publications</p>}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<hr />
|
||||
<p className="font-bold italic">Types</p>
|
||||
<ul className="rounded-lg overflow-hidden">
|
||||
{Object.entries(schema.types).map(([typeKey, type]) => (
|
||||
<li
|
||||
|
@ -0,0 +1,34 @@
|
||||
import { FC, useCallback } from 'react'
|
||||
import { Template } from '../../types/schema';
|
||||
import { useObjectStateWrapper } from '../../hooks/useObjectState';
|
||||
|
||||
interface IProps {
|
||||
templateKey: string;
|
||||
update: (arg0: string, arg1: Template) => void;
|
||||
template: Template
|
||||
}
|
||||
|
||||
export const TemplateEditor: FC<IProps> = ({ templateKey, update, template }) => {
|
||||
|
||||
const updateTemplate = useCallback((t: Template | ((arg: Template) => Template)) => {
|
||||
update(templateKey, typeof t === 'function' ? t(template) : t)
|
||||
}, [templateKey, update, template])
|
||||
|
||||
const { bindProperty, bindPropertyCheck } = useObjectStateWrapper(template, updateTemplate)
|
||||
|
||||
return (
|
||||
<li>
|
||||
<p className="font-bold">{templateKey}</p>
|
||||
<div className="flex gap-4">
|
||||
<label className="w-min">
|
||||
Type
|
||||
<input type="text" {...bindProperty('type')} />
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" {...bindPropertyCheck('publishable')} />
|
||||
Can create publications
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
}
|
@ -31,8 +31,9 @@ export const TypeEditor: FCC<IProps> = ({ saveType, name, type: passedType }) =>
|
||||
isConstant: false,
|
||||
limit: 1,
|
||||
}
|
||||
})
|
||||
}, [propertyName, updateType]);
|
||||
});
|
||||
resetPropertyName();
|
||||
}, [propertyName, updateType, resetPropertyName]);
|
||||
|
||||
const updateField = useCallback((k: keyof typeof type) => (field: FieldType) => {
|
||||
updateType({ [k]: field })
|
||||
|
70
project-warstone/src/constants/TemplateTypes.ts
Normal file
70
project-warstone/src/constants/TemplateTypes.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { FieldTypes, TypeType } from '../types/schema';
|
||||
|
||||
export const TEMPLATE_TYPES: Record<string, TypeType> = {
|
||||
section: {
|
||||
name: {
|
||||
isConstant: false,
|
||||
limit: 1,
|
||||
type: FieldTypes.text,
|
||||
value: ''
|
||||
},
|
||||
body: {
|
||||
isConstant: false,
|
||||
limit: 0,
|
||||
type: FieldTypes['long text'],
|
||||
value: ''
|
||||
},
|
||||
},
|
||||
steps: {
|
||||
steps: {
|
||||
isConstant: false,
|
||||
limit: 0,
|
||||
type: FieldTypes.type,
|
||||
value: 'section'
|
||||
}
|
||||
},
|
||||
image: {
|
||||
name: {
|
||||
isConstant: false,
|
||||
limit: 1,
|
||||
type: FieldTypes.text,
|
||||
value: ''
|
||||
},
|
||||
link: {
|
||||
isConstant: false,
|
||||
limit: 1,
|
||||
type: FieldTypes.text,
|
||||
value: ''
|
||||
},
|
||||
},
|
||||
list: {
|
||||
items: {
|
||||
isConstant: false,
|
||||
limit: 0,
|
||||
type: FieldTypes['long text'],
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
tableRow: {
|
||||
columns: {
|
||||
isConstant: false,
|
||||
limit: 0,
|
||||
type: FieldTypes.any,
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
table: {
|
||||
rows: {
|
||||
isConstant: false,
|
||||
limit: 0,
|
||||
type: FieldTypes.type,
|
||||
value: 'tableRow'
|
||||
},
|
||||
header: {
|
||||
isConstant: false,
|
||||
limit: 1,
|
||||
type: FieldTypes.type,
|
||||
value: 'tableRow'
|
||||
}
|
||||
}
|
||||
};
|
@ -3,5 +3,5 @@ import { Schema } from '../../types/schema';
|
||||
|
||||
export const SchemaEditAtom = atom<Schema>({
|
||||
key: 'schema-edit',
|
||||
default: {name: '', types: {}}
|
||||
default: {name: '', types: {}, templates: {}}
|
||||
});
|
@ -19,7 +19,7 @@ export const GameSystemsService = {
|
||||
|
||||
return {
|
||||
status: 404,
|
||||
json: async () => ({name:'', types: {}})
|
||||
json: async () => ({name:'', types: {}, templates: {}})
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
export type MetadataType = {
|
||||
[key: string]: string
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export type FieldType = {
|
||||
@ -11,9 +11,15 @@ export type FieldType = {
|
||||
|
||||
export type TypeType = Record<string, FieldType>;
|
||||
|
||||
export type Template = {
|
||||
type: string;
|
||||
publishable: boolean;
|
||||
}
|
||||
|
||||
export type Schema = {
|
||||
name: string;
|
||||
types: Record<string, TypeType>
|
||||
templates: Record<string, Template>;
|
||||
types: Record<string, TypeType>;
|
||||
}
|
||||
|
||||
export enum FieldTypes {
|
||||
@ -22,7 +28,8 @@ export enum FieldTypes {
|
||||
'long text' = 'long text',
|
||||
checkbox = 'checkbox',
|
||||
type = '@type',
|
||||
dice = 'dice'
|
||||
dice = 'dice',
|
||||
any = '@select'
|
||||
}
|
||||
|
||||
export const fieldTypeOptions: (keyof typeof FieldTypes)[] = ['number', 'text', 'long text', 'checkbox', 'type', 'dice']
|
||||
|
Loading…
x
Reference in New Issue
Block a user