diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index a713f5957f..634daf363d 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -589,7 +589,7 @@ class Status extends ImmutablePureComponent { } data-id={status.get('id')} > - {(connectReply || connectUp || connectToRoot) &&
} + {(connectUp || connectToRoot) &&
}
@@ -600,15 +600,14 @@ class Status extends ImmutablePureComponent { {status.get('edited_at') && *} - -
- {statusAvatar} -
+ +
+ {statusAvatar} +
- - -
- )} + + +
{matchedFilters && } diff --git a/app/javascript/mastodon/features/compose/components/action_bar.tsx b/app/javascript/mastodon/features/compose/components/action_bar.tsx index 7971f5db10..41f706d091 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.tsx +++ b/app/javascript/mastodon/features/compose/components/action_bar.tsx @@ -71,6 +71,10 @@ export const ActionBar: React.FC = () => { text: intl.formatMessage(messages.emoji_reactions), to: '/emoji_reactions', }, + { + text: intl.formatMessage(messages.reaction_deck), + to: '/reaction_deck', + }, { text: intl.formatMessage(messages.lists), to: '/lists' }, { text: intl.formatMessage(messages.followed_tags), diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx index 48a05e2f5b..c5e8998c90 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx @@ -10,10 +10,10 @@ import { navigateToStatus } from 'mastodon/actions/statuses'; import { Avatar } from 'mastodon/components/avatar'; import { AvatarGroup } from 'mastodon/components/avatar_group'; import EmojiView from 'mastodon/components/emoji_view'; -import type { EmojiReactionGroup } from 'mastodon/models/notification_group'; import type { IconProp } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; +import type { EmojiReactionGroup } from 'mastodon/models/notification_group'; import { NOTIFICATIONS_GROUP_MAX_AVATARS } from 'mastodon/models/notification_group'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; diff --git a/app/javascript/mastodon/features/reaction_deck/index.tsx b/app/javascript/mastodon/features/reaction_deck/index.tsx index 1c4903964b..945f884caf 100644 --- a/app/javascript/mastodon/features/reaction_deck/index.tsx +++ b/app/javascript/mastodon/features/reaction_deck/index.tsx @@ -5,12 +5,36 @@ @typescript-eslint/no-unsafe-assignment */ import type { ReactNode } from 'react'; -import { useCallback } from 'react'; +import { useState, useCallback } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { Helmet } from 'react-helmet'; +import type { + DragStartEvent, + DragEndEvent, + UniqueIdentifier, + // Announcements, + // ScreenReaderInstructions, +} from '@dnd-kit/core'; +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragOverlay, +} from '@dnd-kit/core'; +import { + SortableContext, + sortableKeyboardCoordinates, + rectSortingStrategy, + useSortable, +} from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; + import MenuIcon from '@/material-icons/400-24px/menu.svg?react'; import EmojiReactionIcon from '@/material-icons/400-24px/mood.svg?react'; import { updateReactionDeck } from 'mastodon/actions/reaction_deck'; @@ -37,14 +61,25 @@ const ReactionEmoji: React.FC<{ onChange: (index: number, emoji: any) => void; onRemove: (index: number) => void; }> = ({ index, emoji, emojiMap, onChange, onRemove }) => { - const handleChange = useCallback((emoji: any) => { - onChange(index, emoji); - }, [index, onChange]); + const handleChange = useCallback( + (emoji: any) => { + onChange(index, emoji); + }, + [index, onChange], + ); const handleRemove = useCallback(() => { onRemove(index); }, [index, onRemove]); + const { attributes, listeners, setNodeRef, transform, transition } = + useSortable({ id: index.toString() }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + }; + let content: ReactNode; const mapEmoji = emojiMap.find((e: any) => e.get('shortcode') === emoji); @@ -69,16 +104,25 @@ const ReactionEmoji: React.FC<{ } return ( -
-
-
- -
- {content} +
+ + + +
+
+
+ +
{content}
+
+
+
-
-
-
@@ -119,7 +163,7 @@ export const ReactionDeck: React.FC<{ newDeck[index] = emoji.native || emoji.id.replace(':', ''); onChange(newDeck); }, - [onChange, deck] + [onChange, deck], ); const handleRemove = useCallback( @@ -134,12 +178,48 @@ export const ReactionDeck: React.FC<{ const handleAdd = useCallback( (emoji: any) => { const newDeck = deckToArray(deck); - newDeck.push('👍'); + const newEmoji = emoji.native || emoji.id.replace(':', ''); + newDeck.push(newEmoji); onChange(newDeck); }, [onChange, deck], ); + const [activeId, setActiveId] = useState(null); + + const sensors = useSensors( + useSensor(PointerSensor, { + activationConstraint: { + distance: 5, + }, + }), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }), + ); + + const handleDragStart = useCallback( + (e: DragStartEvent) => { + const { active } = e; + + setActiveId(active.id); + }, + [setActiveId], + ); + + const handleDragEnd = useCallback( + (e: DragEndEvent) => { + const { active, over } = e; + + if (over && active.id !== over.id) { + //onChange(deck); + } + + setActiveId(null); + }, + [dispatch, setActiveId], + ); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!deck) { return ( @@ -159,16 +239,28 @@ export const ReactionDeck: React.FC<{ showBackButton /> - {deck.map((emoji: any, index) => ( - - ))} + + + {deck.map((emoji: any, index) => ( +
+ +
+ ))} +
+ + {activeId ? Test : null} +
'tsc -p tsconfig.json --noEmit', + '*.{js,jsx,ts,tsx}': 'eslint --fix', + '*.{css,scss}': 'stylelint --fix', + '*.haml': 'bin/haml-lint -a', + '**/*.ts?(x)': () => 'tsc -p tsconfig.json --noEmit', }; module.exports = config; diff --git a/vite.config.mts b/vite.config.mts index 92d32b1c4c..add5d21f4b 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -5,13 +5,12 @@ import { optimizeLodashImports } from '@optimize-lodash/rollup-plugin'; import react from '@vitejs/plugin-react'; import { PluginOption } from 'vite'; import svgr from 'vite-plugin-svgr'; -import { visualizer } from 'rollup-plugin-visualizer'; +// import { visualizer } from 'rollup-plugin-visualizer'; import RailsPlugin from 'vite-plugin-rails'; import { VitePWA } from 'vite-plugin-pwa'; import tsconfigPaths from 'vite-tsconfig-paths'; import yaml from 'js-yaml'; import legacy from '@vitejs/plugin-legacy'; -import vitePluginRequire from "vite-plugin-require"; import { defineConfig, UserConfigFnPromise, UserConfig } from 'vite'; import postcssPresetEnv from 'postcss-preset-env'; @@ -107,7 +106,6 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => { }, }, plugins: [ - vitePluginRequire(), tsconfigPaths(), RailsPlugin({ compress: mode === 'production' && command === 'build', @@ -153,7 +151,8 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => { svgr(), // Old library types need to be converted optimizeLodashImports() as PluginOption, - !!process.env.ANALYZE_BUNDLE_SIZE && (visualizer() as PluginOption), + // Disable in knyblue because kmyblue-developer cannot launch foreman + // !!process.env.ANALYZE_BUNDLE_SIZE && (visualizer() as PluginOption), ], } satisfies UserConfig; };