feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,132 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { ListItem, ListItemType } from '../types';
|
||||
import { isFolderSelected, isTagSelected } from '@joplin/lib/components/shared/side-menu-shared';
|
||||
import { Dispatch } from 'redux';
|
||||
import { ALL_NOTES_FILTER_ID } from '@joplin/lib/reserved-ids';
|
||||
|
||||
type UpdateSelectedIndexOptions = { extend: boolean };
|
||||
|
||||
interface Props {
|
||||
dispatch: Dispatch;
|
||||
listItems: ListItem[];
|
||||
|
||||
notesParentType: string;
|
||||
selectedTagId: string;
|
||||
selectedTagIds: string[];
|
||||
selectedFolderId: string;
|
||||
selectedFolderIds: string[];
|
||||
selectedSmartFilterId: string;
|
||||
}
|
||||
|
||||
const useSelectedSidebarIndexes = (props: Props) => {
|
||||
const isIndexInSelection = useCallback((index: number) => {
|
||||
const listItem = props.listItems[index];
|
||||
|
||||
let selected = false;
|
||||
if (listItem.kind === ListItemType.AllNotes) {
|
||||
selected = props.selectedSmartFilterId === ALL_NOTES_FILTER_ID && props.notesParentType === 'SmartFilter';
|
||||
} else if (listItem.kind === ListItemType.Header || listItem.kind === ListItemType.Spacer) {
|
||||
selected = false;
|
||||
} else if (listItem.kind === ListItemType.Folder) {
|
||||
selected = isFolderSelected(listItem.folder, {
|
||||
selectedFolderIds: props.selectedFolderIds,
|
||||
notesParentType: props.notesParentType,
|
||||
});
|
||||
} else if (listItem.kind === ListItemType.Tag) {
|
||||
selected = isTagSelected(listItem.tag, { selectedTagIds: props.selectedTagIds, notesParentType: props.notesParentType });
|
||||
} else {
|
||||
const exhaustivenessCheck: never = listItem;
|
||||
return exhaustivenessCheck;
|
||||
}
|
||||
|
||||
return selected;
|
||||
}, [props.listItems, props.selectedFolderIds, props.selectedTagIds, props.selectedSmartFilterId, props.notesParentType]);
|
||||
|
||||
const isIndexPrimarySelected = useCallback((index: number) => {
|
||||
const listItem = props.listItems[index];
|
||||
|
||||
if (listItem.kind === ListItemType.Folder) {
|
||||
return isFolderSelected(listItem.folder, {
|
||||
selectedFolderIds: [props.selectedFolderId],
|
||||
notesParentType: props.notesParentType,
|
||||
});
|
||||
} else if (listItem.kind === ListItemType.Tag) {
|
||||
return isTagSelected(listItem.tag, { selectedTagIds: [props.selectedTagId], notesParentType: props.notesParentType });
|
||||
} else {
|
||||
return isIndexInSelection(index);
|
||||
}
|
||||
}, [props.listItems, isIndexInSelection, props.selectedFolderId, props.selectedTagId, props.notesParentType]);
|
||||
|
||||
const appStateSelectedIndexes = useMemo(() => {
|
||||
const selectedIndexes = [];
|
||||
for (let i = 0; i < props.listItems.length; i++) {
|
||||
if (isIndexInSelection(i)) {
|
||||
selectedIndexes.push(i);
|
||||
}
|
||||
}
|
||||
return selectedIndexes;
|
||||
}, [props.listItems, isIndexInSelection]);
|
||||
|
||||
const appStateSelectedIndex = useMemo(() => {
|
||||
return props.listItems.findIndex((_item, index) => isIndexPrimarySelected(index));
|
||||
}, [props.listItems, isIndexPrimarySelected]);
|
||||
|
||||
// The main index of all selected indexes. This is where the focus will go.
|
||||
// Ignored if not included in appStateSelectedIndexes.
|
||||
const [primarySelectedIndex, setPrimarySelectedIndex] = useState(0);
|
||||
|
||||
// Not all list items correspond with selectable Joplin folders/tags, but we want to
|
||||
// be able to select them anyway. This is handled with selectedIndexOverride.
|
||||
//
|
||||
// When selectedIndexOverride >= 0, it corresponds to the index of a selected item with no
|
||||
// specific note parent item (e.g. a header).
|
||||
const [selectedIndexOverride, setSelectedIndexOverride] = useState(-1);
|
||||
useEffect(() => {
|
||||
setSelectedIndexOverride(-1);
|
||||
setPrimarySelectedIndex(appStateSelectedIndex);
|
||||
}, [appStateSelectedIndex]);
|
||||
|
||||
const updateSelectedIndex = useCallback((newIndex: number, options: UpdateSelectedIndexOptions) => {
|
||||
if (newIndex < 0) {
|
||||
newIndex = 0;
|
||||
} else if (newIndex >= props.listItems.length) {
|
||||
newIndex = props.listItems.length - 1;
|
||||
}
|
||||
|
||||
const newItem = props.listItems[newIndex];
|
||||
let newOverrideIndex = -1;
|
||||
if (newItem.kind === ListItemType.AllNotes) {
|
||||
props.dispatch({
|
||||
type: 'SMART_FILTER_SELECT',
|
||||
id: ALL_NOTES_FILTER_ID,
|
||||
});
|
||||
} else if (newItem.kind === ListItemType.Folder) {
|
||||
props.dispatch({
|
||||
type: options.extend ? 'FOLDER_SELECT_ADD' : 'FOLDER_SELECT',
|
||||
id: newItem.folder.id,
|
||||
});
|
||||
} else if (newItem.kind === ListItemType.Tag) {
|
||||
props.dispatch({
|
||||
type: options.extend ? 'TAG_SELECT_ADD' : 'TAG_SELECT',
|
||||
id: newItem.tag.id,
|
||||
});
|
||||
} else {
|
||||
newOverrideIndex = newIndex;
|
||||
}
|
||||
setSelectedIndexOverride(newOverrideIndex);
|
||||
setPrimarySelectedIndex(newIndex);
|
||||
}, [props.listItems, props.dispatch]);
|
||||
|
||||
const selectedIndexes = useMemo(() => {
|
||||
return selectedIndexOverride === -1 ? appStateSelectedIndexes : [selectedIndexOverride];
|
||||
}, [appStateSelectedIndexes, selectedIndexOverride]);
|
||||
const selectedIndex = selectedIndexes.includes(primarySelectedIndex) ? primarySelectedIndex : (selectedIndexes[0] ?? -1);
|
||||
|
||||
return {
|
||||
selectedIndex,
|
||||
selectedIndexes,
|
||||
updateSelectedIndex,
|
||||
};
|
||||
};
|
||||
|
||||
export default useSelectedSidebarIndexes;
|
||||
在新工单中引用
屏蔽一个用户