diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue index 4336dfa33e226bbcbc98b938af1a455d7c1595e4..b7eb49f4ba0e4413639005ce561902d734866381 100644 --- a/src/components/AppHeader.vue +++ b/src/components/AppHeader.vue @@ -3,6 +3,7 @@ import { useUserStore } from "@/stores/users"; import { useRoute, useRouter } from "vue-router"; import { watch, ref, computed } from "vue"; import { OpenAPI } from "@/client"; +import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue"; const userRepository = useUserStore(); const route = useRoute(); @@ -13,6 +14,12 @@ function logout() { router.push({ name: "login" }); } +type PossibleThemes = "light" | "dark"; + +const activeTheme = ref<PossibleThemes>( + (localStorage.getItem("theme") as PossibleThemes) ?? "light", +); + const activeRoute = ref(""); const objectStorageActive = computed<boolean>( () => activeRoute.value == "buckets" || activeRoute.value == "s3_keys", @@ -43,6 +50,13 @@ watch( } }, ); + +watch(activeTheme, (newTheme, oldTheme) => { + if (newTheme !== oldTheme) { + document.querySelector("html")?.setAttribute("data-bs-theme", newTheme); + localStorage.setItem("theme", newTheme); + } +}); </script> <template> @@ -259,6 +273,53 @@ watch( </li> </ul> </div> + <div class="dropdown"> + <button + class="btn btn-link nav-link dropdown-toggle d-flex align-items-center" + data-bs-toggle="dropdown" + aria-expanded="false" + > + <font-awesome-icon + :icon="`fa-solid fa-${activeTheme === 'light' ? 'sun' : 'moon'}`" + /> + </button> + <ul class="dropdown-menu w-fit"> + <li> + <button + class="dropdown-item d-flex align-items-center" + :class="{ active: activeTheme === 'light' }" + @click="activeTheme = 'light'" + > + <font-awesome-icon + icon="fa-solid fa-sun" + class="me-2 opacity-50" + /> + <span class="flex-grow-1">Light</span> + <font-awesome-icon + v-if="activeTheme === 'light'" + icon="fa-solid fa-check" + /> + </button> + </li> + <li> + <button + class="dropdown-item d-flex align-items-center" + :class="{ active: activeTheme === 'dark' }" + @click="activeTheme = 'dark'" + > + <font-awesome-icon + icon="fa-solid fa-moon" + class="me-2 opacity-50" + /> + <span class="flex-grow-1">Dark</span> + <font-awesome-icon + v-if="activeTheme === 'dark'" + icon="fa-solid fa-check" + /> + </button> + </li> + </ul> + </div> <div class="dropdown" v-if="userRepository.authenticated && userRepository.user != null" diff --git a/src/components/parameter-schema/description-mode/ParameterDescription.vue b/src/components/parameter-schema/description-mode/ParameterDescription.vue index da45df33f6ab2f700be8f7f3711383e3ef5a2db2..cf07dd5e43d414f8bcb15e0b738730d466c12808 100644 --- a/src/components/parameter-schema/description-mode/ParameterDescription.vue +++ b/src/components/parameter-schema/description-mode/ParameterDescription.vue @@ -54,7 +54,7 @@ const showRightColum = computed<boolean>( </script> <template> - <div class="border-top border-dark" v-if="showHidden || !hidden"> + <div class="border-top" v-if="showHidden || !hidden"> <div class="d-flex pt-2 justify-content-between"> <div class="flex-fill ps-2"> <div class="row"> diff --git a/src/components/parameter-schema/form-mode/ParameterBooleanInput.vue b/src/components/parameter-schema/form-mode/ParameterBooleanInput.vue index d6d581b5cebaa60b7bf08fac16398da56a94bdf8..74faa96ef47b7248ba19bb155420012c287ac1be 100644 --- a/src/components/parameter-schema/form-mode/ParameterBooleanInput.vue +++ b/src/components/parameter-schema/form-mode/ParameterBooleanInput.vue @@ -23,7 +23,7 @@ const iconPresent = computed<boolean>(() => props.parameter["fa_icon"]); const dynamicCssClasses = computed<string[]>(() => { const cssClasses = []; if (props.border) { - cssClasses.push("border", `border-${props.border}`, "text-bg-light"); + cssClasses.push("border", `border-${props.border}`, "bg-dark-subtle"); } if (!helpTextPresent.value) { cssClasses.push("rounded-end"); diff --git a/src/components/workflows/modals/ArbitraryWorkflowModal.vue b/src/components/workflows/modals/ArbitraryWorkflowModal.vue index 5cf624651cded11fb212e034cf24ba1ef468c0be..ad34a85766671009ab99060e01bc4ff4a27934b4 100644 --- a/src/components/workflows/modals/ArbitraryWorkflowModal.vue +++ b/src/components/workflows/modals/ArbitraryWorkflowModal.vue @@ -397,32 +397,6 @@ function checkRepository() { } } }); - // repo - // .checkFilesExist( - // requiredRepositoryFiles( - // workflowMode.modeEnabled ? [workflowMode.mode] : [], - // ), - // true, - // ) - // .then(() => { - // formState.allowUpload = true; - // }) - // .catch((e: Error) => { - // try { - // const headers = JSON.parse(e.message); - // - // } catch { - // formState.missingFiles = e.message.split(","); - // // Allow execution of the workflow if main.nf and parameter schema are not missing - // if ( - // formState.missingFiles.findIndex( - // (file) => file === "main.nf" || file === "nextflow_schema.json", - // ) < 0 - // ) { - // formState.allowUpload = true; - // } - // } - // }); } catch (e) { formState.unsupportedRepository = true; workflowRepositoryElement.value?.setCustomValidity( diff --git a/src/main.ts b/src/main.ts index 6bf10bb4eff87aff28a55b730c5f014b0e309680..c685a8fd880d6e47f59e10efb16e11c85d3622c5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -60,6 +60,13 @@ if (environment.MATOMO_HOST && environment.MATOMO_SITE_ID) { app.use(createPinia()); app.use(router); +const theme = localStorage.getItem("theme"); +if (theme != undefined) { + document.querySelector("html")?.setAttribute("data-bs-theme", theme); +} //else if (window.matchMedia("(prefers-color-scheme: dark)").matches) { +// document.querySelector("html")?.setAttribute("data-bs-theme", "dark"); +//} + app.mount("#app"); // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/stores/users.ts b/src/stores/users.ts index fd2581db96e904071eec41219b99d2373feac51f..ebda0eac18a23483d6b3bcbb4931b8144ef12681 100644 --- a/src/stores/users.ts +++ b/src/stores/users.ts @@ -106,7 +106,11 @@ export const useUserStore = defineStore({ logout() { window._paq.push(["resetUserId"]); this.$reset(); + const activeTheme = localStorage.getItem("theme"); localStorage.clear(); + if (activeTheme != undefined) { + localStorage.setItem("theme", activeTheme); + } dbclear(); useWorkflowExecutionStore().$reset(); useBucketStore().$reset(); diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index 4a281ec25c8201a0fe8d8b31f21f8225b8ea6af7..ffa889c489c09ad561b152639e2f2ee80c571eaa 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -103,7 +103,7 @@ onMounted(() => { <div class="d-flex flex-row justify-content-evenly align-items-center flex-wrap w-100" > - <div class="border rounded p-4 icon text-center m-2" hidden> + <div class="border rounded p-4 icon text-center m-2 text-bg-light" hidden> <h4 class="mb-4">A Service By</h4> <a href="https://nfdi4microbiota.de/"> <img @@ -113,7 +113,7 @@ onMounted(() => { /> </a> </div> - <div class="border rounded p-4 icon text-center m-2"> + <div class="border rounded p-4 icon text-center m-2 text-bg-light"> <h4 class="mb-4">Powered By</h4> <a href="https://www.denbi.de/"> <img @@ -123,17 +123,17 @@ onMounted(() => { /> </a> </div> - <div class="border rounded p-4 icon text-center m-2"> + <div class="border rounded p-4 icon text-center m-2 text-bg-light"> <h4 class="mb-4">Hosted By</h4> <a href="https://bibi.uni-bielefeld.de/"> <img src="/src/assets/images/bibi.png" alt="BiBi Logo" height="50" /> </a> </div> - <div class="border rounded p-4 icon text-center m-2"> + <div class="border rounded p-4 icon text-center m-2 text-bg-light"> <h4 class="mb-4">Funded By</h4> <img src="/src/assets/images/dfg.png" alt="DFG Logo" height="50" /> </div> - <div class="border rounded p-4 icon text-center m-2"> + <div class="border rounded p-4 icon text-center m-2 text-bg-light"> <img src="/src/assets/images/unibi.svg" alt="Bielefeld University Logo"