mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-02-24 15:35:11 +00:00
minor fixes
This commit is contained in:
parent
916d827b1b
commit
bc4ed128b6
1 changed files with 89 additions and 85 deletions
|
@ -64,14 +64,14 @@ interface DestinationItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UnspecificRowProps {
|
interface UnspecificRowProps {
|
||||||
key: string
|
key: string;
|
||||||
destination: DestinationItem,
|
destination: DestinationItem,
|
||||||
rowMode: string
|
rowMode: string;
|
||||||
disabled: boolean,
|
disabled: boolean,
|
||||||
isSelected: boolean,
|
isSelected: boolean,
|
||||||
onPressDestination: (destination: DestinationItem) => void,
|
onPressDestination: (destination: DestinationItem) => void,
|
||||||
"aria-posinset": number,
|
"aria-posinset": number,
|
||||||
"aria-setsize": number
|
"aria-setsize": number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SpecificRowProps extends UnspecificRowProps {
|
interface SpecificRowProps extends UnspecificRowProps {
|
||||||
|
@ -113,8 +113,18 @@ interface GuildResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result = UserResult | ChannelResult | GuildResult;
|
type Result = UserResult | ChannelResult | GuildResult;
|
||||||
|
type SearchType = ("USERS" | "CHANNELS" | "GUILDS")[] | "USERS" | "CHANNELS" | "GUILDS" | "ALL";
|
||||||
|
|
||||||
const searchTypesToResultTypes = (type: string | string[]) => {
|
export interface SearchModalProps {
|
||||||
|
modalProps: ModalProps;
|
||||||
|
onSubmit(selected: DestinationItem[]): void;
|
||||||
|
input?: string;
|
||||||
|
searchType?: SearchType;
|
||||||
|
subText?: string;
|
||||||
|
excludeIds?: string[],
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchTypesToResultTypes = (type: SearchType) => {
|
||||||
if (type === "ALL") return ["USER", "TEXT_CHANNEL", "VOICE_CHANNEL", "GROUP_DM", "GUILD"];
|
if (type === "ALL") return ["USER", "TEXT_CHANNEL", "VOICE_CHANNEL", "GROUP_DM", "GUILD"];
|
||||||
if (typeof type === "string") {
|
if (typeof type === "string") {
|
||||||
if (type === "USERS") return ["USER"];
|
if (type === "USERS") return ["USER"];
|
||||||
|
@ -125,10 +135,10 @@ const searchTypesToResultTypes = (type: string | string[]) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function searchTypeToText(type: string | string[]) {
|
function searchTypeToText(type: SearchType) {
|
||||||
if (type === undefined || type === "ALL") return "Users, Channels, and Servers";
|
if (type === undefined || type === "ALL") return "Users, Channels, and Servers";
|
||||||
if (typeof type === "string") {
|
if (typeof type === "string") {
|
||||||
if (type === "GUILD") return "Servers";
|
if (type === "GUILDS") return "Servers";
|
||||||
else return type.charAt(0) + type.slice(1).toLowerCase();
|
else return type.charAt(0) + type.slice(1).toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
if (type.length === 1) {
|
if (type.length === 1) {
|
||||||
|
@ -144,23 +154,17 @@ function searchTypeToText(type: string | string[]) {
|
||||||
/**
|
/**
|
||||||
* SearchModal component for displaying a modal with search functionality, built after Discord's forwarding Modal.
|
* SearchModal component for displaying a modal with search functionality, built after Discord's forwarding Modal.
|
||||||
*
|
*
|
||||||
* @param {Object} props - The props for the SearchModal component.
|
* @param {SearchModalProps} props - The props for the SearchModal component.
|
||||||
* @param {ModalProps} props.modalProps - The modal props.
|
* @param {ModalProps} props.modalProps - The modal props. You get these from the `openModal` function.
|
||||||
* @param {function} props.onSubmit - The function to call when the user submits their selection.
|
* @param {function} props.onSubmit - The function to call when the user submits their selection.
|
||||||
* @param {string} [props.input] - The initial input value for the search bar.
|
* @param {string} [props.input] - The initial input value for the search bar.
|
||||||
* @param {("USERS" | "CHANNELS" | "GUILDS")[] | "USERS" | "CHANNELS" | "GUILDS" | "ALL"} [props.searchType="ALL"] - The type of items to search for.
|
* @param {SearchType} [props.searchType="ALL"] - The type of items to search for.
|
||||||
* @param {string} [props.subText] - Additional text to display below the heading.
|
* @param {string} [props.subText] - Additional text to display below the heading.
|
||||||
* @param {string[]} [props.excludeIds] - An array of IDs to exclude from the search results.
|
* @param {string[]} [props.excludeIds] - An array of IDs to exclude from the search results.
|
||||||
* @returns The rendered SearchModal component.
|
* @returns The rendered SearchModal component.
|
||||||
*/
|
*/
|
||||||
export default function SearchModal({ modalProps, onSubmit, input, searchType = "ALL", subText, excludeIds }: {
|
export default function SearchModal({ modalProps, onSubmit, input, searchType = "ALL", subText, excludeIds }: SearchModalProps) {
|
||||||
modalProps: ModalProps;
|
|
||||||
onSubmit(selected: DestinationItem[]): void;
|
|
||||||
input?: string;
|
|
||||||
searchType?: ("USERS" | "CHANNELS" | "GUILDS")[] | "USERS" | "CHANNELS" | "GUILDS" | "ALL";
|
|
||||||
subText?: string
|
|
||||||
excludeIds?: string[],
|
|
||||||
}) {
|
|
||||||
const UserIcon = React.memo(function ({
|
const UserIcon = React.memo(function ({
|
||||||
user,
|
user,
|
||||||
size = SearchBarModule.AvatarSizes.SIZE_32,
|
size = SearchBarModule.AvatarSizes.SIZE_32,
|
||||||
|
@ -253,14 +257,14 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row {...otherProps}
|
<Row {...otherProps}
|
||||||
icon={<UserIcon
|
icon={<UserIcon
|
||||||
aria-hidden={true}
|
aria-hidden={true}
|
||||||
size={SearchBarModule.AvatarSizes.SIZE_32}
|
size={SearchBarModule.AvatarSizes.SIZE_32}
|
||||||
user={user}
|
user={user}
|
||||||
status={userStatus}
|
status={userStatus}
|
||||||
/>}
|
/>}
|
||||||
label={nickname ?? username}
|
label={nickname ?? username}
|
||||||
subLabel={userTag}
|
subLabel={userTag}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -321,13 +325,13 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row {...otherProps}
|
<Row {...otherProps}
|
||||||
icon={<SearchBarModule.Avatar
|
icon={<SearchBarModule.Avatar
|
||||||
src={guildIcon}
|
src={guildIcon}
|
||||||
size={SearchBarModule.AvatarSizes.SIZE_32}
|
size={SearchBarModule.AvatarSizes.SIZE_32}
|
||||||
aria-hidden={true}
|
aria-hidden={true}
|
||||||
/>}
|
/>}
|
||||||
label={guildName}
|
label={guildName}
|
||||||
subLabel={""}
|
subLabel={""}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -352,10 +356,10 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row {...otherProps}
|
<Row {...otherProps}
|
||||||
icon={<GroupDMAvatars aria-hidden={true} size={SearchBarModule.AvatarSizes.SIZE_32}
|
icon={<GroupDMAvatars aria-hidden={true} size={SearchBarModule.AvatarSizes.SIZE_32}
|
||||||
channel={channel}/>}
|
channel={channel} />}
|
||||||
label={label}
|
label={label}
|
||||||
subLabel={subLabelValue}
|
subLabel={subLabelValue}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -396,7 +400,7 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
hasQuery: boolean;
|
hasQuery: boolean;
|
||||||
frequentChannels: Channel[];
|
frequentChannels: Channel[];
|
||||||
channelHistory: string[];
|
channelHistory: string[];
|
||||||
guilds: GuildResult[]
|
guilds: GuildResult[];
|
||||||
}): Result[] {
|
}): Result[] {
|
||||||
const removeDuplicates = (arr: Result[]): Result[] => {
|
const removeDuplicates = (arr: Result[]): Result[] => {
|
||||||
const clean: any[] = [];
|
const clean: any[] = [];
|
||||||
|
@ -422,7 +426,7 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
|
|
||||||
return removeDuplicates(
|
return removeDuplicates(
|
||||||
[...(selected.length > 0 ? selected.map(e => getItem(e)) : []),
|
[...(selected.length > 0 ? selected.map(e => getItem(e)) : []),
|
||||||
...recentDestinations
|
...recentDestinations
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,39 +437,39 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
return ref_.current;
|
return ref_.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSearchHandler(searchOptions: Record<string, any>): { search: (e: { query: string, resultTypes: string[] }) => void, results: Result[], query: string } {
|
function getSearchHandler(searchOptions: Record<string, any>): { search: (e: { query: string, resultTypes: string[]; }) => void, results: Result[], query: string; } {
|
||||||
const [results, setResults] = useState<{ results: Result[], query: string }>({
|
const [results, setResults] = useState<{ results: Result[], query: string; }>({
|
||||||
results: [],
|
results: [],
|
||||||
query: ""
|
query: ""
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchHandler: InstanceType<typeof SearchHandler> = getRef(() => {
|
const searchHandler: InstanceType<typeof SearchHandler> = getRef(() => {
|
||||||
const searchHandler = new SearchHandler((r: Result[], q: string) => {
|
const searchHandler = new SearchHandler((r: Result[], q: string) => {
|
||||||
setResults({
|
setResults({
|
||||||
results: r,
|
results: r,
|
||||||
query: q
|
query: q
|
||||||
});
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
searchHandler.setLimit(20);
|
|
||||||
searchHandler.search("");
|
|
||||||
return searchHandler;
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
searchHandler.setLimit(20);
|
||||||
|
searchHandler.search("");
|
||||||
|
return searchHandler;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
useEffect(() => () => searchHandler.destroy(), [searchHandler]);
|
useEffect(() => () => searchHandler.destroy(), [searchHandler]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
searchOptions != null && searchOptions !== searchHandler.options && searchHandler.setOptions(searchOptions);
|
searchOptions != null && searchOptions !== searchHandler.options && searchHandler.setOptions(searchOptions);
|
||||||
}, [searchHandler, searchOptions]
|
}, [searchHandler, searchOptions]
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
search: useCallback(e => {
|
search: useCallback(e => {
|
||||||
const { query, resultTypes } = e;
|
const { query, resultTypes } = e;
|
||||||
if (searchHandler.resultTypes == null || !(resultTypes.length === searchHandler.resultTypes.size && resultTypes.every(e => searchHandler.resultTypes.has(e)))) {
|
if (searchHandler.resultTypes == null || !(resultTypes.length === searchHandler.resultTypes.size && resultTypes.every(e => searchHandler.resultTypes.has(e)))) {
|
||||||
searchHandler.setResultTypes(resultTypes);
|
searchHandler.setResultTypes(resultTypes);
|
||||||
searchHandler.setLimit(resultTypes.length === 1 ? 50 : 20);
|
searchHandler.setLimit(resultTypes.length === 1 ? 50 : 20);
|
||||||
}
|
|
||||||
searchHandler.search(query.trim() === "" ? "" : query);
|
|
||||||
}
|
}
|
||||||
|
searchHandler.search(query.trim() === "" ? "" : query);
|
||||||
|
}
|
||||||
, [searchHandler]),
|
, [searchHandler]),
|
||||||
...results
|
...results
|
||||||
};
|
};
|
||||||
|
@ -530,11 +534,11 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
|
|
||||||
const rowHeight = useCallback(() => 48, []);
|
const rowHeight = useCallback(() => 48, []);
|
||||||
|
|
||||||
function ModalScroller({ rowData, handleToggleDestination, paddingBottom, paddingTop }: { rowData: Result[], handleToggleDestination: (destination: DestinationItem) => void, paddingBottom?: number, paddingTop?: number }) {
|
function ModalScroller({ rowData, handleToggleDestination, paddingBottom, paddingTop }: { rowData: Result[], handleToggleDestination: (destination: DestinationItem) => void, paddingBottom?: number, paddingTop?: number; }) {
|
||||||
|
|
||||||
const sectionCount: number[] = useMemo(() => [rowData.length], [rowData.length]);
|
const sectionCount: number[] = useMemo(() => [rowData.length], [rowData.length]);
|
||||||
|
|
||||||
const callback = useCallback((e: { section: number, row: number }) => {
|
const callback = useCallback((e: { section: number, row: number; }) => {
|
||||||
const { section, row } = e;
|
const { section, row } = e;
|
||||||
if (section > 0)
|
if (section > 0)
|
||||||
return;
|
return;
|
||||||
|
@ -580,7 +584,7 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
sections={sectionCount}
|
sections={sectionCount}
|
||||||
sectionHeight={0}
|
sectionHeight={0}
|
||||||
renderRow={callback}
|
renderRow={callback}
|
||||||
rowHeight={rowHeight}/>;
|
rowHeight={rowHeight} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -612,11 +616,11 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
<div className={cl("header-text")}>
|
<div className={cl("header-text")}>
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
||||||
<Heading variant="heading-lg/semibold"
|
<Heading variant="heading-lg/semibold"
|
||||||
style={{ flexGrow: 1 }}>{"Search for " + searchTypeToText(searchType)}</Heading>
|
style={{ flexGrow: 1 }}>{"Search for " + searchTypeToText(searchType)}</Heading>
|
||||||
{subText !== undefined && <Heading variant="heading-sm/normal"
|
{subText !== undefined && <Heading variant="heading-sm/normal"
|
||||||
style={{ color: "var(--header-muted)" }}>{subText}</Heading>}
|
style={{ color: "var(--header-muted)" }}>{subText}</Heading>}
|
||||||
</div>
|
</div>
|
||||||
<ModalCloseButton onClick={modalProps.onClose}/>
|
<ModalCloseButton onClick={modalProps.onClose} />
|
||||||
</div>
|
</div>
|
||||||
<SearchBarWrapper.SearchBar
|
<SearchBarWrapper.SearchBar
|
||||||
size={SearchBarModule.SearchBar.Sizes.MEDIUM}
|
size={SearchBarModule.SearchBar.Sizes.MEDIUM}
|
||||||
|
@ -639,26 +643,26 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
rowData={results}
|
rowData={results}
|
||||||
handleToggleDestination={setSelectedCallback}
|
handleToggleDestination={setSelectedCallback}
|
||||||
/> : <ModalContent className={cl("no-results")}>
|
/> : <ModalContent className={cl("no-results")}>
|
||||||
<div className={cl("no-results-container")}>
|
<div className={cl("no-results-container")}>
|
||||||
<svg
|
<svg
|
||||||
width="48"
|
width="48"
|
||||||
height="48"
|
height="48"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M18 6L6 18M6 6L18 18"
|
d="M18 6L6 18M6 6L18 18"
|
||||||
stroke="var(--text-muted)"
|
stroke="var(--text-muted)"
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<Text
|
<Text
|
||||||
variant="text-md/normal"
|
variant="text-md/normal"
|
||||||
style={{ color: "var(--text-muted)", marginLeft: "8px" }}
|
style={{ color: "var(--text-muted)", marginLeft: "8px" }}
|
||||||
>No results found</Text>
|
>No results found</Text>
|
||||||
</div>
|
</div>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
}
|
}
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
|
@ -677,7 +681,7 @@ export default function SearchModal({ modalProps, onSubmit, input, searchType =
|
||||||
look={Button.Looks.LINK}
|
look={Button.Looks.LINK}
|
||||||
onClick={modalProps.onClose}
|
onClick={modalProps.onClose}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue