Fix lint issues, update deps
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -8,6 +8,5 @@
|
||||
border: 2px solid;
|
||||
z-index: 2;
|
||||
flex-shrink: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +62,10 @@ const mentionOptions: MentionOptions = {
|
||||
let popup: any;
|
||||
|
||||
return {
|
||||
onStart: (props: any) => {
|
||||
onStart: (props: Record<string, any>) => {
|
||||
component = new VueRenderer(MentionList, {
|
||||
propsData: props,
|
||||
props,
|
||||
editor: props.editor,
|
||||
});
|
||||
|
||||
popup = tippy("body", {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ref, watch } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
items: IPerson[];
|
||||
command: ({ id }: { id: string }) => {};
|
||||
command: ({ id }: { id: string }) => any;
|
||||
}>();
|
||||
|
||||
// @Prop({ type: Function, required: true }) command!: any;
|
||||
@@ -31,37 +31,37 @@ watch(props.items, () => {
|
||||
selectedIndex.value = 0;
|
||||
});
|
||||
|
||||
const onKeyDown = ({ event }: { event: KeyboardEvent }): boolean => {
|
||||
if (event.key === "ArrowUp") {
|
||||
upHandler();
|
||||
return true;
|
||||
}
|
||||
// const onKeyDown = ({ event }: { event: KeyboardEvent }): boolean => {
|
||||
// if (event.key === "ArrowUp") {
|
||||
// upHandler();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (event.key === "ArrowDown") {
|
||||
downHandler();
|
||||
return true;
|
||||
}
|
||||
// if (event.key === "ArrowDown") {
|
||||
// downHandler();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (event.key === "Enter") {
|
||||
enterHandler();
|
||||
return true;
|
||||
}
|
||||
// if (event.key === "Enter") {
|
||||
// enterHandler();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
};
|
||||
// return false;
|
||||
// };
|
||||
|
||||
const upHandler = (): void => {
|
||||
selectedIndex.value =
|
||||
(selectedIndex.value + props.items.length - 1) % props.items.length;
|
||||
};
|
||||
// const upHandler = (): void => {
|
||||
// selectedIndex.value =
|
||||
// (selectedIndex.value + props.items.length - 1) % props.items.length;
|
||||
// };
|
||||
|
||||
const downHandler = (): void => {
|
||||
selectedIndex.value = (selectedIndex.value + 1) % props.items.length;
|
||||
};
|
||||
// const downHandler = (): void => {
|
||||
// selectedIndex.value = (selectedIndex.value + 1) % props.items.length;
|
||||
// };
|
||||
|
||||
const enterHandler = (): void => {
|
||||
selectItem(selectedIndex.value);
|
||||
};
|
||||
// const enterHandler = (): void => {
|
||||
// selectItem(selectedIndex.value);
|
||||
// };
|
||||
|
||||
const selectItem = (index: number): void => {
|
||||
const item = props.items[index];
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
<template>
|
||||
<div class="address-autocomplete">
|
||||
<!-- <o-field expanded>
|
||||
<o-autocomplete
|
||||
:data="addressData"
|
||||
v-model="queryText"
|
||||
:placeholder="$t('e.g. 10 Rue Jangot')"
|
||||
field="fullName"
|
||||
:loading="isFetching"
|
||||
@typing="fetchAsyncData"
|
||||
icon="map-marker"
|
||||
expanded
|
||||
@select="updateSelected"
|
||||
v-bind="$attrs"
|
||||
dir="auto"
|
||||
>
|
||||
<template #default="{ option }">
|
||||
<o-icon :icon="option.poiInfos.poiIcon.icon" />
|
||||
<b>{{ option.poiInfos.name }}</b
|
||||
><br />
|
||||
<small>{{ option.poiInfos.alternativeName }}</small>
|
||||
</template>
|
||||
</o-autocomplete>
|
||||
</o-field>
|
||||
<o-field
|
||||
v-if="canDoGeoLocation"
|
||||
:message="fieldErrors"
|
||||
:type="{ 'is-danger': fieldErrors.length }"
|
||||
>
|
||||
<o-button
|
||||
type="is-text"
|
||||
v-if="!gettingLocation"
|
||||
icon-right="target"
|
||||
@click="locateMe"
|
||||
@keyup.enter="locateMe"
|
||||
>{{ $t("Use my location") }}</o-button
|
||||
>
|
||||
<span v-else>{{ $t("Getting location") }}</span>
|
||||
</o-field> -->
|
||||
<!--
|
||||
<div v-if="selected && selected.geom" class="control">
|
||||
<o-checkbox @input="togglemap" />
|
||||
<label class="label">{{ $t("Show map") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="map" v-if="showmap && selected && selected.geom">
|
||||
<map-leaflet
|
||||
:coords="selected.geom"
|
||||
:marker="{
|
||||
text: [selected.poiInfos.name, selected.poiInfos.alternativeName],
|
||||
icon: selected.poiInfos.poiIcon.icon,
|
||||
}"
|
||||
:updateDraggableMarkerCallback="reverseGeoCode"
|
||||
:options="{ zoom: mapDefaultZoom }"
|
||||
:readOnly="false"
|
||||
/>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Prop, Watch, Vue } from "vue-property-decorator";
|
||||
import { Address, IAddress } from "../../types/address.model";
|
||||
// import AddressAutoCompleteMixin from "@/mixins/AddressAutoCompleteMixin";
|
||||
|
||||
// @Component({
|
||||
// inheritAttrs: false,
|
||||
// })
|
||||
export default class AddressAutoComplete extends Vue {
|
||||
@Prop({ required: false, default: false }) type!: string | false;
|
||||
@Prop({ required: false, default: true, type: Boolean })
|
||||
doGeoLocation!: boolean;
|
||||
|
||||
addressData: IAddress[] = [];
|
||||
|
||||
selected: IAddress = new Address();
|
||||
|
||||
initialQueryText = "";
|
||||
|
||||
addressModalActive = false;
|
||||
|
||||
showmap = false;
|
||||
|
||||
get queryText2(): string {
|
||||
if (this.value !== undefined) {
|
||||
return new Address(this.value).fullName;
|
||||
}
|
||||
return this.initialQueryText;
|
||||
}
|
||||
|
||||
set queryText2(queryText: string) {
|
||||
this.initialQueryText = queryText;
|
||||
}
|
||||
|
||||
@Watch("value")
|
||||
updateEditing(): void {
|
||||
if (!this.value?.id) return;
|
||||
this.selected = this.value;
|
||||
}
|
||||
|
||||
updateSelected(option: IAddress): void {
|
||||
if (option == null) return;
|
||||
this.selected = option;
|
||||
// this.$emit("input", this.selected);
|
||||
}
|
||||
|
||||
resetPopup(): void {
|
||||
this.selected = new Address();
|
||||
}
|
||||
|
||||
openNewAddressModal(): void {
|
||||
this.resetPopup();
|
||||
this.addressModalActive = true;
|
||||
}
|
||||
|
||||
togglemap(): void {
|
||||
this.showmap = !this.showmap;
|
||||
}
|
||||
|
||||
get canDoGeoLocation(): boolean {
|
||||
return this.isSecureContext && this.doGeoLocation;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.address-autocomplete {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.autocomplete {
|
||||
.dropdown-menu {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.dropdown-item.is-disabled {
|
||||
opacity: 1 !important;
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.read-only {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.map {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -150,7 +150,7 @@ import RouteName from "../../router/name";
|
||||
import InlineAddress from "@/components/Address/InlineAddress.vue";
|
||||
|
||||
import { computed, inject } from "vue";
|
||||
import MobilizonTag from "@/components/Tag.vue";
|
||||
import MobilizonTag from "@/components/TagElement.vue";
|
||||
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||
import Video from "vue-material-design-icons/Video.vue";
|
||||
import { formatDateTimeForEvent } from "@/utils/datetime";
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
</template>
|
||||
<a
|
||||
target="_blank"
|
||||
class="hover:underline"
|
||||
class="underline"
|
||||
rel="noopener noreferrer ugc"
|
||||
:href="event.onlineAddress"
|
||||
:title="
|
||||
|
||||
@@ -130,7 +130,7 @@ import InlineAddress from "@/components/Address/InlineAddress.vue";
|
||||
import Video from "vue-material-design-icons/Video.vue";
|
||||
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||
import AccountMultiple from "vue-material-design-icons/AccountMultiple.vue";
|
||||
import Tag from "@/components/Tag.vue";
|
||||
import Tag from "@/components/TagElement.vue";
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
|
||||
@@ -301,7 +301,7 @@ import {
|
||||
organizerAvatarUrl,
|
||||
organizerDisplayName,
|
||||
} from "@/types/event.model";
|
||||
import { displayNameAndUsername, IActor, IPerson } from "@/types/actor";
|
||||
import { displayNameAndUsername, IPerson } from "@/types/actor";
|
||||
import { CURRENT_ACTOR_CLIENT } from "@/graphql/actor";
|
||||
import RouteName from "@/router/name";
|
||||
import { changeIdentity } from "@/utils/identity";
|
||||
@@ -323,29 +323,12 @@ import { useI18n } from "vue-i18n";
|
||||
import { Dialog } from "@/plugins/dialog";
|
||||
import { Snackbar } from "@/plugins/snackbar";
|
||||
import { useDeleteEvent } from "@/composition/apollo/event";
|
||||
import Tag from "@/components/Tag.vue";
|
||||
import Tag from "@/components/TagElement.vue";
|
||||
|
||||
const defaultOptions: IEventCardOptions = {
|
||||
hideDate: true,
|
||||
loggedPerson: false,
|
||||
hideDetails: false,
|
||||
organizerActor: null,
|
||||
};
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
participation: IParticipant;
|
||||
options?: IEventCardOptions;
|
||||
}>(),
|
||||
{
|
||||
options: () => ({
|
||||
hideDate: true,
|
||||
loggedPerson: false,
|
||||
hideDetails: false,
|
||||
organizerActor: null,
|
||||
}),
|
||||
}
|
||||
);
|
||||
const props = defineProps<{
|
||||
participation: IParticipant;
|
||||
options?: IEventCardOptions;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["eventDeleted"]);
|
||||
|
||||
@@ -353,10 +336,6 @@ const { result: currentActorResult } = useQuery(CURRENT_ACTOR_CLIENT);
|
||||
const currentActor = computed(() => currentActorResult.value?.currentActor);
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
const mergedOptions = computed<IEventCardOptions>(() => {
|
||||
return { ...defaultOptions, ...props.options };
|
||||
});
|
||||
|
||||
const dialog = inject<Dialog>("dialog");
|
||||
|
||||
const openDeleteEventModal = (
|
||||
@@ -441,9 +420,8 @@ onDeleteEventError((error) => {
|
||||
* Delete the event
|
||||
*/
|
||||
const openDeleteEventModalWrapper = () => {
|
||||
openDeleteEventModal(
|
||||
props.participation.event,
|
||||
deleteEvent(props.participation.event)
|
||||
openDeleteEventModal(props.participation.event, (event: IEvent) =>
|
||||
deleteEvent({ eventId: event.id ?? "" })
|
||||
);
|
||||
};
|
||||
|
||||
@@ -474,15 +452,15 @@ const gotToWithCheck = async (
|
||||
return router.push(route);
|
||||
};
|
||||
|
||||
const organizerActor = computed<IActor | undefined>(() => {
|
||||
if (
|
||||
props.participation.event.attributedTo &&
|
||||
props.participation.event.attributedTo.id
|
||||
) {
|
||||
return props.participation.event.attributedTo;
|
||||
}
|
||||
return props.participation.event.organizerActor;
|
||||
});
|
||||
// const organizerActor = computed<IActor | undefined>(() => {
|
||||
// if (
|
||||
// props.participation.event.attributedTo &&
|
||||
// props.participation.event.attributedTo.id
|
||||
// ) {
|
||||
// return props.participation.event.attributedTo;
|
||||
// }
|
||||
// return props.participation.event.organizerActor;
|
||||
// });
|
||||
|
||||
const seatsLeft = computed<number | null>(() => {
|
||||
if (props.participation.event.options.maximumAttendeeCapacity > 0) {
|
||||
|
||||
@@ -143,7 +143,7 @@ const props = withDefaults(
|
||||
}
|
||||
);
|
||||
|
||||
const addressModalActive = ref(false);
|
||||
// const addressModalActive = ref(false);
|
||||
|
||||
const componentId = 0;
|
||||
|
||||
@@ -186,14 +186,14 @@ const updateSelected = (option: IAddress): void => {
|
||||
emit("update:modelValue", selected.value);
|
||||
};
|
||||
|
||||
const resetPopup = (): void => {
|
||||
selected.value = new Address();
|
||||
};
|
||||
// const resetPopup = (): void => {
|
||||
// selected.value = new Address();
|
||||
// };
|
||||
|
||||
const openNewAddressModal = (): void => {
|
||||
resetPopup();
|
||||
addressModalActive.value = true;
|
||||
};
|
||||
// const openNewAddressModal = (): void => {
|
||||
// resetPopup();
|
||||
// addressModalActive.value = true;
|
||||
// };
|
||||
|
||||
const checkCurrentPosition = (e: LatLng): boolean => {
|
||||
if (!selected.value?.geom) return false;
|
||||
|
||||
@@ -94,7 +94,7 @@ import ExitToApp from "vue-material-design-icons/ExitToApp.vue";
|
||||
import DotsHorizontal from "vue-material-design-icons/DotsHorizontal.vue";
|
||||
import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
|
||||
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||
import Tag from "@/components/Tag.vue";
|
||||
import Tag from "@/components/TagElement.vue";
|
||||
import { htmlToText } from "@/utils/html";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
@click="clickMap"
|
||||
@update:zoom="updateZoom"
|
||||
:options="{ zoomControl: false }"
|
||||
ref="mapComponent"
|
||||
@ready="onMapReady"
|
||||
>
|
||||
<l-tile-layer :url="tiles?.endpoint" :attribution="attribution">
|
||||
</l-tile-layer>
|
||||
@@ -16,28 +18,36 @@
|
||||
:zoomInTitle="$t('Zoom in')"
|
||||
:zoomOutTitle="$t('Zoom out')"
|
||||
></l-control-zoom>
|
||||
<!-- <v-locatecontrol
|
||||
v-if="canDoGeoLocation"
|
||||
:options="{ icon: 'mdi mdi-map-marker' }"
|
||||
/> -->
|
||||
<l-marker
|
||||
:lat-lng="[lat, lon]"
|
||||
@add="openPopup"
|
||||
@update:latLng="updateDraggableMarkerPosition"
|
||||
:draggable="!readOnly"
|
||||
>
|
||||
<l-popup v-if="popupMultiLine">
|
||||
<l-icon>
|
||||
<MapMarker :size="48" class="text-mbz-purple" />
|
||||
</l-icon>
|
||||
<l-popup v-if="popupMultiLine" :options="{ offset: new Point(22, 8) }">
|
||||
<span v-for="line in popupMultiLine" :key="line"
|
||||
>{{ line }}<br
|
||||
/></span>
|
||||
</l-popup>
|
||||
</l-marker>
|
||||
</l-map>
|
||||
<CrosshairsGps ref="locationIcon" class="hidden" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Icon, LatLng, LeafletMouseEvent, LeafletEvent } from "leaflet";
|
||||
import {
|
||||
LatLng,
|
||||
LeafletMouseEvent,
|
||||
LeafletEvent,
|
||||
Control,
|
||||
DomUtil,
|
||||
Map,
|
||||
Point,
|
||||
} from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import {
|
||||
LMap,
|
||||
@@ -47,10 +57,12 @@ import {
|
||||
LIcon,
|
||||
LControlZoom,
|
||||
} from "@vue-leaflet/vue-leaflet";
|
||||
// import Vue2LeafletLocateControl from "@/components/Map/Vue2LeafletLocateControl.vue";
|
||||
import { computed, nextTick, onMounted, ref } from "vue";
|
||||
import { useMapTiles } from "@/composition/apollo/config";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Locatecontrol from "leaflet.locatecontrol";
|
||||
import CrosshairsGps from "vue-material-design-icons/CrosshairsGps.vue";
|
||||
import MapMarker from "vue-material-design-icons/MapMarker.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -77,8 +89,18 @@ const defaultOptions: {
|
||||
|
||||
const zoom = ref(defaultOptions.zoom);
|
||||
|
||||
onMounted(() => {
|
||||
const mapComponent = ref();
|
||||
const mapObject = ref<Map>();
|
||||
const locateControl = ref<Control.Locate>();
|
||||
const locationIcon = ref();
|
||||
|
||||
const locationIconHTML = computed(() => locationIcon.value?.$el.innerHTML);
|
||||
|
||||
onMounted(async () => {
|
||||
// this part resolve an issue where the markers would not appear
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
// delete Icon.Default.prototype._getIconUrl;
|
||||
// Icon.Default.mergeOptions({
|
||||
// iconRetinaUrl: require("leaflet/dist/images/marker-icon-2x.png"),
|
||||
@@ -87,6 +109,50 @@ onMounted(() => {
|
||||
// });
|
||||
});
|
||||
|
||||
const onMapReady = async () => {
|
||||
mapObject.value = mapComponent.value.leafletObject;
|
||||
mountLocateControl();
|
||||
};
|
||||
|
||||
const mountLocateControl = () => {
|
||||
if (canDoGeoLocation.value && mapObject.value) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
locateControl.value = new Locatecontrol({
|
||||
strings: { title: t("Show me where I am") as string },
|
||||
position: "topleft",
|
||||
drawCircle: false,
|
||||
drawMarker: false,
|
||||
createButtonCallback(container: HTMLElement | undefined, options: any) {
|
||||
const link = DomUtil.create(
|
||||
"a",
|
||||
"leaflet-bar-part leaflet-bar-part-single",
|
||||
container
|
||||
);
|
||||
link.title = options.strings.title;
|
||||
link.href = "#";
|
||||
link.setAttribute("role", "button");
|
||||
|
||||
const icon = DomUtil.create(
|
||||
"span",
|
||||
"material-design-icon rss-icon",
|
||||
link
|
||||
);
|
||||
icon.setAttribute("aria-hidden", "true");
|
||||
icon.setAttribute("role", "img");
|
||||
icon.insertAdjacentHTML("beforeend", locationIconHTML.value);
|
||||
console.log("icon for location", {
|
||||
link,
|
||||
icon,
|
||||
});
|
||||
return { link, icon };
|
||||
},
|
||||
...props.options,
|
||||
}) as Control.Locate;
|
||||
locateControl.value?.addTo(mapObject.value);
|
||||
}
|
||||
};
|
||||
|
||||
const openPopup = async (event: LeafletEvent): Promise<void> => {
|
||||
await nextTick();
|
||||
event.target.openPopup();
|
||||
@@ -147,3 +213,6 @@ div.map-container {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@import "leaflet.locatecontrol/dist/L.Control.Locate.css";
|
||||
</style>
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
<template>
|
||||
<div style="display: none">
|
||||
<slot v-if="ready"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* Fork of https://github.com/domoritz/leaflet-locatecontrol
|
||||
* to try to trigger location manually (not done ATM)
|
||||
*/
|
||||
|
||||
import { DomEvent } from "leaflet";
|
||||
// import { findRealParent, propsBinder } from "vue2-leaflet";
|
||||
import Locatecontrol from "leaflet.locatecontrol";
|
||||
import { Component, Prop, Vue } from "vue-property-decorator";
|
||||
|
||||
@Component({
|
||||
beforeDestroy() {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
this.parentContainer.removeLayer(this);
|
||||
},
|
||||
})
|
||||
export default class Vue2LeafletLocateControl extends Vue {
|
||||
@Prop({ type: Object, default: () => ({}) }) options!: Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
|
||||
@Prop({ type: Boolean, default: true }) visible!: boolean;
|
||||
|
||||
ready = false;
|
||||
|
||||
mapObject!: any;
|
||||
|
||||
parentContainer: any;
|
||||
|
||||
mounted(): void {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
this.mapObject = new Locatecontrol({
|
||||
...this.options,
|
||||
strings: { title: this.$t("Show me where I am") as string },
|
||||
});
|
||||
DomEvent.on(this.mapObject, this.$listeners as any);
|
||||
propsBinder(this, this.mapObject, this.$props);
|
||||
this.ready = true;
|
||||
this.parentContainer = findRealParent(this.$parent);
|
||||
this.mapObject.addTo(this.parentContainer.mapObject, !this.visible);
|
||||
this.$nextTick(() => {
|
||||
this.$emit("ready", this.mapObject);
|
||||
});
|
||||
}
|
||||
|
||||
public locate(): void {
|
||||
this.mapObject.start();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* @import "~leaflet.locatecontrol/dist/L.Control.Locate.css"; */
|
||||
</style>
|
||||
@@ -86,6 +86,7 @@ import { IMedia } from "@/types/media.model";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Upload from "vue-material-design-icons/Upload.vue";
|
||||
import { formatBytes } from "@/utils/datetime";
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
@@ -140,14 +141,4 @@ watch(imageSrc, () => {
|
||||
const showImageLoadingError = (): void => {
|
||||
imagePreviewLoadingError.value = true;
|
||||
};
|
||||
|
||||
// https://gist.github.com/zentala/1e6f72438796d74531803cc3833c039c
|
||||
const formatBytes = (bytes: number, decimals?: number): string => {
|
||||
if (bytes == 0) return "0 Bytes";
|
||||
const k = 1024,
|
||||
dm = decimals || 2,
|
||||
sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
|
||||
i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -61,7 +61,7 @@ import { formatDateTimeString } from "@/filters/datetime";
|
||||
import Tag from "vue-material-design-icons/Tag.vue";
|
||||
import AccountEdit from "vue-material-design-icons/AccountEdit.vue";
|
||||
import Clock from "vue-material-design-icons/Clock.vue";
|
||||
import MbzTag from "@/components/Tag.vue";
|
||||
import MbzTag from "@/components/TagElement.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
||||
@@ -22,12 +22,17 @@
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="" v-if="comment">
|
||||
<article class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48" v-if="comment?.actor?.avatar">
|
||||
<img :src="comment.actor.avatar.url" alt="" />
|
||||
<article class="">
|
||||
<div class="">
|
||||
<figure class="h-8 w-8" v-if="comment?.actor?.avatar">
|
||||
<img
|
||||
:src="comment.actor.avatar.url"
|
||||
alt=""
|
||||
width="48"
|
||||
height="48"
|
||||
/>
|
||||
</figure>
|
||||
<o-icon v-else size="large" icon="account-circle" />
|
||||
<AccountCircle v-else :size="48" />
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="prose dark:prose-invert">
|
||||
@@ -65,7 +70,7 @@
|
||||
</section>
|
||||
|
||||
<footer class="flex gap-2 py-3">
|
||||
<o-button ref="cancelButton" @click="close">
|
||||
<o-button ref="cancelButton" outlined @click="close">
|
||||
{{ translatedCancelText }}
|
||||
</o-button>
|
||||
<o-button
|
||||
|
||||
@@ -75,7 +75,7 @@ import ResourceItem from "@/components/Resource/ResourceItem.vue";
|
||||
import FolderItem from "@/components/Resource/FolderItem.vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { IResource } from "@/types/resource";
|
||||
import Draggable from "@xiaoshuapp/draggable";
|
||||
import Draggable from "vuedraggable";
|
||||
import { IGroup } from "@/types/actor";
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -124,13 +124,13 @@ watch(checkedAll, () => {
|
||||
});
|
||||
});
|
||||
|
||||
const deleteResource = (resourceID: string) => {
|
||||
validCheckedResources.value = validCheckedResources.value.filter(
|
||||
(id) => id !== resourceID
|
||||
);
|
||||
delete checkedResources.value[resourceID];
|
||||
emit("delete", resourceID);
|
||||
};
|
||||
// const deleteResource = (resourceID: string) => {
|
||||
// validCheckedResources.value = validCheckedResources.value.filter(
|
||||
// (id) => id !== resourceID
|
||||
// );
|
||||
// delete checkedResources.value[resourceID];
|
||||
// emit("delete", resourceID);
|
||||
// };
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/styles/_mixins" as *;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
formatDateTimeString(resource.updatedAt?.toString())
|
||||
}}</span>
|
||||
</div>
|
||||
<!-- <draggable
|
||||
<draggable
|
||||
v-if="!inline"
|
||||
class="dropzone"
|
||||
v-model="list"
|
||||
@@ -26,7 +26,7 @@
|
||||
:sort="false"
|
||||
:group="groupObject"
|
||||
@change="onChange"
|
||||
/> -->
|
||||
/>
|
||||
</router-link>
|
||||
<resource-dropdown
|
||||
class="actions"
|
||||
@@ -39,18 +39,18 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from "vue-router";
|
||||
// import Draggable, { ChangeEvent } from "@xiaoshuapp/draggable";
|
||||
// import { SnackbarProgrammatic as Snackbar } from "buefy";
|
||||
import Draggable, { ChangeEvent } from "vuedraggable";
|
||||
import { IResource } from "@/types/resource";
|
||||
import RouteName from "@/router/name";
|
||||
import { IGroup, usernameWithDomain } from "@/types/actor";
|
||||
import ResourceDropdown from "./ResourceDropdown.vue";
|
||||
import { UPDATE_RESOURCE } from "@/graphql/resources";
|
||||
import { ref } from "vue";
|
||||
import { inject, ref } from "vue";
|
||||
import { formatDateTimeString } from "@/filters/datetime";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
import { resourcePathArray } from "@/components/Resource/utils";
|
||||
import Folder from "vue-material-design-icons/Folder.vue";
|
||||
import { Snackbar } from "@/plugins/snackbar";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -77,7 +77,7 @@ const groupObject: Record<string, unknown> = {
|
||||
|
||||
const onChange = async (evt: ChangeEvent<IResource>) => {
|
||||
if (evt.added && evt.added.element) {
|
||||
const movedResource = evt.added.element as IResource;
|
||||
// const movedResource = evt.added.element as IResource;
|
||||
moveResource({
|
||||
id: props.resource.id,
|
||||
path: `${props.resource.path}/${props.resource.title}`,
|
||||
@@ -100,19 +100,20 @@ onMovedResource(({ data }) => {
|
||||
return router.push({
|
||||
name: RouteName.RESOURCE_FOLDER,
|
||||
params: {
|
||||
path: ResourceMixin.resourcePathArray(props.resource),
|
||||
path: resourcePathArray(props.resource),
|
||||
preferredUsername: props.group.preferredUsername,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
const snackbar = inject<Snackbar>("snackbar");
|
||||
|
||||
onMovedResourceError((e) => {
|
||||
// Snackbar.open({
|
||||
// message: e.message,
|
||||
// variant: "danger",
|
||||
// position: "bottom",
|
||||
// });
|
||||
snackbar?.open({
|
||||
message: e.message,
|
||||
variant: "danger",
|
||||
position: "bottom",
|
||||
});
|
||||
return undefined;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { IResource, mapServiceTypeToIcon } from "@/types/resource";
|
||||
import ResourceDropdown from "@/components/Resource/ResourceDropdown.vue";
|
||||
import { ref, computed } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { formatDateTimeString } from "@/filters/datetime";
|
||||
import Link from "vue-material-design-icons/Link.vue";
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<div v-if="loggedUser">
|
||||
<section>
|
||||
<div class="setting-title">
|
||||
<h2>{{ $t("Settings") }}</h2>
|
||||
<h2>{{ t("Settings") }}</h2>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{{ $t("Language") }}</h3>
|
||||
<h3>{{ t("Language") }}</h3>
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"This setting will be used to display the website and send you emails in the correct language."
|
||||
)
|
||||
}}
|
||||
@@ -17,7 +17,7 @@
|
||||
<o-select
|
||||
:loading="loading"
|
||||
v-model="locale"
|
||||
:placeholder="$t('Select a language')"
|
||||
:placeholder="t('Select a language')"
|
||||
>
|
||||
<option v-for="(language, lang) in langs" :value="lang" :key="lang">
|
||||
{{ language }}
|
||||
@@ -27,15 +27,15 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>{{ $t("Timezone") }}</h3>
|
||||
<h3>{{ t("Timezone") }}</h3>
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"We use your timezone to make sure you get notifications for an event at the correct time."
|
||||
)
|
||||
}}
|
||||
{{
|
||||
$t("Your timezone was detected as {timezone}.", {
|
||||
t("Your timezone was detected as {timezone}.", {
|
||||
timezone,
|
||||
})
|
||||
}}
|
||||
@@ -43,7 +43,7 @@
|
||||
variant="danger"
|
||||
v-if="!loading && !supportedTimezone"
|
||||
>
|
||||
{{ $t("Your timezone {timezone} isn't supported.", { timezone }) }}
|
||||
{{ t("Your timezone {timezone} isn't supported.", { timezone }) }}
|
||||
</o-notification>
|
||||
</p>
|
||||
</div>
|
||||
@@ -71,14 +71,14 @@ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const { loggedUser } = useUserSettings();
|
||||
|
||||
onMounted(() => {
|
||||
updateLocale(locale.value);
|
||||
updateLocale(locale.value as string);
|
||||
doUpdateSetting({ timezone });
|
||||
});
|
||||
|
||||
watch(locale, () => {
|
||||
if (locale.value) {
|
||||
updateLocale(locale.value);
|
||||
saveLocaleData(locale.value);
|
||||
updateLocale(locale.value as string);
|
||||
saveLocaleData(locale.value as string);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -272,11 +272,11 @@ const isBasicMode = computed((): boolean => {
|
||||
return props.mode === "basic";
|
||||
});
|
||||
|
||||
const insertMention = (obj: { range: any; attrs: any }) => {
|
||||
console.debug("initialize Mention");
|
||||
};
|
||||
// const insertMention = (obj: { range: any; attrs: any }) => {
|
||||
// console.debug("initialize Mention");
|
||||
// };
|
||||
|
||||
const observer = ref<MutationObserver | null>(null);
|
||||
// const observer = ref<MutationObserver | null>(null);
|
||||
|
||||
onMounted(() => {
|
||||
editor.value = new Editor({
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// import { SnackbarProgrammatic as Snackbar } from "buefy";
|
||||
import { ITodo } from "../../types/todos";
|
||||
import RouteName from "../../router/name";
|
||||
import { UPDATE_TODO } from "../../graphql/todos";
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, inject, ref } from "vue";
|
||||
import { useMutation } from "@vue/apollo-composable";
|
||||
import Account from "vue-material-design-icons/Account.vue";
|
||||
import { formatDateString } from "@/filters/datetime";
|
||||
import { Snackbar } from "@/plugins/snackbar";
|
||||
|
||||
const props = defineProps<{ todo: ITodo }>();
|
||||
|
||||
@@ -41,8 +41,8 @@ const status = computed({
|
||||
get() {
|
||||
return props.todo.status;
|
||||
},
|
||||
set(status: boolean) {
|
||||
updateTodo({ status, id: props.todo.id });
|
||||
set(newStatus: boolean) {
|
||||
updateTodo({ status: newStatus, id: props.todo.id });
|
||||
},
|
||||
});
|
||||
|
||||
@@ -52,11 +52,13 @@ onDone(() => {
|
||||
editMode.value = false;
|
||||
});
|
||||
|
||||
const snackbar = inject<Snackbar>("snackbar");
|
||||
|
||||
onError((e) => {
|
||||
// Snackbar.open({
|
||||
// message: e.message,
|
||||
// variant: "danger",
|
||||
// position: "bottom",
|
||||
// });
|
||||
snackbar?.open({
|
||||
message: e.message,
|
||||
variant: "danger",
|
||||
position: "bottom",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<div v-if="attached && closable" class="tags has-addons">
|
||||
<span class="tag" :class="[variant, size, { rounded }]">
|
||||
<!-- <o-icon
|
||||
v-if="icon"
|
||||
:icon="icon"
|
||||
:size="size"
|
||||
:type="iconType"
|
||||
/> -->
|
||||
<span :class="{ 'has-ellipsis': ellipsis }" @click="click">
|
||||
<slot />
|
||||
</span>
|
||||
</span>
|
||||
<a
|
||||
class="tag"
|
||||
role="button"
|
||||
:aria-label="ariaCloseLabel"
|
||||
:tabindex="tabstop ? 0 : undefined"
|
||||
:disabled="disabled"
|
||||
:class="[
|
||||
size,
|
||||
closeType,
|
||||
{ 'is-rounded': rounded },
|
||||
closeIcon ? 'has-delete-icon' : 'is-delete',
|
||||
]"
|
||||
@click="close"
|
||||
@keyup.delete.prevent="close"
|
||||
>
|
||||
<!-- <o-icon
|
||||
custom-class=""
|
||||
v-if="closeIcon"
|
||||
:icon="closeIcon"
|
||||
:size="size"
|
||||
:type="closeIconType"
|
||||
/> -->
|
||||
</a>
|
||||
</div>
|
||||
<span v-else class="tag" :class="[variant, size, { 'is-rounded': rounded }]">
|
||||
<!-- <o-icon
|
||||
v-if="icon"
|
||||
:icon="icon"
|
||||
:size="size"
|
||||
:type="iconType"
|
||||
/> -->
|
||||
<span :class="{ 'has-ellipsis': ellipsis }" @click="click">
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
<a
|
||||
v-if="closable"
|
||||
role="button"
|
||||
:aria-label="ariaCloseLabel"
|
||||
class="delete is-small"
|
||||
:class="closeType"
|
||||
:disabled="disabled"
|
||||
:tabindex="tabstop ? 0 : undefined"
|
||||
@click="close"
|
||||
@keyup.delete.prevent="close"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
attached?: boolean;
|
||||
closable?: boolean;
|
||||
variant?: string;
|
||||
size?: string;
|
||||
rounded?: boolean;
|
||||
disabled?: boolean;
|
||||
ellipsis?: boolean;
|
||||
tabstop?: boolean;
|
||||
ariaCloseLabel?: string;
|
||||
icon?: string;
|
||||
iconType?: string;
|
||||
closeType?: string;
|
||||
closeIcon?: string;
|
||||
closeIconType?: string;
|
||||
}>(),
|
||||
{
|
||||
tabstop: true,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(["close", "click"]);
|
||||
|
||||
/**
|
||||
* Emit close event when delete button is clicked
|
||||
* or delete key is pressed.
|
||||
*/
|
||||
const close = (event: Event) => {
|
||||
if (props.disabled) return;
|
||||
emit("close", event);
|
||||
};
|
||||
/**
|
||||
* Emit click event when tag is clicked.
|
||||
*/
|
||||
const click = (event: Event) => {
|
||||
if (props.disabled) return;
|
||||
emit("click", event);
|
||||
};
|
||||
</script>
|
||||
@@ -26,13 +26,12 @@
|
||||
<o-field v-if="hasInput">
|
||||
<o-input
|
||||
v-model="prompt"
|
||||
expanded
|
||||
class="input"
|
||||
ref="input"
|
||||
:class="{ 'is-danger': validationMessage }"
|
||||
v-bind="inputAttrs"
|
||||
@keydown.enter="confirm"
|
||||
/>
|
||||
<p class="help is-danger">{{ validationMessage }}</p>
|
||||
</o-field>
|
||||
</div>
|
||||
</section>
|
||||
@@ -83,15 +82,14 @@ const emit = defineEmits(["confirm", "cancel", "close"]);
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
const modalOpened = ref(false);
|
||||
const validationMessage = ref("");
|
||||
// const modalOpened = ref(false);
|
||||
|
||||
const prompt = ref<string>(props.hasInput ? props.inputAttrs?.value ?? "" : "");
|
||||
const input = ref();
|
||||
|
||||
const dialogClass = computed(() => {
|
||||
return [props.size];
|
||||
});
|
||||
// const dialogClass = computed(() => {
|
||||
// return [props.size];
|
||||
// });
|
||||
/**
|
||||
* Icon name (MDI) based on the type.
|
||||
*/
|
||||
@@ -114,10 +112,11 @@ const iconByType = computed(() => {
|
||||
* Call the onConfirm prop (function) and close the Dialog.
|
||||
*/
|
||||
const confirm = () => {
|
||||
console.log("dialog confirmed", input.value.$el);
|
||||
if (input.value !== undefined) {
|
||||
if (!input.value.checkValidity()) {
|
||||
validationMessage.value = input.value.validationMessage;
|
||||
nextTick(() => input.value.select());
|
||||
const inputElement = input.value.$el.querySelector("input");
|
||||
if (!inputElement.checkValidity()) {
|
||||
nextTick(() => inputElement.select());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ const props = withDefaults(
|
||||
indefinite?: boolean;
|
||||
}>(),
|
||||
{
|
||||
onAction: () => {},
|
||||
onAction: () => {
|
||||
// do nothing
|
||||
},
|
||||
cancelText: null,
|
||||
variant: "dark",
|
||||
position: "bottom-right",
|
||||
|
||||
Reference in New Issue
Block a user