-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #266 from VoidShake/feature/advanced-location-edit
Advanced Location Creating/Editing
- Loading branch information
Showing
23 changed files
with
1,975 additions
and
6,840 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,80 @@ | ||
<template> | ||
<section> | ||
<FormKit v-slot="{ value, state: { valid } }" type="form" :actions="false" :errors="errors"> | ||
<FormKit name="world" validation="required" type="hidden" :value="initial?.pos?.world ?? 'overworld'" /> | ||
|
||
<FormKit name="name" :value="initial?.name" validation="required" label="Name" type="text" /> | ||
|
||
<div class="grid grid-flow-col gap-4"> | ||
<FormKit name="minY" label="Min-Y" type="number" step="1" :value="-64" /> | ||
<FormKit name="maxY" label="Max-Y" type="number" step="1" :value="320" /> | ||
</div> | ||
|
||
<InputArea :initial="initial?.points" /> | ||
|
||
<div id="buttons"> | ||
<slot name="buttons" :valid="valid" :value="value"> | ||
<FormKit v-if="!onlyDraft" type="submit" :disabled="!valid" @click.prevent="save(value, false)" /> | ||
<FormKit type="submit" :disabled="!valid" :classes="{ input: 'bg-solid-600' }" | ||
@click.prevent="save(value, true)"> | ||
Save as Draft | ||
</FormKit> | ||
</slot> | ||
</div> | ||
</FormKit> | ||
</section> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { | ||
CreateAreaDocument, | ||
CreateAreaDraftDocument, | ||
Permission, | ||
type AbstractArea, | ||
type CreateAreaDraftMutation, | ||
type CreateAreaInput, | ||
type CreateAreaMutation, | ||
} from '~~/graphql/generated'; | ||
const { hasPermission } = useSession() | ||
const { query } = useRoute() | ||
const onlyDraft = computed(() => { | ||
if ('draft' in query) return true | ||
return !hasPermission(Permission.CreateLocation) | ||
}) | ||
const emit = defineEmits<{ | ||
(e: 'saved', data: CreateAreaMutation | CreateAreaDraftMutation): void | ||
}>() | ||
defineProps<{ | ||
updateId?: number | ||
initial?: Partial<AbstractArea> | ||
}>() | ||
const refetchQueries = ['getArea', 'getAreas'] | ||
const { mutate: createArea, error } = useMutation(CreateAreaDocument, { refetchQueries }) | ||
const { mutate: createAreaDraft, error: draftError } = useMutation(CreateAreaDraftDocument, { refetchQueries }) | ||
const errors = computed(() => | ||
[error, draftError] | ||
.map(it => it.value) | ||
.filter(notNull) | ||
.flatMap(extractMessages), | ||
) | ||
async function save(input: CreateAreaInput, draft: boolean) { | ||
const create = draft ? createAreaDraft : createArea | ||
const response = await create({ input }) | ||
const data = response?.data | ||
if (data) emit('saved', data) | ||
} | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
form { | ||
#buttons { | ||
@apply flex gap-2; | ||
} | ||
} | ||
</style> |
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,70 @@ | ||
<template> | ||
<FormKit v-model="points" name="points" placeholder="optional" label="Max-Y" type="hidden" /> | ||
<MapView id="map" :zoom="8" @click="addPoint"> | ||
<l-polygon :lat-lngs="latLngs" color="#41b782" :fill="true" :fill-opacity="0.5" fill-color="#41b782" /> | ||
<MapDraggableMarker v-for="point, i in points" :key="i" :pos="point" @dragend="updatePoint(i, $event)" /> | ||
</MapView> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { LPolygon } from '@vue-leaflet/vue-leaflet'; | ||
import { minBy } from 'lodash-es'; | ||
import type { FlatPoint, PosFragment } from '~/graphql/generated'; | ||
const context = useMap() | ||
const props = defineProps<{ | ||
initial?: FlatPoint[] | ||
}>() | ||
const points = ref<FlatPoint[]>(props.initial ?? []) | ||
const latLngs = computed(() => points.value.map(it => toMapPos(context.value!.map, it))) | ||
function distance(a: FlatPoint, b: FlatPoint) { | ||
return Math.sqrt((a.x - b.x) ** 2 + (a.z - b.z) ** 2) | ||
} | ||
function findClosest(point: FlatPoint, between: FlatPoint[]) { | ||
const min = minBy(between, it => distance(point, it)) | ||
return min && between.indexOf(min) | ||
} | ||
function addPoint(pos: PosFragment) { | ||
const { x, z } = roundPos(pos) | ||
const current = points.value | ||
const closest = findClosest({ x, z }, current) | ||
if (notNull(closest)) { | ||
const neighbours = [current[(closest - 1 + current.length) % current.length], current[(closest + 1) % current.length]] | ||
const closestNeighbour = findClosest({ x, z }, neighbours)! | ||
const newPoints = [...current] | ||
if (closestNeighbour === 0) { | ||
newPoints.splice(closest, 0, { x, z }) | ||
} else { | ||
newPoints.splice((closest + 1) % current.length, 0, { x, z }) | ||
} | ||
points.value = newPoints | ||
} else { | ||
points.value = [...points.value, { x, z }] | ||
} | ||
} | ||
function updatePoint(index: number, { x, z }: PosFragment) { | ||
const newPoints = [...points.value] | ||
newPoints[index] = roundPos({ x, z }) | ||
points.value = newPoints.map(it => { | ||
const { x, z } = roundPos(it) | ||
return { x, z } | ||
}) | ||
} | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
#map { | ||
width: 100%; | ||
aspect-ratio: 1 / 1; | ||
max-height: 500px; | ||
} | ||
</style> |
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,17 +1,45 @@ | ||
<template> | ||
<div class="grid grid-flow-col gap-4"> | ||
<FormKit name="x" validation="required" label="X" type="number" step="1" :value="floored?.x" /> | ||
<FormKit name="x" validation="required" label="X" type="number" step="1" v-model="xRef" /> | ||
<FormKit name="y" placeholder="optional" label="Y" type="number" step="1" :value="floored?.y" /> | ||
<FormKit name="z" validation="required" label="Z" type="number" step="1" :value="floored?.z" /> | ||
<FormKit name="z" validation="required" label="Z" type="number" step="1" v-model="zRef" /> | ||
</div> | ||
<MapView v-if="showMap" id="map" :zoom="8" :center="marker" @click="moveTo"> | ||
<MapDraggableMarker v-if="marker" :pos="marker" @dragend="moveTo" /> | ||
</MapView> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import type { Point } from '~~/graphql/generated'; | ||
import { type Point, type PosFragment } from '~~/graphql/generated'; | ||
const props = defineProps<{ | ||
initial?: Partial<Point> | ||
showMap?: boolean | ||
}>() | ||
const floored = computed(() => props.initial && roundPos(props.initial)) | ||
const xRef = ref<number | undefined>(floored.value?.x) | ||
const zRef = ref<number | undefined>(floored.value?.z) | ||
const marker = computed(() => { | ||
const x = xRef?.value | ||
const z = zRef?.value | ||
if (notNull(x) && notNull(z)) return { x, z } as PosFragment | ||
return undefined | ||
}) | ||
function moveTo(pos: PosFragment) { | ||
const { x, z } = roundPos(pos) | ||
xRef.value = x | ||
zRef.value = z | ||
} | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
#map { | ||
width: 100%; | ||
aspect-ratio: 1 / 1; | ||
max-height: 500px; | ||
} | ||
</style> |
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,25 @@ | ||
<template> | ||
<l-marker :lat-lng="latLng" draggable @dragend="dragEnd" /> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { LMarker } from '@vue-leaflet/vue-leaflet'; | ||
import type { DragEndEvent } from 'leaflet'; | ||
import type { FlatPoint, PosFragment } from '~/graphql/generated'; | ||
const context = useMap() | ||
const props = defineProps<{ | ||
pos: PosFragment | FlatPoint | ||
}>() | ||
const emit = defineEmits<{ | ||
(event: 'dragend', payload: PosFragment): void | ||
}>() | ||
function dragEnd(event: DragEndEvent) { | ||
emit('dragend', toWorldPos(context.value!.map, event.target._latlng)) | ||
} | ||
const latLng = computed(() => toMapPos(context.value!.map, props.pos)) | ||
</script> |
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
Oops, something went wrong.