mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-10 01:03:36 -05:00
Feature: Add message links.
This commit is contained in:
parent
4474d2ec56
commit
c54fe0f1bf
8 changed files with 78 additions and 27 deletions
2
external/lang
vendored
2
external/lang
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit b18d44b56037d09bd2fac68be04e42723e50a3d7
|
Subproject commit 846a0e8a3a36e606d4d4249e495dc0daeee9c65d
|
|
@ -94,7 +94,7 @@
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scroll": "^1.8.2",
|
"react-scroll": "^1.8.2",
|
||||||
"redux": "^4.1.0",
|
"redux": "^4.1.0",
|
||||||
"revolt.js": "4.3.3-alpha.10",
|
"revolt.js": "4.3.3-alpha.11",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
"shade-blend-color": "^1.0.0",
|
"shade-blend-color": "^1.0.0",
|
||||||
|
|
|
@ -72,11 +72,11 @@ export class SingletonRenderer extends EventEmitter3 {
|
||||||
this.stale = true;
|
this.stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(id: string) {
|
async init(id: string, message_id?: string) {
|
||||||
this.channel = id;
|
this.channel = id;
|
||||||
this.stale = false;
|
this.stale = false;
|
||||||
this.setStateUnguarded({ type: "LOADING" });
|
this.setStateUnguarded({ type: "LOADING" });
|
||||||
await this.currentRenderer.init(this, id);
|
await this.currentRenderer.init(this, id, message_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async reloadStale(id: string) {
|
async reloadStale(id: string) {
|
||||||
|
@ -180,7 +180,7 @@ export class SingletonRenderer extends EventEmitter3 {
|
||||||
if (this.state.type === "RENDER" && this.state.atBottom) {
|
if (this.state.type === "RENDER" && this.state.atBottom) {
|
||||||
this.emit("scroll", { type: "ScrollToBottom", smooth });
|
this.emit("scroll", { type: "ScrollToBottom", smooth });
|
||||||
} else {
|
} else {
|
||||||
await this.currentRenderer.init(this, id, true);
|
await this.currentRenderer.init(this, id, undefined, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,26 @@ import { SMOOTH_SCROLL_ON_RECEIVE } from "../Singleton";
|
||||||
import { RendererRoutines } from "../types";
|
import { RendererRoutines } from "../types";
|
||||||
|
|
||||||
export const SimpleRenderer: RendererRoutines = {
|
export const SimpleRenderer: RendererRoutines = {
|
||||||
init: async (renderer, id, smooth) => {
|
init: async (renderer, id, nearby, smooth) => {
|
||||||
if (renderer.client!.websocket.connected) {
|
if (renderer.client!.websocket.connected) {
|
||||||
|
if (nearby)
|
||||||
|
renderer
|
||||||
|
.client!.channels.fetchMessagesWithUsers(id, { nearby, limit: 100 }, true)
|
||||||
|
.then(({ messages: data }) => {
|
||||||
|
data.sort((a, b) => a._id.localeCompare(b._id));
|
||||||
|
let messages = data.map((x) => mapMessage(x));
|
||||||
|
renderer.setState(
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
type: "RENDER",
|
||||||
|
messages,
|
||||||
|
atTop: false,
|
||||||
|
atBottom: false,
|
||||||
|
},
|
||||||
|
{ type: "ScrollToView", id: nearby },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
else
|
||||||
renderer
|
renderer
|
||||||
.client!.channels.fetchMessagesWithUsers(id, {}, true)
|
.client!.channels.fetchMessagesWithUsers(id, {}, true)
|
||||||
.then(({ messages: data }) => {
|
.then(({ messages: data }) => {
|
||||||
|
|
|
@ -8,6 +8,7 @@ export type ScrollState =
|
||||||
| { type: "Free" }
|
| { type: "Free" }
|
||||||
| { type: "Bottom"; scrollingUntil?: number }
|
| { type: "Bottom"; scrollingUntil?: number }
|
||||||
| { type: "ScrollToBottom" | "StayAtBottom"; smooth?: boolean }
|
| { type: "ScrollToBottom" | "StayAtBottom"; smooth?: boolean }
|
||||||
|
| { type: "ScrollToView", id: string }
|
||||||
| { type: "OffsetTop"; previousHeight: number }
|
| { type: "OffsetTop"; previousHeight: number }
|
||||||
| { type: "ScrollTop"; y: number };
|
| { type: "ScrollTop"; y: number };
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ export interface RendererRoutines {
|
||||||
init: (
|
init: (
|
||||||
renderer: SingletonRenderer,
|
renderer: SingletonRenderer,
|
||||||
id: string,
|
id: string,
|
||||||
|
message?: string,
|
||||||
smooth?: boolean,
|
smooth?: boolean,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,14 @@ export default function App() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/channel/:channel/message/:message"
|
path="/channel/:channel/:message"
|
||||||
component={Channel}
|
component={Channel}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/server/:server/channel/:channel/:message"
|
||||||
|
component={Channel}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/server/:server/channel/:channel"
|
path="/server/:server/channel/:channel"
|
||||||
component={Channel}
|
component={Channel}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { RenderState, ScrollState } from "../../../lib/renderer/types";
|
||||||
import { IntermediateContext } from "../../../context/intermediate/Intermediate";
|
import { IntermediateContext } from "../../../context/intermediate/Intermediate";
|
||||||
import RequiresOnline from "../../../context/revoltjs/RequiresOnline";
|
import RequiresOnline from "../../../context/revoltjs/RequiresOnline";
|
||||||
import {
|
import {
|
||||||
|
AppContext,
|
||||||
ClientStatus,
|
ClientStatus,
|
||||||
StatusContext,
|
StatusContext,
|
||||||
} from "../../../context/revoltjs/RevoltClient";
|
} from "../../../context/revoltjs/RevoltClient";
|
||||||
|
@ -27,6 +28,7 @@ import Preloader from "../../../components/ui/Preloader";
|
||||||
|
|
||||||
import ConversationStart from "./ConversationStart";
|
import ConversationStart from "./ConversationStart";
|
||||||
import MessageRenderer from "./MessageRenderer";
|
import MessageRenderer from "./MessageRenderer";
|
||||||
|
import { useHistory, useParams } from "react-router-dom";
|
||||||
|
|
||||||
const Area = styled.div`
|
const Area = styled.div`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -53,9 +55,13 @@ export const MessageAreaWidthContext = createContext(0);
|
||||||
export const MESSAGE_AREA_PADDING = 82;
|
export const MESSAGE_AREA_PADDING = 82;
|
||||||
|
|
||||||
export function MessageArea({ id }: Props) {
|
export function MessageArea({ id }: Props) {
|
||||||
|
const history = useHistory();
|
||||||
|
const client = useContext(AppContext);
|
||||||
const status = useContext(StatusContext);
|
const status = useContext(StatusContext);
|
||||||
const { focusTaken } = useContext(IntermediateContext);
|
const { focusTaken } = useContext(IntermediateContext);
|
||||||
|
|
||||||
|
const { message } = useParams<{ message: string }>();
|
||||||
|
|
||||||
// ? This is the scroll container.
|
// ? This is the scroll container.
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const { width, height } = useResizeObserver<HTMLDivElement>({ ref });
|
const { width, height } = useResizeObserver<HTMLDivElement>({ ref });
|
||||||
|
@ -91,6 +97,11 @@ export function MessageArea({ id }: Props) {
|
||||||
container: ref.current,
|
container: ref.current,
|
||||||
duration: scrollState.current.smooth ? 150 : 0,
|
duration: scrollState.current.smooth ? 150 : 0,
|
||||||
});
|
});
|
||||||
|
} else if (scrollState.current.type === "ScrollToView") {
|
||||||
|
document.getElementById(scrollState.current.id)
|
||||||
|
?.scrollIntoView();
|
||||||
|
|
||||||
|
setScrollState({ type: "Free" });
|
||||||
} else if (scrollState.current.type === "OffsetTop") {
|
} else if (scrollState.current.type === "OffsetTop") {
|
||||||
animateScroll.scrollTo(
|
animateScroll.scrollTo(
|
||||||
Math.max(
|
Math.max(
|
||||||
|
@ -152,9 +163,24 @@ export function MessageArea({ id }: Props) {
|
||||||
|
|
||||||
// ? Load channel initially.
|
// ? Load channel initially.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (message) return;
|
||||||
SingletonMessageRenderer.init(id);
|
SingletonMessageRenderer.init(id);
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
|
// ? If message present or changes, load it as well.
|
||||||
|
useEffect(() => {
|
||||||
|
if (message) {
|
||||||
|
SingletonMessageRenderer.init(id, message);
|
||||||
|
|
||||||
|
let channel = client.channels.get(id);
|
||||||
|
if (channel?.channel_type === 'TextChannel') {
|
||||||
|
history.push(`/server/${channel.server}/channel/${id}`);
|
||||||
|
} else {
|
||||||
|
history.push(`/channel/${id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [message]);
|
||||||
|
|
||||||
// ? If we are waiting for network, try again.
|
// ? If we are waiting for network, try again.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
|
|
@ -3563,10 +3563,10 @@ reusify@^1.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||||
|
|
||||||
revolt.js@4.3.3-alpha.10:
|
revolt.js@4.3.3-alpha.11:
|
||||||
version "4.3.3-alpha.10"
|
version "4.3.3-alpha.11"
|
||||||
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.10.tgz#3acbdd4f44c7f12be53faa0318396ce21694acde"
|
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.11.tgz#d8499607cc3de48ab580c7da9bf2e8e0a1992ae9"
|
||||||
integrity sha512-s9VEJX1LBiHCl8mXyqD0+GnIQg6WJj7CV8vUAO6Rv35Jwy0gOjjOvma4csXeZTdiLpPoVFxutgBj8bXMnVL5Aw==
|
integrity sha512-//UB+VXKE4MziUoBm2RMDZNgxLmrar8FQ1hCewkdFbTdfkYey6joagNVF5DW+ImbffYbrnnjZhlJP7RRXZ5IeQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@insertish/mutable" "1.1.0"
|
"@insertish/mutable" "1.1.0"
|
||||||
axios "^0.19.2"
|
axios "^0.19.2"
|
||||||
|
|
Loading…
Reference in a new issue