Skip to content

Commit

Permalink
feat: blog page
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotBraem committed Oct 31, 2023
1 parent 6e266db commit 7e459b6
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 78 deletions.
9 changes: 9 additions & 0 deletions src/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ function Page() {
/>
);
}
// ?page=blog
case "blog": {
return (
<Widget
src={"${REPL_DEVHUB}/widget/devhub.page.blog"}
props={passProps}
/>
);
}
default: {
// TODO: 404 page
return <p>404</p>;
Expand Down
2 changes: 1 addition & 1 deletion src/devhub/components/molecule/Input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const TextInput = ({
...otherProps
}) => {
const typeAttribute =
type === "text" || type === "password" || type === "number" ? type : "text";
type === "text" || type === "password" || type === "number" || type === "date" ? type : "text";

const renderedLabels = [
(label?.length ?? 0) > 0 ? (
Expand Down
173 changes: 141 additions & 32 deletions src/devhub/entity/addon/blog/Card.jsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,148 @@
const cidToURL = (cid) => `https://ipfs.near.social/ipfs/${cid}`;

function Card({ title, content, author, image, community, tags }) {
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>
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;
`;

<p className="card-text mt-2">Community: {community || "COMMUNITY"}</p>
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;
`;

<Link to="#" className="btn btn-primary mt-2">
Read More
</Link>
</div>
</div>
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>
);
}

Expand Down
93 changes: 87 additions & 6 deletions src/devhub/entity/addon/blog/Creator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ const { Card } =
VM.require("${REPL_DEVHUB}/widget/devhub.entity.addon.blog.Card") ||
(() => <></>);

const categories = [
{
label: "Guide",
value: "guide",
},
{
label: "News",
value: "news",
},
];

const Banner = styled.div`
border-radius: var(--bs-border-radius-xl) !important;
height: 100%;
Expand Down Expand Up @@ -52,8 +63,12 @@ const initialData = data; // TODO: Check Storage API

const [content, setContent] = useState(initialData.content || "");
const [title, setTitle] = useState(initialData.title || "");
const [subtitle, setSubtitle] = useState(initialData.subtitle || "");
const [description, setDescription] = useState(initialData.description || "");
const [author, setAuthor] = useState(initialData.author || "");
const [previewMode, setPreviewMode] = useState("card"); // "card" or "page"
const [date, setDate] = useState(new Date().toISOString().split("T")[0]);
const [category, setCategory] = useState("guide");

// Legacy State.init for IpfsUploader
State.init({
Expand Down Expand Up @@ -89,6 +104,9 @@ const handlePublish = () => {
post_type: "Comment",
description: JSON.stringify({
title,
subtitle,
description,
date,
content,
author,
image: state.image.cid,
Expand All @@ -109,10 +127,13 @@ function Preview() {
return (
<Card
title={title}
subtitle={subtitle}
description={description}
date={date}
content={content}
author={author}
image={state.image}
tags={data.includeLabels}
tags={data.includeLabels} // filter out "blog" and community handle?
community={handle}
/>
);
Expand All @@ -123,10 +144,13 @@ function Preview() {
src="${REPL_DEVHUB}/widget/devhub.entity.addon.blog.Page"
props={{
title,
subtitle,
description,
date,
content,
author,
image: state.image,
tags: data.includeLabels,
tags: data.includeLabels, // filter out "blog" and community handle?
community: handle,
}}
/>
Expand Down Expand Up @@ -192,8 +216,7 @@ return (
<h5>Title</h5>
<div className="flex-grow-1">
<Widget
// TODO: LEGACY.
src="${REPL_DEVHUB}/widget/gigs-board.components.molecule.text-input"
src="${REPL_DEVHUB}/widget/devhub.components.molecule.Input"
props={{
className: "flex-grow-1",
onChange: (e) => setTitle(e.target.value),
Expand All @@ -203,12 +226,62 @@ return (
/>
</div>
</div>
<div>
<h5>Subtitle</h5>
<div className="flex-grow-1">
<Widget
src="${REPL_DEVHUB}/widget/devhub.components.molecule.Input"
props={{
className: "flex-grow-1",
onChange: (e) => setSubtitle(e.target.value),
value: subtitle,
placeholder: "Subtitle",
}}
/>
</div>
</div>
<div>
<h5>Category</h5>
<div className="flex-grow-1">
<Widget
src={"${REPL_NEAR}/widget/DIG.InputSelect"}
props={{
groups: [
{
items: categories.map((it) => ({
label: it.label,
value: it.value,
})),
},
],
rootProps: {
value: category,
placeholder: "Select a category",
onValueChange: (v) => setCategory(v),
},
}}
/>
</div>
</div>
<div>
<h5>Description</h5>
<div className="flex-grow-1">
<Widget
src="${REPL_DEVHUB}/widget/devhub.components.molecule.Input"
props={{
className: "flex-grow-1",
onChange: (e) => setDescription(e.target.value),
value: description,
placeholder: "Description",
}}
/>
</div>
</div>
<div>
<h5>Author</h5>
<div className="flex-grow-1">
<Widget
// TODO: LEGACY.
src="${REPL_DEVHUB}/widget/gigs-board.components.molecule.text-input"
src="${REPL_DEVHUB}/widget/devhub.components.molecule.Input"
props={{
className: "flex-grow-1",
onChange: (e) => setAuthor(e.target.value),
Expand All @@ -225,6 +298,14 @@ return (
props={{ data: { content }, onChange: setContent }}
/>
</div>
<div>
<h5>Date</h5>
<input
type="date"
value={date}
onChange={(e) => setDate(e.target.value)}
/>
</div>
</FormContainer>
<div
className={"d-flex align-items-center justify-content-end gap-3 mt-4"}
Expand Down
Loading

0 comments on commit 7e459b6

Please sign in to comment.