Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
interface
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
interface
Commits
ad84da10
Unverified
Commit
ad84da10
authored
Nov 14, 2022
by
lynn
Committed by
GitHub
Nov 14, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: nft asset sizing / aspect ratio bug (and make collection nfts fit in square too) (#5180)
* init wip * init
parent
72a82700
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
39 additions
and
150 deletions
+39
-150
Card.tsx
src/nft/components/collection/Card.tsx
+24
-80
CollectionAsset.tsx
src/nft/components/collection/CollectionAsset.tsx
+4
-18
CollectionNfts.tsx
src/nft/components/collection/CollectionNfts.tsx
+5
-9
ProfilePage.tsx
src/nft/components/profile/view/ProfilePage.tsx
+1
-11
ViewMyNftsAsset.tsx
src/nft/components/profile/view/ViewMyNftsAsset.tsx
+5
-32
No files found.
src/nft/components/collection/Card.tsx
View file @
ad84da10
...
...
@@ -16,7 +16,7 @@ import {
import
{
body
,
bodySmall
,
buttonTextSmall
,
subhead
,
subheadSmall
}
from
'
nft/css/common.css
'
import
{
themeVars
}
from
'
nft/css/sprinkles.css
'
import
{
useIsMobile
}
from
'
nft/hooks
'
import
{
GenieAsset
,
Rarity
,
TokenType
,
UniformHeight
,
UniformHeights
,
WalletAsset
}
from
'
nft/types
'
import
{
GenieAsset
,
Rarity
,
TokenType
,
WalletAsset
}
from
'
nft/types
'
import
{
isAudio
,
isVideo
}
from
'
nft/utils
'
import
{
fallbackProvider
,
putCommas
}
from
'
nft/utils
'
import
{
floorFormatter
}
from
'
nft/utils/numbers
'
...
...
@@ -230,19 +230,15 @@ const ImageContainer = ({ children }: { children: ReactNode }) => (
)
/* -------- CARD IMAGE -------- */
interface
ImageProps
{
uniformHeight
?:
UniformHeight
setUniformHeight
?:
(
height
:
UniformHeight
)
=>
void
}
const
Image
=
(
{
uniformHeight
,
setUniformHeight
}:
ImageProps
)
=>
{
const
Image
=
()
=>
{
const
{
hovered
,
asset
}
=
useCardContext
()
const
[
noContent
,
setNoContent
]
=
useState
(
!
asset
.
smallImageUrl
&&
!
asset
.
imageUrl
)
const
[
loaded
,
setLoaded
]
=
useState
(
false
)
const
isMobile
=
useIsMobile
()
if
(
noContent
)
{
return
<
NoContentContainer
uniformHeight=
{
uniformHeight
??
UniformHeights
.
unset
}
/>
return
<
NoContentContainer
/>
}
return
(
...
...
@@ -251,7 +247,7 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
as=
{
'
img
'
}
width=
"full"
style=
{
{
aspectRatio
:
uniformHeight
===
UniformHeights
.
notUniform
?
'
1
'
:
'
auto
'
,
aspectRatio
:
'
1
'
,
transition
:
'
transform 0.4s ease 0s
'
,
}
}
src=
{
asset
.
imageUrl
||
asset
.
smallImageUrl
}
...
...
@@ -259,15 +255,6 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
draggable=
{
false
}
onError=
{
()
=>
setNoContent
(
true
)
}
onLoad=
{
(
e
)
=>
{
if
(
setUniformHeight
)
{
if
(
uniformHeight
===
UniformHeights
.
unset
)
{
setUniformHeight
(
e
.
currentTarget
.
clientHeight
)
}
else
if
(
uniformHeight
!==
UniformHeights
.
notUniform
&&
e
.
currentTarget
.
clientHeight
!==
uniformHeight
)
{
if
(
!
uniformHeight
||
Math
.
abs
(
uniformHeight
-
e
.
currentTarget
.
clientHeight
)
>
1
)
{
setUniformHeight
(
UniformHeights
.
notUniform
)
}
}
}
setLoaded
(
true
)
}
}
className=
{
clsx
(
hovered
&&
!
isMobile
&&
styles
.
cardImageHover
,
!
loaded
&&
styles
.
loadingBackground
)
}
...
...
@@ -277,13 +264,11 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
}
interface
MediaProps
{
uniformHeight
?:
UniformHeight
setUniformHeight
?:
(
u
:
UniformHeight
)
=>
void
shouldPlay
:
boolean
setCurrentTokenPlayingMedia
:
(
tokenId
:
string
|
undefined
)
=>
void
}
const
Video
=
({
uniformHeight
,
setUniformHeight
,
shouldPlay
,
setCurrentTokenPlayingMedia
}:
MediaProps
)
=>
{
const
Video
=
({
shouldPlay
,
setCurrentTokenPlayingMedia
}:
MediaProps
)
=>
{
const
vidRef
=
useRef
<
HTMLVideoElement
>
(
null
)
const
{
hovered
,
asset
}
=
useCardContext
()
const
[
noContent
,
setNoContent
]
=
useState
(
!
asset
.
smallImageUrl
&&
!
asset
.
imageUrl
)
...
...
@@ -297,7 +282,7 @@ const Video = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
}
if
(
noContent
)
{
return
<
NoContentContainer
uniformHeight=
{
UniformHeights
.
notUniform
}
/>
return
<
NoContentContainer
/>
}
return
(
...
...
@@ -317,10 +302,6 @@ const Video = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
draggable=
{
false
}
onError=
{
()
=>
setNoContent
(
true
)
}
onLoad=
{
()
=>
{
if
(
setUniformHeight
&&
uniformHeight
!==
UniformHeights
.
notUniform
)
{
setUniformHeight
(
UniformHeights
.
notUniform
)
}
setImageLoaded
(
true
)
}
}
visibility=
{
shouldPlay
?
'
hidden
'
:
'
visible
'
}
...
...
@@ -380,7 +361,7 @@ const Video = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
)
}
const
Audio
=
({
uniformHeight
,
setUniformHeight
,
shouldPlay
,
setCurrentTokenPlayingMedia
}:
MediaProps
)
=>
{
const
Audio
=
({
shouldPlay
,
setCurrentTokenPlayingMedia
}:
MediaProps
)
=>
{
const
audRef
=
useRef
<
HTMLAudioElement
>
(
null
)
const
{
hovered
,
asset
}
=
useCardContext
()
const
[
noContent
,
setNoContent
]
=
useState
(
!
asset
.
smallImageUrl
&&
!
asset
.
imageUrl
)
...
...
@@ -394,7 +375,7 @@ const Audio = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
}
if
(
noContent
)
{
return
<
NoContentContainer
uniformHeight=
{
uniformHeight
??
UniformHeights
.
unset
}
/>
return
<
NoContentContainer
/>
}
return
(
...
...
@@ -405,7 +386,7 @@ const Audio = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
alt=
{
asset
.
name
||
asset
.
tokenId
}
width=
"full"
style=
{
{
aspectRatio
:
uniformHeight
===
UniformHeights
.
notUniform
?
'
1
'
:
'
auto
'
,
aspectRatio
:
'
1
'
,
transition
:
'
transform 0.4s ease 0s
'
,
}
}
src=
{
asset
.
imageUrl
||
asset
.
smallImageUrl
}
...
...
@@ -413,18 +394,6 @@ const Audio = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
draggable=
{
false
}
onError=
{
()
=>
setNoContent
(
true
)
}
onLoad=
{
(
e
)
=>
{
if
(
setUniformHeight
)
{
if
(
uniformHeight
===
UniformHeights
.
unset
)
{
setUniformHeight
(
e
.
currentTarget
.
clientHeight
)
}
else
if
(
uniformHeight
!==
UniformHeights
.
notUniform
&&
e
.
currentTarget
.
clientHeight
!==
uniformHeight
)
{
if
(
!
uniformHeight
||
Math
.
abs
(
uniformHeight
-
e
.
currentTarget
.
clientHeight
)
>
1
)
{
setUniformHeight
(
UniformHeights
.
notUniform
)
}
}
}
setImageLoaded
(
true
)
}
}
className=
{
clsx
(
hovered
&&
!
isMobile
&&
styles
.
cardImageHover
,
!
imageLoaded
&&
styles
.
loadingBackground
)
}
...
...
@@ -764,56 +733,31 @@ const Pool = () => {
)
}
interface
NoContentContainerProps
{
uniformHeight
:
UniformHeight
}
const
NoContentContainer
=
({
uniformHeight
}:
NoContentContainerProps
)
=>
(
const
NoContentContainer
=
()
=>
(
<>
{
uniformHeight
!==
UniformHeights
.
unset
&&
uniformHeight
!==
UniformHeights
.
notUniform
?
(
<
Box
position=
"relative"
width=
"full"
style=
{
{
paddingTop
:
'
100%
'
,
background
:
`linear-gradient(90deg, ${themeVars.colors.backgroundSurface} 0%, ${themeVars.colors.backgroundInteractive} 95.83%)`
,
}
}
>
<
Box
display=
"flex"
width=
"full"
style=
{
{
height
:
`${uniformHeight as number}px`
,
background
:
`linear-gradient(270deg, ${themeVars.colors.backgroundOutline} 0%, ${themeVars.colors.backgroundSurface} 100%)`
,
}
}
position=
"absolute"
textAlign=
"center"
left=
"1/2"
top=
"1/2"
style=
{
{
transform
:
'
translate3d(-50%, -50%, 0)
'
}
}
fontWeight=
"normal"
color=
"gray500"
className=
{
body
}
justifyContent=
"center"
alignItems=
"center"
textAlign=
"center"
>
Content not
<
br
/>
available yet
</
Box
>
)
:
(
<
Box
position=
"relative"
width=
"full"
style=
{
{
paddingTop
:
'
100%
'
,
background
:
`linear-gradient(90deg, ${themeVars.colors.backgroundSurface} 0%, ${themeVars.colors.backgroundInteractive} 95.83%)`
,
}
}
>
<
Box
position=
"absolute"
textAlign=
"center"
left=
"1/2"
top=
"1/2"
style=
{
{
transform
:
'
translate3d(-50%, -50%, 0)
'
}
}
fontWeight=
"normal"
color=
"gray500"
className=
{
body
}
>
Content not
<
br
/>
available yet
</
Box
>
</
Box
>
)
}
</
Box
>
</>
)
...
...
src/nft/components/collection/CollectionAsset.tsx
View file @
ad84da10
import
{
sendAnalyticsEvent
,
useTrace
}
from
'
@uniswap/analytics
'
import
{
EventName
,
PageName
}
from
'
@uniswap/analytics-events
'
import
{
useBag
}
from
'
nft/hooks
'
import
{
GenieAsset
,
Markets
,
UniformHeight
}
from
'
nft/types
'
import
{
GenieAsset
,
Markets
}
from
'
nft/types
'
import
{
formatWeiToDecimal
,
rarityProviderLogo
}
from
'
nft/utils
'
import
{
useCallback
,
useMemo
}
from
'
react
'
...
...
@@ -12,8 +12,6 @@ import * as Card from './Card'
interface
CollectionAssetProps
{
asset
:
GenieAsset
isMobile
:
boolean
uniformHeight
:
UniformHeight
setUniformHeight
:
(
u
:
UniformHeight
)
=>
void
mediaShouldBePlaying
:
boolean
setCurrentTokenPlayingMedia
:
(
tokenId
:
string
|
undefined
)
=>
void
rarityVerified
?:
boolean
...
...
@@ -22,8 +20,6 @@ interface CollectionAssetProps {
export
const
CollectionAsset
=
({
asset
,
isMobile
,
uniformHeight
,
setUniformHeight
,
mediaShouldBePlaying
,
setCurrentTokenPlayingMedia
,
rarityVerified
,
...
...
@@ -94,21 +90,11 @@ export const CollectionAsset = ({
/>
)
}
{
assetMediaType
===
AssetMediaType
.
Image
?
(
<
Card
.
Image
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
/>
<
Card
.
Image
/>
)
:
assetMediaType
===
AssetMediaType
.
Video
?
(
<
Card
.
Video
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
<
Card
.
Video
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
)
:
(
<
Card
.
Audio
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
<
Card
.
Audio
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
)
}
</
Card
.
ImageContainer
>
<
Card
.
DetailsContainer
>
...
...
src/nft/components/collection/CollectionNfts.tsx
View file @
ad84da10
...
...
@@ -34,7 +34,7 @@ import {
}
from
'
nft/hooks
'
import
{
useIsCollectionLoading
}
from
'
nft/hooks/useIsCollectionLoading
'
import
{
usePriceRange
}
from
'
nft/hooks/usePriceRange
'
import
{
DropDownOption
,
GenieCollection
,
Markets
,
TokenType
,
UniformHeight
,
UniformHeights
}
from
'
nft/types
'
import
{
DropDownOption
,
GenieCollection
,
Markets
,
TokenType
}
from
'
nft/types
'
import
{
getRarityStatus
}
from
'
nft/utils/asset
'
import
{
pluralize
}
from
'
nft/utils/roundAndPluralize
'
import
{
scrollToTop
}
from
'
nft/utils/scrollToTop
'
...
...
@@ -159,10 +159,10 @@ const MarketNameWrapper = styled(Row)`
gap: 8px;
`
const
loadingAssets
=
(
height
?:
number
)
=>
(
const
loadingAssets
=
()
=>
(
<>
{
Array
.
from
(
Array
(
ASSET_PAGE_SIZE
),
(
_
,
index
)
=>
(
<
CollectionAssetLoading
key=
{
index
}
height=
{
height
}
/>
<
CollectionAssetLoading
key=
{
index
}
/>
))
}
</>
)
...
...
@@ -287,7 +287,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
const
{
assets
:
collectionNfts
,
loadNext
,
hasNext
,
isLoadingNext
}
=
useLazyLoadAssetsQuery
(
assetQueryParams
)
const
[
uniformHeight
,
setUniformHeight
]
=
useState
<
UniformHeight
>
(
UniformHeights
.
unset
)
const
[
currentTokenPlayingMedia
,
setCurrentTokenPlayingMedia
]
=
useState
<
string
|
undefined
>
()
const
[
isFiltersExpanded
,
setFiltersExpanded
]
=
useFiltersExpanded
()
const
oldStateRef
=
useRef
<
CollectionFilters
|
null
>
(
null
)
...
...
@@ -309,7 +308,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
)
useEffect
(()
=>
{
setUniformHeight
(
UniformHeights
.
unset
)
setSweepOpen
(
false
)
return
()
=>
{
useCollectionFilters
.
setState
(
initialCollectionFilterState
)
...
...
@@ -323,14 +321,12 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
key=
{
asset
.
address
+
asset
.
tokenId
}
asset=
{
asset
}
isMobile=
{
isMobile
}
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
mediaShouldBePlaying=
{
asset
.
tokenId
===
currentTokenPlayingMedia
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
rarityVerified=
{
rarityVerified
}
/>
))
},
[
collectionNfts
,
currentTokenPlayingMedia
,
isMobile
,
rarityVerified
,
uniformHeight
])
},
[
collectionNfts
,
currentTokenPlayingMedia
,
isMobile
,
rarityVerified
])
const
hasNfts
=
collectionNfts
&&
collectionNfts
.
length
>
0
const
hasErc1155s
=
hasNfts
&&
collectionNfts
[
0
]
&&
collectionNfts
[
0
].
tokenType
===
TokenType
.
ERC1155
...
...
@@ -506,7 +502,7 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
<
InfiniteScroll
next=
{
()
=>
loadNext
(
ASSET_PAGE_SIZE
)
}
hasMore=
{
hasNext
}
loader=
{
hasNext
&&
hasNfts
?
loadingAssets
(
uniformHeight
)
:
null
}
loader=
{
hasNext
&&
hasNfts
?
loadingAssets
()
:
null
}
dataLength=
{
collectionNfts
?.
length
??
0
}
style=
{
{
overflow
:
'
unset
'
}
}
className=
{
hasNfts
||
isLoadingNext
?
styles
.
assetList
:
undefined
}
...
...
src/nft/components/profile/view/ProfilePage.tsx
View file @
ad84da10
...
...
@@ -20,14 +20,7 @@ import {
}
from
'
nft/hooks
'
import
{
ScreenBreakpointsPaddings
}
from
'
nft/pages/collection/index.css
'
import
{
OSCollectionsFetcher
}
from
'
nft/queries
'
import
{
ProfilePageStateType
,
TokenType
,
UniformHeight
,
UniformHeights
,
WalletAsset
,
WalletCollection
,
}
from
'
nft/types
'
import
{
ProfilePageStateType
,
TokenType
,
WalletAsset
,
WalletCollection
}
from
'
nft/types
'
import
{
Dispatch
,
SetStateAction
,
useCallback
,
useEffect
,
useState
}
from
'
react
'
import
InfiniteScroll
from
'
react-infinite-scroll-component
'
import
{
useQuery
}
from
'
react-query
'
...
...
@@ -94,7 +87,6 @@ export const ProfilePage = () => {
const
[
isFiltersExpanded
,
setFiltersExpanded
]
=
useFiltersExpanded
()
const
isMobile
=
useIsMobile
()
const
[
currentTokenPlayingMedia
,
setCurrentTokenPlayingMedia
]
=
useState
<
string
|
undefined
>
()
const
[
uniformHeight
,
setUniformHeight
]
=
useState
<
UniformHeight
>
(
UniformHeights
.
unset
)
const
handleSellModeClick
=
useCallback
(()
=>
{
resetSellAssets
()
...
...
@@ -193,8 +185,6 @@ export const ProfilePage = () => {
isSellMode=
{
isSellMode
}
mediaShouldBePlaying=
{
asset
.
tokenId
===
currentTokenPlayingMedia
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
/>
</
div
>
))
...
...
src/nft/components/profile/view/ViewMyNftsAsset.tsx
View file @
ad84da10
...
...
@@ -7,7 +7,6 @@ import { bodySmall } from 'nft/css/common.css'
import
{
themeVars
}
from
'
nft/css/sprinkles.css
'
import
{
useBag
,
useIsMobile
,
useSellAsset
}
from
'
nft/hooks
'
import
{
TokenType
,
WalletAsset
}
from
'
nft/types
'
import
{
UniformHeight
}
from
'
nft/types
'
import
{
useMemo
}
from
'
react
'
import
{
useNavigate
}
from
'
react-router-dom
'
const
NFT_DETAILS_HREF
=
(
asset
:
WalletAsset
)
=>
...
...
@@ -18,38 +17,20 @@ interface ViewMyNftsAssetProps {
isSellMode
:
boolean
mediaShouldBePlaying
:
boolean
setCurrentTokenPlayingMedia
:
(
tokenId
:
string
|
undefined
)
=>
void
uniformHeight
:
UniformHeight
setUniformHeight
:
(
u
:
UniformHeight
)
=>
void
}
const
getNftDisplayComponent
=
(
assetMediaType
:
AssetMediaType
,
mediaShouldBePlaying
:
boolean
,
setCurrentTokenPlayingMedia
:
(
tokenId
:
string
|
undefined
)
=>
void
,
uniformHeight
:
UniformHeight
,
setUniformHeight
:
(
u
:
UniformHeight
)
=>
void
setCurrentTokenPlayingMedia
:
(
tokenId
:
string
|
undefined
)
=>
void
)
=>
{
switch
(
assetMediaType
)
{
case
AssetMediaType
.
Image
:
return
<
Card
.
Image
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
/>
return
<
Card
.
Image
/>
case
AssetMediaType
.
Video
:
return
(
<
Card
.
Video
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
)
return
<
Card
.
Video
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
case
AssetMediaType
.
Audio
:
return
(
<
Card
.
Audio
uniformHeight=
{
uniformHeight
}
setUniformHeight=
{
setUniformHeight
}
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
)
return
<
Card
.
Audio
shouldPlay=
{
mediaShouldBePlaying
}
setCurrentTokenPlayingMedia=
{
setCurrentTokenPlayingMedia
}
/>
}
}
...
...
@@ -58,8 +39,6 @@ export const ViewMyNftsAsset = ({
isSellMode
,
mediaShouldBePlaying
,
setCurrentTokenPlayingMedia
,
uniformHeight
,
setUniformHeight
,
}:
ViewMyNftsAssetProps
)
=>
{
const
sellAssets
=
useSellAsset
((
state
)
=>
state
.
sellAssets
)
const
selectSellAsset
=
useSellAsset
((
state
)
=>
state
.
selectSellAsset
)
...
...
@@ -119,13 +98,7 @@ export const ViewMyNftsAsset = ({
isDisabled=
{
isDisabled
}
>
<
Card
.
ImageContainer
>
{
getNftDisplayComponent
(
assetMediaType
,
mediaShouldBePlaying
,
setCurrentTokenPlayingMedia
,
uniformHeight
,
setUniformHeight
)
}
{
getNftDisplayComponent
(
assetMediaType
,
mediaShouldBePlaying
,
setCurrentTokenPlayingMedia
)
}
</
Card
.
ImageContainer
>
<
Card
.
DetailsContainer
>
<
Card
.
ProfileNftDetails
asset=
{
asset
}
isSellMode=
{
isSellMode
}
/>
...
...
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