Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Theming with Vuetify #237

tjones-ieee started this conversation in Show and tell
Discussion options

Hello again everyone.

For those of you using Vuetify, you've probably already had to come up with a way to synchronize the colors of VueDataUI components with Vuetify's ability to switch between light and dark modes. Maybe @graphieros will create light and dark modes in the future :P

If you're struggling with ways to easily synchronize colors, here's a way I have found useful. It leverages composables within Vue, enabling reactive updates to all VueDataUI components based on the current Vuetify theme.

Related reading

Note: I'm using VueUiScatter for this example, but they're all very similar.

It starts with useConfig

This composable allows you to set all colors for each component, and then automatically apply them by overriding the component configurations.

// useConfig.ts
import { computed, type Ref } from 'vue';
import { type VueUiScatterConfig } from 'vue-data-ui';
import { mergeObjects } from '@/core/utils';
import { useColors } from '../../config/useColors';
import { useTitle } from '../../config/vdu/useTitle';
import { useLegend } from '../../config/vdu/useLegend';
import { useTooltip } from '../../config/vdu/useTooltip';
export function useConfig(customConfig: Ref<VueUiScatterConfig>) {
 const { colors } = useColors();
 const { title } = useTitle(colors);
 const { legend } = useLegend(colors);
 const { tooltip } = useTooltip(colors);
 const vuetifyConfig = computed<VueUiScatterConfig>(() => {
 return {
 style: {
 backgroundColor: colors.value.bg,
 color: colors.value.text,
 layout: {
 axis: {
 stroke: colors.value.stroke,
 },
 dataLabels: {
 xAxis: {
 color: colors.value.text,
 },
 yAxis: {
 color: colors.value.text,
 },
 },
 marginalBars: {
 fill: colors.value.stroke,
 },
 },
 title: title.value,
 legend: legend.value,
 tooltip: tooltip.value,
 },
 };
 });
 const config = computed<VueUiScatterConfig>(() => {
 const custom = customConfig.value || {};
 const vuetify = vuetifyConfig.value || {};
 const merged = mergeObjects(custom, vuetify);
 return merged;
 });
 return { config };
}

useColors composable

// useColors.ts
import { computed } from 'vue';
import { useTheme } from 'vuetify';
type iColors = {
 bg: string;
 text: string;
 stroke: string;
};
export function useColors() {
 const theme = useTheme();
 const themeName = computed<'light' | 'dark'>(() => {
 if (theme.current.value.dark) return 'dark';
 return 'light';
 });
 const colors = computed<iColors>(() => {
 return {
 bg: theme.current.value.colors.surface,
 text: { light: '#1a1a1a', dark: '#f5f5f5' }[themeName.value],
 stroke: { light: '#afb0b0', dark: '#8f9090' }[themeName.value],
 };
 });
 return { colors };
}

useTitle composable

// useTitle.ts
import { computed, type Ref } from 'vue';
type iColors = {
 bg: string;
 text: string;
 stroke: string;
};
export function useTitle(colors: Ref<iColors>) {
 const title = computed<any>(() => {
 return {
 color: colors.value.text,
 subtitle: {
 color: colors.value.stroke,
 },
 };
 });
 return { title };
}

useLegend composable

// useLegend.ts
import { computed, type Ref } from 'vue';
type iColors = {
 bg: string;
 text: string;
 stroke: string;
};
export function useLegend(colors: Ref<iColors>, noBackground?: boolean) {
 const legend = computed<any>(() => {
 if (noBackground) {
 return {
 color: colors.value.text,
 };
 } else {
 return {
 color: colors.value.text,
 backgroundColor: colors.value.bg,
 };
 }
 });
 return { legend };
}

useTooltip composable

// useTooltip.ts
import { computed, type Ref } from 'vue';
type iColors = {
 bg: string;
 text: string;
 stroke: string;
};
export function useTooltip(colors: Ref<iColors>, noOpacity?: boolean) {
 const tooltip = computed<any>(() => {
 if (noOpacity) {
 return {
 color: colors.value.text,
 backgroundColor: colors.value.bg + '80', // 50% opacity
 borderColor: colors.value.stroke,
 };
 } else {
 // standard...
 return {
 color: colors.value.text,
 backgroundColor: colors.value.bg,
 backgroundOpacity: 50,
 borderColor: colors.value.stroke,
 };
 }
 });
 return { tooltip };
}

Applying this methodology

const defaultConfig = ref<VueUiScatterConfig>(getVueDataUiConfig('vue_ui_scatter'));
const { config } = useConfig(defaultConfig);
<VueUiScatter v-if="dataset.length > 0" :dataset="dataset" :config="config" />
You must be logged in to vote

Replies: 0 comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation reactivity Questions related to reactivity advanced usage
1 participant

AltStyle によって変換されたページ (->オリジナル) /