-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
1,018 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Graphics } from '@inlet/react-pixi'; | ||
import { useActiveDocumentSize } from '@store'; | ||
|
||
const GRID_SIZE = 20; | ||
const GRID_COLOR = 0xc8c8c8; | ||
const BACKGROUND_COLOR = 0xffffff; | ||
|
||
export default function Background() { | ||
const activeDocumentSize = useActiveDocumentSize(); | ||
|
||
if (!activeDocumentSize) return null; | ||
|
||
return ( | ||
<Graphics | ||
draw={g => { | ||
g.clear(); | ||
g.beginFill(BACKGROUND_COLOR); | ||
g.drawRect(0, 0, activeDocumentSize.width, activeDocumentSize.height); | ||
g.beginFill(GRID_COLOR); | ||
let flag = true; | ||
for (let x = 0; x < activeDocumentSize.width; x += GRID_SIZE, flag = !flag) { | ||
for (let y = flag ? 0 : GRID_SIZE; y < activeDocumentSize.height; y += GRID_SIZE * 2) { | ||
g.drawRect(x, y, GRID_SIZE, GRID_SIZE); | ||
} | ||
} | ||
}} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { PixiComponent, useApp } from '@inlet/react-pixi'; | ||
import { Viewport as PixiViewport } from 'pixi-viewport'; | ||
import { Application } from 'pixi.js'; | ||
import { | ||
useCallback, | ||
createContext, | ||
useState, | ||
RefCallback, | ||
PropsWithChildren, | ||
useEffect, | ||
useContext, | ||
} from 'react'; | ||
|
||
const ViewportContext = createContext<PixiViewport | null>(null); | ||
|
||
export function useViewport(): PixiViewport { | ||
return useContext(ViewportContext) as PixiViewport; | ||
} | ||
|
||
export interface ViewportProps { | ||
scale?: number; | ||
onZoomed?: (scale: number) => void; | ||
} | ||
|
||
const PixiViewportComponent = PixiComponent< | ||
{ | ||
app: Application; | ||
scale?: number; | ||
}, | ||
PixiViewport | ||
>('Viewport', { | ||
create: ({ app }) => { | ||
const viewport = new PixiViewport({ | ||
screenWidth: app.renderer.width / app.renderer.resolution, | ||
screenHeight: app.renderer.height / app.renderer.resolution, | ||
interaction: app.renderer.plugins.interaction, | ||
}); | ||
|
||
// 激活插件 | ||
viewport.drag().pinch().wheel(); | ||
|
||
// 设置 viewport 默认中心和缩放 | ||
viewport.moveCenter(0, 0); | ||
viewport.setZoom(1, true); | ||
|
||
function update() { | ||
if (viewport.dirty) { | ||
app.renderer.render(viewport); | ||
viewport.dirty = false; | ||
} | ||
requestAnimationFrame(() => update()); | ||
} | ||
|
||
update(); | ||
|
||
return viewport; | ||
}, | ||
applyProps: (viewport, _, { scale }) => { | ||
if (scale && scale.toFixed(2) !== viewport.scaled.toFixed(2)) { | ||
viewport.setZoom(scale, true); | ||
} | ||
}, | ||
}); | ||
|
||
export default function Viewport({ scale, onZoomed, children }: PropsWithChildren<ViewportProps>) { | ||
const app = useApp(); | ||
const [viewportInstance, setViewportInstance] = useState<PixiViewport | null>(null); | ||
const viewportRef = useCallback<RefCallback<unknown>>(currentViewportInstance => { | ||
if (currentViewportInstance) { | ||
setViewportInstance(currentViewportInstance as PixiViewport); | ||
} | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (viewportInstance && typeof onZoomed === 'function') { | ||
const onViewportZoomed = (e: any) => { | ||
requestAnimationFrame(() => { | ||
onZoomed(e.viewport.scaled); | ||
}); | ||
}; | ||
viewportInstance.on('zoomed', onViewportZoomed); | ||
return () => { | ||
viewportInstance.off('zoomed', onViewportZoomed); | ||
}; | ||
} | ||
}, [onZoomed, viewportInstance]); | ||
|
||
return ( | ||
<PixiViewportComponent ref={viewportRef} app={app} scale={scale}> | ||
<ViewportContext.Provider value={viewportInstance}> | ||
{viewportInstance && children} | ||
</ViewportContext.Provider> | ||
</PixiViewportComponent> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { useMeasure } from 'react-use'; | ||
import { Stage } from '@inlet/react-pixi'; | ||
import { View } from '@adobe/react-spectrum'; | ||
import { ReactReduxContext } from 'react-redux'; | ||
import Viewport from './Viewport'; | ||
import Background from './Background'; | ||
|
||
export default function Canvas() { | ||
const [ref, canvasContainerRect] = useMeasure(); | ||
|
||
return ( | ||
<View | ||
flexGrow={1} | ||
overflow="hidden" | ||
ref={instance => { | ||
const node = instance?.UNSAFE_getDOMNode(); | ||
if (node) ref(node); | ||
}} | ||
> | ||
{canvasContainerRect.width > 0 && canvasContainerRect.height > 0 && ( | ||
<ReactReduxContext.Consumer> | ||
{value => ( | ||
<Stage | ||
width={canvasContainerRect.width} | ||
height={canvasContainerRect.height} | ||
raf={false} | ||
renderOnComponentChange | ||
options={{ | ||
backgroundColor: 0x080808, | ||
autoDensity: true, | ||
resolution: window.devicePixelRatio, | ||
}} | ||
> | ||
<ReactReduxContext.Provider value={value}> | ||
<Viewport> | ||
<Background /> | ||
</Viewport> | ||
</ReactReduxContext.Provider> | ||
</Stage> | ||
)} | ||
</ReactReduxContext.Consumer> | ||
)} | ||
</View> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Flex, View } from '@adobe/react-spectrum'; | ||
import { useActiveDocument } from '@store'; | ||
import Canvas from '@Canvas'; | ||
|
||
export default function DocumentWindow() { | ||
const activeDocument = useActiveDocument()!; | ||
|
||
return ( | ||
<Flex flexGrow={1} width={0} direction="column"> | ||
<View paddingX="size-200" paddingY="size-100"> | ||
{activeDocument.name} | ||
</View> | ||
<Canvas /> | ||
<View paddingX="size-100" paddingY="size-50"> | ||
{/* eslint-disable-next-line i18next/no-literal-string */} | ||
{activeDocument.size.width}×{activeDocument.size.height} | ||
</View> | ||
</Flex> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
import { Flex, View } from '@adobe/react-spectrum'; | ||
import { useActiveDocument } from './store'; | ||
import { Flex } from '@adobe/react-spectrum'; | ||
import DocumentWindow from './DocumentWindow'; | ||
import Panels from './Panels'; | ||
|
||
export default function Editor() { | ||
const activeDocument = useActiveDocument()!; | ||
|
||
return ( | ||
<Flex> | ||
<View>{activeDocument.name}</View> | ||
<Flex width="100vw" height="100vh"> | ||
<DocumentWindow /> | ||
<Panels /> | ||
</Flex> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { EntityId } from '@reduxjs/toolkit'; | ||
import { Flex, View, ActionButton, Text } from '@adobe/react-spectrum'; | ||
import Visibility from '@spectrum-icons/workflow/Visibility'; | ||
import VisibilityOff from '@spectrum-icons/workflow/VisibilityOff'; | ||
import { useDispatch } from 'react-redux'; | ||
import { useLayerById, switchLayerVisible } from '@store'; | ||
|
||
export default function Layer({ id }: { id: EntityId }) { | ||
const layer = useLayerById(id); | ||
const dispatch = useDispatch(); | ||
|
||
if (!layer) return null; | ||
|
||
return ( | ||
<Flex alignItems="center"> | ||
<ActionButton isQuiet onPress={() => dispatch(switchLayerVisible(id))}> | ||
{layer.visible ? <Visibility /> : <VisibilityOff />} | ||
</ActionButton> | ||
<View backgroundColor="gray-200" width="size-600" height="size-600" /> | ||
<Text marginStart="size-200">{layer.name}</Text> | ||
</Flex> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Flex, View } from '@adobe/react-spectrum'; | ||
import { useActiveLayerIds } from '@store'; | ||
import Layer from './LayersPanel/Layer'; | ||
|
||
export default function Panels() { | ||
const activeLayerIds = useActiveLayerIds(); | ||
return ( | ||
<Flex flexShrink={0} direction="column" width="size-5000"> | ||
<View padding="size-200"> | ||
{activeLayerIds?.map(layerId => ( | ||
<Layer key={layerId} id={layerId} /> | ||
))} | ||
</View> | ||
</Flex> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,5 @@ export default { | |
height: 'Height', | ||
create: 'Create', | ||
cancel: 'Cancel', | ||
layer: 'Layer', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,5 @@ export default { | |
height: '高度', | ||
create: '新建', | ||
cancel: '取消', | ||
layer: '图层', | ||
} as Translation; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,28 @@ | ||
import { createEntityAdapter, EntityState } from '@reduxjs/toolkit'; | ||
import { createEntityAdapter, EntityState, nanoid } from '@reduxjs/toolkit'; | ||
import i18next from 'i18next'; | ||
|
||
export interface Layer { | ||
name: string; | ||
visible: boolean; | ||
opacity: number; | ||
} | ||
|
||
const layerAdapter = createEntityAdapter<Layer>(); | ||
|
||
export type LayerEntry = EntityState<Layer>; | ||
|
||
export default layerAdapter; | ||
|
||
export function getInitialLayer(): LayerEntry { | ||
const id = nanoid(); | ||
return { | ||
ids: [id], | ||
entities: { | ||
[id]: { | ||
name: `${i18next.t('layer')} 1`, | ||
visible: true, | ||
opacity: 1, | ||
}, | ||
}, | ||
}; | ||
} |
Oops, something went wrong.