Merge pull request #117 from cheeaun/main

Update from main
This commit is contained in:
Chee Aun 2023-04-26 15:36:11 +08:00 committed by GitHub
commit d0cbb0812d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 223 additions and 200 deletions

View file

@ -1,185 +0,0 @@
import { Menu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { useLongPress } from 'use-long-press';
import { useSnapshot } from 'valtio';
import { api } from '../utils/api';
import states from '../utils/states';
import store from '../utils/store';
import Avatar from './avatar';
import Icon from './icon';
import MenuLink from './menu-link';
function NavMenu(props) {
const snapStates = useSnapshot(states);
const { instance, authenticated } = api();
const accounts = store.local.getJSON('accounts') || [];
const currentAccount = accounts.find(
(account) => account.info.id === store.session.get('currentAccount'),
);
const moreThanOneAccount = accounts.length > 1;
// Home = Following
// But when in multi-column mode, Home becomes columns of anything
// User may choose pin or not to pin Following
// If user doesn't pin Following, we show it in the menu
const showFollowing =
(snapStates.settings.shortcutsColumnsMode ||
snapStates.settings.shortcutsViewMode === 'multi-column') &&
!snapStates.shortcuts.find((pin) => pin.type === 'following');
const bindLongPress = useLongPress(
() => {
states.showAccounts = true;
},
{
threshold: 600,
detect: 'touch',
cancelOnMovement: true,
},
);
return (
<Menu
portal={{
target: document.body,
}}
{...props}
overflow="auto"
viewScroll="close"
boundingBoxPadding="8 8 8 8"
menuButton={({ open }) => (
<button
type="button"
class={`button plain nav-menu-button ${
moreThanOneAccount ? 'with-avatar' : ''
} ${open ? 'active' : ''}`}
style={{ position: 'relative' }}
onContextMenu={(e) => {
e.preventDefault();
states.showAccounts = true;
}}
{...bindLongPress()}
>
{moreThanOneAccount && (
<Avatar
url={
currentAccount?.info?.avatar ||
currentAccount?.info?.avatarStatic
}
size="l"
squircle={currentAccount?.info?.bot}
/>
)}
<Icon icon="menu" size={moreThanOneAccount ? 's' : 'l'} />
</button>
)}
>
{!!snapStates.appVersion?.commitHash &&
__COMMIT_HASH__ !== snapStates.appVersion.commitHash && (
<>
<MenuItem
onClick={() => {
const yes = confirm('Reload page now to update?');
if (yes) {
(async () => {
try {
location.reload();
} catch (e) {}
})();
}
}}
>
<Icon icon="sparkles" size="l" />{' '}
<span>New update available</span>
</MenuItem>
<MenuDivider />
</>
)}
<MenuLink to="/">
<Icon icon="home" size="l" /> <span>Home</span>
</MenuLink>
{authenticated && (
<>
{showFollowing && (
<MenuLink to="/following">
<Icon icon="following" size="l" /> <span>Following</span>
</MenuLink>
)}
<MenuLink to="/mentions">
<Icon icon="at" size="l" /> <span>Mentions</span>
</MenuLink>
<MenuLink to="/notifications">
<Icon icon="notification" size="l" /> <span>Notifications</span>
{snapStates.notificationsShowNew && (
<sup title="New" style={{ opacity: 0.5 }}>
{' '}
&bull;
</sup>
)}
</MenuLink>
<MenuDivider />
<MenuLink to="/l">
<Icon icon="list" size="l" /> <span>Lists</span>
</MenuLink>
<MenuLink to="/ft">
<Icon icon="hashtag" size="l" /> <span>Followed Hashtags</span>
</MenuLink>
<MenuLink to="/b">
<Icon icon="bookmark" size="l" /> <span>Bookmarks</span>
</MenuLink>
<MenuLink to="/f">
<Icon icon="heart" size="l" /> <span>Favourites</span>
</MenuLink>
</>
)}
<MenuDivider />
<MenuLink to={`/search`}>
<Icon icon="search" size="l" /> <span>Search</span>
</MenuLink>
<MenuLink to={`/${instance}/p/l`}>
<Icon icon="group" size="l" /> <span>Local</span>
</MenuLink>
<MenuLink to={`/${instance}/p`}>
<Icon icon="earth" size="l" /> <span>Federated</span>
</MenuLink>
<MenuLink to={`/${instance}/trending`}>
<Icon icon="chart" size="l" /> <span>Trending</span>
</MenuLink>
{authenticated && (
<>
<MenuDivider />
{currentAccount?.info?.id && (
<MenuLink to={`/${instance}/a/${currentAccount.info.id}`}>
<Icon icon="user" size="l" /> <span>Profile</span>
</MenuLink>
)}
<MenuItem
onClick={() => {
states.showAccounts = true;
}}
>
<Icon icon="group" size="l" /> <span>Accounts&hellip;</span>
</MenuItem>
<MenuItem
onClick={() => {
states.showShortcutsSettings = true;
}}
>
<Icon icon="shortcut" size="l" />{' '}
<span>Shortcuts Settings&hellip;</span>
</MenuItem>
<MenuItem
onClick={() => {
states.showSettings = true;
}}
>
<Icon icon="gear" size="l" /> <span>Settings&hellip;</span>
</MenuItem>
</>
)}
</Menu>
);
}
export default NavMenu;

208
src/components/nav-menu.jsx Normal file
View file

@ -0,0 +1,208 @@
import {
ControlledMenu,
MenuDivider,
MenuItem,
useClick,
useMenuState,
} from '@szhsin/react-menu';
import { useRef } from 'preact/hooks';
import { useLongPress } from 'use-long-press';
import { useSnapshot } from 'valtio';
import { api } from '../utils/api';
import states from '../utils/states';
import store from '../utils/store';
import Avatar from './avatar';
import Icon from './icon';
import MenuLink from './menu-link';
function NavMenu(props) {
const snapStates = useSnapshot(states);
const { instance, authenticated } = api();
const accounts = store.local.getJSON('accounts') || [];
const currentAccount = accounts.find(
(account) => account.info.id === store.session.get('currentAccount'),
);
const moreThanOneAccount = accounts.length > 1;
// Home = Following
// But when in multi-column mode, Home becomes columns of anything
// User may choose pin or not to pin Following
// If user doesn't pin Following, we show it in the menu
const showFollowing =
(snapStates.settings.shortcutsColumnsMode ||
snapStates.settings.shortcutsViewMode === 'multi-column') &&
!snapStates.shortcuts.find((pin) => pin.type === 'following');
const bindLongPress = useLongPress(
() => {
states.showAccounts = true;
},
{
threshold: 600,
detect: 'touch',
cancelOnMovement: true,
},
);
const buttonRef = useRef();
const [menuState, toggleMenu] = useMenuState();
const anchorProps = useClick(menuState.state, toggleMenu);
return (
<>
<button
ref={buttonRef}
type="button"
class={`button plain nav-menu-button ${
moreThanOneAccount ? 'with-avatar' : ''
} ${open ? 'active' : ''}`}
style={{ position: 'relative' }}
{...anchorProps}
onContextMenu={(e) => {
e.preventDefault();
states.showAccounts = true;
}}
{...bindLongPress()}
>
{moreThanOneAccount && (
<Avatar
url={
currentAccount?.info?.avatar || currentAccount?.info?.avatarStatic
}
size="l"
squircle={currentAccount?.info?.bot}
/>
)}
<Icon icon="menu" size={moreThanOneAccount ? 's' : 'l'} />
</button>
<ControlledMenu
{...menuState}
anchorRef={buttonRef}
onClose={() => {
toggleMenu(false);
}}
containerProps={{
onClick: () => {
toggleMenu(false);
},
}}
portal={{
target: document.body,
}}
{...props}
overflow="auto"
viewScroll="close"
boundingBoxPadding="8 8 8 8"
unmountOnClose
>
{!!snapStates.appVersion?.commitHash &&
__COMMIT_HASH__ !== snapStates.appVersion.commitHash && (
<>
<MenuItem
onClick={() => {
const yes = confirm('Reload page now to update?');
if (yes) {
(async () => {
try {
location.reload();
} catch (e) {}
})();
}
}}
>
<Icon icon="sparkles" size="l" />{' '}
<span>New update available</span>
</MenuItem>
<MenuDivider />
</>
)}
<MenuLink to="/">
<Icon icon="home" size="l" /> <span>Home</span>
</MenuLink>
{authenticated && (
<>
{showFollowing && (
<MenuLink to="/following">
<Icon icon="following" size="l" /> <span>Following</span>
</MenuLink>
)}
<MenuLink to="/mentions">
<Icon icon="at" size="l" /> <span>Mentions</span>
</MenuLink>
<MenuLink to="/notifications">
<Icon icon="notification" size="l" /> <span>Notifications</span>
{snapStates.notificationsShowNew && (
<sup title="New" style={{ opacity: 0.5 }}>
{' '}
&bull;
</sup>
)}
</MenuLink>
<MenuDivider />
<MenuLink to="/l">
<Icon icon="list" size="l" /> <span>Lists</span>
</MenuLink>
<MenuLink to="/ft">
<Icon icon="hashtag" size="l" /> <span>Followed Hashtags</span>
</MenuLink>
<MenuLink to="/b">
<Icon icon="bookmark" size="l" /> <span>Bookmarks</span>
</MenuLink>
<MenuLink to="/f">
<Icon icon="heart" size="l" /> <span>Favourites</span>
</MenuLink>
</>
)}
<MenuDivider />
<MenuLink to={`/search`}>
<Icon icon="search" size="l" /> <span>Search</span>
</MenuLink>
<MenuLink to={`/${instance}/p/l`}>
<Icon icon="group" size="l" /> <span>Local</span>
</MenuLink>
<MenuLink to={`/${instance}/p`}>
<Icon icon="earth" size="l" /> <span>Federated</span>
</MenuLink>
<MenuLink to={`/${instance}/trending`}>
<Icon icon="chart" size="l" /> <span>Trending</span>
</MenuLink>
{authenticated && (
<>
<MenuDivider />
{currentAccount?.info?.id && (
<MenuLink to={`/${instance}/a/${currentAccount.info.id}`}>
<Icon icon="user" size="l" /> <span>Profile</span>
</MenuLink>
)}
<MenuItem
onClick={() => {
states.showAccounts = true;
}}
>
<Icon icon="group" size="l" /> <span>Accounts&hellip;</span>
</MenuItem>
<MenuItem
onClick={() => {
states.showShortcutsSettings = true;
}}
>
<Icon icon="shortcut" size="l" />{' '}
<span>Shortcuts Settings&hellip;</span>
</MenuItem>
<MenuItem
onClick={() => {
states.showSettings = true;
}}
>
<Icon icon="gear" size="l" /> <span>Settings&hellip;</span>
</MenuItem>
</>
)}
</ControlledMenu>
</>
);
}
export default NavMenu;

View file

@ -679,6 +679,8 @@ function Status({
},
);
const showContextMenu = size !== 'l' && !previewMode && !_deleted;
return (
<article
ref={statusRef}
@ -694,10 +696,8 @@ function Status({
} ${_deleted ? 'status-deleted' : ''} ${quoted ? 'status-card' : ''}`}
onMouseEnter={debugHover}
onContextMenu={(e) => {
if (size === 'l') return;
if (!showContextMenu) return;
if (e.metaKey) return;
if (previewMode) return;
if (_deleted) return;
// console.log('context menu', e);
const link = e.target.closest('a');
if (link && /^https?:\/\//.test(link.getAttribute('href'))) return;
@ -708,9 +708,9 @@ function Status({
});
setIsContextMenuOpen(true);
}}
{...bindLongPress()}
{...(showContextMenu ? bindLongPress() : {})}
>
{size !== 'l' && (
{showContextMenu && (
<ControlledMenu
ref={contextMenuRef}
state={isContextMenuOpen ? 'open' : undefined}

View file

@ -14,7 +14,7 @@ import useScroll from '../utils/useScroll';
import Icon from './icon';
import Link from './link';
import Loader from './loader';
import Menu from './menu';
import NavMenu from './nav-menu';
import Status from './status';
function Timeline({
@ -275,7 +275,7 @@ function Timeline({
>
<div class="header-grid">
<div class="header-side">
<Menu />
<NavMenu />
{headerStart !== null && headerStart !== undefined ? (
headerStart
) : (

View file

@ -3,7 +3,7 @@ import { useEffect, useState } from 'preact/hooks';
import Icon from '../components/icon';
import Link from '../components/link';
import Loader from '../components/loader';
import Menu from '../components/menu';
import NavMenu from '../components/nav-menu';
import { api } from '../utils/api';
import useTitle from '../utils/useTitle';
@ -45,7 +45,7 @@ function FollowedHashtags() {
<header>
<div class="header-grid">
<div class="header-side">
<Menu />
<NavMenu />
<Link to="/" class="button plain">
<Icon icon="home" size="l" />
</Link>

View file

@ -6,8 +6,8 @@ import Icon from '../components/icon';
import Link from '../components/link';
import ListAddEdit from '../components/list-add-edit';
import Loader from '../components/loader';
import Menu from '../components/menu';
import Modal from '../components/modal';
import NavMenu from '../components/nav-menu';
import { api } from '../utils/api';
import useTitle from '../utils/useTitle';
@ -41,7 +41,7 @@ function Lists() {
<header>
<div class="header-grid">
<div class="header-side">
<Menu />
<NavMenu />
<Link to="/" class="button plain">
<Icon icon="home" size="l" />
</Link>

View file

@ -8,8 +8,8 @@ import Avatar from '../components/avatar';
import Icon from '../components/icon';
import Link from '../components/link';
import Loader from '../components/loader';
import Menu from '../components/menu';
import NameText from '../components/name-text';
import NavMenu from '../components/nav-menu';
import RelativeTime from '../components/relative-time';
import Status from '../components/status';
import { api } from '../utils/api';
@ -166,7 +166,7 @@ function Notifications() {
>
<div class="header-grid">
<div class="header-side">
<Menu />
<NavMenu />
<Link to="/" class="button plain">
<Icon icon="home" size="l" alt="Home" />
</Link>

View file

@ -7,7 +7,7 @@ import AccountBlock from '../components/account-block';
import Icon from '../components/icon';
import Link from '../components/link';
import Loader from '../components/loader';
import Menu from '../components/menu';
import NavMenu from '../components/nav-menu';
import Status from '../components/status';
import { api } from '../utils/api';
import useTitle from '../utils/useTitle';
@ -53,7 +53,7 @@ function Search(props) {
<header>
<div class="header-grid">
<div class="header-side">
<Menu />
<NavMenu />
</div>
<form
onSubmit={(e) => {