mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-01-30 14:52:58 -08:00
39adea4ee3
* Add pytesseract * Add simple ocr endpoint replace extension argument * feat/ocr-editor gui * fix frontend linting issues * Add service unit tests * Add split text modes & single ingredient/instruction editing * make split mode really reactive * Remove default step and ingredient * make the linter haappy * Accept only image uploads * Add automatic recipe title suggestion * Correct regex * fix incorrect array.map method usage * make the linter happy again * Swap route to use asset name * Rearange buttons * fix test data * feat: Allow making image the recipe image * Add translation * Make the linter happy * Restrict function setPropertyValueByPath generic * Restrict template literal type * Add a more friendly icon to creation page * update poetry lock file * Correct sloppy ocr classes * Make MyPy happy * Rewrite safer tests * Add tesseract to backend test CI container dependencies * Make canvas element a component global * Remove unwanted spaces in selected text * Add way to know if recipe was created with ocr * Access to ocr-editor for ocr recipes * Update Alembic revision * Make the frontend build * Fix scrolling offset bug * Allow creation of recipes with custom settings * Fix rebasing mistakes * Add format_tsv_output test * Exclude the tests data directory only * Enforce camelCase for frontend functions * Remove import of unused component * Fix type and class initialization * Add multi-language support * Highlight words in mount * Fix image ratio bug * Better ocr creation page * Revert awkward feature to scroll in Selection mode * Rebasing alembic migrations sux * Remove obsolete getShared function * Add function docstring * Move down ocr creation option * Make toolbar icons more generic * Show help at the bottom of the page * move ocr types to own file * Use template ref for the canvas * Use i18n.tc to get strings directly * Correct naming mistake * Move Ocr editor to own directory * Create Ocr Editor parts * Safeguard recipe properties access * Add loading frontend animation due to longer request time * minor cleanup chores Co-authored-by: Miroito <alban.vachette@gmail.com>
143 lines
3.9 KiB
Vue
143 lines
3.9 KiB
Vue
<template>
|
|
<div class="text-center">
|
|
<v-dialog v-model="dialog" width="800">
|
|
<template #activator="{ on, attrs }">
|
|
<BaseButton v-bind="attrs" v-on="on" @click="inputText = inputTextProp">
|
|
{{ $t("new-recipe.bulk-add") }}
|
|
</BaseButton>
|
|
</template>
|
|
|
|
<v-card>
|
|
<v-app-bar dense dark color="primary" class="mb-2">
|
|
<v-icon large left>
|
|
{{ $globals.icons.createAlt }}
|
|
</v-icon>
|
|
<v-toolbar-title class="headline"> {{ $t("new-recipe.bulk-add") }}</v-toolbar-title>
|
|
<v-spacer></v-spacer>
|
|
</v-app-bar>
|
|
|
|
<v-card-text>
|
|
<v-textarea
|
|
v-model="inputText"
|
|
outlined
|
|
rows="12"
|
|
hide-details
|
|
:placeholder="$t('new-recipe.paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list')"
|
|
>
|
|
</v-textarea>
|
|
|
|
<v-divider></v-divider>
|
|
<template v-for="(util, idx) in utilities">
|
|
<v-list-item :key="util.id" dense class="py-1">
|
|
<v-list-item-title>
|
|
<v-list-item-subtitle class="wrap-word">
|
|
{{ util.description }}
|
|
</v-list-item-subtitle>
|
|
</v-list-item-title>
|
|
<BaseButton small color="info" @click="util.action">
|
|
<template #icon> {{ $globals.icons.robot }}</template>
|
|
{{ $t("general.run") }}
|
|
</BaseButton>
|
|
</v-list-item>
|
|
<v-divider :key="`divider-${idx}`" class="mx-2"></v-divider>
|
|
</template>
|
|
</v-card-text>
|
|
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-actions>
|
|
<BaseButton cancel @click="dialog = false"> </BaseButton>
|
|
<v-spacer></v-spacer>
|
|
<BaseButton save color="success" @click="save"> </BaseButton>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { reactive, toRefs, defineComponent, useContext } from "@nuxtjs/composition-api";
|
|
export default defineComponent({
|
|
props: {
|
|
inputTextProp: {
|
|
type: String,
|
|
required: false,
|
|
default: "",
|
|
},
|
|
},
|
|
setup(props, context) {
|
|
const state = reactive({
|
|
dialog: false,
|
|
inputText: props.inputTextProp,
|
|
});
|
|
|
|
function splitText() {
|
|
return state.inputText.split("\n").filter((line) => !(line === "\n" || !line));
|
|
}
|
|
|
|
function removeFirstCharacter() {
|
|
state.inputText = splitText()
|
|
.map((line) => line.substring(1))
|
|
.join("\n");
|
|
}
|
|
|
|
const numberedLineRegex = /\d+[.):] /gm;
|
|
|
|
function splitByNumberedLine() {
|
|
// Split inputText by numberedLineRegex
|
|
const matches = state.inputText.match(numberedLineRegex);
|
|
|
|
matches?.forEach((match, idx) => {
|
|
const replaceText = idx === 0 ? "" : "\n";
|
|
state.inputText = state.inputText.replace(match, replaceText);
|
|
});
|
|
}
|
|
|
|
function trimAllLines() {
|
|
const splitLines = splitText();
|
|
|
|
splitLines.forEach((element: string, index: number) => {
|
|
splitLines[index] = element.trim();
|
|
});
|
|
|
|
state.inputText = splitLines.join("\n");
|
|
}
|
|
|
|
function save() {
|
|
context.emit("bulk-data", splitText());
|
|
state.dialog = false;
|
|
}
|
|
|
|
const { i18n } = useContext();
|
|
|
|
const utilities = [
|
|
{
|
|
id: "trim-whitespace",
|
|
description: i18n.tc("new-recipe.trim-whitespace-description"),
|
|
action: trimAllLines,
|
|
},
|
|
{
|
|
id: "trim-prefix",
|
|
description: i18n.tc("new-recipe.trim-prefix-description"),
|
|
action: removeFirstCharacter,
|
|
},
|
|
{
|
|
id: "split-by-numbered-line",
|
|
description: i18n.tc("new-recipe.split-by-numbered-line-description"),
|
|
action: splitByNumberedLine,
|
|
},
|
|
];
|
|
|
|
return {
|
|
utilities,
|
|
splitText,
|
|
trimAllLines,
|
|
removeFirstCharacter,
|
|
splitByNumberedLine,
|
|
save,
|
|
...toRefs(state),
|
|
};
|
|
},
|
|
});
|
|
</script>
|