diff --git a/package.json b/package.json index dd24c28..7debc77 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "@popperjs/core": "^2.11.8", "@solid-primitives/event-bus": "^1.0.8", "@solid-primitives/scheduled": "^1.4.1", - "@solidjs/router": "^0.10.2", "@tanstack/solid-virtual": "^3.0.1", "fuzzysort": "^2.0.4", "i18next": "^23.7.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82829d1..1f34ef9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,6 @@ dependencies: '@solid-primitives/scheduled': specifier: ^1.4.1 version: 1.4.1(solid-js@1.8.7) - '@solidjs/router': - specifier: ^0.10.2 - version: 0.10.2(solid-js@1.8.7) '@tanstack/solid-virtual': specifier: ^3.0.1 version: 3.0.1(solid-js@1.8.7) @@ -809,14 +806,6 @@ packages: solid-js: 1.8.7 dev: false - /@solidjs/router@0.10.2(solid-js@1.8.7): - resolution: {integrity: sha512-Yp4G9/+oNRTcTQ2snoxsVzo7HZqSm4L5GdaZDIfg24N7wMoRfanQ8aG5DcwEyA5YqFfOF8mjMW3iOCTaafmqdw==} - peerDependencies: - solid-js: ^1.8.6 - dependencies: - solid-js: 1.8.7 - dev: false - /@tanstack/solid-virtual@3.0.1(solid-js@1.8.7): resolution: {integrity: sha512-DxP3GUBEDUNdCH50Q2RgRkaol3bAGpkMcJAdUIPWywEL37TkH/MC748nees0EXRylrC7RMP0zVNN3Z94WFBULA==} peerDependencies: diff --git a/src/App.scss b/src/App.scss index d45b6f1..15ffa1c 100644 --- a/src/App.scss +++ b/src/App.scss @@ -147,13 +147,13 @@ h1 { display: grid; place-items: center; - animation: backdrop .1s forwards; + // animation: backdrop .1s forwards; background: #4444; backdrop-filter: blur(5px); & > .dialog { outline: none !important; - animation: dialog 150ms cubic-bezier(.13,.37,.49,1) forwards; + // animation: dialog 150ms cubic-bezier(.13,.37,.49,1) forwards; } & > .dialog:not(.raw) { diff --git a/src/App.tsx b/src/App.tsx index 46d073b..d54c9f0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,7 @@ -import { lazy, onCleanup } from "solid-js"; +import { Match, Switch, lazy, onCleanup } from "solid-js"; import "./App.scss"; import { Client } from "sdk"; -import { Contextualizer } from "./Context"; -import { HashRouter, Route, Navigate } from "@solidjs/router"; +import { Contextualizer, useGlobals } from "./Context"; const Auth = lazy(() => import("./Auth")); const Main = lazy(() => import("./Main")); @@ -22,25 +21,29 @@ function Wrapper() { const isLoggedOut = () => !client || client.state.state === "logout"; return ( - {props.children}}> - } /> - - - - - - - - - + + + ); } +function Wrap() { + const [globals] = useGlobals(); + return ( + + } /> + } /> + } /> + } /> + + ) +} + function NotFound() { return (
oh no -

This page doesn't exist! Would you like to return to home?

+

