diff --git a/README.md b/README.md
index 094bb889..1a50edc0 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
-## (2020-10-07)
+## (2020-10-08)
- chore: add code of conduct ([6859555](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/6859555))
- chore: add identicons ([45ddea1](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/45ddea1))
- chore: add issue templates ([6adcbee](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/6adcbee))
- chore: add more status icons ([3225e43](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/3225e43))
+- chore: add share buttons to appeals ([4e35099](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/4e35099))
- chore: add social icons and fix font rendering ([b8e09b5](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/b8e09b5))
- chore: auto-detect Web3 call type ([15ae304](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/15ae304))
- chore: begin work on profile details page ([e4283ef](https://github.com/Proof-Of-Humanity/proof-of-humanity-web/commit/e4283ef))
diff --git a/_pages/index/submission-filters.js b/_pages/index/submission-filters.js
index 8c5fe136..10ab57e5 100644
--- a/_pages/index/submission-filters.js
+++ b/_pages/index/submission-filters.js
@@ -1,4 +1,4 @@
-import { Card, Input, Option, Select, Text } from "@kleros/components";
+import { Card, Input, Select, Text } from "@kleros/components";
import { Search } from "@kleros/icons";
import { useRouter } from "next/router";
@@ -10,9 +10,11 @@ export default function SubmissionFilters({ numberOfSubmissions }) {
- {numberOfSubmissions} Profile
- {Number(numberOfSubmissions) === 1 ? "" : "s"}
+
+ {(numberOfSubmissions || numberOfSubmissions === 0) &&
+ `${numberOfSubmissions} Profile${
+ numberOfSubmissions === 1 ? "" : "s"
+ }`}
}
headerSx={{ fontWeight: "bold", justifyContent: "flex-end" }}
@@ -34,26 +36,21 @@ export default function SubmissionFilters({ numberOfSubmissions }) {
}}
/>
+ value={submissionStatusEnum.array.find(
+ ({ kebabCase }) => kebabCase === router.query.status
+ )}
+ label="Filter by status:"
+ />
);
}
diff --git a/_pages/profile/[id]/submission-details-card/deadlines/challenge-button.js b/_pages/profile/[id]/submission-details-card/deadlines/challenge-button.js
index f72fffef..28b7b636 100644
--- a/_pages/profile/[id]/submission-details-card/deadlines/challenge-button.js
+++ b/_pages/profile/[id]/submission-details-card/deadlines/challenge-button.js
@@ -9,13 +9,15 @@ import {
NextLink,
Popup,
Text,
+ ethereumAddressRegExp,
useContract,
useWeb3,
+ zeroAddress,
} from "@kleros/components";
import { useEffect, useMemo, useState } from "react";
import { graphql, useFragment } from "relay-hooks";
-import { challengeReasonEnum, ethereumAddressRegExp, zeroAddress } from "data";
+import { challengeReasonEnum } from "data";
const challengeButtonFragments = {
contract: graphql`
diff --git a/_pages/profile/[id]/submission-details-card/deadlines/remove-button.js b/_pages/profile/[id]/submission-details-card/deadlines/remove-button.js
index a6b31d9a..710c64ff 100644
--- a/_pages/profile/[id]/submission-details-card/deadlines/remove-button.js
+++ b/_pages/profile/[id]/submission-details-card/deadlines/remove-button.js
@@ -6,12 +6,11 @@ import {
Text,
useContract,
useWeb3,
+ zeroAddress,
} from "@kleros/components";
import { useMemo } from "react";
import { graphql, useFragment } from "relay-hooks";
-import { zeroAddress } from "data";
-
const removeButtonFragments = {
contract: graphql`
fragment removeButtonContract on Contract {
diff --git a/components/button.js b/components/button.js
index 152f1232..9fe9a2be 100644
--- a/components/button.js
+++ b/components/button.js
@@ -32,9 +32,9 @@ const Button = forwardRef(
return `linear-gradient(90deg, ${primary} 0%, ${secondary} 100%)`;
},
position: "relative",
- "&:focus": {
+ ":focus": {
boxShadow({ colors: { text } }) {
- return `0 0 2px ${text}`;
+ return `0 0 1px ${text}`;
},
},
...sx,
@@ -47,10 +47,10 @@ const Button = forwardRef(
diff --git a/components/index.js b/components/index.js
index e64daea0..fbf2fa68 100644
--- a/components/index.js
+++ b/components/index.js
@@ -29,7 +29,7 @@ export { default as List, ListItem } from "./list";
export { default as Popup } from "./popup";
export { default as RelayProvider, useQuery } from "./relay-provider";
export { default as SVG } from "./svg";
-export { default as Select, Option } from "./select";
+export { default as Select } from "./select";
export { default as SocialIcons } from "./social-icons";
export { default as Text } from "./text";
export { default as Textarea } from "./textarea";
@@ -40,3 +40,4 @@ export { default as VotingHistory } from "./voting-history";
export { default as Web3Provider, useWeb3, useContract } from "./web3-provider";
export { NextLink, NextETHLink, createWrapConnection } from "./next-router";
+export { zeroAddress, ethereumAddressRegExp, createEnum } from "./parsing";
diff --git a/components/label.js b/components/label.js
index 2a1c8e7f..6314d04a 100644
--- a/components/label.js
+++ b/components/label.js
@@ -1,5 +1,6 @@
+import { forwardRef } from "react";
import { Label as _Label } from "theme-ui";
-export default function Label(props) {
- return <_Label {...props} />;
-}
+const Label = forwardRef((props, ref) => <_Label ref={ref} {...props} />);
+Label.displayName = "Label";
+export default Label;
diff --git a/components/list.js b/components/list.js
index 4f5e40bb..adc050c5 100644
--- a/components/list.js
+++ b/components/list.js
@@ -1,9 +1,11 @@
+import { forwardRef } from "react";
import { Box } from "theme-ui";
-export default function List(props) {
- return ;
-}
+const List = forwardRef((props, ref) => );
+List.displayName = "List";
+export default List;
-export function ListItem(props) {
- return ;
-}
+export const ListItem = forwardRef((props, ref) => (
+
+));
+ListItem.displayName = "ListItem";
diff --git a/components/parsing.js b/components/parsing.js
new file mode 100644
index 00000000..98f2a102
--- /dev/null
+++ b/components/parsing.js
@@ -0,0 +1,51 @@
+import lodashKebabCase from "lodash.kebabcase";
+import lodashStartCase from "lodash.startcase";
+
+export const zeroAddress = "0x0000000000000000000000000000000000000000";
+
+export const ethereumAddressRegExp = /^0x[\dA-Fa-f]{40}$/;
+
+export const createEnum = (keys, parse) => {
+ const _enum = keys.reduce(
+ (acc, key, index) => {
+ let extra;
+ if (Array.isArray(key)) [key, extra] = key;
+
+ const value = {
+ key,
+ index,
+ camelCase: key[0].toLowerCase() + key.slice(1),
+ kebabCase: lodashKebabCase(key),
+ startCase: lodashStartCase(key),
+ ...extra,
+ };
+ value.color = value.camelCase;
+ value.toString = () => value.startCase;
+
+ acc[key] = value;
+ acc[index] = value;
+ acc[value.camelCase] = value;
+ acc[value.kebabCase] = value;
+ acc[value.startCase] = value;
+ return acc;
+ },
+ {
+ parse:
+ parse ||
+ ((arrayOrKey) =>
+ Array.isArray(arrayOrKey)
+ ? arrayOrKey.reduce((acc, key) => {
+ const value = _enum[key];
+ acc[key] = value;
+ acc[value.index] = value;
+ acc[value.camelCase] = value;
+ acc[value.kebabCase] = value;
+ acc[value.startCase] = value;
+ return acc;
+ }, {})
+ : _enum[arrayOrKey]),
+ }
+ );
+ _enum.array = keys.map((_, index) => _enum[index]);
+ return _enum;
+};
diff --git a/components/select.js b/components/select.js
index 4f40591c..1397faaa 100644
--- a/components/select.js
+++ b/components/select.js
@@ -1,9 +1,143 @@
-import { Box, Select as _Select } from "theme-ui";
+import { alpha } from "@theme-ui/color";
+import { useSelect } from "downshift";
+import { useRef } from "react";
+import { usePopper } from "react-popper";
+import { Box } from "theme-ui";
-export default function Select(props) {
- return <_Select {...props} />;
+import Button from "./button";
+import Label from "./label";
+import List, { ListItem } from "./list";
+
+const popperOptions = {
+ modifiers: [
+ {
+ name: "sameWidth",
+ enabled: true,
+ phase: "beforeWrite",
+ fn({ state }) {
+ state.styles.popper.width = `${state.rects.reference.width}px`;
+ },
+ requires: ["computeStyles"],
+ effect: ({ state }) => {
+ state.elements.popper.style.width = `${state.elements.reference.offsetWidth}px`;
+ },
+ },
+ {
+ name: "offset",
+ options: {
+ offset: [0, 8],
+ },
+ },
+ {
+ name: "preventOverflow",
+ },
+ ],
+};
+function Icon({ item }) {
+ return item.Icon ? (
+
+ ) : null;
}
+export default function Select({ items, onChange, value, label, ...rest }) {
+ const {
+ getItemProps,
+ getLabelProps,
+ getMenuProps,
+ getToggleButtonProps,
+ highlightedIndex,
+ isOpen,
+ selectedItem,
+ } = useSelect({
+ items,
+ onSelectedItemChange({ selectedItem: _selectedItem }) {
+ onChange(_selectedItem);
+ },
+ initialSelectedItem: value,
+ });
+
+ const toggleButtonRef = useRef();
+ const menuRef = useRef();
+ const {
+ styles: { popper: popperStyle },
+ attributes: { popper: popperAttributes },
+ } = usePopper(toggleButtonRef.current, menuRef.current, popperOptions);
-export function Option(props) {
- return ;
+ const border = isOpen ? "borderBottom" : "borderTop";
+ return (
+
+
+
+
+ {isOpen &&
+ items.map((item, index) => (
+
+
+ {String(item)}
+
+ ))}
+
+
+ );
}
diff --git a/components/theme-provider.js b/components/theme-provider.js
index b4fb6d2a..64245a9e 100644
--- a/components/theme-provider.js
+++ b/components/theme-provider.js
@@ -103,14 +103,14 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
fontSize: 1,
paddingX: 2,
paddingY: 1,
- "&:disabled:not([data-loading=true])": {
+ ":disabled:not([data-loading=true])": {
backgroundColor: "skeleton",
backgroundImage: "none !important",
},
- "&:hover": {
+ ":hover": {
opacity: 0.8,
},
- "&:focus": {
+ ":focus": {
outline: "none",
},
spinner: {
@@ -125,11 +125,28 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
backgroundImage: "none !important",
fontSize: 1,
padding: 1,
- "&:disabled:not([data-loading=true])": {
+ ":disabled:not([data-loading=true])": {
backgroundColor: "skeleton",
backgroundImage: "none !important",
},
},
+ select: {
+ backgroundColor: "background",
+ backgroundImage: "none !important",
+ borderColor: "skeleton",
+ borderStyle: "solid",
+ borderWidth: 1,
+ color: "text",
+ paddingLeft: 2,
+ paddingRight: 3,
+ paddingY: 1,
+ ":hover": {
+ opacity: 0.8,
+ },
+ ":focus": {
+ outline: "none",
+ },
+ },
},
cards: {
primary: {
@@ -137,7 +154,7 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
boxShadow: "0 6px 10px rgba(255, 153, 0, 0.25)",
fontFamily: "heading",
fontSize: 0,
- "&:hover:not([disabled])": {
+ ":hover:not([disabled])": {
boxShadow: "0 6px 20px rgba(255, 153, 0, 0.25)",
},
},
@@ -149,13 +166,13 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
borderWidth: 2,
fontSize: 1,
padding: 2,
- "&:disabled": {
+ ":disabled": {
backgroundColor: "skeleton",
},
- "&:focus": {
+ ":focus": {
outline: "none",
},
- "&:focus,&:hover:not([disabled]),&.active": {
+ ":focus,:hover:not([disabled]),&.active": {
borderColor: "primary",
},
},
@@ -205,13 +222,18 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
input: {
marginTop: 1,
},
+ visuallyHidden: {
+ border: 0,
+ clip: "rect(0 0 0 0)",
+ height: "1px",
+ margin: "-1px",
+ overflow: "hidden",
+ padding: 0,
+ position: "absolute",
+ width: "1px",
+ },
},
mutedInput: { border: "none" },
- select: {
- borderColor: "skeleton",
- paddingRight: 3,
- paddingY: 1,
- },
smallInput: { borderColor: "skeleton", fontSize: 1, padding: 1 },
textarea: { borderColor: "skeleton" },
},
@@ -241,6 +263,19 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
textDecoration: "none",
},
},
+ select: {
+ list: {
+ backgroundColor: "background",
+ borderRadius: 3,
+ listStyle: "none",
+ padding: 0,
+ ":focus": { outline: "none" },
+ item: {
+ paddingX: 2,
+ paddingY: 1,
+ },
+ },
+ },
tabs: {
tabList: {
fontSize: 1,
@@ -262,6 +297,18 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
},
},
text: {
+ buttons: {
+ primary: {
+ justifyContent: "space-evenly",
+ },
+ secondary: {
+ justifyContent: "space-evenly",
+ },
+ select: {
+ justifyContent: "flex-start",
+ paddingRight: 1,
+ },
+ },
clipped: {
overflow: "hidden",
textOverflow: "ellipsis",
diff --git a/components/voting-history.js b/components/voting-history.js
index 589807fe..1b76a254 100644
--- a/components/voting-history.js
+++ b/components/voting-history.js
@@ -3,7 +3,7 @@ import { Box, Flex } from "theme-ui";
import { createUseDataloaders } from "./archon-provider";
import Card from "./card";
-import Select, { Option } from "./select";
+import Select from "./select";
import Tabs, { Tab, TabList, TabPanel } from "./tabs";
import { useWeb3 } from "./web3-provider";
@@ -96,27 +96,19 @@ function VotingHistoryTabPanel({
<>
+ label="Choose a round:"
+ />
{rulingDescriptions && (
+ items={rulingDescriptions}
+ onChange={(value) => setRuling(rulingDescriptions.indexOf(value))}
+ value={rulingDescriptions[ruling]}
+ label="Choose a voting option:"
+ />
)}
diff --git a/data/index.js b/data/index.js
index 319c93fd..969a366c 100644
--- a/data/index.js
+++ b/data/index.js
@@ -1,9 +1,7 @@
export {
challengeReasonEnum,
- ethereumAddressRegExp,
partyEnum,
queryEnums,
submissionStatusEnum,
- zeroAddress,
} from "./parsing";
export { useEvidenceFile } from "./use-dataloaders";
diff --git a/data/parsing.js b/data/parsing.js
index 97d562f6..e634ea28 100644
--- a/data/parsing.js
+++ b/data/parsing.js
@@ -1,54 +1,5 @@
+import { createEnum } from "@kleros/components";
import { Check, Pending, X } from "@kleros/icons";
-import lodashKebabCase from "lodash.kebabcase";
-import lodashStartCase from "lodash.startcase";
-
-export const zeroAddress = "0x0000000000000000000000000000000000000000";
-
-export const ethereumAddressRegExp = /^0x[\dA-Fa-f]{40}$/;
-
-const createEnum = (keys, parse) => {
- const _enum = keys.reduce(
- (acc, key, index) => {
- let extra;
- if (Array.isArray(key)) [key, extra] = key;
-
- const value = {
- key,
- index,
- camelCase: key[0].toLowerCase() + key.slice(1),
- kebabCase: lodashKebabCase(key),
- startCase: lodashStartCase(key),
- ...extra,
- };
- acc[key] = value;
- acc[index] = value;
- acc[value.camelCase] = value;
- acc[value.kebabCase] = value;
- acc[value.startCase] = value;
- return acc;
- },
- {
- parse:
- parse ||
- ((arrayOrKey) =>
- Array.isArray(arrayOrKey)
- ? arrayOrKey.reduce((acc, key) => {
- const value = _enum[key];
- acc[key] = value;
- acc[value.index] = value;
- acc[value.camelCase] = value;
- acc[value.kebabCase] = value;
- acc[value.startCase] = value;
- return acc;
- }, {})
- : _enum[arrayOrKey]),
- }
- );
- _enum.map = (callback) => keys.map((_, index) => callback(_enum[index]));
- _enum.find = (callback) =>
- Object.values(_enum).find((value) => callback(value));
- return _enum;
-};
export const submissionStatusEnum = createEnum(
[
diff --git a/package-lock.json b/package-lock.json
index 81647679..4d3c070b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2887,6 +2887,11 @@
"fastq": "^1.6.0"
}
},
+ "@popperjs/core": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.5.3.tgz",
+ "integrity": "sha512-RFwCobxsvZ6j7twS7dHIZQZituMIDJJNHS/qY6iuthVebxS3zhRY+jaC2roEKiAYaVuTcGmX6Luc6YBcf6zJVg=="
+ },
"@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
@@ -3037,6 +3042,15 @@
"defer-to-connect": "^1.0.1"
}
},
+ "@theme-ui/color": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@theme-ui/color/-/color-0.3.1.tgz",
+ "integrity": "sha512-Bgew6etspp087AdrKuMpcWjIQDQ8UTp28wtHCXgi1Ip5ClFn9i91DvaKgqXk9UwQJFL/IwydX8Bks/+u9tf0WA==",
+ "requires": {
+ "@theme-ui/css": "^0.3.1",
+ "polished": "^3.4.1"
+ }
+ },
"@theme-ui/color-modes": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@theme-ui/color-modes/-/color-modes-0.3.1.tgz",
@@ -5708,6 +5722,11 @@
"arity-n": "^1.0.4"
}
},
+ "compute-scroll-into-view": {
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz",
+ "integrity": "sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ=="
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -7431,6 +7450,27 @@
"minimatch": "^3.0.4"
}
},
+ "downshift": {
+ "version": "6.0.6",
+ "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.0.6.tgz",
+ "integrity": "sha512-tmLab3cXCn6PtZYl9V8r/nB2m+7/nCNrwo0B3kTHo/2lRBHr+1en1VNOQt2wIt0ajanAnxquZ00WPCyxe6cNFQ==",
+ "requires": {
+ "@babel/runtime": "^7.11.2",
+ "compute-scroll-into-view": "^1.0.14",
+ "prop-types": "^15.7.2",
+ "react-is": "^16.13.1"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.11.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
+ "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ }
+ }
+ },
"drbg.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz",
@@ -15965,6 +16005,14 @@
"ts-pnp": "^1.1.6"
}
},
+ "polished": {
+ "version": "3.6.7",
+ "resolved": "https://registry.npmjs.org/polished/-/polished-3.6.7.tgz",
+ "integrity": "sha512-b4OViUOihwV0icb9PHmWbR+vPqaSzSAEbgLskvb7ANPATVXGiYv/TQFHQo65S53WU9i5EQ1I03YDOJW7K0bmYg==",
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
"posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -17154,6 +17202,15 @@
"react-fast-compare": "^3.0.1"
}
},
+ "react-popper": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.3.tgz",
+ "integrity": "sha512-mOEiMNT1249js0jJvkrOjyHsGvqcJd3aGW/agkiMoZk3bZ1fXN1wQszIQSjHIai48fE67+zwF8Cs+C4fWqlfjw==",
+ "requires": {
+ "react-fast-compare": "^3.0.1",
+ "warning": "^4.0.2"
+ }
+ },
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -20190,6 +20247,14 @@
"he": "^1.1.0"
}
},
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"watchpack": {
"version": "2.0.0-beta.13",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.0.0-beta.13.tgz",
diff --git a/package.json b/package.json
index 8d3b4cda..9fd2b4b8 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,8 @@
"dependencies": {
"@emotion/core": "^10.0.35",
"@kleros/archon": "^0.10.4",
+ "@popperjs/core": "^2.5.3",
+ "@theme-ui/color": "^0.3.1",
"@theme-ui/presets": "^0.3.0",
"@theme-ui/typography": "^0.3.0",
"@unilogin/provider": "^0.6.1",
@@ -45,6 +47,7 @@
"authereum": "0.0.4-beta.186",
"buffer": "^5.6.0",
"dataloader": "^2.0.0",
+ "downshift": "^6.0.6",
"formik": "^2.1.5",
"lodash.kebabcase": "^4.1.1",
"lodash.startcase": "^4.4.0",
@@ -58,6 +61,7 @@
"react-jazzicon": "^0.1.3",
"react-loading-skeleton": "^2.1.1",
"react-player": "^2.6.1",
+ "react-popper": "^2.2.3",
"react-relay-network-modern": "^4.7.4",
"react-ripples": "^2.2.1",
"react-scroll-to": "^3.0.0-beta.6",