Add page titles (#4775)

* restructure template rendering

* add useTitle composable

* Split up render-string-template from getFieldsFromTemplate

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
Nitwel
2021-03-31 16:53:57 +02:00
committed by GitHub
parent 8df659325c
commit 6f9b2cafcd
13 changed files with 81 additions and 50 deletions

View File

@@ -0,0 +1,4 @@
import { useTitle } from './use-title';
export { useTitle };
export default useTitle;

View File

@@ -0,0 +1,18 @@
import { ref, Ref, watch } from '@vue/composition-api';
import { TranslateResult } from 'vue-i18n';
export function useTitle(newTitle: string | Ref<string>) {
if (newTitle === undefined || newTitle === null) return;
const titleRef = typeof newTitle === 'string' ? ref(newTitle) : newTitle;
watch(
titleRef,
(title, oldTitle) => {
if (typeof title === 'string' && oldTitle !== title) document.title = title;
},
{ immediate: true }
);
return titleRef;
}

View File

@@ -1,6 +1,6 @@
import { defineDisplay } from '@/displays/define';
import DisplayRelatedValues from './related-values.vue';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
import adjustFieldsForDisplays from '@/utils/adjust-fields-for-displays';
import getRelatedCollection from '@/utils/get-related-collection';
import useCollection from '@/composables/use-collection';

View File

@@ -28,26 +28,11 @@
<template #append v-if="!disabled">
<template v-if="currentItem">
<v-icon
name="open_in_new"
class="edit"
v-tooltip="$t('edit')"
@click.stop="editModalActive = true"
/>
<v-icon
name="close"
class="deselect"
@click.stop="$emit('input', null)"
v-tooltip="$t('deselect')"
/>
<v-icon name="open_in_new" class="edit" v-tooltip="$t('edit')" @click.stop="editModalActive = true" />
<v-icon name="close" class="deselect" @click.stop="$emit('input', null)" v-tooltip="$t('deselect')" />
</template>
<template v-else>
<v-icon
class="add"
name="add"
v-tooltip="$t('create_item')"
@click.stop="editModalActive = true"
/>
<v-icon class="add" name="add" v-tooltip="$t('create_item')" @click.stop="editModalActive = true" />
<v-icon class="expand" :class="{ active }" name="expand_more" />
</template>
</template>
@@ -71,11 +56,7 @@
@click="setCurrent(item)"
>
<v-list-item-content>
<render-template
:collection="relatedCollection.collection"
:template="displayTemplate"
:item="item"
/>
<render-template :collection="relatedCollection.collection" :template="displayTemplate" :item="item" />
</v-list-item-content>
</v-list-item>
</template>
@@ -105,7 +86,7 @@
import { defineComponent, computed, ref, toRefs, watch, PropType } from '@vue/composition-api';
import { useCollectionsStore, useRelationsStore } from '@/stores/';
import useCollection from '@/composables/use-collection';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
import api from '@/api';
import DrawerItem from '@/views/private/components/drawer-item';
import DrawerCollection from '@/views/private/components/drawer-collection';

View File

@@ -10,8 +10,7 @@
<script lang="ts">
import { defineComponent, computed } from '@vue/composition-api';
import { render } from 'micromustache';
import i18n from '@/lang';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
export default defineComponent({
props: {

View File

@@ -33,7 +33,7 @@ import { defineComponent, PropType, computed, ref, watch } from '@vue/compositio
import { useRelationsStore } from '@/stores/';
import api from '@/api';
import { Relation } from '@/types';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
import DrawerItem from '@/views/private/components/drawer-item/drawer-item.vue';
import { useCollection } from '@/composables/use-collection';
import { unexpectedError } from '@/utils/unexpected-error';

View File

@@ -50,7 +50,7 @@ import { defineComponent, ref, computed, PropType, onMounted, watch } from '@vue
import { useCollection } from '@/composables/use-collection';
import { useRelationsStore } from '@/stores';
import api from '@/api';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
import draggable from 'vuedraggable';
import hideDragImage from '@/utils/hide-drag-image';
import NestedDraggable from './nested-draggable.vue';

View File

@@ -141,7 +141,7 @@ import useSync from '@/composables/use-sync/';
import useCollection from '@/composables/use-collection/';
import useItems from '@/composables/use-items';
import Card from './components/card.vue';
import getFieldsFromTemplate from '@/utils/get-fields-from-template';
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
import { useRelationsStore } from '@/stores/';
import CardsHeader from './components/header.vue';

View File

@@ -207,6 +207,8 @@ import useShortcut from '@/composables/use-shortcut';
import { NavigationGuard } from 'vue-router';
import { usePermissions } from '@/composables/use-permissions';
import unsavedChanges from '@/composables/unsaved-changes';
import { useTitle } from '@/composables/use-title';
import { renderStringTemplate } from '@/utils/render-string-template';
export default defineComponent({
name: 'collections-item',
@@ -300,6 +302,24 @@ export default defineComponent({
: i18n.t('editing_in', { collection: collectionInfo.value?.name });
});
const tabTitle = computed(() => {
let tabTitle = (collectionInfo.value?.name || '') + ' | ';
if (collectionInfo.value && collectionInfo.value.meta) {
if (collectionInfo.value.meta.singleton === true) {
return tabTitle + collectionInfo.value.name;
} else if (isNew.value === false && collectionInfo.value.meta.display_template) {
const { displayValue } = renderStringTemplate(collectionInfo.value.meta.display_template, templateValues);
if (displayValue.value !== undefined) return tabTitle + displayValue.value;
}
}
return tabTitle + title.value;
});
useTitle(tabTitle);
const archiveTooltip = computed(() => {
if (archiveAllowed.value === false) return i18n.t('not_allowed');
if (isArchived.value === true) return i18n.t('unarchive');

View File

@@ -1,6 +1,8 @@
export default function getFieldsFromTemplate(string: string) {
export function getFieldsFromTemplate(template: string | null) {
if (template === null) return [];
const regex = /{{(.*?)}}/g;
let fields = string.match(regex);
let fields = template.match(regex);
if (!Array.isArray(fields)) {
return [];
@@ -9,5 +11,5 @@ export default function getFieldsFromTemplate(string: string) {
fields = fields.map((field) => {
return field.replace(/{{/g, '').replace(/}}/g, '').trim();
});
return fields;
return fields as string[];
}

View File

@@ -1,4 +0,0 @@
import getFieldsFromTemplate from './get-fields-from-template';
export { getFieldsFromTemplate };
export default getFieldsFromTemplate;

View File

@@ -0,0 +1,19 @@
import { computed, Ref } from '@vue/composition-api';
import { render } from 'micromustache';
import { getFieldsFromTemplate } from './get-fields-from-template';
export function renderStringTemplate(template: Ref<string | null> | string, item: Ref<Record<string, any> | null>) {
const templateString = computed(() => (typeof template === 'string' ? template : template.value));
const fieldsInTemplate = computed(() => getFieldsFromTemplate(templateString.value));
const displayValue = computed(() => {
if (!item.value || !templateString.value || !fieldsInTemplate.value) return;
try {
return render(templateString.value, item.value, { propsExist: true });
} catch {}
});
return { fieldsInTemplate, displayValue };
}

View File

@@ -72,6 +72,7 @@ import NotificationsPreview from './components/notifications-preview/';
import NotificationDialogs from './components/notification-dialogs/';
import { useUserStore, useAppStore } from '@/stores';
import router from '@/router';
import useTitle from '@/composables/use-title';
export default defineComponent({
components: {
@@ -90,7 +91,8 @@ export default defineComponent({
default: null,
},
},
setup() {
setup(props) {
const { title } = toRefs(props);
const navOpen = ref(false);
const contentEl = ref<Element>();
const userStore = useUserStore();
@@ -113,20 +115,10 @@ export default defineComponent({
router.afterEach(async (to, from) => {
contentEl.value?.scrollTo({ top: 0 });
// await nextTick();
// const hash = to.hash;
// if (hash) {
// const linkedEl = document.querySelector(hash) as HTMLElement;
// if (linkedEl) {
// contentEl.value?.scrollTo({ top: linkedEl.offsetTop - 100, behavior: 'smooth' });
// }
// }
});
useTitle(title);
return {
navOpen,
contentEl,