Skip to content

Commit

Permalink
Make playground maps shareable by persisting data to the URL (#18)
Browse files Browse the repository at this point in the history
Co-authored-by: cpojer <[email protected]>
  • Loading branch information
connorlindsey and cpojer authored May 16, 2024
1 parent 89a4693 commit 1c07471
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 7 deletions.
111 changes: 109 additions & 2 deletions docs/content/examples/map-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { encodeEffects } from '@deities/apollo/Effects.tsx';
import { Sniper } from '@deities/athena/info/Unit.tsx';
import toSlug from '@deities/hephaestus/toSlug.tsx';
import MapEditor from '@deities/hera/editor/MapEditor.tsx';
import {
MapCreateVariables,
MapObject,
MapUpdateVariables,
} from '@deities/hera/editor/Types.tsx';
import useLocation from '@deities/ui/hooks/useLocation.tsx';
import { useCallback, useEffect, useState } from 'react';

const viewer = {
access: 'User',
Expand All @@ -14,17 +23,115 @@ const viewer = {
username: 'demo-maxima',
} as const;

const decodeMapObject = (data: string | null): MapObject | null => {
if (!data) {
return null;
}

try {
const maybeMapObject: MapObject | null = JSON.parse(data);
const maybeCreator = maybeMapObject?.creator || null;
const mapObject: MapObject = {
campaigns: {
edges: [],
},
creator: maybeCreator
? {
displayName:
typeof maybeCreator.displayName === 'string'
? maybeCreator.displayName
: viewer.displayName,
id:
typeof maybeCreator.id === 'string' ? maybeCreator.id : viewer.id,
username:
typeof maybeCreator.username === 'string'
? maybeCreator.username
: viewer.username,
}
: viewer,
effects:
typeof maybeMapObject?.effects === 'string'
? maybeMapObject.effects
: '',
id: typeof maybeMapObject?.id === 'string' ? maybeMapObject.id : '',
name: typeof maybeMapObject?.name === 'string' ? maybeMapObject.name : '',
slug: typeof maybeMapObject?.slug === 'string' ? maybeMapObject.slug : '',
state:
typeof maybeMapObject?.state === 'string' ? maybeMapObject.state : '',
tags:
Array.isArray(maybeMapObject?.tags) &&
maybeMapObject.tags.every((tag) => typeof tag === 'string')
? maybeMapObject.tags
: [],
};
return mapObject;
} catch {
return null;
}
};

export default function MapEditorExample() {
const location = useLocation();
const params = new URLSearchParams(location.search);

const [mapObject, setMapObject] = useState<MapObject | null>(() =>
decodeMapObject(params.get('map')),
);

const handleMapUpdate = useCallback(
(variables: MapCreateVariables | MapUpdateVariables) => {
setMapObject({
campaigns: {
edges: [],
},
creator: {
displayName: viewer.displayName,
id: viewer.id,
username: viewer.username,
},
effects: JSON.stringify(encodeEffects(variables.effects)),
id: 'id' in variables ? variables.id : '',
name: variables.mapName,
slug: toSlug(variables.mapName),
state: JSON.stringify(variables.map.toJSON()),
tags: variables.tags,
});
},
[],
);

useEffect(() => {
const params = new URLSearchParams(window.location.search);
params.sort();
const search = params.toString();

const newParams = new URLSearchParams();
if (mapObject) {
newParams.set('map', JSON.stringify(mapObject));
}
newParams.sort();
const newSearch = newParams.toString();

if (newSearch !== search) {
window.history.pushState(
{},
'',
window.location.pathname + `${newSearch ? `?${newSearch}` : ``}`,
);
}
}, [mapObject]);

return (
<div style={{ width: '150%' }}>
<MapEditor
animationSpeed={null}
confirmActionStyle="touch"
createMap={() => {}}
createMap={handleMapUpdate}
fogStyle="soft"
mapObject={mapObject}
setHasChanges={() => {}}
tiltStyle="on"
updateMap={() => {}}
updateMap={handleMapUpdate}
user={viewer}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@deities/apollo": "workspace:*",
"@deities/art": "workspace:*",
"@deities/athena": "workspace:*",
"@deities/hephaestus": "workspace:*",
"@deities/hera": "workspace:*",
"@deities/hermes": "workspace:*",
"@deities/ui": "workspace:*",
Expand Down
12 changes: 7 additions & 5 deletions hera/editor/Types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,24 @@ export type SetMapFunction = (
) => void;

type MapSaveType = 'New' | 'Update' | 'Disk' | 'Export';
type MapCreateVariables = Readonly<{
export type MapCreateVariables = Readonly<{
effects: Effects;
map: MapData;
mapName: string;
tags: ReadonlyArray<string>;
}>;

export type MapUpdateVariables = MapCreateVariables &
Readonly<{
id: string;
}>;

export type MapCreateFunction = (
variables: MapCreateVariables,
setSaveState: (state: MapEditorSaveState) => void,
) => void;
export type MapUpdateFunction = (
variables: MapCreateVariables &
Readonly<{
id: string;
}>,
variables: MapUpdateVariables,
type: MapSaveType,
setSaveState: (state: MapEditorSaveState) => void,
) => void;
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1c07471

Please sign in to comment.