feat: MinApp added to the sidebar does not support direct hiding.
This commit is contained in:
parent
ad9fb9aa6d
commit
7633d70435
@ -1,10 +1,11 @@
|
|||||||
import { Center } from '@renderer/components/Layout'
|
import { Center } from '@renderer/components/Layout'
|
||||||
import { getAllMinApps } from '@renderer/config/minapps'
|
import { getAllMinApps } from '@renderer/config/minapps'
|
||||||
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import App from '@renderer/pages/apps/App'
|
import App from '@renderer/pages/apps/App'
|
||||||
import { Popover } from 'antd'
|
import { Popover } from 'antd'
|
||||||
import { Empty } from 'antd'
|
import { Empty } from 'antd'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { FC, useState } from 'react'
|
import { FC, useMemo, useState } from 'react'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -16,7 +17,14 @@ interface Props {
|
|||||||
|
|
||||||
const AppStorePopover: FC<Props> = ({ children }) => {
|
const AppStorePopover: FC<Props> = ({ children }) => {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const apps = getAllMinApps()
|
const { miniAppIcons } = useSettings()
|
||||||
|
const allApps = useMemo(() => getAllMinApps(), [])
|
||||||
|
|
||||||
|
// 只显示可见的小程序
|
||||||
|
const visibleApps = useMemo(() => {
|
||||||
|
if (!miniAppIcons?.visible) return allApps
|
||||||
|
return allApps.filter((app) => miniAppIcons.visible.includes(app.id))
|
||||||
|
}, [allApps, miniAppIcons?.visible])
|
||||||
|
|
||||||
useHotkeys('esc', () => {
|
useHotkeys('esc', () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
@ -29,10 +37,10 @@ const AppStorePopover: FC<Props> = ({ children }) => {
|
|||||||
const content = (
|
const content = (
|
||||||
<PopoverContent>
|
<PopoverContent>
|
||||||
<AppsContainer>
|
<AppsContainer>
|
||||||
{apps.map((app) => (
|
{visibleApps.map((app) => (
|
||||||
<App key={app.id} app={app} onClick={handleClose} size={50} />
|
<App key={app.id} app={app} onClick={handleClose} size={50} />
|
||||||
))}
|
))}
|
||||||
{isEmpty(apps) && (
|
{isEmpty(visibleApps) && (
|
||||||
<Center>
|
<Center>
|
||||||
<Empty />
|
<Empty />
|
||||||
</Center>
|
</Center>
|
||||||
|
|||||||
@ -411,6 +411,7 @@
|
|||||||
"display.minApp.visible": "Visible MinApp",
|
"display.minApp.visible": "Visible MinApp",
|
||||||
"display.minApp.disabled": "Hidden MinApp",
|
"display.minApp.disabled": "Hidden MinApp",
|
||||||
"display.minApp.empty": "Drag minApp from the left to hide them here",
|
"display.minApp.empty": "Drag minApp from the left to hide them here",
|
||||||
|
"display.minApp.pinnedError": "MinApp that have been added to the sidebar do not support hiding. If you want to hide them, please remove them from the sidebar first.",
|
||||||
"display.topic.title": "Topic Settings",
|
"display.topic.title": "Topic Settings",
|
||||||
"display.custom.css": "Custom CSS",
|
"display.custom.css": "Custom CSS",
|
||||||
"display.custom.css.placeholder": "/* Put custom CSS here */",
|
"display.custom.css.placeholder": "/* Put custom CSS here */",
|
||||||
|
|||||||
@ -412,6 +412,7 @@
|
|||||||
"display.minApp.visible": "表示中ミニプログラム",
|
"display.minApp.visible": "表示中ミニプログラム",
|
||||||
"display.minApp.disabled": "非表示ミニプログラム",
|
"display.minApp.disabled": "非表示ミニプログラム",
|
||||||
"display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします",
|
"display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします",
|
||||||
|
"display.minApp.pinnedError": "サイドバーに追加されたミニ プログラムは非表示をサポートしていません。非表示にしたい場合は、まずサイドバーから削除してください",
|
||||||
"input.auto_translate_with_space": "スペースを3回押して翻訳",
|
"input.auto_translate_with_space": "スペースを3回押して翻訳",
|
||||||
"messages.divider": "メッセージ間に区切り線を表示",
|
"messages.divider": "メッセージ間に区切り線を表示",
|
||||||
"messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け",
|
"messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け",
|
||||||
|
|||||||
@ -411,6 +411,7 @@
|
|||||||
"display.minApp.visible": "Отображаемый апплет",
|
"display.minApp.visible": "Отображаемый апплет",
|
||||||
"display.minApp.disabled": "скрытый апплет",
|
"display.minApp.disabled": "скрытый апплет",
|
||||||
"display.minApp.empty": "Перетащите апплет, который хотите скрыть, слева сюда",
|
"display.minApp.empty": "Перетащите апплет, который хотите скрыть, слева сюда",
|
||||||
|
"display.minApp.pinnedError": "Мини-программы, добавленные на боковую панель, не поддерживают скрытие. Если вы хотите скрыть их, сначала удалите их с боковой панели",
|
||||||
"display.topic.title": "Настройки топиков",
|
"display.topic.title": "Настройки топиков",
|
||||||
"display.custom.css": "Пользовательский CSS",
|
"display.custom.css": "Пользовательский CSS",
|
||||||
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
|
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
|
||||||
|
|||||||
@ -412,6 +412,7 @@
|
|||||||
"display.minApp.visible": "显示的小程序",
|
"display.minApp.visible": "显示的小程序",
|
||||||
"display.minApp.disabled": "隐藏的小程序",
|
"display.minApp.disabled": "隐藏的小程序",
|
||||||
"display.minApp.empty": "把要隐藏的小程序从左侧拖拽到这里",
|
"display.minApp.empty": "把要隐藏的小程序从左侧拖拽到这里",
|
||||||
|
"display.minApp.pinnedError": "已经添加到侧边栏的小程序,不支持隐藏,如需隐藏请先从侧边栏移除",
|
||||||
"display.topic.title": "话题设置",
|
"display.topic.title": "话题设置",
|
||||||
"display.custom.css": "自定义 CSS",
|
"display.custom.css": "自定义 CSS",
|
||||||
"display.custom.css.placeholder": "/* 这里写自定义CSS */",
|
"display.custom.css.placeholder": "/* 这里写自定义CSS */",
|
||||||
|
|||||||
@ -408,17 +408,14 @@
|
|||||||
"display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡",
|
"display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡",
|
||||||
"display.sidebar.visible": "顯示我的側邊欄圖標",
|
"display.sidebar.visible": "顯示我的側邊欄圖標",
|
||||||
"display.sidebar.disabled": "隱藏我的側邊欄圖標",
|
"display.sidebar.disabled": "隱藏我的側邊欄圖標",
|
||||||
|
"display.minApp.title": "小程序顯示設定",
|
||||||
|
"display.minApp.visible": "顯示的小程序",
|
||||||
|
"display.minApp.disabled": "隱藏的小程序",
|
||||||
|
"display.minApp.empty": "把要隱藏的小程序從左側拖拽到這裡",
|
||||||
|
"display.minApp.pinnedError": "已新增至側邊欄的小程序,不支援隱藏,如需隱藏請先從側邊欄移除",
|
||||||
"display.custom.css": "自定義 CSS",
|
"display.custom.css": "自定義 CSS",
|
||||||
"display.custom.css.placeholder": "/* 這裡寫自定義 CSS */",
|
"display.custom.css.placeholder": "/* 這裡寫自定義 CSS */",
|
||||||
"input.auto_translate_with_space": "快速敲擊3次空格翻譯",
|
"input.auto_translate_with_space": "快速敲擊3次空格翻譯",
|
||||||
"display": {
|
|
||||||
"minApp": {
|
|
||||||
"title": "小程序顯示設定",
|
|
||||||
"visible": "顯示的小程序",
|
|
||||||
"disabled": "隱藏的小程序",
|
|
||||||
"empty": "把要隱藏的小程序從左側拖拽到這裡"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"messages.divider": "訊息間顯示分隔線",
|
"messages.divider": "訊息間顯示分隔線",
|
||||||
"messages.input.paste_long_text_as_file": "將長文本貼上為檔案",
|
"messages.input.paste_long_text_as_file": "將長文本貼上為檔案",
|
||||||
"messages.input.send_shortcuts": "發送快捷鍵",
|
"messages.input.send_shortcuts": "發送快捷鍵",
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import { FC } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
app: MinAppType
|
app: MinAppType
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
@ -20,6 +19,7 @@ const App: FC<Props> = ({ app, onClick, size = 60 }) => {
|
|||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { miniAppIcons } = useAppSelector((state) => state.settings)
|
const { miniAppIcons } = useAppSelector((state) => state.settings)
|
||||||
const isPinned = miniAppIcons?.pinned.includes(app.id)
|
const isPinned = miniAppIcons?.pinned.includes(app.id)
|
||||||
|
const isVisible = miniAppIcons?.visible.includes(app.id)
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
MinApp.start(app)
|
MinApp.start(app)
|
||||||
@ -38,13 +38,16 @@ const App: FC<Props> = ({ app, onClick, size = 60 }) => {
|
|||||||
dispatch(
|
dispatch(
|
||||||
setMiniAppIcons({
|
setMiniAppIcons({
|
||||||
...miniAppIcons,
|
...miniAppIcons,
|
||||||
pinned: newPinned
|
pinned: newPinned,
|
||||||
|
visible: isPinned ? miniAppIcons.visible : [...new Set([...miniAppIcons.visible, app.id])]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (!isVisible) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown menu={{ items: menuItems }} trigger={['contextMenu']}>
|
<Dropdown menu={{ items: menuItems }} trigger={['contextMenu']}>
|
||||||
<Container onClick={handleClick}>
|
<Container onClick={handleClick}>
|
||||||
|
|||||||
@ -17,11 +17,15 @@ const AppsPage: FC = () => {
|
|||||||
const { miniAppIcons } = useSettings()
|
const { miniAppIcons } = useSettings()
|
||||||
const allApps = useMemo(() => getAllMinApps(), [])
|
const allApps = useMemo(() => getAllMinApps(), [])
|
||||||
|
|
||||||
// 只显示可见的小程序
|
// 只显示可见的小程序,但包括所有固定的小程序
|
||||||
const visibleApps = useMemo(() => {
|
const visibleApps = useMemo(() => {
|
||||||
if (!miniAppIcons?.visible) return allApps
|
if (!miniAppIcons?.visible) return allApps
|
||||||
return allApps.filter((app) => miniAppIcons.visible.includes(app.id))
|
const visibleIds = new Set([
|
||||||
}, [allApps, miniAppIcons?.visible])
|
...miniAppIcons.visible,
|
||||||
|
...(miniAppIcons.pinned || []) // 确保固定的小程序总是可见
|
||||||
|
])
|
||||||
|
return allApps.filter((app) => visibleIds.has(app.id))
|
||||||
|
}, [allApps, miniAppIcons?.visible, miniAppIcons?.pinned])
|
||||||
|
|
||||||
const filteredApps = search
|
const filteredApps = search
|
||||||
? visibleApps.filter(
|
? visibleApps.filter(
|
||||||
|
|||||||
@ -8,13 +8,13 @@ import {
|
|||||||
DropResult
|
DropResult
|
||||||
} from '@hello-pangea/dnd'
|
} from '@hello-pangea/dnd'
|
||||||
import { getAllMinApps } from '@renderer/config/minapps'
|
import { getAllMinApps } from '@renderer/config/minapps'
|
||||||
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
|
import { MinAppIcon, setMiniAppIcons } from '@renderer/store/settings'
|
||||||
import { FC, useCallback, useMemo } from 'react'
|
import { FC, useCallback, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { MinAppIcon, setMiniAppIcons } from '../../../store/settings'
|
|
||||||
|
|
||||||
interface MiniAppManagerProps {
|
interface MiniAppManagerProps {
|
||||||
visibleMiniApps: MinAppIcon[]
|
visibleMiniApps: MinAppIcon[]
|
||||||
disabledMiniApps: MinAppIcon[]
|
disabledMiniApps: MinAppIcon[]
|
||||||
@ -29,6 +29,50 @@ interface AppInfo {
|
|||||||
logo?: string
|
logo?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加 reorderLists 函数的接口定义
|
||||||
|
interface ReorderListsParams {
|
||||||
|
sourceList: MinAppIcon[]
|
||||||
|
destList: MinAppIcon[]
|
||||||
|
sourceIndex: number
|
||||||
|
destIndex: number
|
||||||
|
isSameList: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReorderListsResult {
|
||||||
|
sourceList: MinAppIcon[]
|
||||||
|
destList: MinAppIcon[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加 reorderLists 函数
|
||||||
|
const reorderLists = ({
|
||||||
|
sourceList,
|
||||||
|
destList,
|
||||||
|
sourceIndex,
|
||||||
|
destIndex,
|
||||||
|
isSameList
|
||||||
|
}: ReorderListsParams): ReorderListsResult => {
|
||||||
|
if (isSameList) {
|
||||||
|
// 在同一列表内重新排序
|
||||||
|
const newList = [...sourceList]
|
||||||
|
const [removed] = newList.splice(sourceIndex, 1)
|
||||||
|
newList.splice(destIndex, 0, removed)
|
||||||
|
return {
|
||||||
|
sourceList: newList,
|
||||||
|
destList: destList
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 在不同列表间移动
|
||||||
|
const newSourceList = [...sourceList]
|
||||||
|
const [removed] = newSourceList.splice(sourceIndex, 1)
|
||||||
|
const newDestList = [...destList]
|
||||||
|
newDestList.splice(destIndex, 0, removed)
|
||||||
|
return {
|
||||||
|
sourceList: newSourceList,
|
||||||
|
destList: newDestList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
||||||
visibleMiniApps,
|
visibleMiniApps,
|
||||||
disabledMiniApps,
|
disabledMiniApps,
|
||||||
@ -37,6 +81,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const { miniAppIcons } = useSettings()
|
||||||
const allApps = useMemo(() => getAllMinApps(), [])
|
const allApps = useMemo(() => getAllMinApps(), [])
|
||||||
|
|
||||||
// 创建 app 信息的 Map 缓存
|
// 创建 app 信息的 Map 缓存
|
||||||
@ -58,48 +103,64 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handleListUpdate = useCallback(
|
const handleListUpdate = useCallback(
|
||||||
(visible: MinAppIcon[], disabled: MinAppIcon[]) => {
|
(newVisible: MinAppIcon[], newDisabled: MinAppIcon[]) => {
|
||||||
setVisibleMiniApps(visible)
|
setVisibleMiniApps(newVisible)
|
||||||
setDisabledMiniApps(disabled)
|
setDisabledMiniApps(newDisabled)
|
||||||
dispatch(setMiniAppIcons({ visible, disabled, pinned: [] }))
|
|
||||||
|
// 保持 pinned 状态不变
|
||||||
|
dispatch(
|
||||||
|
setMiniAppIcons({
|
||||||
|
visible: newVisible,
|
||||||
|
disabled: newDisabled,
|
||||||
|
pinned: miniAppIcons.pinned // 保持原有的 pinned 状态
|
||||||
|
})
|
||||||
|
)
|
||||||
},
|
},
|
||||||
[dispatch, setVisibleMiniApps, setDisabledMiniApps]
|
[dispatch, setVisibleMiniApps, setDisabledMiniApps, miniAppIcons.pinned]
|
||||||
)
|
)
|
||||||
|
|
||||||
const onDragEnd = useCallback(
|
const onDragEnd = useCallback(
|
||||||
(result: DropResult) => {
|
(result: DropResult) => {
|
||||||
|
if (!result.destination) return
|
||||||
|
|
||||||
const { source, destination } = result
|
const { source, destination } = result
|
||||||
if (!destination) return
|
const sourceList = source.droppableId as ListType
|
||||||
|
const destList = destination.droppableId as ListType
|
||||||
|
|
||||||
const sourceList = source.droppableId === 'visible' ? visibleMiniApps : disabledMiniApps
|
// 如果是 pinned 的小程序,不允许拖到 disabled
|
||||||
const destList = destination.droppableId === 'visible' ? visibleMiniApps : disabledMiniApps
|
if (destList === 'disabled') {
|
||||||
|
const draggedApp = sourceList === 'visible' ? visibleMiniApps[source.index] : disabledMiniApps[source.index]
|
||||||
|
|
||||||
if (source.droppableId === destination.droppableId) {
|
if (miniAppIcons.pinned.includes(draggedApp)) {
|
||||||
const newList = [...sourceList]
|
window.message.error(t('settings.display.minApp.pinnedError'))
|
||||||
const [removed] = newList.splice(source.index, 1)
|
return
|
||||||
newList.splice(destination.index, 0, removed)
|
}
|
||||||
|
|
||||||
handleListUpdate(
|
|
||||||
source.droppableId === 'visible' ? newList : visibleMiniApps,
|
|
||||||
source.droppableId === 'disabled' ? newList : disabledMiniApps
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
const sourceNewList = [...sourceList]
|
|
||||||
const [removed] = sourceNewList.splice(source.index, 1)
|
|
||||||
const destNewList = [...destList]
|
|
||||||
destNewList.splice(destination.index, 0, removed)
|
|
||||||
|
|
||||||
handleListUpdate(
|
|
||||||
destination.droppableId === 'visible' ? destNewList : sourceNewList,
|
|
||||||
destination.droppableId === 'disabled' ? destNewList : sourceNewList
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newLists = reorderLists({
|
||||||
|
sourceList: sourceList === 'visible' ? visibleMiniApps : disabledMiniApps,
|
||||||
|
destList: destList === 'visible' ? visibleMiniApps : disabledMiniApps,
|
||||||
|
sourceIndex: source.index,
|
||||||
|
destIndex: destination.index,
|
||||||
|
isSameList: sourceList === destList
|
||||||
|
})
|
||||||
|
|
||||||
|
handleListUpdate(
|
||||||
|
sourceList === 'visible' ? newLists.sourceList : newLists.destList,
|
||||||
|
sourceList === 'visible' ? newLists.destList : newLists.sourceList
|
||||||
|
)
|
||||||
},
|
},
|
||||||
[visibleMiniApps, disabledMiniApps, handleListUpdate]
|
[visibleMiniApps, disabledMiniApps, handleListUpdate, miniAppIcons.pinned, t]
|
||||||
)
|
)
|
||||||
|
|
||||||
const onMoveMiniApp = useCallback(
|
const onMoveMiniApp = useCallback(
|
||||||
(program: MinAppIcon, fromList: ListType) => {
|
(program: MinAppIcon, fromList: ListType) => {
|
||||||
|
// 如果是从可见列表移动到隐藏列表,且程序是 pinned 状态,则阻止移动
|
||||||
|
if (fromList === 'visible' && miniAppIcons.pinned.includes(program)) {
|
||||||
|
window.message.error(t('settings.display.minApp.pinnedError'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const isMovingToVisible = fromList === 'disabled'
|
const isMovingToVisible = fromList === 'disabled'
|
||||||
const newVisible = isMovingToVisible
|
const newVisible = isMovingToVisible
|
||||||
? [...visibleMiniApps, program]
|
? [...visibleMiniApps, program]
|
||||||
@ -110,7 +171,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
|
|
||||||
handleListUpdate(newVisible, newDisabled)
|
handleListUpdate(newVisible, newDisabled)
|
||||||
},
|
},
|
||||||
[visibleMiniApps, disabledMiniApps, handleListUpdate]
|
[visibleMiniApps, disabledMiniApps, handleListUpdate, miniAppIcons.pinned, t]
|
||||||
)
|
)
|
||||||
|
|
||||||
const renderProgramItem = (program: MinAppIcon, provided: DraggableProvided, listType: ListType) => {
|
const renderProgramItem = (program: MinAppIcon, provided: DraggableProvided, listType: ListType) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user