organization
parent
95bb2c6b46
commit
56b71709e2
|
|
@ -42,10 +42,8 @@ export function getClientId() {
|
||||||
return fileContents;
|
return fileContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setClientId(id: string) {
|
export function setClientId(id: string | null) {
|
||||||
if(!validUuid(id)) return false;
|
writeFileSync(clientIdPath, id ?? '');
|
||||||
writeFileSync(clientIdPath, id);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHomeServer() {
|
export function getHomeServer() {
|
||||||
|
|
@ -58,12 +56,8 @@ export function getHomeServer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setHomeServer(url: string) {
|
export function setHomeServer(url: string | null) {
|
||||||
if(url === null) {
|
writeFileSync(homeServerPath, url ?? '');
|
||||||
writeFileSync(homeServerPath, '');
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
writeFileSync(homeServerPath, url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSessionToken() {
|
export function getSessionToken() {
|
||||||
|
|
@ -72,6 +66,6 @@ export function getSessionToken() {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setSessionToken(token: string) {
|
export function setSessionToken(token: string | null) {
|
||||||
writeFileSync(sessionTokenPath, token);
|
writeFileSync(sessionTokenPath, token ?? '');
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { createContext, useCallback, useEffect, useState, useMemo } from 'react';
|
||||||
|
import Channels from './pages/Channels';
|
||||||
|
import Chat from './pages/Chat';
|
||||||
|
import Sidebar from './components/Sidebar';
|
||||||
|
import NewAccount from './pages/NewAccount';
|
||||||
|
import ServerConnection from './components/ServerConnection';
|
||||||
|
import EphemeralState from './contexts/EphemeralState/EphemeralState';
|
||||||
|
import PersistentState from '/@/contexts/PersistentState/PersistentState';
|
||||||
|
import Router from './Router';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [transparent, setTransparent] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
// font-size: 16px;
|
||||||
|
// font-family: 'Lato', sans-serif;
|
||||||
|
// font-family: 'Red Hat Text', sans-serif;
|
||||||
|
// font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
// color: #f8f8f2;
|
||||||
|
// background: #282a36;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin='' />
|
||||||
|
<link href={"https://fonts.googleapis.com/css2?family=Fira+Sans&family=Josefin+Sans&family=Lato&family=Radio+Canada&family=Readex+Pro&family=Red+Hat+Text&family=Rubik&family=Signika&family=Telex&display=swap"} rel="stylesheet" />
|
||||||
|
<style>{`
|
||||||
|
html {
|
||||||
|
--background: #282a36;
|
||||||
|
--current-line: #44475a;
|
||||||
|
--foreground: #f8f8f2;
|
||||||
|
--comment: #6272a4;
|
||||||
|
--cyan: #8be9fd;
|
||||||
|
--green: #50fa7b;
|
||||||
|
--orange: #ffb86c;
|
||||||
|
--pink: #ff79c6;
|
||||||
|
--purple: #bd93f9;
|
||||||
|
--red: #ff5555;
|
||||||
|
--yellow: #f1fa8c;
|
||||||
|
--primary: var(--purple);
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--cyan);
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
<div style={{
|
||||||
|
background: transparent ? 'rgba(0, 0, 0, 0)' : 'var(--background)',
|
||||||
|
color: transparent ? 'black' : 'var(--foreground)',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: "'Red Hat Text', sans-serif",
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
}}>
|
||||||
|
<PersistentState>
|
||||||
|
<EphemeralState onTransparencyChange={setTransparent}>
|
||||||
|
<Router></Router>
|
||||||
|
</EphemeralState>
|
||||||
|
</PersistentState>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import ServerConnection from "./components/ServerConnection";
|
||||||
|
import Sidebar from "./components/Sidebar";
|
||||||
|
import useHomeServer from "./contexts/PersistentState/useHomeServerNative";
|
||||||
|
import useClientId from "./hooks/useClientId";
|
||||||
|
import useSessionToken from "./hooks/useSessionToken";
|
||||||
|
import Channels from "./pages/Channels";
|
||||||
|
import Chat from "./pages/Chat";
|
||||||
|
import NewAccount from "./pages/NewAccount";
|
||||||
|
|
||||||
|
interface RouterProps {
|
||||||
|
[name: string]: React.ReactNode;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Router(props: RouterProps) {
|
||||||
|
|
||||||
|
const { clientId } = useClientId();
|
||||||
|
const { sessionToken } = useSessionToken();
|
||||||
|
const { homeServer } = useHomeServer();
|
||||||
|
|
||||||
|
const configured =
|
||||||
|
homeServer !== null &&
|
||||||
|
clientId !== null &&
|
||||||
|
sessionToken !== null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
configured ? (
|
||||||
|
<ServerConnection url={homeServer}>
|
||||||
|
<Sidebar
|
||||||
|
threshold={800}
|
||||||
|
sidebar={300}
|
||||||
|
>
|
||||||
|
<Channels></Channels>
|
||||||
|
<Chat></Chat>
|
||||||
|
</Sidebar>
|
||||||
|
</ServerConnection>
|
||||||
|
) : (
|
||||||
|
<NewAccount></NewAccount>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import useSessionToken from "../hooks/useSessionToken"
|
||||||
|
|
||||||
|
export default function Logout() {
|
||||||
|
|
||||||
|
const { setSessionToken } = useSessionToken();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button onClick={() => setSessionToken(null)}>LOGOUT</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { createContext, PropsWithChildren, ReactNode, useEffect, useMemo } from "react";
|
import { createContext, PropsWithChildren, ReactNode, useEffect, useMemo } from "react";
|
||||||
import { connectApi } from "../lib/api";
|
import { connectApi } from "../lib/api";
|
||||||
import { usePrevious } from "./usePrevious";
|
|
||||||
|
|
||||||
interface ServerConnectionProps {
|
interface ServerConnectionProps {
|
||||||
children: ReactNode,
|
children: ReactNode,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import 'reactjs-popup/dist/index.css';
|
import 'reactjs-popup/dist/index.css';
|
||||||
import { useApi } from '../lib/useApi';
|
import { useApi } from '../lib/useApi';
|
||||||
import { ClientIdContext } from '../pages/App';
|
|
||||||
import QR from 'qrcode';
|
import QR from 'qrcode';
|
||||||
import { usePrevious } from './usePrevious';
|
import { usePrevious } from '../hooks/usePrevious';
|
||||||
|
import useClientId from '../hooks/useClientId';
|
||||||
|
|
||||||
export default function Totp () {
|
export default function Totp () {
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const previousOpen = usePrevious(open);
|
const previousOpen = usePrevious(open);
|
||||||
const { clientId } = useContext(ClientIdContext);
|
const { clientId } = useClientId()
|
||||||
const [qr, setQr] = useState<string | null>(null);
|
const [qr, setQr] = useState<string | null>(null);
|
||||||
const [key, setKey] = useState<string>('');
|
const [key, setKey] = useState<string>('');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { createContext, useState, useMemo, useEffect } from "react";
|
||||||
|
|
||||||
|
export const ChannelContext = createContext<{
|
||||||
|
channel: string | null,
|
||||||
|
setChannel: (uid: string) => void
|
||||||
|
}>({
|
||||||
|
channel: null,
|
||||||
|
setChannel: () => {},
|
||||||
|
});
|
||||||
|
export const TransparencyContext = createContext<(transparent: boolean) => void>(() => {});
|
||||||
|
|
||||||
|
|
||||||
|
export default function EphemeralState(props: {
|
||||||
|
onTransparencyChange: (value: boolean) => void,
|
||||||
|
children?: React.ReactNode
|
||||||
|
}) {
|
||||||
|
|
||||||
|
const [channel, setChannel] = useState<string | null>(null);
|
||||||
|
const [transparent, setTransparent] = useState(false);
|
||||||
|
|
||||||
|
const channelContextValue = useMemo(() => {
|
||||||
|
return { channel, setChannel };
|
||||||
|
}, [channel, setChannel]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if('onTransparencyChange' in props) {
|
||||||
|
props.onTransparencyChange(transparent)
|
||||||
|
}
|
||||||
|
}, [transparent])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChannelContext.Provider value={channelContextValue}>
|
||||||
|
<TransparencyContext.Provider value={setTransparent}>
|
||||||
|
{props.children}
|
||||||
|
</TransparencyContext.Provider>
|
||||||
|
</ChannelContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { createContext } from "react";
|
||||||
|
import useHomeServerNative from "./useHomeServerNative";
|
||||||
|
import useClientIdNative from "./useClientIdNative";
|
||||||
|
import useSessionTokenNative from "./useSessionTokenNative";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const ClientIdContext = createContext<{
|
||||||
|
clientId: string | null,
|
||||||
|
setClientId: (id: string | null) => void
|
||||||
|
}>({
|
||||||
|
clientId: null,
|
||||||
|
setClientId: () => {}
|
||||||
|
});
|
||||||
|
export const HomeServerContext = createContext<{
|
||||||
|
homeServer: string | null,
|
||||||
|
setHomeServer: (uid: string | null) => void
|
||||||
|
}>({
|
||||||
|
homeServer: null,
|
||||||
|
setHomeServer: () => {}
|
||||||
|
});
|
||||||
|
export const SessionTokenContext = createContext<{
|
||||||
|
sessionToken: string | null,
|
||||||
|
setSessionToken: (token: string | null) => void
|
||||||
|
}>({
|
||||||
|
sessionToken: null,
|
||||||
|
setSessionToken() {}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default function PersistentState(props: any) {
|
||||||
|
|
||||||
|
const homeServerContextValue = useHomeServerNative();
|
||||||
|
const clientIdContextValue = useClientIdNative();
|
||||||
|
const sessionTokenContextValue = useSessionTokenNative();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HomeServerContext.Provider value={homeServerContextValue}>
|
||||||
|
<ClientIdContext.Provider value={clientIdContextValue}>
|
||||||
|
<SessionTokenContext.Provider value={sessionTokenContextValue}>
|
||||||
|
{props.children}
|
||||||
|
</SessionTokenContext.Provider>
|
||||||
|
</ClientIdContext.Provider>
|
||||||
|
</HomeServerContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import {
|
||||||
|
getClientId,
|
||||||
|
setClientId
|
||||||
|
} from '/@/lib/native';
|
||||||
|
|
||||||
|
export default function useClientIdNative() {
|
||||||
|
const [cachedClientId, setCachedClientId] =
|
||||||
|
useState<string | null>(getClientId());
|
||||||
|
|
||||||
|
const setClientIdCallback = useCallback((id: string | null) => {
|
||||||
|
setClientId(id);
|
||||||
|
setCachedClientId(getClientId());
|
||||||
|
}, [cachedClientId]);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return {
|
||||||
|
clientId: cachedClientId,
|
||||||
|
setClientId: setClientIdCallback
|
||||||
|
};
|
||||||
|
}, [cachedClientId, setClientIdCallback]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import {
|
||||||
|
setHomeServer,
|
||||||
|
getHomeServer
|
||||||
|
} from '/@/lib/native';
|
||||||
|
|
||||||
|
export default function useHomeServer() {
|
||||||
|
const [cachedHomeServer, setCachedHomeServer] =
|
||||||
|
useState<string | null>(getHomeServer());
|
||||||
|
|
||||||
|
const setHomeServerCallback = useCallback((url: string | null) => {
|
||||||
|
setHomeServer(url);
|
||||||
|
setCachedHomeServer(getHomeServer());
|
||||||
|
}, [cachedHomeServer]);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return {
|
||||||
|
homeServer: cachedHomeServer,
|
||||||
|
setHomeServer: setHomeServerCallback
|
||||||
|
};
|
||||||
|
}, [cachedHomeServer, setHomeServerCallback])
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import {
|
||||||
|
getSessionToken,
|
||||||
|
setSessionToken
|
||||||
|
} from '/@/lib/native';
|
||||||
|
|
||||||
|
export default function useSessionTokenNative() {
|
||||||
|
const [cachedSessionToken, setCachedSessionToken] =
|
||||||
|
useState<string | null>(getSessionToken());
|
||||||
|
|
||||||
|
const setSessionTokenCallback = useCallback((token: string | null) => {
|
||||||
|
setSessionToken(token);
|
||||||
|
setCachedSessionToken(getSessionToken());
|
||||||
|
}, [cachedSessionToken]);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return {
|
||||||
|
sessionToken: cachedSessionToken,
|
||||||
|
setSessionToken: setSessionTokenCallback
|
||||||
|
};
|
||||||
|
}, [cachedSessionToken, setSessionTokenCallback])
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { ChannelContext } from "../contexts/EphemeralState/EphemeralState";
|
||||||
|
|
||||||
|
export default function useChannel() {
|
||||||
|
return useContext(ChannelContext);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { ClientIdContext } from "../contexts/PersistentState/PersistentState";
|
||||||
|
|
||||||
|
|
||||||
|
export default function useClientId() {
|
||||||
|
return useContext(ClientIdContext);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { HomeServerContext } from "../contexts/PersistentState/PersistentState";
|
||||||
|
|
||||||
|
export default function useHomeServer() {
|
||||||
|
return useContext(HomeServerContext);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { SessionTokenContext } from "../contexts/PersistentState/PersistentState";
|
||||||
|
|
||||||
|
export default function useSessionToken() {
|
||||||
|
return useContext(SessionTokenContext);
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import Sidebar from './components/Sidebar';
|
import Sidebar from './components/Sidebar';
|
||||||
import App from './pages/App';
|
import App from './App';
|
||||||
|
|
||||||
const container = document.getElementById('app');
|
const container = document.getElementById('app');
|
||||||
if(container !== null) {
|
if(container !== null) {
|
||||||
|
|
|
||||||
|
|
@ -1,164 +0,0 @@
|
||||||
import { createContext, useCallback, useEffect, useState, useMemo } from 'react';
|
|
||||||
import Channels from './Channels';
|
|
||||||
import Chat from './Chat';
|
|
||||||
import {
|
|
||||||
getClientId,
|
|
||||||
setClientId,
|
|
||||||
getHomeServer,
|
|
||||||
setHomeServer,
|
|
||||||
getSessionToken,
|
|
||||||
setSessionToken
|
|
||||||
} from '../lib/native';
|
|
||||||
import { useApi } from '../lib/useApi';
|
|
||||||
import Sidebar from '../components/Sidebar';
|
|
||||||
import NewAccount from './NewAccount';
|
|
||||||
import ServerConnection from '../components/ServerConnection';
|
|
||||||
|
|
||||||
export const ChannelContext = createContext<{
|
|
||||||
channel: string | null,
|
|
||||||
setChannel: (uid: string) => void
|
|
||||||
}>({
|
|
||||||
channel: null,
|
|
||||||
setChannel: () => {},
|
|
||||||
});
|
|
||||||
export const ClientIdContext = createContext<{
|
|
||||||
clientId: string | null,
|
|
||||||
setClientId: (id: string | null) => void
|
|
||||||
}>({
|
|
||||||
clientId: null,
|
|
||||||
setClientId: () => {}
|
|
||||||
});
|
|
||||||
export const HomeServerContext = createContext<{
|
|
||||||
homeServer: string | null,
|
|
||||||
setHomeServer: (uid: string | null) => void
|
|
||||||
}>({
|
|
||||||
homeServer: null,
|
|
||||||
setHomeServer: () => {}
|
|
||||||
});
|
|
||||||
export const SessionTokenContext = createContext<{
|
|
||||||
sessionToken: string | null,
|
|
||||||
setSessionToken: (token: string) => void
|
|
||||||
}>({
|
|
||||||
sessionToken: null,
|
|
||||||
setSessionToken() {}
|
|
||||||
})
|
|
||||||
export const TransparencyContext = createContext<(transparent: boolean) => void>(() => {});
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
const [channel, setChannel] = useState<string | null>(null);
|
|
||||||
const [clientId, setCachedClientId] = useState(getClientId());
|
|
||||||
const [homeServer, setCachedHomeServer] = useState<string | null>(getHomeServer());
|
|
||||||
const channelContextValue = { channel, setChannel }
|
|
||||||
const [cachedSessionToken, setCachedSessionToken] = useState<string | null>(null);
|
|
||||||
const [transparent, setTransparent] = useState(false);
|
|
||||||
|
|
||||||
const setHomeServerCallback = useCallback((url: string | null) => {
|
|
||||||
console.log('SETTING HOME SERVER', url)
|
|
||||||
setHomeServer(url);
|
|
||||||
setCachedHomeServer(getHomeServer());
|
|
||||||
}, [homeServer]);
|
|
||||||
|
|
||||||
const homeServerContextValue = useMemo(() => {
|
|
||||||
return {
|
|
||||||
homeServer,
|
|
||||||
setHomeServer: setHomeServerCallback
|
|
||||||
};
|
|
||||||
}, [homeServer, setHomeServerCallback])
|
|
||||||
|
|
||||||
// persist given clientId to disk
|
|
||||||
useEffect(() => {
|
|
||||||
if(clientId === null) return;
|
|
||||||
setClientId(clientId);
|
|
||||||
}, [clientId]);
|
|
||||||
|
|
||||||
const updateCachedSessionToken = useCallback((token?: string) => {
|
|
||||||
setSessionToken(token ?? '');
|
|
||||||
setCachedSessionToken(getSessionToken());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const SessionTokenContextValue = useMemo(() => {
|
|
||||||
return {
|
|
||||||
sessionToken: cachedSessionToken,
|
|
||||||
setSessionToken: updateCachedSessionToken
|
|
||||||
}
|
|
||||||
}, [cachedSessionToken, updateCachedSessionToken])
|
|
||||||
|
|
||||||
// const { send } = useApi({
|
|
||||||
// 'client:new'(data: string) {
|
|
||||||
// setCachedClientId(data);
|
|
||||||
// },
|
|
||||||
// }, [setCachedClientId]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if(clientId !== null) return;
|
|
||||||
// send('client:new');
|
|
||||||
// }, [clientId]);
|
|
||||||
|
|
||||||
const clientIdContextValue = { clientId, setClientId: setCachedClientId };
|
|
||||||
|
|
||||||
// font-size: 16px;
|
|
||||||
// font-family: 'Lato', sans-serif;
|
|
||||||
// font-family: 'Red Hat Text', sans-serif;
|
|
||||||
// font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
||||||
// color: #f8f8f2;
|
|
||||||
// background: #282a36;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin='' />
|
|
||||||
<link href={"https://fonts.googleapis.com/css2?family=Fira+Sans&family=Josefin+Sans&family=Lato&family=Radio+Canada&family=Readex+Pro&family=Red+Hat+Text&family=Rubik&family=Signika&family=Telex&display=swap"} rel="stylesheet" />
|
|
||||||
<style>{`
|
|
||||||
html {
|
|
||||||
--background: #282a36;
|
|
||||||
--current-line: #44475a;
|
|
||||||
--foreground: #f8f8f2;
|
|
||||||
--comment: #6272a4;
|
|
||||||
--cyan: #8be9fd;
|
|
||||||
--green: #50fa7b;
|
|
||||||
--orange: #ffb86c;
|
|
||||||
--pink: #ff79c6;
|
|
||||||
--purple: #bd93f9;
|
|
||||||
--red: #ff5555;
|
|
||||||
--yellow: #f1fa8c;
|
|
||||||
--primary: var(--purple);
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: var(--cyan);
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
<ClientIdContext.Provider value={clientIdContextValue}>
|
|
||||||
<ChannelContext.Provider value={channelContextValue}>
|
|
||||||
<HomeServerContext.Provider value={homeServerContextValue}>
|
|
||||||
<TransparencyContext.Provider value={setTransparent}>
|
|
||||||
<SessionTokenContext.Provider value={SessionTokenContextValue}>
|
|
||||||
<div style={{
|
|
||||||
background: transparent ? 'rgba(0, 0, 0, 0)' : 'var(--background)',
|
|
||||||
color: transparent ? 'black' : 'var(--foreground)',
|
|
||||||
fontSize: '16px',
|
|
||||||
fontFamily: "'Red Hat Text', sans-serif",
|
|
||||||
width: '100%',
|
|
||||||
height: '100%'
|
|
||||||
}}>
|
|
||||||
{(cachedSessionToken === null || homeServer === null) ? (
|
|
||||||
<NewAccount></NewAccount>
|
|
||||||
) : (
|
|
||||||
<ServerConnection url={homeServer}>
|
|
||||||
<Sidebar
|
|
||||||
threshold={800}
|
|
||||||
sidebar={300}
|
|
||||||
>
|
|
||||||
<Channels></Channels>
|
|
||||||
<Chat></Chat>
|
|
||||||
</Sidebar>
|
|
||||||
</ServerConnection>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</SessionTokenContext.Provider>
|
|
||||||
</TransparencyContext.Provider>
|
|
||||||
</HomeServerContext.Provider>
|
|
||||||
</ChannelContext.Provider>
|
|
||||||
</ClientIdContext.Provider>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { ChannelContext, ClientIdContext, HomeServerContext } from './App';
|
|
||||||
import { useApi } from '../lib/useApi';
|
import { useApi } from '../lib/useApi';
|
||||||
import type { IMessage } from './Message';
|
import type { IMessage } from './Message';
|
||||||
import NameTextbox from './NameTextbox';
|
import NameTextbox from './NameTextbox';
|
||||||
import LoginQR from './LoginQR';
|
import LoginQR from './LoginQR';
|
||||||
import Totp from '../components/Totp';
|
import Totp from '../components/Totp';
|
||||||
|
import useChannel from '../hooks/useChannel';
|
||||||
|
import useClientId from '../hooks/useClientId';
|
||||||
|
import useHomeServer from '../contexts/PersistentState/useHomeServerNative';
|
||||||
|
import Logout from '../components/Logout';
|
||||||
|
import { CgHashtag } from 'react-icons/cg';
|
||||||
|
|
||||||
interface IChannel {
|
interface IChannel {
|
||||||
uid: string;
|
uid: string;
|
||||||
|
|
@ -12,11 +16,11 @@ interface IChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Hashmark() {
|
function Hashmark() {
|
||||||
return <span style={{
|
return <CgHashtag style={{
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
marginRight: '8px',
|
marginRight: '8px',
|
||||||
marginLeft: '8px',
|
marginLeft: '8px',
|
||||||
}}>#</span>;
|
}}>#</CgHashtag>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IUnreads {
|
interface IUnreads {
|
||||||
|
|
@ -28,10 +32,10 @@ export default function Channels() {
|
||||||
const [channels, setChannels] = useState<IChannel[]>([]);
|
const [channels, setChannels] = useState<IChannel[]>([]);
|
||||||
const [unreads, setUnreads] = useState<IUnreads>({});
|
const [unreads, setUnreads] = useState<IUnreads>({});
|
||||||
|
|
||||||
const { channel, setChannel } = useContext(ChannelContext);
|
const { channel, setChannel } = useChannel()
|
||||||
const { clientId } = useContext(ClientIdContext);
|
const { clientId } = useClientId()
|
||||||
|
|
||||||
const { setHomeServer } = useContext(HomeServerContext);
|
const { setHomeServer } = useHomeServer();
|
||||||
|
|
||||||
const { send } = useApi({
|
const { send } = useApi({
|
||||||
'channels:list'(data: IChannel[]) {
|
'channels:list'(data: IChannel[]) {
|
||||||
|
|
@ -142,7 +146,7 @@ export default function Channels() {
|
||||||
// lineHeight: '20px'
|
// lineHeight: '20px'
|
||||||
}}>ADD</button>
|
}}>ADD</button>
|
||||||
<NameTextbox></NameTextbox><br></br>
|
<NameTextbox></NameTextbox><br></br>
|
||||||
<button onClick={() => setHomeServer(null)}>leave</button><br></br>
|
<Logout></Logout><br></br>
|
||||||
{/* <LoginQR></LoginQR> */}
|
{/* <LoginQR></LoginQR> */}
|
||||||
{/* <Totp></Totp> */}
|
{/* <Totp></Totp> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { useApi } from '../lib/useApi';
|
import { useApi } from '../lib/useApi';
|
||||||
import { ChannelContext, ClientIdContext } from './App';
|
|
||||||
import type { IMessage} from './Message';
|
import type { IMessage} from './Message';
|
||||||
import { Message } from './Message';
|
import { Message } from './Message';
|
||||||
import { MdSend } from 'react-icons/md';
|
import { MdSend } from 'react-icons/md';
|
||||||
|
import useChannel from '../hooks/useChannel';
|
||||||
|
import useClientId from '../hooks/useClientId';
|
||||||
|
|
||||||
function createMessage(from: string, text: string,
|
function createMessage(from: string, text: string,
|
||||||
channel: string, t = 0): IMessage {
|
channel: string, t = 0): IMessage {
|
||||||
|
|
@ -26,8 +27,8 @@ export default () => {
|
||||||
|
|
||||||
const textBoxRef = useRef<HTMLDivElement>(null);
|
const textBoxRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { channel, setChannel } = useContext(ChannelContext);
|
const { channel, setChannel } = useChannel();
|
||||||
const { clientId } = useContext(ClientIdContext);
|
const { clientId } = useClientId();
|
||||||
|
|
||||||
const { send } = useApi({
|
const { send } = useApi({
|
||||||
'message:message'(data: IMessage) {
|
'message:message'(data: IMessage) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { ClientIdContext, HomeServerContext } from "./App";
|
|
||||||
import QR from 'qrcode';
|
import QR from 'qrcode';
|
||||||
|
import useHomeServer from "../contexts/PersistentState/useHomeServerNative";
|
||||||
|
import useClientId from "../hooks/useClientId";
|
||||||
|
|
||||||
export default function LoginQR() {
|
export default function LoginQR() {
|
||||||
const { homeServer } = useContext(HomeServerContext);
|
const { homeServer } = useHomeServer()
|
||||||
const { clientId } = useContext(ClientIdContext);
|
const { clientId } = useClientId();
|
||||||
const [qr, setQr] = useState<string | null>(null);
|
const [qr, setQr] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import {
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { ClientIdContext } from './App';
|
import useClientId from '../hooks/useClientId';
|
||||||
import { useApi } from '../lib/useApi';
|
import { useApi } from '../lib/useApi';
|
||||||
|
|
||||||
|
|
||||||
export default function NameTextbox() {
|
export default function NameTextbox() {
|
||||||
const { clientId } = useContext(ClientIdContext);
|
const { clientId } = useClientId()
|
||||||
const [name, setName] = useState<string | null>(null);
|
const [name, setName] = useState<string | null>(null);
|
||||||
const [inputElement, setInputElement] = useState<HTMLInputElement | null>(null);
|
const [inputElement, setInputElement] = useState<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ import { useEffect, useState } from "react";
|
||||||
import { useCallback, useContext, useRef } from "react"
|
import { useCallback, useContext, useRef } from "react"
|
||||||
import ServerConnection from "../components/ServerConnection";
|
import ServerConnection from "../components/ServerConnection";
|
||||||
import { useApi } from "../lib/useApi";
|
import { useApi } from "../lib/useApi";
|
||||||
import { ClientIdContext, HomeServerContext, SessionTokenContext, TransparencyContext } from "./App"
|
|
||||||
import QR from 'qrcode';
|
import QR from 'qrcode';
|
||||||
|
import useSessionToken from "../hooks/useSessionToken";
|
||||||
|
|
||||||
export default function NewAccount() {
|
export default function NewAccount() {
|
||||||
|
|
||||||
|
|
@ -73,27 +73,24 @@ export default function NewAccount() {
|
||||||
if(connecting) return;
|
if(connecting) return;
|
||||||
setHomeServer(url);
|
setHomeServer(url);
|
||||||
setConnecting(true);
|
setConnecting(true);
|
||||||
try {
|
|
||||||
const ws = new WebSocket(url);
|
|
||||||
|
|
||||||
ws.addEventListener('open', () => {
|
const ws = new WebSocket(url);
|
||||||
setConnecting(false);
|
|
||||||
setConnection(ws);
|
|
||||||
setConnectionError('');
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.addEventListener('close', (e) => {
|
ws.addEventListener('open', () => {
|
||||||
setConnecting(false);
|
setConnecting(false);
|
||||||
setConnection(null);
|
setConnection(ws);
|
||||||
console.log(e)
|
setConnectionError('');
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener('error', (e) => {
|
ws.addEventListener('close', (e) => {
|
||||||
setConnectionError('Couldn\'t connect to ' + url)
|
setConnecting(false);
|
||||||
});
|
setConnection(null);
|
||||||
} catch(e: any) {
|
console.log(e)
|
||||||
console.log('ASDFASDFASDF');
|
});
|
||||||
}
|
|
||||||
|
ws.addEventListener('error', (e) => {
|
||||||
|
setConnectionError('Connection failed')
|
||||||
|
});
|
||||||
}, [connecting])
|
}, [connecting])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -101,17 +98,36 @@ export default function NewAccount() {
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
placeContent: 'center center',
|
placeContent: 'center center',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
textAlign: 'center'
|
||||||
}}>
|
}}>
|
||||||
{returning ? (
|
{returning ? (
|
||||||
<>
|
<div>
|
||||||
Login
|
<span>
|
||||||
|
Login
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="#" onClick={() => setReturning(false)}>Sign up</a>
|
<a href="#" onClick={() => setReturning(false)}>Sign up</a>
|
||||||
</>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<input ref={homeServerInputRef} defaultValue="wss://macos.valnet.xyz" disabled={connection !== null}></input>
|
<div>
|
||||||
<button onClick={() => connect(homeServerInputRef.current?.value ?? '')} disabled={connection !== null}>Next</button>
|
<a href="#" onClick={() => setReturning(true)}>
|
||||||
{connecting ? `Connecting to ${homeServer}` : connectionError}
|
Login
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<span>
|
||||||
|
Sign up
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<br></br>
|
||||||
|
<label>Home Server URL</label>
|
||||||
|
<input style={{textAlign: 'center'}} ref={homeServerInputRef} defaultValue="wss://macos.valnet.xyz" disabled={connection !== null || connecting}></input>
|
||||||
|
<button onClick={() => connect(homeServerInputRef.current?.value ?? '')} disabled={connection !== null || connecting}>Next</button>
|
||||||
|
{connecting ? `Connecting...` : connectionError}
|
||||||
<br></br>
|
<br></br>
|
||||||
{connection !== null && (
|
{connection !== null && (
|
||||||
<ServerConnection url={homeServer ?? ''}>
|
<ServerConnection url={homeServer ?? ''}>
|
||||||
|
|
@ -144,7 +160,7 @@ const SignUp = (props: any) => {
|
||||||
const [clientId, setClientId] = useState<string | null>(null);
|
const [clientId, setClientId] = useState<string | null>(null);
|
||||||
// const [totpToken, setTotpToken] = useState<string | null>(null);
|
// const [totpToken, setTotpToken] = useState<string | null>(null);
|
||||||
const [qr, setQr] = useState<string | null>(null);
|
const [qr, setQr] = useState<string | null>(null);
|
||||||
const { setSessionToken } = useContext(SessionTokenContext)
|
const { setSessionToken } = useSessionToken();
|
||||||
|
|
||||||
const { send } = useApi({
|
const { send } = useApi({
|
||||||
'client:new'(data: any) {
|
'client:new'(data: any) {
|
||||||
|
|
|
||||||
Reference in New Issue