mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-04-17 10:25:34 -04:00
Merge branch 'mealie-next' into feat/announcements
This commit is contained in:
16
.github/workflows/build-package.yml
vendored
16
.github/workflows/build-package.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎
|
- name: Checkout 🛎
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.ref || github.sha }}
|
ref: ${{ inputs.ref || github.sha }}
|
||||||
|
|
||||||
- name: Setup node env 🏗
|
- name: Setup node env 🏗
|
||||||
uses: actions/setup-node@v4.0.0
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache node_modules 📦
|
- name: Cache node_modules 📦
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
working-directory: "frontend"
|
working-directory: "frontend"
|
||||||
|
|
||||||
- name: Archive built frontend
|
- name: Archive built frontend
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: frontend-dist
|
name: frontend-dist
|
||||||
path: frontend/dist
|
path: frontend/dist
|
||||||
@@ -68,12 +68,12 @@ jobs:
|
|||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Check out repository
|
- name: Check out repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.ref || github.sha }}
|
ref: ${{ inputs.ref || github.sha }}
|
||||||
|
|
||||||
- name: Set up python
|
- name: Set up python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ jobs:
|
|||||||
run: pip install uv
|
run: pip install uv
|
||||||
|
|
||||||
- name: Retrieve built frontend
|
- name: Retrieve built frontend
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: frontend-dist
|
name: frontend-dist
|
||||||
path: mealie/frontend
|
path: mealie/frontend
|
||||||
@@ -97,7 +97,7 @@ jobs:
|
|||||||
task py:package
|
task py:package
|
||||||
|
|
||||||
- name: Archive built package
|
- name: Archive built package
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: backend-dist
|
name: backend-dist
|
||||||
path: dist
|
path: dist
|
||||||
|
|||||||
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
@@ -44,11 +44,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v4
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v3
|
uses: github/codeql-action/autobuild@v4
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -75,6 +75,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v4
|
||||||
with:
|
with:
|
||||||
category: "/language:${{matrix.language}}"
|
category: "/language:${{matrix.language}}"
|
||||||
|
|||||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@v4
|
uses: astral-sh/setup-uv@v4
|
||||||
|
|||||||
10
.github/workflows/e2e.yml
vendored
10
.github/workflows/e2e.yml
vendored
@@ -10,21 +10,21 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: ./tests/e2e
|
working-directory: ./tests/e2e
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
cache-dependency-path: ./tests/e2e/yarn.lock
|
cache-dependency-path: ./tests/e2e/yarn.lock
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
- name: Retrieve Python package
|
- name: Retrieve Python package
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: backend-dist
|
name: backend-dist
|
||||||
path: dist
|
path: dist
|
||||||
- name: Build Image
|
- name: Build Image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
file: ./docker/Dockerfile
|
file: ./docker/Dockerfile
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
6
.github/workflows/locale-sync.yml
vendored
6
.github/workflows/locale-sync.yml
vendored
@@ -23,12 +23,12 @@ jobs:
|
|||||||
private-key: ${{ secrets.COMMIT_BOT_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.COMMIT_BOT_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.app-token.outputs.token }}
|
token: ${{ steps.app-token.outputs.token }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Load cached venv
|
- name: Load cached venv
|
||||||
id: cached-python-dependencies
|
id: cached-python-dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: .venv
|
path: .venv
|
||||||
key: venv-${{ runner.os }}-${{ hashFiles('**/uv.lock') }}
|
key: venv-${{ runner.os }}-${{ hashFiles('**/uv.lock') }}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
fail-fast: true
|
fail-fast: true
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Build Dockerfile
|
- name: Build Dockerfile
|
||||||
run: |
|
run: |
|
||||||
@@ -28,6 +28,6 @@ jobs:
|
|||||||
TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db
|
TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db
|
||||||
|
|
||||||
- name: Upload Trivy scan results to GitHub Security tab
|
- name: Upload Trivy scan results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
uses: github/codeql-action/upload-sarif@v4
|
||||||
with:
|
with:
|
||||||
sarif_file: "trivy-results.sarif"
|
sarif_file: "trivy-results.sarif"
|
||||||
|
|||||||
11
.github/workflows/publish.yml
vendored
11
.github/workflows/publish.yml
vendored
@@ -23,19 +23,19 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.ref || github.sha }}
|
ref: ${{ inputs.ref || github.sha }}
|
||||||
|
|
||||||
- name: Log in to the Container registry (ghcr.io)
|
- name: Log in to the Container registry (ghcr.io)
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Log in to the Container registry (dockerhub)
|
- name: Log in to the Container registry (dockerhub)
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate Docker metadata
|
- name: Generate Docker metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
hkotel/mealie
|
hkotel/mealie
|
||||||
@@ -52,9 +52,10 @@ jobs:
|
|||||||
# Overwrite the image.version label with our tag
|
# Overwrite the image.version label with our tag
|
||||||
labels: |
|
labels: |
|
||||||
org.opencontainers.image.version=${{ inputs.tag }}
|
org.opencontainers.image.version=${{ inputs.tag }}
|
||||||
|
org.opencontainers.image.revision=${{ inputs.ref || github.sha }}
|
||||||
|
|
||||||
- name: Retrieve Python package
|
- name: Retrieve Python package
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: backend-dist
|
name: backend-dist
|
||||||
path: dist
|
path: dist
|
||||||
|
|||||||
2
.github/workflows/pull-request-lint.yml
vendored
2
.github/workflows/pull-request-lint.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
# https://github.com/amannn/action-semantic-pull-request
|
# https://github.com/amannn/action-semantic-pull-request
|
||||||
- uses: amannn/action-semantic-pull-request@v5
|
- uses: amannn/action-semantic-pull-request@v6
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
28
.github/workflows/release-drafter.yml
vendored
28
.github/workflows/release-drafter.yml
vendored
@@ -5,26 +5,28 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- mealie-next
|
- mealie-next
|
||||||
# pull_request event is required for autolabeler
|
|
||||||
pull_request:
|
|
||||||
types: [opened, labeled, unlabeled, reopened, synchronize]
|
|
||||||
# pull_request_target event is required for autolabeler to support PRs from forks
|
# pull_request_target event is required for autolabeler to support PRs from forks
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, labeled, unlabeled, reopened, synchronize]
|
types: [opened, labeled, unlabeled, reopened, synchronize]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update_release_draft:
|
draft_release:
|
||||||
permissions:
|
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||||
# write permission is required to create a github release
|
|
||||||
contents: write
|
|
||||||
# write permission is required for autolabeler
|
|
||||||
# otherwise, read permission is required at least
|
|
||||||
pull-requests: write
|
|
||||||
name: ✏️ Draft release
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: 🚀 Run Release Drafter
|
- uses: release-drafter/release-drafter@v7
|
||||||
uses: release-drafter/release-drafter@v6.0.0
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
auto_label:
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: release-drafter/release-drafter/autolabeler@v7
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
private-key: ${{ secrets.COMMIT_BOT_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.COMMIT_BOT_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Checkout 🛎
|
- name: Checkout 🛎
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.app-token.outputs.token }}
|
token: ${{ steps.app-token.outputs.token }}
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ jobs:
|
|||||||
private-key: ${{ secrets.COMMIT_BOT_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.COMMIT_BOT_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Checkout 🛎
|
- name: Checkout 🛎
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.app-token.outputs.token }}
|
token: ${{ steps.app-token.outputs.token }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|||||||
6
.github/workflows/scheduled-checks.yml
vendored
6
.github/workflows/scheduled-checks.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎
|
- name: Checkout 🛎
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
|
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Cache
|
- name: Cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/pre-commit
|
~/.cache/pre-commit
|
||||||
|
|||||||
6
.github/workflows/test-backend.yml
vendored
6
.github/workflows/test-backend.yml
vendored
@@ -46,12 +46,12 @@ jobs:
|
|||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Check out repository
|
- name: Check out repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.ref || github.sha }}
|
ref: ${{ inputs.ref || github.sha }}
|
||||||
|
|
||||||
- name: Set up python
|
- name: Set up python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Load cached venv
|
- name: Load cached venv
|
||||||
id: cached-python-dependencies
|
id: cached-python-dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: .venv
|
path: .venv
|
||||||
key: venv-${{ runner.os }}-${{ hashFiles('**/uv.lock') }}
|
key: venv-${{ runner.os }}-${{ hashFiles('**/uv.lock') }}
|
||||||
|
|||||||
6
.github/workflows/test-frontend.yml
vendored
6
.github/workflows/test-frontend.yml
vendored
@@ -13,12 +13,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎
|
- name: Checkout 🛎
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.ref || github.sha }}
|
ref: ${{ inputs.ref || github.sha }}
|
||||||
|
|
||||||
- name: Setup node env 🏗
|
- name: Setup node env 🏗
|
||||||
uses: actions/setup-node@v4.0.0
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache node_modules 📦
|
- name: Cache node_modules 📦
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -17,6 +17,8 @@
|
|||||||
"source.fixAll.eslint": "explicit",
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.organizeImports": "never"
|
"source.organizeImports": "never"
|
||||||
},
|
},
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.tabSize": 2,
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"eslint.useFlatConfig": true,
|
"eslint.useFlatConfig": true,
|
||||||
"eslint.workingDirectories": [
|
"eslint.workingDirectories": [
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
"**/.svn": true,
|
"**/.svn": true,
|
||||||
"**/CVS": true
|
"**/CVS": true
|
||||||
},
|
},
|
||||||
|
"files.insertFinalNewline": true,
|
||||||
"i18n-ally.enabledFrameworks": [
|
"i18n-ally.enabledFrameworks": [
|
||||||
"vue"
|
"vue"
|
||||||
],
|
],
|
||||||
@@ -67,6 +70,7 @@
|
|||||||
},
|
},
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
"editor.defaultFormatter": "charliermarsh.ruff",
|
||||||
|
"editor.tabSize": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
###############################################
|
###############################################
|
||||||
# Frontend Build
|
# Frontend Build
|
||||||
###############################################
|
###############################################
|
||||||
FROM node:24@sha256:bb20cf73b3ad7212834ec48e2174cdcb5775f6550510a5336b842ae32741ce6c \
|
FROM node:24@sha256:80fc934952c8f1b2b4d39907af7211f8a9fff1a4c2cf673fb49099292c251cec \
|
||||||
AS frontend-builder
|
AS frontend-builder
|
||||||
|
|
||||||
WORKDIR /frontend
|
WORKDIR /frontend
|
||||||
|
|||||||
@@ -160,13 +160,14 @@
|
|||||||
</v-row>
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
<v-card v-intersect="infiniteScroll" />
|
<v-card v-intersect="infiniteScroll" />
|
||||||
<v-fade-transition>
|
|
||||||
<AppLoader
|
|
||||||
v-if="loading"
|
|
||||||
:loading="loading"
|
|
||||||
/>
|
|
||||||
</v-fade-transition>
|
|
||||||
</div>
|
</div>
|
||||||
|
<v-fade-transition>
|
||||||
|
<AppLoader
|
||||||
|
v-if="loading"
|
||||||
|
:loading="loading"
|
||||||
|
/>
|
||||||
|
</v-fade-transition>
|
||||||
|
<AppScrollToTop />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -243,6 +244,7 @@ const ready = ref(false);
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const { fetchMore, getRandom } = useLazyRecipes(isOwnGroup.value ? null : groupSlug.value);
|
const { fetchMore, getRandom } = useLazyRecipes(isOwnGroup.value ? null : groupSlug.value);
|
||||||
|
const { savePosition, getSavedPage, restorePosition } = useScrollPosition();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const queryFilter = computed(() => {
|
const queryFilter = computed(() => {
|
||||||
@@ -283,8 +285,29 @@ async function fetchRecipes(pageCount = 1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await initRecipes();
|
loading.value = true;
|
||||||
ready.value = true;
|
const savedPage = getSavedPage(route.path);
|
||||||
|
|
||||||
|
if (savedPage && savedPage > 2) {
|
||||||
|
page.value = 1;
|
||||||
|
hasMore.value = true;
|
||||||
|
const newRecipes = await fetchRecipes(savedPage);
|
||||||
|
if (newRecipes.length < perPage * savedPage) {
|
||||||
|
hasMore.value = false;
|
||||||
|
}
|
||||||
|
page.value = savedPage;
|
||||||
|
emit(REPLACE_RECIPES_EVENT, newRecipes);
|
||||||
|
ready.value = true;
|
||||||
|
restorePosition(route.path);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await initRecipes();
|
||||||
|
ready.value = true;
|
||||||
|
if (savedPage) {
|
||||||
|
restorePosition(route.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
let lastQuery: string | undefined = JSON.stringify(props.query);
|
let lastQuery: string | undefined = JSON.stringify(props.query);
|
||||||
@@ -337,6 +360,8 @@ const infiniteScroll = useThrottleFn(async () => {
|
|||||||
emit(APPEND_RECIPES_EVENT, newRecipes);
|
emit(APPEND_RECIPES_EVENT, newRecipes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
savePosition(route.path, page.value);
|
||||||
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
@@ -1,91 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<v-dialog
|
<BaseButton @click="dialog = true">
|
||||||
|
{{ $t("new-recipe.bulk-add") }}
|
||||||
|
</BaseButton>
|
||||||
|
<BaseDialog
|
||||||
v-model="dialog"
|
v-model="dialog"
|
||||||
width="800"
|
width="800"
|
||||||
|
:title="$t('new-recipe.bulk-add')"
|
||||||
|
:icon="$globals.icons.createAlt"
|
||||||
|
:submit-text="$t('general.add')"
|
||||||
|
:disable-submit-on-enter="true"
|
||||||
|
can-submit
|
||||||
|
@submit="save"
|
||||||
>
|
>
|
||||||
<template #activator="{ props: activatorProps }">
|
<v-card-text>
|
||||||
<BaseButton
|
<v-textarea
|
||||||
v-bind="activatorProps"
|
v-model="inputText"
|
||||||
@click="inputText = inputTextProp"
|
variant="outlined"
|
||||||
>
|
rows="12"
|
||||||
{{ $t("new-recipe.bulk-add") }}
|
hide-details
|
||||||
</BaseButton>
|
autofocus
|
||||||
</template>
|
:placeholder="$t('new-recipe.paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list')"
|
||||||
|
/>
|
||||||
|
|
||||||
<v-card>
|
<v-divider />
|
||||||
<v-app-bar
|
<v-list lines="two">
|
||||||
density="compact"
|
|
||||||
dark
|
|
||||||
color="primary"
|
|
||||||
class="mb-2 position-relative left-0 top-0 w-100"
|
|
||||||
>
|
|
||||||
<v-icon
|
|
||||||
size="large"
|
|
||||||
start
|
|
||||||
>
|
|
||||||
{{ $globals.icons.createAlt }}
|
|
||||||
</v-icon>
|
|
||||||
<v-toolbar-title class="headline">
|
|
||||||
{{ $t("new-recipe.bulk-add") }}
|
|
||||||
</v-toolbar-title>
|
|
||||||
<v-spacer />
|
|
||||||
</v-app-bar>
|
|
||||||
|
|
||||||
<v-card-text>
|
|
||||||
<v-textarea
|
|
||||||
v-model="inputText"
|
|
||||||
variant="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-divider />
|
|
||||||
<template
|
<template
|
||||||
v-for="(util) in utilities"
|
v-for="(util) in utilities"
|
||||||
:key="util.id"
|
:key="util.id"
|
||||||
>
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
density="compact"
|
class="px-0"
|
||||||
class="py-1"
|
|
||||||
>
|
>
|
||||||
<v-list-item-title>
|
<template #prepend>
|
||||||
<v-list-item-subtitle class="wrap-word">
|
<v-avatar>
|
||||||
{{ util.description }}
|
<v-btn
|
||||||
</v-list-item-subtitle>
|
icon
|
||||||
|
variant="tonal"
|
||||||
|
base-color="info"
|
||||||
|
:title="$t('general.run')"
|
||||||
|
@click="util.action"
|
||||||
|
>
|
||||||
|
<v-icon>
|
||||||
|
{{ $globals.icons.play }}
|
||||||
|
</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-avatar>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title class="text-pre-wrap">
|
||||||
|
{{ util.description }}
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
<BaseButton
|
|
||||||
size="small"
|
|
||||||
color="info"
|
|
||||||
@click="util.action"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
{{ $globals.icons.robot }}
|
|
||||||
</template>
|
|
||||||
{{ $t("general.run") }}
|
|
||||||
</BaseButton>
|
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-divider class="mx-2" />
|
|
||||||
</template>
|
</template>
|
||||||
</v-card-text>
|
</v-list>
|
||||||
|
</v-card-text>
|
||||||
<v-divider />
|
</BaseDialog>
|
||||||
|
|
||||||
<v-card-actions>
|
|
||||||
<BaseButton
|
|
||||||
cancel
|
|
||||||
@click="dialog = false"
|
|
||||||
/>
|
|
||||||
<v-spacer />
|
|
||||||
<BaseButton
|
|
||||||
save
|
|
||||||
color="success"
|
|
||||||
@click="save"
|
|
||||||
/>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -1,62 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<v-dialog
|
<BaseDialog
|
||||||
v-model="dialog"
|
v-model="dialog"
|
||||||
width="500"
|
width="500"
|
||||||
|
:title="properties.title"
|
||||||
|
:icon="properties.icon"
|
||||||
|
can-submit
|
||||||
|
:submit-disabled="!name"
|
||||||
|
@submit="select"
|
||||||
>
|
>
|
||||||
<v-card>
|
<v-form>
|
||||||
<v-app-bar
|
<v-card-text>
|
||||||
density="compact"
|
<v-text-field
|
||||||
dark
|
v-model="name"
|
||||||
color="primary mb-2 position-relative left-0 top-0 w-100 pl-3"
|
:label="properties.label"
|
||||||
>
|
:rules="[rules.required]"
|
||||||
<v-icon
|
autofocus
|
||||||
size="large"
|
/>
|
||||||
start
|
<v-checkbox
|
||||||
class="mt-1"
|
v-if="itemType === Organizer.Tool"
|
||||||
>
|
v-model="onHand"
|
||||||
{{ itemType === Organizer.Tool ? $globals.icons.potSteam
|
:label="$t('tool.on-hand')"
|
||||||
: itemType === Organizer.Category ? $globals.icons.categories
|
/>
|
||||||
: $globals.icons.tags }}
|
</v-card-text>
|
||||||
</v-icon>
|
</v-form>
|
||||||
|
</BaseDialog>
|
||||||
<v-toolbar-title class="headline">
|
|
||||||
{{ properties.title }}
|
|
||||||
</v-toolbar-title>
|
|
||||||
|
|
||||||
<v-spacer />
|
|
||||||
</v-app-bar>
|
|
||||||
<v-card-title />
|
|
||||||
<v-form @submit.prevent="select">
|
|
||||||
<v-card-text>
|
|
||||||
<v-text-field
|
|
||||||
v-model="name"
|
|
||||||
density="compact"
|
|
||||||
:label="properties.label"
|
|
||||||
:rules="[rules.required]"
|
|
||||||
autofocus
|
|
||||||
/>
|
|
||||||
<v-checkbox
|
|
||||||
v-if="itemType === Organizer.Tool"
|
|
||||||
v-model="onHand"
|
|
||||||
:label="$t('tool.on-hand')"
|
|
||||||
/>
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
<BaseButton
|
|
||||||
cancel
|
|
||||||
@click="dialog = false"
|
|
||||||
/>
|
|
||||||
<v-spacer />
|
|
||||||
<BaseButton
|
|
||||||
type="submit"
|
|
||||||
create
|
|
||||||
:disabled="!name"
|
|
||||||
/>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-form>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -65,6 +33,8 @@ import { useUserApi } from "~/composables/api";
|
|||||||
import { useCategoryStore, useTagStore, useToolStore } from "~/composables/store";
|
import { useCategoryStore, useTagStore, useToolStore } from "~/composables/store";
|
||||||
import { type RecipeOrganizer, Organizer } from "~/lib/api/types/non-generated";
|
import { type RecipeOrganizer, Organizer } from "~/lib/api/types/non-generated";
|
||||||
|
|
||||||
|
const { $globals } = useNuxtApp();
|
||||||
|
|
||||||
const CREATED_ITEM_EVENT = "created-item";
|
const CREATED_ITEM_EVENT = "created-item";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -115,18 +85,21 @@ const properties = computed(() => {
|
|||||||
return {
|
return {
|
||||||
title: i18n.t("tag.create-a-tag"),
|
title: i18n.t("tag.create-a-tag"),
|
||||||
label: i18n.t("tag.tag-name"),
|
label: i18n.t("tag.tag-name"),
|
||||||
|
icon: $globals.icons.tags,
|
||||||
api: userApi.tags,
|
api: userApi.tags,
|
||||||
};
|
};
|
||||||
case Organizer.Tool:
|
case Organizer.Tool:
|
||||||
return {
|
return {
|
||||||
title: i18n.t("tool.create-a-tool"),
|
title: i18n.t("tool.create-a-tool"),
|
||||||
label: i18n.t("tool.tool-name"),
|
label: i18n.t("tool.tool-name"),
|
||||||
|
icon: $globals.icons.potSteam,
|
||||||
api: userApi.tools,
|
api: userApi.tools,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
title: i18n.t("category.create-a-category"),
|
title: i18n.t("category.create-a-category"),
|
||||||
label: i18n.t("category.category-name"),
|
label: i18n.t("category.category-name"),
|
||||||
|
icon: $globals.icons.categories,
|
||||||
api: userApi.categories,
|
api: userApi.categories,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -139,12 +112,9 @@ const rules = {
|
|||||||
async function select() {
|
async function select() {
|
||||||
if (store) {
|
if (store) {
|
||||||
// @ts-expect-error the same state is used for different organizer types, which have different requirements
|
// @ts-expect-error the same state is used for different organizer types, which have different requirements
|
||||||
await store.actions.createOne({ name: name.value, onHand: onHand.value });
|
const newItem = await store.actions.createOne({ name: name.value, onHand: onHand.value });
|
||||||
|
emit(CREATED_ITEM_EVENT, newItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newItem = store.store.value.find(item => item.name === name.value);
|
|
||||||
|
|
||||||
emit(CREATED_ITEM_EVENT, newItem);
|
|
||||||
dialog.value = false;
|
dialog.value = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
v-if="updateTarget"
|
v-if="updateTarget"
|
||||||
v-model="dialogs.update"
|
v-model="dialogs.update"
|
||||||
:title="$t('general.update')"
|
:title="$t('general.update')"
|
||||||
|
:icon="$globals.icons.edit"
|
||||||
can-confirm
|
can-confirm
|
||||||
@confirm="updateOne()"
|
@confirm="updateOne()"
|
||||||
>
|
>
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { useUserApi } from "~/composables/api";
|
import { useUserApi } from "~/composables/api";
|
||||||
import type { Recipe } from "~/lib/api/types/recipe";
|
import type { Recipe } from "~/lib/api/types/recipe";
|
||||||
import UserAvatar from "~/components/Domain/User/UserAvatar.vue";
|
import UserAvatar from "~/components/Domain/User/UserAvatar.vue";
|
||||||
@@ -1,117 +1,101 @@
|
|||||||
<template>
|
<template>
|
||||||
<section @keyup.ctrl.z="undoMerge">
|
<section @keyup.ctrl.z="undoMerge">
|
||||||
<!-- Ingredient Link Editor -->
|
<!-- Ingredient Link Editor -->
|
||||||
<v-dialog
|
<BaseDialog
|
||||||
v-if="dialog"
|
|
||||||
v-model="dialog"
|
v-model="dialog"
|
||||||
width="600"
|
:title="$t('recipe.ingredient-linker')"
|
||||||
|
:icon="$globals.icons.link"
|
||||||
|
width="100%"
|
||||||
|
max-width="600px"
|
||||||
|
max-height="40%"
|
||||||
>
|
>
|
||||||
<v-card :ripple="false">
|
<v-card-text class="pt-4">
|
||||||
<v-sheet
|
<p>
|
||||||
color="primary"
|
{{ activeText }}
|
||||||
class="mt-n1 mb-3 pa-3 d-flex align-center"
|
</p>
|
||||||
style="border-radius: 6px; width: 100%;"
|
<v-divider class="my-4" />
|
||||||
>
|
<template v-if="Object.keys(groupedUnusedIngredients).length > 0">
|
||||||
<v-icon
|
<h4 class="ml-1">
|
||||||
size="large"
|
{{ $t("recipe.unlinked") }}
|
||||||
start
|
</h4>
|
||||||
>
|
<template v-for="(ingredients, title) in groupedUnusedIngredients" :key="title">
|
||||||
{{ $globals.icons.link }}
|
<h4 v-if="title" class="py-3 ml-1 pl-4">
|
||||||
</v-icon>
|
{{ title }}
|
||||||
<v-toolbar-title class="headline">
|
|
||||||
{{ $t("recipe.ingredient-linker") }}
|
|
||||||
</v-toolbar-title>
|
|
||||||
<v-spacer />
|
|
||||||
</v-sheet>
|
|
||||||
|
|
||||||
<v-card-text class="pt-4">
|
|
||||||
<p>
|
|
||||||
{{ activeText }}
|
|
||||||
</p>
|
|
||||||
<v-divider class="mb-4" />
|
|
||||||
<template v-if="Object.keys(groupedUnusedIngredients).length > 0">
|
|
||||||
<h4 class="py-3 ml-1">
|
|
||||||
{{ $t("recipe.unlinked") }}
|
|
||||||
</h4>
|
</h4>
|
||||||
<template v-for="(ingredients, title) in groupedUnusedIngredients" :key="title">
|
<v-checkbox-btn
|
||||||
<h4 v-if="title" class="py-3 ml-1 pl-4">
|
v-for="ing in ingredients"
|
||||||
{{ title }}
|
:key="ing.referenceId"
|
||||||
</h4>
|
v-model="activeRefs"
|
||||||
<v-checkbox-btn
|
:value="ing.referenceId"
|
||||||
v-for="ing in ingredients"
|
class="ml-4"
|
||||||
:key="ing.referenceId"
|
>
|
||||||
v-model="activeRefs"
|
<template #label>
|
||||||
:value="ing.referenceId"
|
<RecipeIngredientHtml :ingredient="ing" :scale="scale" />
|
||||||
class="ml-4"
|
</template>
|
||||||
>
|
</v-checkbox-btn>
|
||||||
<template #label>
|
|
||||||
<RecipeIngredientHtml :ingredient="ing" :scale="scale" />
|
|
||||||
</template>
|
|
||||||
</v-checkbox-btn>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-if="Object.keys(groupedUsedIngredients).length > 0">
|
<template v-if="Object.keys(groupedUsedIngredients).length > 0">
|
||||||
<h4 class="py-3 ml-1">
|
<h4 class="py-3 ml-1">
|
||||||
{{ $t("recipe.linked-to-other-step") }}
|
{{ $t("recipe.linked-to-other-step") }}
|
||||||
|
</h4>
|
||||||
|
<template v-for="(ingredients, title) in groupedUsedIngredients" :key="title">
|
||||||
|
<h4 v-if="title" class="py-3 ml-1 pl-4">
|
||||||
|
{{ title }}
|
||||||
</h4>
|
</h4>
|
||||||
<template v-for="(ingredients, title) in groupedUsedIngredients" :key="title">
|
<v-checkbox-btn
|
||||||
<h4 v-if="title" class="py-3 ml-1 pl-4">
|
v-for="ing in ingredients"
|
||||||
{{ title }}
|
:key="ing.referenceId"
|
||||||
</h4>
|
v-model="activeRefs"
|
||||||
<v-checkbox-btn
|
:value="ing.referenceId"
|
||||||
v-for="ing in ingredients"
|
class="ml-4"
|
||||||
:key="ing.referenceId"
|
>
|
||||||
v-model="activeRefs"
|
<template #label>
|
||||||
:value="ing.referenceId"
|
<RecipeIngredientHtml :ingredient="ing" :scale="scale" />
|
||||||
class="ml-4"
|
</template>
|
||||||
>
|
</v-checkbox-btn>
|
||||||
<template #label>
|
|
||||||
<RecipeIngredientHtml :ingredient="ing" :scale="scale" />
|
|
||||||
</template>
|
|
||||||
</v-checkbox-btn>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</v-card-text>
|
</template>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
<v-divider />
|
<v-divider />
|
||||||
|
|
||||||
<v-card-actions>
|
<template #card-actions>
|
||||||
|
<BaseButton
|
||||||
|
cancel
|
||||||
|
@click="dialog = false"
|
||||||
|
/>
|
||||||
|
<v-spacer />
|
||||||
|
<div class="d-flex flex-wrap justify-end">
|
||||||
<BaseButton
|
<BaseButton
|
||||||
cancel
|
class="my-1"
|
||||||
@click="dialog = false"
|
color="info"
|
||||||
|
@click="autoSetReferences"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
{{ $globals.icons.robot }}
|
||||||
|
</template>
|
||||||
|
{{ $t("recipe.auto") }}
|
||||||
|
</BaseButton>
|
||||||
|
<BaseButton
|
||||||
|
class="ml-2 my-1"
|
||||||
|
save
|
||||||
|
@click="setIngredientIds"
|
||||||
/>
|
/>
|
||||||
<v-spacer />
|
<BaseButton
|
||||||
<div class="d-flex flex-wrap justify-end">
|
v-if="availableNextStep"
|
||||||
<BaseButton
|
class="ml-2 my-1"
|
||||||
class="my-1"
|
@click="saveAndOpenNextLinkIngredients"
|
||||||
color="info"
|
>
|
||||||
@click="autoSetReferences"
|
<template #icon>
|
||||||
>
|
{{ $globals.icons.forward }}
|
||||||
<template #icon>
|
</template>
|
||||||
{{ $globals.icons.robot }}
|
{{ $t("recipe.nextStep") }}
|
||||||
</template>
|
</BaseButton>
|
||||||
{{ $t("recipe.auto") }}
|
</div>
|
||||||
</BaseButton>
|
</template>
|
||||||
<BaseButton
|
</BaseDialog>
|
||||||
class="ml-2 my-1"
|
|
||||||
save
|
|
||||||
@click="setIngredientIds"
|
|
||||||
/>
|
|
||||||
<BaseButton
|
|
||||||
v-if="availableNextStep"
|
|
||||||
class="ml-2 my-1"
|
|
||||||
@click="saveAndOpenNextLinkIngredients"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
{{ $globals.icons.forward }}
|
|
||||||
</template>
|
|
||||||
{{ $t("recipe.nextStep") }}
|
|
||||||
</BaseButton>
|
|
||||||
</div>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
|
|
||||||
<div class="d-flex justify-space-between justify-start">
|
<div class="d-flex justify-space-between justify-start">
|
||||||
<h2
|
<h2
|
||||||
@@ -851,6 +835,10 @@ function openImageUpload(index: number) {
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.v-card-text {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.recipe-step-title {
|
.recipe-step-title {
|
||||||
/* Multiline display */
|
/* Multiline display */
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { usePageState } from "~/composables/recipe-page/shared-state";
|
import { usePageState } from "~/composables/recipe-page/shared-state";
|
||||||
import type { NoUndefinedField } from "~/lib/api/types/non-generated";
|
import type { NoUndefinedField } from "~/lib/api/types/non-generated";
|
||||||
import type { Recipe } from "~/lib/api/types/recipe";
|
import type { Recipe } from "~/lib/api/types/recipe";
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import RecipeSettingsSwitches from "./RecipeSettingsSwitches.vue";
|
import RecipeSettingsSwitches from "./RecipeSettingsSwitches.vue";
|
||||||
|
|
||||||
const value = defineModel<object>({ required: true });
|
const value = defineModel<object>({ required: true });
|
||||||
@@ -15,8 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { defineModel, defineProps } from "vue";
|
|
||||||
import type { RecipeSettings } from "~/lib/api/types/recipe";
|
import type { RecipeSettings } from "~/lib/api/types/recipe";
|
||||||
import { useI18n } from "#imports";
|
import { useI18n } from "#imports";
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
v-model="showTimeline"
|
v-model="showTimeline"
|
||||||
:title="timelineAttrs.title"
|
:title="$t('recipe.timeline')"
|
||||||
:icon="$globals.icons.timelineText"
|
:icon="$globals.icons.timelineText"
|
||||||
width="70%"
|
width="70%"
|
||||||
>
|
>
|
||||||
@@ -53,8 +53,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
recipeName: "",
|
recipeName: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const i18n = useI18n();
|
|
||||||
const { smAndDown } = useDisplay();
|
|
||||||
const showTimeline = ref(false);
|
const showTimeline = ref(false);
|
||||||
|
|
||||||
function toggleTimeline() {
|
function toggleTimeline() {
|
||||||
@@ -62,13 +60,7 @@ function toggleTimeline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const timelineAttrs = computed(() => {
|
const timelineAttrs = computed(() => {
|
||||||
let title = i18n.t("recipe.timeline");
|
|
||||||
if (smAndDown.value) {
|
|
||||||
title += ` – ${props.recipeName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title,
|
|
||||||
queryFilter: `recipe.slug="${props.slug}"`,
|
queryFilter: `recipe.slug="${props.slug}"`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { useI18n, useNuxtApp } from "#imports";
|
import { useI18n, useNuxtApp } from "#imports";
|
||||||
import type { RecipeTimelineEventOut } from "~/lib/api/types/recipe";
|
import type { RecipeTimelineEventOut } from "~/lib/api/types/recipe";
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
import { useOnline } from "@vueuse/core";
|
import { useOnline } from "@vueuse/core";
|
||||||
import RecipeIngredientListItem from "../Recipe/RecipeIngredientListItem.vue";
|
import RecipeIngredientListItem from "../Recipe/RecipeIngredientListItem.vue";
|
||||||
import ShoppingListItemEditor from "./ShoppingListItemEditor.vue";
|
import ShoppingListItemEditor from "./ShoppingListItemEditor.vue";
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user