86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
import * as React from "react";
|
|
import { connect } from "react-redux";
|
|
import { Dispatch } from "redux";
|
|
|
|
import { Button, MenuItem } from "@blueprintjs/core";
|
|
import { IconNames } from "@blueprintjs/icons";
|
|
import { IItemRendererProps, ItemPredicate, Select } from "@blueprintjs/select";
|
|
|
|
import { RouteComponentProps, withRouter } from "react-router";
|
|
import { selectAndLoadInstance } from "../redux/actions";
|
|
import { IAppState, IInstance } from "../redux/types";
|
|
|
|
interface IInstanceSearchProps extends RouteComponentProps {
|
|
currentInstanceName: string | null;
|
|
instances?: IInstance[];
|
|
selectAndLoadInstance: (instanceName: string) => void;
|
|
}
|
|
|
|
const InstanceSelect = Select.ofType<IInstance>();
|
|
|
|
class InstanceSearchImpl extends React.Component<IInstanceSearchProps> {
|
|
public render() {
|
|
return (
|
|
<InstanceSelect
|
|
items={this.props.instances || []}
|
|
itemRenderer={this.itemRenderer}
|
|
onItemSelect={this.onItemSelect}
|
|
itemPredicate={this.itemPredicate}
|
|
disabled={!this.props.instances || this.props.location.pathname !== "/"}
|
|
initialContent={this.renderInitialContent()}
|
|
noResults={this.renderNoResults()}
|
|
popoverProps={{ popoverClassName: "fediverse-instance-search-popover" }}
|
|
>
|
|
<Button
|
|
icon={IconNames.SELECTION}
|
|
rightIcon={IconNames.CARET_DOWN}
|
|
text={this.props.currentInstanceName || "Select an instance"}
|
|
disabled={!this.props.instances}
|
|
/>
|
|
</InstanceSelect>
|
|
);
|
|
}
|
|
|
|
private renderInitialContent = () => {
|
|
return <MenuItem disabled={true} text={"Start typing"} />;
|
|
};
|
|
|
|
private renderNoResults = () => {
|
|
return <MenuItem disabled={true} text={"Keep typing"} />;
|
|
};
|
|
|
|
private itemRenderer = (item: IInstance, itemProps: IItemRendererProps) => {
|
|
if (!itemProps.modifiers.matchesPredicate) {
|
|
return null;
|
|
}
|
|
return (
|
|
<MenuItem text={item.name} key={item.name} active={itemProps.modifiers.active} onClick={itemProps.handleClick} />
|
|
);
|
|
};
|
|
|
|
private itemPredicate: ItemPredicate<IInstance> = (query, item, index) => {
|
|
if (!item.name || query.length < 4) {
|
|
return false;
|
|
}
|
|
return item.name.toLowerCase().indexOf(query.toLowerCase()) >= 0;
|
|
};
|
|
|
|
private onItemSelect = (item: IInstance, event?: React.SyntheticEvent<HTMLElement>) => {
|
|
this.props.selectAndLoadInstance(item.name);
|
|
};
|
|
}
|
|
|
|
const mapStateToProps = (state: IAppState) => ({
|
|
currentInstanceName: state.currentInstance.currentInstanceName,
|
|
instances: state.data.instances
|
|
});
|
|
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
|
selectAndLoadInstance: (instanceName: string) => dispatch(selectAndLoadInstance(instanceName) as any)
|
|
});
|
|
export const InstanceSearch = withRouter(
|
|
connect(
|
|
mapStateToProps,
|
|
mapDispatchToProps
|
|
)(InstanceSearchImpl)
|
|
);
|