Skip to content

Commit

Permalink
feat: default props (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
webbertakken authored Oct 29, 2022
1 parent 1123e95 commit d8d20ee
Show file tree
Hide file tree
Showing 18 changed files with 243 additions and 56 deletions.
62 changes: 62 additions & 0 deletions src/components/atoms/Field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react'
import { Input } from 'dracula-ui'

type Type =
| 'button'
| 'checkbox'
| 'color'
| 'date'
| 'datetime-local'
| 'email'
| 'file'
| 'hidden'
| 'image'
| 'month'
| 'number'
| 'password'
| 'radio'
| 'range'
| 'reset'
| 'search'
| 'submit'
| 'tel'
| 'text'
| 'time'
| 'url'
| 'week'

interface Props {
value: number | string
type?: Type
step?: number | string | undefined
enforceStep?: boolean | undefined
[key: string]: any
}

export const Field = ({ id, value, onChange, type, step, enforceStep, ...props }: Props) => {
const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') e.currentTarget.blur()
}

if (type === 'number') {
// Rounding after a comma or dot is added.
if (enforceStep && step === '1' && value !== '' && typeof value === 'number') {
value = Math.round(value).toString()
}
}

return (
<Input
lang="en-150"
size="sm"
borderSize="sm"
onKeyDown={onKeyDown}
onChange={onChange}
{...props}
id={id}
type={type}
step={step}
value={value}
/>
)
}
5 changes: 4 additions & 1 deletion src/components/canvas/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import CopyAndPasteListener from './listeners/CopyAndPasteListener'
import DeleteListener from './listeners/DeleteListener'
import DeselectListener from './listeners/DeselectListener'
import { useGlobalHotkeys } from '../../hooks/useGlobalHotkeys'
import { defaultPropertiesState } from '../../state/AssetsState'

export const Canvas = () => {
const ref = createRef<HTMLDivElement>()
const stageRef = React.useRef<Konva.Stage>(null)
const windowSize = useWindowSize()
const [_1, setSelectedSpriteIds] = useRecoilState(selectedSpriteIdsState)
const [defaultProps] = useRecoilState(defaultPropertiesState)
const [width, setWidth] = useState<number | undefined>(windowSize.width)
const [height, setHeight] = useState<number | undefined>(windowSize.height)
const addSprite = useRecoilCallback(addSpriteCallback, [])
Expand Down Expand Up @@ -46,7 +48,8 @@ export const Canvas = () => {
const { x, y } = stageRef.current.getPointerPosition() || { x: 0, y: 0 }

// Add sprite to canvas at that position
const spriteData = SpriteData.createFromDragAndDrop(x, y, dragAndDropRef.current.relativePath)
const { relativePath } = dragAndDropRef.current
const spriteData = SpriteData.createFromDragAndDrop(x, y, relativePath, defaultProps)
const spriteMeta = SpriteMeta.createFromSpriteAsset(spriteData.id, dragAndDropRef.current)
addSprite(spriteData.id, spriteData, spriteMeta)

Expand Down
10 changes: 9 additions & 1 deletion src/components/menu/scene/LoadScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import { useNotification } from '../../../hooks/useNotification'
import { SceneMeta } from '../../../model/SceneMeta'
import { isSceneLoadedState, sceneMetaState, sceneState } from '../../../state/SceneState'
import { AssetsLoader } from '../../../service/AssetsLoader'
import { assetsState } from '../../../state/AssetsState'
import { assetsState, defaultPropertiesState } from '../../../state/AssetsState'
import { AssetPath } from '../../../model/AssetPath'
import { Path } from '../../../model/Path'
import { Assets } from '../../../model/Assets'
import { CanvasLoader } from '../../../service/CanvasLoader'
import { allSpritesState } from '../../../state/SpritesState'
import { Sprites } from '../../../model/Sprites'
import { DefaultProperties } from '../../../model/DefaultProperties'

class Props {}

Expand All @@ -27,6 +28,7 @@ const NewScene = ({}: Props): JSX.Element => {
const [_3, setAssets] = useRecoilState(assetsState)
const [_4, setAllSprites] = useRecoilState(allSpritesState)
const [_5, setHasLoadedScene] = useRecoilState(isSceneLoadedState)
const [_6, setDefaultProperties] = useRecoilState(defaultPropertiesState)
const notify = useNotification()
const [isOpen, setIsOpen] = React.useState(false)

Expand Down Expand Up @@ -63,6 +65,7 @@ const NewScene = ({}: Props): JSX.Element => {
setSceneMeta(SceneMeta.default())
setAssets(Assets.default())
setAllSprites(Sprites.default())
setDefaultProperties(DefaultProperties.default())

// Load file
const fileContents = await readTextFile(filePath)
Expand All @@ -78,6 +81,11 @@ const NewScene = ({}: Props): JSX.Element => {
// Close modal
setIsOpen(false)

// Load defaults
if (scene.defaultProperties) {
setDefaultProperties(scene.defaultProperties)
}

// Load assets
if (scene.assetsRelativePath !== null) {
console.log('Scene has assets path, loading assets...')
Expand Down
1 change: 1 addition & 0 deletions src/components/menu/scene/SaveScene.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect } from 'react'
import {
isSceneLoadedState,
isSceneOpenState,
sceneAbsoluteFilePath,
sceneFileDataSelector,
} from '../../../state/SceneState'
Expand Down
10 changes: 8 additions & 2 deletions src/components/sidebars/LeftSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import React from 'react'
import FlexFiller from '../atoms/FlexFiller'
import { SceneSection } from './scenes-section/SceneSection'
import { SpritesSection } from './assets-section/SpritesSection'
import { SceneSection } from './scenes/SceneSection'
import { SpritesSection } from './assets/SpritesSection'
import DefaultPropertiesSection from './default-properties/DefaultPropertiesSection'
import { isSceneLoadedState, isSceneOpenState } from '../../state/SceneState'
import { useRecoilValue } from 'recoil'

interface Props {}

const LeftSidebar = ({}: Props): JSX.Element => {
const isSceneLoaded = useRecoilValue(isSceneLoadedState)
const isSceneOpen = useRecoilValue(isSceneOpenState)
return (
<>
<SceneSection />
<SpritesSection />
{isSceneOpen && isSceneLoaded && <DefaultPropertiesSection />}
<FlexFiller />
</>
)
Expand Down
2 changes: 1 addition & 1 deletion src/components/sidebars/RightSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { useRecoilValue } from 'recoil'
import { selectedSpriteIdsState } from '../../state/SpritesState'
import InspectorSection from './inspector-section/InspectorSection'
import InspectorSection from './inspector/InspectorSection'

interface Props {}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react'
import Section from '../../layout/Section'
import { Box, Heading } from 'dracula-ui'
import FormRow from '../../atoms/FormRow'
import { Field } from '../../atoms/Field'
import { defaultPropertiesState } from '../../../state/AssetsState'
import { useRecoilState } from 'recoil'
import { cloneDeep, set } from 'lodash'

interface Props {}

const DefaultPropertiesSection = ({}: Props): JSX.Element => {
const [defaultProps, setDefaultProps] = useRecoilState(defaultPropertiesState)

const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { id, value } = e.target
console.log(id, value)
setDefaultProps((data) => set(cloneDeep(data), id, value))
}

return (
<Section title="Default properties" color="yellow">
<Heading size="xs">Layer</Heading>
<FormRow>
<label htmlFor="position.z">Z</label>
<Field
style={{ width: '6em' }}
color="green"
type="number"
step="1"
min="-1"
max="1000"
id="position.z"
value={defaultProps.position.z}
onChange={onChange}
/>
</FormRow>

<Heading size="xs">Scale</Heading>
<FormRow>
<label htmlFor="scale.x">X</label>
<Field
color="green"
type="number"
step="0.1"
max="100"
id="scale.x"
value={defaultProps.scale.x}
onChange={onChange}
/>
<label htmlFor="scale.y">Y</label>
<Field
color="green"
type="number"
step="0.1"
max="100"
id="scale.y"
value={defaultProps.scale.y}
onChange={onChange}
/>
</FormRow>

<Box pt="sm">
<Heading size="xs" color="yellow" as="h3">
Other settings
</Heading>
</Box>

<Heading size="xs">Rotation</Heading>
<FormRow>
<Field
style={{ width: '6em' }}
color="green"
type="number"
step="1"
min="-179"
max="180"
id="rotation"
value={defaultProps.rotation}
onChange={onChange}
/>
<label htmlFor="rotation">Angle</label>
</FormRow>

<Heading size="xs">Opacity</Heading>
<FormRow>
<Field
style={{ width: '6em' }}
color="green"
type="number"
step="0.1"
max="1"
min="0"
id="opacity"
value={defaultProps.opacity}
onChange={onChange}
/>
<label htmlFor="opacity">Opacity</label>
</FormRow>
</Section>
)
}

export default DefaultPropertiesSection
Loading

0 comments on commit d8d20ee

Please sign in to comment.