Left Menu: Add Telegram Features, Report Bug and app info items

This commit is contained in:
Alexander Zinchuk 2021-04-14 00:30:23 +03:00
parent 47edc22f9a
commit 2499a4ca95
16 changed files with 229 additions and 148 deletions

View File

@ -7,7 +7,7 @@
"dev": "cross-env APP_ENV=development webpack-dev-server -d", "dev": "cross-env APP_ENV=development webpack-dev-server -d",
"build": "webpack -p", "build": "webpack -p",
"build:staging": "rm -rf dist/ && APP_ENV=staging npm run build && ./deploy/copy_to_dist.sh", "build:staging": "rm -rf dist/ && APP_ENV=staging npm run build && ./deploy/copy_to_dist.sh",
"build:production": "rm -rf dist/ && APP_ENV=production npm run build -- --env.noSourceMap && ./deploy/copy_to_dist.sh", "build:production": "rm -rf dist/ && APP_INFO=\"Telegram WebZ alpha $(git rev-parse --short HEAD)\" APP_ENV=production npm run build -- --env.noSourceMap && ./deploy/copy_to_dist.sh",
"deploy:contest": "./deploy/contest.sh", "deploy:contest": "./deploy/contest.sh",
"perf:serve": "APP_ENV=perf parcel src/index-perf.html", "perf:serve": "APP_ENV=perf parcel src/index-perf.html",
"lint": "eslint . --ext .ts,.tsx", "lint": "eslint . --ext .ts,.tsx",

