Browse Source

feat: project theme

Signed-off-by: mertmit <mertmit99@gmail.com>
pull/3368/head
mertmit 2 years ago
parent
commit
9505c4c569
  1. 9
      packages/nc-gui-v2/composables/useProject.ts
  2. 52
      packages/nc-gui-v2/composables/useTheme/index.ts
  3. 6
      packages/nc-gui-v2/pages/[projectType]/[projectId]/index.vue
  4. 2
      packages/nocodb/src/lib/meta/api/projectApis.ts

9
packages/nc-gui-v2/composables/useProject.ts

@ -88,6 +88,14 @@ export function useProject(projectId?: MaybeRef<string>) {
await $api.project.update(_projectId, data) await $api.project.update(_projectId, data)
} }
function getProjectMeta() {
try {
return typeof project.value.meta === 'string' ? JSON.parse(project.value.meta) : project.value.meta
} catch (e) {
return {}
}
}
return { return {
project, project,
tables, tables,
@ -102,5 +110,6 @@ export function useProject(projectId?: MaybeRef<string>) {
isSharedBase, isSharedBase,
loadProjectMetaInfo, loadProjectMetaInfo,
projectMetaInfo, projectMetaInfo,
getProjectMeta,
} }
} }

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

@ -1,7 +1,6 @@
import { ConfigProvider } from 'ant-design-vue' import { ConfigProvider } from 'ant-design-vue'
import type { Theme as AntTheme } from 'ant-design-vue/es/config-provider' import type { Theme as AntTheme } from 'ant-design-vue/es/config-provider'
import { useStorage } from '@vueuse/core' import { hexToRGB, themeV2Colors, useCssVar, useInjectionState, useProject } from '#imports'
import { NOCO, hexToRGB, themeV2Colors, useCssVar, useInjectionState } from '#imports'
interface ThemeConfig extends AntTheme { interface ThemeConfig extends AntTheme {
primaryColor: string primaryColor: string
@ -12,17 +11,40 @@ const [setup, use] = useInjectionState((config?: Partial<ThemeConfig>) => {
const primaryColor = useCssVar('--color-primary', typeof document !== 'undefined' ? document.documentElement : null) const primaryColor = useCssVar('--color-primary', typeof document !== 'undefined' ? document.documentElement : null)
const accentColor = useCssVar('--color-accent', typeof document !== 'undefined' ? document.documentElement : null) const accentColor = useCssVar('--color-accent', typeof document !== 'undefined' ? document.documentElement : null)
/** current theme config */ const { project, getProjectMeta, updateProject } = useProject()
const currentTheme = useStorage<ThemeConfig>(
`${NOCO}db-theme`, const route = useRoute()
{
// set theme based on active project
watch(project, () => {
setTheme({
primaryColor: themeV2Colors['royal-blue'].DEFAULT, primaryColor: themeV2Colors['royal-blue'].DEFAULT,
accentColor: themeV2Colors.pink['500'], accentColor: themeV2Colors.pink['500'],
...getProjectMeta()?.theme,
})
})
// set default theme for routes out of project
watch(
() => route,
(v) => {
if (!v.params?.projectId) {
setTheme({
primaryColor: themeV2Colors['royal-blue'].DEFAULT,
accentColor: themeV2Colors.pink['500'],
})
}
}, },
localStorage, { deep: true },
{ mergeDefaults: true },
) )
/** current theme config */
const currentTheme = ref({
primaryColor: themeV2Colors['royal-blue'].DEFAULT,
accentColor: themeV2Colors.pink['500'],
...getProjectMeta()?.theme,
})
/** set initial config */ /** set initial config */
setTheme(config ?? currentTheme.value) setTheme(config ?? currentTheme.value)
@ -39,9 +61,23 @@ const [setup, use] = useInjectionState((config?: Partial<ThemeConfig>) => {
}) })
} }
async function saveTheme(theme: Partial<ThemeConfig>) {
const meta = getProjectMeta()
await updateProject({
meta: JSON.stringify({
...meta,
theme: {
...theme,
},
}),
})
setTheme(theme)
}
return { return {
theme: currentTheme, theme: currentTheme,
setTheme, setTheme,
saveTheme,
} }
}, 'theme') }, 'theme')

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

@ -59,11 +59,11 @@ let pickerActive = $ref<boolean | 'primary' | 'accent'>(false)
const email = computed(() => user.value?.email ?? '---') const email = computed(() => user.value?.email ?? '---')
const { setTheme, theme } = useTheme() const { saveTheme, theme } = useTheme()
watch(pickedColor, (nextColor) => { watch(pickedColor, (nextColor) => {
if (pickerActive && nextColor.hex) { if (pickerActive && nextColor.hex) {
setTheme({ saveTheme({
primaryColor: pickerActive === 'primary' ? nextColor.hex : theme.value.primaryColor, primaryColor: pickerActive === 'primary' ? nextColor.hex : theme.value.primaryColor,
accentColor: pickerActive === 'accent' ? nextColor.hex : theme.value.accentColor, accentColor: pickerActive === 'accent' ? nextColor.hex : theme.value.accentColor,
}) })
@ -348,7 +348,7 @@ const onMenuClose = (visible: boolean) => {
<a-menu-divider /> <a-menu-divider />
<a-sub-menu> <a-sub-menu v-if="isUIAllowed('projectTheme')">
<template #title> <template #title>
<div class="nc-project-menu-item group"> <div class="nc-project-menu-item group">
<ClarityImageLine class="group-hover:text-accent" /> <ClarityImageLine class="group-hover:text-accent" />

2
packages/nocodb/src/lib/meta/api/projectApis.ts

@ -54,7 +54,7 @@ export async function projectUpdate(
'meta', 'meta',
]); ]);
if (await Project.getByTitle(data.title) && project.title !== data.title) { if (data?.title && project.title !== data.title && await Project.getByTitle(data.title)) {
NcError.badRequest('Project title already in use'); NcError.badRequest('Project title already in use');
} }

Loading…
Cancel
Save