Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/design/components/Popover/style/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './index.less';
26 changes: 26 additions & 0 deletions packages/design/components/Reactions/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Meta, StoryFn } from '@storybook/react';
import React from 'react';

import type { ReactionsDropdownProps } from './Dropdown';
import ReactionsDropdown from './Dropdown';

const storyMeta: Meta<typeof ReactionsDropdown> = {
title: 'modern/Reactions/Dropdown',
component: ReactionsDropdown,
};

export default storyMeta;

const Template: StoryFn<ReactionsDropdownProps> = (args) => {
return (
<div style={{ paddingLeft: 100 }}>
<ReactionsDropdown {...args} />
</div>
);
};

export const Default = Template.bind({});
Default.args = {};

export const WithText = Template.bind({});
WithText.args = { showText: true };
47 changes: 47 additions & 0 deletions packages/design/components/Reactions/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import './style/Dropdown.less';

import React from 'react';

import { Reaction } from '@bangumi/icons';

import Button from '../Button';
import Popover from '../Popover';
import { reactions } from './constants';

export interface ReactionsDropdownProps {
showText?: boolean;
onClick?: (key: number) => void;
}

const ReactionsDropdown = ({ showText = false, onClick }: ReactionsDropdownProps) => {
return (
<Popover
className='bgm-reactions-dropdown'
content={
<ul className='bgm-reactions-dropdown__grid'>
{reactions.map(([key, value]) => (
<li
key={key}
className='bgm-reactions-dropdown__item'
onClick={() => {
onClick?.(key);
}}
>
<img
className='bgm-reactions-dropdown__smile'
src={`https://lain.bgm.tv/img/smiles/tv/${value}.gif`}
/>
</li>
))}
</ul>
}
>
<Button type='plain' className='bgm-reactions-dropdown__button'>
<Reaction />
{showText && '贴贴'}
</Button>
</Popover>
);
};

export default ReactionsDropdown;
24 changes: 24 additions & 0 deletions packages/design/components/Reactions/List.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryFn } from '@storybook/react';
import React from 'react';

import type { ReactionsListProps } from './List';
import ReactionsList from './List';

const storyMeta: Meta<typeof ReactionsList> = {
title: 'modern/Reactions/List',
component: ReactionsList,
};

export default storyMeta;

const Template: StoryFn<ReactionsListProps> = (args) => {
return <ReactionsList {...args} />;
};

export const Default = Template.bind({});
Default.args = {
reactions: [
{ selected: false, total: 233, value: 54 },
{ selected: false, total: 1, value: 0 },
],
};
43 changes: 43 additions & 0 deletions packages/design/components/Reactions/List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import './style/List.less';

import React from 'react';

import type { Reaction } from '@bangumi/client/client';

import Button from '../Button';
import { reactionMappings } from './constants';

export interface ReactionsListProps {
reactions: Reaction[];
}

const ReactionsList = ({ reactions }: ReactionsListProps) => {
return (
<div className='bgm-reactions-list'>
{reactions?.map((reaction) => {
const reactionValue = reactionMappings.get(reaction.value);
if (!reactionValue) {
return null;
}
return (
<Button
className='bgm-reactions-list__item'
key={reaction.value}
type='plain'
size='medium'
>
{reactionMappings.get(reaction.value) && (
<img
className='bgm-reactions__smile'
src={`https://lain.bgm.tv/img/smiles/tv/${reactionValue}.gif`}
/>
)}{' '}
{reaction.total}
</Button>
);
})}
</div>
);
};

export default ReactionsList;
31 changes: 31 additions & 0 deletions packages/design/components/Reactions/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 使用数组以保证顺序
Comment thread
trim21 marked this conversation as resolved.
export const reactions: Array<[number, string]> = [
[0, '44'], // bgm67
[140, '101'], // bgm124
[80, '41'], // bgm64
[54, '15'], // bgm38
[85, '46'], // bgm69

[104, '65'], // bgm88
[88, '49'], // bgm72
[62, '23'], // bgm46
[79, '40'], // bgm63
[53, '14'], // bgm37

[122, '83'], // bgm106
[92, '53'], // bgm76
[118, '79'], // bgm102
[141, '102'], // bgm125
[90, '51'], // bgm74

[76, '37'], // bgm60
[60, '21'], // bgm44
[128, '89'], // bgm112
[47, '08'], // bgm31
[68, '29'], // bgm52

[137, '98'], // bgm121
[132, '93'], // bgm116
];

export const reactionMappings = new Map(reactions);
7 changes: 7 additions & 0 deletions packages/design/components/Reactions/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Dropdown from './Dropdown';
import List from './List';

export default { Dropdown, List };

