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
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
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
love_飞影
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
Hide 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