Merge commit '0ef43a431d353a17419ea6664ed745b5dbfbf2f9' into glitch-soc/merge-upstream
This commit is contained in:
commit
60236bffe6
99 files changed
+2171
-1313
No files matched your search
@@ -6,7 +6,7 @@ import { defineMessages, useIntl } from 'react-intl';
|
||||
import { Combobox } from '@/mastodon/components/form_fields';
|
||||
import { useSearchTags } from '@/mastodon/hooks/useSearchTags';
|
||||
import type { TagSearchResult } from '@/mastodon/hooks/useSearchTags';
|
||||
import { addFeaturedTag } from '@/mastodon/reducers/slices/profile_edit';
|
||||
import { addFeaturedTags } from '@/mastodon/reducers/slices/profile_edit';
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||
|
||||
@@ -47,7 +47,7 @@ export const AccountEditTagSearch: FC = () => {
|
||||
(item: TagSearchResult) => {
|
||||
resetSearch();
|
||||
setQuery('');
|
||||
void dispatch(addFeaturedTag({ name: item.name }));
|
||||
void dispatch(addFeaturedTags({ names: [item.name] }));
|
||||
},
|
||||
[dispatch, resetSearch],
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
||||
import type { TagData } from '@/mastodon/reducers/slices/profile_edit';
|
||||
import {
|
||||
addFeaturedTag,
|
||||
addFeaturedTags,
|
||||
deleteFeaturedTag,
|
||||
fetchProfile,
|
||||
fetchSuggestedTags,
|
||||
@@ -128,7 +128,7 @@ const SuggestedTag: FC<{ name: string; disabled?: boolean }> = ({
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const handleAddTag = useCallback(() => {
|
||||
void dispatch(addFeaturedTag({ name }));
|
||||
void dispatch(addFeaturedTags({ names: [name] }));
|
||||
}, [dispatch, name]);
|
||||
return <Tag name={name} onClick={handleAddTag} disabled={disabled} />;
|
||||
};
|
||||
@@ -18,7 +18,10 @@ import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { RemoteHint } from '@/mastodon/components/remote_hint';
|
||||
import StatusList from '@/mastodon/components/status_list';
|
||||
import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error';
|
||||
import { useAccountId } from '@/mastodon/hooks/useAccountId';
|
||||
import {
|
||||
useAccountId,
|
||||
useCurrentAccountId,
|
||||
} from '@/mastodon/hooks/useAccountId';
|
||||
import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility';
|
||||
import { selectTimelineByKey } from '@/mastodon/selectors/timelines';
|
||||
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
||||
@@ -34,6 +37,7 @@ import {
|
||||
usePinnedStatusIds,
|
||||
} from './pinned_statuses';
|
||||
import classes from './styles.module.scss';
|
||||
import { TagSuggestions } from './tags_suggestions';
|
||||
|
||||
const emptyList = ImmutableList<string>();
|
||||
|
||||
@@ -135,6 +139,7 @@ const Prepend: FC<{
|
||||
accountId: string;
|
||||
forceEmpty: boolean;
|
||||
}> = ({ forceEmpty, accountId }) => {
|
||||
const me = useCurrentAccountId();
|
||||
if (forceEmpty) {
|
||||
return <AccountHeader accountId={accountId} hideTabs />;
|
||||
}
|
||||
@@ -144,6 +149,7 @@ const Prepend: FC<{
|
||||
<AccountHeader accountId={accountId} hideTabs />
|
||||
<AccountFilters />
|
||||
<FeaturedTags accountId={accountId} />
|
||||
{me === accountId && <TagSuggestions />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -49,8 +49,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tagsWrapper {
|
||||
.tagsWrapper,
|
||||
.tagSuggestions {
|
||||
margin: 0 24px 8px;
|
||||
}
|
||||
|
||||
.tagsWrapper {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
import type { FC } from 'react';
|
||||
import { useEffect, useCallback, useState } from 'react';
|
||||
|
||||
import { FormattedMessage, FormattedList } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { fetchFeaturedTags } from '@/mastodon/actions/featured_tags';
|
||||
import { Callout } from '@/mastodon/components/callout';
|
||||
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
||||
import { useDismissible } from '@/mastodon/hooks/useDismissible';
|
||||
import {
|
||||
fetchProfile,
|
||||
fetchSuggestedTags,
|
||||
addFeaturedTags,
|
||||
} from '@/mastodon/reducers/slices/profile_edit';
|
||||
import { useAppSelector, useAppDispatch } from '@/mastodon/store';
|
||||
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
const MAX_SUGGESTED_TAGS = 3;
|
||||
|
||||
export const TagSuggestions: FC = () => {
|
||||
const { dismiss, wasDismissed } = useDismissible(
|
||||
'profile/featured_tag_suggestions',
|
||||
);
|
||||
|
||||
const suggestedTags = useAppSelector((state) =>
|
||||
state.profileEdit.tagSuggestions?.slice(0, MAX_SUGGESTED_TAGS),
|
||||
);
|
||||
const existingTagCount = useAppSelector(
|
||||
(state) => state.profileEdit.profile?.featuredTags.length,
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const isLoading = !suggestedTags || existingTagCount === undefined;
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) {
|
||||
void dispatch(fetchProfile());
|
||||
void dispatch(fetchSuggestedTags());
|
||||
}
|
||||
}, [dispatch, isLoading]);
|
||||
|
||||
const me = useCurrentAccountId();
|
||||
const [showSuccessNotice, setSuccessNotice] = useState(false);
|
||||
|
||||
const handleAdd = useCallback(() => {
|
||||
if (!suggestedTags?.length || !me) {
|
||||
return;
|
||||
}
|
||||
|
||||
const addTags = async () => {
|
||||
await dispatch(
|
||||
addFeaturedTags({ names: suggestedTags.map((tag) => tag.name) }),
|
||||
);
|
||||
await dispatch(fetchFeaturedTags({ accountId: me }));
|
||||
setSuccessNotice(true);
|
||||
dismiss();
|
||||
};
|
||||
void addTags();
|
||||
}, [dismiss, dispatch, me, suggestedTags]);
|
||||
|
||||
const handleDismissSuccessNotice = useCallback(() => {
|
||||
setSuccessNotice(false);
|
||||
}, []);
|
||||
|
||||
if (showSuccessNotice) {
|
||||
return (
|
||||
<Callout
|
||||
variant='subtle'
|
||||
className={classes.tagSuggestions}
|
||||
onClose={handleDismissSuccessNotice}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='featured_tags.suggestions.added'
|
||||
defaultMessage='Manage your featured hashtags at any time under <link>Edit Profile > Featured hashtags</link>.'
|
||||
values={{
|
||||
link: (chunks) => <Link to='/profile/featured_tags'>{chunks}</Link>,
|
||||
}}
|
||||
/>
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
isLoading ||
|
||||
!suggestedTags.length ||
|
||||
existingTagCount > 0 ||
|
||||
wasDismissed
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Callout
|
||||
id='featured_tags.suggestions'
|
||||
variant='subtle'
|
||||
className={classes.tagSuggestions}
|
||||
onPrimary={handleAdd}
|
||||
primaryLabel={
|
||||
<FormattedMessage
|
||||
id='featured_tags.suggestions.add'
|
||||
defaultMessage='Add'
|
||||
/>
|
||||
}
|
||||
onSecondary={dismiss}
|
||||
secondaryLabel={
|
||||
<FormattedMessage
|
||||
id='featured_tags.suggestions.dismiss'
|
||||
defaultMessage='No thanks'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='featured_tags.suggestions'
|
||||
defaultMessage='Lately you’ve posted about {items}. Add these as featured hashtags?'
|
||||
values={{
|
||||
items: (
|
||||
<FormattedList
|
||||
value={suggestedTags.map(({ name }) => `#${name}`)}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Callout>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,4 @@
|
||||
import { EMOJI_DB_NAME_SHORTCODES, EMOJI_TYPE_CUSTOM } from './constants';
|
||||
import {
|
||||
importCustomEmojiData,
|
||||
importEmojiData,
|
||||
importLegacyShortcodes,
|
||||
} from './loader';
|
||||
|
||||
addEventListener('message', handleMessage);
|
||||
self.postMessage('ready'); // After the worker is ready, notify the main thread
|
||||
@@ -16,6 +11,8 @@ function handleMessage(event: MessageEvent<{ locale: string }>) {
|
||||
}
|
||||
|
||||
async function loadData(locale: string) {
|
||||
const { importCustomEmojiData, importEmojiData, importLegacyShortcodes } =
|
||||
await import('./loader');
|
||||
let importCount: number | undefined;
|
||||
if (locale === EMOJI_TYPE_CUSTOM) {
|
||||
importCount = (await importCustomEmojiData())?.length;
|
||||
|
||||
Reference in new issue
Block a user