diff --git a/.github/workflows/build-and-push-image-semver.yaml b/.github/workflows/build-and-push-image-semver.yaml index 1da1dda9df..cbef71e52f 100644 --- a/.github/workflows/build-and-push-image-semver.yaml +++ b/.github/workflows/build-and-push-image-semver.yaml @@ -100,6 +100,7 @@ jobs: # About VEX attestations https://docs.docker.com/scout/explore/exceptions/ # Justifications https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-justifications - name: Add VEX attestations + if: steps.dockerhub.outputs.enabled == 'true' env: CVE_EXCEPTIONS: ${{ steps.cve-list.outputs.CVE_EXCEPTIONS }} run: | diff --git a/.github/workflows/build-and-push-image.yaml b/.github/workflows/build-and-push-image.yaml index 2519d1362d..609921fc5f 100644 --- a/.github/workflows/build-and-push-image.yaml +++ b/.github/workflows/build-and-push-image.yaml @@ -121,6 +121,7 @@ jobs: # About VEX attestations https://docs.docker.com/scout/explore/exceptions/ # Justifications https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-justifications - name: Add VEX attestations + if: steps.dockerhub.outputs.enabled == 'true' env: CVE_EXCEPTIONS: ${{ steps.cve-list.outputs.CVE_EXCEPTIONS }} run: | diff --git a/frontend/index.html b/frontend/index.html index 22cc5b0f62..2804ff239c 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -28,6 +28,10 @@ + + + + diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json new file mode 100644 index 0000000000..f99301edad --- /dev/null +++ b/frontend/public/manifest.json @@ -0,0 +1,6 @@ +{ + "name":"AnythingLLM", + "short_name":"AnythingLLM", + "display":"standalone", + "orientation":"portrait" +} diff --git a/frontend/src/index.css b/frontend/src/index.css index 8c4ff7e1aa..a29506f1ab 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -255,6 +255,18 @@ body { background-color: white; } +@media (max-width: 600px) { + html { + overscroll-behavior: none; + } +} + +@media (prefers-color-scheme: dark) { + body { + background-color: #0e0f0f; + } +} + a { color: inherit; text-decoration: none; diff --git a/server/utils/boot/MetaGenerator.js b/server/utils/boot/MetaGenerator.js index 61f7e0d7a8..5bb9f84f68 100644 --- a/server/utils/boot/MetaGenerator.js +++ b/server/utils/boot/MetaGenerator.js @@ -126,6 +126,19 @@ class MetaGenerator { { tag: "link", props: { rel: "icon", href: "/favicon.png" } }, { tag: "link", props: { rel: "apple-touch-icon", href: "/favicon.png" } }, + // PWA tags + { + tag: "meta", + props: { name: "mobile-web-app-capable", content: "yes" }, + }, + { + tag: "meta", + props: { + name: "apple-mobile-web-app-status-bar-style", + content: "black-translucent", + }, + }, + { tag: "link", props: { rel: "manifest", href: "/manifest.json" } }, ]; } @@ -168,10 +181,19 @@ class MetaGenerator { async #fetchConfg() { this.#log(`fetching custom meta tag settings...`); const { SystemSettings } = require("../../models/systemSettings"); - const customTitle = await SystemSettings.getValueOrFallback( + + let customTitle = await SystemSettings.getValueOrFallback( { label: "meta_page_title" }, null ); + + if (!customTitle) { + customTitle = await SystemSettings.getValueOrFallback( + { label: "custom_app_name" }, + null + ); + } + const faviconURL = await SystemSettings.getValueOrFallback( { label: "meta_page_favicon" }, null @@ -181,19 +203,78 @@ class MetaGenerator { if (customTitle === null && faviconURL === null) { this.#customConfig = this.#defaultMeta(); } else { - this.#customConfig = [ - { - tag: "link", - props: { rel: "icon", href: this.#validUrl(faviconURL) }, - }, - { - tag: "title", - props: null, - content: - customTitle ?? - "AnythingLLM | Your personal LLM trained on anything", - }, - ]; + // When custom settings exist, include all default meta tags but override specific ones + this.#customConfig = this.#defaultMeta().map((tag) => { + // Override favicon link + if (tag.tag === "link" && tag.props?.rel === "icon") { + return { + tag: "link", + props: { rel: "icon", href: this.#validUrl(faviconURL) }, + }; + } + // Override page title + if (tag.tag === "title") { + return { + tag: "title", + props: null, + content: + customTitle ?? + "AnythingLLM | Your personal LLM trained on anything", + }; + } + // Override meta title + if (tag.tag === "meta" && tag.props?.name === "title") { + return { + tag: "meta", + props: { + name: "title", + content: + customTitle ?? + "AnythingLLM | Your personal LLM trained on anything", + }, + }; + } + // Override og:title + if (tag.tag === "meta" && tag.props?.property === "og:title") { + return { + tag: "meta", + props: { + property: "og:title", + content: + customTitle ?? + "AnythingLLM | Your personal LLM trained on anything", + }, + }; + } + // Override twitter:title + if (tag.tag === "meta" && tag.props?.property === "twitter:title") { + return { + tag: "meta", + props: { + property: "twitter:title", + content: + customTitle ?? + "AnythingLLM | Your personal LLM trained on anything", + }, + }; + } + // Override apple-touch-icon if custom favicon is set + if ( + tag.tag === "link" && + tag.props?.rel === "apple-touch-icon" && + faviconURL + ) { + return { + tag: "link", + props: { + rel: "apple-touch-icon", + href: this.#validUrl(faviconURL), + }, + }; + } + // Return original tag for everything else (including PWA tags) + return tag; + }); } return this.#customConfig;