Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
Neos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Neos
Commits
5e0baeb2
Commit
5e0baeb2
authored
Aug 13, 2023
by
timel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: card detail content in card build
parent
2849c472
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
248 additions
and
34 deletions
+248
-34
src/common.ts
src/common.ts
+8
-0
src/ui/BuildDeck/CardDetail.module.scss
src/ui/BuildDeck/CardDetail.module.scss
+28
-1
src/ui/BuildDeck/CardDetail.tsx
src/ui/BuildDeck/CardDetail.tsx
+77
-4
src/ui/BuildDeck/index.tsx
src/ui/BuildDeck/index.tsx
+40
-27
src/ui/Shared/CardEffectText/index.module.scss
src/ui/Shared/CardEffectText/index.module.scss
+12
-0
src/ui/Shared/CardEffectText/index.tsx
src/ui/Shared/CardEffectText/index.tsx
+76
-0
src/ui/Shared/YgoCard/index.tsx
src/ui/Shared/YgoCard/index.tsx
+5
-1
src/ui/Shared/index.ts
src/ui/Shared/index.ts
+1
-0
src/ui/theme.ts
src/ui/theme.ts
+1
-1
No files found.
src/common.ts
View file @
5e0baeb2
...
...
@@ -118,6 +118,14 @@ export function isToken(typeCode: number): boolean {
return
(
typeCode
&
TYPE_TOKEN
)
>
0
;
}
export
function
isMonster
(
typeCode
:
number
):
boolean
{
return
(
typeCode
&
TYPE_MONSTER
)
>
0
;
}
export
function
isLinkMonster
(
typeCode
:
number
):
boolean
{
return
(
typeCode
&
TYPE_LINK
)
>
0
;
}
// 属性
// const ATTRIBUTE_ALL = 0x7f; //
const
ATTRIBUTE_EARTH
=
0x01
;
//
...
...
src/ui/BuildDeck/CardDetail.module.scss
View file @
5e0baeb2
...
...
@@ -8,7 +8,7 @@
width
:
100%
;
height
:
100%
;
padding
:
0
10px
20px
10px
;
//
transition: 0.2s;
transition
:
0
.2s
;
}
.detail.open
{
...
...
@@ -21,6 +21,9 @@
box-shadow
:
0
0
0
1px
rgba
(
255
,
255
,
255
,
0
.2
)
,
0
0
30px
0
#ffffff
54
;
backdrop-filter
:
blur
(
20px
);
@include
utils
.
noise-bg
;
padding
:
15px
;
display
:
flex
;
flex-direction
:
column
;
}
.btn-close
{
...
...
@@ -28,3 +31,27 @@
right
:
5px
;
top
:
5px
;
}
.card
{
--width
:
160px
;
width
:
var
(
--
width
);
height
:
calc
(
var
(
--
width
)
/
var
(
--
card-ratio
));
flex-shrink
:
0
;
border-radius
:
4px
;
overflow
:
hidden
;
box-shadow
:
0px
14px
20px
-5px
rgba
(
0
,
0
,
0
,
0
.3
);
}
.title
{
font-size
:
18px
;
font-family
:
var
(
--
theme-font
);
margin
:
20px
0
15px
;
display
:
flex
;
justify-content
:
space-between
;
// color: rgba(255, 255, 255, 0.45);
}
.content
{
// font-size: ;
color
:
white
;
}
src/ui/BuildDeck/CardDetail.tsx
View file @
5e0baeb2
import
{
LineOutlined
}
from
"
@ant-design/icons
"
;
import
{
Button
}
from
"
antd
"
;
import
{
Avatar
,
Button
,
Descriptions
}
from
"
antd
"
;
import
classNames
from
"
classnames
"
;
import
{
useEffect
,
useMemo
,
useState
}
from
"
react
"
;
import
{
type
CardMeta
,
fetchCard
,
fetchStrings
,
Region
}
from
"
@/api
"
;
import
{
Attribute2StringCodeMap
,
extraCardTypes
,
isLinkMonster
,
isMonster
,
Race2StringCodeMap
,
Type2StringCodeMap
,
}
from
"
@/common
"
;
import
{
CardEffectText
,
IconFont
,
ScrollableArea
,
YgoCard
}
from
"
@/ui/Shared
"
;
import
styles
from
"
./CardDetail.module.scss
"
;
...
...
@@ -9,16 +20,78 @@ export const CardDetail: React.FC<{
open
:
boolean
;
onClose
:
()
=>
void
;
}
>
=
({
code
,
open
,
onClose
})
=>
{
code
;
const
[
card
,
setCard
]
=
useState
<
CardMeta
>
();
useEffect
(()
=>
{
fetchCard
(
code
).
then
(
setCard
);
},
[
code
]);
const
cardType
=
useMemo
(
()
=>
extraCardTypes
(
card
?.
data
.
type
??
0
)
.
map
((
t
)
=>
fetchStrings
(
Region
.
System
,
Type2StringCodeMap
.
get
(
t
)
||
0
))
.
join
(
"
/
"
),
[
card
?.
data
.
type
]
);
return
(
<
div
className=
{
classNames
(
styles
.
detail
,
{
[
styles
.
open
]:
open
})
}
>
<
div
className=
{
styles
.
container
}
>
<
Button
className=
{
styles
[
"
btn-close
"
]
}
icon=
{
<
LineOutlined
/>
}
icon=
{
<
IconFont
type=
"icon-side-bar-fill"
size=
{
16
}
/>
}
type=
"text"
onClick=
{
onClose
}
/>
<
YgoCard
className=
{
styles
.
card
}
code=
{
code
}
/>
<
div
className=
{
styles
.
title
}
>
<
span
>
{
card
?.
text
.
name
}
</
span
>
<
Avatar
size=
{
22
}
>
光
</
Avatar
>
</
div
>
<
ScrollableArea
>
<
Descriptions
layout=
"vertical"
size=
"small"
>
{
card
?.
data
.
level
&&
(
<
Descriptions
.
Item
label=
"等级"
>
{
card
?.
data
.
level
}
</
Descriptions
.
Item
>
)
}
<
Descriptions
.
Item
label=
"类型"
span=
{
2
}
>
{
cardType
}
</
Descriptions
.
Item
>
{
card
?.
data
.
attribute
&&
(
<
Descriptions
.
Item
label=
"属性"
>
{
fetchStrings
(
Region
.
System
,
Attribute2StringCodeMap
.
get
(
card
?.
data
.
attribute
??
0
)
||
0
)
}
</
Descriptions
.
Item
>
)
}
{
card
?.
data
.
race
&&
(
<
Descriptions
.
Item
label=
"种族"
span=
{
2
}
>
{
fetchStrings
(
Region
.
System
,
Race2StringCodeMap
.
get
(
card
?.
data
.
race
??
0
)
||
0
)
}
</
Descriptions
.
Item
>
)
}
{
isMonster
(
card
?.
data
.
type
??
0
)
&&
(
<>
<
Descriptions
.
Item
label=
"攻击力"
>
2000
</
Descriptions
.
Item
>
{
!
isLinkMonster
(
card
?.
data
.
type
??
0
)
&&
(
<
Descriptions
.
Item
label=
"守备力"
>
0
</
Descriptions
.
Item
>
)
}
{
card
?.
data
.
lscale
&&
(
<
Descriptions
.
Item
label=
"灵摆刻度"
>
←
{
card
.
data
.
lscale
}
-
{
card
.
data
.
rscale
}
→
</
Descriptions
.
Item
>
)
}
</>
)
}
</
Descriptions
>
<
Descriptions
layout=
"vertical"
size=
"small"
>
<
Descriptions
.
Item
label=
"卡片效果"
span=
{
3
}
>
<
CardEffectText
desc=
{
card
?.
text
.
desc
}
/>
</
Descriptions
.
Item
>
</
Descriptions
>
</
ScrollableArea
>
</
div
>
</
div
>
);
...
...
src/ui/BuildDeck/index.tsx
View file @
5e0baeb2
...
...
@@ -23,11 +23,11 @@ import { memo, useCallback, useEffect, useRef, useState } from "react";
import
{
DndProvider
,
useDrag
,
useDrop
}
from
"
react-dnd
"
;
import
{
HTML5Backend
}
from
"
react-dnd-html5-backend
"
;
import
{
LoaderFunction
}
from
"
react-router-dom
"
;
import
{
useSnapshot
}
from
"
valtio
"
;
import
{
proxy
,
useSnapshot
}
from
"
valtio
"
;
import
{
subscribeKey
}
from
"
valtio/utils
"
;
import
{
type
CardMeta
,
initForbiddens
,
searchCards
}
from
"
@/api
"
;
import
{
is
ExtraDeckCard
,
is
Token
}
from
"
@/common
"
;
import
{
isToken
}
from
"
@/common
"
;
import
{
FtsConditions
}
from
"
@/middleware/sqlite/fts
"
;
import
{
deckStore
,
type
IDeck
,
initStore
}
from
"
@/stores
"
;
import
{
...
...
@@ -101,7 +101,7 @@ export const Component: React.FC = () => {
onAdd=
{
()
=>
console
.
log
(
"
add
"
)
}
/>
</
ScrollableArea
>
<
CardDetail
code=
{
123
}
open=
{
false
}
onClose=
{
()
=>
{}
}
/>
<
HigherCardDetail
/>
</
div
>
<
div
className=
{
styles
.
content
}
>
<
div
className=
{
styles
.
deck
}
>
...
...
@@ -231,14 +231,14 @@ const Search: React.FC = () => {
[
[
"
从新到旧
"
,
()
=>
setSortRef
((
a
,
b
)
=>
b
.
id
-
a
.
id
)],
[
"
从旧到新
"
,
()
=>
setSortRef
((
a
,
b
)
=>
a
.
id
-
b
.
id
)],
[
"
攻击力从高到低
"
,
genSort
(
"
atk
"
)],
[
"
攻击力从低到高
"
,
genSort
(
"
atk
"
,
-
1
)],
[
"
守备力从高到低
"
,
genSort
(
"
def
"
)],
[
"
守备力从低到高
"
,
genSort
(
"
def
"
,
-
1
)],
[
"
星/阶/刻/Link从高到低
"
,
genSort
(
"
level
"
)],
[
"
星/阶/刻/Link从低到高
"
,
genSort
(
"
level
"
,
-
1
)],
[
"
灵摆刻度从高到低
"
,
genSort
(
"
lscale
"
)],
[
"
灵摆刻度从低到高
"
,
genSort
(
"
lscale
"
,
-
1
)],
[
"
攻击力从高到低
"
,
genSort
(
"
atk
"
,
-
1
)],
[
"
攻击力从低到高
"
,
genSort
(
"
atk
"
)],
[
"
守备力从高到低
"
,
genSort
(
"
def
"
,
-
1
)],
[
"
守备力从低到高
"
,
genSort
(
"
def
"
)],
[
"
星/阶/刻/Link从高到低
"
,
genSort
(
"
level
"
,
-
1
)],
[
"
星/阶/刻/Link从低到高
"
,
genSort
(
"
level
"
)],
[
"
灵摆刻度从高到低
"
,
genSort
(
"
lscale
"
,
-
1
)],
[
"
灵摆刻度从低到高
"
,
genSort
(
"
lscale
"
)],
]
as
const
).
map
(([
label
,
onClick
],
key
)
=>
({
key
,
label
,
onClick
}));
...
...
@@ -430,11 +430,6 @@ const SearchResults: React.FC<{
results
:
CardMeta
[];
scrollToTop
:
()
=>
void
;
}
>
=
memo
(({
results
,
scrollToTop
})
=>
{
const
handleClick
=
(
card
:
CardMeta
)
=>
{
const
type
=
isExtraDeckCard
(
card
.
data
.
type
??
0
)
?
"
extra
"
:
"
main
"
;
editDeckStore
.
canAdd
(
card
,
type
).
result
&&
editDeckStore
.
add
(
type
,
card
);
};
const
itemsPerPage
=
196
;
// 每页显示的数据数量
const
[
currentPage
,
setCurrentPage
]
=
useState
(
1
);
...
...
@@ -450,12 +445,7 @@ const SearchResults: React.FC<{
<>
<
div
className=
{
styles
[
"
search-cards
"
]
}
>
{
currentData
.
map
((
card
)
=>
(
<
Card
value=
{
card
}
key=
{
card
.
id
}
source=
"search"
onClick=
{
()
=>
handleClick
(
card
)
}
/>
<
Card
value=
{
card
}
key=
{
card
.
id
}
source=
"search"
/>
))
}
</
div
>
{
results
.
length
>
itemsPerPage
&&
(
...
...
@@ -482,9 +472,8 @@ const SearchResults: React.FC<{
const
Card
:
React
.
FC
<
{
value
:
CardMeta
;
source
:
Type
|
"
search
"
;
onClick
?:
()
=>
void
;
onRightClick
?:
()
=>
void
;
}
>
=
memo
(({
value
,
source
,
on
Click
,
on
RightClick
})
=>
{
}
>
=
memo
(({
value
,
source
,
onRightClick
})
=>
{
const
ref
=
useRef
<
HTMLDivElement
>
(
null
);
const
[{
isDragging
},
drag
]
=
useDrag
({
type
:
"
Card
"
,
...
...
@@ -494,19 +483,43 @@ const Card: React.FC<{
}),
});
drag
(
ref
);
const
[
showText
,
setShowText
]
=
useState
(
true
);
return
(
<
div
className=
{
styles
.
card
}
ref=
{
ref
}
style=
{
{
opacity
:
isDragging
&&
source
!==
"
search
"
?
0
:
1
}
}
onClick=
{
onClick
}
onClick=
{
()
=>
{
selectedCard
.
id
=
value
.
id
;
selectedCard
.
open
=
true
;
}
}
onContextMenu=
{
(
e
)
=>
{
e
.
preventDefault
();
onRightClick
?.();
}
}
>
<
div
className=
{
styles
.
cardname
}
>
{
value
.
text
.
name
}
</
div
>
<
YgoCard
className=
{
styles
.
cardcover
}
code=
{
value
.
id
}
/>
{
showText
&&
<
div
className=
{
styles
.
cardname
}
>
{
value
.
text
.
name
}
</
div
>
}
<
YgoCard
className=
{
styles
.
cardcover
}
code=
{
value
.
id
}
onLoad=
{
()
=>
setShowText
(
false
)
}
/>
</
div
>
);
});
const
HigherCardDetail
:
React
.
FC
=
()
=>
{
const
{
id
,
open
}
=
useSnapshot
(
selectedCard
);
return
(
<
CardDetail
open=
{
open
}
code=
{
id
}
onClose=
{
()
=>
(
selectedCard
.
open
=
false
)
}
/>
);
};
const
selectedCard
=
proxy
({
id
:
23995346
,
open
:
false
,
});
src/ui/Shared/CardEffectText/index.module.scss
0 → 100644
View file @
5e0baeb2
.desc
{
line-height
:
1
.8
;
font-size
:
14px
;
max-height
:
calc
(
100%
-
237px
);
font-family
:
var
(
--
theme-font
);
.maro-item
{
display
:
flex
;
margin-top
:
8px
;
gap
:
6px
;
}
}
src/ui/Shared/CardEffectText/index.tsx
0 → 100644
View file @
5e0baeb2
import
{
Fragment
,
useMemo
}
from
"
react
"
;
import
styles
from
"
./index.module.scss
"
;
export
const
CardEffectText
:
React
.
FC
<
{
desc
?:
string
}
>
=
({
desc
=
""
})
=>
{
if
(
!
desc
)
return
<></>;
const
preprocessedDesc
=
useMemo
(()
=>
{
return
addSpaces
(
desc
);
},
[
desc
]);
return
(
<
div
className=
{
styles
.
desc
}
>
<
RegexWrapper
text=
{
preprocessedDesc
}
re=
{
/
(
①|②|③|④|⑤|⑥|⑦|⑧|⑨|⑩
)
:.+
?(?=((
①|②|③|④|⑤|⑥|⑦|⑧|⑨|⑩
)
:|$
))
/g
s
}
Wrapper=
{
MaroListItem
}
/>
</
div
>
);
};
/** 使用re去提取文本,并且将提取到的文本用Wrapper进行环绕 */
const
RegexWrapper
:
React
.
FC
<
{
text
:
string
;
re
:
RegExp
;
Wrapper
:
React
.
FunctionComponent
<
any
>
;
}
>
=
({
text
,
re
,
Wrapper
})
=>
{
const
matches
=
text
.
match
(
re
);
if
(
!
matches
)
return
<>
{
text
}
</>;
const
sepRe
=
new
RegExp
(
matches
?.
reduce
((
acc
,
cur
)
=>
`
${
acc
}
|
${
cur
}
`
)
??
""
);
const
parts
=
text
.
split
(
sepRe
);
return
(
<>
{
parts
.
map
((
part
,
index
)
=>
(
<
Fragment
key=
{
`${part}-${index}`
}
>
<
div
>
{
part
}
</
div
>
{
index
!==
parts
.
length
-
1
&&
<
Wrapper
>
{
matches
?.[
index
]
}
</
Wrapper
>
}
</
Fragment
>
))
}
</>
);
};
const
MaroListItem
:
React
.
FC
<
{
children
:
string
}
>
=
({
children
})
=>
{
return
(
<
div
className=
{
styles
[
"
maro-item
"
]
}
>
<
span
>
{
children
[
0
]
}
</
span
>
<
span
>
<
RegexWrapper
text=
{
children
.
slice
(
2
)
}
re=
{
/●.+
?(?=(
●|$
))
/g
s
}
Wrapper=
{
CircleListItem
}
/>
</
span
>
</
div
>
);
};
const
CircleListItem
:
React
.
FC
<
{
children
:
string
}
>
=
({
children
})
=>
{
return
children
?
(
<
div
className=
{
styles
[
"
maro-item
"
]
}
>
<
span
>
{
children
[
0
]
}
</
span
>
<
span
>
{
children
.
slice
(
1
)
}
</
span
>
</
div
>
)
:
(
<></>
);
};
function
addSpaces
(
str
:
string
):
string
{
const
regex
=
/
\d
+/g
;
return
str
.
replace
(
regex
,
(
match
)
=>
`
${
match
}
`
);
}
// function removePendulumPrefix(str: string): string {}
src/ui/Shared/YgoCard/index.tsx
View file @
5e0baeb2
...
...
@@ -12,6 +12,7 @@ interface Props {
style
?:
CSSProperties
;
width
?:
number
;
onClick
?:
()
=>
void
;
onLoad
?:
()
=>
void
;
}
export
const
YgoCard
:
React
.
FC
<
Props
>
=
(
props
)
=>
{
...
...
@@ -21,7 +22,8 @@ export const YgoCard: React.FC<Props> = (props) => {
isBack
=
false
,
width
,
style
,
onClick
=
()
=>
{},
onClick
,
onLoad
,
}
=
props
;
return
useMemo
(
()
=>
(
...
...
@@ -30,6 +32,8 @@ export const YgoCard: React.FC<Props> = (props) => {
src=
{
getCardImgUrl
(
code
,
isBack
)
}
style=
{
{
width
,
...
style
}
}
onClick=
{
onClick
}
// 加载完成
onLoad=
{
onLoad
}
/>
),
[
code
]
...
...
src/ui/Shared/index.ts
View file @
5e0baeb2
export
*
from
"
./Background
"
;
export
*
from
"
./CardEffectText
"
;
export
*
from
"
./css
"
;
export
*
from
"
./IconFont
"
;
export
*
from
"
./Loading
"
;
...
...
src/ui/theme.ts
View file @
5e0baeb2
...
...
@@ -30,7 +30,7 @@ export const theme: ThemeConfig = {
colorBgContainer
:
"
hsla(0, 0%, 100%, 0.05)
"
,
},
Dropdown
:
{
colorBgElevated
:
"
#
3f4d6
0
"
,
colorBgElevated
:
"
#
2e3c5
0
"
,
boxShadow
:
"
0 6px 16px 0 rgb(51 51 51 / 80%), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05)
"
,
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment