refactor(vpn-desktop): clean ui (#4263)

* set cursor default on disabled state

* fix long error messages overflow

* clean code

* fix hop select component style

* fix exit select button

* add nym vpn icon

* style refactoring

* style refactoring

* fix hover bg country list in light mode

* fix hover bg country list in light mode

---------

Co-authored-by: Zane Schepke <zanecschepke@gmail.com>
This commit is contained in:
Pierre Dommerc
2023-12-20 14:13:48 +01:00
committed by GitHub
parent dd9f4f24f1
commit 08aaa8813e
27 changed files with 92 additions and 86 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en" class="text-[12px]">
<html lang="en" class="text-[14px]">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 25 KiB

+16 -12
View File
@@ -66,22 +66,26 @@ function ConnectionStatus() {
{getStatusText(state.state)}
</div>
</div>
<div className="flex-col flex-1 text-center">
<div className="w-full flex flex-col flex-1 items-center overflow-hidden">
{state.loading && state.progressMessages.length > 0 && !state.error && (
<p className="text-dim-gray dark:text-mercury-mist font-bold">
{t(
`connection-progress.${
state.progressMessages[state.progressMessages.length - 1]
}`,
{
ns: 'backendMessages',
},
)}
</p>
<div className="w-4/5 h-2/3 overflow-scroll break-words text-center">
<p className="text-dim-gray dark:text-mercury-mist font-bold">
{t(
`connection-progress.${
state.progressMessages[state.progressMessages.length - 1]
}`,
{
ns: 'backendMessages',
},
)}
</p>
</div>
)}
{state.state === 'Connected' && <ConnectionTimer />}
{state.error && (
<p className="text-teaberry font-bold">{state.error}</p>
<div className="w-4/5 h-2/3 overflow-scroll break-words text-center">
<p className="text-teaberry font-bold">{state.error}</p>
</div>
)}
</div>
</div>
+1 -2
View File
@@ -71,9 +71,8 @@ function Home() {
<div className="h-full flex flex-col p-4">
<ConnectionStatus />
<div className="flex grow flex-col justify-between gap-y-2">
<div className="flex flex-col justify-between">
<div className="flex flex-col justify-between gap-y-2">
<NetworkModeSelect />
<div className="py-2"></div>
<div className="flex flex-col gap-6">
<div className="mt-3 font-semibold text-lg">
{t('select-node-title')}
+35 -37
View File
@@ -1,6 +1,7 @@
import { useTranslation } from 'react-i18next';
import clsx from 'clsx';
import { Country, NodeHop } from '../../types';
import { QuickConnectPrefix } from '../../constants';
import { useMainState } from '../../contexts';
interface HopSelectProps {
country: Country;
@@ -13,44 +14,41 @@ export default function HopSelect({
country,
onClick,
}: HopSelectProps) {
const { state } = useMainState();
const { t } = useTranslation('home');
return (
<>
<div
className="relative w-full flex flex-row justify-center cursor-pointer"
onKeyDown={onClick}
role="presentation"
onClick={onClick}
>
<input
readOnly={true}
type="text"
id="floating_outlined"
value={country.name}
className="dark:bg-baltic-sea cursor-pointer pl-11 dark:placeholder-white border border-gun-powder block px-2.5 pb-4 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg border-1 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer"
/>
<div className="top-1/2 transform -translate-y-1/2 left-2 absolute pointer-events-none">
{country.name.includes(QuickConnectPrefix) ? (
<span className="font-icon cursor-pointer px-2">bolt</span>
) : (
<img
src={`./flags/${country.code.toLowerCase()}.svg`}
className="h-8 scale-75 pointer-events-none fill-current"
alt={country.code}
/>
)}
</div>
<span className="font-icon scale-125 pointer-events-none absolute fill-current top-1/4 transform -translate-x-1/2 right-2">
arrow_right
</span>
<label
htmlFor="floating_outlined"
className="dark:text-white bg-blanc-nacre dark:bg-baltic-sea absolute text-sm text-gray-500 dark:text-gray-400 ml-4 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] dark:bg-gray-900 px-2 peer-placeholder-shown:px-2 peer-placeholder-shown:text-blue-600 peer-placeholder-shown:dark:text-blue-500 peer-placeholder-shown:top-2 peer-placeholder-shown:scale-75 peer-placeholder-shown:-translate-y-4 rtl:peer-placeholder-shown:translate-x-1/4 rtl:peer-placeholder-shown:left-auto start-1"
>
{nodeHop === 'entry' ? t('first-hop') : t('last-hop')}
</label>
return (
<div
className={clsx([
state === 'Disconnected' ? 'cursor-pointer' : 'cursor-not-allowed',
'w-full flex flex-row justify-between items-center py-3 px-4',
'text-baltic-sea dark:text-mercury-pinkish',
'border-cement-feet dark:border-gun-powder border-2 rounded-lg',
'relative',
])}
onKeyDown={onClick}
role="presentation"
onClick={onClick}
>
<div
className={clsx([
'absolute left-3 -top-3 px-1',
'bg-blanc-nacre dark:bg-baltic-sea text-sm',
])}
>
{nodeHop === 'entry' ? t('first-hop') : t('last-hop')}
</div>
</>
<div className="flex flex-row items-center gap-3">
<img
src={`./flags/${country.code.toLowerCase()}.svg`}
className="h-8 scale-90 pointer-events-none fill-current"
alt={country.code}
/>
<div className="text-base">{country.name}</div>
</div>
<span className="font-icon scale-150 pointer-events-none">
arrow_right
</span>
</div>
);
}
@@ -102,7 +102,7 @@ function NetworkModeSelect() {
</RadioGroup.Label>
<RadioGroup.Description
as="span"
className="text-base text-ciment-feet dark:text-mercury-mist"
className="text-base text-cement-feet dark:text-mercury-mist"
>
<span>{mode.desc}</span>
</RadioGroup.Description>
@@ -12,14 +12,14 @@ export default function CountryList({
}: CountryListProps) {
const { t } = useTranslation('nodeLocation');
return (
<ul className="flex flex-col w-full items-stretch px-6 gap-4">
<ul className="flex flex-col w-full items-stretch gap-4">
{countries && countries.length > 0 ? (
countries.map((country) => (
<li key={country.code} className="list-none w-full">
<div
role="presentation"
onKeyDown={() => onClick(country.name, country.code)}
className="flex flex-row justify-between dark:hover:bg-baltic-sea-jaguar hover:bg-coal-mine-light rounded-lg cursor-pointer"
className="flex flex-row justify-between dark:hover:bg-gun-powder hover:dark:bg-opacity-80 hover:bg-cement-feet hover:bg-opacity-20 rounded-lg cursor-pointer px-3"
onClick={() => onClick(country.name, country.code)}
>
<div className="flex flex-row items-center m-1 gap-3 p-1 cursor-pointer">
@@ -32,7 +32,7 @@ export default function CountryList({
{country.name}
</div>
</div>
<div className="p-4 flex items-center text-mercury-mist text-xs cursor-pointer">
<div className="p-4 flex items-center text-mercury-mist text-sm cursor-pointer">
{isSelected(country.code) ? t('selected') : ''}
</div>
</div>
+14 -16
View File
@@ -66,22 +66,20 @@ function NodeLocation({ node }: { node: NodeHop }) {
};
return (
<div>
<div className="h-full flex flex-col">
<div className="h-70 flex flex-col justify-center items-center gap-y-2 p-1">
<QuickConnect onClick={handleCountrySelection} />
<SearchBox
value={search}
onChange={filter}
placeholder={t('search-country')}
/>
<span className="mt-3" />
<CountryList
countries={foundCountries}
onClick={handleCountrySelection}
isSelected={isCountrySelected}
/>
</div>
<div className="h-full flex flex-col p-4">
<div className="h-70 flex flex-col justify-center items-center gap-y-2">
<QuickConnect onClick={handleCountrySelection} />
<SearchBox
value={search}
onChange={filter}
placeholder={t('search-country')}
/>
<span className="mt-3" />
<CountryList
countries={foundCountries}
onClick={handleCountrySelection}
isSelected={isCountrySelected}
/>
</div>
</div>
);
@@ -14,12 +14,12 @@ export default function QuickConnect({ onClick }: QuickConnectProps) {
onKeyDown={() =>
onClick(defaultNodeLocation.name, defaultNodeLocation.code)
}
className="flex px-5 flex-row w-full py-8 cursor-pointer"
className="flex px-1 flex-row items-center w-full py-8 cursor-pointer"
onClick={() =>
onClick(defaultNodeLocation.name, defaultNodeLocation.code)
}
>
<span className="font-icon px-4 cursor-pointer">bolt</span>
<span className="font-icon text-2xl px-4 cursor-pointer">bolt</span>
<div className="cursor-pointer">{`${QuickConnectPrefix} ${defaultNodeLocation.name}`}</div>
</div>
);
+17 -10
View File
@@ -1,3 +1,4 @@
import clsx from 'clsx';
import { InputEvent } from '../../types';
interface SearchProps {
@@ -12,24 +13,30 @@ export default function SearchBox({
placeholder,
}: SearchProps) {
return (
<div className="relative w-full flex flex-row justify-center px-6">
<div className="w-full relative flex flex-row items-center px-4 mb-2">
<input
type="text"
id="floating_outlined"
id="country_search"
value={value}
className="dark:bg-baltic-sea pl-9 dark:placeholder-white border border-gun-powder block px-2.5 pb-4 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg border-1 border-gray-300 appearance-none dark:text-white dark:border-gray-600 focus:outline-none focus:ring-0 peer"
className={clsx([
'bg-blanc-nacre dark:bg-baltic-sea focus:outline-none focus:ring-0',
'w-full flex flex-row justify-between items-center py-3 px-4 pl-11',
'text-baltic-sea dark:text-mercury-pinkish',
'placeholder:text-cement-feet placeholder:dark:text-mercury-mist',
'border-cement-feet dark:border-gun-powder border-2 rounded-lg',
'relative text-base',
])}
placeholder={placeholder}
onChange={onChange}
/>
<span className="font-icon scale-125 pointer-events-none absolute fill-current top-1/2 transform -translate-y-1/2 left-9">
<span
className={clsx([
'font-icon text-2xl absolute left-7',
'text-baltic-sea dark:text-laughing-jack',
])}
>
search
</span>
<label
htmlFor="floating_outlined"
className="dark:text-white dark:bg-baltic-sea absolute text-sm text-gray-500 dark:text-gray-400 ml-8 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] bg-blanc-nacre dark:bg-gray-900 px-2 peer-placeholder-shown:px-2 peer-placeholder-shown:top-2 peer-placeholder-shown:scale-75 peer-placeholder-shown:-translate-y-4 rtl:peer-placeholder-shown:translate-x-1/4 rtl:peer-placeholder-shown:left-auto start-1"
>
Search
</label>
</div>
);
}
+1 -1
View File
@@ -50,7 +50,7 @@ function Settings() {
<span
className={clsx([
darkModeEnabled ? 'translate-x-6' : 'translate-x-1',
'inline-block h-4 w-4 transform rounded-full bg-ciment-feet dark:bg-white transition',
'inline-block h-4 w-4 transform rounded-full bg-cement-feet dark:bg-white transition',
])}
/>
</Switch>
+1 -1
View File
@@ -62,7 +62,7 @@ export default {
'dim-gray': '#696571',
// [L] network mode desc text
// [L] node location select outline
'ciment-feet': '#79747E',
'cement-feet': '#79747E',
// [D] node location select outline
'gun-powder': '#49454F',
// [D] top-bar icon