feat: compact theme (#1574)
* feat: compact theme * fix: theme * fix: styling * fix: margin * feat: improve * fix: remove console.log
This commit is contained in:
parent
75c338b0f1
commit
4427c70087
@ -1,3 +1,4 @@
|
|||||||
|
import '@/theme';
|
||||||
import { Application } from '@nocobase/client';
|
import { Application } from '@nocobase/client';
|
||||||
|
|
||||||
export const app = new Application({
|
export const app = new Application({
|
||||||
|
6
packages/app/client/src/theme.ts
Normal file
6
packages/app/client/src/theme.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
if (localStorage.getItem('NOCOBASE_THEME') === 'compact') {
|
||||||
|
import('antd/dist/antd.compact.css');
|
||||||
|
} else {
|
||||||
|
import('antd/dist/antd.css');
|
||||||
|
}
|
||||||
|
window.document.documentElement.classList.add('theme-' + (localStorage.getItem('NOCOBASE_THEME') || 'default'));
|
@ -1,5 +1,5 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
|
import React, { createContext, useContext } from 'react';
|
||||||
import { useRequest } from '../api-client';
|
import { useRequest } from '../api-client';
|
||||||
|
|
||||||
export const CurrentAppInfoContext = createContext(null);
|
export const CurrentAppInfoContext = createContext(null);
|
||||||
@ -8,17 +8,26 @@ export const useCurrentAppInfo = () => {
|
|||||||
return useContext(CurrentAppInfoContext);
|
return useContext(CurrentAppInfoContext);
|
||||||
};
|
};
|
||||||
export const CurrentAppInfoProvider = (props) => {
|
export const CurrentAppInfoProvider = (props) => {
|
||||||
const result = useRequest({
|
const result = useRequest(
|
||||||
|
{
|
||||||
url: 'app:getInfo',
|
url: 'app:getInfo',
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
onSuccess(data) {
|
||||||
|
const localTheme = localStorage.getItem('NOCOBASE_THEME');
|
||||||
|
if (localTheme !== data?.data?.theme) {
|
||||||
|
localStorage.setItem('NOCOBASE_THEME', data?.data?.theme);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const localTheme = localStorage.getItem('NOCOBASE_THEME');
|
||||||
|
if (localTheme && localTheme !== result?.data?.data?.theme) {
|
||||||
|
return <Spin />;
|
||||||
|
}
|
||||||
if (result.loading) {
|
if (result.loading) {
|
||||||
return <Spin />;
|
return <Spin />;
|
||||||
}
|
}
|
||||||
return (
|
return <CurrentAppInfoContext.Provider value={result.data}>{props.children}</CurrentAppInfoContext.Provider>;
|
||||||
<CurrentAppInfoContext.Provider
|
|
||||||
value={result.data}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</CurrentAppInfoContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'antd/dist/antd.css';
|
|
||||||
import './global.less';
|
import './global.less';
|
||||||
|
|
||||||
export * from './acl';
|
export * from './acl';
|
||||||
@ -27,3 +26,4 @@ export * from './schema-templates';
|
|||||||
export * from './settings-form';
|
export * from './settings-form';
|
||||||
export * from './system-settings';
|
export * from './system-settings';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
|
|
||||||
|
@ -680,5 +680,8 @@ export default {
|
|||||||
'Use variable': '使用变量',
|
'Use variable': '使用变量',
|
||||||
'True': '真',
|
'True': '真',
|
||||||
'False': '假',
|
'False': '假',
|
||||||
'Prettify': '格式化'
|
'Prettify': '格式化',
|
||||||
|
'Theme': '主题',
|
||||||
|
'Default theme': '默认主题',
|
||||||
|
'Compact theme': '紧凑主题',
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ const PluginList = (props) => {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div style={{ margin: 24, display: 'flex', flexFlow: 'row wrap' }}>
|
<div className={'m24'} style={{ margin: 24, display: 'flex', flexFlow: 'row wrap' }}>
|
||||||
{React.createElement(
|
{React.createElement(
|
||||||
{
|
{
|
||||||
local: LocalPlugins,
|
local: LocalPlugins,
|
||||||
@ -399,7 +399,7 @@ const SettingsCenter = (props) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div style={{ margin: 24 }}>
|
<div className={'m24'} style={{ margin: 24 }}>
|
||||||
{aclPluginTabCheck ? (
|
{aclPluginTabCheck ? (
|
||||||
component && React.createElement(component)
|
component && React.createElement(component)
|
||||||
) : (
|
) : (
|
||||||
|
@ -2,3 +2,23 @@
|
|||||||
color: #000000d9;
|
color: #000000d9;
|
||||||
font-weight:600;
|
font-weight:600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-table-pagination.ant-pagination {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-formily-item {
|
||||||
|
font-size: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-compact {
|
||||||
|
.ant-formily-item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.ant-card {
|
||||||
|
margin-bottom: 16px !important;
|
||||||
|
}
|
||||||
|
.m24 {
|
||||||
|
margin: 16px !important;
|
||||||
|
}
|
||||||
|
}
|
@ -253,7 +253,7 @@ export const Page = (props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ margin: 24 }}>
|
<div className={'m24'} style={{ margin: 24 }}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Spin />
|
<Spin />
|
||||||
) : !disablePageHeader && enablePageTabs ? (
|
) : !disablePageHeader && enablePageTabs ? (
|
||||||
|
@ -81,7 +81,7 @@ export const BlockTemplateDetails = () => {
|
|||||||
ghost={false}
|
ghost={false}
|
||||||
title={<EditableTitle filterByTk={key} title={data?.data?.name} />}
|
title={<EditableTitle filterByTk={key} title={data?.data?.name} />}
|
||||||
/>
|
/>
|
||||||
<div style={{ margin: 24 }}>
|
<div className={'m24'} style={{ margin: 24 }}>
|
||||||
<SchemaComponentContext.Provider value={{ ...value, designable: true }}>
|
<SchemaComponentContext.Provider value={{ ...value, designable: true }}>
|
||||||
<RemoteSchemaComponent uid={data?.data?.uid} />
|
<RemoteSchemaComponent uid={data?.data?.uid} />
|
||||||
</SchemaComponentContext.Provider>
|
</SchemaComponentContext.Provider>
|
||||||
|
@ -11,7 +11,7 @@ export const BlockTemplatePage = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AntdPageHeader ghost={false} title={t('Block templates')} />
|
<AntdPageHeader ghost={false} title={t('Block templates')} />
|
||||||
<div style={{ margin: 24 }}>
|
<div className={'m24'} style={{ margin: 24 }}>
|
||||||
<CollectionManagerProvider collections={[uiSchemaTemplatesCollection]}>
|
<CollectionManagerProvider collections={[uiSchemaTemplatesCollection]}>
|
||||||
<SchemaComponent schema={uiSchemaTemplatesSchema} />
|
<SchemaComponent schema={uiSchemaTemplatesSchema} />
|
||||||
</CollectionManagerProvider>
|
</CollectionManagerProvider>
|
||||||
|
@ -10,9 +10,25 @@ export const useSystemSettings = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SystemSettingsProvider: React.FC = (props) => {
|
export const SystemSettingsProvider: React.FC = (props) => {
|
||||||
const result = useRequest({
|
const result = useRequest(
|
||||||
|
{
|
||||||
url: 'systemSettings:get/1?appends=logo',
|
url: 'systemSettings:get/1?appends=logo',
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
onSuccess(data) {
|
||||||
|
const localTheme = localStorage.getItem('NOCOBASE_THEME');
|
||||||
|
if (!localTheme) {
|
||||||
|
const theme = data?.data?.options?.theme;
|
||||||
|
localStorage.setItem('NOCOBASE_THEME', theme || 'default');
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const localTheme = localStorage.getItem('NOCOBASE_THEME');
|
||||||
|
if (!localTheme) {
|
||||||
|
return <Spin />;
|
||||||
|
}
|
||||||
if (result.loading) {
|
if (result.loading) {
|
||||||
return <Spin />;
|
return <Spin />;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,19 @@ const schema2: ISchema = {
|
|||||||
// accept: 'jpg,png'
|
// accept: 'jpg,png'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'options.theme': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Theme")}}',
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
// mode: 'multiple',
|
||||||
|
},
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
enum: [
|
||||||
|
{ label: '{{t("Default theme")}}', value: 'default' },
|
||||||
|
{ label: '{{t("Compact theme")}}', value: 'compact' },
|
||||||
|
],
|
||||||
|
},
|
||||||
enabledLanguages: {
|
enabledLanguages: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
title: '{{t("Enabled languages")}}',
|
title: '{{t("Enabled languages")}}',
|
||||||
|
@ -9,6 +9,7 @@ import { ChangePassword } from './ChangePassword';
|
|||||||
import { EditProfile } from './EditProfile';
|
import { EditProfile } from './EditProfile';
|
||||||
import { LanguageSettings } from './LanguageSettings';
|
import { LanguageSettings } from './LanguageSettings';
|
||||||
import { SwitchRole } from './SwitchRole';
|
import { SwitchRole } from './SwitchRole';
|
||||||
|
import { ThemeSettings } from './ThemeSettings';
|
||||||
|
|
||||||
const ApplicationVersion = () => {
|
const ApplicationVersion = () => {
|
||||||
const data = useCurrentAppInfo();
|
const data = useCurrentAppInfo();
|
||||||
@ -43,6 +44,7 @@ export const CurrentUser = () => {
|
|||||||
<ChangePassword />
|
<ChangePassword />
|
||||||
<SwitchRole />
|
<SwitchRole />
|
||||||
<LanguageSettings />
|
<LanguageSettings />
|
||||||
|
<ThemeSettings />
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="signout"
|
key="signout"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
import { Menu, Select } from 'antd';
|
import { Menu, Select } from 'antd';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -22,6 +23,13 @@ export const LanguageSettings = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
{t('Language')}{' '}
|
{t('Language')}{' '}
|
||||||
<Select
|
<Select
|
||||||
@ -51,6 +59,7 @@ export const LanguageSettings = () => {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
import { Menu, Select } from 'antd';
|
import { Menu, Select } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -36,6 +37,13 @@ export const SwitchRole = () => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Menu.Item key="role" eventKey={'SwitchRole'}>
|
<Menu.Item key="role" eventKey={'SwitchRole'}>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
`}
|
||||||
|
>
|
||||||
{t('Switch role')}{' '}
|
{t('Switch role')}{' '}
|
||||||
<Select
|
<Select
|
||||||
style={{ minWidth: 100 }}
|
style={{ minWidth: 100 }}
|
||||||
@ -53,6 +61,7 @@ export const SwitchRole = () => {
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
47
packages/core/client/src/user/ThemeSettings.tsx
Normal file
47
packages/core/client/src/user/ThemeSettings.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { Menu, Select } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAPIClient } from '../api-client';
|
||||||
|
import { useCurrentUserContext } from './CurrentUserProvider';
|
||||||
|
|
||||||
|
export const ThemeSettings = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const ctx = useCurrentUserContext();
|
||||||
|
const api = useAPIClient();
|
||||||
|
return (
|
||||||
|
<Menu.Item key="theme" eventKey={'theme'}>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{t('Theme')}{' '}
|
||||||
|
<Select
|
||||||
|
style={{ minWidth: 100 }}
|
||||||
|
bordered={false}
|
||||||
|
defaultValue={localStorage.getItem('NOCOBASE_THEME')}
|
||||||
|
options={[
|
||||||
|
{ label: t('Default theme'), value: 'default' },
|
||||||
|
{ label: t('Compact theme'), value: 'compact' },
|
||||||
|
]}
|
||||||
|
onChange={async (value) => {
|
||||||
|
await api.resource('users').update({
|
||||||
|
filterByTk: ctx.data.data.id,
|
||||||
|
values: {
|
||||||
|
systemSettings: {
|
||||||
|
...ctx.data.data.systemSettings,
|
||||||
|
theme: value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
localStorage.setItem('NOCOBASE_THEME', value);
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Menu.Item>
|
||||||
|
);
|
||||||
|
};
|
@ -48,6 +48,7 @@ export class ClientPlugin extends Plugin {
|
|||||||
},
|
},
|
||||||
version: await ctx.app.version.get(),
|
version: await ctx.app.version.get(),
|
||||||
lang,
|
lang,
|
||||||
|
theme: currentUser?.systemSettings?.theme || systemSetting?.options?.theme || 'default',
|
||||||
};
|
};
|
||||||
await next();
|
await next();
|
||||||
},
|
},
|
||||||
|
@ -37,5 +37,10 @@ export default defineCollection({
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'appLang',
|
name: 'appLang',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'json',
|
||||||
|
name: 'options',
|
||||||
|
defaultValue: {},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -80,5 +80,10 @@ export default {
|
|||||||
unique: true,
|
unique: true,
|
||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'json',
|
||||||
|
name: 'systemSettings',
|
||||||
|
defaultValue: {},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
} as CollectionOptions;
|
} as CollectionOptions;
|
||||||
|
Loading…
Reference in New Issue
Block a user