mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-02 12:49:02 -05:00
added titles
This commit is contained in:
@@ -137,15 +137,21 @@ import MessageListDialog from "@/components/dialogs/MessageListDialog.vue";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import NavigationDrawerContextMenu from "@/components/display/NavigationDrawerContextMenu.vue";
|
||||
import {useDjangoUrls} from "@/composables/useDjangoUrls";
|
||||
import {onMounted} from "vue";
|
||||
import {nextTick, onMounted} from "vue";
|
||||
import {isSpaceAboveLimit} from "@/utils/logic_utils";
|
||||
import {useMediaQuery} from "@vueuse/core";
|
||||
import {useMediaQuery, useTitle} from "@vueuse/core";
|
||||
import HelpDialog from "@/components/dialogs/HelpDialog.vue";
|
||||
import {NAVIGATION_DRAWER} from "@/utils/navigation.ts";
|
||||
import {useNavigation} from "@/composables/useNavigation.ts";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const {lgAndUp} = useDisplay()
|
||||
const {getDjangoUrl} = useDjangoUrls()
|
||||
const {t} = useI18n()
|
||||
|
||||
const title = useTitle()
|
||||
const router = useRouter()
|
||||
|
||||
const isPrintMode = useMediaQuery('print')
|
||||
|
||||
@@ -153,6 +159,19 @@ onMounted(() => {
|
||||
useUserPreferenceStore()
|
||||
})
|
||||
|
||||
/**
|
||||
* global title update handler, might be overridden by page specific handlers
|
||||
*/
|
||||
router.afterEach((to, from) => {
|
||||
nextTick(() => {
|
||||
if (to.meta.title) {
|
||||
title.value = t(to.meta.title)
|
||||
} else {
|
||||
title.value = 'Tandoor'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -8,54 +8,54 @@ import vuetify from "@/vuetify";
|
||||
import mavonEditor from 'mavon-editor'
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
import 'vite/modulepreload-polyfill';
|
||||
import { createRulesPlugin } from 'vuetify/labs/rules'
|
||||
import {createRulesPlugin} from 'vuetify/labs/rules'
|
||||
|
||||
import {setupI18n} from "@/i18n";
|
||||
import MealPlanPage from "@/pages/MealPlanPage.vue";
|
||||
import {TANDOOR_PLUGINS, TandoorPlugin} from "@/types/Plugins.ts";
|
||||
|
||||
let routes = [
|
||||
{path: '/', component: () => import("@/pages/StartPage.vue"), name: 'StartPage'},
|
||||
{path: '/', component: () => import("@/pages/StartPage.vue"), name: 'StartPage' },
|
||||
{path: '/search', redirect: {name: 'StartPage'}},
|
||||
{path: '/test', component: () => import("@/pages/TestPage.vue"), name: 'view_test'},
|
||||
{path: '/help', component: () => import("@/pages/HelpPage.vue"), name: 'HelpPage'},
|
||||
{path: '/help', component: () => import("@/pages/HelpPage.vue"), name: 'HelpPage', meta: {title: 'Help'}},
|
||||
{
|
||||
path: '/settings', component: () => import("@/pages/SettingsPage.vue"), name: 'SettingsPage', redirect: '/settings/account',
|
||||
children: [
|
||||
{path: 'account', component: () => import("@/components/settings/AccountSettings.vue"), name: 'AccountSettings'},
|
||||
{path: 'cosmetic', component: () => import("@/components/settings/CosmeticSettings.vue"), name: 'CosmeticSettings'},
|
||||
{path: 'shopping', component: () => import("@/components/settings/ShoppingSettings.vue"), name: 'ShoppingSettings'},
|
||||
{path: 'meal-plan', component: () => import("@/components/settings/MealPlanSettings.vue"), name: 'MealPlanSettings'},
|
||||
{path: 'search', component: () => import("@/components/settings/SearchSettings.vue"), name: 'SearchSettings'},
|
||||
{path: 'space', component: () => import("@/components/settings/SpaceSettings.vue"), name: 'SpaceSettings'},
|
||||
{path: 'space-members', component: () => import("@/components/settings/SpaceMemberSettings.vue"), name: 'SpaceMemberSettings'},
|
||||
{path: 'user-space', component: () => import("@/components/settings/UserSpaceSettings.vue"), name: 'UserSpaceSettings'},
|
||||
{path: 'open-data-import', component: () => import("@/components/settings/OpenDataImportSettings.vue"), name: 'OpenDataImportSettings'},
|
||||
{path: 'export', component: () => import("@/components/settings/ExportDataSettings.vue"), name: 'ExportDataSettings'},
|
||||
{path: 'api', component: () => import("@/components/settings/ApiSettings.vue"), name: 'ApiSettings'},
|
||||
]
|
||||
{path: 'account', component: () => import("@/components/settings/AccountSettings.vue"), name: 'AccountSettings', meta: {title: 'Settings'}},
|
||||
{path: 'cosmetic', component: () => import("@/components/settings/CosmeticSettings.vue"), name: 'CosmeticSettings', meta: {title: 'Settings'}},
|
||||
{path: 'shopping', component: () => import("@/components/settings/ShoppingSettings.vue"), name: 'ShoppingSettings', meta: {title: 'Settings'}},
|
||||
{path: 'meal-plan', component: () => import("@/components/settings/MealPlanSettings.vue"), name: 'MealPlanSettings', meta: {title: 'Settings'}},
|
||||
{path: 'search', component: () => import("@/components/settings/SearchSettings.vue"), name: 'SearchSettings', meta: {title: 'Settings'}},
|
||||
{path: 'space', component: () => import("@/components/settings/SpaceSettings.vue"), name: 'SpaceSettings', meta: {title: 'Settings'}},
|
||||
{path: 'space-members', component: () => import("@/components/settings/SpaceMemberSettings.vue"), name: 'SpaceMemberSettings', meta: {title: 'Settings'}},
|
||||
{path: 'user-space', component: () => import("@/components/settings/UserSpaceSettings.vue"), name: 'UserSpaceSettings', meta: {title: 'Settings'}},
|
||||
{path: 'open-data-import', component: () => import("@/components/settings/OpenDataImportSettings.vue"), name: 'OpenDataImportSettings', meta: {title: 'Settings'}},
|
||||
{path: 'export', component: () => import("@/components/settings/ExportDataSettings.vue"), name: 'ExportDataSettings', meta: {title: 'Settings'}},
|
||||
{path: 'api', component: () => import("@/components/settings/ApiSettings.vue"), name: 'ApiSettings', meta: {title: 'Settings'}},
|
||||
], meta: {title: 'Settings'}
|
||||
},
|
||||
//{path: '/settings/:page', component: SettingsPage, name: 'view_settings_page', props: true},
|
||||
{path: '/advanced-search', component: () => import("@/pages/SearchPage.vue"), name: 'SearchPage'},
|
||||
{path: '/shopping', component: () => import("@/pages/ShoppingListPage.vue"), name: 'ShoppingListPage'},
|
||||
{path: '/mealplan', component: MealPlanPage, name: 'MealPlanPage'},
|
||||
{path: '/books', component: () => import("@/pages/BooksPage.vue"), name: 'BooksPage'},
|
||||
{path: '/book/:bookId', component: () => import("@/pages/BookViewPage.vue"), name: 'BookViewPage', props: true},
|
||||
{path: '/recipe/import', component: () => import("@/pages/RecipeImportPage.vue"), name: 'RecipeImportPage'},
|
||||
{path: '/advanced-search', component: () => import("@/pages/SearchPage.vue"), name: 'SearchPage', meta: {title: 'Search'}},
|
||||
{path: '/shopping', component: () => import("@/pages/ShoppingListPage.vue"), name: 'ShoppingListPage', meta: {title: 'Shopping_list'}},
|
||||
{path: '/mealplan', component: MealPlanPage, name: 'MealPlanPage', meta: {title: 'Meal_Plan'}},
|
||||
{path: '/books', component: () => import("@/pages/BooksPage.vue"), name: 'BooksPage', meta: {title: 'Books'}},
|
||||
{path: '/book/:bookId', component: () => import("@/pages/BookViewPage.vue"), name: 'BookViewPage', props: true, meta: {title: 'Book'}},
|
||||
{path: '/recipe/import', component: () => import("@/pages/RecipeImportPage.vue"), name: 'RecipeImportPage', meta: {title: 'Import'}},
|
||||
|
||||
{path: '/recipe/:id', component: () => import("@/pages/RecipeViewPage.vue"), name: 'RecipeViewPage', props: true},
|
||||
{path: '/recipe/:id', component: () => import("@/pages/RecipeViewPage.vue"), name: 'RecipeViewPage', props: true, meta: {title: 'Recipe'}},
|
||||
{path: '/view/recipe/:id', redirect: {name: 'RecipeViewPage'}}, // old Tandoor v1 url pattern
|
||||
|
||||
{path: '/list/:model?', component: () => import("@/pages/ModelListPage.vue"), props: true, name: 'ModelListPage'},
|
||||
{path: '/edit/:model/:id?', component: () => import("@/pages/ModelEditPage.vue"), props: true, name: 'ModelEditPage'},
|
||||
{path: '/database', component: () => import("@/pages/DatabasePage.vue"), props: true, name: 'DatabasePage'},
|
||||
{path: '/database', component: () => import("@/pages/DatabasePage.vue"), props: true, name: 'DatabasePage', meta: {title: 'Database'}},
|
||||
|
||||
{path: '/ingredient-editor', component: () => import("@/pages/IngredientEditorPage.vue"), name: 'IngredientEditorPage'},
|
||||
{path: '/property-editor', component: () => import("@/pages/PropertyEditorPage.vue"), name: 'PropertyEditorPage'},
|
||||
{path: '/ingredient-editor', component: () => import("@/pages/IngredientEditorPage.vue"), name: 'IngredientEditorPage', meta: {title: 'Ingredient Editor'}},
|
||||
{path: '/property-editor', component: () => import("@/pages/PropertyEditorPage.vue"), name: 'PropertyEditorPage', meta: {title: 'Property_Editor'}},
|
||||
|
||||
{path: '/space-setup', component: () => import("@/pages/SpaceSetupPage.vue"), name: 'SpaceSetupPage'},
|
||||
|
||||
{path: '/:pathMatch(.*)*', component: () => import("@/pages/404Page.vue"), name: '404Page'},
|
||||
{path: '/:pathMatch(.*)*', component: () => import("@/pages/404Page.vue"), name: '404Page', meta: {title: 'NotFound'}},
|
||||
]
|
||||
|
||||
// load plugin routes into routing table
|
||||
@@ -74,7 +74,7 @@ const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(vuetify)
|
||||
app.use(createRulesPlugin({ /* options */ }, vuetify.locale))
|
||||
app.use(createRulesPlugin({ /* options */}, vuetify.locale))
|
||||
app.use(router)
|
||||
app.use(i18n)
|
||||
app.use(mavonEditor) // TODO only use on pages that need it
|
||||
|
||||
@@ -265,7 +265,7 @@ function aiConvertRecipe() {
|
||||
})
|
||||
|
||||
} else {
|
||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, [r.error, r.msg])
|
||||
}
|
||||
|
||||
}).catch(err => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {useI18n} from "vue-i18n";
|
||||
import {ResponseError} from "@/openapi";
|
||||
import {getNestedProperty} from "@/utils/utils";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import {useTitle} from "@vueuse/core";
|
||||
|
||||
// TODO type emit parameter (https://mokkapps.de/vue-tips/emit-event-from-composable)
|
||||
// TODO alternatively there seems to be a getContext method to get the calling context (good practice?)
|
||||
@@ -18,6 +19,7 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
|
||||
const editingObjChanged = ref(false)
|
||||
|
||||
const {t} = useI18n()
|
||||
const title = useTitle()
|
||||
|
||||
/**
|
||||
* watch editing object to detect changes
|
||||
@@ -108,12 +110,14 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
|
||||
newItemFunction()
|
||||
|
||||
loading.value = false
|
||||
title.value = editingObjName()
|
||||
return Promise.resolve(editingObj.value)
|
||||
} else if (item !== null) {
|
||||
// item is given so return that
|
||||
editingObj.value = item
|
||||
existingItemFunction()
|
||||
loading.value = false
|
||||
title.value = editingObjName()
|
||||
return Promise.resolve(editingObj.value)
|
||||
} else if (itemId !== undefined && itemId != '') {
|
||||
// itemId is given => fetch from server and return item
|
||||
@@ -126,6 +130,7 @@ export function useModelEditorFunctions<T>(modelName: EditorSupportedModels, emi
|
||||
return modelClass.value.retrieve(itemId).then((r: T) => {
|
||||
editingObj.value = r
|
||||
existingItemFunction()
|
||||
title.value = editingObjName()
|
||||
return editingObj.value
|
||||
}).catch((err: any) => {
|
||||
if (err instanceof ResponseError && err.response.status == 404) {
|
||||
|
||||
@@ -101,10 +101,12 @@ import ModelMergeDialog from "@/components/dialogs/ModelMergeDialog.vue";
|
||||
import {VDataTableUpdateOptions} from "@/vuetify";
|
||||
import SyncDialog from "@/components/dialogs/SyncDialog.vue";
|
||||
import {ApiApi, RecipeImport} from "@/openapi";
|
||||
import {useTitle} from "@vueuse/core";
|
||||
|
||||
const {t} = useI18n()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const title = useTitle()
|
||||
|
||||
const props = defineProps({
|
||||
model: {
|
||||
@@ -160,6 +162,8 @@ onBeforeMount(() => {
|
||||
genericModel.value = getGenericModelFromString('Food', t)
|
||||
}
|
||||
|
||||
title.value = t(genericModel.value.model.localizationKey)
|
||||
|
||||
if (typeof route.query.page == "string" && !isNaN(parseInt(route.query.page))) {
|
||||
tablePage.value = parseInt(route.query.page)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import {onMounted, ref, watch} from 'vue'
|
||||
import {ApiApi, ApiRecipeRetrieveRequest, Recipe, ViewLog} from "@/openapi";
|
||||
import RecipeView from "@/components/display/RecipeView.vue";
|
||||
import {useDisplay} from "vuetify";
|
||||
import {useUrlSearchParams} from "@vueuse/core";
|
||||
import {useTitle, useUrlSearchParams} from "@vueuse/core";
|
||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
|
||||
@@ -20,6 +20,7 @@ const props = defineProps({
|
||||
|
||||
const params = useUrlSearchParams('history')
|
||||
const {mobile} = useDisplay()
|
||||
const title = useTitle()
|
||||
|
||||
const recipe = ref({} as Recipe)
|
||||
|
||||
@@ -42,6 +43,7 @@ function refreshData(recipeId: string) {
|
||||
|
||||
api.apiRecipeRetrieve(requestParameters).then(r => {
|
||||
recipe.value = r
|
||||
title.value = recipe.value.name
|
||||
|
||||
if (useUserPreferenceStore().isAuthenticated) {
|
||||
api.apiViewLogCreate({viewLog: {recipe: Number(recipeId)} as ViewLog})
|
||||
|
||||
Reference in New Issue
Block a user