FollowTarget improvements
- Show current world/location when follow target is visible - Add ellipsis overflow - Add copy location on click
This commit is contained in:
parent
6d49021220
commit
6717cab096
@ -47,8 +47,7 @@ import {LeafletMouseEvent} from "leaflet";
|
|||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import WorldListItem from "@/components/sidebar/WorldListItem.vue";
|
import WorldListItem from "@/components/sidebar/WorldListItem.vue";
|
||||||
import {CSSProperties, ref} from "vue";
|
import {CSSProperties, ref} from "vue";
|
||||||
import {getUrlForLocation} from "@/util";
|
import {clipboardError, clipboardSuccess, getUrlForLocation} from "@/util";
|
||||||
import {notify} from "@kyvg/vue3-notification";
|
|
||||||
import {nextTick} from 'vue';
|
import {nextTick} from 'vue';
|
||||||
import {handleKeyboardEvent} from "@/util/events";
|
import {handleKeyboardEvent} from "@/util/events";
|
||||||
|
|
||||||
@ -69,8 +68,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
messageCopyLink = computed(() => store.state.messages.contextMenuCopyLink),
|
messageCopyLink = computed(() => store.state.messages.contextMenuCopyLink),
|
||||||
messageCenterHere = computed(() => store.state.messages.contextMenuCenterHere),
|
messageCenterHere = computed(() => store.state.messages.contextMenuCenterHere),
|
||||||
messageCopySuccess = computed(() => store.state.messages.copyToClipboardSuccess),
|
|
||||||
messageCopyError = computed(() => store.state.messages.copyToClipboardError),
|
|
||||||
|
|
||||||
menuElement = ref<HTMLInputElement | null>(null),
|
menuElement = ref<HTMLInputElement | null>(null),
|
||||||
menuVisible = computed(() => !!event.value),
|
menuVisible = computed(() => !!event.value),
|
||||||
@ -162,12 +159,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const copySuccess = () => notify(messageCopySuccess.value);
|
|
||||||
const copyError = (e: Error) => {
|
|
||||||
notify({ type: 'error', text: messageCopyError.value });
|
|
||||||
console.error('Error copying to clipboard', e);
|
|
||||||
};
|
|
||||||
|
|
||||||
watch(event, value => {
|
watch(event, value => {
|
||||||
if(value) {
|
if(value) {
|
||||||
props.leaflet.closePopup();
|
props.leaflet.closePopup();
|
||||||
@ -221,8 +212,8 @@ export default defineComponent({
|
|||||||
messageCopyLink,
|
messageCopyLink,
|
||||||
messageCenterHere,
|
messageCenterHere,
|
||||||
|
|
||||||
copySuccess,
|
copySuccess: clipboardSuccess(),
|
||||||
copyError,
|
copyError: clipboardError(),
|
||||||
|
|
||||||
menuVisible,
|
menuVisible,
|
||||||
menuElement,
|
menuElement,
|
||||||
|
@ -21,7 +21,10 @@
|
|||||||
<div :class="{'following__target': true, 'following__target--hidden': target.hidden}">
|
<div :class="{'following__target': true, 'following__target--hidden': target.hidden}">
|
||||||
<img v-if="imagesEnabled" width="32" height="32" class="target__icon" :src="image" alt="" />
|
<img v-if="imagesEnabled" width="32" height="32" class="target__icon" :src="image" alt="" />
|
||||||
<span class="target__name" v-html="target.displayName"></span>
|
<span class="target__name" v-html="target.displayName"></span>
|
||||||
<span class="target__status" v-show="target.hidden">{{ messageHidden }}</span>
|
<span class="target__status">{{ status }}</span>
|
||||||
|
<span class="target__location" v-show="!target.hidden" v-clipboard:copy="location"
|
||||||
|
v-clipboard:success="copySuccess"
|
||||||
|
v-clipboard:error="copyError">{{ location }}</span>
|
||||||
<button class="target__unfollow" type="button" :title="messageUnfollowTitle"
|
<button class="target__unfollow" type="button" :title="messageUnfollowTitle"
|
||||||
@click.prevent="unfollow" :aria-label="messageUnfollow">
|
@click.prevent="unfollow" :aria-label="messageUnfollow">
|
||||||
<SvgIcon name="cross"></SvgIcon>
|
<SvgIcon name="cross"></SvgIcon>
|
||||||
@ -34,7 +37,7 @@
|
|||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import {MutationTypes} from "@/store/mutation-types";
|
import {MutationTypes} from "@/store/mutation-types";
|
||||||
import {computed, defineComponent, onMounted, ref, watch} from "@vue/runtime-core";
|
import {computed, defineComponent, onMounted, ref, watch} from "@vue/runtime-core";
|
||||||
import {getMinecraftHead} from '@/util';
|
import {clipboardError, clipboardSuccess, getMinecraftHead} from '@/util';
|
||||||
import defaultImage from '@/assets/images/player_face.png';
|
import defaultImage from '@/assets/images/player_face.png';
|
||||||
import {LiveAtlasPlayer} from "@/index";
|
import {LiveAtlasPlayer} from "@/index";
|
||||||
import SvgIcon from "@/components/SvgIcon.vue";
|
import SvgIcon from "@/components/SvgIcon.vue";
|
||||||
@ -60,17 +63,35 @@ export default defineComponent({
|
|||||||
messageUnfollowTitle = computed(() => store.state.messages.followingTitleUnfollow),
|
messageUnfollowTitle = computed(() => store.state.messages.followingTitleUnfollow),
|
||||||
messageHidden = computed(() => store.state.messages.followingHidden),
|
messageHidden = computed(() => store.state.messages.followingHidden),
|
||||||
|
|
||||||
|
status = computed(() => {
|
||||||
|
if (props.target.hidden) {
|
||||||
|
return messageHidden.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const world = store.state.worlds.get(props.target.location.world || '');
|
||||||
|
return world ? world.displayName : messageHidden.value;
|
||||||
|
}),
|
||||||
|
|
||||||
|
location = computed(() => {
|
||||||
|
if (props.target.hidden) {
|
||||||
|
return messageHidden.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${Math.floor(props.target.location.x)}, ${props.target.location.y}, ${Math.floor(props.target.location.z)}`;
|
||||||
|
}),
|
||||||
|
|
||||||
unfollow = () => {
|
unfollow = () => {
|
||||||
store.commit(MutationTypes.CLEAR_FOLLOW_TARGET, undefined);
|
store.commit(MutationTypes.CLEAR_FOLLOW_TARGET, undefined);
|
||||||
},
|
},
|
||||||
updatePlayerImage = async () => {
|
updatePlayerImage = async () => {
|
||||||
image.value = defaultImage;
|
image.value = defaultImage;
|
||||||
|
|
||||||
if(imagesEnabled.value) {
|
if (imagesEnabled.value) {
|
||||||
try {
|
try {
|
||||||
const result = await getMinecraftHead(props.target, 'small');
|
const result = await getMinecraftHead(props.target, 'small');
|
||||||
image.value = result.src;
|
image.value = result.src;
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,6 +106,10 @@ export default defineComponent({
|
|||||||
messageUnfollow,
|
messageUnfollow,
|
||||||
messageUnfollowTitle,
|
messageUnfollowTitle,
|
||||||
messageHidden,
|
messageHidden,
|
||||||
|
status,
|
||||||
|
location,
|
||||||
|
copySuccess: clipboardSuccess(),
|
||||||
|
copyError: clipboardError(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -99,8 +124,8 @@ export default defineComponent({
|
|||||||
.following__target {
|
.following__target {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
grid-template-rows: 1fr min-content min-content 1fr;
|
grid-template-rows: 1fr min-content min-content min-content 1fr;
|
||||||
grid-template-areas: "icon ." "icon name" "icon status" "icon .";
|
grid-template-areas: "icon ." "icon name" "icon status" "icon location" "icon .";
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
@ -136,12 +161,24 @@ export default defineComponent({
|
|||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.target__location {
|
||||||
|
grid-area: location;
|
||||||
|
font-family: monospace;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
&.following__target--hidden {
|
&.following__target--hidden {
|
||||||
.target__icon {
|
.target__icon {
|
||||||
filter: grayscale(1);
|
filter: grayscale(1);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px), (max-height: 480px) {
|
@media (max-width: 480px), (max-height: 480px) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
||||||
import {HeadQueueEntry, LiveAtlasPlayer, LiveAtlasPlayerImageSize} from "@/index";
|
import {HeadQueueEntry, LiveAtlasPlayer, LiveAtlasPlayerImageSize} from "@/index";
|
||||||
|
import {notify} from "@kyvg/vue3-notification";
|
||||||
|
|
||||||
const headCache = new Map<string, HTMLImageElement>(),
|
const headCache = new Map<string, HTMLImageElement>(),
|
||||||
headUnresolvedCache = new Map<string, Promise<HTMLImageElement>>(),
|
headUnresolvedCache = new Map<string, Promise<HTMLImageElement>>(),
|
||||||
@ -203,3 +204,11 @@ export const focus = (selector: string) => {
|
|||||||
(element as HTMLElement).focus();
|
(element as HTMLElement).focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const clipboardSuccess = () => () => notify(useStore().state.messages.copyToClipboardSuccess);
|
||||||
|
|
||||||
|
export const clipboardError = () => (e: Error) => {
|
||||||
|
notify({ type: 'error', text: useStore().state.messages.copyToClipboardError });
|
||||||
|
console.error('Error copying to clipboard', e);
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user