blowater/app/UI/setting.tsx

285 lines
10 KiB
TypeScript
Raw Normal View History

2023-06-30 14:05:57 +00:00
/** @jsx h */
import { Component, Fragment, h } from "https://esm.sh/preact@10.17.1";
2023-10-08 17:22:53 +00:00
2023-06-30 14:05:57 +00:00
import {
CenterClass,
inputBorderClass,
InputClass,
LinearGradientsClass,
NoOutlineClass,
} from "./components/tw.ts";
import KeyView from "./key-view.tsx";
2024-01-01 17:28:10 +00:00
2023-06-30 14:05:57 +00:00
import {
DividerBackgroundColor,
ErrorColor,
HoverButtonBackgroundColor,
2023-06-30 14:05:57 +00:00
PrimaryTextColor,
2023-09-07 00:37:14 +00:00
SecondaryBackgroundColor,
2023-06-30 14:05:57 +00:00
SuccessColor,
TitleIconColor,
WarnColor,
} from "./style/colors.ts";
2023-11-11 11:19:21 +00:00
import { RelayIcon } from "./icons/relay-icon.tsx";
import { DeleteIcon } from "./icons/delete-icon.tsx";
import { default_blowater_relay, RelayConfig, RemoveBlowaterRelay } from "./relay-config.ts";
2024-01-01 17:28:10 +00:00
import { ConnectionPool } from "../../libs/nostr.ts/relay-pool.ts";
import { emitFunc } from "../event-bus.ts";
2023-11-14 09:08:20 +00:00
import { sleep } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
2024-01-01 17:28:10 +00:00
import { InMemoryAccountContext, NostrAccountContext } from "../../libs/nostr.ts/nostr.ts";
import { PrivateKey } from "../../libs/nostr.ts/key.ts";
2023-06-30 14:05:57 +00:00
export interface SettingProps {
logout: () => void;
relayConfig: RelayConfig;
relayPool: ConnectionPool;
2023-06-30 14:05:57 +00:00
myAccountContext: NostrAccountContext;
emit: emitFunc<RelayConfigChange | ViewRelayDetail | ViewRecommendedRelaysList>;
2023-10-26 04:42:24 +00:00
show: boolean;
2023-06-30 14:05:57 +00:00
}
const colors = {
"Connecting": WarnColor,
"Open": SuccessColor,
"Closing": WarnColor,
"Closed": ErrorColor,
};
export const Setting = (props: SettingProps) => {
2023-06-30 14:05:57 +00:00
let priKey: PrivateKey | undefined;
const ctx = props.myAccountContext;
if (ctx instanceof InMemoryAccountContext) {
priKey = ctx.privateKey;
}
2023-10-26 04:42:24 +00:00
if (props.show == false) {
return undefined;
}
2023-06-30 14:05:57 +00:00
return (
2023-10-26 04:42:24 +00:00
<div
2024-01-02 06:54:30 +00:00
class={`flex-1 overflow-y-auto`}
2023-10-26 04:42:24 +00:00
>
2023-12-17 20:51:45 +00:00
<div class={`min-w-full min-h-full px-2 bg-[${SecondaryBackgroundColor}]`}>
<div class={`max-w-[41rem] m-auto py-[1.5rem]`}>
<div class={`px-[1rem] py-[1.5rem] ${inputBorderClass} rounded-lg mt-[1.5rem]`}>
2023-10-26 04:42:24 +00:00
<RelaySetting
emit={props.emit}
2024-03-16 13:01:10 +00:00
getRelayURLs={props.relayConfig.getRelayURLs}
2023-10-26 04:42:24 +00:00
relayPool={props.relayPool}
>
</RelaySetting>
</div>
2023-06-30 14:05:57 +00:00
2023-10-26 04:42:24 +00:00
<div
2023-12-17 20:51:45 +00:00
class={`px-[1rem] py-[0.5rem] ${inputBorderClass} rounded-lg mt-[1.5rem] text-[${PrimaryTextColor}]`}
2023-10-26 04:42:24 +00:00
>
<KeyView
privateKey={priKey}
publicKey={props.myAccountContext.publicKey}
/>
</div>
<button
2023-12-17 20:51:45 +00:00
class={`w-full p-[0.75rem] mt-[1.5rem] rounded-lg ${NoOutlineClass} ${CenterClass} ${LinearGradientsClass} hover:bg-gradient-to-l text-[${PrimaryTextColor}]`}
2023-10-26 04:42:24 +00:00
onClick={props.logout}
>
Logout
</button>
2023-09-07 00:37:14 +00:00
</div>
2023-06-30 14:05:57 +00:00
</div>
</div>
);
};
export type RelayConfigChange = {
type: "RelayConfigChange";
2023-11-15 13:21:45 +00:00
kind: "add" | "remove";
url: string;
};
2023-11-21 07:20:39 +00:00
export type ViewRelayDetail = {
type: "ViewRelayDetail";
url: string;
};
export type ViewRecommendedRelaysList = {
type: "ViewRecommendedRelaysList";
};
2024-03-16 13:01:10 +00:00
export type func_GetRelayURLs = () => Set<string>;
type RelaySettingProp = {
2024-03-16 13:01:10 +00:00
getRelayURLs: func_GetRelayURLs;
relayPool: ConnectionPool;
emit: emitFunc<RelayConfigChange | ViewRelayDetail | ViewRecommendedRelaysList>;
};
type RelaySettingState = {
error: string;
addRelayInput: string;
relayStatus: { url: string; status: keyof typeof colors }[];
};
export class RelaySetting extends Component<RelaySettingProp, RelaySettingState> {
state: Readonly<RelaySettingState> = {
error: "",
addRelayInput: "",
relayStatus: [],
};
2023-11-14 09:08:20 +00:00
private exit = false;
async componentDidMount() {
while (this.exit == false) {
await sleep(333);
2023-11-14 09:08:20 +00:00
const status = this.computeRelayStatus(this.props);
this.setState({
relayStatus: status,
});
}
}
componentWillUnmount(): void {
this.exit == true;
}
computeRelayStatus(props: RelaySettingProp) {
const _relayStatus: { url: string; status: keyof typeof colors }[] = [];
2024-03-16 13:01:10 +00:00
for (const url of props.getRelayURLs()) {
const relay = props.relayPool.getRelay(url);
2023-11-14 06:22:50 +00:00
let status: keyof typeof colors = "Closed";
if (relay) {
2023-11-15 13:21:45 +00:00
status = relay.status();
}
_relayStatus.push({
url,
status,
});
}
return _relayStatus;
}
2023-11-21 07:20:39 +00:00
showRelayDetail = (url: string) => {
this.props.emit({
type: "ViewRelayDetail",
url: url,
});
};
showRecommendedRelaysList = () => {
this.props.emit({
type: "ViewRecommendedRelaysList",
});
};
render(props: RelaySettingProp) {
const addRelayInput = this.state.addRelayInput;
const relayStatus = this.computeRelayStatus(props);
const addRelay = async () => {
console.log("add", addRelayInput);
2024-03-16 13:01:10 +00:00
if (addRelayInput.length < 0) {
return;
}
2024-03-16 13:01:10 +00:00
this.setState({
addRelayInput: "",
relayStatus: this.computeRelayStatus(props),
});
props.emit({
type: "RelayConfigChange",
kind: "add",
url: addRelayInput,
});
};
2023-11-21 07:20:39 +00:00
return (
<Fragment>
2023-12-17 20:51:45 +00:00
<p class={`text-[1.3125rem] flex text-[${PrimaryTextColor}]`}>
<RelayIcon
2023-12-17 20:51:45 +00:00
class={`w-[2rem] h-[2rem] mr-[1rem]`}
style={{
stroke: TitleIconColor,
}}
/>
Relays
</p>
2023-12-17 20:51:45 +00:00
<p class={`mt-[1.75rem] text-[${PrimaryTextColor}]`}>
Add Relay
</p>
2023-12-17 20:51:45 +00:00
<div class={`mt-[0.5rem] flex text-[${PrimaryTextColor}]`}>
<input
autofocus={true}
onInput={(e) => this.setState({ addRelayInput: e.currentTarget.value })}
value={addRelayInput}
placeholder="wss://"
type="text"
2023-12-17 20:51:45 +00:00
class={`${InputClass}`}
/>
<button
class={`ml-[0.75rem] w-[5.9375rem] h-[3rem] p-[0.75rem] rounded-lg ${NoOutlineClass} bg-[${DividerBackgroundColor}] hover:bg-[${HoverButtonBackgroundColor}] ${CenterClass} text-[${PrimaryTextColor}]`}
onClick={addRelay}
>
Add
</button>
</div>
{this.state.error
2023-12-17 20:51:45 +00:00
? <p class={`mt-2 text-[${ErrorColor}] text-[0.875rem]`}>{this.state.error}</p>
: undefined}
2023-12-17 20:51:45 +00:00
<ul class={`mt-[1.5rem] text-[${PrimaryTextColor}]`}>
2023-10-08 17:22:53 +00:00
{relayStatus.map((r) => {
return (
<li
2023-11-21 07:20:39 +00:00
onClick={() => this.showRelayDetail(r.url)}
class={`w-full px-[1rem] py-[0.75rem] rounded-lg bg-[${DividerBackgroundColor}80] mb-[0.5rem] flex items-center justify-between cursor-pointer hover:bg-[${HoverButtonBackgroundColor}]`}
2023-10-08 17:22:53 +00:00
>
2023-12-17 20:51:45 +00:00
<div class={`flex items-center flex-1 overflow-hidden`}>
2023-10-08 17:22:53 +00:00
<span
2023-12-17 20:51:45 +00:00
class={`bg-[${
2023-10-08 17:22:53 +00:00
colors[r.status]
}] text-center block py-1 px-2 rounded text-[0.8rem] mr-2 font-bold`}
>
{r.status}
</span>
2023-12-17 20:51:45 +00:00
<span class={`truncate`}>{r.url}</span>
2023-10-08 17:22:53 +00:00
</div>
{r.url != default_blowater_relay
? (
<button
2023-12-17 20:51:45 +00:00
class={`w-[2rem] h-[2rem] rounded-lg bg-transparent hover:bg-[${DividerBackgroundColor}] ${CenterClass} ${NoOutlineClass}`}
2024-03-16 13:01:10 +00:00
onClick={this.removeRelay(props, r.url)}
>
<DeleteIcon
2023-12-17 20:51:45 +00:00
class={`w-[1rem] h-[1rem]`}
style={{
stroke: ErrorColor,
}}
/>
</button>
)
: undefined}
2023-10-08 17:22:53 +00:00
</li>
);
})}
</ul>
<button
class={`w-full p-[0.75rem] mt-[1.5rem] rounded-lg ${NoOutlineClass} ${CenterClass} ${LinearGradientsClass} hover:bg-gradient-to-l text-[${PrimaryTextColor}]`}
onClick={this.showRecommendedRelaysList}
>
View Recommended Relays
</button>
</Fragment>
);
}
2024-03-16 13:01:10 +00:00
removeRelay = (props: RelaySettingProp, url: string) => async (e: Event) => {
e.stopPropagation();
this.setState({
relayStatus: this.computeRelayStatus(props),
});
props.emit({
type: "RelayConfigChange",
kind: "remove",
url: url,
});
};
2023-06-30 14:05:57 +00:00
}