mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 06:23:34 -07:00
New docs for v0.4.0 (#234)
* spacing * fix parser bug * update for v0.4.0 * demo link * remove gifs * add organize diagram * demo code * remove large gifs * v0.4.0 changelog Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
parent
c8284eaeee
commit
629aae49c9
14 changed files with 84 additions and 61 deletions
73
README.md
73
README.md
|
@ -23,7 +23,7 @@
|
||||||
<a href="https://github.com/hay-kot/mealie">
|
<a href="https://github.com/hay-kot/mealie">
|
||||||
</a>
|
</a>
|
||||||
<br />
|
<br />
|
||||||
<a href="https://github.com/hay-kot/mealie"><s>View Demo</s></a>
|
<a href="https://mealie-demo.hay-kot.dev/">View Demo</a>
|
||||||
·
|
·
|
||||||
<a href="https://github.com/hay-kot/mealie/issues">Report Bug</a>
|
<a href="https://github.com/hay-kot/mealie/issues">Report Bug</a>
|
||||||
·
|
·
|
||||||
|
@ -39,41 +39,51 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ABOUT THE PROJECT -->
|
|
||||||
## About The Project
|
|
||||||
|
|
||||||
|
|
||||||
[![Product Name Screen Shot][product-screenshot]](https://example.com)
|
[![Product Name Screen Shot][product-screenshot]](https://example.com)
|
||||||
|
|
||||||
**Mealie** is a self hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in Vue for a pleasant user experience for the whole family. Easily add recipes into your database by providing the url and mealie will automatically import the relevant data or add a family recipe with the UI editor.
|
# About The Project
|
||||||
|
|
||||||
Mealie also provides a secure API for interactions from 3rd party applications. **Why does my recipe manager need an API?** An API allows integration into applications like [Home Assistant]() that can act as notification engines to provide custom notifications based of Meal Plan data to remind you to defrost the chicken, marinade the steak, or start the CrockPot. See the section on [Meal Plan hooks](#hooks) for more information. Additionally, you can access any available API from the backend server. To explore the API spin up your server and navigate to http://yourserver.com/docs for interactive API documentation.
|
Mealie is a self hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in Vue for a pleasant user experience for the whole family. Easily add recipes into your database by providing the url and Mealie will automatically import the relevant data or add a family recipe with the UI editor. Mealie also provides an API for interactions from 3rd party applications.
|
||||||
|
|
||||||
|
[Remember to join the Discord](https://discord.gg/R6QDyJgbD2)!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Main Features
|
## Key Features
|
||||||
#### Recipes
|
- 🔍 Fuzzy search
|
||||||
- Automatic web scrapping for common recipe platforms
|
- 🏷️ Tag recipes with categories or tags to flexible sorting
|
||||||
|
- 🕸 Import recipes from around the web by URL
|
||||||
|
- 📱 Beautiful Mobile Views
|
||||||
|
- 📆 Create Meal Plans
|
||||||
|
- 🛒 Generate shopping lists
|
||||||
|
- 🐳 Easy setup with Docker
|
||||||
|
- 🎨 Customize your interface with color themes layouts
|
||||||
|
- 💾 Export all your data in any format with Jinja2 Templates, with easy data restoration from the user interface.
|
||||||
|
- 🌍 localized in many languages
|
||||||
|
- ➕ Plus tons more!
|
||||||
|
- Flexible API
|
||||||
|
- Custom key/value pairs for recipes
|
||||||
|
- Webhook support
|
||||||
- Interactive API Documentation thanks to [FastAPI](https://fastapi.tiangolo.com/) and [Swagger](https://petstore.swagger.io/)
|
- Interactive API Documentation thanks to [FastAPI](https://fastapi.tiangolo.com/) and [Swagger](https://petstore.swagger.io/)
|
||||||
- UI Recipe Editor
|
- Raw JSON Recipe Editor
|
||||||
- JSON Recipe Editor in browser
|
- Migration from other platforms
|
||||||
- Custom tags and categories
|
- Chowdown
|
||||||
- Rate recipes
|
- Nextcloud Cookbook
|
||||||
- Add notes to recipes
|
- Random meal plan generation
|
||||||
#### Meal Planner
|
|
||||||
- Random Meal plan generation based off categories
|
|
||||||
- Expose notes in the API to allow external applications to access relevant information for meal plans
|
|
||||||
- Shopping Lists
|
|
||||||
#### Database Import / Export
|
|
||||||
- Easily Import / Export your recipes from the UI
|
|
||||||
- Export recipes in into custom files using Jinja2 templates
|
|
||||||
|
|
||||||
### Built With
|
## FAQ
|
||||||
|
|
||||||
* [Vue.js](https://vuejs.org/)
|
### Why An API?
|
||||||
* [Vuetify](https://vuetifyjs.com/en/)
|
An API allows integration into applications like [Home Assistant](https://www.home-assistant.io/) that can act as notification engines to provide custom notifications based of Meal Plan data to remind you to defrost the chicken, marinade the steak, or start the CrockPot. Additionally, you can access nearly any backend service via the API giving you total control to extend the application. To explore the API spin up your server and navigate to http://yourserver.com/docs for interactive API documentation.
|
||||||
* [FastAPI](https://fastapi.tiangolo.com/)
|
|
||||||
* [Docker](https://www.docker.com/)
|
### Why a Database?
|
||||||
|
Some users of static-site generator applications like ChowDown have expressed concerns about their data being stuck in a database. Considering this is a new project it is a valid concern to be worried about your data. Mealie specifically addresses this concern by provided automatic daily backups that export your data in json, plain-text markdown files, and/or custom Jinja2 templates. **This puts you in controls of how your data is represented** when exported from Mealie, which means you can easily migrate to any other service provided Mealie doesn't work for you.
|
||||||
|
|
||||||
|
As to why we need a database?
|
||||||
|
|
||||||
|
- **Developer Experience:** Without a database a lot of the work to maintain your data is taken on by the developer instead of a battle tested platform for storing data.
|
||||||
|
- **Multi User Support:** With a solid database as backend storage for your data Mealie can better support multi-user sites and avoid read/write access errors when multiple actions are taken at the same time.
|
||||||
|
|
||||||
|
|
||||||
<!-- CONTRIBUTING -->
|
<!-- CONTRIBUTING -->
|
||||||
|
@ -87,7 +97,6 @@ If you are not a coder, you can still contribute financially. financial contribu
|
||||||
|
|
||||||
<!-- LICENSE -->
|
<!-- LICENSE -->
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Distributed under the MIT License. See `LICENSE` for more information.
|
Distributed under the MIT License. See `LICENSE` for more information.
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,16 +106,6 @@ Project Link: [https://github.com/hay-kot/mealie](https://github.com/hay-kot/mea
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ACKNOWLEDGEMENTS -->
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
* [Talk Python Training for helping me learn python](https://training.talkpython.fm/)
|
|
||||||
* [Academind for helping me learn Javascript and Vue.js](https://academind.com/)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- MARKDOWN LINKS & IMAGES -->
|
<!-- MARKDOWN LINKS & IMAGES -->
|
||||||
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
||||||
[contributors-shield]: https://img.shields.io/github/contributors/hay-kot/mealie.svg?style=flat-square
|
[contributors-shield]: https://img.shields.io/github/contributors/hay-kot/mealie.svg?style=flat-square
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 30 MiB |
Binary file not shown.
Before Width: | Height: | Size: 35 MiB |
BIN
docs/docs/assets/img/MealieDiagram.png
Normal file
BIN
docs/docs/assets/img/MealieDiagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
|
@ -12,14 +12,14 @@
|
||||||
A new database will be created. You must export your data and then import it after upgrading.
|
A new database will be created. You must export your data and then import it after upgrading.
|
||||||
|
|
||||||
#### Site Settings
|
#### Site Settings
|
||||||
With the addition of group settings and a re-write of the database layer of the application backend, there is no migration path for your current site settings. Webhooks Settings, Meal Plan Categories are now managed by groups. Site settings, mainly homepage settings, are now site specific and managed by administrators.
|
With the addition of group settings and a re-write of the database layer of the application backend, there is no migration path for your current site settings. Webhooks Settings, Meal Plan Categories are now managed by groups. Site settings, mainly homepage settings, are now site specific and managed by administrators. When upgrading be sure to uncheck the settings when importing your old data.
|
||||||
|
|
||||||
#### ENV Variables
|
#### ENV Variables
|
||||||
Names have been changed to be more consistent with industry standards. See the [Installation Page](/getting-started/install/) for new parameters.
|
Names have been changed to be more consistent with industry standards. See the [Installation Page](/getting-started/install/) for new parameters.
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
- Fixed Search Results Limited to 100 - #198
|
- Fixed Search Results Limited to 100 - #198
|
||||||
- Fixed Recette from marmiton.org not fully scrapped - #196
|
- Fixed recipes from marmiton.org not fully scrapped - #196
|
||||||
- Fixed Unable to get a page to load - #194
|
- Fixed Unable to get a page to load - #194
|
||||||
- Fixed Recipe's from Epicurious don't upload. - #193
|
- Fixed Recipe's from Epicurious don't upload. - #193
|
||||||
- Fixed Edited blank recipe in meal plan is not saved - #184
|
- Fixed Edited blank recipe in meal plan is not saved - #184
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Documentation Rewrite
|
- Documentation Rewrite
|
||||||
|
- [New Demo Site!](https://mealie-demo.hay-kot.dev/)
|
||||||
- New Documentation
|
- New Documentation
|
||||||
- Landing Page
|
- Landing Page
|
||||||
- Custom Caddy Configuration
|
- Custom Caddy Configuration
|
||||||
|
@ -77,8 +78,9 @@
|
||||||
### Behind the Scenes
|
### Behind the Scenes
|
||||||
- Removed CDN dependencies
|
- Removed CDN dependencies
|
||||||
- Database Model Refactoring
|
- Database Model Refactoring
|
||||||
|
- Import/Export refactoring
|
||||||
- File/Folder Name Refactoring
|
- File/Folder Name Refactoring
|
||||||
- Development is now easier with a makefile!
|
- Development is now easier with a makefile
|
||||||
- Mealie is now a proper package using poetry
|
- Mealie is now a proper package using poetry
|
||||||
- Test refactoring
|
- Test refactoring
|
||||||
- Test Coverage 75%
|
- Test Coverage 83% up from 75%!
|
||||||
|
|
|
@ -2,3 +2,7 @@
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
Below is a suggestion of guidelines my wife and I use for organizing our recipes within Mealie. Mealie is fairly flexible, so feel free to utilize how you'd like! 👍
|
Below is a suggestion of guidelines my wife and I use for organizing our recipes within Mealie. Mealie is fairly flexible, so feel free to utilize how you'd like! 👍
|
||||||
|
|
||||||
|
In the diagram below you will see what we came up with using the new custom pages feature. The large circles indicate pages, and the rectangles indicate categories. We've grouped several 'like' categories with each other as a way to quickly find similar items.
|
||||||
|
|
||||||
|

|
|
@ -4,16 +4,11 @@
|
||||||
Adding a recipe can be as easy as copying the recipe URL into mealie and letting the web scrapper try to pull down the information. Currently this scraper is implemented with [scrape-schema-recipe package](https://pypi.org/project/scrape-schema-recipe/). You may have mixed results on some websites, especially with blogs or non specific recipe websites. See the bulk import Option below for another a convenient way to add blog style recipes into Mealie.
|
Adding a recipe can be as easy as copying the recipe URL into mealie and letting the web scrapper try to pull down the information. Currently this scraper is implemented with [scrape-schema-recipe package](https://pypi.org/project/scrape-schema-recipe/). You may have mixed results on some websites, especially with blogs or non specific recipe websites. See the bulk import Option below for another a convenient way to add blog style recipes into Mealie.
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## Recipe Editor
|
## Recipe Editor
|
||||||
Recipes can be edited and created via the UI. This is done with both a form based approach where you have a UI to work with as well as with a in browser JSON Editor. The JSON editor allows you to easily copy and paste data from other sources.
|
Recipes can be edited and created via the UI. This is done with both a form based approach where you have a UI to work with as well as with a in browser JSON Editor. The JSON editor allows you to easily copy and paste data from other sources.
|
||||||
|
|
||||||
You can also add a custom recipe with the UI editor built into the web view.
|
You can also add a custom recipe with the UI editor built into the web view.
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Bulk Import
|
## Bulk Import
|
||||||
Mealie also supports bulk import of recipe instructions and ingredients. Select "Bulk Add" in the editor and paste in your plain text data to be parsed. Each line is treated as one entry and will be appended to the existing ingredients or instructions if they exist. Empty lines will be stripped from the text.
|
Mealie also supports bulk import of recipe instructions and ingredients. Select "Bulk Add" in the editor and paste in your plain text data to be parsed. Each line is treated as one entry and will be appended to the existing ingredients or instructions if they exist. Empty lines will be stripped from the text.
|
||||||
|
|
||||||
|
|
|
@ -239,8 +239,8 @@
|
||||||
<a href="{{ page.next_page.url | url }}" title="{{ page.next_page.title | striptags }}" class="md-button md-button--primary">
|
<a href="{{ page.next_page.url | url }}" title="{{ page.next_page.title | striptags }}" class="md-button md-button--primary">
|
||||||
Get started
|
Get started
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ config.repo_url }}" title="{{ lang.t('source.link.title') }}" class="md-button">
|
<a href="{{ config.demo_url }}" title="{{ lang.t('source.link.title') }}" target="_blank" class="md-button">
|
||||||
Go to GitHub
|
View the Demo
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
site_name: Mealie
|
site_name: Mealie
|
||||||
|
demo_url: https://mealie-demo.hay-kot.dev/
|
||||||
theme:
|
theme:
|
||||||
custom_dir: docs/overrides
|
custom_dir: docs/overrides
|
||||||
features:
|
features:
|
||||||
|
|
|
@ -31,6 +31,12 @@
|
||||||
<LanguageMenu />
|
<LanguageMenu />
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
<v-main>
|
<v-main>
|
||||||
|
<v-banner v-if="demo" sticky
|
||||||
|
><div class="text-center">
|
||||||
|
<b> This is a Demo</b> | Username: changeme@email.com | Password: demo
|
||||||
|
</div></v-banner
|
||||||
|
>
|
||||||
|
|
||||||
<v-slide-x-reverse-transition>
|
<v-slide-x-reverse-transition>
|
||||||
<AddRecipeFab v-if="loggedIn" />
|
<AddRecipeFab v-if="loggedIn" />
|
||||||
</v-slide-x-reverse-transition>
|
</v-slide-x-reverse-transition>
|
||||||
|
@ -47,6 +53,7 @@ import AddRecipeFab from "@/components/UI/AddRecipeFab";
|
||||||
import LanguageMenu from "@/components/UI/LanguageMenu";
|
import LanguageMenu from "@/components/UI/LanguageMenu";
|
||||||
import Vuetify from "./plugins/vuetify";
|
import Vuetify from "./plugins/vuetify";
|
||||||
import { user } from "@/mixins/user";
|
import { user } from "@/mixins/user";
|
||||||
|
import { api } from "./api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
|
@ -80,7 +87,7 @@ export default {
|
||||||
this.$store.dispatch("initLang", { currentVueComponent: this });
|
this.$store.dispatch("initLang", { currentVueComponent: this });
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.$store.dispatch("initTheme");
|
this.$store.dispatch("initTheme");
|
||||||
this.$store.dispatch("requestRecentRecipes");
|
this.$store.dispatch("requestRecentRecipes");
|
||||||
this.$store.dispatch("refreshToken");
|
this.$store.dispatch("refreshToken");
|
||||||
|
@ -89,10 +96,14 @@ export default {
|
||||||
this.$store.dispatch("requestTags");
|
this.$store.dispatch("requestTags");
|
||||||
this.darkModeSystemCheck();
|
this.darkModeSystemCheck();
|
||||||
this.darkModeAddEventListener();
|
this.darkModeAddEventListener();
|
||||||
|
|
||||||
|
const api_status = await api.meta.getIsDemo();
|
||||||
|
this.demo = api_status.demoStatus;
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
search: false,
|
search: false,
|
||||||
|
demo: false,
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
// For Later!
|
// For Later!
|
||||||
|
|
|
@ -6,6 +6,7 @@ const prefix = baseURL + "debug";
|
||||||
const debugURLs = {
|
const debugURLs = {
|
||||||
version: `${prefix}/version`,
|
version: `${prefix}/version`,
|
||||||
lastRecipe: `${prefix}/last-recipe-json`,
|
lastRecipe: `${prefix}/last-recipe-json`,
|
||||||
|
demo: `${prefix}/is-demo`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const metaAPI = {
|
export const metaAPI = {
|
||||||
|
@ -17,4 +18,10 @@ export const metaAPI = {
|
||||||
let response = await apiReq.get(debugURLs.lastRecipe);
|
let response = await apiReq.get(debugURLs.lastRecipe);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getIsDemo() {
|
||||||
|
let response = await apiReq.get(debugURLs.demo);
|
||||||
|
console.log(response);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -78,6 +78,7 @@ class AppSettings:
|
||||||
def __init__(self, app_dirs: AppDirectories) -> None:
|
def __init__(self, app_dirs: AppDirectories) -> None:
|
||||||
global DB_VERSION
|
global DB_VERSION
|
||||||
self.PRODUCTION = bool(os.environ.get("ENV"))
|
self.PRODUCTION = bool(os.environ.get("ENV"))
|
||||||
|
self.IS_DEMO = os.getenv("DEMO", "False") == "True"
|
||||||
self.API_PORT = int(os.getenv("API_PORT", 9000))
|
self.API_PORT = int(os.getenv("API_PORT", 9000))
|
||||||
self.API = os.getenv("API_DOCS", "False") == "True"
|
self.API = os.getenv("API_DOCS", "False") == "True"
|
||||||
self.DOCS_URL = "/docs" if self.API else None
|
self.DOCS_URL = "/docs" if self.API else None
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from mealie.core.config import APP_VERSION, LOGGER_FILE, app_dirs
|
from mealie.core.config import APP_VERSION, LOGGER_FILE, app_dirs, settings
|
||||||
from mealie.routes.deps import get_current_user
|
from mealie.routes.deps import get_current_user
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/debug", tags=["Debug"], dependencies=[Depends(get_current_user)])
|
router = APIRouter(prefix="/api/debug", tags=["Debug"])
|
||||||
|
|
||||||
|
|
||||||
@router.get("/version")
|
@router.get("/version")
|
||||||
async def get_mealie_version():
|
async def get_mealie_version(current_user=Depends(get_current_user)):
|
||||||
""" Returns the current version of mealie"""
|
""" Returns the current version of mealie"""
|
||||||
return {"version": APP_VERSION}
|
return {"version": APP_VERSION}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/is-demo")
|
||||||
|
async def get_demo_status():
|
||||||
|
print(settings.IS_DEMO)
|
||||||
|
return {"demoStatus": settings.IS_DEMO}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/last-recipe-json")
|
@router.get("/last-recipe-json")
|
||||||
async def get_last_recipe_json():
|
async def get_last_recipe_json(current_user=Depends(get_current_user)):
|
||||||
""" Doc Str """
|
""" Doc Str """
|
||||||
|
|
||||||
with open(app_dirs.DEBUG_DIR.joinpath("last_recipe.json"), "r") as f:
|
with open(app_dirs.DEBUG_DIR.joinpath("last_recipe.json"), "r") as f:
|
||||||
|
@ -22,7 +28,7 @@ async def get_last_recipe_json():
|
||||||
|
|
||||||
|
|
||||||
@router.get("/log/{num}")
|
@router.get("/log/{num}")
|
||||||
async def get_log(num: int):
|
async def get_log(num: int, current_user=Depends(get_current_user)):
|
||||||
""" Doc Str """
|
""" Doc Str """
|
||||||
with open(LOGGER_FILE, "rb") as f:
|
with open(LOGGER_FILE, "rb") as f:
|
||||||
log_text = tail(f, num)
|
log_text = tail(f, num)
|
||||||
|
|
|
@ -146,7 +146,5 @@ class Cleaner:
|
||||||
return None
|
return None
|
||||||
elif isinstance(time_entry, datetime):
|
elif isinstance(time_entry, datetime):
|
||||||
print(time_entry)
|
print(time_entry)
|
||||||
elif isinstance(time_entry, str):
|
|
||||||
return str(time_entry)
|
|
||||||
else:
|
else:
|
||||||
return time_entry
|
return str(time_entry)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue