react guild list
This commit is contained in:
parent
7136fbfb0b
commit
22c258bafd
@ -0,0 +1,65 @@
|
||||
import React, { FC, useMemo, useRef } from 'react';
|
||||
import CombinedGuild from '../../../guild-combined';
|
||||
import BasicHover, { BasicHoverSide } from '../../contexts/context-hover-basic';
|
||||
import BaseElements from '../../require/base-elements';
|
||||
import GuildSubscriptions from '../../require/guild-subscriptions';
|
||||
import ReactHelper from '../../require/react-helper';
|
||||
|
||||
export interface GuildListElementProps {
|
||||
guild: CombinedGuild;
|
||||
activeGuild: CombinedGuild | null;
|
||||
setSelfActiveGuild: () => void;
|
||||
}
|
||||
|
||||
const GuildListElement: FC<GuildListElementProps> = (props: GuildListElementProps) => {
|
||||
const { guild, activeGuild, setSelfActiveGuild } = props;
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// TODO: state higher up
|
||||
// TODO: handle metadata error
|
||||
const [ guildMeta, guildMetaError ] = GuildSubscriptions.useGuildMetadataSubscription(guild);
|
||||
const [ selfMember ] = GuildSubscriptions.useSelfMemberSubscription(guild);
|
||||
const [ iconSrc ] = GuildSubscriptions.useSoftImageSrcResourceSubscription(guild, guildMeta?.iconResourceId ?? null);
|
||||
|
||||
const [ contextHover, mouseEnterCallable, mouseLeaveCallable ] = ReactHelper.useContextHover(() => {
|
||||
if (!guildMeta) return null;
|
||||
if (!selfMember) return null;
|
||||
const nameStyle = selfMember.roleColor ? { color: selfMember.roleColor } : {};
|
||||
return (
|
||||
<BasicHover relativeToRef={rootRef} side={BasicHoverSide.RIGHT}>
|
||||
<div className="guild-hover">
|
||||
<div className="tab">{BaseElements.TAB_LEFT}</div>
|
||||
<div className="info">
|
||||
<div className="guild-name">{guildMeta.name}</div>
|
||||
<div className={'connection ' + selfMember.status}>
|
||||
<div className="status-circle" />
|
||||
<div className="display-name" style={nameStyle}>{selfMember.displayName}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BasicHover>
|
||||
)
|
||||
}, [ guildMeta, selfMember ]);
|
||||
|
||||
const className = useMemo(() => {
|
||||
console.log('active: ' + activeGuild?.id + '/ me: ' + guild.id);
|
||||
return activeGuild && guild.id === activeGuild.id ? 'guild active' : 'guild';
|
||||
}, [ guild, activeGuild ]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className={className} ref={rootRef}
|
||||
onClick={setSelfActiveGuild}
|
||||
onMouseEnter={mouseEnterCallable} onMouseLeave={mouseLeaveCallable}
|
||||
>
|
||||
<div className="pill" />
|
||||
<img src={iconSrc} alt="guild" />
|
||||
</div>
|
||||
{contextHover}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GuildListElement;
|
0
src/client/webapp/elements/lists/guild-list.scss
Normal file
0
src/client/webapp/elements/lists/guild-list.scss
Normal file
41
src/client/webapp/elements/lists/guild-list.tsx
Normal file
41
src/client/webapp/elements/lists/guild-list.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import React, { FC, useEffect, useMemo, useState } from 'react';
|
||||
import CombinedGuild from '../../guild-combined';
|
||||
import GuildsManager from '../../guilds-manager';
|
||||
import UI from '../../ui';
|
||||
import Util from '../../util';
|
||||
import { useGuildListSubscription } from '../require/guild-manager-subscriptions';
|
||||
import GuildListElement from './components/guild-list-element';
|
||||
|
||||
export interface GuildListProps {
|
||||
guildsManager: GuildsManager;
|
||||
ui: UI;
|
||||
}
|
||||
|
||||
const GuildList: FC<GuildListProps> = (props: GuildListProps) => {
|
||||
const { guildsManager, ui } = props;
|
||||
|
||||
const [ guilds ] = useGuildListSubscription(guildsManager);
|
||||
const [ activeGuild, setActiveGuild ] = useState<CombinedGuild | null>(null);
|
||||
|
||||
// TODO: Remove dependency on UI
|
||||
useEffect(() => {
|
||||
if (activeGuild !== null) {
|
||||
(async () => {
|
||||
await Util.sleep(0);
|
||||
ui.setActiveGuild(activeGuild);
|
||||
})();
|
||||
}
|
||||
}, [ activeGuild ]);
|
||||
|
||||
const guildElements = useMemo(() => {
|
||||
return guilds.map((guild: CombinedGuild) => <GuildListElement key={guild.id} guild={guild} activeGuild={activeGuild} setSelfActiveGuild={() => { setActiveGuild(guild); } } />);
|
||||
}, [ guilds ]);
|
||||
|
||||
return (
|
||||
<div className="guild-list">
|
||||
{guildElements}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GuildList;
|
@ -1,47 +1,22 @@
|
||||
import React from 'react';
|
||||
import { Channel } from "../data-types";
|
||||
import CombinedGuild from "../guild-combined";
|
||||
import GuildsManager from '../guilds-manager';
|
||||
import Q from "../q-module";
|
||||
import ElementsUtil from "./require/elements-util";
|
||||
import UI from '../ui';
|
||||
import GuildList from './lists/guild-list';
|
||||
import ElementsUtil from "./require/elements-util";
|
||||
import GuildElement from './sections/guild';
|
||||
|
||||
export function mountBaseComponents() {
|
||||
export function mountBaseComponents(q: Q, ui: UI, guildsManager: GuildsManager) {
|
||||
// guild-list
|
||||
// TODO
|
||||
console.log(q.$('.guild-list-anchor'));
|
||||
ElementsUtil.unmountReactComponent(q.$('.guild-list-anchor'));
|
||||
ElementsUtil.mountReactComponent(q.$('.guild-list-anchor'), <GuildList ui={ui} guildsManager={guildsManager} />);
|
||||
}
|
||||
|
||||
export function mountGuildComponents(q: Q, ui: UI, guild: CombinedGuild) {
|
||||
export function mountGuildComponents(q: Q, guild: CombinedGuild) {
|
||||
console.log(q.$('.guild-anchor'));
|
||||
ElementsUtil.unmountReactComponent(q.$('.guild-anchor'));
|
||||
ElementsUtil.mountReactComponent(q.$('.guild-anchor'), <GuildElement guild={guild} />);
|
||||
|
||||
// // guild title
|
||||
// ElementsUtil.unmountReactComponent(q.$('.guild-title-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.guild-title-anchor'), <GuildTitle guild={guild} />);
|
||||
|
||||
// // connection info
|
||||
// ElementsUtil.unmountReactComponent(q.$('.connection-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.connection-anchor'), <ConnectionInfo guild={guild} />);
|
||||
|
||||
// // member-list
|
||||
// ElementsUtil.unmountReactComponent(q.$('.member-list-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.member-list-anchor'), <MemberList guild={guild} />);
|
||||
|
||||
// // channel-list
|
||||
// ElementsUtil.unmountReactComponent(q.$('.channel-list-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.channel-list-anchor'), <ChannelList guild={guild} ui={ui} />);
|
||||
}
|
||||
|
||||
export function mountGuildChannelComponents(q: Q, guild: CombinedGuild, channel: Channel) {
|
||||
// // channel-title pieces
|
||||
// ElementsUtil.unmountReactComponent(q.$('.channel-title-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.channel-title-anchor'), <ChannelTitle channel={channel} />);
|
||||
|
||||
// // message-list
|
||||
// ElementsUtil.unmountReactComponent(q.$('.message-list-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.message-list-anchor'), <MessageList guild={guild} channel={channel} />);
|
||||
|
||||
// // send-message
|
||||
// ElementsUtil.unmountReactComponent(q.$('.send-message-input-wrapper-anchor'));
|
||||
// ElementsUtil.mountReactComponent(q.$('.send-message-input-wrapper-anchor'), <SendMessage guild={guild} channel={channel} />);
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import * as uuid from 'uuid';
|
||||
import CombinedGuild from '../../guild-combined';
|
||||
import GuildsManager from "../../guilds-manager";
|
||||
|
||||
export function useGuildListSubscription(guildsManager: GuildsManager): [ guilds: CombinedGuild[] ] {
|
||||
const [ refreshId, setRefreshId ] = useState<string>(uuid.v4());
|
||||
|
||||
const refresh = useCallback(() => {
|
||||
setRefreshId(uuid.v4());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
guildsManager.on('update-guilds', refresh);
|
||||
return () => {
|
||||
guildsManager.off('update-guilds', refresh);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const guilds = useMemo(() => {
|
||||
return guildsManager.guilds.slice();
|
||||
}, [ refreshId ]);
|
||||
|
||||
return [ guilds ];
|
||||
}
|
@ -22,6 +22,8 @@ import { AutoVerifierChangesType } from './auto-verifier';
|
||||
import { IDQuery, PartialMessageListQuery } from './auto-verifier-with-args';
|
||||
|
||||
export default class GuildsManager extends EventEmitter<{
|
||||
'update-guilds': () => void;
|
||||
|
||||
'connect': (guild: CombinedGuild) => void;
|
||||
'disconnect': (guild: CombinedGuild) => void;
|
||||
'verified': (guild: CombinedGuild) => void;
|
||||
@ -77,6 +79,7 @@ export default class GuildsManager extends EventEmitter<{
|
||||
await this.personalDB.clearAllMembersStatus(guild.id);
|
||||
|
||||
this.guilds.push(guild);
|
||||
this.emit('update-guilds');
|
||||
|
||||
// Forward guild events through this event emitter
|
||||
for (const eventName of GuildEventNames) {
|
||||
@ -194,5 +197,6 @@ export default class GuildsManager extends EventEmitter<{
|
||||
await this.personalDB.removeGuild(guild.id);
|
||||
});
|
||||
this.guilds = this.guilds.filter(g => g.id != guild.id);
|
||||
this.emit('update-guilds');
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="guild-list-container">
|
||||
<div class="guild-list-anchor"></div>
|
||||
<div id="guild-list"></div>
|
||||
<div id="add-guild">
|
||||
<div class="pill"></div>
|
||||
|
@ -13,7 +13,7 @@ import GuildsManager from './guilds-manager';
|
||||
import Globals from './globals';
|
||||
|
||||
import UI from './ui';
|
||||
import { Changes, GuildMetadata, Resource, Token } from './data-types';
|
||||
import { GuildMetadata } from './data-types';
|
||||
import Q from './q-module';
|
||||
import bindWindowButtonEvents from './elements/events-window-buttons';
|
||||
import bindAddGuildEvents from './elements/events-add-guild';
|
||||
@ -22,7 +22,7 @@ import MessageRAMCache from './message-ram-cache';
|
||||
import ResourceRAMCache from './resource-ram-cache';
|
||||
import CombinedGuild from './guild-combined';
|
||||
import { AutoVerifierChangesType } from './auto-verifier';
|
||||
import { IDQuery } from './auto-verifier-with-args';
|
||||
import { mountBaseComponents } from './elements/mounts';
|
||||
|
||||
LOG.silly('modules loaded');
|
||||
|
||||
@ -73,6 +73,8 @@ window.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
LOG.silly('events bound');
|
||||
|
||||
mountBaseComponents(q, ui, guildsManager);
|
||||
|
||||
// Add guild icons
|
||||
await ui.setGuilds(guildsManager, guildsManager.guilds);
|
||||
|
||||
|
@ -100,22 +100,19 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.info {
|
||||
.guild-hover {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $background-floating; /* for the tab */
|
||||
|
||||
.content {
|
||||
.info {
|
||||
background-color: $background-floating;
|
||||
color: $header-primary;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.content.guild {
|
||||
line-height: 1;
|
||||
|
||||
.name:not(:last-child) {
|
||||
> :not(:last-child) {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
@ -130,10 +127,6 @@
|
||||
border-radius: 5px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.connection .display-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,20 @@
|
||||
}
|
||||
|
||||
#guild-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.guild-list {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
#guild-list::-webkit-scrollbar {
|
||||
.guild-listguild-list::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#add-guild,
|
||||
#guild-list .guild {
|
||||
.guild-list .guild {
|
||||
cursor: pointer;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
@ -30,7 +34,7 @@
|
||||
}
|
||||
|
||||
#add-guild .pill,
|
||||
#guild-list .guild .pill {
|
||||
.guild-list .guild .pill {
|
||||
background-color: $header-primary;
|
||||
width: 8px;
|
||||
height: 0;
|
||||
@ -40,21 +44,21 @@
|
||||
transition: height .1s ease-in-out;
|
||||
}
|
||||
|
||||
#guild-list .guild.active .pill {
|
||||
.guild-list .guild.active .pill {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
#guild-list .guild.unread:not(.active) .pill {
|
||||
.guild-list .guild.unread:not(.active) .pill {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
#add-guild:hover .pill,
|
||||
#guild-list .guild:not(.active):hover .pill {
|
||||
.guild-list .guild:not(.active):hover .pill {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#add-guild img,
|
||||
#guild-list .guild img {
|
||||
.guild-list .guild img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 24px;
|
||||
@ -62,7 +66,7 @@
|
||||
}
|
||||
|
||||
#add-guild:hover img,
|
||||
#guild-list .guild:hover img,
|
||||
#guild-list .guild.active img {
|
||||
.guild-list .guild:hover img,
|
||||
.guild-list .guild.active img {
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ export default class UI {
|
||||
next.classList.add('active');
|
||||
|
||||
this.activeGuild = guild;
|
||||
mountGuildComponents(this.q, this, guild);
|
||||
mountGuildComponents(this.q, guild);
|
||||
}
|
||||
|
||||
public async setGuilds(guildsManager: GuildsManager, guilds: CombinedGuild[]): Promise<void> {
|
||||
|
Loading…
Reference in New Issue
Block a user