Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: polish governance UI/UX #5532

Merged
merged 22 commits into from Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
797ac74
fix: proposals grid spacing
jeeanribeiro Dec 29, 2022
71044d3
enhancement: adds sorting to proposals
jeeanribeiro Dec 29, 2022
fd5886f
chore: wrap register proposal in a form element
jeeanribeiro Dec 29, 2022
873be30
chore: wrap vote for proposal in a form element
jeeanribeiro Dec 29, 2022
0a86874
enhancement: adds only value UI to SelectorInput
jeeanribeiro Dec 29, 2022
0d7331b
feat: adds NodeInput component
jeeanribeiro Dec 29, 2022
a78b6b2
enhancement: adds NodeInput in RegisterProposalPopup
jeeanribeiro Dec 29, 2022
5b75e1d
feat: adds disabled state to SliderInput
jeeanribeiro Dec 29, 2022
e82fcd5
fix: adds dark mode styling
jeeanribeiro Dec 29, 2022
a2e44fd
chore: debounce buttons and add spinners in register proposal and nod…
jeeanribeiro Dec 29, 2022
0af8ec2
fix: only show text hint in remove proposal popup if event status is …
jeeanribeiro Dec 29, 2022
e109ae0
fix: disabled voting options when event is in upcoming or ended phase
jeeanribeiro Dec 29, 2022
357a58a
fix: adds reactivity to counted votes
jeeanribeiro Dec 30, 2022
2bc5ae2
enhancement: adds reactivity to ProposalDetailsMenu
jeeanribeiro Dec 31, 2022
fd85ea2
Merge branch 'stardust-develop' of github.com:iotaledger/firefly into…
jeeanribeiro Dec 31, 2022
4d7fb62
Merge branch 'stardust-develop' into chore/polish-governance-ui-ux
jeeanribeiro Dec 31, 2022
135a585
refactor: SliderInput code style
jeeanribeiro Jan 10, 2023
75bfa58
fix: apply suggestions
jeeanribeiro Jan 10, 2023
a11c5d4
Merge branch 'develop' into chore/polish-governance-ui-ux
jeeanribeiro Jan 10, 2023
f21f2aa
fix: adds missing semicolon in css
jeeanribeiro Jan 11, 2023
ed8ee36
fix: missing display block
jeeanribeiro Jan 11, 2023
ccd3131
Merge branch 'develop' into chore/polish-governance-ui-ux
Tuditi Jan 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -6,6 +6,7 @@
Button,
FontWeight,
Icon,
KeyValueBox,
Pane,
ProposalDetailsButton,
ProposalInformation,
Expand Down Expand Up @@ -46,6 +47,8 @@

$: isTransferring = $selectedAccount?.isTransferring

$: proposalState, void setTotalVotes()

