+
@@ -52,7 +53,16 @@ const LocaleLayout = ({
- {children}
+
+
+ {children}
+
+
diff --git a/web/context/app-context.tsx b/web/context/app-context.tsx
index 3d6acc55a3..a6a9afaec9 100644
--- a/web/context/app-context.tsx
+++ b/web/context/app-context.tsx
@@ -8,15 +8,12 @@ import { fetchAppList } from '@/service/apps'
import Loading from '@/app/components/base/loading'
import { fetchCurrentWorkspace, fetchLanggeniusVersion, fetchUserProfile, getSystemFeatures } from '@/service/common'
import type { App } from '@/types/app'
-import { Theme } from '@/types/app'
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
import type { SystemFeatures } from '@/types/feature'
import { defaultSystemFeatures } from '@/types/feature'
export type AppContextValue = {
- theme: Theme
- setTheme: (theme: Theme) => void
apps: App[]
systemFeatures: SystemFeatures
mutateApps: VoidFunction
@@ -56,9 +53,7 @@ const initialWorkspaceInfo: ICurrentWorkspace = {
}
const AppContext = createContext
({
- theme: Theme.light,
systemFeatures: defaultSystemFeatures,
- setTheme: () => { },
apps: [],
mutateApps: () => { },
userProfile: {
@@ -128,24 +123,11 @@ export const AppContextProvider: FC = ({ children }) =>
setCurrentWorkspace(currentWorkspaceResponse)
}, [currentWorkspaceResponse])
- const [theme, setTheme] = useState(Theme.light)
- const handleSetTheme = useCallback((theme: Theme) => {
- setTheme(theme)
- globalThis.document.documentElement.setAttribute('data-theme', theme)
- }, [])
-
- useEffect(() => {
- globalThis.document.documentElement.setAttribute('data-theme', theme)
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [])
-
if (!appList || !userProfile)
return
return (
{
+ const { theme, resolvedTheme, ...rest } = useBaseTheme()
+ return {
+ // only returns 'light' or 'dark' theme
+ theme: theme === Theme.system ? resolvedTheme as Theme : theme as Theme,
+ ...rest,
+ }
+}
+
+export default useTheme
diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts
index f302d81c47..a3d5beaa36 100644
--- a/web/i18n/en-US/plugin.ts
+++ b/web/i18n/en-US/plugin.ts
@@ -194,6 +194,8 @@ const translation = {
firstReleased: 'First Released',
},
viewMore: 'View more',
+ verifiedTip: 'This plugin is verified by Dify',
+ partnerTip: 'This plugin is developed by Dify partners',
},
task: {
installing: 'Installing {{installingLength}} plugins, 0 done.',
diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts
index c13f7b84f1..6dca9dd33f 100644
--- a/web/i18n/zh-Hans/plugin.ts
+++ b/web/i18n/zh-Hans/plugin.ts
@@ -194,6 +194,8 @@ const translation = {
firstReleased: '首次发布',
},
viewMore: '查看更多',
+ verifiedTip: '此插件已由 Dify 认证',
+ partnerTip: '此插件由 Dify 合作伙伴开发',
},
task: {
installing: '{{installingLength}} 个插件安装中,0 已完成',
diff --git a/web/package.json b/web/package.json
index a80dce141d..d6a9740e11 100644
--- a/web/package.json
+++ b/web/package.json
@@ -33,7 +33,13 @@
"@headlessui/react": "^1.7.13",
"@heroicons/react": "^2.0.16",
"@hookform/resolvers": "^3.9.0",
+ "@lexical/code": "^0.18.0",
+ "@lexical/link": "^0.18.0",
+ "@lexical/list": "^0.18.0",
"@lexical/react": "^0.18.0",
+ "@lexical/selection": "^0.18.0",
+ "@lexical/text": "^0.18.0",
+ "@lexical/utils": "^0.18.0",
"@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0",
"@monaco-editor/react": "^4.6.0",
@@ -77,6 +83,7 @@
"mitt": "^3.0.1",
"negotiator": "^0.6.3",
"next": "^14.2.10",
+ "next-themes": "^0.4.3",
"pinyin-pro": "^3.25.0",
"qrcode.react": "^4.1.0",
"qs": "^6.13.0",
diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml
index cd2101df52..465947e2e3 100644
--- a/web/pnpm-lock.yaml
+++ b/web/pnpm-lock.yaml
@@ -40,9 +40,27 @@ importers:
'@hookform/resolvers':
specifier: ^3.9.0
version: 3.9.0(react-hook-form@7.53.1(react@18.2.0))
+ '@lexical/code':
+ specifier: ^0.18.0
+ version: 0.18.0
+ '@lexical/link':
+ specifier: ^0.18.0
+ version: 0.18.0
+ '@lexical/list':
+ specifier: ^0.18.0
+ version: 0.18.0
'@lexical/react':
specifier: ^0.18.0
version: 0.18.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(yjs@13.6.20)
+ '@lexical/selection':
+ specifier: ^0.18.0
+ version: 0.18.0
+ '@lexical/text':
+ specifier: ^0.18.0
+ version: 0.18.0
+ '@lexical/utils':
+ specifier: ^0.18.0
+ version: 0.18.0
'@mdx-js/loader':
specifier: ^3.1.0
version: 3.1.0(acorn@8.13.0)(webpack@5.95.0(esbuild@0.23.1)(uglify-js@3.19.3))
@@ -172,6 +190,9 @@ importers:
next:
specifier: ^14.2.10
version: 14.2.15(@babel/core@7.25.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.80.3)
+ next-themes:
+ specifier: ^0.4.3
+ version: 0.4.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
pinyin-pro:
specifier: ^3.25.0
version: 3.25.0
@@ -6299,6 +6320,12 @@ packages:
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+ next-themes@0.4.4:
+ resolution: {integrity: sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==}
+ peerDependencies:
+ react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+
next@14.2.15:
resolution: {integrity: sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==}
engines: {node: '>=18.17.0'}
@@ -15966,6 +15993,11 @@ snapshots:
neo-async@2.6.2: {}
+ next-themes@0.4.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
+ dependencies:
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+
next@14.2.15(@babel/core@7.25.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.80.3):
dependencies:
'@next/env': 14.2.15
diff --git a/web/types/app.ts b/web/types/app.ts
index 2f5f6254ff..39f011dcaa 100644
--- a/web/types/app.ts
+++ b/web/types/app.ts
@@ -11,6 +11,7 @@ import type { UploadFileSetting } from '@/app/components/workflow/types'
export enum Theme {
light = 'light',
dark = 'dark',
+ system = 'system',
}
export enum ProviderType {