general layout improvements

This commit is contained in:
vabene1111
2024-12-01 15:35:40 +01:00
parent da4abcfce2
commit ab9f9701d8
11 changed files with 102 additions and 71 deletions

View File

@@ -10,7 +10,7 @@
},
"dependencies": {
"@types/luxon": "^3.4.2",
"@vueform/multiselect": "^2.6.8",
"@vueform/multiselect": "^2.6.11",
"@vueuse/core": "^10.11.0",
"luxon": "^3.4.4",
"mavon-editor": "^3.0.1",

View File

@@ -7,35 +7,59 @@
<v-spacer></v-spacer>
<global-search-dialog></global-search-dialog>
<v-avatar color="cyan" class="me-2">V
<v-avatar color="primary" class="me-2">{{useUserPreferenceStore().userSettings.user.displayName.charAt(0)}}
<v-menu activator="parent">
<v-list density="compact">
<v-list-item class="pb-2">
<v-card>
<v-avatar color="cyan" class="me-2">V</v-avatar> vabene1111
</v-card>
<v-list-item class="mb-1">
<template #prepend>
<v-avatar color="primary">{{ useUserPreferenceStore().userSettings.user.displayName.charAt(0) }}</v-avatar>
</template>
<v-list-item-title>{{ useUserPreferenceStore().userSettings.user.displayName }}</v-list-item-title>
<v-list-item-subtitle>{{ useUserPreferenceStore().activeSpace.name }}</v-list-item-subtitle>
</v-list-item>
<v-divider></v-divider>
<v-list-item :to="{ name: 'view_settings', params: {} }"><template #prepend><v-icon icon="fa-solid fa-sliders"></v-icon></template>{{$t('Settings')}}</v-list-item>
<v-list-item :to="{ name: 'ModelListPage', params: {model: 'food'} }"><template #prepend><v-icon icon="fa-solid fa-folder-tree"></v-icon></template>{{$t('Database')}}</v-list-item>
<!-- <v-list-item><template #prepend><v-icon icon="fa-solid fa-user-shield"></v-icon></template>Admin</v-list-item>-->
<!-- <v-list-item><template #prepend><v-icon icon="fa-solid fa-question"></v-icon></template>Help</v-list-item>-->
<v-list-item :to="{ name: 'view_settings', params: {} }">
<template #prepend>
<v-icon icon="fa-solid fa-sliders"></v-icon>
</template>
{{ $t('Settings') }}
</v-list-item>
<v-list-item :to="{ name: 'ModelListPage', params: {model: 'food'} }">
<template #prepend>
<v-icon icon="fa-solid fa-folder-tree"></v-icon>
</template>
{{ $t('Database') }}
</v-list-item>
<!-- <v-list-item><template #prepend><v-icon icon="fa-solid fa-user-shield"></v-icon></template>Admin</v-list-item>-->
<!-- <v-list-item><template #prepend><v-icon icon="fa-solid fa-question"></v-icon></template>Help</v-list-item>-->
<v-divider></v-divider>
<v-list-subheader>Spaces</v-list-subheader>
<v-list-item>Space 1</v-list-item>
<v-list-item>Space 2</v-list-item>
<v-list-item>Space 3</v-list-item>
<v-divider></v-divider>
<v-list-item link><template #prepend><v-icon icon="fa-solid fa-database"></v-icon></template>{{$t('Messages')}}<message-list-dialog></message-list-dialog></v-list-item>
<v-list-item><template #prepend><v-icon icon="fa-solid fa-arrow-right-from-bracket"></v-icon></template>{{$t('Logout')}}</v-list-item>
<v-list-item link>
<template #prepend>
<v-icon icon="fa-solid fa-database"></v-icon>
</template>
{{ $t('Messages') }}
<message-list-dialog></message-list-dialog>
</v-list-item>
<v-list-item>
<template #prepend>
<v-icon icon="fa-solid fa-arrow-right-from-bracket"></v-icon>
</template>
{{ $t('Logout') }}
</v-list-item>
</v-list>
</v-menu>
</v-avatar>
</v-app-bar>
<v-app-bar color="warning" density="compact" v-if="useUserPreferenceStore().activeSpace.maxRecipes == 10 && useUserPreferenceStore().serverSettings.hosted">
<p class="text-center w-100">
{{ $t('HostedFreeVersion')}} <v-btn color="success" variant="flat" href="https://tandoor.dev/manage">{{$t('UpgradeNow')}}</v-btn>
{{ $t('HostedFreeVersion') }}
<v-btn color="success" variant="flat" href="https://tandoor.dev/manage">{{ $t('UpgradeNow') }}</v-btn>
</p>
</v-app-bar>
@@ -50,13 +74,24 @@
</v-main>
<v-navigation-drawer v-if="lgAndUp">
<v-list-item title="My Application" subtitle="Vuetify"></v-list-item>
<v-list-item>
<template #prepend>
<v-avatar color="primary">{{ useUserPreferenceStore().userSettings.user.displayName.charAt(0) }}</v-avatar>
</template>
<v-list-item-title>{{ useUserPreferenceStore().userSettings.user.displayName }}</v-list-item-title>
<v-list-item-subtitle>{{ useUserPreferenceStore().activeSpace.name }}</v-list-item-subtitle>
</v-list-item>
<v-divider></v-divider>
<v-list-item prepend-icon="fas fa-book" title="Home" :to="{ name: 'view_home', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-calendar-alt" title="Mealplan" :to="{ name: 'view_mealplan', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-shopping-cart" title="Shopping" :to="{ name: 'view_shopping', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-bars" title="More" :to="{ name: 'view_books', params: {} }"></v-list-item>
<v-list-item prepend-icon="fas fa-bars" title="Test" :to="{ name: 'view_test', params: {} }"></v-list-item>
<template #append>
<v-list-item prepend-icon="fas fa-sliders" :title="$t('Settings')" :to="{ name: 'view_settings', params: {} }"></v-list-item>
<v-list-item prepend-icon="fa-solid fa-heart" href="https://tandoor.dev" target="_blank">
Tandoor {{ useUserPreferenceStore().serverSettings.version }}
</v-list-item>
</template>
<!-- TODO link -->
</v-navigation-drawer>

View File

@@ -1,15 +1,14 @@
<template>
<!-- TODO label is not showing for some reason, for now in placeholder -->
<!-- TODO support density prop -->
<v-input :hint="props.hint" persistent-hint :label="props.label" class="">
<v-input :hint="props.hint" persistent-hint :label="props.label" class="" >
<!-- TODO resolve-on-load false for now, race condition with model class, make prop once better solution is found -->
<!-- TODO strange behavior/layering issues with appendTo body, find solution to make it work -->
<Multiselect
:id="props.id"
:ref="`ref_${props.id}`"
class="material-multiselect z-max"
class="material-multiselect"
:resolve-on-load="searchOnLoad"
v-model="model"
:options="search"
@@ -31,6 +30,10 @@
:noResultsText="$t('No_Results')"
:loading="loading"
@open="multiselect.refreshOptions()"
append-to-body
:classes="{
dropdown: 'multiselect-dropdown z-3000',
}"
/>
</v-input>
@@ -140,4 +143,8 @@ async function createObject(object: any, select$: Multiselect) {
.multiselect-tag {
background-color: #b98766 !important;
}
.z-3000 {
z-index: 3000;
}
</style>

View File

@@ -1239,11 +1239,8 @@ export interface ApiShoppingListEntryDestroyRequest {
}
export interface ApiShoppingListEntryListRequest {
checked?: string;
id?: number;
page?: number;
pageSize?: number;
supermarket?: number;
updatedAfter?: Date;
}
@@ -1620,7 +1617,7 @@ export interface ApiUserPartialUpdateRequest {
export interface ApiUserPreferencePartialUpdateRequest {
user: number;
patchedUserPreference?: Omit<PatchedUserPreference, 'food_inherit_default'|'food_children_exist'>;
patchedUserPreference?: Omit<PatchedUserPreference, 'user'|'food_inherit_default'|'food_children_exist'>;
}
export interface ApiUserPreferenceRetrieveRequest {
@@ -9096,7 +9093,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryBulkCreateRaw(requestParameters: ApiShoppingListEntryBulkCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ShoppingListEntryBulk>> {
if (requestParameters['shoppingListEntryBulk'] == null) {
@@ -9128,7 +9125,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryBulkCreate(requestParameters: ApiShoppingListEntryBulkCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ShoppingListEntryBulk> {
const response = await this.apiShoppingListEntryBulkCreateRaw(requestParameters, initOverrides);
@@ -9136,7 +9133,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryCreateRaw(requestParameters: ApiShoppingListEntryCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ShoppingListEntry>> {
if (requestParameters['shoppingListEntry'] == null) {
@@ -9168,7 +9165,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryCreate(requestParameters: ApiShoppingListEntryCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ShoppingListEntry> {
const response = await this.apiShoppingListEntryCreateRaw(requestParameters, initOverrides);
@@ -9176,7 +9173,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryDestroyRaw(requestParameters: ApiShoppingListEntryDestroyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
if (requestParameters['id'] == null) {
@@ -9205,26 +9202,18 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryDestroy(requestParameters: ApiShoppingListEntryDestroyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
await this.apiShoppingListEntryDestroyRaw(requestParameters, initOverrides);
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryListRaw(requestParameters: ApiShoppingListEntryListRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<PaginatedShoppingListEntryList>> {
const queryParameters: any = {};
if (requestParameters['checked'] != null) {
queryParameters['checked'] = requestParameters['checked'];
}
if (requestParameters['id'] != null) {
queryParameters['id'] = requestParameters['id'];
}
if (requestParameters['page'] != null) {
queryParameters['page'] = requestParameters['page'];
}
@@ -9233,10 +9222,6 @@ export class ApiApi extends runtime.BaseAPI {
queryParameters['page_size'] = requestParameters['pageSize'];
}
if (requestParameters['supermarket'] != null) {
queryParameters['supermarket'] = requestParameters['supermarket'];
}
if (requestParameters['updatedAfter'] != null) {
queryParameters['updated_after'] = (requestParameters['updatedAfter'] as any).toISOString();
}
@@ -9258,7 +9243,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryList(requestParameters: ApiShoppingListEntryListRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<PaginatedShoppingListEntryList> {
const response = await this.apiShoppingListEntryListRaw(requestParameters, initOverrides);
@@ -9266,7 +9251,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryPartialUpdateRaw(requestParameters: ApiShoppingListEntryPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ShoppingListEntry>> {
if (requestParameters['id'] == null) {
@@ -9298,7 +9283,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryPartialUpdate(requestParameters: ApiShoppingListEntryPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ShoppingListEntry> {
const response = await this.apiShoppingListEntryPartialUpdateRaw(requestParameters, initOverrides);
@@ -9306,7 +9291,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryRetrieveRaw(requestParameters: ApiShoppingListEntryRetrieveRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ShoppingListEntry>> {
if (requestParameters['id'] == null) {
@@ -9335,7 +9320,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryRetrieve(requestParameters: ApiShoppingListEntryRetrieveRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ShoppingListEntry> {
const response = await this.apiShoppingListEntryRetrieveRaw(requestParameters, initOverrides);
@@ -9343,7 +9328,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryUpdateRaw(requestParameters: ApiShoppingListEntryUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ShoppingListEntry>> {
if (requestParameters['id'] == null) {
@@ -9382,7 +9367,7 @@ export class ApiApi extends runtime.BaseAPI {
}
/**
* logs request counts to redis cache total/per user/
* individual entries of a shopping list automatically filtered to only contain unchecked items that are not older than the shopping recent days setting to not bloat endpoint
*/
async apiShoppingListEntryUpdate(requestParameters: ApiShoppingListEntryUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ShoppingListEntry> {
const response = await this.apiShoppingListEntryUpdateRaw(requestParameters, initOverrides);

View File

@@ -64,10 +64,10 @@ import {
export interface PatchedUserPreference {
/**
*
* @type {number}
* @type {User}
* @memberof PatchedUserPreference
*/
user?: number;
readonly user?: User;
/**
*
* @type {UserFileView}
@@ -257,7 +257,7 @@ export function PatchedUserPreferenceFromJSONTyped(json: any, ignoreDiscriminato
}
return {
'user': json['user'] == null ? undefined : json['user'],
'user': json['user'] == null ? undefined : UserFromJSON(json['user']),
'image': json['image'] == null ? undefined : UserFileViewFromJSON(json['image']),
'theme': json['theme'] == null ? undefined : ThemeEnumFromJSON(json['theme']),
'navBgColor': json['nav_bg_color'] == null ? undefined : json['nav_bg_color'],
@@ -293,14 +293,13 @@ export function PatchedUserPreferenceToJSON(json: any): PatchedUserPreference {
return PatchedUserPreferenceToJSONTyped(json, false);
}
export function PatchedUserPreferenceToJSONTyped(value?: Omit<PatchedUserPreference, 'food_inherit_default'|'food_children_exist'> | null, ignoreDiscriminator: boolean = false): any {
export function PatchedUserPreferenceToJSONTyped(value?: Omit<PatchedUserPreference, 'user'|'food_inherit_default'|'food_children_exist'> | null, ignoreDiscriminator: boolean = false): any {
if (value == null) {
return value;
}
return {
'user': value['user'],
'image': UserFileViewToJSON(value['image']),
'theme': ThemeEnumToJSON(value['theme']),
'nav_bg_color': value['navBgColor'],

View File

@@ -67,6 +67,12 @@ export interface ServerSettings {
* @memberof ServerSettings
*/
debug: boolean;
/**
*
* @type {string}
* @memberof ServerSettings
*/
version: string;
}
/**
@@ -81,6 +87,7 @@ export function instanceOfServerSettings(value: object): value is ServerSettings
if (!('imprintUrl' in value) || value['imprintUrl'] === undefined) return false;
if (!('hosted' in value) || value['hosted'] === undefined) return false;
if (!('debug' in value) || value['debug'] === undefined) return false;
if (!('version' in value) || value['version'] === undefined) return false;
return true;
}
@@ -102,6 +109,7 @@ export function ServerSettingsFromJSONTyped(json: any, ignoreDiscriminator: bool
'imprintUrl': json['imprint_url'],
'hosted': json['hosted'],
'debug': json['debug'],
'version': json['version'],
};
}
@@ -124,6 +132,7 @@ export function ServerSettingsToJSONTyped(value?: ServerSettings | null, ignoreD
'imprint_url': value['imprintUrl'],
'hosted': value['hosted'],
'debug': value['debug'],
'version': value['version'],
};
}

View File

@@ -64,10 +64,10 @@ import {
export interface UserPreference {
/**
*
* @type {number}
* @type {User}
* @memberof UserPreference
*/
user: number;
readonly user: User;
/**
*
* @type {UserFileView}
@@ -260,7 +260,7 @@ export function UserPreferenceFromJSONTyped(json: any, ignoreDiscriminator: bool
}
return {
'user': json['user'],
'user': UserFromJSON(json['user']),
'image': json['image'] == null ? undefined : UserFileViewFromJSON(json['image']),
'theme': json['theme'] == null ? undefined : ThemeEnumFromJSON(json['theme']),
'navBgColor': json['nav_bg_color'] == null ? undefined : json['nav_bg_color'],
@@ -296,14 +296,13 @@ export function UserPreferenceToJSON(json: any): UserPreference {
return UserPreferenceToJSONTyped(json, false);
}
export function UserPreferenceToJSONTyped(value?: Omit<UserPreference, 'food_inherit_default'|'food_children_exist'> | null, ignoreDiscriminator: boolean = false): any {
export function UserPreferenceToJSONTyped(value?: Omit<UserPreference, 'user'|'food_inherit_default'|'food_children_exist'> | null, ignoreDiscriminator: boolean = false): any {
if (value == null) {
return value;
}
return {
'user': value['user'],
'image': UserFileViewToJSON(value['image']),
'theme': ThemeEnumToJSON(value['theme']),
'nav_bg_color': value['navBgColor'],

View File

@@ -1,13 +1,5 @@
<template>
<v-container>
<v-row >
<v-col class="pb-0" cols="6" offset="3">
<v-text-field variant="solo" :placeholder="$t('Search') + ' (CTRL + K)'" ></v-text-field>
</v-col>
</v-row>
<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 -->

View File

@@ -550,10 +550,10 @@
resolved "https://registry.yarnpkg.com/@vue/tsconfig/-/tsconfig-0.5.1.tgz#3124ec16cc0c7e04165b88dc091e6b97782fffa9"
integrity sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==
"@vueform/multiselect@^2.6.8":
version "2.6.8"
resolved "https://registry.yarnpkg.com/@vueform/multiselect/-/multiselect-2.6.8.tgz#a8ea77788571f7ce92c650f536a4ed3784c5cea0"
integrity sha512-vu1bkFkViuLbrtSfyWgw11ecNPK7mlBDFe5X9WdsZj3gri3PiZ3OvlfJ920Ebysf7rgiN/+mHJDY2/Y1ITnGEg==
"@vueform/multiselect@^2.6.11":
version "2.6.11"
resolved "https://registry.yarnpkg.com/@vueform/multiselect/-/multiselect-2.6.11.tgz#3585bf1989b969019cd6f8095c8a27d4d45c61e7"
integrity sha512-iG4TGfqE3baftbSGF0PhoS+xZOCnV0ChkDo9rwhJ/Qi2YlCdb6tyQCjvyug3jnzncga8+d85kx0WvG7rDYFqiA==
"@vuetify/loader-shared@^2.0.3":
version "2.0.3"