mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
improved code quality of start page scrollers
This commit is contained in:
@@ -50,29 +50,12 @@
|
||||
|
||||
<link rel="stylesheet" href="{% static 'themes/select2-bootstrap-theme.css' %}"/>
|
||||
|
||||
<script type="text/javascript">
|
||||
$.fn.select2.defaults.set("theme", "bootstrap");
|
||||
{% if request.user.is_authenticated %}
|
||||
window.ACTIVE_SPACE_ID = '{{request.space.id}}';
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
<!-- Fontawesome icons -->
|
||||
<link rel="stylesheet" href="{% static "fontawesome/fontawesome_all.min.css" %}">
|
||||
|
||||
{% block extra_head %} <!-- block for templates to put stuff into header -->
|
||||
{% endblock %}
|
||||
|
||||
<style>
|
||||
{% if request.user.userpreference.left_handed %}
|
||||
@media screen and (max-width: 600px) {
|
||||
#switcher .btn-circle {
|
||||
left: 80px !important;
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -93,317 +76,8 @@
|
||||
aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
{% if request.user.userpreference.left_handed %}
|
||||
{% if not request.user.is_authenticated or request.user.userpreference.nav_show_logo %}
|
||||
<a class="navbar-brand p-0 me-2 justify-content-center" href="{% base_path request 'base' %}"
|
||||
aria-label="Tandoor">
|
||||
<img class="brand-icon" src="{{ theme_values.nav_logo }}" alt="Logo">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item {% if request.resolver_match.url_name in 'view_search' %}active{% endif %}">
|
||||
<a class="nav-link" href="{% url 'view_search' %}"><i
|
||||
class="fas fa-fw fa-book"></i> {% trans 'Recipes' %}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.resolver_match.url_name in 'view_plan' %}active{% endif %}">
|
||||
<a class="nav-link" href="{% url 'view_plan' %}"><i
|
||||
class="fas fa-fw fa-calendar"></i> {% trans 'Meal-Plan' %}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.resolver_match.url_name in 'list_shopping_list,view_shopping' %}active{% endif %}">
|
||||
<a class="nav-link" href="{% url 'view_shopping' %}"><i
|
||||
class="fas fa-fw fa-shopping-cart"></i> {% trans 'Shopping' %}</a>
|
||||
</li>
|
||||
<li class="nav-item {% if request.resolver_match.url_name in 'view_books' %}active{% endif %}">
|
||||
<a class="nav-link" href="{% url 'view_books' %}"><i
|
||||
class="fas fa-fw fa-book-open"></i> {% trans 'Books' %}</a>
|
||||
</li>
|
||||
{% plugin_main_nav_templates as plugin_main_nav_templates %}
|
||||
{% for pn in plugin_main_nav_templates %}
|
||||
{% include pn %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav ml-auto">
|
||||
{% if user.is_authenticated %}
|
||||
{% page_help request.resolver_match.url_name as help_button %}
|
||||
{% if help_button %}{{ help_button|safe }}{% endif %}
|
||||
|
||||
<li class="nav-item dropdown {% if request.resolver_match.url_name in 'list_keyword,list_food,list_unit,view_supermarket,data_batch_edit,view_history' %}active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-fw fa-toolbox fa-lg"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-center dropdown-menu-center-large">
|
||||
<div class="row m-0 mt-1 mt-md-0">
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_keyword' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-tags fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Keyword' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_food' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-leaf fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Foods' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_unit' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-balance-scale fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Units' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-0 mt-1 mt-md-0">
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_supermarket' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-store-alt fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Supermarket' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_supermarket_category' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-cubes fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Supermarket Category' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_automation' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-robot fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Automations' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-0 mt-1 mt-md-0">
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_user_file' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-file fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Files' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'data_batch_edit' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-edit fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Batch Edit' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'view_history' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-history fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'History' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-0 mt-1 mt-md-0">
|
||||
<div class="col-4">
|
||||
<a href="{% url 'view_ingredient_editor' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-th-list fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Ingredient Editor' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'view_export' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-file-export fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Export' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_property_type' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-database fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Properties' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-0 mt-1 mt-md-0">
|
||||
<div class="col-4">
|
||||
<a href="{% url 'list_unit_conversion' %}" class="p-0 p-md-1">
|
||||
<div class="card p-1 pt-2 no-gutters border-0">
|
||||
<div class="card-body text-center p-0 no-gutters">
|
||||
<i class="fas fa-exchange-alt fa-2x"></i>
|
||||
</div>
|
||||
<div class="card-body text-break text-center p-0 no-gutters text-muted menu-dropdown-text">
|
||||
{% trans 'Unit Conversions' %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown {% if request.resolver_match.url_name in 'data_import_url,new_recipe' %}active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false"><i
|
||||
class="fas fa-fw fa-plus fa-lg"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-center"
|
||||
aria-labelledby="navbarDropdownMenuLink">
|
||||
<a class="dropdown-item" href="{% url 'data_import_url' %}"><i
|
||||
class="fas fa-file-import"></i> {% trans 'Import Recipe' %}</a>
|
||||
<a class="dropdown-item " href="{% url 'new_recipe' %}"><i
|
||||
class="fas fa-plus"></i> {% trans 'Create' %}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown {% if request.resolver_match.url_name in 'view_space,view_settings,view_history,view_system,docs_markdown' %}active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false"><i
|
||||
class="fas fa-fw fa-user-alt"></i> {{ user.get_user_display_name }}
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
|
||||
<a class="dropdown-item" href="{% url 'view_settings' %}"><i
|
||||
class="fas fa-user-cog fa-fw"></i> {% trans 'Settings' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'data_sync' %}"><i
|
||||
class="fas fa-sync-alt fa-fw"></i> {% trans 'External Recipes' %}</a>
|
||||
{% if request.user == request.space.created_by %}
|
||||
<a class="dropdown-item" href="{% url 'view_space_manage' request.space.pk %}"><i
|
||||
class="fas fa-server fa-fw"></i> {% trans 'Space Settings' %}</a>
|
||||
{% endif %}
|
||||
{% if not DISABLE_EXTERNAL_CONNECTORS and request.user == request.space.created_by or not DISABLE_EXTERNAL_CONNECTORS and user.is_superuser %}
|
||||
<a class="dropdown-item" href="{% url 'list_connector_config' %}"><i
|
||||
class="fas fa-sync-alt fa-fw"></i> {% trans 'External Connectors' %}</a>
|
||||
{% endif %}
|
||||
{% if user.is_superuser %}
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'view_system' %}"><i
|
||||
class="fas fa-server fa-fw"></i> {% trans 'System' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'admin:index' %}"><i
|
||||
class="fas fa-user-shield fa-fw"></i> {% trans 'Admin' %}</a>
|
||||
{% endif %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<div class="dropdown-divider"></div>
|
||||
<h6 class="dropdown-header">{% trans 'Your Spaces' %}</h6>
|
||||
{% for us in request.user.userspace_set.all %}
|
||||
<a class="dropdown-item" href="{% url 'view_switch_space' us.space.id %}">
|
||||
{% if us.active %}
|
||||
<i class="far fa-dot-circle fa-fw"></i>
|
||||
{% else %}
|
||||
<i class="far fa-circle fa-fw"></i>
|
||||
{% endif %}
|
||||
{{ us.space.name }}</a>
|
||||
{% endfor %}
|
||||
<a class="dropdown-item" href="{% url 'view_space_overview' %}"><i
|
||||
class="fas fa-list"></i> {% trans 'Overview' %}</a>
|
||||
{% endif %}
|
||||
{% plugin_dropdown_nav_templates as plugin_dropdown_nav_templates %}
|
||||
{% for pn in plugin_dropdown_nav_templates %}
|
||||
<div class="dropdown-divider"></div>
|
||||
{% include pn %}
|
||||
{% endfor %}
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'docs_markdown' %}"><i
|
||||
class="fab fa-markdown fa-fw"></i> {% trans 'Markdown Guide' %}</a>
|
||||
<a class="dropdown-item" href="https://github.com/vabene1111/recipes"><i class="fab fa-github fa-fw"></i> {% trans 'GitHub' %}</a>
|
||||
<a class="dropdown-item" href="https://translate.tandoor.dev/projects/tandoor/"><i class="fas fa-language fa-fw"></i> {% trans 'Translate Tandoor' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'docs_api' %}"><i class="fas fa-passport fa-fw"></i> {% trans 'API ReDoc Documentation' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'docs_swagger' %}"><i class="fas fa-passport fa-fw"></i> {% trans 'API Swagger Documentation' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'api:api-root' %}"><i class="fas fa-file-code fa-fw"></i> {% trans 'API Browser' %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'account_logout' %}"><i class="fas fa-sign-out-alt fa-fw"></i> {% trans 'Log out' %}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'account_login' %}">{% trans 'Login' %} <i
|
||||
class="fas fa-fw fa-sign-in-alt"></i></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
{% message_of_the_day request as message_of_the_day %}
|
||||
{% if message_of_the_day %}
|
||||
<div class="bg-info" style=" width: 100%; text-align: center!important; color: #ffffff; padding: 8px">
|
||||
{{ message_of_the_day | markdown |safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if HOSTED and request.space.max_recipes == 10 %}
|
||||
<div class="bg-warning" style=" width: 100%; text-align: center!important; color: #ffffff; padding: 8px">
|
||||
{% trans 'You are using the free version of Tandoor' %} <a class="btn-success btn-sm"
|
||||
href="https://tandoor.dev/manage">{% trans 'Upgrade Now' %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="container-fluid mt-2 mt-md-3 mt-xl-3 mt-lg-3{% if request.user.userpreference.left_handed %} left-handed {% endif %}"
|
||||
id="id_base_container">
|
||||
<div class="row">
|
||||
|
||||
@@ -34,25 +34,12 @@ from recipes.settings import PLUGINS
|
||||
|
||||
|
||||
def index(request):
|
||||
return HttpResponseRedirect(reverse('vue3'))
|
||||
|
||||
with scopes_disabled():
|
||||
if not request.user.is_authenticated:
|
||||
if User.objects.count() < 1 and 'django.contrib.auth.backends.RemoteUserBackend' not in settings.AUTHENTICATION_BACKENDS:
|
||||
return HttpResponseRedirect(reverse_lazy('view_setup'))
|
||||
return HttpResponseRedirect(reverse_lazy('view_search'))
|
||||
|
||||
try:
|
||||
page_map = {
|
||||
UserPreference.SEARCH: reverse_lazy('view_search'),
|
||||
UserPreference.PLAN: reverse_lazy('view_plan'),
|
||||
UserPreference.BOOKS: reverse_lazy('view_books'),
|
||||
UserPreference.SHOPPING: reverse_lazy('view_shopping'),
|
||||
}
|
||||
|
||||
return HttpResponseRedirect(page_map.get(request.user.userpreference.default_page))
|
||||
except UserPreference.DoesNotExist:
|
||||
return HttpResponseRedirect(reverse('view_search'))
|
||||
return HttpResponseRedirect(reverse('vue3'))
|
||||
|
||||
|
||||
def search(request):
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
</router-link>
|
||||
<v-spacer></v-spacer>
|
||||
<global-search-dialog></global-search-dialog>
|
||||
<v-btn icon="$add">
|
||||
<v-icon icon="$add"></v-icon>
|
||||
<v-menu activator="parent">
|
||||
<v-list>
|
||||
<v-list-item prepend-icon="$add" :to="{ name: 'ModelEditPage', params: {model: 'Recipe'} }">{{ $t('Create Recipe') }}</v-list-item>
|
||||
<v-list-item prepend-icon="fa-solid fa-globe" :to="{ name: 'RecipeImportPage', params: {} }">{{ $t('Import Recipe') }}</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
|
||||
<v-avatar color="primary" class="me-2">{{ useUserPreferenceStore().userSettings.user.displayName.charAt(0) }}
|
||||
<v-menu activator="parent">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<template v-if="loading || recipes.length > 0">
|
||||
<v-row justify="space-between">
|
||||
<v-col>
|
||||
<h4><i v-if="icon != 'undefined'" :class="icon + ' fa-fw'"></i> {{ title }}</h4>
|
||||
<h4><i :class="icon + ' fa-fw'"></i> {{ title }}</h4>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
@@ -18,7 +19,8 @@
|
||||
</v-window>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-if="recipeWindows.length == 0 && skeletons > 0">
|
||||
|
||||
<v-row v-if="skeletons > 0 && loading">
|
||||
<v-col>
|
||||
<v-window>
|
||||
<v-window-item>
|
||||
@@ -31,41 +33,127 @@
|
||||
</v-window>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</template>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed, PropType, toRefs} from 'vue'
|
||||
import {computed, onMounted, PropType, ref, toRefs} from 'vue'
|
||||
import RecipeCard from "@/components/display/RecipeCard.vue";
|
||||
import {DisplayBreakpoint, useDisplay} from "vuetify";
|
||||
import {Recipe, RecipeOverview} from "@/openapi";
|
||||
import {ApiApi, ApiRecipeListRequest, Keyword, Recipe, RecipeOverview} from "@/openapi";
|
||||
import {homePageCols} from "@/utils/breakpoint_utils";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
|
||||
//TODO mode ideas "last year/month/cooked long ago"
|
||||
const props = defineProps(
|
||||
{
|
||||
title: {type: String as PropType<undefined | String>, required: true},
|
||||
icon: {type: String, required: false},
|
||||
mode: {type: String as PropType<'recent' | 'new' | 'keyword' | 'rating'>, required: true},
|
||||
skeletons: {type: Number, default: 0},
|
||||
recipes: {
|
||||
type: Array as PropType<Recipe[] | RecipeOverview[]>,
|
||||
required: true
|
||||
},
|
||||
}
|
||||
)
|
||||
const {title, recipes} = toRefs(props)
|
||||
|
||||
let numberOfCols = computed(() => {
|
||||
const {name} = useDisplay()
|
||||
const {t} = useI18n()
|
||||
const {name} = useDisplay()
|
||||
|
||||
const loading = ref(true)
|
||||
const recipes = ref([] as Recipe[] | RecipeOverview[])
|
||||
const keyword = ref({} as Keyword)
|
||||
|
||||
/**
|
||||
* determine title based on type
|
||||
*/
|
||||
const title = computed(() => {
|
||||
switch (props.mode) {
|
||||
case 'recent':
|
||||
return t('Recently_Viewed')
|
||||
case 'new':
|
||||
return t('New')
|
||||
case 'rating':
|
||||
return t('Rating')
|
||||
case 'keyword':
|
||||
if (Object.keys(keyword.value).length > 0) {
|
||||
return keyword.value.label
|
||||
}
|
||||
return t('Keyword')
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* determine icon based on type
|
||||
*/
|
||||
const icon = computed(() => {
|
||||
switch (props.mode) {
|
||||
case 'recent':
|
||||
return 'fa-solid fa-eye'
|
||||
case 'new':
|
||||
return 'fa-solid fa-calendar-alt'
|
||||
case 'rating':
|
||||
return 'fa-solid fa-star'
|
||||
case 'keyword':
|
||||
return 'fa-solid fa-tags'
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* number of columns to show depending on display size
|
||||
*/
|
||||
const numberOfCols = computed(() => {
|
||||
return homePageCols(name.value)
|
||||
})
|
||||
|
||||
type CustomWindow = {
|
||||
id: number,
|
||||
recipes: Array<Recipe | RecipeOverview>
|
||||
onMounted(() => {
|
||||
loadRecipes()
|
||||
})
|
||||
|
||||
/**
|
||||
* load recipes depending on type by creating request parameters and executing request function
|
||||
*/
|
||||
function loadRecipes() {
|
||||
let api = new ApiApi()
|
||||
let requestParameters = {pageSize: 16} as ApiRecipeListRequest
|
||||
|
||||
switch (props.mode) {
|
||||
case 'recent':
|
||||
// TODO implement correct parameter
|
||||
requestParameters._new = 'true'
|
||||
break;
|
||||
case 'new':
|
||||
requestParameters._new = 'true'
|
||||
break;
|
||||
case 'rating':
|
||||
requestParameters.rating = 4
|
||||
break;
|
||||
case 'keyword':
|
||||
api.apiKeywordList({random: "true", limit: "1"}).then((r) => {
|
||||
if (r.count > 0) {
|
||||
keyword.value = r.results[0]
|
||||
requestParameters.keywords = [keyword.value.id!]
|
||||
doRecipeRequest(requestParameters)
|
||||
}
|
||||
})
|
||||
return;
|
||||
}
|
||||
doRecipeRequest(requestParameters)
|
||||
}
|
||||
|
||||
/**
|
||||
* actual request function requesting the recipes from the server based on the given parameters
|
||||
* @param params
|
||||
*/
|
||||
function doRecipeRequest(params: ApiRecipeListRequest) {
|
||||
let api = new ApiApi()
|
||||
|
||||
api.apiRecipeList(params).then((r) => {
|
||||
recipes.value = r.results
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* split the list of recipes into windows for display based on column count
|
||||
*/
|
||||
let recipeWindows = computed(() => {
|
||||
let windows = []
|
||||
let current_window = []
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
"Food_Alias": "",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
"Food_Alias": "Псевдоним на храната",
|
||||
"Foods": "Храни",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Групирай по",
|
||||
"Hide_Food": "Скриване на храна",
|
||||
"Hide_Keyword": "Скриване на ключови думи",
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
"Food_Replace": "",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
"Food_Replace": "Nahrazení v potravině",
|
||||
"Foods": "Potraviny",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Seskupit podle",
|
||||
"Hide_Food": "Skrýt potravinu",
|
||||
"Hide_Keyword": "Skrýt štítky",
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
"Food_Replace": "Erstat ingrediens",
|
||||
"Foods": "Mad",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Grupper efter",
|
||||
"Hide_Food": "Skjul mad",
|
||||
"Hide_Keyword": "Skjul nøgleord",
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"Food_Replace": "Essen Ersetzen",
|
||||
"Foods": "Lebensmittel",
|
||||
"Friday": "Freitag",
|
||||
"GettingStarted": "Erste Schritte",
|
||||
"GroupBy": "Gruppieren nach",
|
||||
"Hide_Food": "Lebensmittel verbergen",
|
||||
"Hide_Keyword": "Schlüsselwörter verbergen",
|
||||
|
||||
@@ -136,6 +136,7 @@
|
||||
"Food_Alias": "Ψευδώνυμο φαγητού",
|
||||
"Foods": "Φαγητά",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Ομαδοποίηση κατά",
|
||||
"Hide_Food": "Απόκρυψη φαγητού",
|
||||
"Hide_Keyword": "Απόκρυψη λέξεων-κλειδί",
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
"Food_Replace": "Food Replace",
|
||||
"Foods": "Foods",
|
||||
"Friday": "Friday",
|
||||
"GettingStarted": "Getting Started",
|
||||
"GroupBy": "Group By",
|
||||
"Hide_Food": "Hide Food",
|
||||
"Hide_Keyword": "Hide keywords",
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
"Food_Replace": "Sustituir Alimento",
|
||||
"Foods": "Comida",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Agrupar por",
|
||||
"Hide_Food": "Esconder ingrediente",
|
||||
"Hide_Keyword": "Esconder Palabras Clave",
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
"Food": "Ruoka",
|
||||
"Food_Alias": "Ruoan nimimerkki",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"Hide_Food": "Piilota ruoka",
|
||||
"Hide_Keyword": "Piilota avainsana",
|
||||
"Hide_Keywords": "Piilota Avainsana",
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
"Food_Replace": "Remplacer l'aliment",
|
||||
"Foods": "Aliments",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Grouper par",
|
||||
"Hide_Food": "Cacher l’aliment",
|
||||
"Hide_Keyword": "masquer les mots clefs",
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
"Food_Replace": "החלף אוכל",
|
||||
"Foods": "מאכלים",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "אסוף לפי",
|
||||
"Hide_Food": "הסתר אוכל",
|
||||
"Hide_Keyword": "הסתר מילות מפתח",
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
"Food_Replace": "Étel cseréje",
|
||||
"Foods": "Alapanyagok",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Csoportosítva",
|
||||
"Hide_Food": "Alapanyag elrejtése",
|
||||
"Hide_Keyword": "Kulcsszavak elrejtése",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"Files": "",
|
||||
"Food": "Սննդամթերք",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"Hide_Food": "Թաքցնել սննդամթերքը",
|
||||
"Hide_Keywords": "Թաքցնել բանալի բառը",
|
||||
"Hide_Recipes": "Թաքցնել բաղադրատոմսերը",
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
"Food_Alias": "",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
"Food_Replace": "",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
"Food_Alias": "Alias Alimento",
|
||||
"Foods": "Alimenti",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Raggruppa per",
|
||||
"Hide_Food": "Nascondi alimento",
|
||||
"Hide_Keyword": "Nascondi parole chiave",
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
"Food_Replace": "",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "",
|
||||
"Hide_Food": "",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
"Food_Alias": "Matrett Alias",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Grupér",
|
||||
"Hide_Food": "Skjul Matrett",
|
||||
"Hide_Keyword": "Skjul nøkkelord",
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
"Food_Alias": "Eten Alias",
|
||||
"Foods": "Ingrediënten",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Groepeer per",
|
||||
"Hide_Food": "Verberg Eten",
|
||||
"Hide_Keyword": "Verberg etiketten",
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"Food_Replace": "Zastąp produkt",
|
||||
"Foods": "Żywność",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Grupuj według",
|
||||
"Hide_Food": "Ukryj żywność",
|
||||
"Hide_Keyword": "Ukryj słowa kluczowe",
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
"Food_Alias": "Alcunha da comida",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Agrupar por",
|
||||
"Hide_Food": "Esconder comida",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
"Food_Replace": "Substituir Alimento",
|
||||
"Foods": "Alimentos",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Agrupar Por",
|
||||
"Hide_Food": "Esconder Comida",
|
||||
"Hide_Keyword": "Oculta palavras-chave",
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
"Food_Alias": "Pseudonim mâncare",
|
||||
"Foods": "Alimente",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Grupat de",
|
||||
"Hide_Food": "Ascunde mâncare",
|
||||
"Hide_Keyword": "Ascunde cuvintele cheie",
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
"FoodOnHand": "{food} у вас в наличии.",
|
||||
"Food_Alias": "Наименование еды",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Сгруппировать по",
|
||||
"Hide_Food": "Скрыть еду",
|
||||
"Hide_Keyword": "Скрыть ключевые слова",
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
"FoodOnHand": "Imaš {food} v roki.",
|
||||
"Food_Alias": "Vzdevek hrane",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Združi po",
|
||||
"Hide_Food": "Skrij hrano",
|
||||
"Hide_Keyword": "Skrij ključne besede",
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
"Food_Replace": "Ersätt ingrediens",
|
||||
"Foods": "Livsmedel",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Gruppera enligt",
|
||||
"Hide_Food": "Dölj livsmedel",
|
||||
"Hide_Keyword": "Dölj nyckelord",
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
"Food_Replace": "Yiyecek Değiştir",
|
||||
"Foods": "Yiyecekler",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "Gruplandırma Ölçütü",
|
||||
"Hide_Food": "Yiyeceği Gizle",
|
||||
"Hide_Keyword": "Anahtar kelimeleri gizle",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"Food_Alias": "",
|
||||
"Foods": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "По Групі",
|
||||
"Hide_Food": "Сховати Їжу",
|
||||
"Hide_Keyword": "",
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
"Food_Replace": "食物替换",
|
||||
"Foods": "食物",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"GroupBy": "分组",
|
||||
"Hide_Food": "隐藏食物",
|
||||
"Hide_Keyword": "隐藏关键词",
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
"File": "",
|
||||
"Files": "",
|
||||
"Friday": "",
|
||||
"GettingStarted": "",
|
||||
"Hide_as_header": "隱藏為標題",
|
||||
"History": "",
|
||||
"HostedFreeVersion": "",
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<vue-draggable v-model="s.ingredients" group="ingredients" drag-class="drag-handle">
|
||||
<v-list-item v-for="i in s.ingredients" border>
|
||||
<v-icon size="small" class="drag-handle cursor-grab" icon="$dragHandle"></v-icon>
|
||||
{{ i.amount }} {{ i.unit.name }} {{ i.food.name }}
|
||||
{{ i.amount }} <span v-if="i.unit">{{ i.unit.name }}</span> <span v-if="i.food">{{ i.food.name }}</span>
|
||||
<template #append>
|
||||
<v-btn size="small" color="edit" @click="editingIngredient = i; dialog=true">
|
||||
<v-icon icon="$edit"></v-icon>
|
||||
|
||||
@@ -2,74 +2,38 @@
|
||||
<v-container>
|
||||
<horizontal-meal-plan-window></horizontal-meal-plan-window>
|
||||
|
||||
<!--TODO ideas for "start page": new recipes, meal plan, "last year/month/cooked long ago", high rated, random keyword -->
|
||||
<!--TODO if nothing comes up for a category, hide the element, probably move fetch logic into component -->
|
||||
<horizontal-recipe-scroller title="New Recipes" :skeletons="4" :recipes="new_recipes" icon="fas fa-calendar-alt"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller title="Top Rated" :skeletons="2" :recipes="high_rated_recipes" icon="fas fa-star"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller
|
||||
:title="random_keyword.label"
|
||||
:skeletons="4"
|
||||
:recipes="random_keyword_recipes"
|
||||
icon="fas fa-tags"
|
||||
v-if="random_keyword.label"
|
||||
></horizontal-recipe-scroller>
|
||||
<v-card v-if="totalRecipes == 0" class="mt-5 mb-5">
|
||||
<v-card-title><i class="fa-solid fa-eye-slash"></i> {{ $t('search_no_recipes') }}</v-card-title>
|
||||
<v-card-text>
|
||||
<v-btn-group divided>
|
||||
<v-btn size="large" color="success" prepend-icon="$create" :to="{ name: 'ModelEditPage', params: {model: 'Recipe'} }">{{ $t('Create Recipe') }}</v-btn>
|
||||
<v-btn size="large" color="primary" prepend-icon="fa-solid fa-globe" :to="{ name: 'RecipeImportPage', params: {} }">{{ $t('Import Recipe') }}</v-btn>
|
||||
</v-btn-group>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="recent"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="new"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="2" mode="rating"></horizontal-recipe-scroller>
|
||||
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>
|
||||
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, ref} from "vue"
|
||||
import {ApiApi, Keyword, Recipe, RecipeOverview} from "@/openapi"
|
||||
import KeywordsComponent from "@/components/display/KeywordsBar.vue"
|
||||
import RecipeCardComponent from "@/components/display/RecipeCard.vue"
|
||||
import GlobalSearchDialog from "@/components/inputs/GlobalSearchDialog.vue"
|
||||
import RecipeCard from "@/components/display/RecipeCard.vue"
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref} from "vue"
|
||||
import {ApiApi} from "@/openapi"
|
||||
import HorizontalRecipeScroller from "@/components/display/HorizontalRecipeWindow.vue"
|
||||
import HorizontalMealPlanWindow from "@/components/display/HorizontalMealPlanWindow.vue"
|
||||
import ModelSelect from "@/components/inputs/ModelSelect.vue"
|
||||
|
||||
export default defineComponent({
|
||||
name: "StartPage",
|
||||
components: {ModelSelect, HorizontalMealPlanWindow, HorizontalRecipeScroller, RecipeCard, GlobalSearchDialog, RecipeCardComponent, KeywordsComponent},
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
recipes: [] as Recipe[],
|
||||
items: Array.from({length: 50}, (k, v) => v + 1),
|
||||
const totalRecipes = ref(-1)
|
||||
|
||||
new_recipes: [] as RecipeOverview[],
|
||||
high_rated_recipes: [] as RecipeOverview[],
|
||||
random_keyword: {} as Keyword,
|
||||
random_keyword_recipes: [] as RecipeOverview[],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
onMounted(() => {
|
||||
const api = new ApiApi()
|
||||
|
||||
api.apiRecipeList({_new: "true", pageSize: 16}).then((r) => {
|
||||
if (r.results != undefined) {
|
||||
// TODO openapi generator makes arrays nullable for some reason
|
||||
this.new_recipes = r.results
|
||||
}
|
||||
api.apiRecipeList({pageSize: 1}).then((r) => {
|
||||
totalRecipes.value = r.count
|
||||
})
|
||||
|
||||
api.apiRecipeList({rating: 4, pageSize: 16}).then((r) => {
|
||||
if (r.results != undefined) {
|
||||
this.high_rated_recipes = r.results
|
||||
}
|
||||
})
|
||||
|
||||
api.apiKeywordList({random: "true", limit: "1"}).then((r) => {
|
||||
if (r.results != undefined && r.results.length > 0) {
|
||||
this.random_keyword = r.results[0]
|
||||
api.apiRecipeList({keywords: r.results[0].id}).then((r) => {
|
||||
if (r.results != undefined) {
|
||||
this.random_keyword_recipes = r.results
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user