From 9ef3e6b75813f4512aaac386e99ee98f739cd2aa Mon Sep 17 00:00:00 2001 From: 0xExp-po <153439271+0xExp-po@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:50:40 +0900 Subject: [PATCH] Add first DAO UI components (#89) --- dapp/package.json | 1 + dapp/public/ag.svg | 19 +- dapp/public/icons/arrow-down.svg | 23 +- dapp/public/icons/arrow-up.svg | 23 +- dapp/public/icons/arrow.svg | 14 +- dapp/public/icons/avatar.svg | 27 + dapp/public/icons/check.svg | 18 +- dapp/public/icons/failed.svg | 18 +- dapp/public/icons/logos/discord.svg | 6 +- dapp/public/icons/logos/git.svg | 11 +- dapp/public/icons/logos/github.svg | 6 +- dapp/public/icons/logos/instagram.svg | 6 +- dapp/public/icons/logos/stellar-expert.svg | 19 +- dapp/public/icons/logos/stellar-xlm.svg | 15 + dapp/public/icons/logos/tansu.svg | 39 +- dapp/public/icons/logos/telegram.svg | 6 +- dapp/public/icons/logos/twitter.svg | 6 +- dapp/public/icons/logos/web.svg | 16 +- dapp/public/icons/release.svg | 12 +- dapp/public/icons/search.svg | 8 +- dapp/public/logo.svg | 39 +- dapp/src/components/layout/Container.astro | 2 +- .../page/governance/GovernancePage.astro | 9 + .../page/governance/GovernancePageTitle.astro | 36 + .../components/page/governance/IdeaList.tsx | 28 + .../page/governance/ProposalCard.tsx | 69 ++ .../page/governance/ProposalList.tsx | 48 ++ .../page/governance/ProposalStatusShow.tsx | 49 ++ .../page/governance/ProposalTypeButton.tsx | 40 ++ .../page/governance/ProposalsSection.tsx | 36 + dapp/src/components/page/project/Commit.astro | 4 +- .../components/page/project/CommitHistory.jsx | 66 +- .../components/page/project/DonateModal.astro | 14 +- .../components/page/project/GetCommit.astro | 4 +- .../components/page/project/ProjectInfo.astro | 68 +- .../components/page/project/ReadmeViewer.tsx | 1 - .../page/proposal/ExecuteProposalModal.tsx | 97 +++ .../page/proposal/ProposalDetail.tsx | 217 ++++++ .../components/page/proposal/ProposalPage.tsx | 123 ++++ .../page/proposal/ProposalPageTitle.tsx | 92 +++ .../page/proposal/ProposalStatusSection.tsx | 28 + .../page/proposal/VoteStatusBar.tsx | 43 ++ .../components/page/proposal/VotersModal.tsx | 92 +++ .../components/page/proposal/VotingModal.tsx | 103 +++ .../page/register/RegisterProject.astro | 4 +- dapp/src/components/stellar-wallets-kit.ts | 2 + dapp/src/components/utils/Pagination.tsx | 74 ++ dapp/src/components/utils/PrimaryButton.astro | 6 +- dapp/src/components/utils/Topic.astro | 2 +- dapp/src/constants/demoProposalData.ts | 632 ++++++++++++++++++ dapp/src/constants/serviceLinks.js | 2 + dapp/src/layouts/Layout.astro | 4 +- dapp/src/pages/governance/index.astro | 30 + dapp/src/pages/proposal/index.astro | 30 + dapp/src/service/ProposalService.ts | 31 + dapp/src/styles/global.css | 12 +- dapp/src/types/proposal.ts | 68 ++ dapp/src/utils/formatTimeFunctions.ts | 16 + dapp/src/utils/store.js | 3 + dapp/src/utils/utils.ts | 33 + dapp/tailwind.config.mjs | 20 +- 61 files changed, 2395 insertions(+), 175 deletions(-) create mode 100644 dapp/public/icons/avatar.svg create mode 100644 dapp/public/icons/logos/stellar-xlm.svg create mode 100644 dapp/src/components/page/governance/GovernancePage.astro create mode 100644 dapp/src/components/page/governance/GovernancePageTitle.astro create mode 100644 dapp/src/components/page/governance/IdeaList.tsx create mode 100644 dapp/src/components/page/governance/ProposalCard.tsx create mode 100644 dapp/src/components/page/governance/ProposalList.tsx create mode 100644 dapp/src/components/page/governance/ProposalStatusShow.tsx create mode 100644 dapp/src/components/page/governance/ProposalTypeButton.tsx create mode 100644 dapp/src/components/page/governance/ProposalsSection.tsx create mode 100644 dapp/src/components/page/proposal/ExecuteProposalModal.tsx create mode 100644 dapp/src/components/page/proposal/ProposalDetail.tsx create mode 100644 dapp/src/components/page/proposal/ProposalPage.tsx create mode 100644 dapp/src/components/page/proposal/ProposalPageTitle.tsx create mode 100644 dapp/src/components/page/proposal/ProposalStatusSection.tsx create mode 100644 dapp/src/components/page/proposal/VoteStatusBar.tsx create mode 100644 dapp/src/components/page/proposal/VotersModal.tsx create mode 100644 dapp/src/components/page/proposal/VotingModal.tsx create mode 100644 dapp/src/components/utils/Pagination.tsx create mode 100644 dapp/src/constants/demoProposalData.ts create mode 100644 dapp/src/constants/serviceLinks.js create mode 100644 dapp/src/pages/governance/index.astro create mode 100644 dapp/src/pages/proposal/index.astro create mode 100644 dapp/src/service/ProposalService.ts create mode 100644 dapp/src/types/proposal.ts diff --git a/dapp/package.json b/dapp/package.json index f669c00..a324df5 100644 --- a/dapp/package.json +++ b/dapp/package.json @@ -14,6 +14,7 @@ "js-sha3": "^0.9.3", "markdown-to-jsx": "^7.6.2", "nanostores": "^0.11.3", + "react18-json-view": "^0.2.8", "tailwindcss": "^3.4.15", "typescript": "^5.6.3" }, diff --git a/dapp/public/ag.svg b/dapp/public/ag.svg index 6262e7b..bf50d7b 100644 --- a/dapp/public/ag.svg +++ b/dapp/public/ag.svg @@ -1,6 +1,15 @@ - - - - - + + + + + diff --git a/dapp/public/icons/arrow-down.svg b/dapp/public/icons/arrow-down.svg index cba2b38..751013f 100644 --- a/dapp/public/icons/arrow-down.svg +++ b/dapp/public/icons/arrow-down.svg @@ -1,4 +1,21 @@ - - - + + + diff --git a/dapp/public/icons/arrow-up.svg b/dapp/public/icons/arrow-up.svg index e2213dd..de6dbe5 100644 --- a/dapp/public/icons/arrow-up.svg +++ b/dapp/public/icons/arrow-up.svg @@ -1,4 +1,21 @@ - - - + + + diff --git a/dapp/public/icons/arrow.svg b/dapp/public/icons/arrow.svg index 04f032b..a6f982d 100644 --- a/dapp/public/icons/arrow.svg +++ b/dapp/public/icons/arrow.svg @@ -1,3 +1,11 @@ - - - \ No newline at end of file + + + diff --git a/dapp/public/icons/avatar.svg b/dapp/public/icons/avatar.svg new file mode 100644 index 0000000..539f9a4 --- /dev/null +++ b/dapp/public/icons/avatar.svg @@ -0,0 +1,27 @@ + diff --git a/dapp/public/icons/check.svg b/dapp/public/icons/check.svg index 0e82c45..75422bf 100644 --- a/dapp/public/icons/check.svg +++ b/dapp/public/icons/check.svg @@ -1,4 +1,16 @@ - - - + + + diff --git a/dapp/public/icons/failed.svg b/dapp/public/icons/failed.svg index d339de3..3f77d85 100644 --- a/dapp/public/icons/failed.svg +++ b/dapp/public/icons/failed.svg @@ -1,4 +1,16 @@ - - - + + + diff --git a/dapp/public/icons/logos/discord.svg b/dapp/public/icons/logos/discord.svg index b8cf97e..77cc138 100644 --- a/dapp/public/icons/logos/discord.svg +++ b/dapp/public/icons/logos/discord.svg @@ -1,3 +1,5 @@ - - \ No newline at end of file + + diff --git a/dapp/public/icons/logos/git.svg b/dapp/public/icons/logos/git.svg index c9502a1..000e8dc 100644 --- a/dapp/public/icons/logos/git.svg +++ b/dapp/public/icons/logos/git.svg @@ -1,3 +1,10 @@ - - + + diff --git a/dapp/public/icons/logos/github.svg b/dapp/public/icons/logos/github.svg index 13482d1..c1fe4ed 100644 --- a/dapp/public/icons/logos/github.svg +++ b/dapp/public/icons/logos/github.svg @@ -1,3 +1,5 @@ - - \ No newline at end of file + + diff --git a/dapp/public/icons/logos/instagram.svg b/dapp/public/icons/logos/instagram.svg index 26689b7..f561fcc 100644 --- a/dapp/public/icons/logos/instagram.svg +++ b/dapp/public/icons/logos/instagram.svg @@ -1,3 +1,5 @@ - - \ No newline at end of file + + diff --git a/dapp/public/icons/logos/stellar-expert.svg b/dapp/public/icons/logos/stellar-expert.svg index a438180..c849daf 100644 --- a/dapp/public/icons/logos/stellar-expert.svg +++ b/dapp/public/icons/logos/stellar-expert.svg @@ -1,12 +1,19 @@ - - - + + Stellar Streamline Icon: https://streamlinehq.com + Stellar + diff --git a/dapp/public/icons/logos/tansu.svg b/dapp/public/icons/logos/tansu.svg index 2c253b4..04d5426 100644 --- a/dapp/public/icons/logos/tansu.svg +++ b/dapp/public/icons/logos/tansu.svg @@ -1,7 +1,21 @@ - - + - + - - \ No newline at end of file +z" + > + diff --git a/dapp/public/icons/logos/telegram.svg b/dapp/public/icons/logos/telegram.svg index 28e862e..2611a45 100644 --- a/dapp/public/icons/logos/telegram.svg +++ b/dapp/public/icons/logos/telegram.svg @@ -1,3 +1,5 @@ - - \ No newline at end of file + + diff --git a/dapp/public/icons/logos/twitter.svg b/dapp/public/icons/logos/twitter.svg index 8b64bda..28198cf 100644 --- a/dapp/public/icons/logos/twitter.svg +++ b/dapp/public/icons/logos/twitter.svg @@ -1,3 +1,5 @@ - - \ No newline at end of file + + diff --git a/dapp/public/icons/logos/web.svg b/dapp/public/icons/logos/web.svg index 10e79ce..5aaac2b 100644 --- a/dapp/public/icons/logos/web.svg +++ b/dapp/public/icons/logos/web.svg @@ -1,3 +1,13 @@ - - - \ No newline at end of file + + + diff --git a/dapp/public/icons/release.svg b/dapp/public/icons/release.svg index 1e90c4f..41e9078 100644 --- a/dapp/public/icons/release.svg +++ b/dapp/public/icons/release.svg @@ -1,5 +1,11 @@ - + - - + + diff --git a/dapp/public/icons/search.svg b/dapp/public/icons/search.svg index fa79636..299f25c 100644 --- a/dapp/public/icons/search.svg +++ b/dapp/public/icons/search.svg @@ -11,13 +11,11 @@ fill="#B9FF66" strokeWidth="2" strokeLinecap="round" - strokeLinejoin="round" - /> + strokeLinejoin="round"> - \ No newline at end of file + strokeLinejoin="round"> + diff --git a/dapp/public/logo.svg b/dapp/public/logo.svg index cf33d48..362f087 100644 --- a/dapp/public/logo.svg +++ b/dapp/public/logo.svg @@ -1,7 +1,21 @@ - - + - + - - \ No newline at end of file +z" + > + diff --git a/dapp/src/components/layout/Container.astro b/dapp/src/components/layout/Container.astro index b7e8944..0a0dced 100644 --- a/dapp/src/components/layout/Container.astro +++ b/dapp/src/components/layout/Container.astro @@ -1,5 +1,5 @@
diff --git a/dapp/src/components/page/governance/GovernancePage.astro b/dapp/src/components/page/governance/GovernancePage.astro new file mode 100644 index 0000000..15f65ec --- /dev/null +++ b/dapp/src/components/page/governance/GovernancePage.astro @@ -0,0 +1,9 @@ +--- +import GovernancePageTitle from "./GovernancePageTitle.astro"; +import ProposalsSection from "./ProposalsSection.tsx"; +--- + +
+ + +
diff --git a/dapp/src/components/page/governance/GovernancePageTitle.astro b/dapp/src/components/page/governance/GovernancePageTitle.astro new file mode 100644 index 0000000..85833b8 --- /dev/null +++ b/dapp/src/components/page/governance/GovernancePageTitle.astro @@ -0,0 +1,36 @@ +--- +import PrimaryButton from "../../utils/PrimaryButton.astro"; +import Topic from "../../utils/Topic.astro"; +--- + +
+ +
+ +
+
+ + diff --git a/dapp/src/components/page/governance/IdeaList.tsx b/dapp/src/components/page/governance/IdeaList.tsx new file mode 100644 index 0000000..e395778 --- /dev/null +++ b/dapp/src/components/page/governance/IdeaList.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { useState } from "react"; +import Pagination from "../../utils/Pagination"; +import { projectNameForGovernance } from "utils/store"; +import { useStore } from "@nanostores/react"; + +const IdeaList: React.FC = () => { + const projectName = useStore(projectNameForGovernance); + const [currentPage, setCurrentPage] = useState(1); + + return ( +
+
+
+

Stay tuned!

+
+
+
+ setCurrentPage(page)} + /> +
+
+ ); +}; + +export default IdeaList; diff --git a/dapp/src/components/page/governance/ProposalCard.tsx b/dapp/src/components/page/governance/ProposalCard.tsx new file mode 100644 index 0000000..bac1802 --- /dev/null +++ b/dapp/src/components/page/governance/ProposalCard.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import ProposalStatusShow from "./ProposalStatusShow"; +import type { ProposalCardProps } from "types/proposal"; +import { calculateDateDifference } from "utils/formatTimeFunctions"; +import { navigate } from "astro:transitions/client"; + +const ProposalCard: React.FC = ({ + proposalNumber, + proposalTitle, + proposalStatus, + endDate, +}) => { + return ( +
navigate(`/proposal?id=${proposalNumber}`)} + > +
+
+
+
+ {proposalNumber} +
+
+
+ {proposalTitle} +
+
+
+
+ {proposalStatus === "active" && + endDate && + calculateDateDifference(endDate) && ( +
+ Ends in {calculateDateDifference(endDate)} +
+ )} + {proposalStatus === "voted" && ( +
+ Pending execution +
+ )} +
+
+ +
+
+
+
+
+ {proposalStatus === "active" && + endDate && + calculateDateDifference(endDate) && ( +
+ Ends in {calculateDateDifference(endDate)} +
+ )} + {proposalStatus === "voted" && ( +
+ Pending execution +
+ )} +
+
+
+ ); +}; + +export default ProposalCard; diff --git a/dapp/src/components/page/governance/ProposalList.tsx b/dapp/src/components/page/governance/ProposalList.tsx new file mode 100644 index 0000000..b922f40 --- /dev/null +++ b/dapp/src/components/page/governance/ProposalList.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { useState, useEffect } from "react"; +import Pagination from "../../utils/Pagination"; +import { demoProposalCardData } from "constants/demoProposalData"; +import ProposalCard from "./ProposalCard"; +import { projectNameForGovernance } from "utils/store"; +import { useStore } from "@nanostores/react"; +import type { ProposalCardProps } from "types/proposal"; + +const ProposalList: React.FC = () => { + const projectName = useStore(projectNameForGovernance); + const [currentPage, setCurrentPage] = useState(1); + const [proposalCardData, setProposalCardData] = useState( + [], + ); + + const fetchProposalCardData = async (_page: number) => { + setProposalCardData(demoProposalCardData); + }; + + useEffect(() => { + fetchProposalCardData(currentPage); + }, [currentPage, projectName]); + + return ( +
+
+ {proposalCardData.map((proposal) => ( + + ))} +
+
+ setCurrentPage(page)} + /> +
+
+ ); +}; + +export default ProposalList; diff --git a/dapp/src/components/page/governance/ProposalStatusShow.tsx b/dapp/src/components/page/governance/ProposalStatusShow.tsx new file mode 100644 index 0000000..fb27b20 --- /dev/null +++ b/dapp/src/components/page/governance/ProposalStatusShow.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import type { ProposalStatus } from "types/proposal"; + +interface ProposalStatusShowProps { + proposalStatus: ProposalStatus; +} + +const ProposalStatusShow: React.FC = ({ + proposalStatus, +}) => { + let title; + let backgroundColorClass; + + switch (proposalStatus) { + case "active": + title = "Active"; + backgroundColorClass = "bg-active"; + break; + case "rejected": + title = "Rejected"; + backgroundColorClass = "bg-conflict"; + break; + case "cancelled": + title = "Cancelled"; + backgroundColorClass = "bg-abstain"; + break; + case "voted": + title = "Voted"; + backgroundColorClass = "bg-voted"; + break; + case "approved": + title = "Approved"; + backgroundColorClass = "bg-approved"; + break; + default: + title = "Unknown"; + backgroundColorClass = "bg-gray"; + } + + return ( +
+

{title}

+
+ ); +}; + +export default ProposalStatusShow; diff --git a/dapp/src/components/page/governance/ProposalTypeButton.tsx b/dapp/src/components/page/governance/ProposalTypeButton.tsx new file mode 100644 index 0000000..169a9ef --- /dev/null +++ b/dapp/src/components/page/governance/ProposalTypeButton.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { useState, useEffect } from "react"; + +interface ProposalTypeButtonProps { + proposalTypeStatus: string; + proposalType: string; + title: string; + position?: "start" | "end"; + onClick: (proposalType: string) => void; +} + +const ProposalTypeButton: React.FC = ({ + proposalTypeStatus, + proposalType, + title, + position = null, + onClick, +}) => { + const [isSelected, setIsSelected] = useState(true); + + useEffect(() => { + if (proposalTypeStatus === proposalType) { + setIsSelected(true); + } else { + setIsSelected(false); + } + }, [proposalTypeStatus]); + + const buttonClass = `px-2.5 sm:px-3 py-1.5 sm:py-2 text-md sm:text-xl font-medium border border-zinc-200 focus:outline-none ${ + isSelected ? "bg-zinc-200" : "bg-white" + } ${position === "start" ? "rounded-tl-lg" : position === "end" ? "rounded-tr-lg" : ""}`; + + return ( + + ); +}; + +export default ProposalTypeButton; diff --git a/dapp/src/components/page/governance/ProposalsSection.tsx b/dapp/src/components/page/governance/ProposalsSection.tsx new file mode 100644 index 0000000..29ba8be --- /dev/null +++ b/dapp/src/components/page/governance/ProposalsSection.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { useState } from "react"; +import ProposalTypeButton from "./ProposalTypeButton"; +import ProposalList from "./ProposalList"; +import IdeaList from "./IdeaList"; + +const ProposalsSection: React.FC = () => { + const [proposalType, setProposalType] = useState("proposal"); + + return ( +
+
+ setProposalType(proposalType)} + /> + setProposalType(proposalType)} + /> +
+
+ {proposalType === "proposal" && } + {proposalType === "idea" && } +
+
+ ); +}; + +export default ProposalsSection; diff --git a/dapp/src/components/page/project/Commit.astro b/dapp/src/components/page/project/Commit.astro index a4b09c5..d95c183 100644 --- a/dapp/src/components/page/project/Commit.astro +++ b/dapp/src/components/page/project/Commit.astro @@ -5,7 +5,9 @@ import PrimaryButton from "../../utils/PrimaryButton.astro"; --- @@ -57,7 +57,7 @@ import Loading from "../../utils/Loading.astro";