Modal Component (#465)

This commit is contained in:
Bob 2024-06-29 14:58:41 +08:00 committed by GitHub
parent d457cf089e
commit 5dcf8267bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 142 additions and 2 deletions

View File

@ -33,6 +33,7 @@ import { getTags, Parsed_Event } from "../nostr.ts";
import { Toast } from "./components/toast.tsx";
import { ToastChannel } from "./components/toast.tsx";
import { RightPanelChannel } from "./components/right-panel.tsx";
import { Modal, ModalInputChannel } from "./components/modal.tsx";
import { func_IsAdmin } from "./message-list.tsx";
import { getRelayInformation } from "../../libs/nostr.ts/nip11.ts";
@ -52,6 +53,7 @@ export async function Start(database: DexieDatabase) {
const eventBus = new EventBus<UI_Interaction_Event>();
const popOverInputChan: PopOverInputChannel = new Channel();
const rightPanelInputChan: RightPanelChannel = new Channel();
const modalInputChan: ModalInputChannel = new Channel();
const toastInputChan: ToastChannel = new Channel();
const dbView = await Database_View.New(database, database, database);
@ -74,6 +76,7 @@ export async function Start(database: DexieDatabase) {
pool: new ConnectionPool({ signer: ctx }),
popOverInputChan,
rightPanelInputChan,
modalInputChan,
otherConfig,
lamport,
installPrompt,
@ -91,6 +94,7 @@ export async function Start(database: DexieDatabase) {
model={model}
popOverInputChan={popOverInputChan}
rightPanelInputChan={rightPanelInputChan}
modalInputChan={modalInputChan}
installPrompt={installPrompt}
toastInputChan={toastInputChan}
/>,
@ -104,6 +108,7 @@ export async function Start(database: DexieDatabase) {
dbView: dbView,
popOver: popOverInputChan,
rightPanel: rightPanelInputChan,
modal: modalInputChan,
lamport,
installPrompt,
toastInputChan: toastInputChan,
@ -117,6 +122,7 @@ export async function Start(database: DexieDatabase) {
model={model}
popOverInputChan={popOverInputChan}
rightPanelInputChan={rightPanelInputChan}
modalInputChan={modalInputChan}
installPrompt={installPrompt}
toastInputChan={toastInputChan}
/>,
@ -136,6 +142,7 @@ export class App {
public readonly pool: ConnectionPool,
public readonly popOverInputChan: PopOverInputChannel,
public readonly rightPanelInputChan: RightPanelChannel,
public readonly modalInputChan: ModalInputChannel,
public readonly otherConfig: OtherConfig,
public readonly conversationLists: DM_List,
public readonly relayConfig: RelayConfig,
@ -152,6 +159,7 @@ export class App {
pool: ConnectionPool;
popOverInputChan: PopOverInputChannel;
rightPanelInputChan: RightPanelChannel;
modalInputChan: ModalInputChannel;
otherConfig: OtherConfig;
lamport: LamportTime;
installPrompt: InstallPrompt;
@ -247,6 +255,7 @@ export class App {
args.pool,
args.popOverInputChan,
args.rightPanelInputChan,
args.modalInputChan,
args.otherConfig,
conversationLists,
relayConfig,
@ -274,6 +283,7 @@ export class App {
model={this.model}
popOverInputChan={this.popOverInputChan}
rightPanelInputChan={this.rightPanelInputChan}
modalInputChan={this.modalInputChan}
installPrompt={installPrompt}
toastInputChan={this.toastInputChan}
/>,
@ -305,6 +315,7 @@ export class App {
model={this.model}
popOverInputChan={this.popOverInputChan}
rightPanelInputChan={this.rightPanelInputChan}
modalInputChan={this.modalInputChan}
installPrompt={installPrompt}
toastInputChan={this.toastInputChan}
/>,
@ -326,6 +337,7 @@ type AppProps = {
eventBus: AppEventBus;
popOverInputChan: PopOverInputChannel;
rightPanelInputChan: RightPanelChannel;
modalInputChan: ModalInputChannel;
toastInputChan: ToastChannel;
installPrompt: InstallPrompt;
};
@ -495,6 +507,7 @@ export class AppComponent extends Component<AppProps, {
inputChan={props.rightPanelInputChan}
/>
<Toast inputChan={props.toastInputChan} />
<Modal inputChan={props.modalInputChan} />
</div>
);

View File

@ -62,7 +62,7 @@ import { SyncEvent } from "./message-panel.tsx";
import { SendingEventRejection, ToastChannel } from "./components/toast.tsx";
import { SingleRelayConnection } from "../../libs/nostr.ts/relay-single.ts";
import { default_blowater_relay } from "./relay-config.ts";
import { forever, setState } from "./_helper.ts";
import { forever } from "./_helper.ts";
import { DeleteEvent, func_GetEventByID } from "./message-list.tsx";
import { FilterContent } from "./filter.tsx";
import { CloseRightPanel } from "./components/right-panel.tsx";
@ -70,7 +70,7 @@ import { RightPanelChannel } from "./components/right-panel.tsx";
import { ReplyToMessage } from "./message-list.tsx";
import { EditorSelectProfile } from "./editor.tsx";
import { uploadFile } from "../../libs/nostr.ts/nip96.ts";
import * as csp from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { HideModal, ModalInputChannel } from "./components/modal.tsx";
export type UI_Interaction_Event =
| SearchUpdate
@ -92,6 +92,7 @@ export type UI_Interaction_Event =
| UnblockUser
| SelectSpace
| HidePopOver
| HideModal
| SyncEvent
| FilterContent
| CloseRightPanel
@ -121,6 +122,7 @@ export function UI_Interaction_Update(args: {
dbView: Database_View;
popOver: PopOverInputChannel;
rightPanel: RightPanelChannel;
modal: ModalInputChannel;
lamport: LamportTime;
installPrompt: InstallPrompt;
toastInputChan: ToastChannel;
@ -136,6 +138,7 @@ const handle_update_event = async (chan: PutChannel<true>, args: {
dbView: Database_View;
popOver: PopOverInputChannel;
rightPanel: RightPanelChannel;
modal: ModalInputChannel;
lamport: LamportTime;
installPrompt: InstallPrompt;
toastInputChan: ToastChannel;
@ -161,6 +164,7 @@ const handle_update_event = async (chan: PutChannel<true>, args: {
pool,
popOverInputChan: args.popOver,
rightPanelInputChan: args.rightPanel,
modalInputChan: args.modal,
otherConfig,
lamport: args.lamport,
installPrompt,
@ -210,6 +214,11 @@ const handle_update_event = async (chan: PutChannel<true>, args: {
/>
);
args.popOver.put({ children: search });
} else if (event.type == "HideModal") {
await app.modalInputChan.put({
children: undefined,
onClose: event.onClose,
});
} //
//
// Setting

View File

@ -0,0 +1,59 @@
/** @jsx h */
import { h, render } from "https://esm.sh/preact@10.17.1";
import { HideModal, Modal, ModalInputChannel } from "./modal.tsx";
import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { CenterClass } from "./tw.ts";
import { testEventBus } from "../_setup.test.ts";
import { emitFunc } from "../../event-bus.ts";
const modalChan: ModalInputChannel = new Channel();
function ModalTest(props: {
emit: emitFunc<HideModal>;
}) {
return (
<div class={`${CenterClass} w-screen h-screen text-white`}>
<button
class={`rounded bg-black px-4 py2`}
onClick={async () => {
await modalChan.put({
children: (
<div class="h-20 w-40 bg-white text-black rounded flex flex-col justify-center items-center">
<div>
Modal Test
</div>
<button
class="rounded bg-[#007FFF] px-4 py2"
onClick={async () => {
await props.emit({
type: "HideModal",
onClose() {
console.log("close the modal by HideModal");
},
});
}}
>
close
</button>
</div>
),
onClose() {
console.log("close the modal by click");
},
});
}}
>
Show
</button>
<Modal inputChan={modalChan} />
</div>
);
}
render(<ModalTest emit={testEventBus.emit} />, document.body);
for await (const event of testEventBus.onChange()) {
if (event.type === "HideModal") {
await modalChan.put({ children: undefined, onClose: event.onClose });
}
}

View File

@ -0,0 +1,59 @@
/** @jsx h */
import { Component, ComponentChildren, h } from "https://esm.sh/preact@10.17.1";
import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { setState } from "../_helper.ts";
export type HideModal = {
type: "HideModal";
onClose?: () => void;
};
type State = {
show: boolean;
};
export type ModalInputChannel = Channel<{ children: ComponentChildren; onClose?: () => void }>;
export class Modal extends Component<{
inputChan: ModalInputChannel;
}, State> {
state: State = { show: false };
children: ComponentChildren = undefined;
onClose?: () => void;
async componentDidMount() {
for await (const { children, onClose } of this.props.inputChan) {
this.onClose = onClose;
if (children) {
await this.show(children);
} else {
await this.hide();
}
}
}
show = async (children: ComponentChildren) => {
this.children = children;
await setState(this, { show: true });
};
hide = async () => {
await setState(this, { show: false });
if (this.onClose) this.onClose();
};
render() {
if (!this.state.show) return;
return (
<div className="fixed inset-0 flex items-center justify-center z-30">
<div
className="fixed inset-0 z-[-1] bg-[#0A0A0A] bg-opacity-50 cursor-pointer"
onClick={this.hide}
>
</div>
<div className={`absolute`}>
{this.children}
</div>
</div>
);
}
}