diff --git a/src/App.scss b/src/App.scss index d3ec407..d45b6f1 100644 --- a/src/App.scss +++ b/src/App.scss @@ -152,12 +152,15 @@ h1 { backdrop-filter: blur(5px); & > .dialog { - border: solid var(--background-3) 1px; outline: none !important; + animation: dialog 150ms cubic-bezier(.13,.37,.49,1) forwards; + } + + & > .dialog:not(.raw) { + border: solid var(--background-3) 1px; background: var(--background-1); color: inherit; padding: 8px; - animation: dialog 150ms cubic-bezier(.13,.37,.49,1) forwards; } } diff --git a/src/Atoms.tsx b/src/Atoms.tsx index 476ccae..6a18009 100644 --- a/src/Atoms.tsx +++ b/src/Atoms.tsx @@ -285,7 +285,7 @@ export function Dropdown(props: VoidProps<{ selected?: T, required?: boolean, ); } -export function Dialog() { +export function Dialog(props: ParentProps<{ raw?: boolean }>) { const [_globals, action] = useGlobals(); // TODO: close animation @@ -297,10 +297,8 @@ export function Dialog() { return (
- diff --git a/src/Context.tsx b/src/Context.tsx index 8e0ca0a..bcac6dc 100644 --- a/src/Context.tsx +++ b/src/Context.tsx @@ -1,34 +1,38 @@ import { Accessor, ParentProps, Resource, createContext, createEffect, createResource, createSignal, onCleanup, useContext } from "solid-js"; import * as i18n from "i18next"; import { Client, ClientState, Event, Room, Thread } from "sdk"; -import { EventId, UserId } from "sdk/dist/src/api"; +import { EventId, RoomId, UserId } from "sdk/dist/src/api"; import { Store, createStore } from "solid-js/store"; import { createEmitter } from "@solid-primitives/event-bus"; import { useNavigate } from "@solidjs/router"; +import { FileI } from "./Media"; interface Settings { compact: boolean, locale: string, } -interface GlobalState { - dialogs: Array, - sidebar: null | "members" | Thread, - contextMenu: null | any, -} - -interface RoomState { -} +interface RoomState {} interface ThreadState { - // reply: Event, + reply: Event | null, } +type Dialog = { type: "media", file: FileI }; + +type ContextMenu = { x: number, y: number } & ( + { type: "room", room: Room } | + { type: "thread", thread: Thread } | + { type: "message", thread: Thread, event: Event } +); + interface Globals { settings: Settings, - global: GlobalState, - room: RoomState | null, - thread: ThreadState | null, + dialogs: Array, + sidebar: null | "members" | Thread, + contextMenu: null | ContextMenu, + rooms: Record, + threads: Record, locale: i18n.TFunction | null, client: Client, scene: Scene, @@ -54,9 +58,10 @@ type Action = { type: "login", client: Client } | { type: "logout" } | { type: "sidebar.focus", item: Thread | "members" | null } | - { type: "dialog" } | + { type: "dialog.open", dialog: Dialog } | { type: "dialog.close" } | - { type: "contextmenu.set", menu: any } + { type: "input.reply", thread: Thread, event: Event | null } | + { type: "contextmenu.set", menu: ContextMenu | null } const GlobalsContext = createContext<[Store, (change: Action) => void]>(); export const useGlobals = () => useContext(GlobalsContext)!; @@ -77,13 +82,11 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { compact: true, locale: "en", }, - global: { - dialogs: [], - sidebar: null, - contextMenu: null, - }, - room: null, - thread: null, + dialogs: [], + sidebar: null, + contextMenu: null, + rooms: {}, + threads: {}, locale: null, // FIXME: type safety client: props.client as Client, @@ -109,10 +112,10 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { const navigate = useNavigate(); function redux(action: Action) { - // console.log("dispatch action", action); + console.log("dispatch action", action); switch (action.type) { case "sidebar.focus": - update("global", "sidebar", action.item); + update("sidebar", action.item); break; case "login": update("client", action.client); @@ -125,16 +128,24 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { case "logout": globals.client.logout(); break; - case "dialog": { - update("global", "dialogs", [...globals.global.dialogs, null]); + case "dialog.open": { + update("dialogs", [...globals.dialogs, action.dialog]); break; } case "dialog.close": { - update("global", "dialogs", globals.global.dialogs.slice(0, -1)); + update("dialogs", globals.dialogs.slice(0, -1)); + break; + } + case "input.reply": { + if (!globals.threads[action.thread.id]) { + update("threads", action.thread.id, { reply: action.event }); + } else { + update("threads", action.thread.id, "reply", action.event); + } break; } case "contextmenu.set": { - update("global", "contextMenu", action.menu); + update("contextMenu", action.menu); } } } diff --git a/src/Main.tsx b/src/Main.tsx index d8f89e8..a0c5745 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -11,6 +11,7 @@ import * as menu from "./Menu"; import { useFloating } from "solid-floating-ui"; import { ClientRectObject, ReferenceElement, autoPlacement, autoUpdate, shift } from "@floating-ui/dom"; import { ROOM_TYPE_DEFAULT, ROOM_TYPE_SPACE } from "./consts"; +import { File, FileI } from "./Media"; type View = { type: "loading" } | @@ -101,9 +102,6 @@ export default function App(): JSX.Element { globals.client.on("list", updateRooms); onCleanup(() => globals.client.off("list", updateRooms)); - const sidebar = () => globals.global.sidebar; - const contextMenu = () => globals.global.contextMenu; - const willHandleRoomContextMenu = (room: Room) => (e: MouseEvent) => { e.preventDefault(); change({ type: "contextmenu.set", menu: { type: "room", room, x: e.clientX, y: e.clientY } }); @@ -120,7 +118,7 @@ export default function App(): JSX.Element { const [menuParentRef, setMenuParentRef] = createSignal(); const [menuRef, setMenuRef] = createSignal(); const menuFloating = useFloating(menuParentRef, menuRef, { - middleware: [shift()], + middleware: [shift({ mainAxis: true, crossAxis: true, padding: 8 })], placement: "right-start", }); @@ -128,12 +126,12 @@ export default function App(): JSX.Element { setMenuParentRef({ getBoundingClientRect(): ClientRectObject { return { - x: contextMenu().x, - y: contextMenu().y, - left: contextMenu().x, - top: contextMenu().y, - right: contextMenu().x, - bottom: contextMenu().y, + x: globals.contextMenu!.x, + y: globals.contextMenu!.y, + left: globals.contextMenu!.x, + top: globals.contextMenu!.y, + right: globals.contextMenu!.x, + bottom: globals.contextMenu!.y, width: 0, height: 0, }; @@ -185,16 +183,16 @@ export default function App(): JSX.Element { - -