diff --git a/.eslintignore b/.eslintignore
index 3f5a819d..290c9003 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
workspaces/
-build/
\ No newline at end of file
+build/
+apps/
\ No newline at end of file
diff --git a/apps/homepage/widget/MetadataEditor.jsx b/apps/homepage/widget/MetadataEditor.jsx
new file mode 100644
index 00000000..9f53547c
--- /dev/null
+++ b/apps/homepage/widget/MetadataEditor.jsx
@@ -0,0 +1,204 @@
+const initialMetadata = props.initialMetadata ?? {};
+const onChange = props.onChange;
+const options = props.options;
+
+State.init({
+ initialMetadata,
+ metadata: initialMetadata,
+ reportedMetadata: initialMetadata,
+ linktree: initialMetadata.linktree ?? {},
+ image: initialMetadata.image,
+ backgroundImage: initialMetadata.backgroundImage,
+ screenshots: initialMetadata.screenshots ?? {},
+});
+
+const metadata = {
+ name: options.name ? state.metadata.name : undefined,
+ description: options.name ? state.metadata.description : undefined,
+ linktree:
+ options.linktree && Object.keys(state.linktree).length > 0
+ ? state.linktree
+ : undefined,
+ image:
+ options.image && state.image && Object.keys(state.image).length > 0
+ ? state.image
+ : undefined,
+ backgroundImage:
+ options.backgroundImage &&
+ state.backgroundImage &&
+ Object.keys(state.backgroundImage).length > 0
+ ? state.backgroundImage
+ : undefined,
+ tags: options.tags ? state.metadata.tags : undefined,
+ screenshots: options.screenshots ? state.metadata.screenshots : undefined,
+};
+
+if (
+ onChange &&
+ JSON.stringify(state.reportedMetadata) !== JSON.stringify(metadata)
+) {
+ State.update({
+ reportedMetadata: metadata,
+ });
+ onChange(metadata);
+}
+
+const Container = styled.div`
+ color: #fff;
+`;
+
+const CustomTagEditor = styled.div`
+ .form-control {
+ background: #23242b;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ }
+`;
+
+const CustomImageUpload = styled.div`
+ .nav-link {
+ background: transparent;
+ color: #fff;
+ border: none;
+ }
+
+ .nav.nav-tabs {
+ border: none;
+ }
+
+ .nav-link.active {
+ color: #fff;
+ background: transparent;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-bottom: none;
+ }
+
+ .p-2 {
+ border: none;
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
+ /* border-top: 0; */
+ background: #23242b !important;
+ color: #fff !important;
+ }
+
+ .form-control {
+ background: #23242b;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ }
+`;
+
+return (
+
+ {options.name && (
+
+ {options.name.label ?? "Name"}
+
+
+ )}
+ {options.image && (
+
+
+ {options.image.label ?? "Image"}
+
+
+ State.update({ image }),
+ }}
+ />
+
+
+ )}
+ {options.backgroundImage && (
+
+
+ {options.backgroundImage.label ?? "Background image"}
+
+ State.update({ backgroundImage }),
+ }}
+ />
+
+ )}
+ {options.description && (
+
+
+ {options.description.label ?? "Description"}
+
+ (supports markdown)
+
+ )}
+ {options.tags && (
+
+ {options.tags.label ?? "Tags"}
+ {
+ state.metadata.tags = tags;
+ State.update();
+ },
+ }}
+ />
+
+ )}
+ {options.linktree &&
+ (options.linktree.links ?? []).map((link) => (
+
+
{link.label}
+
+
+ {link.prefix}
+
+
+
+
+ ))}
+
+);
diff --git a/apps/homepage/widget/WidgetMetadata.jsx b/apps/homepage/widget/WidgetMetadata.jsx
new file mode 100644
index 00000000..774d9591
--- /dev/null
+++ b/apps/homepage/widget/WidgetMetadata.jsx
@@ -0,0 +1,181 @@
+const accountId = props.accountId;
+const widgetName = props.widgetName;
+const widgetPath = `${accountId}/widget/${widgetName}`;
+const blockHeight = props.blockHeight;
+const metadata = props.metadata ?? Social.getr(`${widgetPath}/metadata`);
+const renderTag = props.renderTag;
+
+const name = metadata.name ?? widgetName;
+const description = metadata.description;
+const image = metadata.image;
+const tags = Object.keys(metadata.tags ?? {});
+const expanded = !!props.expanded;
+
+const linktree = Object.entries(metadata.linktree ?? {});
+const linktreeElements = {
+ website: {
+ prefix: "https://",
+ icon: "bi-globe2",
+ },
+};
+
+const CustomProfileLink = styled.div`
+ * {
+ color: #fff !important;
+ }
+`;
+
+const linktreeObjects = linktree.map((o, i) => {
+ const key = o[0];
+ let value = o[1];
+ if (!value) {
+ return null;
+ }
+ const e = linktreeElements[key];
+ if (e.prefix) {
+ value = value && value.replace(e.prefix, "");
+ }
+ const icon = e.icon ? (
+
+ ) : (
+ ""
+ );
+ return e.prefix ? (
+
+ ) : (
+
+ {key}: {icon}
+ {value}
+
+ );
+});
+
+const descriptionKey = `${widgetPath}-description`.replaceAll(/[._\/-]/g, "--");
+
+return (
+
+
+
+
+ {linktreeObjects}
+
+
+
+);
diff --git a/apps/homepage/widget/WidgetMetadataEditor.jsx b/apps/homepage/widget/WidgetMetadataEditor.jsx
new file mode 100644
index 00000000..34c6d5c9
--- /dev/null
+++ b/apps/homepage/widget/WidgetMetadataEditor.jsx
@@ -0,0 +1,38 @@
+const widgetPath = props.widgetPath;
+const onChange = props.onChange;
+
+let metadata = Social.getr(`${widgetPath}/metadata`);
+
+if (metadata === null) {
+ return "Loading";
+}
+
+return (
+
+);
diff --git a/apps/homepage/widget/community/join.jsx b/apps/homepage/widget/community/join.jsx
new file mode 100644
index 00000000..e2169701
--- /dev/null
+++ b/apps/homepage/widget/community/join.jsx
@@ -0,0 +1,147 @@
+const accountId = context.accountId;
+const roleId = props.roleId ?? "community";
+const daoId = props.daoId ?? "build.sputnik-dao.near";
+const proposalId =
+ props.proposalId ?? Near.view(daoId, "get_last_proposal_id") - 1;
+
+if (!accountId) {
+ return "";
+}
+
+State.init({
+ isMember: false,
+});
+
+// get DAO policy, deposit, and group
+const policy = Near.view(daoId, "get_policy");
+
+if (policy === null) {
+ return "";
+}
+
+const deposit = policy.proposal_bond;
+
+const group = policy.roles
+ .filter((role) => role.name === roleId)
+ .map((role) => role.kind.Group);
+
+// get data from last proposal
+const proposal = Near.view(daoId, "get_proposal", {
+ id: proposalId,
+});
+
+if (proposal === null) {
+ return "";
+}
+
+// check if the potential member submitted last proposal
+const canJoin = accountId && accountId !== proposal.proposer;
+
+const handleJoin = () => {
+ Near.call([
+ {
+ contractName: daoId,
+ methodName: "add_proposal",
+ args: {
+ proposal: {
+ description: `add ${accountId} to the ${roleId} group`,
+ kind: {
+ AddMemberToRole: {
+ member_id: accountId,
+ role: roleId,
+ },
+ },
+ },
+ },
+ gas: 219000000000000,
+ deposit: deposit,
+ },
+ ]);
+};
+
+const groupMembers = group.join(", ");
+
+const checkMembership = (groupMembers) => {
+ if (groupMembers.indexOf(accountId) !== -1) {
+ return State.update({ isMember: true });
+ }
+};
+
+const validMember = checkMembership(groupMembers);
+
+// check if the potential member is a verified human
+let human = false;
+const userSBTs = Near.view("registry.i-am-human.near", "sbt_tokens_by_owner", {
+ account: accountId,
+});
+
+for (let i = 0; i < userSBTs.length; i++) {
+ if ("fractal.i-am-human.near" == userSBTs[i][0]) {
+ human = true;
+ }
+}
+
+// check if the potential member is connected
+const connectEdge = Social.keys(
+ `${accountId}/graph/connect/${daoId}`,
+ undefined,
+ {
+ values_only: true,
+ }
+);
+
+const loading = connectEdge === null || inverseEdge === null;
+const isConnected = connectEdge && Object.keys(connectEdge).length;
+
+return (
+
+ {!isConnected ? (
+
+ ) : (
+ <>
+ {!validMember ? (
+ <>
+ {canJoin ? (
+
+ Join DAO
+
+ ) : (
+ <>
+
+ Pending
+
+
+ Customize
+
+ >
+ )}
+ >
+ ) : (
+ <>
+
+ Joined
+
+
+ Customize
+
+ >
+ )}
+ >
+ )}
+
+);
diff --git a/apps/homepage/widget/create-something.jsx b/apps/homepage/widget/create-something.jsx
new file mode 100644
index 00000000..dfd5a860
--- /dev/null
+++ b/apps/homepage/widget/create-something.jsx
@@ -0,0 +1,280 @@
+const [isMember, setIsMember] = useState(false);
+
+if (!context.accountId) {
+ return "Login to continue...";
+}
+
+const JoinContainer = styled.div`
+ padding: 3rem;
+ background-color: #0b0c14;
+ color: #fff;
+ height: 100%;
+
+ position: relative;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+const Card = styled.div`
+ display: flex;
+ max-width: 500px;
+ width: 100%;
+ max-height: 550px;
+ padding: 80px 24px;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 40px;
+
+ border-radius: 32px;
+ background: var(--bg-2, #23242b);
+
+ img {
+ width: auto;
+ height: 54px;
+ }
+
+ h1 {
+ color: var(--white-100, #fff);
+ text-align: center;
+
+ /* H1/small */
+ font-size: 2rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 100%; /* 32px */
+ }
+`;
+
+const CTASection = styled.div`
+ display: flex;
+ padding: 24px;
+ flex-direction: column;
+ align-items: center;
+ gap: 24px;
+ align-self: stretch;
+
+ h3 {
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+ text-align: center;
+
+ /* H3/Small */
+ font-size: 20px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 140%; /* 28px */
+ }
+
+ a,
+ button {
+ all: unset;
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ &:hover {
+ text-decoration: none;
+ color: #000 !important;
+ cursor: pointer;
+ background: var(--Yellow, #ffaf51);
+ }
+
+ border-radius: 8px;
+ background: var(--Yellow, #ffaf51);
+
+ color: var(--black-100, #000);
+
+ /* Other/Button_text */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ }
+
+ span.pending {
+ display: flex;
+ padding: 4px 12px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 8px;
+ border: 1px solid rgba(81, 182, 255, 0.2);
+ background: rgba(81, 182, 255, 0.2);
+
+ color: var(--Blue, #51b6ff);
+
+ /* Other/Button_text */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ }
+
+ span.joined {
+ display: flex;
+ padding: 4px 12px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 8px;
+ border: 1px solid rgba(81, 255, 234, 0.2);
+ background: rgba(81, 255, 234, 0.2);
+
+ color: var(--Sea-Blue, #51ffea);
+
+ /* Other/Button_text */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ }
+`;
+
+const userWidgets = Social.keys(`${context.accountId}/widget/**`) || [];
+
+const daoId = "build.sputnik-dao.near";
+const accountId = context.accountId;
+
+// get DAO policy, deposit, and group
+const policy = Near.view(daoId, "get_policy");
+
+if (policy === null) {
+ return "";
+}
+
+const deposit = policy.proposal_bond;
+const roleId = "community";
+const group = policy.roles
+ .filter((role) => role.name === roleId)
+ .map((role) => role.kind.Group);
+
+const handleJoin = () => {
+ Near.call([
+ {
+ contractName: daoId,
+ methodName: "add_proposal",
+ args: {
+ proposal: {
+ description: `add ${accountId} to the ${roleId} group`,
+ kind: {
+ AddMemberToRole: {
+ member_id: accountId,
+ role: roleId,
+ },
+ },
+ },
+ },
+ gas: 219000000000000,
+ deposit: deposit,
+ },
+ ]);
+};
+
+const proposalId = Near.view(daoId, "get_last_proposal_id") - 1;
+
+// get data from last proposal
+const proposal = Near.view(daoId, "get_proposal", {
+ id: proposalId,
+});
+
+if (proposal === null) {
+ return "";
+}
+
+// check if the potential member submitted last proposal
+const canJoin = accountId && accountId !== proposal.proposer;
+
+const groupMembers = group.join(", ");
+
+const checkMembership = (groupMembers) => {
+ if (groupMembers.indexOf(accountId) !== -1) {
+ return setIsMember(true);
+ }
+};
+
+const validMember = checkMembership(groupMembers);
+
+const CreateSomethingView = (props) => {
+ return (
+
+
+ {" "}
+
+
+ Designed to connect and empower builders in a multi-chain ecosystem
+
+
+ {userWidgets.length === 0 ? (
+ <>
+ In order to join Build DAO, you need to create a widget
+
+ Create Something{" "}
+
+
+
+
+ >
+ ) : (
+ <>
+ {canJoin ? (
+
+ Join Build DAO{" "}
+
+
+
+
+ ) : (
+ <>
+
+ {!validMember ? "Pending..." : "Joined"}
+
+
+ Propose Changes{" "}
+
+
+
+
+ >
+ )}
+ >
+ )}{" "}
+
+
+
+ );
+};
+
+return ;
diff --git a/apps/homepage/widget/home.jsx b/apps/homepage/widget/home.jsx
index aafed715..db50e0b5 100644
--- a/apps/homepage/widget/home.jsx
+++ b/apps/homepage/widget/home.jsx
@@ -1,842 +1,22 @@
-let theme = props.theme;
-let variables = props.variables;
-
-if (!variables) {
- variables = `
- --bg-1: #0B0C14;
- --bg-2: #23242B;
- --white-100: #FFF;
- --white-50: rgba(255, 255, 255, 0.70);
- --yellow: #FFAF51;
- --stroke-color: rgba(255, 255, 255, 0.2);
- --sea-blue: #51FFEA;
- `;
-}
-
-if (!theme) {
- theme = ``;
-}
+const ownerId = "builddao.near";
const Root = styled.div`
- ${variables}
- ${theme}
-`;
-
-const Container = styled.div`
- display: flex;
- width: 100vw;
- flex-direction: column;
- align-items: flex-start;
-
- background-color: var(--bg-1);
-
- overflow-x: hidden;
-`;
-
-const Hero = styled.div`
- display: flex;
- width: 100%;
- padding: 150px 48px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 40px;
- align-self: stretch;
-
- text-align: center;
- position: relative;
-
- // overflow-x: hidden;
-`;
+ background-color: #0b0c14;
+ color: #ffffff;
+ font-family: Satoshi;
-const Grid = styled.img`
- position: absolute;
- margin: 0 !important;
- left: 0rem;
width: 100%;
- object-fit: cover;
- z-index: 0;
-
- opacity: 0.01;
-`;
-
-const Blur = styled.div`
- width: 560px;
- height: 560px;
- position: absolute;
- border-radius: 560px;
- background: rgba(${(props) => props.color}, 0.1);
- filter: blur(129.5px);
-
- ${(props) =>
- props.position === "left" &&
- `
- left: -216px;
- bottom: -31px;
- `}
-
- ${(props) =>
- props.position === "right" &&
- `
- right: -216px;
- bottom: -269px;
- `}
-`;
-
-const Logo = styled.img`
- width: 138px;
- height: 54px;
-`;
-
-const Headline = styled.h1`
- color: var(--white-100);
- max-width: 700px;
-
- font-size: 48px;
- font-style: normal;
- font-weight: 500;
- line-height: 120%;
-
- white-space: pre-line;
-`;
-
-const ColoredText = styled.span`
- color: ${(props) => props.color};
-`;
-
-const FrameChild = styled.img`
- height: 100%;
- object-fit: cover;
-`;
-
-const Goals = styled.div`
- display: flex;
- padding: 100px 48px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 50px;
- align-self: stretch;
`;
-const Tag = styled.div`
- display: flex;
- padding: 8px 12px;
- justify-content: center;
- align-items: center;
- gap: 4px;
-
- border-radius: 100px;
- border: 1px solid var(--yellow);
- background: rgba(255, 189, 52, 0.2);
-
- color: var(--yellow);
- text-align: center;
- leading-trim: both;
- text-edge: cap;
- font-size: 12px;
- font-style: normal;
- font-weight: 500;
- line-height: normal;
- text-transform: capitalize;
-`;
-
-const SectionHeader = styled.h2`
- max-width: 600px;
-
- color: var(--white-100);
- text-align: center;
-
- font-size: 40px;
- font-style: normal;
- font-weight: 500;
- line-height: 120%;
-
- white-space: pre-line;
-`;
-
-const SectionSubtitle = styled.div`
- max-width: 500px;
-
- color: var(--white-50);
- text-align: center;
-
- font-size: 16px;
- font-style: normal;
- font-weight: 400;
- line-height: 170%; /* 27.2px */
-`;
-
-const Objectives = styled.div`
- display: flex;
- max-width: 1200px;
- flex-direction: column;
- align-items: flex-start;
- gap: 40px;
-`;
-
-const ObjectivesTop = styled.div`
- display: flex;
- padding: 40px;
- justify-content: center;
- align-items: center;
- gap: 24px;
-
- border-radius: 16px;
- border: 1px solid #51ffea;
- background: var(--bg-2);
-`;
-
-const ObjectivesTopLeft = styled.div`
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- gap: 16px;
- flex: 1 0 0;
-`;
-
-const ObjectiveTitle = styled.div`
- color: var(--yellow);
-
- font-size: 14px;
- font-style: normal;
- font-weight: 500;
- line-height: 160%;
- text-transform: uppercase;
-`;
-
-const ObjectiveSubtitle = styled.h3`
- color: var(--white-100);
-
- font-size: 24px;
- font-style: normal;
- font-weight: 500;
- line-height: 140%;
-`;
-
-const ObjectiveBody = styled.div`
- color: var(--white-50);
-
- font-size: 16px;
- font-style: normal;
- font-weight: 400;
- line-height: 170%;
-`;
-
-const ObjectivesTopRight = styled.div`
- display: flex;
- height: 434px;
- padding: 36px 48.872px 36.231px 49px;
- justify-content: center;
- align-items: center;
- flex: 1 0 0;
-`;
-
-const ObjectivesBottom = styled.div`
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 40px;
-`;
-
-const ObjectiveCard = styled.div`
- display: flex;
- height: 635.75px;
- padding: 40px;
- flex-direction: column;
- justify-content: center;
- gap: 24px;
- flex: 1 0 0;
-
- border-radius: 16px;
- border: 1px solid var(--stroke-color);
- background: var(--bg-2, #23242b);
-`;
-
-const ObjectiveImage = styled.div`
- display: flex;
- height: 265px;
- padding: 20.125px 96.964px 20.125px 96px;
- justify-content: center;
- align-items: center;
- flex-shrink: 0;
-`;
-
-const EducationImage = styled.div`
- width: 307.036px;
- height: 224.75px;
-
- border-radius: 14.124px;
- background: url("https://ipfs.near.social/ipfs/bafkreigdor4dtdj5sfq6g2m6wvsfihx72psb7sc5wtx6mbp7g7kxetrpsi"),
- lightgray 50% / contain no-repeat;
-`;
-
-const CommunityImage = styled.div`
- width: 307px;
- height: 224.724px;
-
- border-radius: 14.124px;
- background: url("https://ipfs.near.social/ipfs/bafkreie2iztiiskycciokdlvqxy5z63lq7iac7r72zoybinya6p6yzf6nu"),
- lightgray 50% / contain no-repeat;
-`;
-
-const Join = styled.div`
- display: flex;
- padding: 100px 48px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 40px;
- align-self: stretch;
-`;
-
-const JoinHeading = styled.div`
- display: flex;
- width: 700px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 16px;
-`;
-
-const JoinItems = styled.div`
- display: flex;
- width: 600px;
- height: 312px;
- max-width: 600px;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- gap: 16px;
-`;
-
-const JoinItem = styled.div`
- display: flex;
- padding: 12px;
- align-items: flex-start;
- gap: 16px;
- align-self: stretch;
-
- border-radius: 12px;
- border: 1px solid var(--stroke-color);
- background: var(--bg-2);
-`;
-
-const JoinItemIcon = styled.div`
- display: flex;
- width: 64px;
- height: 64px;
- padding: 20px;
- justify-content: center;
- align-items: center;
-
- border-radius: 8px;
- border: 1px solid var(--sea-blue);
-`;
-
-const JoinItemBody = styled.div`
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- gap: 8px;
- flex: 1 0 0;
-`;
-
-const JoinItemTitle = styled.h4`
- color: var(--white-100);
-
- font-size: 18px;
- font-style: normal;
- font-weight: 500;
- line-height: 160%; /* 28.8px */
-`;
-
-const JoinItemSubtitle = styled.h4`
- color: var(--white-50);
-
- font-size: 16px;
- font-style: normal;
- font-weight: 400;
- line-height: 170%; /* 27.2px */
-`;
-
-const HowToJoinContainer = styled.div`
- display: flex;
- max-width: 1200px;
- padding: 40px;
- justify-content: center;
- align-items: flex-start;
- gap: 40px;
- align-self: stretch;
-
- border-radius: 16px;
- border: 1px solid var(--sea-blue);
- background: rgba(81, 255, 234, 0.1);
- box-shadow: 4px 24px 48px 0px rgba(81, 255, 234, 0.1);
-`;
-
-const HowToJoin = styled.h2`
- max-width: 500px;
- flex: 1 0 0;
- color: var(--white-100);
-
- font-size: 40px;
- font-style: normal;
- font-weight: 500;
- line-height: 120%; /* 48px */
-`;
-
-const HowToJoinRight = styled.div`
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- gap: 24px;
- flex: 1 0 0;
-`;
-
-const HowToJoinInstructions = styled.div`
- color: var(--sea-blue);
-
- font-size: 16px;
- font-style: normal;
- font-weight: 400;
- line-height: 170%; /* 27.2px */
-`;
-
-const JoinButton = styled.div`
- display: flex;
- padding: 10px 20px;
- justify-content: center;
- align-items: center;
- gap: 4px;
-
- border-radius: 8px;
- background: var(--yellow);
-`;
-
-const Governance = styled.div`
- display: flex;
- padding: 100px 48px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 40px;
- align-self: stretch;
-`;
-
-const GovernanceImage = styled.img`
- height: 447px;
- max-width: 1200px;
-`;
-
-const CTA = styled.div`
- postition: relative;
- display: flex;
- height: 816px;
- padding: 100px 48px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 40px;
- align-self: stretch;
-`;
-
-const CTAWrapper = styled.div`
- display: flex;
- width: 600px;
- padding: 40px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 40px;
-
- border-radius: 16px;
- border: 1px solid #51b6ff;
- background: var(--black-100);
- box-shadow: 4px 24px 48px 0px rgba(255, 189, 52, 0.1);
-`;
-
-const CTABody = styled.h1`
- color: var(--white-100);
- text-align: center;
-
- font-size: 48px;
- font-style: normal;
- font-weight: 500;
- line-height: 120%; /* 57.6px */
-`;
-
-const Footer = styled.div`
- display: flex;
- padding: 50px;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 24px;
- align-self: stretch;
-`;
-
-const Socials = styled.div`
- display: flex;
- align-items: flex-start;
- align-content: flex-start;
- gap: 12px;
- flex-wrap: wrap;
-`;
-
-const FooterReserved = styled.div`
- color: var(--white-50);
- text-align: center;
-
- font-size: 16px;
- font-style: normal;
- font-weight: 400;
- line-height: 170%; /* 27.2px */
-`;
+const sections = ["hero", "goals", "join", "governance", "cta", "footer"];
return (
-
-
-
-
-
- {`Designed to connect and empower builders in a `}
-
- multi-chain ecosystem
-
-
-
-
-
-
-
- Goals{" "}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Primary Objectives
-
-
-
-
- Development
- Support builders
-
- {`The core mission is to build open-source infrastructure and web applications for everyone. By creating systems to reward useful contributions, we can grow successful projects that solve problems and generate sustainable value.`}
-
-
-
-
-
-
-
-
-
-
-
- Education
- Learn together
-
- {`We are cultivating a worldwide community of builders who are motivated to help others. Members can earn badges and get necessary resources for training potential contributors.`}
-
-
-
-
-
-
- Community
- Facilitate Governance
-
- {`We introduced on-chain feedback channels to gather input from participants. This will be crucial for understanding common issues, optimizing documentation, and improving quality of experience.`}
-
-
-
-
-
-
-
-
- Join{" "}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {`Open call for members to `}
-
- join and contribute
-
-
-
- Build DAO is an innovative, community-led organization intended to
- serve the open web ecosystem in multiple ways:
-
-
-
-
-
-
-
-
-
-
- Vote on Important Decisions
-
- Members collectively shape community programs and policies.
-
-
-
-
-
-
-
-
-
-
- Earn Recognition and Rewards
-
- Members develop their own reputations as builders.
-
-
-
-
-
-
-
-
-
-
- Discover Opportunities
-
- Members gain exposure to new gigs and interesting projects.
-
-
-
-
-
- How to Join
-
-
- 1. Sign membership agreement (on-chain)
- 2. Propose to be added to the “Community” role
- 3. Fulfill contribution requirements
-
- Join
-
-
-
-
-
-
- Goverance{" "}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Let's coordinate!
-
- {`Build DAO upholds the principles of openness and accountability in its decision-making processes. We believe success depends on metagovernance of builders, by builders, for builders.`}
-
-
-
-
-
-
-
-
- Together, we can build a better future.
- Join
-
-
-
-
-
-
- @2023 BuildDAO all rights reserved
-
-
+ {sections.map((section) => (
+
+ ))}
);
diff --git a/apps/homepage/widget/login.jsx b/apps/homepage/widget/login.jsx
new file mode 100644
index 00000000..9d05322b
--- /dev/null
+++ b/apps/homepage/widget/login.jsx
@@ -0,0 +1,94 @@
+const LoginContainer = styled.div`
+ background-color: #0b0c14;
+ color: #fff;
+ height: 100%;
+
+ position: relative;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ img {
+ width: 100%;
+ max-height: 100vh;
+ object-fit: cover;
+ object-position: center top;
+ position: absolute;
+ top: 0%;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ .card {
+ z-index: 5;
+ background: transparent;
+ display: flex;
+ max-width: 500px;
+ width: 100%;
+ max-height: 550px;
+ padding: 80px 24px;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 40px;
+
+ img {
+ width: auto;
+ height: 54px;
+ object-fit: cover;
+ }
+
+ h1 {
+ color: var(--white-100, #fff);
+ text-align: center;
+
+ /* H1/small */
+ font-size: 2rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 100%; /* 32px */
+ }
+
+ a {
+ display: flex;
+ padding: 16px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+ align-self: stretch;
+
+ border-radius: 8px;
+ border: 1px solid var(--white-100, #fff);
+ background: #fff;
+
+ &:hover {
+ text-decoration: none;
+ }
+
+ color: var(--black-100, #000);
+
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ }
+ }
+`;
+
+const LoginView = () => {
+ return (
+
+
+
+
+ Designed to connect and empower builders in a multi-chain ecosystem
+
+
Login
+
+
+
+ );
+};
+
+return ;
diff --git a/apps/homepage/widget/propose-widget.jsx b/apps/homepage/widget/propose-widget.jsx
new file mode 100644
index 00000000..a4444aba
--- /dev/null
+++ b/apps/homepage/widget/propose-widget.jsx
@@ -0,0 +1,28 @@
+const [proposalWidget, setProposalWidget] = useState("");
+
+return (
+ <>
+ Propose a new page
+ setProposalWidget(e.target.value)}
+ />
+
+ {" "}
+ Propose{" "}
+
+
+
+
+ >
+);
diff --git a/apps/homepage/widget/propose.jsx b/apps/homepage/widget/propose.jsx
new file mode 100644
index 00000000..d34b1891
--- /dev/null
+++ b/apps/homepage/widget/propose.jsx
@@ -0,0 +1,198 @@
+const [view, setView] = useState("selection");
+const [selection, setSelection] = useState(0);
+
+const Container = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+
+ background: #0b0c14;
+ color: #fff;
+`;
+
+const Card = styled.div`
+ display: flex;
+ padding: 80px 24px;
+ max-width: 500px;
+ width: 100%;
+ flex-direction: column;
+ align-items: center;
+ gap: 40px;
+
+ h1 {
+ color: var(--white-100, #fff);
+ text-align: center;
+
+ /* H1/small */
+ font-size: 32px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 100%; /* 32px */
+ }
+
+ span.disabled {
+ cursor: not-allowed !important;
+ }
+
+ input {
+ border-radius: 4px;
+ border: 1px solid var(--Stroke-color, rgba(255, 255, 255, 0.2));
+
+ padding: 12px;
+
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+ /* Body/Small */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 23.8px */
+
+ background-color: #0b0c14;
+ }
+
+ .form-control:focus {
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+ background-color: #0b0c14;
+ }
+
+ input::placeholder {
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+ /* Body/Small */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 23.8px */
+ }
+
+ a {
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 8px;
+ background: var(--Yellow, #ffaf51);
+
+ color: var(--black-100, #000) !important;
+
+ ${selection === 0 && "pointer-events: none;"}
+
+ /* Other/Button_text */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+
+ &:hover {
+ text-decoration: none;
+ }
+ }
+`;
+
+const Box = styled.div`
+ display: flex;
+ width: 200px;
+ padding: 40px 16px;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 24px;
+
+ border-radius: 16px;
+ background: var(--bg-2, #23242b);
+
+ cursor: pointer;
+
+ h3 {
+ color: var(--white-100, #fff);
+
+ /* H3/Small */
+ font-size: 20px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 140%; /* 28px */
+ }
+`;
+
+const SelectionBox = ({ title, selected, value }) => {
+ return (
+ setSelection(value)}>
+ {selected ? (
+
+
+
+ ) : (
+
+
+
+ )}
+ {title}
+
+ );
+};
+
+return (
+
+
+ {view === "selection" ? (
+ <>
+ What would you like to do?
+
+
+
+
+
+ selection === 2 && setView("proposal")}
+ >
+ Continue{" "}
+
+
+
+
+
+ >
+ ) : (
+
+ )}
+
+
+);
diff --git a/apps/homepage/widget/section/cta.jsx b/apps/homepage/widget/section/cta.jsx
new file mode 100644
index 00000000..ddf8b860
--- /dev/null
+++ b/apps/homepage/widget/section/cta.jsx
@@ -0,0 +1,142 @@
+const logoLink =
+ "https://ipfs.near.social/ipfs/bafkreihbwho3qfvnu4yss3eh5jrx6uxhrlzdgtdjyzyjrpa6odro6wdxya";
+const gridLink =
+ "https://ipfs.near.social/ipfs/bafkreiay3ytllrxhtyunppqxcazpistttwdzlz3jefdbsq5tosxuryauu4";
+const leftBlur =
+ "https://ipfs.near.social/ipfs/bafkreig2cgzqloepedal5ypphzhzcakl5uoedxjtvbpxbxnywerjbzmfpm";
+const rightBlur =
+ "https://ipfs.near.social/ipfs/bafkreierwhnzytfajagidxim5mzdphu5fopjmlrxehatywzuy6ahr5q7pe";
+
+const CTAContainer = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+
+ position: relative;
+
+ padding: 6.25rem 3rem;
+
+ @media screen and (max-width: 768px) {
+ padding: 6.25rem 1.5rem;
+ }
+`;
+
+const LeftBlur = styled.img`
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ object-fit: cover;
+ width: 25%;
+
+ @media screen and (max-width: 768px) {
+ width: 50%;
+ opacity: 0.5;
+ }
+`;
+
+const RightBlur = styled.img`
+ position: absolute;
+ right: 0;
+ top: 75%;
+ transform: translateY(-50%);
+ object-fit: cover;
+ width: 25%;
+
+ @media screen and (max-width: 768px) {
+ width: 50%;
+ opacity: 0.5;
+ }
+`;
+
+const Grid = styled.img`
+ position: absolute;
+ top: 0;
+ left: 0;
+ opacity: 0.05;
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+`;
+
+const Card = styled.div`
+ z-index: 2;
+ display: flex;
+ max-width: 37.5rem;
+ padding: 2.5rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+
+ border-radius: 16px;
+ border: 1px solid #51b6ff;
+ background: #000;
+ box-shadow: 4px 24px 48px 0px rgba(255, 189, 52, 0.1);
+
+ h1 {
+ color: #fff;
+ text-align: center;
+
+ /* H1/large */
+ font-size: 48px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 120%; /* 57.6px */
+ margin: 0;
+ }
+
+ a {
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 8px;
+ background: #ffaf51;
+
+ color: #000;
+ margin: 0;
+
+ /* Other/Button_text */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+
+ text-decoration: none;
+ transition: all 300ms;
+
+ &:hover {
+ background: #c98a40;
+ }
+ }
+
+ @media screen and (max-width: 768px) {
+ h1 {
+ font-size: 2rem;
+ }
+ }
+`;
+
+const Logo = styled.img`
+ height: 2.875rem;
+ object-fit: cover;
+`;
+
+return (
+
+
+
+ Together, we can build a better future.
+ Join Now
+
+
+
+
+
+);
diff --git a/apps/homepage/widget/section/footer.jsx b/apps/homepage/widget/section/footer.jsx
new file mode 100644
index 00000000..3c6e89c4
--- /dev/null
+++ b/apps/homepage/widget/section/footer.jsx
@@ -0,0 +1,92 @@
+const Footer = styled.div`
+ display: flex;
+ flex-direction: column;
+ padding: 3.125rem;
+ justify-content: center;
+ align-items: center;
+ gap: 1.5rem;
+ align-self: stretch;
+ background-color: #0b0c14;
+ width: 100%;
+
+ p {
+ max-width: 700px;
+
+ align-self: stretch;
+
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+ text-align: center;
+
+ /* Body/Large */
+ font-family: Satoshi;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 27.2px */
+ margin: 0 auto;
+ }
+`;
+
+const InstagramIcon = (
+
+
+
+);
+
+const XIcon = (
+
+
+
+);
+
+const YoutubeIcon = (
+
+
+
+);
+
+const SocialContainer = styled.div`
+ display: flex;
+ gap: 1.25rem;
+ align-items: center;
+`;
+
+const date = new Date();
+
+return (
+
+);
diff --git a/apps/homepage/widget/section/goals.jsx b/apps/homepage/widget/section/goals.jsx
index e69de29b..90b324b7 100644
--- a/apps/homepage/widget/section/goals.jsx
+++ b/apps/homepage/widget/section/goals.jsx
@@ -0,0 +1,245 @@
+const GoalsContainer = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 3.125rem;
+
+ position: relative;
+
+ padding: 6.25rem 3rem;
+
+ @media screen and (max-width: 768px) {
+ padding: 6.25rem 1.5rem;
+ }
+`;
+
+const SectionPill = ({ title, icon }) => {
+ const Pill = styled.div`
+ display: flex;
+ padding: 8px 12px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 100px;
+ border: 1px solid var(--Yellow, #ffaf51);
+ background: rgba(255, 189, 52, 0.2);
+
+ color: var(--Yellow, #ffaf51);
+ text-align: center;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ text-transform: capitalize;
+
+ width: max-content;
+ `;
+
+ return (
+
+ {title} {icon}
+
+ );
+};
+
+const MagicIcon = (
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+const Title = styled.h2`
+ color: #fff;
+ text-align: center;
+ font-size: 2.5rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 120%; /* 48px */
+ margin: 0;
+
+ span.yellow {
+ color: var(--Yellow, #ffaf51);
+ }
+
+ @media screen and (max-width: 768px) {
+ font-size: 1.5rem;
+ }
+`;
+
+const GridContainer = styled.div`
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 2.5rem;
+
+ @media screen and (max-width: 768px) {
+ display: flex;
+ flex-direction: column;
+ gap: 2.5rem;
+ }
+`;
+
+const GridItem = ({ tag, title, description, image, isFirst }) => {
+ const Card = styled.div`
+ display: flex;
+ max-height: 635.75px;
+ padding: 2.5rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 1.5rem;
+ ${isFirst && "grid-column: 1 / span 2;"}
+ ${isFirst && "flex-direction: row-reverse;"}
+
+ border-radius: 16px;
+ border: 1px solid var(--Stroke-color, rgba(255, 255, 255, 0.2));
+ background: var(--bg-2, #23242b);
+
+ ${isFirst && "border: 1px solid #51FFEA;"}
+
+ div {
+ flex: 0 1 auto;
+ }
+
+ div.content {
+ width: 100%;
+ ${isFirst && "max-width: 50%;"}
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+
+ span.tag {
+ color: var(--Yellow, #ffaf51);
+
+ /* Other/CAPS */
+ font-size: 0.875rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 160%; /* 22.4px */
+ text-transform: uppercase;
+ }
+
+ h3 {
+ color: var(--white-100, #fff);
+
+ /* H3/Large */
+ font-size: 1.5rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 140%; /* 33.6px */
+ margin: 0;
+ }
+
+ p {
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+
+ /* Body/Large */
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 27.2px */
+ margin: 0;
+ }
+ }
+
+ div.image img {
+ width: 100%;
+ max-width: 600px;
+ max-height: 400px;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ @media screen and (max-width: 768px) {
+ flex-direction: column;
+ div.content {
+ max-width: 100%;
+ }
+ }
+ `;
+ return (
+
+
+
+
+
+
{tag}
+
{title}
+
{description}
+
+
+ );
+};
+
+return (
+
+
+
+ Primary Objectives
+
+
+
+
+
+
+
+);
diff --git a/apps/homepage/widget/section/governance.jsx b/apps/homepage/widget/section/governance.jsx
new file mode 100644
index 00000000..0c25d027
--- /dev/null
+++ b/apps/homepage/widget/section/governance.jsx
@@ -0,0 +1,162 @@
+const imageLink =
+ "https://ipfs.near.social/ipfs/bafybeifaeuepgsffn32kjsaboqrnruv7blhfy2mwe74yvjuo4vggeppr3y";
+
+const SectionPill = ({ title, icon }) => {
+ const Pill = styled.div`
+ display: flex;
+ padding: 8px 12px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 100px;
+ border: 1px solid var(--Blue, #51b6ff);
+ background: rgba(81, 182, 255, 0.2);
+
+ color: var(--Blue, #51b6ff);
+ text-align: center;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ text-transform: capitalize;
+
+ width: max-content;
+ `;
+
+ return (
+
+ {title} {icon}
+
+ );
+};
+
+const MagicIcon = (
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+const GovernanceContainer = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+
+ position: relative;
+
+ padding: 6.25rem 3rem;
+
+ @media screen and (max-width: 768px) {
+ padding: 6.25rem 1.5rem;
+ }
+
+ img {
+ max-height: 447px;
+ width: 100%;
+ }
+`;
+
+const ContentContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+
+ h2 {
+ color: #fff;
+ text-align: center;
+ font-size: 2.5rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 120%; /* 48px */
+ margin: 0;
+ }
+
+ span.blue {
+ color: #51b6ff;
+ }
+
+ p {
+ max-width: 500px;
+ color: rgba(255, 255, 255, 0.7);
+ text-align: center;
+
+ /* Body/Large */
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 27.2px */
+ margin: 0;
+ }
+
+ @media screen and (max-widht: 768px) {
+ h2 {
+ font-size: 1.5rem;
+ }
+
+ p {
+ font-size: 0.875rem;
+ }
+ }
+`;
+
+return (
+
+
+
+
+ Let's coordinate!
+
+
+ Build DAO upholds the principles of openness and accountability in its
+ decision-making processes. We believe success depends on metagovernance
+ of builders, by builders, for builders.
+
+
+
+
+);
diff --git a/apps/homepage/widget/section/hero.jsx b/apps/homepage/widget/section/hero.jsx
index e69de29b..ed91a2c7 100644
--- a/apps/homepage/widget/section/hero.jsx
+++ b/apps/homepage/widget/section/hero.jsx
@@ -0,0 +1,106 @@
+const logoLink =
+ "https://ipfs.near.social/ipfs/bafkreihbwho3qfvnu4yss3eh5jrx6uxhrlzdgtdjyzyjrpa6odro6wdxya";
+const gridLink =
+ "https://ipfs.near.social/ipfs/bafkreiay3ytllrxhtyunppqxcazpistttwdzlz3jefdbsq5tosxuryauu4";
+const leftBlur =
+ "https://ipfs.near.social/ipfs/bafkreig2cgzqloepedal5ypphzhzcakl5uoedxjtvbpxbxnywerjbzmfpm";
+const rightBlur =
+ "https://ipfs.near.social/ipfs/bafkreierwhnzytfajagidxim5mzdphu5fopjmlrxehatywzuy6ahr5q7pe";
+
+const HeroContainer = styled.div`
+ width: 100%;
+ position: relative;
+
+ padding: 6.25rem 3rem;
+
+ @media screen and (max-width: 768px) {
+ padding: 6.25rem 1.5rem;
+ }
+`;
+
+const LeftBlur = styled.img`
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ object-fit: cover;
+ width: 25%;
+
+ @media screen and (max-width: 768px) {
+ width: 50%;
+ opacity: 0.5;
+ }
+`;
+
+const RightBlur = styled.img`
+ position: absolute;
+ right: 0;
+ top: 100%;
+ transform: translateY(-50%);
+ object-fit: cover;
+ width: 25%;
+
+ @media screen and (max-width: 768px) {
+ width: 50%;
+ opacity: 0.5;
+ }
+`;
+
+const Grid = styled.img`
+ position: absolute;
+ top: 0;
+ left: 0;
+ opacity: 0.05;
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+`;
+
+const Logo = styled.img`
+ height: 54px;
+ object-fit: cover;
+`;
+
+const Tagline = styled.h1`
+ max-width: 700px;
+
+ text-align: center;
+ font-size: 3rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 120%; /* 57.6px */
+ margin: 0;
+
+ span.muted {
+ color: rgba(255, 255, 255, 0.7);
+ }
+
+ @media screen and (max-width: 768px) {
+ font-size: 2rem;
+ }
+`;
+
+const Content = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+
+ margin: 0 auto;
+`;
+
+return (
+
+
+
+
+ Designed to connect and empower builders in a{" "}
+ multi-chain ecosystem
+
+
+
+
+
+
+);
diff --git a/apps/homepage/widget/section/join.jsx b/apps/homepage/widget/section/join.jsx
new file mode 100644
index 00000000..26df90a0
--- /dev/null
+++ b/apps/homepage/widget/section/join.jsx
@@ -0,0 +1,361 @@
+const SectionPill = ({ title, icon }) => {
+ const Pill = styled.div`
+ display: flex;
+ padding: 8px 12px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 100px;
+ border: 1px solid var(--Sea-Blue, #51ffea);
+ background: rgba(81, 255, 234, 0.2);
+
+ color: var(--Sea-Blue, #51ffea);
+ text-align: center;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ text-transform: capitalize;
+
+ width: max-content;
+ `;
+
+ return (
+
+ {title} {icon}
+
+ );
+};
+
+const MagicIcon = (
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+const JoinContainer = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+
+ position: relative;
+
+ padding: 6.25rem 3rem;
+
+ @media screen and (max-width: 768px) {
+ padding: 6.25rem 1.5rem;
+ }
+`;
+
+const ContentContainer = styled.div`
+ max-width: 700px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+
+ h2 {
+ color: #fff;
+ text-align: center;
+ font-size: 2.5rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 120%; /* 48px */
+ margin: 0;
+ }
+
+ span.blue {
+ color: var(--Sea-Blue, #51ffea);
+ }
+
+ p {
+ max-width: 500px;
+ color: rgba(255, 255, 255, 0.7);
+ text-align: center;
+
+ /* Body/Large */
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 27.2px */
+ margin: 0;
+ }
+
+ @media screen and (max-width: 768px) {
+ h2 {
+ font-size: 1.5rem;
+ }
+
+ p {
+ font-size: 0.875rem;
+ }
+ }
+`;
+
+const CardContainer = styled.div`
+ max-width: 36rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+`;
+
+const CardIcon = () => {
+ const Icon = styled.div`
+ display: flex;
+ width: 64px;
+ height: 64px;
+ padding: 1.25rem;
+ justify-content: center;
+ align-items: center;
+
+ border-radius: 0.5rem;
+ border: 1px solid var(--Sea-Blue, #51ffea);
+
+ @media screen and (max-width: 768px) {
+ width: 2.5rem;
+ height: 2.5rem;
+ padding: 7.875px 0.5rem 8.125px 0.5rem;
+ }
+ `;
+
+ return (
+
+
+
+
+
+ );
+};
+
+const Card = ({ title, description }) => {
+ const Body = styled.div`
+ display: flex;
+ padding: 0.75rem;
+ align-items: flex-start;
+ gap: 1rem;
+ align-self: stretch;
+
+ border-radius: 12px;
+ border: 1px solid var(--Stroke-color, rgba(255, 255, 255, 0.2));
+ background: var(--bg-2, #23242b);
+
+ h4 {
+ color: var(--white-100, #fff);
+
+ /* H4/Large */
+ font-size: 1.125rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 160%; /* 28.8px */
+ margin: 0;
+ }
+
+ p {
+ color: var(--white-50, rgba(255, 255, 255, 0.7));
+
+ /* Body/Large */
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 27.2px */
+ margin: 0;
+ }
+ `;
+
+ return (
+
+
+
+
{title}
+
{description}
+
+
+ );
+};
+
+const CTAContainer = styled.div`
+ display: flex;
+ max-width: 75rem;
+ width: 100%;
+ padding: 2.5rem;
+ justify-content: center;
+ align-items: flex-start;
+ gap: 2.5rem;
+ margin: 0 auto;
+
+ border-radius: 1rem;
+ border: 1px solid var(--Sea-Blue, #51ffea);
+ background: rgba(81, 255, 234, 0.1);
+ box-shadow: 0.25rem 1.5rem 3rem 0rem rgba(81, 255, 234, 0.1);
+
+ h2 {
+ max-width: 500px;
+ flex: 1 0 0;
+
+ color: var(--white-100, #fff);
+
+ /* H2/Large */
+ font-family: Satoshi;
+ font-size: 40px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 120%; /* 48px */
+ }
+
+ span.blue {
+ color: var(--Sea-Blue, #51ffea);
+ }
+
+ @media screen and (max-width: 768px) {
+ flex-direction: column;
+ padding: 2.5rem 1.5rem;
+
+ h2 {
+ font-size: 1.5rem;
+ }
+ }
+`;
+
+const CTAContent = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 1.5rem;
+ flex: 1 0 0;
+
+ p {
+ color: var(--Sea-Blue, #51ffea);
+ /* Body/Large */
+ font-family: Satoshi;
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 170%; /* 27.2px */
+ }
+
+ a {
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ border-radius: 8px;
+ background: #ffaf51;
+
+ color: #000;
+ margin: 0;
+
+ /* Other/Button_text */
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+
+ text-decoration: none;
+ transition: all 300ms;
+
+ &:hover {
+ background: #c98a40;
+ }
+ }
+`;
+
+return (
+
+
+
+
+ Open call for members to{" "}
+ join and contribute
+
+
+ Build DAO is an innovative, community-led organization designed to serve
+ the open web ecosystem in multiple ways:
+
+
+
+
+
+
+
+
+
+ How to join
+
+
+
+ 1. Sign membership agreement (on-chain)
+
+ 2. Propose to be added to the “Community” role
+
+ 3. Fulfill contribution requirements
+
+ Join Now
+
+
+
+);
diff --git a/public/index.html b/public/index.html
index b0d4af7c..421d68ef 100644
--- a/public/index.html
+++ b/public/index.html
@@ -11,16 +11,20 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
-
+
-
-
-
+
+
+
-
+
Build DAO
diff --git a/src/App.js b/src/App.js
index 722bbc4f..5ae0bb56 100644
--- a/src/App.js
+++ b/src/App.js
@@ -35,6 +35,8 @@ import EmbedPage from "./pages/EmbedPage";
import Flags from "./pages/Flags";
import SignInPage from "./pages/SignInPage";
import ViewPage from "./pages/ViewPage";
+import JoinPage from "./pages/JoinPage";
+import ProposePage from "./pages/ProposePage";
export const refreshAllowanceObj = {};
const documentationHref = "https://github.com/NearBuilders/docs";
@@ -166,7 +168,7 @@ function App() {
};
return (
-
+
@@ -177,6 +179,12 @@ function App() {
+
+
+
+
+
+
diff --git a/src/App.scss b/src/App.scss
index 413020d1..9d5bd7c4 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -6,6 +6,7 @@ body {
body, html {
-webkit-font-smoothing: antialiased;
+ height: 100%;
}
.pointer {
diff --git a/src/components/Editor/FileTab.js b/src/components/Editor/FileTab.js
index b64443b9..1d7a7298 100644
--- a/src/components/Editor/FileTab.js
+++ b/src/components/Editor/FileTab.js
@@ -1,6 +1,7 @@
import { Nav } from "react-bootstrap";
import React, { useEffect, useState } from "react";
import { useAccountId, useCache, useNear } from "near-social-vm";
+import styled from "styled-components";
export const Filetype = {
Widget: "widget",
@@ -85,17 +86,69 @@ export function FileTab(props) {
updateSaved && updateSaved(jp, !saved, localCode);
}, [saved, updateSaved, localCode]);
+ const Button = styled.button`
+ all: unset;
+
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ color: var(--black-100, #000);
+ /* Other/Button_text */
+ font-family: Satoshi;
+ font-size: 0.875rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+
+ border-radius: 8px;
+ background: var(--Blue, #51b6ff);
+
+ ${active && "box-shadow:0px 0px 0px 2px #fff inset;"}
+ `;
+
+ const CloseButton = styled.button`
+ all: unset;
+ padding: 4px;
+ font-size: 12px;
+
+ height: 8px;
+ width: 8px;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ color: #000;
+ border-radius: 50%;
+ transition: all 300ms;
+
+ &:hover {
+ background-color: #fff;
+ }
+ `;
+
return (
-
-
+
+
{p.name}
{saved && (
-
+
)}
- {
@@ -111,9 +164,9 @@ export function FileTab(props) {
}
}}
>
-
-
-
-
+
+
+
+
);
}
diff --git a/src/components/navigation/Logotype.js b/src/components/navigation/Logotype.js
index 2170afe9..fe04846e 100644
--- a/src/components/navigation/Logotype.js
+++ b/src/components/navigation/Logotype.js
@@ -3,14 +3,16 @@ import React from "react";
export function Logotype({ color = "white" }) {
return (
- build
-
+ width="155"
+ height="39"
+ viewBox="0 0 155 23"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ className="logotype"
+ >
+
+ build
+
+
);
-}
\ No newline at end of file
+}
diff --git a/src/data/widgets.js b/src/data/widgets.js
index e2132842..7318a705 100644
--- a/src/data/widgets.js
+++ b/src/data/widgets.js
@@ -18,13 +18,12 @@ const TestnetWidgets = {
notificationButton: "eugenethedream/widget/NotificationButton",
};
-
const MainnetWidgets = {
image: "mob.near/widget/Image",
default: "builddao.near/widget/home",
viewSource: "mob.near/widget/WidgetSource",
- widgetMetadataEditor: "mob.near/widget/WidgetMetadataEditor",
- widgetMetadata: "mob.near/widget/WidgetMetadata",
+ widgetMetadataEditor: "builddao.near/widget/WidgetMetadataEditor",
+ widgetMetadata: "builddao.near/widget/WidgetMetadata",
profileImage: "mob.near/widget/ProfileImage",
notificationButton: "mob.near/widget/NotificationButton",
profilePage: "near/widget/ProfilePage",
diff --git a/src/pages/EditorPage.js b/src/pages/EditorPage.js
index ba1f98e1..901629e0 100644
--- a/src/pages/EditorPage.js
+++ b/src/pages/EditorPage.js
@@ -23,6 +23,8 @@ import {
} from "../components/Editor/FileTab";
import { useHashRouterLegacy } from "../hooks/useHashRouterLegacy";
import vmTypesDeclaration from "raw-loader!near-social-vm-types";
+import styled from "styled-components";
+import { useBosLoaderStore } from "../stores/bos-loader";
const LsKey = "social.near:v01:";
const EditorLayoutKey = LsKey + "editorLayout:";
@@ -31,6 +33,65 @@ const EditorUncommittedPreviewsKey = LsKey + "editorUncommittedPreviews:";
const DefaultEditorCode = "return Hello World
;";
+const NavPill = styled.button`
+ all: unset;
+
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 10px;
+
+ border-radius: 8px;
+ background: var(--bg-2, #23242b);
+
+ color: var(--white-100, #fff);
+
+ font-size: 0.875rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+`;
+
+const Container = styled.div`
+ background: #0b0c14;
+ color: #fff;
+
+ min-height: 100%;
+`;
+
+const CustomSearch = styled.div`
+ .form-control {
+ background: #23242b;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ color: #fff;
+ }
+ input::placeholder {
+ color: #c7c7c7;
+ }
+`;
+
+const Button = styled.button`
+ all: unset;
+
+ display: flex;
+ padding: 10px 20px;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+
+ /* Other/Button_text */
+ font-family: Satoshi;
+ font-size: 0.875rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+
+ border-radius: 8px;
+ background: #51b6ff;
+ color: black;
+`;
+
const Tab = {
Editor: "Editor",
Props: "Props",
@@ -47,6 +108,7 @@ export default function EditorPage(props) {
useHashRouterLegacy();
const { widgetSrc } = useParams();
const history = useHistory();
+ const redirectMapStore = useBosLoaderStore();
const setWidgetSrc = props.setWidgetSrc;
const [loading, setLoading] = useState(false);
@@ -224,7 +286,7 @@ export default function EditorPage(props) {
c
);
if (code) {
- const name = widgetSrc.split("/").slice(2).join("/");
+ // const name = widgetSrc.split("/").slice(2).join("/");
openFile(toPath(Filetype.Widget, widgetSrc), code);
}
};
@@ -353,7 +415,7 @@ export default function EditorPage(props) {
[openFile, createFile]
);
- const layoutClass = layout === Layout.Split ? "col-lg-6" : "";
+ const layoutClass = layout === Layout.Split ? "w-50" : "";
const onLayoutChange = useCallback(
(e) => {
@@ -400,7 +462,17 @@ export default function EditorPage(props) {
const commitButton = (
+
setShowOpenModal(false)}
/>
-
+
openFile(JSON.parse(key))}
+ className="gap-3"
>
{files?.map((p, idx) => {
const jp = JSON.stringify(p);
@@ -472,24 +552,28 @@ export default function EditorPage(props) {
);
})}
- setShowOpenModal(true)}
>
- Add
-
+ {" "}
+ Add
+
- closeCommitted(path, allSaved)}
>
- Close unchanged
-
+ Close unchanged
+
{props.widgets.editorComponentSearch && (
-
+
- Open "{widgetName}" component in the editor
+ {`Open "${widgetName}" component in the editor`}
}
>
@@ -519,11 +603,15 @@ export default function EditorPage(props) {
[loadFile]
)}
/>
-
+
)}
-
+
-
-
-
+
+
+
setTab(Tab.Editor)}
>
@@ -576,6 +713,13 @@ export default function EditorPage(props) {
setTab(Tab.Props)}
>
@@ -585,6 +729,13 @@ export default function EditorPage(props) {
{props.widgets.widgetMetadataEditor && (
-
+
-
-
+ {
renderPreview(code);
if (layout === Layout.Tabs) {
@@ -635,20 +794,25 @@ export default function EditorPage(props) {
}
}}
>
- Render preview
-
+ Render Preview
+
{!path?.unnamed && commitButton}
-
{
setShowRenameModal(true);
}}
>
Rename {path?.type}
-
- {path && accountId && (
+
+ {/* {path && accountId && (
Open Component in a new tab
- )}
-
{
const v = !uncommittedPreviews;
@@ -676,12 +840,13 @@ export default function EditorPage(props) {
>
Multi-file previews (
{uncommittedPreviews ? "ON" : "OFF"})
-
+ */}
-
+
setWidgetProps(props)}
@@ -702,10 +867,20 @@ export default function EditorPage(props) {
: "visually-hidden"
}`}
>
-
+
({
widgetPath,
@@ -726,7 +901,7 @@ export default function EditorPage(props) {
: "visually-hidden"
}`}
>
-
+
{renderCode ? (
@@ -750,10 +925,13 @@ export default function EditorPage(props) {
>
-
+
({ metadata, accountId, widgetName }),
[metadata, accountId, widgetName]
@@ -766,6 +944,6 @@ export default function EditorPage(props) {
-
+
);
}
diff --git a/src/pages/JoinPage.js b/src/pages/JoinPage.js
new file mode 100644
index 00000000..01943c60
--- /dev/null
+++ b/src/pages/JoinPage.js
@@ -0,0 +1,33 @@
+import React from "react";
+import { UserDropdown } from "../components/navigation/desktop/UserDropdown";
+import { Widget } from "near-social-vm";
+import { useBosLoaderStore } from "../stores/bos-loader";
+
+export default function JoinPage(props) {
+ const redirectMapStore = useBosLoaderStore();
+
+ const CurrentView = props.signedIn
+ ? "builddao.near/widget/create-something"
+ : "builddao.near/widget/login";
+ return (
+
+ {props.signedIn && (
+
+
+
+ )}
+
+
+ );
+}
diff --git a/src/pages/ProposePage.js b/src/pages/ProposePage.js
new file mode 100644
index 00000000..58a1dbc9
--- /dev/null
+++ b/src/pages/ProposePage.js
@@ -0,0 +1,20 @@
+import React from "react";
+import { Widget } from "near-social-vm";
+import { useBosLoaderStore } from "../stores/bos-loader";
+
+export default function ProposePage(props) {
+ const redirectMapStore = useBosLoaderStore();
+ return (
+
+
+
+ );
+}
diff --git a/src/pages/ViewPage.js b/src/pages/ViewPage.js
index 2d234d5a..d94be60e 100644
--- a/src/pages/ViewPage.js
+++ b/src/pages/ViewPage.js
@@ -40,25 +40,15 @@ export default function ViewPage(props) {
}, [src, query, setWidgetSrc, viewSourceWidget]);
return showMenu ? (
-