Skip to content

Commit

Permalink
Refactor UI dark/bright mode (#2590)
Browse files Browse the repository at this point in the history
- collapse pipeline configs by default, closes
#2557
- refactor ui themes: instead of just differentiating between "is dark"
or "is not dark", add a third "auto" option following the browser
settings (closes
#2204) and put
everything into an enum. also move the option from the navbar to user
settings.

---------

Co-authored-by: Anbraten <anton@ju60.de>
  • Loading branch information
qwerty287 and anbraten authored Nov 1, 2023
1 parent 4198c44 commit 2ff916c
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 62 deletions.
10 changes: 7 additions & 3 deletions web/src/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
"password": "Password",
"url": "URL",
"back": "Back",
"color_scheme_light": "Switch to dark mode",
"color_scheme_dark": "Switch to light mode",
"unknown_error": "An unknown error occurred",
"documentation_for": "Documentation for \"{topic}\"",
"pipeline_feed": "Pipeline feed",
Expand Down Expand Up @@ -453,7 +451,13 @@
"settings": "User Settings",
"general": {
"general": "General",
"language": "Language"
"language": "Language",
"theme": {
"theme": "Theme",
"light": "Light",
"dark": "Dark",
"auto": "Auto"
}
},
"secrets": {
"secrets": "Secrets",
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/layout/Panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ import Icon from '~/components/atomic/Icon.vue';
const props = defineProps<{
title?: string;
collapsable?: boolean;
collapsedByDefault?: boolean;
}>();
/**
* _collapsed is used to store the internal state of the panel, but is
* ignored if the panel is not collapsable.
*/
const _collapsed = ref(false);
const _collapsed = ref(props.collapsedByDefault || false);
const collapsed = computed(() => props.collapsable && _collapsed.value);
</script>
9 changes: 0 additions & 9 deletions web/src/components/layout/header/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@
</div>
<!-- Right Icons Box -->
<div class="flex ml-auto -m-1.5 items-center space-x-2">
<!-- Dark Mode Toggle -->
<IconButton
:icon="darkMode ? 'dark' : 'light'"
:title="$t(darkMode ? 'color_scheme_dark' : 'color_scheme_light')"
class="navbar-icon"
@click="darkMode = !darkMode"
/>
<!-- Admin Settings -->
<IconButton
v-if="user?.admin"
Expand Down Expand Up @@ -62,15 +55,13 @@ import Button from '~/components/atomic/Button.vue';
import IconButton from '~/components/atomic/IconButton.vue';
import useAuthentication from '~/compositions/useAuthentication';
import useConfig from '~/compositions/useConfig';
import { useDarkMode } from '~/compositions/useDarkMode';
import ActivePipelines from './ActivePipelines.vue';
const config = useConfig();
const route = useRoute();
const authentication = useAuthentication();
const { user } = authentication;
const { darkMode } = useDarkMode();
const apiUrl = `${config.rootPath ?? ''}/swagger/index.html`;
function doLogin() {
Expand Down
12 changes: 12 additions & 0 deletions web/src/components/user/UserGeneralTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
<InputField :label="$t('user.settings.general.language')">
<SelectField v-model="selectedLocale" :options="localeOptions" />
</InputField>
<InputField :label="$t('user.settings.general.theme.theme')">
<SelectField
v-model="storeTheme"
:options="[
{ value: 'auto', text: $t('user.settings.general.theme.auto') },
{ value: 'light', text: $t('user.settings.general.theme.light') },
{ value: 'dark', text: $t('user.settings.general.theme.dark') },
]"
/>
</InputField>
</Settings>
</template>

Expand All @@ -17,8 +27,10 @@ import { useI18n } from 'vue-i18n';
import SelectField from '~/components/form/SelectField.vue';
import Settings from '~/components/layout/Settings.vue';
import { setI18nLanguage } from '~/compositions/useI18n';
import { useTheme } from '~/compositions/useTheme';
const { locale } = useI18n();
const { storeTheme } = useTheme();
const localeOptions = computed(() =>
SUPPORTED_LOCALES.map((supportedLocale) => ({
Expand Down
47 changes: 0 additions & 47 deletions web/src/compositions/useDarkMode.ts

This file was deleted.

5 changes: 3 additions & 2 deletions web/src/compositions/useFavicon.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { computed, ref, watch } from 'vue';

import useConfig from '~/compositions/useConfig';
import { useDarkMode } from '~/compositions/useDarkMode';
import { useTheme } from '~/compositions/useTheme';
import { PipelineStatus } from '~/lib/api/types';

const darkMode = computed(() => (useDarkMode().darkMode.value ? 'dark' : 'light'));
const { theme } = useTheme();
const darkMode = computed(() => theme.value);

type Status = 'default' | 'success' | 'pending' | 'error';
const faviconStatus = ref<Status>('default');
Expand Down
31 changes: 31 additions & 0 deletions web/src/compositions/useTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useColorMode } from '@vueuse/core';
import { watch } from 'vue';

const { store: storeTheme, state: resolvedTheme } = useColorMode({
storageKey: 'woodpecker:theme',
});

function updateTheme() {
if (resolvedTheme.value === 'dark') {
document.documentElement.classList.remove('light');
document.documentElement.classList.add('dark');
document.documentElement.setAttribute('data-theme', 'dark');
document.querySelector('meta[name=theme-color]')?.setAttribute('content', '#2A2E3A'); // internal-wp-secondary-600 (see windi.config.ts)
} else {
document.documentElement.classList.remove('dark');
document.documentElement.classList.add('light');
document.documentElement.setAttribute('data-theme', 'light');
document.querySelector('meta[name=theme-color]')?.setAttribute('content', '#369943'); // internal-wp-primary-400
}
}

watch(storeTheme, updateTheme);

updateTheme();

export function useTheme() {
return {
theme: resolvedTheme,
storeTheme,
};
}
1 change: 1 addition & 0 deletions web/src/views/repo/pipeline/PipelineConfig.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
v-for="pipelineConfig in pipelineConfigs || []"
:key="pipelineConfig.hash"
collapsable
collapsed-by-default
:title="pipelineConfig.name"
>
<SyntaxHighlight class="font-mono whitespace-pre overflow-auto" language="yaml" :code="pipelineConfig.data" />
Expand Down

0 comments on commit 2ff916c

Please sign in to comment.