Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit 1c77ddb

Browse files
authored
feat(dashboard) tags editor (#1344)
* feat(dashboard): basci tags selector settings * chore: clean warning * refactor(saving-bar): add children behavior * refactor(tags-editor): basic UX * refactor(tags-editor): update done * fix(tags-editor): rallback edge case * fix(tags-editor): transiton only for bg * refactor(tags-editor): adjust naming
1 parent da2381e commit 1c77ddb

30 files changed

+623
-110
lines changed

src/containers/thread/DashboardThread/BasicInfo/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { FC, memo } from 'react'
22

33
import type { TPostLayout } from '@/spec'
44

5-
import { POST_LAYOUT } from '@/constant'
6-
75
import { Br } from '@/widgets/Common'
86
import OSSUploader from '@/widgets/OSSUploader'
97

src/containers/thread/DashboardThread/SavingBar.tsx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, memo, ReactNode } from 'react'
1+
import { FC, memo, Fragment, ReactNode } from 'react'
22

33
import type { TSpace } from '@/spec'
44
import { SpaceGrow } from '@/widgets/Common'
@@ -14,22 +14,49 @@ import {
1414
ActionWrapper,
1515
} from './styles/saving_bar'
1616

17-
import { rollbackEdit } from './logic'
17+
import { rollbackEdit, onSave } from './logic'
1818

1919
type TProps = {
2020
field: TSettingField
2121
prefix?: string
2222
hint?: ReactNode
23+
children?: ReactNode
24+
isTouched?: boolean
2325
} & TSpace
2426