async function setVotingEventPayload(eventId: string): Promise<void> {
const event = await getVotingEvent(eventId)
if (event?.data?.payload?.type === ParticipationEventType.Voting) {
Expand Down Expand Up @@ -118,13 +121,11 @@
</Text>
<ul class="space-y-2">
{#each Object.keys(votesCounter) as counterKey}
<li class="flex justify-between bg-gray-50 px-4 py-3 rounded-lg">
<Text fontWeight={FontWeight.medium} overrideColor classes="text-gray-600">
{localize(`views.governance.details.yourVote.${counterKey}`)}
</Text>
<Text overrideColor classes="text-gray-600">
{votesCounter[counterKey]}
</Text>
<li>
<KeyValueBox
keyText={localize(`views.governance.details.yourVote.${counterKey}`)}
valueText={votesCounter[counterKey]}
/>
</li>
{/each}
</ul>
Expand Down
Expand Up @@ -29,7 +29,7 @@
<ProposalsDetails />
</Pane>
</div>
<span class="block w-0.5 h-full bg-gray-200" />
<span class="block w-0.5 h-full bg-gray-200 dark:bg-gray-800" />
<div class="w-2/3">
{#if loaded}
<Proposals {proposals} />
Expand Down
44 changes: 30 additions & 14 deletions packages/shared/components/ProposalAnswer.svelte
@@ -1,32 +1,39 @@
<script lang="typescript">
import type { Answer } from '@iota/wallet'
import { createEventDispatcher } from 'svelte'
import { Text, FontWeight, TooltipIcon } from 'shared/components'
import { Position } from 'shared/components/enums'
import type { Answer } from '@iota/wallet'
import { Icon as IconEnum } from '@auxiliary/icon'
import { appSettings } from '@core/app/stores'
import { Icon } from '@auxiliary/icon'

export let answer: Answer
export let answerIndex: number = undefined
export let disabled = false
Tuditi marked this conversation as resolved.
Show resolved Hide resolved
export let hidden: boolean = null
export let isSelected: boolean = null
export let isVotedFor: boolean = null
export let answerIndex: number = undefined
export let percentage: string = ''

$: showBorder = isVotedFor || isSelected
$: dark = $appSettings.darkMode

const dispatch = createEventDispatcher()

function handleClick(): void {
dispatch('answerClicked', answer?.value)
if (!disabled) {
dispatch('answerClicked', answer?.value)
}
}
</script>

<proposal-answer
style:--percentage={percentage}
class:hidden={isVotedFor ? false : hidden}
class="flex justify-between items-center p-3 rounded-md border border-solid relative
class:dark
class="flex justify-between items-center p-3 rounded-md border border-solid relative dark:bg-gray-900
{disabled ? 'cursor-default' : 'cursor-pointer'}
{isVotedFor ? 'bg-blue-100' : ''}
{showBorder ? 'border-blue-500' : 'border-gray-200'}
{showBorder ? 'border-blue-500' : 'border-gray-200 dark:border-transparent'}
"
on:click={handleClick}
>
Expand All @@ -40,31 +47,36 @@
<span
class="flex items-center justify-center h-5 w-5 text-12 {isSelected
? 'bg-blue-500 text-white'
: 'bg-white text-gray-500'} text-700 border border-solid border-gray-200"
: 'bg-white dark:bg-gray-900 text-gray-500'} text-700 border border-solid border-gray-200 dark:border-gray-800"
>
{answerIndex + 1}
</span>
{/if}
{/if}
<Text fontWeight={FontWeight.medium}>{answer.text}</Text>
</div>
<div class="flex items-center space-x-1">
<div class="flex items-center space-x-1.5">
{#if percentage}
<div>
<Text smaller fontWeight={FontWeight.medium} classes="ml-auto text-gray-700" overrideColor
>{percentage}</Text
<Text
smaller
fontWeight={FontWeight.medium}
classes="ml-auto text-gray-700 dark:text-gray-500"
overrideColor
>
{percentage}
</Text>
</div>
{/if}
<div class="flex justify-center items-center w-3 h-3">
{#if answer.additionalInfo}
<TooltipIcon
icon={IconEnum.Info}
iconClasses="text-gray-600 dark:text-gray-200"
icon={Icon.Info}
iconClasses="text-gray-600 dark:text-gray-500"
text={answer.additionalInfo}
position={Position.Left}
width={10}
height={10}
width={13}
height={13}
/>
{/if}
</div>
Expand All @@ -90,6 +102,10 @@
width: var(--percentage);
z-index: 1;
}

&.dark::after {
@apply bg-gray-1000;
}
}

.ring {
Expand Down
14 changes: 11 additions & 3 deletions packages/shared/components/ProposalQuestion.svelte
@@ -1,7 +1,8 @@
<script lang="typescript">
import type { AnswerStatus, Question } from '@iota/wallet'
import { Text, FontWeight, Icon, ProposalAnswer } from 'shared/components'
import { ProposalStatus, selectedProposal } from '@contexts/governance'
import { Icon as IconEnum } from '@auxiliary/icon'
import type { AnswerStatus, Question } from '@iota/wallet'

export let currentVote: AnswerStatus[] = undefined
export let questionIndex: number = undefined
Expand All @@ -16,6 +17,8 @@
$: answers = [...question?.answers, { value: 0, text: 'Abstain', additionalInfo: '' }]
$: showMargin = isOpened || ((voteValue || voteValue === 0) && !isOpened) // voteValue 0 corresponds to abstained vote
$: currentVote, setPercentagesFromAccumulated()
$: disabled =
$selectedProposal.status === ProposalStatus.Upcoming || $selectedProposal.status === ProposalStatus.Ended

function setPercentagesFromAccumulated(): void {
const totalAccumulated = currentVote?.reduce((acc, answer) => acc + answer.accumulated, 0)
Expand All @@ -35,15 +38,19 @@
}
</script>

<proposal-question class="flex flex-col px-5 py-4 rounded-xl border border-solid border-gray-200 cursor-pointer">
<proposal-question
class="flex flex-col px-5 py-4 rounded-xl border border-solid border-gray-200 dark:border-transparent dark:bg-gray-850 cursor-pointer"
>
<div on:click={onClick} class="flex justify-between items-center">
<div class="flex flex-col">
{#if questionIndex !== undefined}
<Text smaller fontWeight={FontWeight.bold} overrideColor classes="mb-1 text-blue-500"
>Question {questionIndex + 1}</Text
>
{/if}
<Text fontWeight={FontWeight.bold} overrideColor classes="text-gray-900">{question.text}</Text>
<Text fontWeight={FontWeight.bold} overrideColor classes="text-gray-900 dark:text-white">
{question.text}
</Text>
</div>
<div class="transform {isOpened ? 'rotate-180' : 'rotate-0'}">
<Icon icon={IconEnum.ChevronDown} classes="text-gray-500" />
Expand All @@ -54,6 +61,7 @@
<ProposalAnswer
{answer}
{answerIndex}
{disabled}
on:answerClicked={(event) => handleAnswerClick(event.detail)}
hidden={!isOpened}
isSelected={selectedAnswerValues[questionIndex] === answer?.value}
Expand Down
6 changes: 4 additions & 2 deletions packages/shared/components/Proposals.svelte
Expand Up @@ -6,6 +6,8 @@
import { IProposal } from '@contexts/governance/interfaces'

export let proposals: IProposal[] = []

$: sortedProposals = proposals.sort((a, b) => (a.id < b.id ? -1 : 1))
</script>

<proposals-container class="flex flex-col h-full">
Expand All @@ -14,8 +16,8 @@
{localize('views.governance.proposals.title')}
</Text>
</header-container>
<ul class="grid grid-cols-2 gap-6 flex-1 overflow-y-scroll">
{#each proposals as proposal}
<ul class="grid grid-cols-2 auto-rows-min gap-6 flex-1 overflow-y-scroll">
{#each sortedProposals as proposal}
<ProposalCard {proposal} />
{/each}
</ul>
Expand Down
14 changes: 6 additions & 8 deletions packages/shared/components/ProposalsDetails.svelte
@@ -1,5 +1,5 @@
<script lang="typescript">
import { ProposalsDetailsButton, Text } from 'shared/components'
import { ProposalsDetailsButton, Text, KeyValueBox } from 'shared/components'
import { FontWeight } from './enums'
import { localize } from '@core/i18n'
import { activeProfileId } from '@core/profile'
Expand Down Expand Up @@ -39,13 +39,11 @@
</header-container>
<ul class="space-y-2">
{#each Object.keys(details) as detailKey}
<li class="flex justify-between bg-gray-50 px-4 py-3 rounded-lg">
<Text fontWeight={FontWeight.medium} overrideColor classes="text-gray-600">
{localize(`views.governance.proposalsDetails.${detailKey}`)}
</Text>
<Text overrideColor classes="text-gray-600">
{details[detailKey] ?? '-'}
</Text>
<li>
<KeyValueBox
keyText={localize(`views.governance.proposalsDetails.${detailKey}`)}
valueText={details[detailKey] ?? '-'}
/>
</li>
{/each}
</ul>
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/components/VotingPower.svelte
Expand Up @@ -25,7 +25,7 @@
{localize('views.governance.votingPower.title')}
</Text>
<Text type={TextType.h1}>{formattedVotingPower}</Text>
<Text fontWeight={FontWeight.medium} overrideColor classes="mb-4 text-gray-600">
<Text fontWeight={FontWeight.medium} overrideColor classes="mb-4 text-gray-600 dark:text-white">
{localize('views.governance.votingPower.maximal', { values: { value: formattedMaxVotingPower } })}
</Text>
<Button
Expand Down
Expand Up @@ -16,7 +16,7 @@
<Pill
data={localize(`pills.proposalStatus.${status}`)}
textColor="gray-800"
darkTextColor="white"
darkTextColor="gray-800"
backgroundColor={STATUS_COLORS[status]}
darkBackgroundColor={STATUS_COLORS[status]}
classes="rounded-full px-2 py-1 flex items-center"
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/components/inputs/AssetAmountInput.svelte
Expand Up @@ -114,7 +114,7 @@
</div>
{#if containsSlider}
<div class="flex flex-col mt-5">
<SliderInput bind:value={amount} {max} decimals={asset.metadata.decimals} />
<SliderInput bind:value={amount} {max} decimals={asset.metadata.decimals} {disabled} />
<div class="flex flex-row justify-between">
<Text color="gray-800" darkColor="gray-500" fontSize="xs"
>{formatTokenAmountBestMatch(0, asset?.metadata)}</Text
Expand Down
52 changes: 52 additions & 0 deletions packages/shared/components/inputs/NodeInput.svelte
@@ -0,0 +1,52 @@
<script lang="ts">
import { SelectorInput, IOption, Modal } from 'shared/components'
import { localize } from '@core/i18n'
import { activeProfile } from '@core/profile/stores'
import { isValidUrl } from '@core/utils'

export let disabled = false
export let error: string
export let nodeUrl: string

let inputElement: HTMLInputElement
let modal: Modal
let nodeOptions: IOption[]
let selected: IOption

$: clientOptionsNodes = $activeProfile?.clientOptions?.nodes
$: clientOptionsNodes, (nodeOptions = getNodeOptionsFromClientOptions())
$: nodeUrl = selected?.value

export async function validate(): Promise<void> {
try {
if (!isValidUrl(selected?.value)) {
throw new Error(localize('error.node.invalid'))
}
return Promise.resolve()
Tuditi marked this conversation as resolved.
Show resolved Hide resolved
} catch (err) {
error = err?.message ?? err
return Promise.reject(error)
}
}

function getNodeOptionsFromClientOptions(): IOption[] {
return clientOptionsNodes
.filter((node) => !node.disabled)
.map((node, index) => ({
id: index,
key: null,
value: node.url,
}))
}
</script>

<SelectorInput
labelLocale="views.governance.details.proposalInformation.nodeUrl"
bind:selected
bind:inputElement
bind:modal
bind:error
{disabled}
options={nodeOptions}
{...$$restProps}
/>