Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32215845
D3341.1765163280.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D3341.1765163280.diff
View Options
diff --git a/web/sidebar/app-switcher.react.js b/web/sidebar/app-switcher.react.js
--- a/web/sidebar/app-switcher.react.js
+++ b/web/sidebar/app-switcher.react.js
@@ -1,11 +1,111 @@
// @flow
+import invariant from 'invariant';
import * as React from 'react';
+import { useDispatch } from 'react-redux';
+import {
+ mostRecentReadThreadSelector,
+ unreadCount,
+} from 'lib/selectors/thread-selectors';
+
+import { useSelector } from '../redux/redux-utils';
+import SWMansionIcon from '../SWMansionIcon.react';
+import { updateNavInfoActionType } from '../types/nav-types';
+import css from './left-layout-aside.css';
import NavigationPanel from './navigation-panel.react';
function AppSwitcher(): React.Node {
- return <NavigationPanel />;
+ const activeChatThreadID = useSelector(
+ state => state.navInfo.activeChatThreadID,
+ );
+ const mostRecentReadThread = useSelector(mostRecentReadThreadSelector);
+ const activeThreadCurrentlyUnread = useSelector(
+ state =>
+ !activeChatThreadID ||
+ !!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread,
+ );
+ const viewerID = useSelector(
+ state => state.currentUserInfo && state.currentUserInfo.id,
+ );
+
+ const dispatch = useDispatch();
+
+ const onClickCalendar = React.useCallback(
+ (event: SyntheticEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ dispatch({
+ type: updateNavInfoActionType,
+ payload: { tab: 'calendar' },
+ });
+ },
+ [dispatch],
+ );
+
+ const onClickChat = React.useCallback(
+ (event: SyntheticEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ dispatch({
+ type: updateNavInfoActionType,
+ payload: {
+ tab: 'chat',
+ activeChatThreadID: activeThreadCurrentlyUnread
+ ? mostRecentReadThread
+ : activeChatThreadID,
+ },
+ });
+ },
+ [
+ dispatch,
+ activeThreadCurrentlyUnread,
+ mostRecentReadThread,
+ activeChatThreadID,
+ ],
+ );
+
+ const boundUnreadCount = useSelector(unreadCount);
+
+ invariant(viewerID, 'should be set');
+ let chatBadge = null;
+ if (boundUnreadCount > 0) {
+ chatBadge = <div className={css.chatBadge}>{boundUnreadCount}</div>;
+ }
+
+ const chatNavigationItem = React.useMemo(
+ () => (
+ <p>
+ <span className={css.chatIconWrapper}>
+ <SWMansionIcon icon="message-square" size={24} />
+ {chatBadge}
+ </span>
+ <a onClick={onClickChat}>Chat</a>
+ </p>
+ ),
+ [chatBadge, onClickChat],
+ );
+
+ const calendarNavigationItem = React.useMemo(
+ () => (
+ <p>
+ <SWMansionIcon icon="calendar" size={24} />
+ <a onClick={onClickCalendar}>Calendar</a>
+ </p>
+ ),
+ [onClickCalendar],
+ );
+
+ const navigationItems = React.useMemo(
+ () => [
+ { tab: 'chat', link: chatNavigationItem },
+ {
+ tab: 'calendar',
+ link: calendarNavigationItem,
+ },
+ ],
+ [calendarNavigationItem, chatNavigationItem],
+ );
+
+ return <NavigationPanel navigationItems={navigationItems} />;
}
export default AppSwitcher;
diff --git a/web/sidebar/left-layout-aside.css b/web/sidebar/left-layout-aside.css
--- a/web/sidebar/left-layout-aside.css
+++ b/web/sidebar/left-layout-aside.css
@@ -57,12 +57,12 @@
line-height: 1.25;
}
-p.current-tab svg {
+li.current-tab svg {
color: var(--fg);
}
-p.current-tab a,
-p.current-tab svg {
+li.current-tab a,
+li.current-tab svg {
fill: var(--fg);
color: var(--fg);
}
diff --git a/web/sidebar/navigation-panel.react.js b/web/sidebar/navigation-panel.react.js
--- a/web/sidebar/navigation-panel.react.js
+++ b/web/sidebar/navigation-panel.react.js
@@ -1,103 +1,41 @@
// @flow
import classNames from 'classnames';
-import invariant from 'invariant';
import * as React from 'react';
-import { useDispatch } from 'react-redux';
-
-import {
- mostRecentReadThreadSelector,
- unreadCount,
-} from 'lib/selectors/thread-selectors';
import { useSelector } from '../redux/redux-utils';
-import SWMansionIcon from '../SWMansionIcon.react';
-import { updateNavInfoActionType } from '../types/nav-types';
+import type { NavigationTab } from '../types/nav-types';
import css from './left-layout-aside.css';
-function NavigationPanel(): React.Node {
- const activeChatThreadID = useSelector(
- state => state.navInfo.activeChatThreadID,
- );
- const navInfo = useSelector(state => state.navInfo);
- const mostRecentReadThread = useSelector(mostRecentReadThreadSelector);
- const activeThreadCurrentlyUnread = useSelector(
- state =>
- !activeChatThreadID ||
- !!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread,
- );
- const viewerID = useSelector(
- state => state.currentUserInfo && state.currentUserInfo.id,
- );
-
- const dispatch = useDispatch();
+type Props = {
+ +navigationItems: $ReadOnlyArray<{
+ +tab: NavigationTab,
+ +link: React.Node,
+ }>,
+};
- const onClickCalendar = React.useCallback(
- (event: SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- dispatch({
- type: updateNavInfoActionType,
- payload: { tab: 'calendar' },
- });
- },
- [dispatch],
- );
+function NavigationPanel(props: Props): React.Node {
+ const { navigationItems } = props;
+ const navInfo = useSelector(state => state.navInfo);
- const onClickChat = React.useCallback(
- (event: SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- dispatch({
- type: updateNavInfoActionType,
- payload: {
- tab: 'chat',
- activeChatThreadID: activeThreadCurrentlyUnread
- ? mostRecentReadThread
- : activeChatThreadID,
- },
- });
- },
- [
- dispatch,
- activeThreadCurrentlyUnread,
- mostRecentReadThread,
- activeChatThreadID,
- ],
+ const items = React.useMemo(
+ () =>
+ navigationItems.map(item => (
+ <li
+ key={item.tab}
+ className={classNames({
+ [css['current-tab']]: navInfo.tab === item.tab,
+ })}
+ >
+ {item.link}
+ </li>
+ )),
+ [navInfo.tab, navigationItems],
);
- const boundUnreadCount = useSelector(unreadCount);
-
- invariant(viewerID, 'should be set');
- let chatBadge = null;
- if (boundUnreadCount > 0) {
- chatBadge = <div className={css.chatBadge}>{boundUnreadCount}</div>;
- }
-
- const calendarNavClasses = classNames({
- [css['current-tab']]: navInfo.tab === 'calendar',
- });
- const chatNavClasses = classNames({
- [css['current-tab']]: navInfo.tab === 'chat',
- });
-
return (
<div className={css.navigationPanelContainer}>
- <ul>
- <li>
- <p className={chatNavClasses}>
- <span className={css.chatIconWrapper}>
- <SWMansionIcon icon="message-square" size={24} />
- {chatBadge}
- </span>
- <a onClick={onClickChat}>Chat</a>
- </p>
- </li>
- <li>
- <p className={calendarNavClasses}>
- <SWMansionIcon icon="calendar" size={24} />
- <a onClick={onClickCalendar}>Calendar</a>
- </p>
- </li>
- </ul>
+ <ul>{items}</ul>
</div>
);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Dec 8, 3:08 AM (17 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5846869
Default Alt Text
D3341.1765163280.diff (7 KB)
Attached To
Mode
D3341: [web] Make NavigationPanel reusable
Attached
Detach File
Event Timeline
Log In to Comment