From 7a80c0edb54c54bf34ab088a2b9e76569a96d27f Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 9 Aug 2021 17:34:25 +0100 Subject: [PATCH] Add search back. --- src/components/common/messaging/Message.tsx | 33 ++-- src/components/navigation/RightSidebar.tsx | 22 +++ .../navigation/right/MemberSidebar.tsx | 8 +- src/components/navigation/right/Search.note | 80 --------- src/components/navigation/right/Search.tsx | 164 ++++++++++++++++-- src/lib/eventEmitter.ts | 1 + src/pages/channels/actions/HeaderActions.tsx | 25 ++- 7 files changed, 219 insertions(+), 114 deletions(-) delete mode 100644 src/components/navigation/right/Search.note diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx index e3540bcd..e17cc8b0 100644 --- a/src/components/common/messaging/Message.tsx +++ b/src/components/common/messaging/Message.tsx @@ -33,6 +33,7 @@ interface Props { contrast?: boolean; content?: Children; head?: boolean; + hideReply?: boolean; } const Message = observer( @@ -44,6 +45,7 @@ const Message = observer( content: replacement, head: preferHead, queued, + hideReply, }: Props) => { const client = useClient(); const user = message.author; @@ -72,23 +74,26 @@ const Message = observer( return (
- {message.reply_ids?.map((message_id, index) => ( - - ))} + {!hideReply && + message.reply_ids?.map((message_id, index) => ( + + ))} 0 - )) ?? - false + hideReply + ? false + : (head && + !( + message.reply_ids && + message.reply_ids.length > 0 + )) ?? + false } contrast={contrast} sending={typeof queued !== "undefined"} diff --git a/src/components/navigation/RightSidebar.tsx b/src/components/navigation/RightSidebar.tsx index edfac4db..46d938d6 100644 --- a/src/components/navigation/RightSidebar.tsx +++ b/src/components/navigation/RightSidebar.tsx @@ -1,9 +1,31 @@ import { Route, Switch } from "react-router"; +import { useEffect, useState } from "preact/hooks"; + +import { internalSubscribe } from "../../lib/eventEmitter"; + import SidebarBase from "./SidebarBase"; import MemberSidebar from "./right/MemberSidebar"; +import { SearchSidebar } from "./right/Search"; export default function RightSidebar() { + const [sidebar, setSidebar] = useState<"search" | undefined>(); + const close = () => setSidebar(undefined); + + useEffect( + () => + internalSubscribe( + "RightSidebar", + "open", + setSidebar as (...args: unknown[]) => void, + ), + [setSidebar], + ); + + if (sidebar === "search") { + return ; + } + return ( diff --git a/src/components/navigation/right/MemberSidebar.tsx b/src/components/navigation/right/MemberSidebar.tsx index 37cc085a..4e8bb83e 100644 --- a/src/components/navigation/right/MemberSidebar.tsx +++ b/src/components/navigation/right/MemberSidebar.tsx @@ -16,10 +16,10 @@ import { import { GenericSidebarBase } from "../SidebarBase"; import MemberList, { MemberListGroup } from "./MemberList"; -export default function MemberSidebar({ channel: obj }: { channel?: Channel }) { - const { channel: channel_id } = useParams<{ channel: string }>(); - const client = useClient(); - const channel = obj ?? client.channels.get(channel_id); +export default function MemberSidebar() { + const channel = useClient().channels.get( + useParams<{ channel: string }>().channel, + ); switch (channel?.channel_type) { case "Group": diff --git a/src/components/navigation/right/Search.note b/src/components/navigation/right/Search.note deleted file mode 100644 index 0e467399..00000000 --- a/src/components/navigation/right/Search.note +++ /dev/null @@ -1,80 +0,0 @@ -// this is the search code - -function Search({ channel }: { channel: Channel }) { - if (!getState().experiments.enabled?.includes("search")) return null; - - type Sort = "Relevance" | "Latest" | "Oldest"; - const [sort, setSort] = useState("Relevance"); - - const [query, setV] = useState(""); - const [results, setResults] = useState([]); - - async function search() { - const data = await channel.searchWithUsers({ query, sort }); - setResults(data.messages); - } - - return ( - - (BETA) - - }> -
- {["Relevance", "Latest", "Oldest"].map((key) => ( - - ))} -
- e.key === "Enter" && search()} - value={query} - onChange={(e) => setV(e.currentTarget.value)} - /> -
- {results.map((message) => { - let href = ""; - if (channel?.channel_type === "TextChannel") { - href += `/server/${channel.server_id}`; - } - - href += `/channel/${message.channel_id}/${message._id}`; - - return ( - -
- @{message.author?.username} -
- {message.content} -
- - ); - })} -
-
- ); -} diff --git a/src/components/navigation/right/Search.tsx b/src/components/navigation/right/Search.tsx index f8023f16..388f424c 100644 --- a/src/components/navigation/right/Search.tsx +++ b/src/components/navigation/right/Search.tsx @@ -1,12 +1,154 @@ -/*export const SearchSidebar = observer( - ({ channel }: { channel: Channel }) => { - const keys = [...channel.recipient_ids!]; - const entries = useEntries(channel, keys); +import { Link, useParams } from "react-router-dom"; +import { Message as MessageI } from "revolt.js/dist/maps/Messages"; +import styled from "styled-components"; - return ( - - - - ); - }, -);*/ +import { Text } from "preact-i18n"; +import { useEffect, useState } from "preact/hooks"; + +import { useClient } from "../../../context/revoltjs/RevoltClient"; + +import Message from "../../common/messaging/Message"; +import Button from "../../ui/Button"; +import InputBox from "../../ui/InputBox"; +import Overline from "../../ui/Overline"; +import Preloader from "../../ui/Preloader"; + +import { GenericSidebarBase } from "../SidebarBase"; + +type SearchState = + | { + type: "waiting"; + } + | { + type: "loading"; + } + | { + type: "results"; + results: MessageI[]; + }; + +const SearchBase = styled.div` + padding: 6px; + + input { + width: 100%; + } + + .list { + gap: 4px; + margin: 8px 0; + display: flex; + flex-direction: column; + } + + .message { + margin: 2px; + padding: 6px; + overflow: hidden; + border-radius: var(--border-radius); + background: var(--primary-background); + + &:hover { + background: var(--hover); + } + + > * { + pointer-events: none; + } + } + + .sort { + gap: 4px; + margin: 6px 0; + display: flex; + + > * { + flex: 1; + min-width: 0; + } + } +`; + +interface Props { + close: () => void; +} + +export function SearchSidebar({ close }: Props) { + const channel = useClient().channels.get( + useParams<{ channel: string }>().channel, + )!; + + type Sort = "Relevance" | "Latest" | "Oldest"; + const [sort, setSort] = useState("Latest"); + const [query, setQuery] = useState(""); + + const [state, setState] = useState({ type: "waiting" }); + + async function search() { + if (!query) return; + setState({ type: "loading" }); + const data = await channel.searchWithUsers({ query, sort }); + setState({ type: "results", results: data.messages }); + } + + useEffect(() => { + search(); + // eslint-disable-next-line + }, [sort]); + + return ( + + + + go back to members + + + + + e.key === "Enter" && search()} + onChange={(e) => setQuery(e.currentTarget.value)} + /> +
+ {["Latest", "Oldest", "Relevance"].map((key) => ( + + ))} +
+ {state.type === "loading" && } + {state.type === "results" && ( +
+ {state.results.map((message) => { + let href = ""; + if (channel?.channel_type === "TextChannel") { + href += `/server/${channel.server_id}`; + } + + href += `/channel/${message.channel_id}/${message._id}`; + + return ( + +
+ +
+ + ); + })} +
+ )} +
+
+ ); +} diff --git a/src/lib/eventEmitter.ts b/src/lib/eventEmitter.ts index cdb6c3a2..51227f27 100644 --- a/src/lib/eventEmitter.ts +++ b/src/lib/eventEmitter.ts @@ -18,6 +18,7 @@ export function internalEmit(ns: string, event: string, ...args: unknown[]) { // Event structure: namespace/event /// Event List +// - RightSidebar/open // - MessageArea/jump_to_bottom // - MessageRenderer/edit_last // - MessageRenderer/edit_message diff --git a/src/pages/channels/actions/HeaderActions.tsx b/src/pages/channels/actions/HeaderActions.tsx index 3a9bb1ab..ef3ba03c 100644 --- a/src/pages/channels/actions/HeaderActions.tsx +++ b/src/pages/channels/actions/HeaderActions.tsx @@ -1,4 +1,5 @@ /* eslint-disable react-hooks/rules-of-hooks */ +import { Search } from "@styled-icons/boxicons-regular"; import { UserPlus, Cog, @@ -8,6 +9,7 @@ import { } from "@styled-icons/boxicons-solid"; import { useHistory } from "react-router-dom"; +import { internalEmit } from "../../../lib/eventEmitter"; import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; import { voiceState, VoiceStatus } from "../../../lib/vortex/VoiceState"; @@ -25,13 +27,17 @@ export default function HeaderActions({ const { openScreen } = useIntermediate(); const history = useHistory(); + function openRightSidebar() { + const panels = document.querySelector("#app > div > div"); + panels?.scrollTo({ + behavior: "smooth", + left: panels.clientWidth * 3, + }); + } + function openSidebar() { if (isTouchscreenDevice) { - const panels = document.querySelector("#app > div > div"); - panels?.scrollTo({ - behavior: "smooth", - left: panels.clientWidth * 3, - }); + openRightSidebar(); } else { toggleSidebar?.(); } @@ -65,6 +71,15 @@ export default function HeaderActions({ )} + {channel.channel_type !== "VoiceChannel" && ( + { + internalEmit("RightSidebar", "open", "search"); + openRightSidebar(); + }}> + + + )} {(channel.channel_type === "Group" || channel.channel_type === "TextChannel") && (