This page doesn't exist! Would you like to return to home?

) } diff --git a/src/Auth.tsx b/src/Auth.tsx index a9452af..6932357 100644 --- a/src/Auth.tsx +++ b/src/Auth.tsx @@ -1,4 +1,3 @@ -import { useLocation, A, useNavigate } from "@solidjs/router"; import "./Auth.scss"; import { createForm, required } from "@modular-forms/solid"; import { UserId } from "sdk/dist/src/api"; @@ -6,10 +5,9 @@ import { Client, Setup } from "sdk"; import { useGlobals } from "./Context"; export default function Auth() { - const location = useLocation(); - const navigate = useNavigate(); - const [globals] = useGlobals(); - if (globals.client && globals.client.state.state !== "logout") navigate("/home"); + const location = { pathname: "/login" }; + // const [globals] = useGlobals(); + // if (globals.client && globals.client.state.state !== "logout") navigate("/home"); return ( <>
@@ -65,7 +63,7 @@ function Login() {
-

or register

+

or register

) } @@ -74,6 +72,6 @@ function Register() {

register

todo

-

or login

+

or login

) } diff --git a/src/Context.tsx b/src/Context.tsx index bcac6dc..31a1421 100644 --- a/src/Context.tsx +++ b/src/Context.tsx @@ -4,7 +4,6 @@ import { Client, ClientState, Event, Room, Thread } from "sdk"; 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 { @@ -43,9 +42,14 @@ interface Globals { // mutation" than other settings, and may change constantly type Scene = { type: "auth", sub: "register" | "login" } | - { type: "main", room?: Room, thread?: Thread, isThreadFullscreen: boolean } | - { type: "config-room", room: Room, sub: "general" | "permissions" | "members" } | - { type: "config-user", sub: "account" | "appearance" } + { type: "loading-room", roomId: RoomId } | + { type: "room", room: Room } | + { type: "thread", thread: Thread } | + { type: "inbox", space?: Thread } | + { type: "home" } | + { type: "config-room", room: Room, sub: "general" | "permissions" | "security" | "integrations" | "members" | "rooms" } | + { type: "config-user", sub: "account" | "appearance" } | + { type: "not-found" } type Modal = { type: "user", user: UserId } | @@ -61,6 +65,7 @@ type Action = { type: "dialog.open", dialog: Dialog } | { type: "dialog.close" } | { type: "input.reply", thread: Thread, event: Event | null } | + { type: "scene.set", scene: Scene } | { type: "contextmenu.set", menu: ContextMenu | null } const GlobalsContext = createContext<[Store, (change: Action) => void]>(); @@ -74,8 +79,7 @@ type Events = { export function Contextualizer(props: ParentProps<{ client: Client | null }>) { const emitter = createEmitter>(); - - const scene: Scene = props.client ? { type: "main", isThreadFullscreen: false } : { type: "auth", sub: "login" }; + const scene: Scene = props.client ? { type: "home" } : { type: "auth", sub: "login" }; const [globals, update] = createStore({ settings: { @@ -110,7 +114,6 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { } }); - const navigate = useNavigate(); function redux(action: Action) { console.log("dispatch action", action); switch (action.type) { @@ -120,7 +123,7 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { case "login": update("client", action.client); localStorage.setItem("auth", JSON.stringify(action.client.config)); - navigate("/home"); + redux({ type: "scene.set", scene: { type: "home" }}); Object.assign(globalThis, { client: action.client }); globals.client.on("state", handleState); globals.client.start(); @@ -144,8 +147,15 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { } break; } + case "scene.set": { + update("scene", action.scene); + const hash = "#" + sceneToHash(action.scene); + if (hash !== location.hash && hash !== "#/todo") location.hash = hash; + break; + } case "contextmenu.set": { update("contextMenu", action.menu); + break; } } } @@ -155,16 +165,58 @@ export function Contextualizer(props: ParentProps<{ client: Client | null }>) { if (state.state === "logout") { localStorage.removeItem("auth"); globals.client.off("state", handleState); - navigate("/login"); + redux({ type: "scene.set", scene: { type: "auth", sub: "login" }}); + } + } + + function sceneToHash(s: Scene) { + switch (s.type) { + case "auth": return `/${s.sub}` + case "loading-room": return `/rooms/${s.roomId}`; + case "room": return `/rooms/${s.room.id}`; + case "thread": return `/todo`; + case "inbox": return `/inbox`; + case "home": return `/home`; + case "config-room": return `/todo`; + case "config-user": return `/todo`; + case "not-found": return location.hash.slice(1); + } + } + + function handleHash() { + console.log("hash change", location.hash, location.hash.split("/")); + + if (!globals.client) { + update("scene", { type: "auth", sub: "login" }); + return; + } + + switch (location.hash.split("/")[1]) { + case undefined: + case "home": return update("scene", { type: "home" }); + case "inbox": return update("scene", { type: "inbox" }); + case "rooms": { + const roomId = location.hash.split("/")[2]; + const room = globals.client.rooms.get(roomId); + if (room) { + return update("scene", { type: "room", room }); + } else { + return update("scene", { type: "loading-room", roomId }); + } + } + default: return update("scene", { type: "not-found" }); } } globals.client?.on("state", handleState); globals.client?.start(); - Object.assign(globalThis, { client: globals.client }); + Object.assign(globalThis, { client: globals.client, redux }); + window.addEventListener("hashchange", handleHash); + handleHash(); onCleanup(() => { globals.client?.off("state", handleState); globals.client?.stop(); + window.removeEventListener("hashchange", handleHash); }); return ( diff --git a/src/Main.tsx b/src/Main.tsx index a0c5745..9dba22e 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -6,42 +6,32 @@ import { Portal } from "solid-js/web"; import { Dialog, Dropdown, Text, Time, Tooltip } from "./Atoms"; import { useGlobals } from "./Context"; import { ThreadView } from "./Thread"; -import { useParams, A, useNavigate, Navigate, useLocation } from "@solidjs/router"; 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" } | - { type: "room", room: Room } | - { type: "home" } | - { type: "inbox" }; - export default function App(): JSX.Element { - const params = useParams(); - const [globals, change] = useGlobals(); - if (!globals.client || globals.client.state.state === "logout") { - return ; - } + const [globals, action] = useGlobals(); + // if (!globals.client || globals.client.state.state === "logout") { + // return ; + // } const [rooms, setRooms] = createSignal(globals.client.lists.get("rooms") ?? { count: 0, rooms: [] as Array }); - const [view, setView] = createSignal({ type: "loading" }); - - const loc = useLocation(); - createEffect(() => { - if (loc.pathname === "/home") { - setView({ type: "home" }); - } else if (loc.pathname === "/inbox") { - setView({ type: "inbox" }); - } else if (globals.client.rooms.has(params.roomId)) { - setView({ - type: "room", - room: globals.client.rooms.get(params.roomId)!, - }) - } - }); + // const loc = useLocation(); + // createEffect(() => { + // if (loc.pathname === "/home") { + // setView({ type: "home" }); + // } else if (loc.pathname === "/inbox") { + // setView({ type: "inbox" }); + // } else if (globals.client.rooms.has(params.roomId)) { + // setView({ + // type: "room", + // room: globals.client.rooms.get(params.roomId)!, + // }) + // } + // }); if (!globals.client.lists.has("rooms")) { globals.client.lists.subscribe("rooms", { @@ -68,12 +58,17 @@ export default function App(): JSX.Element { if (name === "rooms") setRooms({ ...list }); // if (name === "requests") console.log("update requests", list); - const newRoom = globals.client.rooms.get(params.roomId); - if ((view() as any)?.room !== newRoom) { - setView({ - type: "room", - room: newRoom!, - }); + if (globals.scene.type === "loading-room") { + const newRoom = globals.client.rooms.get(globals.scene.roomId); + if (newRoom) { + action({ + type: "scene.set", + scene: { + type: "room", + room: newRoom, + } + }); + } } } @@ -104,12 +99,12 @@ export default function App(): JSX.Element { const willHandleRoomContextMenu = (room: Room) => (e: MouseEvent) => { e.preventDefault(); - change({ type: "contextmenu.set", menu: { type: "room", room, x: e.clientX, y: e.clientY } }); + action({ type: "contextmenu.set", menu: { type: "room", room, x: e.clientX, y: e.clientY } }); } // TODO: put on main div function hideContextMenu() { - change({ type: "contextmenu.set", menu: null }); + action({ type: "contextmenu.set", menu: null }); } window.addEventListener("mousedown", hideContextMenu); @@ -144,12 +139,11 @@ export default function App(): JSX.Element { -
+
- please wait... - - - + + +