Default types and templates

This commit is contained in:
Emma 2023-06-12 18:02:19 -06:00
parent 8fb7494464
commit a7337bd33a
10 changed files with 179 additions and 18 deletions

View File

@ -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]);

View File

@ -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>
)
}

View File

@ -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>

View File

@ -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

View File

@ -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>
)
}

View File

@ -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 })

View 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'
}
}
};

View File

@ -3,5 +3,5 @@ import { Schema } from '../../types/schema';
export const SchemaEditAtom = atom<Schema>({
key: 'schema-edit',
default: {name: '', types: {}}
default: {name: '', types: {}, templates: {}}
});

View File

@ -19,7 +19,7 @@ export const GameSystemsService = {
return {
status: 404,
json: async () => ({name:'', types: {}})
json: async () => ({name:'', types: {}, templates: {}})
}
}
}

View File

@ -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']