committed by
							
								
								拾邑
							
						
					
				
				 18 changed files with 278 additions and 76 deletions
			
			
		@ -0,0 +1,94 @@ | 
				
			|||
/** @jsx jsx */ | 
				
			|||
import { jsx, css } from '@emotion/core'; | 
				
			|||
import styled from '@emotion/styled'; | 
				
			|||
import { Row, Col, Tooltip, Input, Checkbox, Select } from 'antd'; | 
				
			|||
import { useTranslation } from 'react-i18next'; | 
				
			|||
import { useUIState, useSetUIState } from '../store/ui'; | 
				
			|||
import { | 
				
			|||
  CaretDownIcon, | 
				
			|||
  CaretRightIcon, | 
				
			|||
  EditIcon, | 
				
			|||
  SettingIcon, | 
				
			|||
  PlusIcon, | 
				
			|||
} from '../utils/styles/common'; | 
				
			|||
 | 
				
			|||
const { Option } = Select; | 
				
			|||
 | 
				
			|||
const FieldInput = styled(Input)` | 
				
			|||
  .ant-input-group-addon { | 
				
			|||
    background: transparent; | 
				
			|||
    border: none; | 
				
			|||
  } | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
function EditorHead(): JSX.Element { | 
				
			|||
  const { t } = useTranslation(); | 
				
			|||
  const uiState = useUIState(); | 
				
			|||
  const setUIState = useSetUIState(); | 
				
			|||
  const { formVisible } = uiState; | 
				
			|||
 | 
				
			|||
  const toggleFormVisible = (): void => { | 
				
			|||
    setUIState((prev) => ({ ...prev, formVisible: !formVisible })); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <Row | 
				
			|||
      css={css` | 
				
			|||
        margin-top: 10px; | 
				
			|||
      `}
 | 
				
			|||
    > | 
				
			|||
      <Col span="24"> | 
				
			|||
        <Row align="middle"> | 
				
			|||
          <Col span="8"> | 
				
			|||
            <Row align="middle"> | 
				
			|||
              <Col span="2"> | 
				
			|||
                {formVisible ? ( | 
				
			|||
                  <CaretDownIcon onClick={toggleFormVisible} /> | 
				
			|||
                ) : ( | 
				
			|||
                  <CaretRightIcon onClick={toggleFormVisible} /> | 
				
			|||
                )} | 
				
			|||
              </Col> | 
				
			|||
              <Col span="22"> | 
				
			|||
                <FieldInput | 
				
			|||
                  disabled | 
				
			|||
                  value="root" | 
				
			|||
                  addonAfter={ | 
				
			|||
                    <Tooltip placement="top" title={t('select_all')}> | 
				
			|||
                      <Checkbox | 
				
			|||
                        checked={false} | 
				
			|||
                        onChange={(): void => { | 
				
			|||
                          // code
 | 
				
			|||
                        }} | 
				
			|||
                      /> | 
				
			|||
                    </Tooltip> | 
				
			|||
                  } | 
				
			|||
                /> | 
				
			|||
              </Col> | 
				
			|||
            </Row> | 
				
			|||
          </Col> | 
				
			|||
          <Col span="3"> | 
				
			|||
            <Select value="object" disabled> | 
				
			|||
              <Option value="object">object</Option> | 
				
			|||
            </Select> | 
				
			|||
          </Col> | 
				
			|||
          <Col span="5"> | 
				
			|||
            <Input value="" placeholder="Title" addonAfter={<EditIcon />} /> | 
				
			|||
          </Col> | 
				
			|||
          <Col span="5"> | 
				
			|||
            <Input value="" placeholder="Description" addonAfter={<EditIcon />} /> | 
				
			|||
          </Col> | 
				
			|||
          <Col span="3"> | 
				
			|||
            <Tooltip placement="top" title={t('setting')}> | 
				
			|||
              <SettingIcon /> | 
				
			|||
            </Tooltip> | 
				
			|||
            <Tooltip placement="top" title={t('add_child_node')}> | 
				
			|||
              <PlusIcon /> | 
				
			|||
            </Tooltip> | 
				
			|||
          </Col> | 
				
			|||
        </Row> | 
				
			|||
      </Col> | 
				
			|||
    </Row> | 
				
			|||
  ); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default EditorHead; | 
				
			|||
@ -0,0 +1,28 @@ | 
				
			|||
/** @jsx jsx */ | 
				
			|||
import { jsx, css } from '@emotion/core'; | 
				
			|||
import { Button } from 'antd'; | 
				
			|||
import { useTranslation } from 'react-i18next'; | 
				
			|||
import EditorHead from './editor-head'; | 
				
			|||
import SchemaForm from './schema-form'; | 
				
			|||
import { useUIState } from '../store/ui'; | 
				
			|||
 | 
				
			|||
function Layout(): JSX.Element { | 
				
			|||
  const { t } = useTranslation(); | 
				
			|||
  const uiState = useUIState(); | 
				
			|||
  const { formVisible } = uiState; | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <div | 
				
			|||
      className="json-schema-editor" | 
				
			|||
      css={css` | 
				
			|||
        padding: 5px; | 
				
			|||
      `}
 | 
				
			|||
    > | 
				
			|||
      <Button type="primary">{t('import_json')}</Button> | 
				
			|||
      <EditorHead /> | 
				
			|||
      {formVisible && <SchemaForm />} | 
				
			|||
    </div> | 
				
			|||
  ); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default Layout; | 
				
			|||
@ -0,0 +1,22 @@ | 
				
			|||
/** @jsx jsx */ | 
				
			|||
import { useEffect, memo, useRef } from 'react'; | 
				
			|||
import { jsx } from '@emotion/core'; | 
				
			|||
import { useUIState } from '../store/ui'; | 
				
			|||
 | 
				
			|||
function SchemaForm(): JSX.Element { | 
				
			|||
  const uiState = useUIState(); | 
				
			|||
  const { formVisible } = uiState; | 
				
			|||
  const renders = useRef(1); | 
				
			|||
  useEffect(() => { | 
				
			|||
    console.log(11111); | 
				
			|||
  }); | 
				
			|||
  renders.current += 1; | 
				
			|||
  return ( | 
				
			|||
    <div> | 
				
			|||
      {formVisible ? 3 : 0} | 
				
			|||
      (renders:{renders.current}) | 
				
			|||
    </div> | 
				
			|||
  ); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default memo(SchemaForm); | 
				
			|||
@ -0,0 +1,20 @@ | 
				
			|||
import * as React from 'react'; | 
				
			|||
import { createContext, useContext, useReducer } from 'react'; | 
				
			|||
import uiReducer from '../reducer/ui'; | 
				
			|||
import { UIContext } from '../model'; | 
				
			|||
 | 
				
			|||
interface ProviderProps { | 
				
			|||
  children: React.ReactChild; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
const initialData = { formVisible: true, aaa: true }; | 
				
			|||
 | 
				
			|||
const Context = createContext({ uiState: initialData } as UIContext); | 
				
			|||
 | 
				
			|||
export const UIProvider = ({ children }: ProviderProps): JSX.Element => { | 
				
			|||
  const [uiState, uiDispatch] = useReducer(uiReducer, initialData); | 
				
			|||
 | 
				
			|||
  return <Context.Provider value={{ uiState, uiDispatch }}>{children}</Context.Provider>; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
export const useUI = (): UIContext => useContext(Context); | 
				
			|||
@ -1,6 +1,8 @@ | 
				
			|||
{ | 
				
			|||
  "translation": { | 
				
			|||
    "import_json": "Import JSON", | 
				
			|||
    "select_all": "Select All" | 
				
			|||
    "select_all": "Select All", | 
				
			|||
    "setting": "Advanced Setting", | 
				
			|||
    "add_child_node": "Add child node" | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -1,6 +1,8 @@ | 
				
			|||
{ | 
				
			|||
  "translation": { | 
				
			|||
    "import_json": "导入 JSON", | 
				
			|||
    "select_all": "全选" | 
				
			|||
    "select_all": "全选", | 
				
			|||
    "setting": "高级设置", | 
				
			|||
    "add_child_node": "添加子节点" | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -0,0 +1 @@ | 
				
			|||
export * from './ui'; | 
				
			|||
@ -0,0 +1,13 @@ | 
				
			|||
export interface UIState { | 
				
			|||
  formVisible: boolean; | 
				
			|||
  aaa: boolean; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export interface UIAction { | 
				
			|||
  type: string; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export interface UIContext { | 
				
			|||
  uiState: UIState; | 
				
			|||
  uiDispatch: React.Dispatch<UIAction>; | 
				
			|||
} | 
				
			|||
@ -0,0 +1,16 @@ | 
				
			|||
import { UIState, UIAction } from '../model'; | 
				
			|||
 | 
				
			|||
const reducer = (state: UIState, action: UIAction): UIState => { | 
				
			|||
  switch (action.type) { | 
				
			|||
    case 'TOGGLE_FORM_VISIBLE': | 
				
			|||
      return { formVisible: state.formVisible, aaa: false }; | 
				
			|||
    case 'increment': | 
				
			|||
      return state; | 
				
			|||
    case 'decrement': | 
				
			|||
      return state; | 
				
			|||
    default: | 
				
			|||
      return state; | 
				
			|||
  } | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
export default reducer; | 
				
			|||
@ -0,0 +1,16 @@ | 
				
			|||
import { useState, Dispatch, SetStateAction } from 'react'; | 
				
			|||
import { createContainer } from 'react-tracked'; | 
				
			|||
 | 
				
			|||
export type State = { | 
				
			|||
  formVisible: boolean; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
const initialData = { formVisible: true }; | 
				
			|||
 | 
				
			|||
const useValue = (): [State, Dispatch<SetStateAction<State>>] => useState<State>(initialData); | 
				
			|||
 | 
				
			|||
export const { | 
				
			|||
  Provider: UIProvider, | 
				
			|||
  useTrackedState: useUIState, | 
				
			|||
  useUpdate: useSetUIState, | 
				
			|||
} = createContainer(useValue); | 
				
			|||
@ -0,0 +1,44 @@ | 
				
			|||
import { css } from '@emotion/core'; | 
				
			|||
import styled from '@emotion/styled'; | 
				
			|||
import { | 
				
			|||
  CaretDownOutlined, | 
				
			|||
  CaretRightOutlined, | 
				
			|||
  EditOutlined, | 
				
			|||
  SettingOutlined, | 
				
			|||
  PlusOutlined, | 
				
			|||
} from '@ant-design/icons'; | 
				
			|||
 | 
				
			|||
const cursorStyle = css` | 
				
			|||
  cursor: pointer; | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
const IconStyle = css` | 
				
			|||
  margin: 0 5px; | 
				
			|||
  svg { | 
				
			|||
    font-size: 14px; | 
				
			|||
  } | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
export const CaretDownIcon = styled(CaretDownOutlined)` | 
				
			|||
  ${cursorStyle} | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
export const CaretRightIcon = styled(CaretRightOutlined)` | 
				
			|||
  ${cursorStyle} | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
export const EditIcon = styled(EditOutlined)` | 
				
			|||
  ${cursorStyle} | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
export const SettingIcon = styled(SettingOutlined)` | 
				
			|||
  color: #00a854; | 
				
			|||
  ${cursorStyle} | 
				
			|||
  ${IconStyle} | 
				
			|||
`;
 | 
				
			|||
 | 
				
			|||
export const PlusIcon = styled(PlusOutlined)` | 
				
			|||
  color: #2395f1; | 
				
			|||
  ${cursorStyle} | 
				
			|||
  ${IconStyle} | 
				
			|||
`;
 | 
				
			|||
					Loading…
					
					
				
		Reference in new issue