mirror of
https://github.com/BlowaterNostr/blowater.git
synced 2024-10-18 07:33:22 +00:00
sliding right panel & contact tags (#370)
This commit is contained in:
parent
c73b485189
commit
feaa3f2ead
@ -1,12 +1,8 @@
|
||||
/** @jsx h */
|
||||
import { h, render } from "https://esm.sh/preact@10.17.1";
|
||||
import { setup } from "https://esm.sh/twind@0.16.16";
|
||||
import { NewIndexedDB } from "./dexie-db.ts";
|
||||
import { TWConfig } from "./tw.config.ts";
|
||||
import { Start } from "./app.tsx";
|
||||
|
||||
setup(TWConfig);
|
||||
|
||||
const database = NewIndexedDB();
|
||||
if (database instanceof Error) {
|
||||
console.error(database);
|
||||
|
@ -417,7 +417,6 @@ export function AppComponent(props: {
|
||||
dmVNode = (
|
||||
<DirectMessageContainer
|
||||
{...model.dm}
|
||||
rightPanelModel={model.rightPanelModel}
|
||||
bus={app.eventBus}
|
||||
ctx={myAccountCtx}
|
||||
profileGetter={app.database}
|
||||
|
@ -3,7 +3,6 @@ import { SearchInitModel, SearchModel } from "./search_model.ts";
|
||||
import { ProfileData } from "../features/profile.ts";
|
||||
import { EditorModel } from "./editor.tsx";
|
||||
import { DM_Model } from "./dm.tsx";
|
||||
import { RightPanelModel } from "./right-panel.tsx";
|
||||
import { App } from "./app.tsx";
|
||||
|
||||
export type Model = {
|
||||
@ -23,7 +22,6 @@ export type Model = {
|
||||
|
||||
// UI
|
||||
navigationModel: NavigationModel;
|
||||
rightPanelModel: RightPanelModel;
|
||||
};
|
||||
|
||||
export function initialModel(): Model {
|
||||
@ -45,9 +43,6 @@ export function initialModel(): Model {
|
||||
navigationModel: {
|
||||
activeNav: "DM",
|
||||
},
|
||||
rightPanelModel: {
|
||||
show: false,
|
||||
},
|
||||
myProfile: undefined,
|
||||
};
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ import { Search } from "./search.tsx";
|
||||
import { SearchUpdate, SelectConversation } from "./search_model.ts";
|
||||
import { RelayConfigChange, ViewRelayDetail } from "./setting.tsx";
|
||||
import { SignInEvent } from "./signIn.tsx";
|
||||
import { TagSelected } from "./contact-tags.tsx";
|
||||
|
||||
export type UI_Interaction_Event =
|
||||
| SearchUpdate
|
||||
@ -60,7 +61,8 @@ export type UI_Interaction_Event =
|
||||
| StartEditGroupChatProfile
|
||||
| StartInvite
|
||||
| InviteUsersToGroup
|
||||
| ViewRelayDetail;
|
||||
| ViewRelayDetail
|
||||
| TagSelected;
|
||||
|
||||
type BackToContactList = {
|
||||
type: "BackToContactList";
|
||||
@ -151,9 +153,6 @@ export async function* UI_Interaction_Update(args: {
|
||||
else if (event.type == "SelectConversation") {
|
||||
model.navigationModel.activeNav = "DM";
|
||||
model.search.isSearching = false;
|
||||
model.rightPanelModel = {
|
||||
show: false,
|
||||
};
|
||||
updateConversation(app.model, event.pubkey, event.isGroupChat);
|
||||
|
||||
if (!model.dm.focusedContent.get(event.pubkey.hex)) {
|
||||
@ -237,9 +236,6 @@ export async function* UI_Interaction_Update(args: {
|
||||
//
|
||||
else if (event.type == "ChangeNavigation") {
|
||||
model.navigationModel.activeNav = event.id;
|
||||
model.rightPanelModel = {
|
||||
show: false,
|
||||
};
|
||||
} //
|
||||
//
|
||||
// DM
|
||||
@ -260,8 +256,6 @@ export async function* UI_Interaction_Update(args: {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (event.type == "ToggleRightPanel") {
|
||||
model.rightPanelModel.show = event.show;
|
||||
} else if (event.type == "ViewThread") {
|
||||
if (model.navigationModel.activeNav == "DM") {
|
||||
if (model.dm.currentEditor) {
|
||||
@ -271,23 +265,19 @@ export async function* UI_Interaction_Update(args: {
|
||||
);
|
||||
}
|
||||
}
|
||||
model.rightPanelModel.show = true;
|
||||
} else if (event.type == "ViewUserDetail") {
|
||||
if (model.dm.currentEditor) {
|
||||
const currentFocus = model.dm.focusedContent.get(model.dm.currentEditor.pubkey.hex);
|
||||
if (
|
||||
model.rightPanelModel.show == true &&
|
||||
currentFocus instanceof PublicKey &&
|
||||
currentFocus.hex == event.pubkey.hex &&
|
||||
currentFocus.hex == model.dm.currentEditor.pubkey.hex
|
||||
) {
|
||||
model.rightPanelModel.show = false;
|
||||
} else {
|
||||
model.dm.focusedContent.set(
|
||||
model.dm.currentEditor.pubkey.hex,
|
||||
event.pubkey,
|
||||
);
|
||||
model.rightPanelModel.show = true;
|
||||
}
|
||||
}
|
||||
} else if (event.type == "OpenNote") {
|
||||
|
@ -1,7 +1,6 @@
|
||||
/** @jsx h */
|
||||
import { createRef, h, render } from "https://esm.sh/preact@10.17.1";
|
||||
import { Toast, ToastChannel } from "./toast.tsx";
|
||||
import { TWConfig } from "../tw.config.ts";
|
||||
import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
|
||||
import { CenterClass, inputBorderClass } from "./tw.ts";
|
||||
|
||||
|
12
app/UI/contact-tags.test.tsx
Normal file
12
app/UI/contact-tags.test.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
/** @jsx h */
|
||||
import { h, render } from "https://esm.sh/preact@10.17.1";
|
||||
import { ContactTags } from "./contact-tags.tsx";
|
||||
import { testEventBus } from "./_setup.test.ts";
|
||||
|
||||
render(
|
||||
<ContactTags
|
||||
tags={["contacts", "strangers"]}
|
||||
emit={testEventBus.emit}
|
||||
/>,
|
||||
document.body,
|
||||
);
|
54
app/UI/contact-tags.tsx
Normal file
54
app/UI/contact-tags.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
/** @jsx h */
|
||||
import { Component, h } from "https://esm.sh/preact@10.17.1";
|
||||
import { HintTextColor, PrimaryTextColor, SecondaryTextColor } from "./style/colors.ts";
|
||||
import { emitFunc } from "../event-bus.ts";
|
||||
|
||||
export type TagSelected = {
|
||||
type: "tagSelected";
|
||||
tag: Tag;
|
||||
};
|
||||
|
||||
export type Tag = "contacts" | "strangers" | "blocked";
|
||||
|
||||
type Props = {
|
||||
tags: Tag[];
|
||||
emit: emitFunc<TagSelected>;
|
||||
};
|
||||
|
||||
type State = {
|
||||
selectedTag: Tag | undefined;
|
||||
};
|
||||
|
||||
export class ContactTags extends Component<Props, State> {
|
||||
state: State = {
|
||||
selectedTag: undefined,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{/* https://tailwindcolor.com/ */}
|
||||
{Array.from(this.props.tags).map((tag) => (
|
||||
<div
|
||||
class={`m-1 px-2 rounded-full inline-block
|
||||
hover:cursor-pointer select-none
|
||||
text-white hover:text-black
|
||||
${tag == this.state.selectedTag ? "border-2 border-cyan-300" : ""}
|
||||
bg-green-400 hover:bg-white`}
|
||||
onClick={(e) => {
|
||||
this.setState({
|
||||
selectedTag: tag,
|
||||
});
|
||||
this.props.emit({
|
||||
type: "tagSelected",
|
||||
tag: tag,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ import { UnpinIcon } from "./icons/unpin-icon.tsx";
|
||||
import { ProfileGetter } from "./search.tsx";
|
||||
import { SearchUpdate, SelectConversation } from "./search_model.ts";
|
||||
import { ErrorColor, PrimaryTextColor, SecondaryBackgroundColor } from "./style/colors.ts";
|
||||
import { ContactTags, TagSelected } from "./contact-tags.tsx";
|
||||
|
||||
export interface ConversationListRetriever {
|
||||
getContacts: () => Iterable<ConversationSummary>;
|
||||
@ -43,7 +44,7 @@ export interface NewMessageChecker {
|
||||
}
|
||||
|
||||
type Props = {
|
||||
emit: emitFunc<ContactUpdate | SearchUpdate>;
|
||||
emit: emitFunc<ContactUpdate | SearchUpdate | TagSelected>;
|
||||
eventBus: EventSubscriber<UI_Interaction_Event>;
|
||||
convoListRetriever: ConversationListRetriever;
|
||||
groupChatListGetter: GroupMessageListGetter;
|
||||
@ -72,6 +73,14 @@ export class ConversationList extends Component<Props, State> {
|
||||
e.isGroupChat,
|
||||
),
|
||||
});
|
||||
} else if (e.type == "tagSelected") {
|
||||
let group: ConversationType = "Strangers";
|
||||
if (e.tag == "contacts") {
|
||||
group = "Contacts";
|
||||
}
|
||||
this.setState({
|
||||
selectedContactGroup: group,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,7 +123,7 @@ export class ConversationList extends Component<Props, State> {
|
||||
<div
|
||||
// https://tailwindcss.com/docs/hover-focus-and-other-states#quick-reference
|
||||
class={`
|
||||
h-screen w-80 max-sm:w-full
|
||||
h-screen w-60 max-sm:w-full
|
||||
flex flex-col bg-[${SecondaryBackgroundColor}]`}
|
||||
>
|
||||
<div
|
||||
@ -160,52 +169,10 @@ export class ConversationList extends Component<Props, State> {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class={tw`bg-[#36393F] w-full flex h-[3rem] border-b border-[#36393F]`}>
|
||||
<li
|
||||
class={tw`h-full flex-1 cursor-pointer hover:text-[#F7F7F7] text-[#96989D] bg-[#2F3136] hover:bg-[#42464D] ${CenterClass} ${
|
||||
this.state.selectedContactGroup == "Contacts"
|
||||
? "border-b-2 border-[#54D48C] bg-[#42464D] text-[#F7F7F7]"
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => this.setState({ selectedContactGroup: "Contacts" })}
|
||||
>
|
||||
Contacts: {contacts.length}
|
||||
</li>
|
||||
<li class={tw`w-[0.05rem] h-full bg-[#2F3136]`}></li>
|
||||
<li
|
||||
class={tw`h-full flex-1 cursor-pointer hover:text-[#F7F7F7] text-[#96989D] bg-[#2F3136] hover:bg-[#42464D] ${CenterClass} ${
|
||||
this.state.selectedContactGroup == "Strangers"
|
||||
? "border-b-2 border-[#54D48C] bg-[#42464D] text-[#F7F7F7]"
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
selectedContactGroup: "Strangers",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Strangers: {strangers.length}
|
||||
</li>
|
||||
|
||||
{IS_BETA_VERSION
|
||||
? (
|
||||
<li
|
||||
class={tw`h-full flex-1 cursor-pointer hover:text-[#F7F7F7] text-[#96989D] bg-[#2F3136] hover:bg-[#42464D] ${CenterClass} ${
|
||||
this.state.selectedContactGroup == "Group"
|
||||
? "border-b-2 border-[#54D48C] bg-[#42464D] text-[#F7F7F7]"
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
selectedContactGroup: "Group",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Group: {groups.length}
|
||||
</li>
|
||||
)
|
||||
: undefined}
|
||||
</ul>
|
||||
<div class="py-1 border-b border-[#36393F]">
|
||||
<ContactTags tags={["contacts", "strangers"]} emit={this.props.emit}>
|
||||
</ContactTags>
|
||||
</div>
|
||||
|
||||
<ContactGroup
|
||||
contacts={Array.from(convoListToRender.values())}
|
||||
@ -264,7 +231,7 @@ function ContactGroup(props: ConversationListProps) {
|
||||
props.isGroupChat == props.currentSelected.isGroupChat
|
||||
? "bg-[#42464D] text-[#FFFFFF]"
|
||||
: "bg-[#42464D] text-[#96989D]"
|
||||
} cursor-pointer p-2 hover:bg-[#3C3F45] my-2 rounded-lg flex items-center w-full relative group`}
|
||||
} cursor-pointer p-2 hover:bg-[#3C3F45] mb-2 rounded-lg flex items-center w-full relative group`}
|
||||
onClick={selectConversation(
|
||||
props.emit,
|
||||
contact.conversation.pubkey,
|
||||
@ -279,7 +246,10 @@ function ContactGroup(props: ConversationListProps) {
|
||||
/>
|
||||
|
||||
<button
|
||||
class={tw`w-6 h-6 absolute hidden group-hover:flex top-[-0.75rem] right-[0.75rem] ${IconButtonClass} bg-[#42464D] hover:bg-[#2F3136]`}
|
||||
class={tw`
|
||||
w-6 h-6 absolute hidden group-hover:flex top-[-0.75rem] right-[0.75rem]
|
||||
focus:outline-none focus-visible:outline-none rounded-full hover:bg-[#42464D] ${CenterClass}
|
||||
bg-[#42464D] hover:bg-[#2F3136]`}
|
||||
style={{
|
||||
boxShadow: "2px 2px 5px 0 black",
|
||||
}}
|
||||
@ -331,7 +301,10 @@ function ContactGroup(props: ConversationListProps) {
|
||||
/>
|
||||
|
||||
<button
|
||||
class={tw`w-6 h-6 absolute hidden group-hover:flex top-[-0.75rem] right-[0.75rem] ${IconButtonClass} bg-[#42464D] hover:bg-[#2F3136]`}
|
||||
class={tw`
|
||||
w-6 h-6 absolute hidden group-hover:flex top-[-0.75rem] right-[0.75rem]
|
||||
focus:outline-none focus-visible:outline-none rounded-full hover:bg-[#42464D] ${CenterClass}
|
||||
bg-[#42464D] hover:bg-[#2F3136]`}
|
||||
style={{
|
||||
boxShadow: "2px 2px 5px 0 black",
|
||||
}}
|
||||
|
@ -19,7 +19,6 @@ import { SettingIcon } from "./icons/setting-icon.tsx";
|
||||
import { UserIcon } from "./icons/user-icon.tsx";
|
||||
import { InviteButton } from "./invite-button.tsx";
|
||||
import { MessagePanel, NewMessageListener } from "./message-panel.tsx";
|
||||
import { RightPanelModel } from "./right-panel.tsx";
|
||||
import { ProfileGetter } from "./search.tsx";
|
||||
import { PrimaryTextColor } from "./style/colors.ts";
|
||||
import {
|
||||
@ -36,7 +35,6 @@ export type DM_Model = {
|
||||
};
|
||||
|
||||
type DirectMessageContainerProps = {
|
||||
rightPanelModel: RightPanelModel;
|
||||
ctx: NostrAccountContext;
|
||||
pool: ConnectionPool;
|
||||
bus: EventBus<UI_Interaction_Event>;
|
||||
@ -178,13 +176,12 @@ export class DirectMessageContainer extends Component<DirectMessageContainerProp
|
||||
buttons={buttons}
|
||||
currentEditor={this.state.currentEditor}
|
||||
profileGetter={this.props.profileGetter}
|
||||
showRightPanel={this.props.rightPanelModel.show}
|
||||
/>
|
||||
<div class={`flex-1 overflow-auto`}>
|
||||
<MessagePanel
|
||||
myPublicKey={props.ctx.publicKey}
|
||||
rightPanelModel={props.rightPanelModel}
|
||||
emit={props.bus.emit}
|
||||
eventSub={props.bus}
|
||||
newMessageListener={props.newMessageListener}
|
||||
focusedContent={getFocusedContent(
|
||||
props.focusedContent.get(this.state.currentEditor.pubkey.hex),
|
||||
@ -213,7 +210,6 @@ function TopBar(props: {
|
||||
bus: EventBus<UI_Interaction_Event>;
|
||||
currentEditor: EditorModel;
|
||||
profileGetter: ProfileGetter;
|
||||
showRightPanel: boolean;
|
||||
buttons: VNode[];
|
||||
}) {
|
||||
return (
|
||||
@ -228,7 +224,7 @@ function TopBar(props: {
|
||||
type: "BackToContactList",
|
||||
});
|
||||
}}
|
||||
class={`w-6 h-6 mobile:mr-2 desktop:hidden ${IconButtonClass}`}
|
||||
class={`w-6 h-6 mx-2 ${IconButtonClass}`}
|
||||
>
|
||||
<LeftArrowIcon
|
||||
class={`w-4 h-4`}
|
||||
@ -241,8 +237,8 @@ function TopBar(props: {
|
||||
// https://tailwindcss.com/docs/customizing-colors
|
||||
// https://tailwindcss.com/docs/cursor
|
||||
class={`text-[#F3F4EA] text-[1.2rem]
|
||||
hover:text-[#60a5fa] hover:cursor-pointer
|
||||
ml-4 mobile:text-base whitespace-nowrap truncate`}
|
||||
hover:text-[#60a5fa] hover:cursor-pointer
|
||||
whitespace-nowrap truncate`}
|
||||
onClick={() => {
|
||||
if (!props.currentEditor) {
|
||||
return;
|
||||
@ -263,28 +259,23 @@ function TopBar(props: {
|
||||
<div>
|
||||
{props.buttons}
|
||||
|
||||
{!props.showRightPanel
|
||||
? (
|
||||
<button
|
||||
class={`absolute z-10 w-6 h-6 transition-transform duration-100 ease-in-out right-4 mobile:right-0 top-4${
|
||||
props.showRightPanel ? " rotate-180" : ""
|
||||
} ${IconButtonClass}`}
|
||||
onClick={() => {
|
||||
props.bus.emit({
|
||||
type: "ToggleRightPanel",
|
||||
show: !props.showRightPanel,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<LeftArrowIcon
|
||||
class={`w-4 h-4`}
|
||||
style={{
|
||||
fill: "#F3F4EA",
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
)
|
||||
: undefined}
|
||||
<button
|
||||
class={`absolute z-10 w-6 h-6 transition-transform duration-100 ease-in-out
|
||||
right-4 mobile:right-0 top-4 ${IconButtonClass}`}
|
||||
onClick={() => {
|
||||
props.bus.emit({
|
||||
type: "ToggleRightPanel",
|
||||
show: true,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<LeftArrowIcon
|
||||
class={`w-4 h-4`}
|
||||
style={{
|
||||
fill: "#F3F4EA",
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -6,11 +6,11 @@ import { PublicKey } from "../../libs/nostr.ts/key.ts";
|
||||
import { NoteID } from "../../libs/nostr.ts/nip19.ts";
|
||||
import { NostrEvent, NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
||||
import { RelayRecordGetter } from "../database.ts";
|
||||
import { emitFunc } from "../event-bus.ts";
|
||||
import { emitFunc, EventSubscriber } from "../event-bus.ts";
|
||||
import { ProfileData, ProfileSyncer } from "../features/profile.ts";
|
||||
import { Parsed_Event, PinConversation, UnpinConversation } from "../nostr.ts";
|
||||
import { isMobile } from "./_helper.ts";
|
||||
import { ChatMessagesGetter } from "./app_update.tsx";
|
||||
import { ChatMessagesGetter, UI_Interaction_Event } from "./app_update.tsx";
|
||||
import { Avatar } from "./components/avatar.tsx";
|
||||
import { IconButtonClass } from "./components/tw.ts";
|
||||
import { Editor, EditorEvent, EditorModel } from "./editor.tsx";
|
||||
@ -28,17 +28,14 @@ import {
|
||||
} from "./message.ts";
|
||||
import { NoteCard } from "./note-card.tsx";
|
||||
import { ProfileCard } from "./profile-card.tsx";
|
||||
import { RightPanel, RightPanelModel } from "./right-panel.tsx";
|
||||
import { RightPanel } from "./right-panel.tsx";
|
||||
import { ProfileGetter } from "./search.tsx";
|
||||
import { SelectConversation } from "./search_model.ts";
|
||||
import { DividerBackgroundColor, ErrorColor, LinkColor, PrimaryTextColor } from "./style/colors.ts";
|
||||
import { UserDetail } from "./user-detail.tsx";
|
||||
|
||||
export type DirectMessagePanelUpdate =
|
||||
| {
|
||||
type: "ToggleRightPanel";
|
||||
show: boolean;
|
||||
}
|
||||
| ToggleRightPanel
|
||||
| ViewThread
|
||||
| ViewUserDetail
|
||||
| OpenNote
|
||||
@ -47,6 +44,11 @@ export type DirectMessagePanelUpdate =
|
||||
message: ChatMessage;
|
||||
};
|
||||
|
||||
export type ToggleRightPanel = {
|
||||
type: "ToggleRightPanel";
|
||||
show: boolean;
|
||||
};
|
||||
|
||||
export type OpenNote = {
|
||||
type: "OpenNote";
|
||||
event: NostrEvent;
|
||||
@ -74,11 +76,10 @@ interface DirectMessagePanelProps {
|
||||
pubkey: PublicKey;
|
||||
} | undefined;
|
||||
|
||||
rightPanelModel: RightPanelModel;
|
||||
|
||||
emit: emitFunc<
|
||||
EditorEvent | DirectMessagePanelUpdate | PinConversation | UnpinConversation | SelectConversation
|
||||
>;
|
||||
eventSub: EventSubscriber<UI_Interaction_Event>;
|
||||
profilesSyncer: ProfileSyncer;
|
||||
eventSyncer: EventSyncer;
|
||||
profileGetter: ProfileGetter;
|
||||
@ -111,34 +112,32 @@ export class MessagePanel extends Component<DirectMessagePanelProps> {
|
||||
render() {
|
||||
const props = this.props;
|
||||
|
||||
let rightPanel;
|
||||
if (props.rightPanelModel.show) {
|
||||
let rightPanelChildren: h.JSX.Element | undefined;
|
||||
if (props.focusedContent) {
|
||||
if (props.focusedContent.type == "ProfileData") {
|
||||
rightPanelChildren = (
|
||||
<UserDetail
|
||||
targetUserProfile={{
|
||||
name: props.focusedContent?.data?.name,
|
||||
picture: props.focusedContent?.data?.picture,
|
||||
about: props.focusedContent?.data?.about,
|
||||
website: props.focusedContent?.data?.website,
|
||||
}}
|
||||
pubkey={props.focusedContent.pubkey}
|
||||
emit={props.emit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
let rightPanelChildren: h.JSX.Element | undefined;
|
||||
if (props.focusedContent) {
|
||||
if (props.focusedContent.type == "ProfileData") {
|
||||
rightPanelChildren = (
|
||||
<UserDetail
|
||||
targetUserProfile={{
|
||||
name: props.focusedContent?.data?.name,
|
||||
picture: props.focusedContent?.data?.picture,
|
||||
about: props.focusedContent?.data?.about,
|
||||
website: props.focusedContent?.data?.website,
|
||||
}}
|
||||
pubkey={props.focusedContent.pubkey}
|
||||
emit={props.emit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
rightPanel = (
|
||||
<RightPanel
|
||||
emit={props.emit}
|
||||
rightPanelModel={props.rightPanelModel}
|
||||
>
|
||||
{rightPanelChildren}
|
||||
</RightPanel>
|
||||
);
|
||||
}
|
||||
let rightPanel = (
|
||||
<RightPanel
|
||||
emit={props.emit}
|
||||
eventSub={props.eventSub}
|
||||
>
|
||||
{rightPanelChildren}
|
||||
</RightPanel>
|
||||
);
|
||||
|
||||
let vnode = (
|
||||
<div class={tw`flex h-full w-full relative bg-[#36393F]`}>
|
||||
<div class={tw`flex flex-col h-full flex-1 overflow-hidden`}>
|
||||
|
@ -7,9 +7,7 @@ render(
|
||||
<div class="border">
|
||||
<RightPanel
|
||||
emit={testEventBus.emit}
|
||||
rightPanelModel={{
|
||||
show: true,
|
||||
}}
|
||||
eventSub={testEventBus}
|
||||
>
|
||||
Test
|
||||
</RightPanel>
|
||||
|
@ -1,35 +1,49 @@
|
||||
/** @jsx h */
|
||||
import { Component, h } from "https://esm.sh/preact@10.17.1";
|
||||
import { emitFunc } from "../event-bus.ts";
|
||||
import { Component, createRef, h } from "https://esm.sh/preact@10.17.1";
|
||||
import { emitFunc, EventSubscriber } from "../event-bus.ts";
|
||||
import { IconButtonClass } from "./components/tw.ts";
|
||||
import { CloseIcon } from "./icons/close-icon.tsx";
|
||||
import { DirectMessagePanelUpdate } from "./message-panel.tsx";
|
||||
|
||||
export type RightPanelModel = {
|
||||
show: boolean;
|
||||
};
|
||||
import { DirectMessagePanelUpdate, ToggleRightPanel } from "./message-panel.tsx";
|
||||
import { tw } from "https://esm.sh/twind@0.16.16";
|
||||
import { UI_Interaction_Event } from "./app_update.tsx";
|
||||
|
||||
type RightPanelProps = {
|
||||
emit: emitFunc<DirectMessagePanelUpdate>;
|
||||
rightPanelModel: RightPanelModel;
|
||||
eventSub: EventSubscriber<UI_Interaction_Event>;
|
||||
};
|
||||
|
||||
type RightPanelState = {
|
||||
show: boolean;
|
||||
};
|
||||
export class RightPanel extends Component<RightPanelProps, {}> {
|
||||
ref = createRef<HTMLDivElement>();
|
||||
events = this.props.eventSub.onChange();
|
||||
|
||||
export class RightPanel extends Component<RightPanelProps, RightPanelState> {
|
||||
state: RightPanelState = {
|
||||
show: true,
|
||||
};
|
||||
async componentDidMount() {
|
||||
for await (const event of this.events) {
|
||||
if (event.type == "ToggleRightPanel") {
|
||||
if (event.show) {
|
||||
const ele = this.ref.current;
|
||||
if (ele) ele.classList.remove("translate-x-full");
|
||||
} else {
|
||||
const ele = this.ref.current;
|
||||
if (ele) ele.classList.add("translate-x-full");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.events.close();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { emit, children } = this.props;
|
||||
const { show } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
class={`border-l fixed top-0 right-0 h-full bg-[#2F3136] overflow-hidden overflow-y-auto z-20 transition-all duration-300 ease-in-out w-96 max-w-full`}
|
||||
ref={this.ref}
|
||||
class={tw`fixed top-0 right-0 border-l
|
||||
h-full bg-[#2F3136]
|
||||
z-20 transition duration-150 ease-in-out w-96 max-w-full
|
||||
translate-x-full`}
|
||||
>
|
||||
<button
|
||||
class={`w-6 min-w-[1.5rem] h-6 ml-4 ${IconButtonClass} hover:bg-[#36393F] absolute right-2 top-3 z-10 border-2`}
|
||||
@ -38,7 +52,6 @@ export class RightPanel extends Component<RightPanelProps, RightPanelState> {
|
||||
type: "ToggleRightPanel",
|
||||
show: false,
|
||||
});
|
||||
this.setState({ show: !show });
|
||||
}}
|
||||
>
|
||||
<CloseIcon
|
||||
|
@ -1,33 +0,0 @@
|
||||
import { Configuration } from "https://esm.sh/twind@0.16.16";
|
||||
|
||||
export const TWConfig: Configuration = {
|
||||
theme: {
|
||||
fontFamily: {
|
||||
roboto: ["Roboto", "sans-serif"],
|
||||
},
|
||||
screens: {
|
||||
"mobile": { "max": "1023px" },
|
||||
"desktop": { "min": "1024px" },
|
||||
},
|
||||
extend: {
|
||||
keyframes: {
|
||||
toast: {
|
||||
"0%": { transform: "translateX(0)" },
|
||||
"16.66%": { transform: "translateX(calc(-100% - 1rem))" },
|
||||
"83.34%": { transform: "translateX(calc(-100% - 1rem))" },
|
||||
"100%": { transform: "translateX(0)" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"toast": "toast 3s cubic-bezier(0.68, -0.55, 0.25, 1.35)",
|
||||
},
|
||||
},
|
||||
},
|
||||
// https://twind.dev/handbook/extended-functionality.html
|
||||
// https://sass-lang.com/documentation/style-rules/parent-selector/
|
||||
variants: {
|
||||
"children": "& > *",
|
||||
"firstChild": "& > *:first-child",
|
||||
"lastChild": "& > *:last-child",
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue
Block a user