Browse Source

feat(gui-v2): persist theme colors and add picker for accent

pull/3249/head
braks 2 years ago
parent
commit
1bd8e778af
  1. 7
      packages/nc-gui-v2/app.vue
  2. 1
      packages/nc-gui-v2/components.d.ts
  3. 26
      packages/nc-gui-v2/composables/useTheme/index.ts
  4. 71
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue
  5. 2
      packages/nc-gui-v2/windi.config.ts

7
packages/nc-gui-v2/app.vue

@ -1,14 +1,11 @@
<script setup lang="ts">
import { computed, themeV2Colors, useRoute, useTheme } from '#imports'
import { computed, provideTheme, useRoute } from '#imports'
const route = useRoute()
const disableBaseLayout = computed(() => route.path.startsWith('/nc/view') || route.path.startsWith('/nc/form'))
useTheme({
primaryColor: themeV2Colors['royal-blue'].DEFAULT,
accentColor: themeV2Colors.pink['500'],
})
provideTheme()
</script>
<template>

1
packages/nc-gui-v2/components.d.ts vendored

@ -72,6 +72,7 @@ declare module '@vue/runtime-core' {
CilFullscreen: typeof import('~icons/cil/fullscreen')['default']
CilFullscreenExit: typeof import('~icons/cil/fullscreen-exit')['default']
ClarityColorPickerLine: typeof import('~icons/clarity/color-picker-line')['default']
ClarityColorPickerSolid: typeof import('~icons/clarity/color-picker-solid')['default']
ClarityImageLine: typeof import('~icons/clarity/image-line')['default']
ClaritySuccessLine: typeof import('~icons/clarity/success-line')['default']
EvaEmailOutline: typeof import('~icons/eva/email-outline')['default']

26
packages/nc-gui-v2/composables/useTheme/index.ts

@ -1,8 +1,10 @@
import { ConfigProvider } from 'ant-design-vue'
import type { Theme as AntTheme } from 'ant-design-vue/es/config-provider'
import { hexToRGB, ref, useCssVar, useInjectionState } from '#imports'
import { useStorage } from '@vueuse/core'
import { NOCO, hexToRGB, themeV2Colors, toRefs, useCssVar, useInjectionState } from '#imports'
interface ThemeConfig extends AntTheme {
primaryColor: string
accentColor: string
}
@ -11,17 +13,26 @@ const [setup, use] = useInjectionState((config?: Partial<ThemeConfig>) => {
const accentColor = useCssVar('--color-accent', typeof document !== 'undefined' ? document.documentElement : null)
/** current theme config */
const currentTheme = ref<Partial<ThemeConfig>>()
/** set initial config if exists */
if (config) setTheme(config)
const currentTheme = useStorage<ThemeConfig>(
`${NOCO}db-theme`,
{
primaryColor: themeV2Colors['royal-blue'].DEFAULT,
accentColor: themeV2Colors.pink['500'],
},
localStorage,
{ mergeDefaults: true },
)
/** set initial config */
setTheme(config ?? currentTheme.value)
/** set theme (persists in localstorage) */
function setTheme(theme: Partial<ThemeConfig>) {
// convert hex colors to rgb values
if (theme.primaryColor) primaryColor.value = hexToRGB(theme.primaryColor)
if (theme.accentColor) accentColor.value = hexToRGB(theme.accentColor)
currentTheme.value = theme
currentTheme.value = theme as ThemeConfig
ConfigProvider.config({
theme,
@ -31,7 +42,6 @@ const [setup, use] = useInjectionState((config?: Partial<ThemeConfig>) => {
return {
theme: currentTheme,
setTheme,
cssVars: { primaryColor, accentColor },
}
})

71
packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue

@ -53,18 +53,19 @@ const dropdownOpen = ref(false)
/** Sidebar ref */
const sidebar = ref()
const pickedColor = ref<any>('')
const pickedColor = ref<any>('#ffffff')
const pickerActive = ref(false)
let pickerActive = $ref<boolean | 'primary' | 'accent'>(false)
const email = computed(() => user.value?.email ?? '---')
const { setTheme } = useTheme()
const { setTheme, theme } = useTheme()
watch(pickedColor, (nextColor) => {
if (nextColor) {
if (pickerActive && nextColor.hex) {
setTheme({
primaryColor: nextColor.hex,
primaryColor: pickerActive === 'primary' ? nextColor.hex : theme.value.primaryColor,
accentColor: pickerActive === 'accent' ? nextColor.hex : theme.value.accentColor,
})
}
})
@ -124,6 +125,22 @@ const copyAuthToken = async () => {
message.error(e.message)
}
}
const openColorPicker = (type: 'primary' | 'accent') => {
if (!pickerActive || pickerActive !== type) {
pickedColor.value = type === 'primary' ? theme.value.primaryColor : theme.value.accentColor
pickerActive = type
} else {
pickerActive = false
}
}
const onMenuClose = (visible: boolean) => {
if (!visible) {
pickedColor.value = '#ffffff'
pickerActive = false
}
}
</script>
<template>
@ -171,7 +188,7 @@ const copyAuthToken = async () => {
</template>
</div>
<a-dropdown v-else class="h-full min-w-0 flex-1" :trigger="['click']" placement="bottom">
<a-dropdown v-else class="h-full min-w-0 flex-1" :trigger="['click']" placement="bottom" @visible-change="onMenuClose">
<div
:style="{ width: isOpen ? 'calc(100% - 40px) pr-2' : '100%' }"
:class="[isOpen ? '' : 'justify-center']"
@ -331,14 +348,42 @@ const copyAuthToken = async () => {
<a-menu-divider />
<a-menu-item class="relative">
<div class="nc-project-menu-item group" @click.stop="pickerActive = !pickerActive">
<ClarityImageLine class="group-hover:text-accent" />
Theme
<a-sub-menu>
<template #title>
<div class="nc-project-menu-item group">
<ClarityImageLine class="group-hover:text-accent" />
Theme
<Chrome v-if="pickerActive" v-model="pickedColor" class="absolute top-0 right-5" @click.stop />
</div>
</a-menu-item>
<div class="flex-1" />
<MaterialSymbolsChevronRightRounded
class="transform group-hover:(scale-115 text-accent) text-xl text-gray-400"
/>
</div>
</template>
<a-menu-item>
<div class="nc-project-menu-item group" @click.stop="openColorPicker('primary')">
<ClarityColorPickerSolid class="group-hover:text-accent" />
Primary Color
</div>
</a-menu-item>
<a-menu-item>
<div class="nc-project-menu-item group" @click.stop="openColorPicker('accent')">
<ClarityColorPickerSolid class="group-hover:text-accent" />
Accent Color
</div>
</a-menu-item>
</a-sub-menu>
<Chrome
v-if="pickerActive"
v-model="pickedColor"
class="z-99 absolute right-[-225px]"
@click.stop
@blur="onMenuClose(false)"
/>
</a-menu-item-group>
</a-menu>
</template>

2
packages/nc-gui-v2/windi.config.ts

@ -27,7 +27,7 @@ export default defineConfig({
questionMark,
formsPlugin,
typographyPlugin({
dark: false,
dark: true,
}),
aspectRatioPlugin,
lineClampPlugin,

Loading…
Cancel
Save