diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b83fbf19c..2ceae625a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,7 +11,7 @@ // Use -bullseye variants on local on arm64/Apple Silicon. "VARIANT": "3.12-bullseye", // Options - "NODE_VERSION": "16" + "NODE_VERSION": "20" } }, "mounts": [ @@ -55,5 +55,6 @@ "ghcr.io/devcontainers/features/docker-in-docker:2": { "dockerDashComposeVersion": "v2" } - } + }, + "appPort": 3000 } diff --git a/.github/workflows/build-package.yml b/.github/workflows/build-package.yml index bae0de02c..dddc7a2f4 100644 --- a/.github/workflows/build-package.yml +++ b/.github/workflows/build-package.yml @@ -19,7 +19,7 @@ jobs: - name: Setup node env πŸ— uses: actions/setup-node@v4.0.0 with: - node-version: 16 + node-version: 20 check-latest: true - name: Get yarn cache directory path πŸ›  diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a13cc2d23..07fd7adfc 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 cache: 'yarn' cache-dependency-path: ./tests/e2e/yarn.lock - name: Set up Docker Buildx diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 00f8a2673..20d9c98f6 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -14,7 +14,7 @@ jobs: - name: Setup node env πŸ— uses: actions/setup-node@v4.0.0 with: - node-version: 16 + node-version: 20 check-latest: true - name: Get yarn cache directory path πŸ›  @@ -34,6 +34,10 @@ jobs: run: yarn working-directory: "frontend" + - name: Prepare nuxt πŸš€ + run: yarn nuxt prepare + working-directory: "frontend" + - name: Run linter πŸ‘€ run: yarn lint working-directory: "frontend" diff --git a/.gitignore b/.gitignore index cd0725b3a..b24f03a93 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ docs/site/ *temp/* .secret frontend/dist/ +frontend/.output/* +frontend/.yarn/* +frontend/.yarnrc.yml dev/code-generation/generated/* dev/data/mealie.db-journal @@ -164,3 +167,5 @@ dev/code-generation/openapi.json .run/ .task/* +.dev.env +frontend/eslint.config.deprecated.js diff --git a/.vscode/settings.json b/.vscode/settings.json index b842cd45e..61ab0e239 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,6 +18,7 @@ "source.organizeImports": "never" }, "editor.formatOnSave": true, + "eslint.useFlatConfig": true, "eslint.workingDirectories": [ "./frontend" ], diff --git a/Taskfile.yml b/Taskfile.yml index c42cb76c7..ccff66fd6 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -243,7 +243,7 @@ tasks: desc: runs the frontend server dir: frontend cmds: - - yarn run dev + - yarn run dev --no-fork docker:build-from-package: desc: Builds the Docker image from the existing Python package in dist/ diff --git a/dev/code-generation/gen_ts_locales.py b/dev/code-generation/gen_ts_locales.py index e1b73242a..6ff441d22 100644 --- a/dev/code-generation/gen_ts_locales.py +++ b/dev/code-generation/gen_ts_locales.py @@ -156,12 +156,13 @@ PROJECT_DIR = Path(__file__).parent.parent.parent datetime_dir = PROJECT_DIR / "frontend" / "lang" / "dateTimeFormats" locales_dir = PROJECT_DIR / "frontend" / "lang" / "messages" -nuxt_config = PROJECT_DIR / "frontend" / "nuxt.config.js" +nuxt_config = PROJECT_DIR / "frontend" / "nuxt.config.ts" +i18n_config = PROJECT_DIR / "frontend" / "i18n.config.ts" reg_valid = PROJECT_DIR / "mealie" / "schema" / "_mealie" / "validators.py" """ This snippet walks the message and dat locales directories and generates the import information -for the nuxt.config.js file and automatically injects it into the nuxt.config.js file. Note that +for the nuxt.config.ts file and automatically injects it into the nuxt.config.ts file. Note that the code generation ID is hardcoded into the script and required in the nuxt config. """ @@ -173,12 +174,12 @@ def inject_nuxt_values(): all_langs = [] for match in locales_dir.glob("*.json"): - lang_string = f'{{ code: "{match.stem}", file: "{match.name}" }},' + lang_string = f'{{ code: "{match.stem}", file: "{match.name.replace(".json", ".ts")}" }},' all_langs.append(lang_string) log.debug(f"injecting locales into nuxt config -> {nuxt_config}") inject_inline(nuxt_config, CodeKeys.nuxt_local_messages, all_langs) - inject_inline(nuxt_config, CodeKeys.nuxt_local_dates, all_date_locales) + inject_inline(i18n_config, CodeKeys.nuxt_local_dates, all_date_locales) def inject_registration_validation_values(): diff --git a/docker/Dockerfile b/docker/Dockerfile index ada531826..f199602d6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Frontend Build ############################################### -FROM node:16 AS frontend-builder +FROM node:20 AS frontend-builder WORKDIR /frontend diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js deleted file mode 100644 index f6ab3103b..000000000 --- a/frontend/.eslintrc.js +++ /dev/null @@ -1,74 +0,0 @@ -module.exports = { - root: true, - env: { - browser: true, - node: true, - }, - parser: "vue-eslint-parser", - parserOptions: { - parser: "@typescript-eslint/parser", - requireConfigFile: false, - tsConfigRootDir: __dirname, - project: ["./tsconfig.json"], - extraFileExtensions: [".vue"], - }, - extends: [ - "@nuxtjs/eslint-config-typescript", - "plugin:nuxt/recommended", - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - // "plugin:prettier/recommended", - "prettier", - ], - // Re-add once we use nuxt bridge - // See https://v3.nuxtjs.org/getting-started/bridge#update-nuxtconfig - ignorePatterns: ["nuxt.config.js", "lib/api/types/**/*.ts"], - plugins: ["prettier"], - // add your custom rules here - rules: { - "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", - "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", - quotes: ["error", "double"], - "vue/component-name-in-template-casing": ["error", "PascalCase"], - camelcase: 0, - "vue/singleline-html-element-content-newline": "off", - "vue/multiline-html-element-content-newline": "off", - "vue/no-mutating-props": "off", - "vue/no-v-text-v-html-on-component": "warn", - "vue/no-v-for-template-key-on-child": "off", - "vue/valid-v-slot": [ - "error", - { - allowModifiers: true, - }, - ], - "@typescript-eslint/ban-ts-comment": [ - "error", - { - "ts-ignore": "allow-with-description", - }, - ], - "no-restricted-imports": [ - "error", - { paths: ["@vue/reactivity", "@vue/runtime-dom", "@vue/composition-api", "vue-demi"] }, - ], - - // TODO Gradually activate all rules - // Allow Promise in onMounted - "@typescript-eslint/no-misused-promises": [ - "error", - { - checksVoidReturn: { - arguments: false, - }, - }, - ], - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-floating-promises": "off", - "@typescript-eslint/no-explicit-any": "off", - }, -}; diff --git a/frontend/assets/css/fonts.css b/frontend/assets/css/fonts.css index 15d2f1305..b8c8be4c7 100644 --- a/frontend/assets/css/fonts.css +++ b/frontend/assets/css/fonts.css @@ -1,378 +1,390 @@ /* cyrillic-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-cyrillic-ext1.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-100-cyrillic-ext1.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-cyrillic2.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-100-cyrillic2.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-greek-ext3.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-100-greek-ext3.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-greek4.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-100-greek4.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-vietnamese5.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-100-vietnamese5.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-latin-ext6.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-100-latin-ext6.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 100; font-display: swap; - src: url('~assets/fonts/Roboto-100-latin7.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("~assets/fonts/Roboto-100-latin7.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, + U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-cyrillic-ext8.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-300-cyrillic-ext8.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-cyrillic9.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-300-cyrillic9.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-greek-ext10.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-300-greek-ext10.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-greek11.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-300-greek11.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-vietnamese12.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-300-vietnamese12.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-latin-ext13.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-300-latin-ext13.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 300; font-display: swap; - src: url('~assets/fonts/Roboto-300-latin14.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("~assets/fonts/Roboto-300-latin14.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, + U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-cyrillic-ext15.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-400-cyrillic-ext15.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-cyrillic16.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-400-cyrillic16.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-greek-ext17.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-400-greek-ext17.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-greek18.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-400-greek18.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-vietnamese19.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-400-vietnamese19.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-latin-ext20.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-400-latin-ext20.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 400; font-display: swap; - src: url('~assets/fonts/Roboto-400-latin21.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("~assets/fonts/Roboto-400-latin21.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, + U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-cyrillic-ext22.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-500-cyrillic-ext22.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-cyrillic23.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-500-cyrillic23.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-greek-ext24.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-500-greek-ext24.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-greek25.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-500-greek25.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-vietnamese26.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-500-vietnamese26.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-latin-ext27.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-500-latin-ext27.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 500; font-display: swap; - src: url('~assets/fonts/Roboto-500-latin28.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("~assets/fonts/Roboto-500-latin28.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, + U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-cyrillic-ext29.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-700-cyrillic-ext29.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-cyrillic30.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-700-cyrillic30.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-greek-ext31.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-700-greek-ext31.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-greek32.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-700-greek32.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-vietnamese33.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-700-vietnamese33.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-latin-ext34.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-700-latin-ext34.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 700; font-display: swap; - src: url('~assets/fonts/Roboto-700-latin35.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("~assets/fonts/Roboto-700-latin35.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, + U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-cyrillic-ext36.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-900-cyrillic-ext36.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-cyrillic37.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-900-cyrillic37.woff2") format("woff2"); unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-greek-ext38.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-900-greek-ext38.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-greek39.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-900-greek39.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-vietnamese40.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-900-vietnamese40.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-latin-ext41.woff2') format('woff2'); + src: url("~assets/fonts/Roboto-900-latin-ext41.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Roboto'; + font-family: "Roboto"; font-style: normal; font-weight: 900; font-display: swap; - src: url('~assets/fonts/Roboto-900-latin42.woff2') format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: url("~assets/fonts/Roboto-900-latin42.woff2") format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, + U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } diff --git a/frontend/assets/css/main.css b/frontend/assets/css/main.css index 74257bd4a..b421c15eb 100644 --- a/frontend/assets/css/main.css +++ b/frontend/assets/css/main.css @@ -17,11 +17,11 @@ } .theme--dark.v-application { - background-color: var(--v-background-base, #1e1e1e) !important; + background-color: rgb(var(--v-theme-background, 30, 30, 30)) !important; } .theme--dark.v-navigation-drawer { - background-color: var(--v-background-base, #1e1e1e) !important; + background-color: rgb(var(--v-theme-background, 30, 30, 30)) !important; } .theme--dark.v-card { @@ -29,11 +29,11 @@ } .left-border { - border-left: 5px solid var(--v-primary-base) !important; + border-left: 5px solid rgb(var(--v-theme-primary)) !important; } .left-warning-border { - border-left: 5px solid var(--v-warning-base) !important; + border-left: 5px solid rgb(var(--v-theme-warning)) !important; } .handle { @@ -56,3 +56,11 @@ text-overflow: ellipsis; max-width: 100%; } + +a { + color: rgb(var(--v-theme-primary)); +} + +.fill-height { + min-height: 100vh; +} diff --git a/frontend/components/Domain/Cookbook/CookbookEditor.vue b/frontend/components/Domain/Cookbook/CookbookEditor.vue index 8b42656f7..1ee47067d 100644 --- a/frontend/components/Domain/Cookbook/CookbookEditor.vue +++ b/frontend/components/Domain/Cookbook/CookbookEditor.vue @@ -1,17 +1,41 @@ + useSeoMeta({ + title: book?.value?.name || "Cookbook", + }); + + return { + book, + slug, + tab, + appendRecipes, + assignSorted, + recipes, + removeRecipe, + replaceRecipes, + canEdit, + dialogStates, + editTarget, + handleEditCookbook, + editCookbook, + actions, + }; + }, +}); + diff --git a/frontend/components/Domain/Group/GroupExportData.vue b/frontend/components/Domain/Group/GroupExportData.vue index 64cf4efe0..fc2f0c05f 100644 --- a/frontend/components/Domain/Group/GroupExportData.vue +++ b/frontend/components/Domain/Group/GroupExportData.vue @@ -7,21 +7,24 @@ class="elevation-0" @click:row="downloadData" > -