diff --git a/.github/workflows/check-formatting.yml b/.github/workflows/check-formatting.yml index d4c8c816..09814185 100644 --- a/.github/workflows/check-formatting.yml +++ b/.github/workflows/check-formatting.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 with: version: 8 - name: Setup Node.js environment diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cab3377c..30740e9f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 with: version: 8 - name: Setup Node.js environment diff --git a/package.json b/package.json index 460ea736..fede6c6a 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,12 @@ "@pcd/semaphore-identity-pcd": "^0.8.0", "@pcd/semaphore-signature-pcd": "^0.9.0", "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-icons": "^1.3.0", "@tanstack/react-query": "^5.13.4", "@tanstack/react-query-devtools": "^5.13.5", - "lucide-react": "^0.395.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "lucide-react": "^0.397.0", "react": "^18.2.0", "react-content-loader": "^7.0.0", "react-dom": "^18.2.0", @@ -41,6 +44,7 @@ "devDependencies": { "@hookform/devtools": "^4.3.1", "@tanstack/eslint-plugin-query": "^5.18.0", + "@types/node": "^20.12.4", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", "@typescript-eslint/eslint-plugin": "^6.19.0", @@ -51,8 +55,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", "prettier": "^3.1.1", - "typescript": "^5.2.2", + "typescript": "^5.5.2", "vite": "^5.0.0", "vite-plugin-node-polyfills": "^0.17.0" } -} \ No newline at end of file +} diff --git a/packages/berlin/components.json b/packages/berlin/components.json new file mode 100644 index 00000000..8a529f4e --- /dev/null +++ b/packages/berlin/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/_components", + "utils": "@/lib/utils" + } +} diff --git a/packages/berlin/package.json b/packages/berlin/package.json index 99cdc60f..98f43ed6 100644 --- a/packages/berlin/package.json +++ b/packages/berlin/package.json @@ -11,7 +11,36 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-navigation-menu": "^1.2.0", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.0.2", "api": "workspace:*", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "cmdk": "^1.0.0", + "lucide-react": "^0.397.0", + "tailwind-merge": "^2.2.2", + "tailwindcss-animate": "^1.0.7", "ui": "workspace:*" + }, + "devDependencies": { + "@types/node": "^20.12.4", + "@types/react-dom": "^18.2.22", + "@types/react": "^18.3.3", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.19", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "eslint": "^8.57.0", + "postcss-cli": "^11.0.0", + "postcss": "^8.4.38", + "tailwindcss": "^3.4.3", + "vite-plugin-dts": "^3.8.1", + "vite": "^5.2.0" } } diff --git a/packages/berlin/postcss.config.js b/packages/berlin/postcss.config.js new file mode 100644 index 00000000..2aa7205d --- /dev/null +++ b/packages/berlin/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/packages/berlin/public/icons/arrow-back-dark.svg b/packages/berlin/public/icons/arrow-back-dark.svg deleted file mode 100644 index 52ea50fc..00000000 --- a/packages/berlin/public/icons/arrow-back-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/arrow-back-light.svg b/packages/berlin/public/icons/arrow-back-light.svg deleted file mode 100644 index ee3b714d..00000000 --- a/packages/berlin/public/icons/arrow-back-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/badge-bronze.svg b/packages/berlin/public/icons/badge-bronze.svg deleted file mode 100644 index da7b9267..00000000 --- a/packages/berlin/public/icons/badge-bronze.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/badge-gold.svg b/packages/berlin/public/icons/badge-gold.svg deleted file mode 100644 index 26df3ab5..00000000 --- a/packages/berlin/public/icons/badge-gold.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/badge-silver.svg b/packages/berlin/public/icons/badge-silver.svg deleted file mode 100644 index 1c1c2657..00000000 --- a/packages/berlin/public/icons/badge-silver.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/comments-dark.svg b/packages/berlin/public/icons/comments-dark.svg deleted file mode 100644 index e5705f47..00000000 --- a/packages/berlin/public/icons/comments-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/comments-light.svg b/packages/berlin/public/icons/comments-light.svg deleted file mode 100644 index 6d0f4b6a..00000000 --- a/packages/berlin/public/icons/comments-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/copy-dark.svg b/packages/berlin/public/icons/copy-dark.svg deleted file mode 100644 index 519477c9..00000000 --- a/packages/berlin/public/icons/copy-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/copy-light.svg b/packages/berlin/public/icons/copy-light.svg deleted file mode 100644 index c62ba036..00000000 --- a/packages/berlin/public/icons/copy-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/decentralized.svg b/packages/berlin/public/icons/decentralized.svg deleted file mode 100644 index 7e2db8d7..00000000 --- a/packages/berlin/public/icons/decentralized.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/filter-dark.svg b/packages/berlin/public/icons/filter-dark.svg deleted file mode 100644 index c25336b7..00000000 --- a/packages/berlin/public/icons/filter-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/filter-light.svg b/packages/berlin/public/icons/filter-light.svg deleted file mode 100644 index da7218a9..00000000 --- a/packages/berlin/public/icons/filter-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/heart-empty.svg b/packages/berlin/public/icons/heart-empty.svg deleted file mode 100644 index 1ad3527f..00000000 --- a/packages/berlin/public/icons/heart-empty.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/berlin/public/icons/heart-full.svg b/packages/berlin/public/icons/heart-full.svg deleted file mode 100644 index 6099f875..00000000 --- a/packages/berlin/public/icons/heart-full.svg +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/berlin/public/icons/money-dark.svg b/packages/berlin/public/icons/money-dark.svg deleted file mode 100644 index 52386eca..00000000 --- a/packages/berlin/public/icons/money-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/money-light.svg b/packages/berlin/public/icons/money-light.svg deleted file mode 100644 index 361531ef..00000000 --- a/packages/berlin/public/icons/money-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/plurality-score.svg b/packages/berlin/public/icons/plurality-score.svg index 9a07c3d4..fe4f94cf 100644 --- a/packages/berlin/public/icons/plurality-score.svg +++ b/packages/berlin/public/icons/plurality-score.svg @@ -1,190 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/packages/berlin/public/icons/plurality.svg b/packages/berlin/public/icons/plurality.svg deleted file mode 100644 index bea7c8f7..00000000 --- a/packages/berlin/public/icons/plurality.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/research.svg b/packages/berlin/public/icons/research.svg deleted file mode 100644 index 303a31bb..00000000 --- a/packages/berlin/public/icons/research.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/sort-dark.svg b/packages/berlin/public/icons/sort-dark.svg deleted file mode 100644 index e8b02d4f..00000000 --- a/packages/berlin/public/icons/sort-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/sort-light.svg b/packages/berlin/public/icons/sort-light.svg deleted file mode 100644 index 8e3edc37..00000000 --- a/packages/berlin/public/icons/sort-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/sqrt-dark.svg b/packages/berlin/public/icons/sqrt-dark.svg deleted file mode 100644 index eb548d54..00000000 --- a/packages/berlin/public/icons/sqrt-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/sqrt-light.svg b/packages/berlin/public/icons/sqrt-light.svg deleted file mode 100644 index 200a9ded..00000000 --- a/packages/berlin/public/icons/sqrt-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/thumb-up-active.svg b/packages/berlin/public/icons/thumb-up-active.svg deleted file mode 100644 index dff25672..00000000 --- a/packages/berlin/public/icons/thumb-up-active.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/thumb-up-dark.svg b/packages/berlin/public/icons/thumb-up-dark.svg deleted file mode 100644 index 799d09a5..00000000 --- a/packages/berlin/public/icons/thumb-up-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/thumb-up-light.svg b/packages/berlin/public/icons/thumb-up-light.svg deleted file mode 100644 index ffc6acff..00000000 --- a/packages/berlin/public/icons/thumb-up-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/toggle-dark.svg b/packages/berlin/public/icons/toggle-dark.svg deleted file mode 100644 index 54042f33..00000000 --- a/packages/berlin/public/icons/toggle-dark.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/toggle-light.svg b/packages/berlin/public/icons/toggle-light.svg deleted file mode 100644 index 36a2a00c..00000000 --- a/packages/berlin/public/icons/toggle-light.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/trash-dark.svg b/packages/berlin/public/icons/trash-dark.svg deleted file mode 100644 index e72f2c26..00000000 --- a/packages/berlin/public/icons/trash-dark.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/trash-light.svg b/packages/berlin/public/icons/trash-light.svg deleted file mode 100644 index 6b9b5d0c..00000000 --- a/packages/berlin/public/icons/trash-light.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/berlin/public/icons/unvote-dark.svg b/packages/berlin/public/icons/unvote-dark.svg deleted file mode 100644 index 2f63eaef..00000000 --- a/packages/berlin/public/icons/unvote-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/unvote-light.svg b/packages/berlin/public/icons/unvote-light.svg deleted file mode 100644 index 523a3ad4..00000000 --- a/packages/berlin/public/icons/unvote-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/user-dark.svg b/packages/berlin/public/icons/user-dark.svg deleted file mode 100644 index 22ded840..00000000 --- a/packages/berlin/public/icons/user-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/user-light.svg b/packages/berlin/public/icons/user-light.svg deleted file mode 100644 index d0daf501..00000000 --- a/packages/berlin/public/icons/user-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/vote-dark.svg b/packages/berlin/public/icons/vote-dark.svg deleted file mode 100644 index 9c1eb89d..00000000 --- a/packages/berlin/public/icons/vote-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/public/icons/vote-light.svg b/packages/berlin/public/icons/vote-light.svg deleted file mode 100644 index 22404063..00000000 --- a/packages/berlin/public/icons/vote-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/berlin/src/components/back-button/BackButton.tsx b/packages/berlin/src/components/back-button/BackButton.tsx index afb0c7a2..b6e47541 100644 --- a/packages/berlin/src/components/back-button/BackButton.tsx +++ b/packages/berlin/src/components/back-button/BackButton.tsx @@ -1,6 +1,6 @@ import { useNavigate } from 'react-router-dom'; -import { useAppStore } from '../../store'; -import IconButton from '../icon-button'; +import { ArrowLeft } from 'lucide-react'; +import Icon from '../icon'; type BackButtonProps = { fallbackRoute?: string; @@ -8,7 +8,6 @@ type BackButtonProps = { function BackButton({ fallbackRoute }: BackButtonProps) { const navigate = useNavigate(); - const theme = useAppStore((state) => state.theme); const handleBackClick = () => { if (fallbackRoute) { @@ -19,12 +18,9 @@ function BackButton({ fallbackRoute }: BackButtonProps) { }; return ( - + + + ); } diff --git a/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx b/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx index f939be67..c1161717 100644 --- a/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx +++ b/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx @@ -1,6 +1,8 @@ +import { Heart } from 'lucide-react'; import IconButton from '../../icon-button'; import { Body } from '../../typography/Body.styled'; import { Affiliation, Lead, Card, Hearts, Proposal, Plurality } from './CycleColumns.styled'; +import Icon from '../../icon'; type CycleColumnsProps = { onColumnClick: (column: string) => void; @@ -20,11 +22,9 @@ function CycleColumns({ onColumnClick, showScore }: CycleColumnsProps) { Affiliation onColumnClick('numOfVotes')}> - + + + {showScore && ( onColumnClick('voteScore')}> diff --git a/packages/berlin/src/components/columns/results-columns/ResultsColumns.tsx b/packages/berlin/src/components/columns/results-columns/ResultsColumns.tsx index 7d6098ca..d472ca93 100644 --- a/packages/berlin/src/components/columns/results-columns/ResultsColumns.tsx +++ b/packages/berlin/src/components/columns/results-columns/ResultsColumns.tsx @@ -1,3 +1,4 @@ +import { Heart, Radical } from 'lucide-react'; import { useAppStore } from '../../../store'; import IconButton from '../../icon-button'; import { Bold } from '../../typography/Bold.styled'; @@ -12,16 +13,8 @@ function ResultsColumns({ $showFunding }: ResultsColumnsType) { return ( Title - - + + - navigate('/account')} - icon={{ src: `/icons/user-${theme}.svg`, alt: 'User' }} - $color="primary" - $height={20} - $width={20} - /> + ) : ( Login with Zupass @@ -95,14 +93,9 @@ function Header() {
  • - - Toggle theme icon - +
  • diff --git a/packages/berlin/src/components/icon/Icon.styled.tsx b/packages/berlin/src/components/icon/Icon.styled.tsx new file mode 100644 index 00000000..e7644786 --- /dev/null +++ b/packages/berlin/src/components/icon/Icon.styled.tsx @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +export const StyledIcon = styled.div` + cursor: pointer; + height: 1.5rem; + width: 1.5rem; + + &:hover { + opacity: 0.8; + transition: opacity 0.2s ease-in; + } +`; diff --git a/packages/berlin/src/components/icon/Icon.tsx b/packages/berlin/src/components/icon/Icon.tsx new file mode 100644 index 00000000..ba3d553c --- /dev/null +++ b/packages/berlin/src/components/icon/Icon.tsx @@ -0,0 +1,12 @@ +import React, { forwardRef } from 'react'; +import { StyledIcon } from './Icon.styled'; + +type IconProps = { + children: React.ReactNode; +}; + +const Icon = forwardRef(({ children }, ref) => ( + {children} +)); + +export default Icon; diff --git a/packages/berlin/src/components/icon/index.ts b/packages/berlin/src/components/icon/index.ts new file mode 100644 index 00000000..dc6b45c3 --- /dev/null +++ b/packages/berlin/src/components/icon/index.ts @@ -0,0 +1 @@ +export { default } from './Icon'; diff --git a/packages/berlin/src/components/option-card/OptionCard.tsx b/packages/berlin/src/components/option-card/OptionCard.tsx index 1072de63..b1ecb8d1 100644 --- a/packages/berlin/src/components/option-card/OptionCard.tsx +++ b/packages/berlin/src/components/option-card/OptionCard.tsx @@ -1,3 +1,25 @@ +// React and third-party libraries +import { MessageSquareText } from 'lucide-react'; +import { useMemo, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useQuery } from '@tanstack/react-query'; +import Markdown from 'react-markdown'; + +// Store +import { useAppStore } from '../../store'; + +// API +import { fetchOptionUsers, GetCycleResponse } from 'api'; + +// Components +import { Body } from '../typography/Body.styled'; +import { Bold } from '../typography/Bold.styled'; +import { FlexColumn } from '../containers/FlexColumn.styled'; +import IconButton from '../icon-button'; +import Link from '../link'; +import Icon from '../icon'; + +// Styled Components import { Affiliation, ArrowDownIcon, @@ -12,15 +34,6 @@ import { Votes, VotesIcon, } from './OptionCard.styled'; -import { Body } from '../typography/Body.styled'; -import { Bold } from '../typography/Bold.styled'; -import { FlexColumn } from '../containers/FlexColumn.styled'; -import { fetchOptionUsers, GetCycleResponse } from 'api'; -import { useAppStore } from '../../store'; -import { useNavigate, useParams } from 'react-router-dom'; -import { useQuery } from '@tanstack/react-query'; -import { useMemo, useState } from 'react'; -import IconButton from '../icon-button'; type OptionCardProps = { option: GetCycleResponse['forumQuestions'][number]['questionOptions'][number]; @@ -161,15 +174,19 @@ function OptionCard({ Funding request: {option.fundingRequest} )} - {option.optionSubTitle && {option.optionSubTitle}} - + {option.optionSubTitle && ( + {props.children}, + p: ({ node, ...props }) => {props.children}, + }} + > + {option.optionSubTitle} + + )} + + +
    diff --git a/packages/berlin/src/components/secret-code/SecretCode.tsx b/packages/berlin/src/components/secret-code/SecretCode.tsx index aeb10e18..e186af60 100644 --- a/packages/berlin/src/components/secret-code/SecretCode.tsx +++ b/packages/berlin/src/components/secret-code/SecretCode.tsx @@ -1,11 +1,10 @@ -import toast from 'react-hot-toast'; -import { useAppStore } from '../../store'; - import { Body } from '../typography/Body.styled'; +import { Copy } from 'lucide-react'; import { FlexRow } from '../containers/FlexRow.styled'; import { SecretCodeContainer } from './SecretCode.styled'; import { Subtitle } from '../typography/Subtitle.styled'; -import IconButton from '../icon-button'; +import Icon from '../icon'; +import toast from 'react-hot-toast'; type SecretCodeProps = { groupName: string; @@ -13,8 +12,6 @@ type SecretCodeProps = { }; function SecretCode({ groupName, secretCode }: SecretCodeProps) { - const theme = useAppStore((state) => state.theme); - const handleCopyButtonClick = () => { navigator.clipboard.writeText(secretCode); toast.success(`Secret code ${secretCode} copied to clipboard`); @@ -24,12 +21,9 @@ function SecretCode({ groupName, secretCode }: SecretCodeProps) { Access code for {groupName} research group {secretCode} - + + + ); diff --git a/packages/berlin/src/components/tables/comment-table/CommentsTable.tsx b/packages/berlin/src/components/tables/comment-table/CommentsTable.tsx index 6580aac1..4a5801f0 100644 --- a/packages/berlin/src/components/tables/comment-table/CommentsTable.tsx +++ b/packages/berlin/src/components/tables/comment-table/CommentsTable.tsx @@ -1,4 +1,5 @@ // React and third-party libraries +import { ThumbsUp, Trash } from 'lucide-react'; import { useEffect, useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; @@ -9,14 +10,11 @@ import { GetCommentsResponse, deleteComment, deleteLike, fetchCommentLikes, post // Hooks import useUser from '../../../hooks/useUser'; -// Store -import { useAppStore } from '../../../store'; - // Components import { FlexRow } from '../../containers/FlexRow.styled'; import Button from '../../button'; import Dialog from '../../dialog'; -import IconButton from '../../icon-button'; +import Icon from '../../icon'; // Styled Components import { Author, Card, Comment, FormattedDate } from './CommentsTable.styled'; @@ -27,7 +25,6 @@ type CommentsTableProps = { function CommentsTable({ comment }: CommentsTableProps) { const { optionId } = useParams(); - const theme = useAppStore((state) => state.theme); const queryClient = useQueryClient(); const { user } = useUser(); @@ -114,16 +111,7 @@ function CommentsTable({ comment }: CommentsTableProps) { onClick={handleLikeClick} style={{ userSelect: 'none' }} > - + {isCommentLiked ? : } @@ -131,13 +119,11 @@ function CommentsTable({ comment }: CommentsTableProps) { {comment.user?.username === user?.username && ( +
    + + + +
    } title="Are you sure?" description="This action cannot be undone. This will permanently delete your comment from our servers." diff --git a/packages/berlin/src/components/tables/groups-table/GroupsTable.tsx b/packages/berlin/src/components/tables/groups-table/GroupsTable.tsx index 192cd47c..64edd8eb 100644 --- a/packages/berlin/src/components/tables/groups-table/GroupsTable.tsx +++ b/packages/berlin/src/components/tables/groups-table/GroupsTable.tsx @@ -1,4 +1,5 @@ // React and third-party libraries +import { Copy } from 'lucide-react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; import toast from 'react-hot-toast'; @@ -7,8 +8,8 @@ import toast from 'react-hot-toast'; import { deleteUsersToGroups, fetchGroupMembers, - GetUsersToGroupsResponse, fetchGroupRegistrations, + GetUsersToGroupsResponse, } from 'api'; // Hooks @@ -16,14 +17,15 @@ import { useAppStore } from '../../../store'; import useUser from '../../../hooks/useUser'; // Components +import { Body } from '../../typography/Body.styled'; +import { Bold } from '../../typography/Bold.styled'; import { Card, Group, GroupProposal, Secret } from './GroupsTable.styled'; +import { FlexColumn } from '../../containers/FlexColumn.styled'; +import { FlexRow } from '../../containers/FlexRow.styled'; import Button from '../../button'; import Dialog from '../../dialog'; +import Icon from '../../icon'; import IconButton from '../../icon-button'; -import { Body } from '../../typography/Body.styled'; -import { FlexRow } from '../../containers/FlexRow.styled'; -import { FlexColumn } from '../../containers/FlexColumn.styled'; -import { Bold } from '../../typography/Bold.styled'; interface GroupCardProps { userToGroup: GetUsersToGroupsResponse[0]; @@ -91,12 +93,9 @@ function GroupCard({ userToGroup, theme, onLeaveGroup }: GroupCardProps) { {userToGroup.group.secret ? ( {userToGroup.group.secret} - handleCopyButtonClick(userToGroup.group.secret || '')} - icon={{ src: `/icons/copy-${theme}.svg`, alt: 'Copy icon' }} - $color="secondary" - $padding={4} - /> + + handleCopyButtonClick(userToGroup.group.secret || '')} /> + ) : ( No secret diff --git a/packages/berlin/src/components/tables/results-table/ResultsTable.tsx b/packages/berlin/src/components/tables/results-table/ResultsTable.tsx index 6e4487fc..248d0bed 100644 --- a/packages/berlin/src/components/tables/results-table/ResultsTable.tsx +++ b/packages/berlin/src/components/tables/results-table/ResultsTable.tsx @@ -1,6 +1,9 @@ // React and third-party libraries import { useQuery } from '@tanstack/react-query'; +import { Heart, MessageSquareText, Radical } from 'lucide-react'; import { useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; +import Markdown from 'react-markdown'; // API import { fetchOptionUsers, fetchRegistrationData, fetchRegistrationFields } from 'api'; @@ -14,9 +17,9 @@ import { FlexRow } from '../../containers/FlexRow.styled'; import IconButton from '../../icon-button'; import { Body } from '../../typography/Body.styled'; import { Bold } from '../../typography/Bold.styled'; +import Link from '../../link'; // Styled Components -import { useNavigate } from 'react-router-dom'; import { Card, Funding, Icon, Plurality, TitleContainer } from './ResultsTable.styled'; type ResultsTableProps = { @@ -103,21 +106,13 @@ function ResultsTable({ $expanded, option, onClick, cycleId, eventId }: ResultsT - + {option.allocatedHearts} - + {formattedQuadraticScore} @@ -159,7 +154,26 @@ function ResultsTable({ $expanded, option, onClick, cycleId, eventId }: ResultsT /> - {option.optionSubTitle} + {option.optionSubTitle && ( + {props.children}, + p: ({ node, ...props }) => {props.children}, + }} + > + {option.optionSubTitle} + + )} + + Research Output: {researchOutputValue} + + + Lead Author: {optionUsers?.user?.firstName} {optionUsers?.user?.lastName} + + + Collaborators:{' '} + {collaborators && collaborators.length > 0 ? collaborators.join(', ') : 'None'} + Research Output: {researchOutputValue} @@ -177,14 +191,9 @@ function ResultsTable({ $expanded, option, onClick, cycleId, eventId }: ResultsT Voter affiliations: {option.listOfGroupNames.join(', ')} - + + + diff --git a/packages/berlin/src/hooks/useCountdown.tsx b/packages/berlin/src/hooks/useCountdown.tsx index 500900c5..ef943531 100644 --- a/packages/berlin/src/hooks/useCountdown.tsx +++ b/packages/berlin/src/hooks/useCountdown.tsx @@ -52,17 +52,13 @@ const useCountdown = (startAt: string | null, endAt: string | null): Countdown = const minutes = Math.floor((time % 3600) / 60); const seconds = time % 60; - if (days > 0) { - return `${pluralize(days, 'day')} ${pluralize(hours, 'hour')} ${pluralize( - minutes, - 'minute', - )} ${pluralize(seconds, 'second')}`; + if (days > 1) { + return `${pluralize(days, 'day')} ${pluralize(hours, 'hour')}`; + } else if (hours >= 1) { + return `${pluralize(hours, 'hour')} ${pluralize(minutes, 'minute')}`; + } else { + return `${pluralize(minutes, 'minute')} ${pluralize(seconds, 'second')}`; } - - return `${pluralize(hours, 'hour')} ${pluralize(minutes, 'minute')} ${pluralize( - seconds, - 'second', - )}`; }; return { formattedTime: calculateTime(), cycleState, time }; diff --git a/packages/berlin/src/index.css b/packages/berlin/src/index.css new file mode 100644 index 00000000..8abdb15c --- /dev/null +++ b/packages/berlin/src/index.css @@ -0,0 +1,76 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/packages/berlin/src/lib/utils.ts b/packages/berlin/src/lib/utils.ts new file mode 100644 index 00000000..9ad0df42 --- /dev/null +++ b/packages/berlin/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/packages/berlin/src/main.tsx b/packages/berlin/src/main.tsx index 95dc2ece..6f5ba456 100644 --- a/packages/berlin/src/main.tsx +++ b/packages/berlin/src/main.tsx @@ -6,7 +6,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import BerlinApp from './App.tsx'; import ThemedApp from './global.styled'; -// import 'ui/dist/style.css'; +import './index.css'; const queryClient = new QueryClient(); diff --git a/packages/berlin/src/pages/Comments.tsx b/packages/berlin/src/pages/Comments.tsx index d30167bc..1d7e49c3 100644 --- a/packages/berlin/src/pages/Comments.tsx +++ b/packages/berlin/src/pages/Comments.tsx @@ -1,4 +1,5 @@ // React and third-party libraries +import { ArrowDownUp } from 'lucide-react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; import { useMemo, useState } from 'react'; @@ -17,9 +18,6 @@ import { fetchOption, fetchComments, postComment, fetchOptionUsers } from 'api'; // handleLocalVote, // } from '../utils/voting'; -// Store -import { useAppStore } from '../store'; - // Components import { Body } from '../components/typography/Body.styled'; import { Bold } from '../components/typography/Bold.styled'; @@ -29,16 +27,15 @@ import { Form } from '../components/containers/Form.styled'; import { Subtitle } from '../components/typography/Subtitle.styled'; import BackButton from '../components/back-button'; import Button from '../components/button'; -import CommentsTable from '../components/tables/comment-table'; import CommentsColumns from '../components/columns/comments-columns'; -import IconButton from '../components/icon-button'; +import CommentsTable from '../components/tables/comment-table'; +import Icon from '../components/icon'; import Textarea from '../components/textarea'; // import { INITIAL_HEARTS } from '../utils/constants'; // type LocalUserVotes = { optionId: string; numOfVotes: number }[]; function Comments() { - const theme = useAppStore((state) => state.theme); const queryClient = useQueryClient(); const { optionId } = useParams(); // const { user } = useUser(); @@ -223,20 +220,17 @@ function Comments() { <> Total comments ({sortedComments.length}) -
    + + setSortOrder((prevOrder) => (prevOrder === 'asc' ? 'desc' : 'asc'))} + > Sort - setSortOrder((prevOrder) => (prevOrder === 'asc' ? 'desc' : 'asc'))} - icon={{ - src: `/icons/sort-${theme}.svg`, - alt: 'Sort icon', - }} - $padding={4} - $color="secondary" - $height={24} - $width={24} - /> -
    + + + +
    diff --git a/packages/berlin/src/pages/Cycle.tsx b/packages/berlin/src/pages/Cycle.tsx index a625aa85..ecfc1666 100644 --- a/packages/berlin/src/pages/Cycle.tsx +++ b/packages/berlin/src/pages/Cycle.tsx @@ -32,7 +32,8 @@ import BackButton from '../components/back-button'; import Button from '../components/button'; import CycleColumns from '../components/columns/cycle-columns'; import OptionCard from '../components/option-card'; -import { FINAL_QUESTION_TITLE, FIVE_MINUTES_IN_SECONDS, INITIAL_HEARTS } from '../utils/constants'; +import { FINAL_QUESTION_TITLE, INITIAL_HEARTS } from '../utils/constants'; +import { Heart } from 'lucide-react'; type Order = 'asc' | 'desc'; type LocalUserVotes = { optionId: string; numOfVotes: number }[]; @@ -54,7 +55,6 @@ function Cycle() { queryKey: ['votes', cycleId], queryFn: () => fetchUserVotes(cycleId || ''), enabled: !!user?.id && !!cycleId, - retry: false, }); const availableHearts = @@ -113,28 +113,22 @@ function Cycle() { case 'upcoming': return `Vote opens in: ${formattedTime}`; case 'open': - if (time && time <= FIVE_MINUTES_IN_SECONDS) { - return `Vote closes in: ${formattedTime}`; - } else if (time === 0) { - return 'Vote has ended.'; - } - return ''; + return time === 0 ? 'Vote has ended.' : `Vote closes in: ${formattedTime}`; default: return ''; } }, [cycleState, time, formattedTime]); - const updateInitialVotesAndHearts = (votes: GetUserVotesResponse) => { - const givenVotes = votes - .map((option) => option.numOfVotes) - .reduce((prev, curr) => prev + curr, 0); + const updateInitialVotesAndHearts = (votes: GetUserVotesResponse | null | undefined) => { + const givenVotes = + votes?.map((option) => option.numOfVotes).reduce((prev, curr) => prev + curr, 0) ?? 0; setAvailableHearts({ questionId: cycle?.forumQuestions[0].id || '', hearts: Math.max(0, INITIAL_HEARTS - givenVotes), }); - setLocalUserVotes(votes); + setLocalUserVotes(votes ?? []); }; const votesAreDifferent = useMemo(() => { @@ -155,9 +149,7 @@ function Cycle() { }, [localUserVotes, userVotes]); useEffect(() => { - if (userVotes?.length) { - updateInitialVotesAndHearts(userVotes); - } + updateInitialVotesAndHearts(userVotes); // eslint-disable-next-line react-hooks/exhaustive-deps }, [userVotes]); @@ -311,13 +303,7 @@ function Cycle() { {Array.from({ length: INITIAL_HEARTS }).map((_, id) => ( - {id + ))}