2527
const SavingBar: FC<TProps> = ({
2628
field,
2729
prefix = '是否保存',
2830
hint = null,
31+
children = null,
32+
isTouched = false,
2933
...restProps
3034
}) => {
35+
if (children !== null) {
36+
if (isTouched) {
37+
return (
38+
<Wrapper gradientDirection="left" {...restProps}>
39+
<Fragment>{children}</Fragment>
40+
<SpaceGrow />
41+
<ActionWrapper>
42+
<YesOrNoButtons
43+
cancelText="取消"
44+
confirmText="确定"
45+
space={4}
46+
onCancel={() => rollbackEdit(field)}
47+
onConfirm={() => onSave(field)}
48+
/>
49+
</ActionWrapper>
50+
</Wrapper>
51+
)
52+
}
53+
return <Fragment>{children}</Fragment>
54+
}
55+
56+
if (!isTouched) return null
57+
3158
return (
32-
<Wrapper {...restProps}>
59+
<Wrapper gradientDirection="right" {...restProps}>
3360
<HintWrapper>
3461
<InfoIcon />
3562
<HintText>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { FC, memo, useState } from 'react'
2+
3+
import { Space } from '@/widgets/Common'
4+
5+
import {
6+
Wrapper,
7+
CatsWrapper,
8+
CatButton,
9+
Hint,
10+
} from '../styles/tags/category_selector'
11+
12+
const TagCats = [
13+
{
14+
title: '分组 1',
15+
raw: '1',
16+
},
17+
{
18+
title: '分组 2',
19+
raw: '2',
20+
},
21+
{
22+
title: '分组 3',
23+
raw: '3',
24+
},
25+
// {
26+
// title: '分组 4',
27+
// raw: '4',
28+
// },
29+
// {
30+
// title: '分组 5',
31+
// raw: '5',
32+
// },
33+
// {
34+
// title: '分组 6',
35+
// raw: '6',
36+
// },
37+
// {
38+
// title: '分组 7',
39+
// raw: '7',
40+
// },
41+
// {
42+
// title: '分组 8',
43+
// raw: '8',
44+
// },
45+
]
46+
47+
type TProps = {
48+
testid?: string
49+
}
50+
51+
const CategorySelector: FC<TProps> = () => {
52+
const [cat, setCat] = useState('0')
53+
const CAT_SPACE = 12
54+
55+
return (
56+
<Wrapper>
57+
<Hint>分组:</Hint>
58+
<CatsWrapper>
59+
<CatButton
60+
ghost
61+
size="small"
62+
noBorder={cat !== '0'}
63+
onClick={() => setCat('0')}
64+
>
65+
全部
66+
</CatButton>
67+
<Space right={CAT_SPACE} />
68+
{TagCats.map((item) => (
69+
<CatButton
70+
key={item.raw}
71+
ghost
72+
size="small"
73+
noBorder={cat !== item.raw}
74+
onClick={() => setCat(item.raw)}
75+
>
76+
{item.title}
77+
</CatButton>
78+
))}
79+
</CatsWrapper>
80+
</Wrapper>
81+
)
82+
}
83+
84+
export default memo(CategorySelector)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { FC, memo } from 'react'
2+
3+
import type { TTag } from '@/spec'
4+
import { COLORS } from '@/constant'
5+
6+
import { SETTING_FIELD } from '../constant'
7+
import { Space, SpaceGrow } from '@/widgets/Common'
8+
import ColorSelector from '@/widgets/ColorSelector'
9+
10+
import SavingBar from '../SavingBar'
11+
12+
import {
13+
Wrapper,
14+
Dot,
15+
DotSelector,
16+
Title,
17+
InputWrapper,
18+
Inputer,
19+
Actions,
20+
EditIcon,
21+
CloseIcon,
22+
} from '../styles/tags/tag_bar'
23+
import { updateEditingTag } from '../logic'
24+
25+
type TProps = {
26+
tag: TTag
27+
editingTag: TTag
28+
}
29+
30+
const TagBar: FC<TProps> = ({ tag, editingTag }) => {
31+
const editing = editingTag?.id === tag.id
32+
33+
return (
34+
<Wrapper key={tag.id} editing={editing}>
35+
<SavingBar isTouched={editing} field={SETTING_FIELD.TAG}>
36+
{editing ? (
37+
<ColorSelector
38+
activeColor={editingTag.color}
39+
onChange={(color) => updateEditingTag({ ...editingTag, color })}
40+
placement="bottom-start"
41+
offset={[-8, 0]}
42+
>
43+
<DotSelector>
44+
<Dot color={COLORS[editingTag.color]} editing={editing} />
45+
</DotSelector>
46+
</ColorSelector>
47+
) : (
48+
<Dot color={COLORS[tag.color]} />
49+
)}
50+
{editing ? (
51+
<InputWrapper>
52+
<Inputer
53+
value={editingTag.title}
54+
onChange={(e) =>
55+
updateEditingTag({ ...editingTag, title: e.target.value })
56+
}
57+
autoFocus
58+
/>
59+
</InputWrapper>
60+
) : (
61+
<Title>{tag.title}</Title>
62+
)}
63+
<SpaceGrow />
64+
{!editing && (
65+
<Actions>
66+
<EditIcon onClick={() => updateEditingTag(tag)} />
67+
<Space right={4} />
68+
<CloseIcon />
69+
</Actions>
70+
)}
71+
</SavingBar>
72+
</Wrapper>
73+
)
74+
}
75+
76+
export default memo(TagBar)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { FC, memo, useState } from 'react'
2+
3+
import { THREAD } from '@/constant'
4+
5+
import {
6+
Wrapper,
7+
Hint,
8+
CatsWrapper,
9+
CatButton,
10+
} from '../styles/tags/thread_selector'
11+
12+
const ThreadSelector: FC = () => {
13+
const [thread, setThread] = useState(THREAD.POST)
14+
15+
return (
16+
<Wrapper>
17+
<Hint>板块</Hint>
18+
<CatsWrapper>
19+
<CatButton
20+
ghost={thread !== THREAD.POST}
21+
size="small"
22+
noBorder={thread !== THREAD.POST}
23+
onClick={() => setThread(THREAD.POST)}
24+
>
25+
讨论区
26+
</CatButton>
27+
28+
<CatButton
29+
ghost={thread !== THREAD.ROADMAP}
30+
size="small"
31+
noBorder={thread !== THREAD.ROADMAP}
32+
onClick={() => setThread(THREAD.ROADMAP)}
33+
>
34+
看板墙
35+
</CatButton>
36+
37+
<CatButton
38+
ghost={thread !== THREAD.CHANGELOG}
39+
size="small"
40+
noBorder={thread !== THREAD.CHANGELOG}
41+
onClick={() => setThread(THREAD.CHANGELOG)}
42+
>
43+
更新日志
44+
</CatButton>
45+
</CatsWrapper>
46+
</Wrapper>
47+
)
48+
}
49+
50+
export default memo(ThreadSelector)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { FC, memo } from 'react'
2+
3+
import Portal from '../Portal'
4+
5+
import ThreadSelector from './ThreadSelector'
6+
import CategorySelector from './CategorySelector'
7+
import TagBar from './TagBar'
8+
9+
import type { TTagSettings } from '../spec'
10+
import { Wrapper, InnerWrapper, ContentWrapper } from '../styles/tags'
11+
12+
type TProps = {
13+
settings: TTagSettings
14+
}
15+
16+
const Tags: FC<TProps> = ({ settings }) => {
17+
const { tags, editingTag } = settings
18+
19+
return (
20+
<Wrapper>
21+
<Portal
22+
title="标签设置"
23+
desc="编辑各板块标签,标签分组,颜色名称等均可编辑。"
24+
/>
25+
<InnerWrapper>
26+
<ThreadSelector />
27+
<ContentWrapper>
28+
<CategorySelector />
29+
{tags.map((tag) => (
30+
<TagBar key={tag.id} tag={tag} editingTag={editingTag} />
31+
))}
32+
</ContentWrapper>
33+
</InnerWrapper>
34+
</Wrapper>
35+
)
36+
}
37+
38+
export default memo(Tags)

src/containers/thread/DashboardThread/UI/BannerLayout.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import type { TBannerLayout } from '@/spec'
55
import { BANNER_LAYOUT, DASHBOARD_DESC_LAYOUT } from '@/constant'
66
import { callDashboardDesc } from '@/utils/helper'
77

8-
import Button from '@/widgets/Buttons/Button'
98
import { Br, Space, SpaceGrow, Inline } from '@/widgets/Common'
9+
import ArrowButton from '@/widgets/Buttons/ArrowButton'
1010
import CheckLabel from '@/widgets/CheckLabel'
1111

1212
import { SETTING_FIELD } from '../constant'
@@ -43,16 +43,15 @@ const BannerLayout: FC<TProps> = ({ layout, isTouched }) => {
4343
<>
4444
整体页面的 Header 布局,适用于除文章页的所有页面。
4545
<Inline>
46-
<Button
46+
<ArrowButton
4747
onClick={() =>
4848
callDashboardDesc(DASHBOARD_DESC_LAYOUT.POST_LIST)
4949
}
50-
size="small"
51-
ghost
52-
noBorder
50+
size="tiny"
51+
arrowStyle="simple"
5352
>
5453
查看示例
55-
</Button>
54+
</ArrowButton>
5655
</Inline>
5756
</>
5857
}
@@ -174,7 +173,11 @@ const BannerLayout: FC<TProps> = ({ layout, isTouched }) => {
174173
</LayoutTitle>
175174
</Layout>
176175
</SelectWrapper>
177-
{isTouched && <SavingBar top={20} field={SETTING_FIELD.BANNER_LAYOUT} />}
176+
<SavingBar
177+
isTouched={isTouched}
178+
field={SETTING_FIELD.BANNER_LAYOUT}
179+
top={20}
180+
/>
178181
</Wrapper>
179182
)
180183
}

0 commit comments

Comments
 (0)