BIN
src/assets/fonts/icomoon.woff Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -57,6 +57,10 @@
flex-shrink: 0; flex-shrink: 0;
} }
.Menu .bubble {
min-width: 17rem;
}
// @optimization // @optimization
@include while-transition() { @include while-transition() {
.Menu .bubble { .Menu .bubble {

View File

@ -7,6 +7,7 @@ import { GlobalActions } from '../../../global/types';
import { LeftColumnContent, ISettings } from '../../../types'; import { LeftColumnContent, ISettings } from '../../../types';
import { ApiChat } from '../../../api/types'; import { ApiChat } from '../../../api/types';
import { APP_INFO, FEEDBACK_URL } from '../../../config';
import { IS_MOBILE_SCREEN } from '../../../util/environment'; import { IS_MOBILE_SCREEN } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { pick } from '../../../util/iteratees'; import { pick } from '../../../util/iteratees';
@ -45,8 +46,9 @@ type StateProps = {
chatsById?: Record<number, ApiChat>; chatsById?: Record<number, ApiChat>;
}; };
type DispatchProps = Pick<GlobalActions, type DispatchProps = Pick<GlobalActions, (
'openChat'| 'openSupportChat' | 'setGlobalSearchDate' | 'setGlobalSearchChatId' | 'setSettingOption'>; 'openChat' | 'openTipsChat' | 'setGlobalSearchDate' | 'setGlobalSearchChatId' | 'setSettingOption'
)>;
const ANIMATION_LEVEL_OPTIONS = [0, 1, 2]; const ANIMATION_LEVEL_OPTIONS = [0, 1, 2];
@ -68,7 +70,7 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
animationLevel, animationLevel,
chatsById, chatsById,
openChat, openChat,
openSupportChat, openTipsChat,
setGlobalSearchDate, setGlobalSearchDate,
setSettingOption, setSettingOption,
}) => { }) => {
@ -144,9 +146,11 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
const lang = useLang(); const lang = useLang();
const isSearchFocused = Boolean(globalSearchChatId) const isSearchFocused = (
|| content === LeftColumnContent.GlobalSearch Boolean(globalSearchChatId)
|| content === LeftColumnContent.Contacts; || content === LeftColumnContent.GlobalSearch
|| content === LeftColumnContent.Contacts
);
const searchInputPlaceholder = content === LeftColumnContent.Contacts const searchInputPlaceholder = content === LeftColumnContent.Contacts
? lang('SearchFriends') ? lang('SearchFriends')
@ -157,6 +161,7 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
<div id="LeftMainHeader" className="left-header"> <div id="LeftMainHeader" className="left-header">
<DropdownMenu <DropdownMenu
trigger={MainButton} trigger={MainButton}
footer={APP_INFO}
> >
<MenuItem <MenuItem
icon="saved-messages" icon="saved-messages"
@ -209,9 +214,15 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
</MenuItem> </MenuItem>
<MenuItem <MenuItem
icon="help" icon="help"
onClick={openSupportChat} onClick={openTipsChat}
> >
{lang('BotHelp')} Telegram Features
</MenuItem>
<MenuItem
icon="bug"
href={FEEDBACK_URL}
>
Report Bug
</MenuItem> </MenuItem>
</DropdownMenu> </DropdownMenu>
<SearchInput <SearchInput
@ -273,7 +284,7 @@ export default memo(withGlobal<OwnProps>(
}, },
(setGlobal, actions): DispatchProps => pick(actions, [ (setGlobal, actions): DispatchProps => pick(actions, [
'openChat', 'openChat',
'openSupportChat', 'openTipsChat',
'setGlobalSearchDate', 'setGlobalSearchDate',
'setGlobalSearchChatId', 'setGlobalSearchChatId',
'setSettingOption', 'setSettingOption',

View File

@ -9,17 +9,18 @@ type OwnProps = {
trigger: FC<{ onTrigger: () => void; isOpen?: boolean }>; trigger: FC<{ onTrigger: () => void; isOpen?: boolean }>;
positionX?: 'left' | 'right'; positionX?: 'left' | 'right';
positionY?: 'top' | 'bottom'; positionY?: 'top' | 'bottom';
footer?: string;
children: any; children: any;
}; };
const DropdownMenu: FC<OwnProps> = (props) => { const DropdownMenu: FC<OwnProps> = ({
const { trigger,
trigger, className,
className, children,
children, positionX = 'left',
positionX = 'left', positionY = 'top',
positionY = 'top', footer,
} = props; }) => {
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const menuRef = useRef<HTMLDivElement>(null); const menuRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
@ -64,6 +65,7 @@ const DropdownMenu: FC<OwnProps> = (props) => {
className={className || ''} className={className || ''}
positionX={positionX} positionX={positionX}
positionY={positionY} positionY={positionY}
footer={footer}
autoClose autoClose
onClose={handleClose} onClose={handleClose}
> >

View File

@ -14,6 +14,7 @@
} }
.bubble { .bubble {
overflow: hidden;
display: block; display: block;
list-style: none; list-style: none;
padding: 0.5rem 0; padding: 0.5rem 0;
@ -63,5 +64,17 @@
&.right { &.right {
right: var(--offset-x); right: var(--offset-x);
} }
&.with-footer {
padding-bottom: 0;
}
}
.footer {
padding: 0.5rem 0;
background: #F4F4F5;
color: var(--color-text-secondary);
font-size: 0.8125rem;
text-align: center;
} }
} }

View File

@ -20,6 +20,7 @@ type OwnProps = {
positionX?: 'left' | 'right'; positionX?: 'left' | 'right';
positionY?: 'top' | 'bottom'; positionY?: 'top' | 'bottom';
autoClose?: boolean; autoClose?: boolean;
footer?: string;
noCloseOnBackdrop?: boolean; noCloseOnBackdrop?: boolean;
onKeyDown?: (e: React.KeyboardEvent<any>) => void; onKeyDown?: (e: React.KeyboardEvent<any>) => void;
onCloseAnimationEnd?: () => void; onCloseAnimationEnd?: () => void;
@ -41,6 +42,7 @@ const Menu: FC<OwnProps> = ({
positionX = 'left', positionX = 'left',
positionY = 'top', positionY = 'top',
autoClose = false, autoClose = false,
footer,
noCloseOnBackdrop = false, noCloseOnBackdrop = false,
onCloseAnimationEnd, onCloseAnimationEnd,
onClose, onClose,
@ -72,6 +74,14 @@ const Menu: FC<OwnProps> = ({
noCloseOnBackdrop ? undefined : onClose, noCloseOnBackdrop ? undefined : onClose,
); );
const bubbleClassName = buildClassName(
'bubble menu-container custom-scroll',
positionY,
positionX,
footer && 'with-footer',
transitionClassNames,
);
return ( return (
<div <div
className={buildClassName('Menu no-selection', className)} className={buildClassName('Menu no-selection', className)}
@ -87,12 +97,13 @@ const Menu: FC<OwnProps> = ({
)} )}
<div <div
ref={menuRef} ref={menuRef}
className={buildClassName('bubble menu-container custom-scroll', positionY, positionX, transitionClassNames)} className={bubbleClassName}
// @ts-ignore teact feature // @ts-ignore teact feature
style={`transform-origin: ${positionY} ${positionX}`} style={`transform-origin: ${positionY} ${positionX}`}
onClick={autoClose ? onClose : undefined} onClick={autoClose ? onClose : undefined}
> >
{children} {children}
{footer && <div className="footer">{footer}</div>}
</div> </div>
</div> </div>
); );

View File

@ -16,6 +16,8 @@
&:hover, &:focus { &:hover, &:focus {
background-color: var(--color-chat-hover); background-color: var(--color-chat-hover);
text-decoration: none;
color: inherit;
} }
i { i {

View File

@ -82,6 +82,8 @@ const MenuItem: FC<OwnProps> = (props) => {
download={download} download={download}
aria-label={ariaLabel} aria-label={ariaLabel}
title={ariaLabel} title={ariaLabel}
target="_blank"
rel="noopener noreferrer"
> >
{content} {content}
</a> </a>

View File

@ -1,3 +1,5 @@
export const APP_INFO = process.env.APP_INFO || 'Telegram T';
export const DEBUG = ( export const DEBUG = (
process.env.APP_ENV !== 'production' && process.env.APP_ENV !== 'perf' && process.env.APP_ENV !== 'test' process.env.APP_ENV !== 'production' && process.env.APP_ENV !== 'perf' && process.env.APP_ENV !== 'test'
); );
@ -115,3 +117,5 @@ export const MAX_ACTIVE_PINNED_CHATS = 5;
export const SCHEDULED_WHEN_ONLINE = 0x7FFFFFFE; export const SCHEDULED_WHEN_ONLINE = 0x7FFFFFFE;
export const DEFAULT_LANG_PACK = 'android'; export const DEFAULT_LANG_PACK = 'android';
export const LANG_PACKS = ['android', 'ios']; export const LANG_PACKS = ['android', 'ios'];
export const TIPS_USERNAME = 'TelegramTips';
export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time';

View File

@ -385,7 +385,8 @@ export type ActionTypes = (
'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' | 'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' |
'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'gotToAuthQrCode' | 'clearCache' | 'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'gotToAuthQrCode' | 'clearCache' |
// chats // chats
'preloadTopChatMessages' | 'loadChats' | 'loadMoreChats' | 'openChat' | 'openChatWithInfo' | 'openSupportChat' | 'preloadTopChatMessages' | 'loadChats' | 'loadMoreChats' | 'openChat' | 'openChatWithInfo' |
'openSupportChat' | 'openTipsChat' |
'loadFullChat' | 'loadSuperGroupOnlines' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' | 'loadFullChat' | 'loadSuperGroupOnlines' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' |
'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' | 'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' |
'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' | 'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' |

View File

@ -13,8 +13,9 @@ import {
TOP_CHAT_MESSAGES_PRELOAD_LIMIT, TOP_CHAT_MESSAGES_PRELOAD_LIMIT,
CHAT_LIST_LOAD_SLICE, CHAT_LIST_LOAD_SLICE,
RE_TME_LINK, RE_TME_LINK,
TIPS_USERNAME,
} from '../../../config'; } from '../../../config';
import { IS_TOUCH_ENV } from '../../../util/environment';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
import { import {
addChats, addChats,
@ -43,7 +44,6 @@ import { debounce, pause, throttle } from '../../../util/schedulers';
import { import {
isChatSummaryOnly, isChatArchived, prepareChatList, isChatBasicGroup, isChatSummaryOnly, isChatArchived, prepareChatList, isChatBasicGroup,
} from '../../helpers'; } from '../../helpers';
import { IS_TOUCH_ENV } from '../../../util/environment';
const TOP_CHATS_PRELOAD_PAUSE = 200; const TOP_CHATS_PRELOAD_PAUSE = 200;
// We expect this ID does not exist // We expect this ID does not exist
@ -136,6 +136,10 @@ addReducer('openSupportChat', (global, actions) => {
})(); })();
}); });
addReducer('openTipsChat', (global, actions) => {
actions.openChatByUsername({ username: TIPS_USERNAME });
});
addReducer('loadMoreChats', (global, actions, payload) => { addReducer('loadMoreChats', (global, actions, payload) => {
const { listType = 'active' } = payload!; const { listType = 'active' } = payload!;
const listIds = global.chats.listIds[listType as ('active' | 'archived')]; const listIds = global.chats.listIds[listType as ('active' | 'archived')];

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,9 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-bug:before {
content: "\e97d";
}
.icon-darkmode:before { .icon-darkmode:before {
content: "\e979"; content: "\e979";
} }

View File

@ -103,6 +103,7 @@ module.exports = (env = {}, argv = {}) => {
ignoreOrder: true, ignoreOrder: true,
}), }),
new EnvironmentPlugin({ new EnvironmentPlugin({
APP_INFO: 'Telegram T',
APP_ENV: 'production', APP_ENV: 'production',
TELEGRAM_T_API_ID: '', TELEGRAM_T_API_ID: '',
TELEGRAM_T_API_HASH: '', TELEGRAM_T_API_HASH: '',