mirror of
https://github.com/BlowaterNostr/blowater.git
synced 2024-10-18 07:33:22 +00:00
experimental global filter (#425)
This commit is contained in:
parent
f9ee637d35
commit
ae537311e9
@ -25,7 +25,7 @@ import { LamportTime } from "../time.ts";
|
||||
import { InstallPrompt, NavBar } from "./nav.tsx";
|
||||
import { Component } from "https://esm.sh/preact@10.17.1";
|
||||
import { SingleRelayConnection } from "../../libs/nostr.ts/relay-single.ts";
|
||||
import { ChannelContainer } from "./channel-container.tsx";
|
||||
import { PublicMessageContainer } from "./public-message-container.tsx";
|
||||
import { ChatMessage } from "./message.ts";
|
||||
import { filter, forever, map } from "./_helper.ts";
|
||||
import { RightPanel } from "./components/right-panel.tsx";
|
||||
@ -342,12 +342,12 @@ export class AppComponent extends Component<AppProps> {
|
||||
}
|
||||
}
|
||||
|
||||
let socialNode: VNode | undefined;
|
||||
let publicNode: VNode | undefined;
|
||||
if (model.navigationModel.activeNav == "Public" && model.currentRelay) {
|
||||
socialNode = (
|
||||
<ChannelContainer
|
||||
publicNode = (
|
||||
<PublicMessageContainer
|
||||
ctx={myAccountCtx}
|
||||
{...model.social}
|
||||
{...model.public}
|
||||
getters={{
|
||||
convoListRetriever: app.conversationLists,
|
||||
newMessageChecker: app.conversationLists,
|
||||
@ -414,7 +414,7 @@ export class AppComponent extends Component<AppProps> {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{socialNode}
|
||||
{publicNode}
|
||||
{dmVNode}
|
||||
{aboutNode}
|
||||
{Setting({
|
||||
|
@ -2,7 +2,7 @@ import { NavigationModel } from "./nav.tsx";
|
||||
import { ProfileData } from "../features/profile.ts";
|
||||
|
||||
import { DM_Model } from "./dm.tsx";
|
||||
import { Social_Model } from "./channel-container.tsx";
|
||||
import { Public_Model } from "./public-message-container.tsx";
|
||||
import { App } from "./app.tsx";
|
||||
import { PublicKey } from "../../libs/nostr.ts/key.ts";
|
||||
import { default_blowater_relay } from "./relay-config.ts";
|
||||
@ -12,7 +12,7 @@ export type Model = {
|
||||
currentRelay: string;
|
||||
dm: DM_Model;
|
||||
|
||||
social: Social_Model;
|
||||
public: Public_Model;
|
||||
|
||||
// profile
|
||||
newProfileField: {
|
||||
@ -31,7 +31,7 @@ export function initialModel(): Model {
|
||||
dm: {
|
||||
currentConversation: undefined,
|
||||
},
|
||||
social: {
|
||||
public: {
|
||||
relaySelectedChannel: new Map(),
|
||||
},
|
||||
newProfileField: {
|
||||
|
@ -49,13 +49,14 @@ import { TagSelected } from "./contact-tags.tsx";
|
||||
import { BlockUser, UnblockUser, UserDetail } from "./user-detail.tsx";
|
||||
import { RelayRecommendList } from "./relay-recommend-list.tsx";
|
||||
import { HidePopOver } from "./components/popover.tsx";
|
||||
import { Social_Model } from "./channel-container.tsx";
|
||||
import { Public_Model } from "./public-message-container.tsx";
|
||||
import { SyncEvent } from "./message-panel.tsx";
|
||||
import { SendingEventRejection, ToastChannel } from "./components/toast.tsx";
|
||||
import { SingleRelayConnection } from "../../libs/nostr.ts/relay-single.ts";
|
||||
import { default_blowater_relay } from "./relay-config.ts";
|
||||
import { forever } from "./_helper.ts";
|
||||
import { func_GetEventByID } from "./message-list.tsx";
|
||||
import { FilterContent } from "./filter.tsx";
|
||||
|
||||
export type UI_Interaction_Event =
|
||||
| SearchUpdate
|
||||
@ -63,7 +64,6 @@ export type UI_Interaction_Event =
|
||||
| EditorEvent
|
||||
| NavigationUpdate
|
||||
| DirectMessagePanelUpdate
|
||||
| BackToChannelList
|
||||
| BackToContactList
|
||||
| SaveProfile
|
||||
| PinConversation
|
||||
@ -78,11 +78,9 @@ export type UI_Interaction_Event =
|
||||
| UnblockUser
|
||||
| SelectRelay
|
||||
| HidePopOver
|
||||
| SyncEvent;
|
||||
| SyncEvent
|
||||
| FilterContent;
|
||||
|
||||
type BackToChannelList = {
|
||||
type: "BackToChannelList";
|
||||
};
|
||||
type BackToContactList = {
|
||||
type: "BackToContactList";
|
||||
};
|
||||
@ -306,15 +304,6 @@ const handle_update_event = async (chan: PutChannel<true>, args: {
|
||||
model.navigationModel.activeNav = event.id;
|
||||
} //
|
||||
//
|
||||
// Channel
|
||||
//
|
||||
else if (event.type == "SelectChannel") {
|
||||
model.social.relaySelectedChannel.set(model.currentRelay, event.channel);
|
||||
app.popOverInputChan.put({ children: undefined });
|
||||
} else if (event.type == "BackToChannelList") {
|
||||
model.social.relaySelectedChannel.delete(model.currentRelay);
|
||||
app.popOverInputChan.put({ children: undefined });
|
||||
} //
|
||||
// DM
|
||||
//
|
||||
else if (event.type == "ViewUserDetail") {
|
||||
@ -559,7 +548,7 @@ export async function handle_SendMessage(
|
||||
db: Database_View,
|
||||
args: {
|
||||
navigationModel: NavigationModel;
|
||||
social: Social_Model;
|
||||
public: Public_Model;
|
||||
dm: {
|
||||
currentConversation: PublicKey | undefined;
|
||||
};
|
||||
|
@ -1,14 +0,0 @@
|
||||
import { h, render } from "https://esm.sh/preact@10.17.1";
|
||||
import { ChannelList } from "./channel-list.tsx";
|
||||
import { testEventBus } from "./_setup.test.ts";
|
||||
|
||||
render(
|
||||
<ChannelList
|
||||
emit={testEventBus.emit}
|
||||
relay="test"
|
||||
currentSelected="test"
|
||||
channels={["general", "games", "work"]}
|
||||
>
|
||||
</ChannelList>,
|
||||
document.body,
|
||||
);
|
@ -1,49 +0,0 @@
|
||||
import { Component, h } from "https://esm.sh/preact@10.17.1";
|
||||
import { SelectChannel } from "./search_model.ts";
|
||||
import { emitFunc } from "../event-bus.ts";
|
||||
|
||||
type ChannelListProps = {
|
||||
relay: string;
|
||||
currentSelected: string | undefined;
|
||||
emit: emitFunc<SelectChannel>;
|
||||
channels: string[];
|
||||
};
|
||||
|
||||
export class ChannelList extends Component<ChannelListProps> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.channels.map((c) =>
|
||||
this.ChannelListItem(this.props, c, c == this.props.currentSelected)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChannelListItem(props: ChannelListProps, name: string, isSelected: boolean) {
|
||||
const selected = isSelected ? " bg-[#404248] text-[#fff]" : "";
|
||||
return (
|
||||
<div
|
||||
class={`m-2 p-1
|
||||
rounded
|
||||
text-[#959BA3]
|
||||
hover:text-[#fff]
|
||||
hover:bg-[#36373C]
|
||||
hover:cursor-pointer` + selected}
|
||||
onClick={selectChannel(
|
||||
props.emit,
|
||||
name,
|
||||
)}
|
||||
>
|
||||
# {name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const selectChannel = (emit: emitFunc<SelectChannel>, channel: string) => () => {
|
||||
return emit({
|
||||
type: "SelectChannel",
|
||||
channel,
|
||||
});
|
||||
};
|
4
app/UI/filter.test.tsx
Normal file
4
app/UI/filter.test.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
import { h, render } from "https://esm.sh/preact@10.17.1";
|
||||
import { Filter } from "./filter.tsx";
|
||||
|
||||
render(<Filter></Filter>, document.body);
|
32
app/UI/filter.tsx
Normal file
32
app/UI/filter.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { Component, h } from "https://esm.sh/preact@10.17.1";
|
||||
import { emitFunc } from "../event-bus.ts";
|
||||
|
||||
type Props = {
|
||||
emit: emitFunc<FilterContent>;
|
||||
};
|
||||
|
||||
export class Filter extends Component<Props, {}> {
|
||||
render() {
|
||||
return (
|
||||
<div class="border flex flex-col items-center">
|
||||
<div class="flex flex-row border">
|
||||
<input
|
||||
placeholder={"search content"}
|
||||
onInput={(e) => {
|
||||
this.props.emit({
|
||||
type: "FilterContent",
|
||||
content: e.currentTarget.value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export type FilterContent = {
|
||||
type: "FilterContent";
|
||||
content: string;
|
||||
};
|
@ -51,6 +51,13 @@ export class MessageList extends Component<MessageListProps, MessageListState> {
|
||||
|
||||
jitter = new JitterPrevention(100);
|
||||
|
||||
async componentWillReceiveProps(nextPrpos: MessageListProps) {
|
||||
if (nextPrpos.messages.length != this.props.messages.length) {
|
||||
await setState(this, { offset: 0 });
|
||||
await this.goToLastPage();
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidUpdate(previousProps: Readonly<MessageListProps>) {
|
||||
const newest = last(this.props.messages);
|
||||
const pre_newest = last(previousProps.messages);
|
||||
@ -69,6 +76,7 @@ export class MessageList extends Component<MessageListProps, MessageListState> {
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log(this.state.offset, this.props.messages.length);
|
||||
const messages_to_render = this.sortAndSliceMessage();
|
||||
const groups = groupContinuousMessages(messages_to_render, (pre, cur) => {
|
||||
const sameAuthor = pre.event.pubkey == cur.event.pubkey;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { fail } from "https://deno.land/std@0.176.0/testing/asserts.ts";
|
||||
import { h, render } from "https://esm.sh/preact@10.17.1";
|
||||
import { ChannelContainer } from "./channel-container.tsx";
|
||||
import { PublicMessageContainer } from "./public-message-container.tsx";
|
||||
import { relays } from "../../libs/nostr.ts/relay-list.test.ts";
|
||||
import { ConnectionPool } from "../../libs/nostr.ts/relay-pool.ts";
|
||||
import { testEventBus } from "./_setup.test.ts";
|
||||
@ -41,7 +41,7 @@ dm_list.addEvents([e], true);
|
||||
dm_list.addEvents(Array.from(database.getAllEvents()), true);
|
||||
|
||||
render(
|
||||
<ChannelContainer
|
||||
<PublicMessageContainer
|
||||
ctx={ctx}
|
||||
relay={relay}
|
||||
bus={testEventBus}
|
@ -1,7 +1,6 @@
|
||||
import { Component, h } from "https://esm.sh/preact@10.17.1";
|
||||
import { ChannelList } from "./channel-list.tsx";
|
||||
import { SingleRelayConnection } from "../../libs/nostr.ts/relay-single.ts";
|
||||
import { EventBus } from "../event-bus.ts";
|
||||
import { emitFunc, EventBus } from "../event-bus.ts";
|
||||
import { UI_Interaction_Event } from "./app_update.tsx";
|
||||
import { setState } from "./_helper.ts";
|
||||
import { ProfileGetter } from "./search.tsx";
|
||||
@ -11,20 +10,19 @@ import { NewMessageChecker } from "./conversation-list.tsx";
|
||||
import { ConversationListRetriever } from "./conversation-list.tsx";
|
||||
import { NostrAccountContext } from "../../libs/nostr.ts/nostr.ts";
|
||||
|
||||
import { IconButtonClass } from "./components/tw.ts";
|
||||
import { LeftArrowIcon } from "./icons/left-arrow-icon.tsx";
|
||||
import { MessagePanel } from "./message-panel.tsx";
|
||||
import { PublicKey } from "../../libs/nostr.ts/key.ts";
|
||||
import { ChatMessage } from "./message.ts";
|
||||
import { func_GetEventByID } from "./message-list.tsx";
|
||||
import { Filter, FilterContent } from "./filter.tsx";
|
||||
|
||||
export type Social_Model = {
|
||||
export type Public_Model = {
|
||||
relaySelectedChannel: Map<string, /* relay url */ string /* channel name */>;
|
||||
};
|
||||
|
||||
export type func_IsUserBlocked = (pubkey: PublicKey) => boolean;
|
||||
|
||||
type ChannelContainerProps = {
|
||||
type Props = {
|
||||
ctx: NostrAccountContext;
|
||||
relay: SingleRelayConnection;
|
||||
bus: EventBus<UI_Interaction_Event>;
|
||||
@ -37,78 +35,64 @@ type ChannelContainerProps = {
|
||||
isUserBlocked: func_IsUserBlocked;
|
||||
getEventByID: func_GetEventByID;
|
||||
};
|
||||
} & Social_Model;
|
||||
} & Public_Model;
|
||||
|
||||
type ChannelContainerState = {
|
||||
type State = {
|
||||
currentSelectedChannel: string /*channel name*/ | undefined;
|
||||
currentEditor: {
|
||||
text: string;
|
||||
};
|
||||
filter: FilterContent | undefined;
|
||||
};
|
||||
|
||||
export class ChannelContainer extends Component<ChannelContainerProps, ChannelContainerState> {
|
||||
state: ChannelContainerState = {
|
||||
export class PublicMessageContainer extends Component<Props, State> {
|
||||
state: State = {
|
||||
currentSelectedChannel: "general",
|
||||
currentEditor: {
|
||||
text: "",
|
||||
},
|
||||
filter: undefined,
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
for await (const e of this.props.bus.onChange()) {
|
||||
if (e.type == "SelectChannel") {
|
||||
if (e.type == "FilterContent") {
|
||||
await setState(this, {
|
||||
currentSelectedChannel: e.channel,
|
||||
filter: e,
|
||||
});
|
||||
} else if (e.type == "SelectRelay") {
|
||||
await setState(this, {
|
||||
currentSelectedChannel: "general", // this.props.relaySelectedChannel.get(e.relay.url),
|
||||
});
|
||||
} else if (e.type == "BackToChannelList") {
|
||||
// await setState(this, {
|
||||
// currentSelectedChannel: undefined,
|
||||
// });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render(props: ChannelContainerProps, state: ChannelContainerState) {
|
||||
render(props: Props, state: State) {
|
||||
let msgs = props.messages;
|
||||
const filter = this.state.filter;
|
||||
if (filter) {
|
||||
msgs = this.props.messages.filter((msg) => {
|
||||
if (filter.content == "") {
|
||||
return true;
|
||||
}
|
||||
return msg.content.toLowerCase().includes(filter.content.toLowerCase());
|
||||
});
|
||||
}
|
||||
return (
|
||||
<div class="flex flex-row h-full w-full flex bg-[#36393F] overflow-hidden">
|
||||
{
|
||||
/* <div
|
||||
class={`h-screen w-60 max-sm:w-full
|
||||
flex flex-col bg-[${SecondaryBackgroundColor}] `}
|
||||
>
|
||||
<div
|
||||
class={`flex items-center w-full h-20 font-bold text-xl text-[${PrimaryTextColor}] m-1 p-3 border-b border-[#36393F]`}
|
||||
>
|
||||
{new URL(props.relay.url).host}
|
||||
</div>
|
||||
<ChannelList
|
||||
relay={props.relay.url}
|
||||
currentSelected={state.currentSelectedChannel}
|
||||
channels={["general", "games", "work"]}
|
||||
emit={props.bus.emit}
|
||||
/>
|
||||
</div> */
|
||||
}
|
||||
{this.state.currentSelectedChannel
|
||||
? (
|
||||
<div class={`flex flex-col flex-1 overflow-hidden`}>
|
||||
<TopBar
|
||||
bus={props.bus}
|
||||
currentSelected={state.currentSelectedChannel}
|
||||
profileGetter={props.getters.profileGetter}
|
||||
emit={props.bus.emit}
|
||||
/>
|
||||
<div class={`flex-1 overflow-auto`}>
|
||||
{
|
||||
<MessagePanel
|
||||
key={props.relay.url}
|
||||
myPublicKey={props.ctx.publicKey}
|
||||
emit={props.bus.emit}
|
||||
eventSub={props.bus}
|
||||
getters={props.getters}
|
||||
messages={props.messages}
|
||||
messages={msgs}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
@ -121,9 +105,8 @@ export class ChannelContainer extends Component<ChannelContainerProps, ChannelCo
|
||||
}
|
||||
|
||||
function TopBar(props: {
|
||||
bus: EventBus<UI_Interaction_Event>;
|
||||
currentSelected: string | undefined;
|
||||
profileGetter: ProfileGetter;
|
||||
emit: emitFunc<FilterContent>;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
@ -131,24 +114,15 @@ function TopBar(props: {
|
||||
items-center justify-between bg-[#2F3136]`}
|
||||
>
|
||||
<div class={`flex items-center overflow-hidden`}>
|
||||
{
|
||||
/* <button
|
||||
class={`w-6 h-6 mx-2 ${IconButtonClass}`}
|
||||
>
|
||||
<LeftArrowIcon
|
||||
class={`w-4 h-4`}
|
||||
style={{
|
||||
fill: "rgb(185, 187, 190)",
|
||||
}}
|
||||
/>
|
||||
</button> */
|
||||
}
|
||||
<span
|
||||
class={`text-[#F3F4EA] text-[1.2rem] mx-4
|
||||
whitespace-nowrap truncate`}
|
||||
>
|
||||
{props.currentSelected}
|
||||
</span>
|
||||
<div>
|
||||
<Filter {...props}></Filter>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
@ -1,6 +1,6 @@
|
||||
import { PublicKey } from "../../libs/nostr.ts/key.ts";
|
||||
|
||||
export type SearchUpdate = SelectChannel | SelectConversation | StartSearch;
|
||||
export type SearchUpdate = SelectConversation | StartSearch;
|
||||
export type StartSearch = {
|
||||
type: "StartSearch";
|
||||
};
|
||||
@ -8,7 +8,3 @@ export type SelectConversation = {
|
||||
type: "SelectConversation";
|
||||
pubkey: PublicKey;
|
||||
};
|
||||
export type SelectChannel = {
|
||||
type: "SelectChannel";
|
||||
channel: string;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user