export type { ReactionsDropdownProps } from './Dropdown';
export type { ReactionsListProps } from './List';
30 changes: 30 additions & 0 deletions packages/design/components/Reactions/style/Dropdown.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@import '../../../theme/base.less';

.bgm-reactions-dropdown {
&:hover &__button {
color: @primary-color;
}

&__grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 2px 8px;
padding: 14px 16px;
}

&__item {
padding: 6px;
border-radius: 10px;
cursor: pointer;
line-height: 12px;

&:hover {
background-color: #f5f5f5;
}
}

&__smile {
width: 21px;
aspect-ratio: 1;
}
}
25 changes: 25 additions & 0 deletions packages/design/components/Reactions/style/List.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@import '../../../theme/variables.less';

.bgm-reactions-list {
display: flex;
column-gap: 12px;

&__item {
padding: 1px 14px 1px 8px;
gap: 10px;
border-radius: 17px;
border: 2px solid transparent;
background-color: #f5f5f5;

&:hover {
border-color: #e6e6e6;
color: @gray-60;
}

&:active {
background: @pink-60;
border-color: @pink-60;
color: #fff;
}
}
}
4 changes: 4 additions & 0 deletions packages/design/components/Topic/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { getUserProfileLink } from '@bangumi/utils/pages';
import Avatar from '../../components/Avatar';
import RichContent from '../../components/RichContent';
import Typography from '../../components/Typography';
import Reactions from '../Reactions';
import { toast } from '../Toast';
import CommentActions from './CommentActions';
import CommentInfo from './CommentInfo';
Expand All @@ -27,6 +28,7 @@ export type CommentProps = ((SubReply & { isReply: true }) | (Reply & { isReply:
};

const Link = Typography.Link;
const ReactionsList = Reactions.List;

const RenderContent = memo(({ state, text }: { state: State; text: string }) => {
switch (state) {
Expand Down Expand Up @@ -79,6 +81,7 @@ const Comment: FC<CommentProps> = ({
state,
user,
topicId,
reactions,
onCommentUpdate,
...props
}) => {
Expand Down Expand Up @@ -196,6 +199,7 @@ const Comment: FC<CommentProps> = ({
</div>
</span>
<RenderContent state={state} text={text} />
<ReactionsList reactions={reactions} />
</div>
{showReplyEditor && (
<div className='bgm-comment__opinions'>
Expand Down
4 changes: 3 additions & 1 deletion packages/design/components/Topic/CommentActions.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export default {
const Template: StoryFn<CommentActionsProps> = (args) => {
return (
<BrowserRouter>
<CommentActions {...args} id={375793} />
<div style={{ paddingLeft: 100 }}>
<CommentActions {...args} id={375793} />
</div>
</BrowserRouter>
);
};
Expand Down
7 changes: 6 additions & 1 deletion packages/design/components/Topic/CommentActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import { Comment as CommentIcon, More } from '@bangumi/icons';

import Button from '../../components/Button';
import Popover from '../Popover';
import Reactions from '../Reactions';

const ReactionsDropdown = Reactions.Dropdown;

export interface CommentActionsProps {
id: number;
onReply?: () => void;
onDelete?: () => void;
onReact?: () => void;
isAuthor?: boolean;
editable?: boolean;
showText?: boolean;
Expand All @@ -18,6 +22,7 @@ const CommentActions = ({
id,
onReply,
onDelete,
onReact,
isAuthor = false,
editable = true,
showText = false,
Expand All @@ -28,7 +33,7 @@ const CommentActions = ({
<CommentIcon />
{showText && '回复'}
</Button>
{/* TODO: 实现贴贴功能 */}
<ReactionsDropdown showText={showText} onClick={onReact} />
<Popover
content={
<div className='bgm-comment-actions__popover'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@ const render = (props: CommentActionsProps) =>

describe('Basic Usage', () => {
it('should render', () => {
expect(render({ id: 233 })).toMatchSnapshot();
expect(render({ id: 233 }).container).toMatchSnapshot();
});
});

describe('With Text', () => {
it('should render', () => {
expect(render({ id: 233, showText: true })).toMatchSnapshot();
expect(render({ id: 233, showText: true }).container).toMatchSnapshot();
});
});

describe('Is Author', () => {
it('should render', () => {
expect(render({ id: 233, isAuthor: true })).toMatchSnapshot();
expect(render({ id: 233, isAuthor: true }).container).toMatchSnapshot();
});
});

describe('Non-editable', () => {
it('should render', () => {
expect(render({ id: 233, isAuthor: true, editable: false })).toMatchSnapshot();
expect(render({ id: 233, isAuthor: true, editable: false }).container).toMatchSnapshot();
});
});
Loading