forked from NEAR-DevHub/neardevhub-bos
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/near/neardevhub-widgets int…
…o develop
- Loading branch information
Showing
22 changed files
with
1,273 additions
and
264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
const TextInput = ({ | ||
className, | ||
format, | ||
inputProps: { className: inputClassName, ...inputProps }, | ||
key, | ||
label, | ||
multiline, | ||
onChange, | ||
placeholder, | ||
type, | ||
value, | ||
skipPaddingGap, | ||
style, | ||
...otherProps | ||
}) => { | ||
const typeAttribute = | ||
type === "text" || | ||
type === "password" || | ||
type === "number" || | ||
type === "date" | ||
? type | ||
: "text"; | ||
|
||
const renderedLabels = [ | ||
(label?.length ?? 0) > 0 ? ( | ||
<span className="d-inline-flex gap-1 text-wrap"> | ||
<span>{label}</span> | ||
|
||
{inputProps.required ? <span className="text-danger">*</span> : null} | ||
</span> | ||
) : null, | ||
|
||
format === "markdown" ? ( | ||
<i class="bi bi-markdown text-muted" title="Markdown" /> | ||
) : null, | ||
|
||
format === "comma-separated" ? ( | ||
<span | ||
className="d-inline-flex align-items-center text-muted" | ||
style={{ fontSize: 12 }} | ||
> | ||
{format} | ||
</span> | ||
) : null, | ||
|
||
(inputProps.max ?? null) !== null ? ( | ||
<span className="d-inline-flex text-muted" style={{ fontSize: 12 }}>{`${ | ||
value?.length ?? 0 | ||
} / ${inputProps.max}`}</span> | ||
) : null, | ||
].filter((label) => label !== null); | ||
|
||
return ( | ||
<div | ||
className={[ | ||
"d-flex flex-column flex-1 align-items-start justify-content-evenly", | ||
skipPaddingGap ? "" : "gap-1 p-2", | ||
className ?? "", | ||
].join(" ")} | ||
style={style} | ||
{...otherProps} | ||
> | ||
{renderedLabels.length > 0 ? ( | ||
<span | ||
className="d-flex justify-content-between align-items-center gap-3 w-100" | ||
id={key} | ||
> | ||
{renderedLabels.map((label) => label)} | ||
</span> | ||
) : null} | ||
|
||
{!multiline ? ( | ||
<div className="input-group"> | ||
{inputProps.prefix && ( | ||
<span className="input-group-text">{inputProps.prefix}</span> | ||
)} | ||
<input | ||
aria-describedby={key} | ||
aria-label={label} | ||
className={["form-control border border-2", inputClassName].join( | ||
" " | ||
)} | ||
type={typeAttribute} | ||
{...{ onChange, placeholder, value, ...inputProps }} | ||
/> | ||
</div> | ||
) : ( | ||
<textarea | ||
aria-describedby={key} | ||
aria-label={label} | ||
className={["form-control border border-2", inputClassName].join(" ")} | ||
placeholder={ | ||
placeholder + (inputProps.required ? " ( required )" : "") | ||
} | ||
style={{ resize: inputProps.resize ?? "vertical" }} | ||
type={typeAttribute} | ||
{...{ onChange, placeholder, value, ...inputProps }} | ||
/> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
return TextInput(props); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,158 @@ | ||
const { title, content, author, image, community, tags } = props; | ||
|
||
const cidToURL = (cid) => `https://ipfs.near.social/ipfs/${cid}`; | ||
|
||
return ( | ||
<div className="card" style={{ width: "18rem" }}> | ||
{image && ( | ||
<img | ||
src={cidToURL(image.cid)} | ||
className="card-img-top" | ||
alt="Blog image" | ||
/> | ||
)} | ||
|
||
<div className="card-body"> | ||
<h5 className="card-title">{title}</h5> | ||
|
||
<p className="card-text"> | ||
<small className="text-muted">Author: {author || "AUTHOR"}</small> | ||
</p> | ||
|
||
<div> | ||
{(tags || []).map((tag) => ( | ||
<Widget | ||
src="${REPL_DEVHUB}/widget/devhub.components.atom.Tag" | ||
props={{ tag }} | ||
/> | ||
))} | ||
</div> | ||
|
||
<p className="card-text mt-2">Community: {community || "COMMUNITY"}</p> | ||
|
||
<Link to="#" className="btn btn-primary mt-2"> | ||
Read More | ||
</Link> | ||
</div> | ||
</div> | ||
); | ||
const Container = styled.div` | ||
width: 100%; | ||
height: 100%; | ||
padding: 24px; | ||
background: #fffefe; | ||
border-radius: 16px; | ||
overflow: hidden; | ||
border: 1px rgba(129, 129, 129, 0.3) solid; | ||
display: inline-flex; | ||
flex-direction: column; | ||
justify-content: flex-start; | ||
align-items: flex-start; | ||
gap: 24px; | ||
`; | ||
|
||
const InfoContainer = styled.div` | ||
padding-right: 16px; | ||
display: inline-flex; | ||
justify-content: flex-start; | ||
align-items: center; | ||
gap: 16px; | ||
`; | ||
|
||
const InfoText = styled.div` | ||
color: ${(props) => props.color || "#818181"}; | ||
font-size: 16px; | ||
font-family: ${(props) => props.fontFamily || "Aeonik Fono"}; | ||
font-weight: ${(props) => props.fontWeight || "400"}; | ||
line-height: 20px; | ||
word-wrap: break-word; | ||
`; | ||
|
||
const TitleContainer = styled.div` | ||
width: 344px; | ||
padding-right: 16px; | ||
display: inline-flex; | ||
justify-content: flex-start; | ||
align-items: center; | ||
gap: 8px; | ||
`; | ||
|
||
const Title = styled.div` | ||
width: 422px; | ||
color: #151515; | ||
font-size: 36px; | ||
font-family: "Aeonik"; | ||
font-weight: 700; | ||
line-height: 39.6px; | ||
word-wrap: break-word; | ||
`; | ||
|
||
const DescriptionContainer = styled.div` | ||
align-self: stretch; | ||
height: 155px; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: flex-start; | ||
`; | ||
|
||
const Description = styled.div` | ||
align-self: stretch; | ||
height: 103px; | ||
padding-bottom: 16px; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: flex-start; | ||
align-items: center; | ||
gap: 16px; | ||
`; | ||
|
||
const DescriptionText = styled.div` | ||
align-self: stretch; | ||
color: #151515; | ||
font-size: 24px; | ||
font-family: "Aeonik"; | ||
font-weight: 400; | ||
line-height: 28.8px; | ||
word-wrap: break-word; | ||
`; | ||
|
||
const TagsContainer = styled.div` | ||
padding: 16px; | ||
border-radius: 360px; | ||
overflow: hidden; | ||
display: inline-flex; | ||
justify-content: flex-start; | ||
align-items: center; | ||
gap: 16px; | ||
`; | ||
|
||
const Separator = styled.div` | ||
color: #8a8e93; | ||
font-size: 16px; | ||
font-family: "Circular Std"; | ||
font-weight: 400; | ||
line-height: 19.2px; | ||
word-wrap: break-word; | ||
`; | ||
|
||
function Card({ labels, data }) { | ||
const { | ||
title, | ||
subtitle, | ||
description, | ||
category, | ||
author, | ||
image, | ||
community, | ||
date, | ||
} = data; | ||
|
||
function formatDate(date) { | ||
const options = { | ||
weekday: "short", | ||
year: "numeric", | ||
month: "short", | ||
day: "numeric", | ||
hour: "2-digit", | ||
minute: "2-digit", | ||
second: "2-digit", | ||
timeZoneName: "short", | ||
}; | ||
return date.toLocaleString("en-US", options).replace(",", ""); | ||
} | ||
|
||
return ( | ||
<Container> | ||
<InfoContainer> | ||
<InfoText color="#F40303" fontWeight="700"> | ||
{category && category.toUpperCase()} | ||
</InfoText> | ||
<Separator>·</Separator> | ||
<InfoText>{date && formatDate(date)}</InfoText> | ||
</InfoContainer> | ||
<TitleContainer> | ||
<Title>{title}</Title> | ||
</TitleContainer> | ||
<DescriptionContainer> | ||
<Description> | ||
<DescriptionText>{description}</DescriptionText> | ||
</Description> | ||
<TagsContainer> | ||
{(labels || []).map((label, index) => ( | ||
<div key={label}> | ||
{index > 0 && <Separator />} | ||
<InfoText fontWeight="700">{label}</InfoText> | ||
</div> | ||
))} | ||
</TagsContainer> | ||
</DescriptionContainer> | ||
</Container> | ||
); | ||
} | ||
|
||
return { Card }; |
Oops, something went wrong.