summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2025-02-25 09:44:18 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2025-02-25 09:44:18 +0100
commit3d264be4e22da7aefa72432db9684b8b5930a64d (patch)
tree70abfe9fe101e58942c9e0d3ab444df6cbd5c7f5
parent63b4a2460e47e34c8a37cc42727759d42e0beeb7 (diff)
parent81265faa84a5f0701685cc76e3311b40247ce04d (diff)
downloadmullvadvpn-3d264be4e22da7aefa72432db9684b8b5930a64d.tar.xz
mullvadvpn-3d264be4e22da7aefa72432db9684b8b5930a64d.zip
Merge branch 'update-icons-in-app-to-latest-version-from-design-system-des-1648'
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-account-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-add-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-alert-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-checkmark-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-checkmark.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-copy.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-cross-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-cross.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-edit-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-external.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-filter-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-grabber.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-hide.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-info-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-reconnect.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-remove-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-search-circle.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-search.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-settings-filled.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/icons/icon-show.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/app-header-backdrop.svg5
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/app-triangle.svg5
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-account.svg3
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-add.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-alert.svg4
-rwxr-xr-xdesktop/packages/mullvad-vpn/assets/images/icon-arrow.svg7
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-back.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-check.svg3
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-checkmark.svg3
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-chevron-down.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-chevron-up.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-chevron.svg6
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-close-down.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-close-sml.svg1
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-close.svg8
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-copy.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-cross.svg3
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-edit.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-extLink.svg6
-rwxr-xr-xdesktop/packages/mullvad-vpn/assets/images/icon-fastest.svg7
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-filter-round.svg3
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-filter.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-info.svg3
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-language.svg69
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-more.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-obscure.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-reload.svg10
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-remove.svg23
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-search.svg17
-rwxr-xr-xdesktop/packages/mullvad-vpn/assets/images/icon-settings.svg9
-rwxr-xr-xdesktop/packages/mullvad-vpn/assets/images/icon-tick.svg4
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/icon-unobscure.svg4
-rwxr-xr-xdesktop/packages/mullvad-vpn/assets/images/negative.svg (renamed from desktop/packages/mullvad-vpn/assets/images/icon-fail.svg)0
-rwxr-xr-xdesktop/packages/mullvad-vpn/assets/images/positive.svg (renamed from desktop/packages/mullvad-vpn/assets/images/icon-success.svg)0
-rw-r--r--desktop/packages/mullvad-vpn/assets/images/spinner.svg (renamed from desktop/packages/mullvad-vpn/assets/images/icon-spinner.svg)0
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/Account.tsx13
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ApiAccessMethods.tsx118
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/AppButton.tsx11
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ChevronButton.tsx13
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ClipboardLabel.tsx84
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ContextMenu.tsx17
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettings.tsx55
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettingsStyles.tsx24
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/DeviceInfoButton.tsx19
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/DeviceRevokedView.tsx18
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ErrorView.tsx37
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountAddTime.tsx17
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorView.tsx25
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorViewStyles.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/Filter.tsx16
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ImageView.tsx70
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/InfoButton.tsx27
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/Login.tsx36
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/LoginStyles.tsx27
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/Modal.tsx25
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/NotificationBanner.tsx27
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/PageSlider.tsx40
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/ProblemReport.tsx34
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx29
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx19
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/RelayStatusIndicator.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/SearchBar.tsx33
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/SettingsImport.tsx21
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/SettingsTextImport.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettings.tsx149
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettingsStyles.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/Support.tsx6
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/TooManyDevices.tsx71
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/UserInterfaceSettings.tsx2
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderAccountButton.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderSettingsButton.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/app-navigation-header/components/AppNavigationHeaderBackButton.tsx12
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/cell/CellButton.tsx11
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/cell/Input.tsx29
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/cell/Label.tsx51
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/cell/Selector.tsx29
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsRow.tsx6
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsSelect.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanel.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanelChevron.tsx40
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/main-view/FeatureIndicators.tsx15
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/main-view/MainView.tsx6
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/main-view/SelectLocationButton.tsx5
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomListDialogs.tsx4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomLists.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRow.tsx8
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRowStyles.tsx9
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/select-location/SelectLocation.tsx94
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/select-location/SpecialLocationList.tsx14
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/box/Box.tsx2
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChip.tsx80
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChipContext.tsx22
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipIcon.tsx14
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx14
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/index.ts2
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/flex/Flex.tsx3
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx77
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButtonContext.tsx24
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx43
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/Icon.tsx41
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/types.ts34
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/image/Image.tsx15
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/image/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/index.ts4
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/logo/Logo.tsx10
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/Spinner.tsx23
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/index.ts1
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/IconBadge.tsx14
-rw-r--r--desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/index.ts1
-rwxr-xr-xios/convert-assets.rb93
146 files changed, 1295 insertions, 1239 deletions
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-account-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-account-circle.svg
new file mode 100644
index 0000000000..58e71e4ead
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-account-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2660" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2660)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM11.9949 11.8129C11.3452 11.8137 10.6978 11.8946 10.0669 12.0536C9.37813 12.2327 8.70677 12.4753 8.06039 12.7785C7.75379 12.9252 7.49057 13.1529 7.29734 13.4384C7.09459 13.7466 6.99107 14.1123 7.0006 14.4843V15.0316C6.99962 15.159 7.02328 15.2853 7.07027 15.4032C7.11726 15.5211 7.18627 15.6283 7.27368 15.7184C7.36109 15.8085 7.46526 15.8798 7.57962 15.9282C7.65126 15.9584 7.72618 15.9793 7.80242 15.9905C7.8481 15.9971 7.89411 16.0003 7.94011 16H16.0602C16.1837 16.0007 16.3063 15.9762 16.4207 15.9277C16.535 15.8793 16.6389 15.808 16.7263 15.718C16.7674 15.6757 16.8045 15.6297 16.837 15.5805C16.8738 15.5251 16.9047 15.4655 16.9297 15.4031C16.9767 15.2852 17.0007 15.1589 16.9997 15.0316V14.4843C17.0066 14.1111 16.8991 13.7452 16.6924 13.4384C16.4953 13.1494 16.2255 12.9213 15.912 12.7785C15.2653 12.4856 14.5969 12.2459 13.9133 12.0619C13.2863 11.8972 12.6419 11.8136 11.9949 11.8129ZM11.9949 6.00227C11.6837 5.98804 11.3728 6.0408 11.0823 6.15707C10.7918 6.27342 10.528 6.45083 10.3078 6.67795C10.0876 6.90515 9.91541 7.17706 9.8027 7.4765C9.68999 7.77593 9.63872 8.09628 9.65285 8.41714C9.63905 8.73792 9.69031 9.05818 9.80303 9.35745C9.91607 9.6568 10.0879 9.92854 10.3081 10.1557C10.5286 10.3827 10.7922 10.56 11.0827 10.6764C11.3728 10.7926 11.6837 10.8455 11.9949 10.8313C12.3061 10.8452 12.6166 10.7923 12.9068 10.6759C13.197 10.5595 13.4608 10.3822 13.681 10.1552C13.9012 9.92812 14.0734 9.65646 14.1861 9.35719C14.2991 9.05801 14.3504 8.73792 14.3369 8.41714C14.3507 8.09637 14.2995 7.7761 14.1867 7.47683C14.0737 7.17757 13.9018 6.90574 13.6813 6.67862C13.4612 6.45159 13.1973 6.27427 12.9071 6.15792C12.6166 6.04165 12.3061 5.98813 11.9949 6.00227Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-add-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-add-circle.svg
new file mode 100644
index 0000000000..331c5365e6
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-add-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_146_123" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_146_123)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM7 12C7 11.4477 7.44772 11 8 11H11V8C11 7.44772 11.4477 7 12 7C12.5523 7 13 7.44772 13 8V11H16C16.5523 11 17 11.4477 17 12C17 12.5523 16.5523 13 16 13H13V16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16V13H8C7.44772 13 7 12.5523 7 12Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-alert-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-alert-circle.svg
new file mode 100644
index 0000000000..4416d62324
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-alert-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_114_1782" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_114_1782)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16C12.5523 16 13 16.4477 13 17ZM13 13V7C13 6.44772 12.5523 6 12 6C11.4477 6 11 6.44772 11 7V13C11 13.5523 11.4477 14 12 14C12.5523 14 13 13.5523 13 13Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-checkmark-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-checkmark-circle.svg
new file mode 100644
index 0000000000..5eeaff89ae
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-checkmark-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_150_85" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_150_85)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM15.2601 8.82733C15.6316 8.41867 16.264 8.38855 16.6727 8.76006C17.0813 9.13157 17.1114 9.76402 16.7399 10.1727L11.7399 15.6727C11.3797 16.0689 10.7712 16.1111 10.3598 15.7682L7.35982 13.2682C6.93554 12.9147 6.87821 12.2841 7.23178 11.8598C7.58534 11.4355 8.21591 11.3782 8.64018 11.7318L10.9044 13.6186L15.2601 8.82733Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-checkmark.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-checkmark.svg
new file mode 100644
index 0000000000..41602b60f2
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-checkmark.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_521_2713" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_521_2713)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M19.2071 6.29289C19.5976 6.68342 19.5976 7.31658 19.2071 7.70711L10.2071 16.7071C9.83272 17.0815 9.23138 17.0992 8.83565 16.7474L4.33565 12.7474C3.92286 12.3805 3.88568 11.7484 4.2526 11.3356C4.61952 10.9229 5.25159 10.8857 5.66437 11.2526L9.45964 14.6262L17.7929 6.29289C18.1834 5.90237 18.8166 5.90237 19.2071 6.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down-circle.svg
new file mode 100644
index 0000000000..b6e8420ce6
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_125_2166" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_125_2166)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM15.2929 9.79289C15.6834 9.40237 16.3166 9.40237 16.7071 9.79289C17.0976 10.1834 17.0976 10.8166 16.7071 11.2071L12.7071 15.2071C12.3166 15.5976 11.6834 15.5976 11.2929 15.2071L7.29289 11.2071C6.90237 10.8166 6.90237 10.1834 7.29289 9.79289C7.68342 9.40237 8.31658 9.40237 8.70711 9.79289L12 13.0858L15.2929 9.79289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down.svg
new file mode 100644
index 0000000000..fffed869b0
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-down.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2708" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2708)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M16.7071 9.29289C16.3166 8.90237 15.6834 8.90237 15.2929 9.29289L12 12.5858L8.70711 9.29289C8.31658 8.90237 7.68342 8.90237 7.29289 9.29289C6.90237 9.68342 6.90237 10.3166 7.29289 10.7071L11.2929 14.7071C11.6834 15.0976 12.3166 15.0976 12.7071 14.7071L16.7071 10.7071C17.0976 10.3166 17.0976 9.68342 16.7071 9.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left-circle.svg
new file mode 100644
index 0000000000..4b8f49e5cd
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_122_2130" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_122_2130)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM12.7929 7.29289C13.1834 6.90237 13.8166 6.90237 14.2071 7.29289C14.5976 7.68342 14.5976 8.31658 14.2071 8.70711L10.9142 12L14.2071 15.2929C14.5976 15.6834 14.5976 16.3166 14.2071 16.7071C13.8166 17.0976 13.1834 17.0976 12.7929 16.7071L8.79289 12.7071C8.40237 12.3166 8.40237 11.6834 8.79289 11.2929L12.7929 7.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left.svg
new file mode 100644
index 0000000000..915b920681
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-left.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2707" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2707)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M14.7071 7.29289C14.3166 6.90237 13.6834 6.90237 13.2929 7.29289L9.29289 11.2929C8.90237 11.6834 8.90237 12.3166 9.29289 12.7071L13.2929 16.7071C13.6834 17.0976 14.3166 17.0976 14.7071 16.7071C15.0976 16.3166 15.0976 15.6834 14.7071 15.2929L11.4142 12L14.7071 8.70711C15.0976 8.31658 15.0976 7.68342 14.7071 7.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right-circle.svg
new file mode 100644
index 0000000000..4ba2e907e8
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_122_2108" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_122_2108)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM11.2071 7.29289C10.8166 6.90237 10.1834 6.90237 9.79289 7.29289C9.40237 7.68342 9.40237 8.31658 9.79289 8.70711L13.0858 12L9.79289 15.2929C9.40237 15.6834 9.40237 16.3166 9.79289 16.7071C10.1834 17.0976 10.8166 17.0976 11.2071 16.7071L15.2071 12.7071C15.5976 12.3166 15.5976 11.6834 15.2071 11.2929L11.2071 7.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right.svg
new file mode 100644
index 0000000000..61984c5155
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-right.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2706" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2706)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M9.29289 7.29289C8.90237 7.68342 8.90237 8.31658 9.29289 8.70711L12.5858 12L9.29289 15.2929C8.90237 15.6834 8.90237 16.3166 9.29289 16.7071C9.68342 17.0976 10.3166 17.0976 10.7071 16.7071L14.7071 12.7071C15.0976 12.3166 15.0976 11.6834 14.7071 11.2929L10.7071 7.29289C10.3166 6.90237 9.68342 6.90237 9.29289 7.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up-circle.svg
new file mode 100644
index 0000000000..71e948cee6
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_125_2190" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_125_2190)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM7.29289 12.7929L11.2929 8.79289C11.6834 8.40237 12.3166 8.40237 12.7071 8.79289L16.7071 12.7929C17.0976 13.1834 17.0976 13.8166 16.7071 14.2071C16.3166 14.5976 15.6834 14.5976 15.2929 14.2071L12 10.9142L8.70711 14.2071C8.31658 14.5976 7.68342 14.5976 7.29289 14.2071C6.90237 13.8166 6.90237 13.1834 7.29289 12.7929Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up.svg
new file mode 100644
index 0000000000..9525597ca7
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-chevron-up.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2709" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2709)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12.7071 9.29289C12.3166 8.90237 11.6834 8.90237 11.2929 9.29289L7.29289 13.2929C6.90237 13.6834 6.90237 14.3166 7.29289 14.7071C7.68342 15.0976 8.31658 15.0976 8.70711 14.7071L12 11.4142L15.2929 14.7071C15.6834 15.0976 16.3166 15.0976 16.7071 14.7071C17.0976 14.3166 17.0976 13.6834 16.7071 13.2929L12.7071 9.29289Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-copy.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-copy.svg
new file mode 100644
index 0000000000..dc6f6fd30c
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-copy.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2675" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2675)">
+ <path d="M15.789 2H5.684C5.23778 2.00142 4.81021 2.19342 4.49469 2.53405C4.17916 2.87468 4.00132 3.33626 4 3.81799V16.546C4.00121 16.6587 4.02423 16.7699 4.06757 16.8724C4.11091 16.9749 4.17362 17.0665 4.25168 17.1413C4.32973 17.2161 4.42141 17.2725 4.52083 17.3068C4.62025 17.3411 4.72522 17.3526 4.829 17.3406C5.03911 17.3536 5.24569 17.278 5.40519 17.1298C5.56469 16.9816 5.66465 16.7723 5.684 16.546V3.81799H15.789C16.0033 3.80121 16.205 3.7022 16.3576 3.53885C16.5102 3.37549 16.6037 3.15859 16.621 2.92735C16.6095 2.69036 16.5189 2.46588 16.3659 2.29542C16.213 2.12495 16.008 2.02001 15.789 2ZM18.315 5.63597H9.053C8.60643 5.63711 8.17846 5.82913 7.86269 6.17002C7.54692 6.51092 7.36906 6.97294 7.368 7.45504V20.182C7.36932 20.6637 7.54716 21.1253 7.86269 21.466C8.17822 21.8066 8.60578 21.9986 9.052 22H18.315C18.7614 21.9989 19.1892 21.807 19.505 21.4663C19.8207 21.1257 19.9987 20.6639 20 20.182V7.45504C19.9989 6.97313 19.8212 6.51127 19.5057 6.1704C19.1901 5.82954 18.7614 5.6374 18.315 5.63597ZM18.315 20.182H9.053V7.45504H18.316L18.315 20.182Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-cross-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-cross-circle.svg
new file mode 100644
index 0000000000..37698f5690
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-cross-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+ <mask id="mask0_146_119" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="48" height="48">
+ <path d="M48 0H0V48H48V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_146_119)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M44 24C44 35.0457 35.0457 44 24 44C12.9543 44 4 35.0457 4 24C4 12.9543 12.9543 4 24 4C35.0457 4 44 12.9543 44 24ZM16.5858 16.5858C17.3668 15.8047 18.6332 15.8047 19.4142 16.5858L24 21.1716L28.5858 16.5858C29.3668 15.8047 30.6332 15.8047 31.4142 16.5858C32.1953 17.3668 32.1953 18.6332 31.4142 19.4142L26.8284 24L31.4142 28.5858C32.1953 29.3668 32.1953 30.6332 31.4142 31.4142C30.6332 32.1953 29.3668 32.1953 28.5858 31.4142L24 26.8284L19.4142 31.4142C18.6332 32.1953 17.3668 32.1953 16.5858 31.4142C15.8047 30.6332 15.8047 29.3668 16.5858 28.5858L21.1716 24L16.5858 19.4142C15.8047 18.6332 15.8047 17.3668 16.5858 16.5858Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-cross.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-cross.svg
new file mode 100644
index 0000000000..08896ce5c0
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-cross.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+ <mask id="mask0_585_7935" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="48" height="48">
+ <rect width="48" height="48" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_585_7935)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M15.4142 12.5858C14.6332 11.8047 13.3668 11.8047 12.5858 12.5858C11.8047 13.3668 11.8047 14.6332 12.5858 15.4142L21.1716 24L12.5858 32.5858C11.8047 33.3668 11.8047 34.6332 12.5858 35.4142C13.3668 36.1953 14.6332 36.1953 15.4142 35.4142L24 26.8284L32.5858 35.4142C33.3668 36.1953 34.6332 36.1953 35.4142 35.4142C36.1953 34.6332 36.1953 33.3668 35.4142 32.5858L26.8284 24L35.4142 15.4142C36.1953 14.6332 36.1953 13.3668 35.4142 12.5858C34.6332 11.8047 33.3668 11.8047 32.5858 12.5858L24 21.1716L15.4142 12.5858Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-edit-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-edit-circle.svg
new file mode 100644
index 0000000000..b153761bbd
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-edit-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_151_181" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_151_181)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM7.86583 16.1343C7.95754 16.226 8.07119 16.2719 8.20676 16.2719H9.12405C9.25315 16.2719 9.37621 16.2471 9.49322 16.1976C9.61022 16.148 9.71216 16.0798 9.79904 15.9929L15.0035 10.7927L13.2109 9L8.00721 14.2011C7.92033 14.288 7.85212 14.3899 7.80258 14.5069C7.75303 14.6239 7.72825 14.747 7.72825 14.8761V15.7934C7.72825 15.929 7.77411 16.0426 7.86583 16.1343ZM14.7112 7.50003C14.7912 7.42732 14.8796 7.37113 14.9763 7.33147C15.0731 7.2918 15.1745 7.27197 15.2807 7.27197C15.3868 7.27197 15.4896 7.29081 15.5891 7.32849C15.6886 7.36616 15.7767 7.42605 15.8534 7.50817L16.4999 8.1628C16.5821 8.2395 16.6406 8.32775 16.6755 8.42756C16.7105 8.52737 16.728 8.62717 16.728 8.72697C16.728 8.83343 16.7098 8.93502 16.6734 9.03176C16.6371 9.1285 16.5793 9.2169 16.4999 9.29695L15.7902 10.01L14.0002 8.21002L14.7112 7.50003Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-external.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-external.svg
new file mode 100644
index 0000000000..8399c901bd
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-external.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_1744_3687" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_1744_3687)">
+ <path d="M16 20H6C5.73478 20 5.48043 19.8947 5.29289 19.7071C5.10536 19.5196 5 19.2652 5 19V9.00001C5 8.73479 5.10536 8.48044 5.29289 8.2929C5.48043 8.10537 5.73478 8.00001 6 8.00001H13.465L11.465 10H7V18H15V13.536L17 11.536V19C17 19.2652 16.8946 19.5196 16.7071 19.7071C16.5196 19.8947 16.2652 20 16 20ZM11 15C10.802 15.0002 10.6085 14.9416 10.4439 14.8316C10.2792 14.7217 10.151 14.5654 10.0752 14.3825C9.99953 14.1996 9.97981 13.9983 10.0186 13.8042C10.0573 13.6101 10.1528 13.4318 10.293 13.292L17.586 6.00001H13.991C13.7258 5.99882 13.4719 5.89232 13.2852 5.70393C13.0985 5.51555 12.9943 5.26073 12.9955 4.99551C12.9967 4.73029 13.1032 4.47641 13.2916 4.28972C13.48 4.10303 13.7348 3.99882 14 4.00001H20C20.2652 4.00001 20.5196 4.10537 20.7071 4.2929C20.8946 4.48044 21 4.73479 21 5.00001V11C21.0008 11.2652 20.8962 11.5199 20.7092 11.708C20.5223 11.8961 20.2682 12.0022 20.003 12.003C19.7378 12.0038 19.4831 11.8992 19.295 11.7122C19.1069 11.5253 19.0008 11.2712 19 11.006V7.41501L11.707 14.707C11.6144 14.8002 11.5042 14.8741 11.3829 14.9244C11.2615 14.9747 11.1314 15.0004 11 15Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-filter-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-filter-circle.svg
new file mode 100644
index 0000000000..abeda4f184
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-filter-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_521_2715" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_521_2715)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM7 8.5C6.44772 8.5 6 8.94772 6 9.5C6 10.0523 6.44772 10.5 7 10.5H17C17.5523 10.5 18 10.0523 18 9.5C18 8.94772 17.5523 8.5 17 8.5H7ZM9 12C8.44772 12 8 12.4477 8 13C8 13.5523 8.44772 14 9 14H15C15.5523 14 16 13.5523 16 13C16 12.4477 15.5523 12 15 12H9ZM11 15.5C10.4477 15.5 10 15.9477 10 16.5C10 17.0523 10.4477 17.5 11 17.5H13C13.5523 17.5 14 17.0523 14 16.5C14 15.9477 13.5523 15.5 13 15.5H11Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-grabber.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-grabber.svg
new file mode 100644
index 0000000000..f8792121c1
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-grabber.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_1903_1526" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_1903_1526)">
+ <path d="M4.32165 16.2682C4.09707 16.2682 3.90261 16.1833 3.73828 16.0135C3.57943 15.8437 3.5 15.6438 3.5 15.4137C3.5 15.1891 3.57943 14.9947 3.73828 14.8304C3.89713 14.666 4.09159 14.5839 4.32165 14.5839H19.6783C19.9029 14.5839 20.0947 14.666 20.2535 14.8304C20.4178 14.9947 20.5 15.1891 20.5 15.4137C20.5 15.6438 20.4178 15.8437 20.2535 16.0135C20.0947 16.1833 19.9029 16.2682 19.6783 16.2682H4.32165ZM4.32165 12.464C4.09707 12.464 3.90261 12.3818 3.73828 12.2175C3.57943 12.0477 3.5 11.8505 3.5 11.6259C3.5 11.3958 3.57943 11.1986 3.73828 11.0343C3.89713 10.8645 4.09159 10.7796 4.32165 10.7796H19.6783C19.9029 10.7796 20.0947 10.8645 20.2535 11.0343C20.4178 11.1986 20.5 11.3958 20.5 11.6259C20.5 11.8505 20.4178 12.0477 20.2535 12.2175C20.0947 12.3818 19.9029 12.464 19.6783 12.464H4.32165ZM4.32165 8.67617C4.09707 8.67617 3.90261 8.59401 3.73828 8.42968C3.57943 8.25987 3.5 8.06267 3.5 7.83809C3.5 7.60802 3.57943 7.41083 3.73828 7.2465C3.89713 7.08217 4.09159 7 4.32165 7H19.6783C19.9029 7 20.0947 7.08217 20.2535 7.2465C20.4178 7.41083 20.5 7.60802 20.5 7.83809C20.5 8.06267 20.4178 8.25987 20.2535 8.42968C20.0947 8.59401 19.9029 8.67617 19.6783 8.67617H4.32165Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-hide.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-hide.svg
new file mode 100644
index 0000000000..4b429fa965
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-hide.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2677" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2677)">
+ <path d="M12 6.98676C13.6716 6.98116 15.3108 7.45108 16.7292 8.34251C18.1476 9.23393 19.2876 10.5107 20.0182 12.0259C19.4909 13.1206 18.745 14.0938 17.8273 14.8845L19.1091 16.1764C20.3856 15.0435 21.3765 13.6208 22 12.0259C20.9982 9.4607 19.0645 7.37638 16.5922 6.1969C14.1198 5.01743 11.2945 4.83137 8.69091 5.67658L10.1909 7.18833C10.7858 7.06097 11.3918 6.99345 12 6.98676ZM11.0273 8.03124L12.9091 9.92781C13.4287 10.1585 13.8438 10.5769 14.0727 11.1006L15.9545 12.9971C16.0343 12.6764 16.0771 12.3474 16.0818 12.0168C16.0827 11.4763 15.9776 10.941 15.7728 10.4415C15.568 9.942 15.2673 9.48816 14.8882 9.10599C14.509 8.72382 14.0586 8.42084 13.563 8.2144C13.0674 8.00796 12.5363 7.90213 12 7.90297C11.6717 7.90384 11.3448 7.94695 11.0273 8.03124ZM2.91818 5.03523L5.35455 7.49068C3.85484 8.67366 2.69659 10.2396 2 12.0259C2.78976 14.0507 4.16597 15.7889 5.94951 17.0145C7.73305 18.2401 9.84134 18.8962 12 18.8975C13.3444 18.8988 14.6769 18.6439 15.9273 18.1462L19.0364 21.2797C19.2103 21.4298 19.434 21.5082 19.6628 21.4993C19.8916 21.4904 20.1086 21.3948 20.2705 21.2316C20.4324 21.0685 20.5273 20.8497 20.5361 20.6191C20.5449 20.3886 20.4671 20.1631 20.3182 19.9878C20 19.6369 4.53727 4.03381 4.2 3.7342C4.02018 3.58289 3.79335 3.5 3.55909 3.5C3.32483 3.5 3.098 3.58289 2.91818 3.7342C2.75557 3.91119 2.66524 4.14351 2.66524 4.38472C2.66524 4.62592 2.75557 4.85824 2.91818 5.03523ZM9.73636 11.9068L12.1091 14.2981C12.0736 14.3087 12.037 14.3149 12 14.3165C11.3972 14.3165 10.8192 14.0751 10.3929 13.6456C9.96672 13.216 9.72727 12.6334 9.72727 12.0259C9.72727 11.9801 9.73636 11.9526 9.73636 11.9068ZM6.64545 8.7917L8.23636 10.3951C8.02082 10.9114 7.90957 11.4658 7.90909 12.0259C7.90982 12.7078 8.07814 13.3788 8.39902 13.9791C8.7199 14.5794 9.18333 15.0902 9.74791 15.4659C10.3125 15.8416 10.9606 16.0705 11.6344 16.1321C12.3082 16.1938 12.9866 16.0862 13.6091 15.8191L14.5 16.7169C13.6858 16.9447 12.845 17.0618 12 17.0651C10.3284 17.0707 8.68921 16.6008 7.2708 15.7094C5.85239 14.8179 4.71238 13.5412 3.98182 12.0259C4.60619 10.7525 5.51856 9.64472 6.64545 8.7917Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-info-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-info-circle.svg
new file mode 100644
index 0000000000..242a66186f
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-info-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_116_1925" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_116_1925)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM13 7C13 7.55228 12.5523 8 12 8C11.4477 8 11 7.55228 11 7C11 6.44772 11.4477 6 12 6C12.5523 6 13 6.44772 13 7ZM13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V11C11 10.4477 11.4477 10 12 10C12.5523 10 13 10.4477 13 11V17Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal-circle.svg
new file mode 100644
index 0000000000..4bf927854e
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_522_2738" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_522_2738)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM12 13.5C12.8284 13.5 13.5 12.8284 13.5 12C13.5 11.1716 12.8284 10.5 12 10.5C11.1716 10.5 10.5 11.1716 10.5 12C10.5 12.8284 11.1716 13.5 12 13.5ZM8.5 12C8.5 12.8284 7.82843 13.5 7 13.5C6.17157 13.5 5.5 12.8284 5.5 12C5.5 11.1716 6.17157 10.5 7 10.5C7.82843 10.5 8.5 11.1716 8.5 12ZM17 13.5C17.8284 13.5 18.5 12.8284 18.5 12C18.5 11.1716 17.8284 10.5 17 10.5C16.1716 10.5 15.5 11.1716 15.5 12C15.5 12.8284 16.1716 13.5 17 13.5Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal.svg
new file mode 100644
index 0000000000..da5e0fc81c
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-more-horizontal.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_1578_8073" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_1578_8073)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 12C8 13.1046 7.10457 14 6 14C4.89543 14 4 13.1046 4 12C4 10.8954 4.89543 10 6 10C7.10457 10 8 10.8954 8 12ZM14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12ZM18 14C19.1046 14 20 13.1046 20 12C20 10.8954 19.1046 10 18 10C16.8954 10 16 10.8954 16 12C16 13.1046 16.8954 14 18 14Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical-circle.svg
new file mode 100644
index 0000000000..3703c2823d
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_1744_3796" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_1744_3796)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM12 13.5C12.8284 13.5 13.5 12.8284 13.5 12C13.5 11.1716 12.8284 10.5 12 10.5C11.1716 10.5 10.5 11.1716 10.5 12C10.5 12.8284 11.1716 13.5 12 13.5ZM13.5 7C13.5 7.82843 12.8284 8.5 12 8.5C11.1716 8.5 10.5 7.82843 10.5 7C10.5 6.17157 11.1716 5.5 12 5.5C12.8284 5.5 13.5 6.17157 13.5 7ZM12 18.5C12.8284 18.5 13.5 17.8284 13.5 17C13.5 16.1716 12.8284 15.5 12 15.5C11.1716 15.5 10.5 16.1716 10.5 17C10.5 17.8284 11.1716 18.5 12 18.5Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical.svg
new file mode 100644
index 0000000000..89526553a2
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-more-vertical.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_522_2719" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_522_2719)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M14 6C14 7.10457 13.1046 8 12 8C10.8954 8 10 7.10457 10 6C10 4.89543 10.8954 4 12 4C13.1046 4 14 4.89543 14 6ZM14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12ZM12 20C13.1046 20 14 19.1046 14 18C14 16.8954 13.1046 16 12 16C10.8954 16 10 16.8954 10 18C10 19.1046 10.8954 20 12 20Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-reconnect.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-reconnect.svg
new file mode 100644
index 0000000000..cc203ec2c5
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-reconnect.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_605_13351" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_605_13351)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M6 12C6 8.68629 8.68629 6 12 6C13.7762 6 15.3729 6.77144 16.4724 8H15C14.4477 8 14 8.44772 14 9C14 9.55228 14.4477 10 15 10H19C19.5523 10 20 9.55228 20 9V5C20 4.44772 19.5523 4 19 4C18.4477 4 18 4.44772 18 5V6.70853C16.535 5.04867 14.3903 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C14.13 20 16.0674 19.1663 17.5001 17.8094C17.9011 17.4296 17.9183 16.7967 17.5386 16.3957C17.1588 15.9947 16.5259 15.9775 16.1249 16.3572C15.0487 17.3764 13.5983 18 12 18C8.68629 18 6 15.3137 6 12Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-remove-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-remove-circle.svg
new file mode 100644
index 0000000000..cfeeca72f4
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-remove-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_150_69" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <path d="M24 0H0V24H24V0Z" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_150_69)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM8 11C7.44772 11 7 11.4477 7 12C7 12.5523 7.44772 13 8 13H12H16C16.5523 13 17 12.5523 17 12C17 11.4477 16.5523 11 16 11H12H8Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-search-circle.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-search-circle.svg
new file mode 100644
index 0000000000..4f99c8d33b
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-search-circle.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_1747_3962" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_1747_3962)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM13.7574 15.1716C12.967 15.6951 12.0191 16 11 16C8.23858 16 6 13.7614 6 11C6 8.23858 8.23858 6 11 6C13.7614 6 16 8.23858 16 11C16 12.0191 15.6951 12.967 15.1716 13.7574L17.7071 16.2929C18.0976 16.6834 18.0976 17.3166 17.7071 17.7071C17.3166 18.0976 16.6834 18.0976 16.2929 17.7071L13.7574 15.1716ZM8 11C8 9.34315 9.34315 8 11 8C12.6569 8 14 9.34315 14 11C14 12.6569 12.6569 14 11 14C9.34315 14 8 12.6569 8 11Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-search.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-search.svg
new file mode 100644
index 0000000000..211a98a03e
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-search.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2680" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2680)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M7 10C7 7.79086 8.79086 6 11 6C13.2091 6 15 7.79086 15 10C15 11.2998 14.38 12.4548 13.4196 13.1855C13.4066 13.1947 13.3938 13.2044 13.3812 13.2143C12.7159 13.708 11.8921 14 11 14C8.79086 14 7 12.2091 7 10ZM13.861 15.2752C13.0106 15.7374 12.036 16 11 16C7.68629 16 5 13.3137 5 10C5 6.68629 7.68629 4 11 4C14.3137 4 17 6.68629 17 10C17 11.5515 16.4111 12.9654 15.4447 14.0305L19.7071 18.2929C20.0976 18.6834 20.0976 19.3166 19.7071 19.7071C19.3166 20.0976 18.6834 20.0976 18.2929 19.7071L13.861 15.2752Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-settings-filled.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-settings-filled.svg
new file mode 100644
index 0000000000..289bc9e4a0
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-settings-filled.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2674" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2674)">
+ <path d="M14.0574 22H9.94487C9.82552 22.0017 9.7095 21.9606 9.6178 21.8842C9.52609 21.8078 9.46476 21.7011 9.44487 21.5834L9.05404 18.9326C8.43311 18.683 7.84779 18.3526 7.31321 17.95L4.75321 18.9501C4.69568 18.9705 4.63508 18.9809 4.57404 18.9809C4.48399 18.9826 4.3951 18.9603 4.31647 18.9164C4.23784 18.8725 4.1723 18.8085 4.12654 18.7309L2.07071 15.27C2.0102 15.1665 1.98944 15.0444 2.01228 14.9267C2.03513 14.8089 2.10003 14.7035 2.19487 14.63L4.36154 12.98C4.31687 12.6552 4.29321 12.3279 4.29071 12C4.29343 11.6725 4.31737 11.3454 4.36237 11.0209L2.19571 9.37088C2.0985 9.29903 2.0318 9.19332 2.00881 9.07465C1.98582 8.95598 2.0082 8.833 2.07154 8.73005L4.12654 5.27005C4.17041 5.19235 4.23426 5.12781 4.31149 5.08312C4.38871 5.03842 4.47649 5.01521 4.56571 5.01588C4.62982 5.01602 4.69336 5.02788 4.75321 5.05088L7.31321 6.05088C7.84873 5.65203 8.43252 5.32247 9.05071 5.07005L9.44154 2.41672C9.46142 2.29901 9.52276 2.19231 9.61446 2.11589C9.70617 2.03947 9.82218 1.99838 9.94154 2.00005H14.0574C14.1767 1.99838 14.2927 2.03947 14.3845 2.11589C14.4762 2.19231 14.5375 2.29901 14.5574 2.41672L14.9482 5.06672C15.5691 5.31679 16.1544 5.6474 16.689 6.05005L19.249 5.05005C19.3066 5.02962 19.3672 5.0192 19.4282 5.01922C19.5183 5.01751 19.6071 5.03975 19.6858 5.08368C19.7644 5.12761 19.83 5.19164 19.8757 5.26922L21.9324 8.73005C21.9919 8.83402 22.0121 8.95591 21.9893 9.07352C21.9665 9.19114 21.9022 9.29666 21.8082 9.37088L19.6415 11.0209C19.6857 11.3454 19.7091 11.6725 19.7115 12C19.7086 12.3279 19.6847 12.6552 19.6399 12.98L21.8065 14.63C21.9014 14.7035 21.9663 14.8089 21.9891 14.9267C22.012 15.0444 21.9912 15.1665 21.9307 15.27L19.874 18.7309C19.8301 18.8087 19.7661 18.8733 19.6887 18.918C19.6114 18.9627 19.5234 18.9859 19.434 18.9851C19.3699 18.985 19.3064 18.9731 19.2465 18.9501L16.6865 17.95C16.1512 18.3487 15.5673 18.6777 14.949 18.9292L14.5607 21.5834C14.5407 21.7017 14.4789 21.8088 14.3865 21.8853C14.2941 21.9618 14.1773 22.0025 14.0574 22ZM11.999 7.83338C11.175 7.83338 10.3694 8.07775 9.68416 8.53559C8.99896 8.99343 8.46491 9.64418 8.14954 10.4055C7.83418 11.1669 7.75166 12.0047 7.91244 12.8129C8.07321 13.6212 8.47004 14.3636 9.05276 14.9463C9.63548 15.529 10.3779 15.9259 11.1862 16.0867C11.9944 16.2474 12.8322 16.1649 13.5936 15.8495C14.3549 15.5342 15.0057 15.0001 15.4635 14.3149C15.9213 13.6297 16.1657 12.8241 16.1657 12C16.1646 10.8953 15.7253 9.83615 14.9441 9.05499C14.1629 8.27383 13.1038 7.83449 11.999 7.83338Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/icons/icon-show.svg b/desktop/packages/mullvad-vpn/assets/icons/icon-show.svg
new file mode 100644
index 0000000000..a4b2aa591d
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/assets/icons/icon-show.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
+ <mask id="mask0_519_2676" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
+ <rect width="24" height="24" fill="#D9D9D9"/>
+ </mask>
+ <g mask="url(#mask0_519_2676)">
+ <path d="M12 7.2334C13.6716 7.2281 15.3108 7.67263 16.7292 8.51588C18.1476 9.35913 19.2876 10.5669 20.0182 12.0003C19.2832 13.4303 18.1421 14.6351 16.7247 15.4778C15.3073 16.3204 13.6704 16.7671 12 16.7671C10.3296 16.7671 8.69269 16.3204 7.27529 15.4778C5.85789 14.6351 4.71684 13.4303 3.98182 12.0003C4.71238 10.5669 5.85239 9.35913 7.2708 8.51588C8.68921 7.67263 10.3284 7.2281 12 7.2334ZM12 5.5C9.84134 5.50123 7.73305 6.1219 5.94951 7.28125C4.16597 8.4406 2.78976 10.0849 2 12.0003C2.78879 13.9162 4.16477 15.5611 5.94855 16.7205C7.73232 17.8799 9.84112 18.5 12 18.5C14.1589 18.5 16.2677 17.8799 18.0515 16.7205C19.8352 15.5611 21.2112 13.9162 22 12.0003C21.2102 10.0849 19.834 8.4406 18.0505 7.28125C16.2669 6.1219 14.1587 5.50123 12 5.5ZM12 9.8335C12.4495 9.8335 12.8889 9.96058 13.2627 10.1987C13.6364 10.4367 13.9277 10.7751 14.0997 11.1711C14.2717 11.567 14.3168 12.0027 14.2291 12.423C14.1414 12.8433 13.9249 13.2294 13.6071 13.5324C13.2892 13.8354 12.8843 14.0418 12.4434 14.1254C12.0025 14.209 11.5456 14.1661 11.1303 14.0021C10.715 13.8381 10.36 13.5604 10.1103 13.204C9.86057 12.8477 9.72727 12.4288 9.72727 12.0003C9.72727 11.4256 9.96672 10.8745 10.3929 10.4681C10.8192 10.0618 11.3972 9.8335 12 9.8335ZM12 8.1001C11.1909 8.1001 10.4 8.32884 9.72721 8.75739C9.05447 9.18595 8.53012 9.79507 8.22049 10.5077C7.91086 11.2204 7.82985 12.0046 7.9877 12.7611C8.14555 13.5177 8.53517 14.2126 9.10729 14.7581C9.67942 15.3035 10.4083 15.675 11.2019 15.8255C11.9955 15.976 12.818 15.8987 13.5655 15.6035C14.313 15.3083 14.952 14.8084 15.4015 14.1671C15.851 13.5257 16.0909 12.7716 16.0909 12.0003C16.0892 10.9664 15.6577 9.97527 14.8909 9.2442C14.124 8.51313 13.0845 8.10171 12 8.1001Z" fill="white"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/app-header-backdrop.svg b/desktop/packages/mullvad-vpn/assets/images/app-header-backdrop.svg
deleted file mode 100644
index 4c811518bf..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/app-header-backdrop.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>app-triangle-extended</title>
- <desc>Mullvad VPN app</desc>
- <rect x="0" y="12" width="100%" height="100%" rx="8" ry="8" />
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/app-triangle.svg b/desktop/packages/mullvad-vpn/assets/images/app-triangle.svg
deleted file mode 100644
index e2f7ca044b..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/app-triangle.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="30px" height="13px" viewBox="0 0 30 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>app-triangle-extended</title>
- <desc>Mullvad VPN app</desc>
- <path fill="#294D73" d="M0,12 L30,12 L30,13 L0,13 L0,12 Z M0,12 C7.24137931,12 12.9310345,1.0135008e-16 15,0 C17.0689655,0 23.7931034,12 30,12 L0,12 Z" id="app-triangle-extended"></path>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-account.svg b/desktop/packages/mullvad-vpn/assets/images/icon-account.svg
deleted file mode 100644
index 0c6b3faaf1..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-account.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 24A12 12 0 0 1 3.515 3.515a12 12 0 1 1 16.97 16.97A11.922 11.922 0 0 1 12 24zm0-11.825a12.164 12.164 0 0 0-2.873.348 17.625 17.625 0 0 0-2.99 1.048A2.85 2.85 0 0 0 5 14.525a2.573 2.573 0 0 0-.442 1.512v.791a1.39 1.39 0 0 0 1.4 1.4h12.1a1.392 1.392 0 0 0 1.4-1.4v-.791A2.567 2.567 0 0 0 19 14.525a2.809 2.809 0 0 0-1.163-.954 19.906 19.906 0 0 0-2.978-1.036 11.634 11.634 0 0 0-2.859-.36zm0-8.4a3.345 3.345 0 0 0-3.49 3.491 3.346 3.346 0 0 0 3.49 3.49 3.348 3.348 0 0 0 3.49-3.49A3.346 3.346 0 0 0 12 3.776z" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-add.svg b/desktop/packages/mullvad-vpn/assets/images/icon-add.svg
deleted file mode 100644
index 331bf4d273..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-add.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-close</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" style="transform-origin: center; transform: rotate(45deg);">
- <path d="M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z M13.5,12 L17.2947612,8.20523878 C17.6857559,7.81424414 17.6838785,7.18387854 17.293923,6.79392296 L17.206077,6.70607704 C16.8181114,6.31811142 16.1842538,6.31574616 15.7947612,6.70523878 L12,10.5 L8.20523878,6.70523878 C7.81574616,6.31574616 7.18188858,6.31811142 6.79392296,6.70607704 L6.70607704,6.79392296 C6.31612146,7.18387854 6.31424414,7.81424414 6.70523878,8.20523878 L10.5,12 L6.70523878,15.7947612 C6.31424414,16.1857559 6.31612146,16.8161215 6.70607704,17.206077 L6.79392296,17.293923 C7.18188858,17.6818886 7.81574616,17.6842538 8.20523878,17.2947612 L12,13.5 L15.7947612,17.2947612 C16.1842538,17.6842538 16.8181114,17.6818886 17.206077,17.293923 L17.293923,17.206077 C17.6838785,16.8161215 17.6857559,16.1857559 17.2947612,15.7947612 L13.5,12 L13.5,12 Z" id="path" fill="#FFFFFF"></path>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-alert.svg b/desktop/packages/mullvad-vpn/assets/images/icon-alert.svg
deleted file mode 100644
index c11507a4a5..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-alert.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>alert</title>
- <path d="m12 24c-6.627417 0-12-5.372583-12-12s5.372583-12 12-12 12 5.372583 12 12-5.372583 12-12 12zm0-19.5c-.8284271 0-1.5.67157288-1.5 1.5v7.5c0 .8284271.6715729 1.5 1.5 1.5s1.5-.6715729 1.5-1.5v-7.5c0-.82842712-.6715729-1.5-1.5-1.5zm0 12c-.8284271 0-1.5.6715729-1.5 1.5s.6715729 1.5 1.5 1.5 1.5-.6715729 1.5-1.5-.6715729-1.5-1.5-1.5z" fill="currentColor" />
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-arrow.svg b/desktop/packages/mullvad-vpn/assets/images/icon-arrow.svg
deleted file mode 100755
index 96f1356fbe..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-arrow.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="24px" height="16px" viewBox="0 0 24 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-arrow</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <path fill="#FFFFFF" d="M18.7015867,9 L14.4331381,12.762659 C13.851665,13.2752305 13.8579999,14.1003943 14.4392669,14.612784 C15.0245863,15.1287461 15.9602099,15.1275926 16.5380921,14.6181865 L23.5668627,8.42228969 C23.8565791,8.16690324 24.000373,7.83391619 23.999837,7.50067932 L24,7.4966702 C23.999589,7.16348359 23.8547954,6.83138119 23.5668627,6.57756713 L16.5380921,0.381670278 C15.956619,-0.130901228 15.0205338,-0.125317014 14.4392669,0.387072772 C13.8539474,0.903034846 13.8552559,1.72779176 14.4331381,2.23719784 L18.7017491,6 L1.50909424,6 C0.66354084,6 0,6.67157288 0,7.5 C0,8.33420277 0.675644504,9 1.50909424,9 L18.7015867,9 Z" id="icon-arrow"></path>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-back.svg b/desktop/packages/mullvad-vpn/assets/images/icon-back.svg
deleted file mode 100644
index fabf78530d..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-back.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-back</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <path d="M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z M7.00548958,11.9978652 C6.97547323,12.2732292 7.06852694,12.5603856 7.28524783,12.7773547 L13.2129013,18.7117979 C13.5936146,19.0929473 14.2231287,19.090784 14.6233317,18.7027276 L14.6942341,18.6339771 C15.09248,18.2478183 15.1055305,17.6195657 14.7108992,17.2180331 L9.58045095,11.9978652 L14.7108992,6.77769718 C15.1055305,6.37616462 15.09248,5.74791199 14.6942341,5.36175323 L14.6233317,5.29300272 C14.2231287,4.90494629 13.5936146,4.90278303 13.2129013,5.28393238 L7.28524783,11.2183756 C7.06852694,11.4353448 6.97547323,11.7225011 7.00548958,11.9978652 L7.00548958,11.9978652 Z" id="path" fill="#FFFFFF"></path>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-check.svg b/desktop/packages/mullvad-vpn/assets/images/icon-check.svg
deleted file mode 100644
index 2289a19807..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-check.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg data-name="Icons/Check" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 24A12 12 0 0 1 3.515 3.515a12 12 0 1 1 16.97 16.97A11.922 11.922 0 0 1 12 24zM5.345 10.9a1.108 1.108 0 0 0-.785.322 1.095 1.095 0 0 0 0 1.556L9 17.177a1.115 1.115 0 0 0 1.569 0l8.874-8.8a1.095 1.095 0 0 0 0-1.556 1.116 1.116 0 0 0-1.569 0l-8.092 8.024-3.653-3.623a1.106 1.106 0 0 0-.784-.322z" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-checkmark.svg b/desktop/packages/mullvad-vpn/assets/images/icon-checkmark.svg
deleted file mode 100644
index 67773298f8..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-checkmark.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">
- <path d="M2.683 6.69a1.581 1.581 0 0 0-2.222 0 1.549 1.549 0 0 0 0 2.2l6.286 6.233a1.581 1.581 0 0 0 2.222 0L21.54 2.66a1.549 1.549 0 0 0 0-2.2 1.581 1.581 0 0 0-2.222 0L7.857 11.821z" transform="translate(0 3.208)" style="fill:#44ad4d"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-chevron-down.svg b/desktop/packages/mullvad-vpn/assets/images/icon-chevron-down.svg
deleted file mode 100644
index e1e7af1104..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-chevron-down.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-cheveron-down</title>
- <path d="M11.9497475,15.9497475 C11.6938252,15.9497475 11.4379028,15.8521164 11.2426407,15.6568542 L6.29289322,10.7071068 C5.90236893,10.3165825 5.90236893,9.68341751 6.29289322,9.29289322 C6.68341751,8.90236893 7.31658249,8.90236893 7.70710678,9.29289322 L11.9497475,13.5355339 L16.1923882,9.29289322 C16.5829124,8.90236893 17.2160774,8.90236893 17.6066017,9.29289322 C17.997126,9.68341751 17.997126,10.3165825 17.6066017,10.7071068 L12.6568542,15.6568542 C12.4615921,15.8521164 12.2056698,15.9497475 11.9497475,15.9497475 Z" fill="currentColor"/>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-chevron-up.svg b/desktop/packages/mullvad-vpn/assets/images/icon-chevron-up.svg
deleted file mode 100644
index 84d8b56350..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-chevron-up.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-cheveron-up</title>
- <path d="M11.9497475,9 C12.2056698,9 12.4615921,9.09763107 12.6568542,9.29289322 L17.6066017,14.2426407 C17.997126,14.633165 17.997126,15.26633 17.6066017,15.6568542 C17.2160774,16.0473785 16.5829124,16.0473785 16.1923882,15.6568542 L11.9497475,11.4142136 L7.70710678,15.6568542 C7.31658249,16.0473785 6.68341751,16.0473785 6.29289322,15.6568542 C5.90236893,15.26633 5.90236893,14.633165 6.29289322,14.2426407 L11.2426407,9.29289322 C11.4379028,9.09763107 11.6938252,9 11.9497475,9 Z" fill="currentColor"/>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-chevron.svg b/desktop/packages/mullvad-vpn/assets/images/icon-chevron.svg
deleted file mode 100644
index 923532cd28..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-chevron.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="7px" height="12px" viewBox="0 0 7 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-cheveron</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <path d="M0.335204989,1.95371785 L4.23669259,6 L0.335204989,10.0462822 C-0.111734996,10.4932221 -0.111734996,11.217855 0.335204989,11.664795 C0.782144974,12.111735 1.49826561,12.111735 1.9452056,11.664795 L6.66818642,6.80553188 C6.88657769,6.58714061 6.99779844,6.29559541 6.99881099,6.00303766 C6.99779844,5.70440459 6.88657769,5.41285939 6.66818642,5.19446812 L1.9452056,0.335204989 C1.49826561,-0.111734996 0.782144974,-0.111734996 0.335204989,0.335204989 C-0.111734996,0.782144974 -0.111734996,1.50677786 0.335204989,1.95371785 Z" id="path" fill="currentColor" fill-rule="evenodd"></path>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-close-down.svg b/desktop/packages/mullvad-vpn/assets/images/icon-close-down.svg
deleted file mode 100644
index e81ded8acf..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-close-down.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-close-down</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <path d="M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z M7.00548958,11.9978652 C6.97547323,12.2732292 7.06852694,12.5603856 7.28524783,12.7773547 L13.2129013,18.7117979 C13.5936146,19.0929473 14.2231287,19.090784 14.6233317,18.7027276 L14.6942341,18.6339771 C15.09248,18.2478183 15.1055305,17.6195657 14.7108992,17.2180331 L9.58045095,11.9978652 L14.7108992,6.77769718 C15.1055305,6.37616462 15.09248,5.74791199 14.6942341,5.36175323 L14.6233317,5.29300272 C14.2231287,4.90494629 13.5936146,4.90278303 13.2129013,5.28393238 L7.28524783,11.2183756 C7.06852694,11.4353448 6.97547323,11.7225011 7.00548958,11.9978652 L7.00548958,11.9978652 Z" id="path" fill="#FFFFFF" transform="rotate(-90 12 12)"></path>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-close-sml.svg b/desktop/packages/mullvad-vpn/assets/images/icon-close-sml.svg
deleted file mode 100644
index a379068d03..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-close-sml.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="16" height="16" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icon close sml</title><desc>Created with Sketch.</desc><g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" fill-opacity="1"><g id="Views/Login-Inputted-filltered-prev-IDs" transform="translate(-268.000000, -403.000000)" fill="#294D73"><g id="Input" transform="translate(24.000000, 338.000000)"><g id="suggestions" transform="translate(0.000000, 49.000000)"><g id="1"><path d="M253,24 L255.290281,21.7097195 C255.681035,21.3189651 255.684193,20.6841926 255.294624,20.2946243 L255.705376,20.7053757 C255.316406,20.3164062 254.682248,20.3177522 254.290281,20.7097195 L252,23 L249.709719,20.7097195 C249.317752,20.3177522 248.683594,20.3164062 248.294624,20.7053757 L248.705376,20.2946243 C248.315807,20.6841926 248.318965,21.3189651 248.709719,21.7097195 L251,24 L248.709719,26.2902805 C248.318965,26.6810349 248.315807,27.3158074 248.705376,27.7053757 L248.294624,27.2946243 C248.683594,27.6835938 249.317752,27.6822478 249.709719,27.2902805 L252,25 L254.290281,27.2902805 C254.682248,27.6822478 255.316406,27.6835938 255.705376,27.2946243 L255.294624,27.7053757 C255.684193,27.3158074 255.681035,26.6810349 255.290281,26.2902805 L253,24 Z M252,32 C247.58208,32 244,28.41792 244,24 C244,19.58208 247.58208,16 252,16 C256.41792,16 260,19.58208 260,24 C260,28.41792 256.41792,32 252,32 Z" id="icon-close-sml"/></g></g></g></g></g></svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-close.svg b/desktop/packages/mullvad-vpn/assets/images/icon-close.svg
deleted file mode 100644
index 334ccb4ad4..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-close.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-close</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <path d="M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z M13.5,12 L17.2947612,8.20523878 C17.6857559,7.81424414 17.6838785,7.18387854 17.293923,6.79392296 L17.206077,6.70607704 C16.8181114,6.31811142 16.1842538,6.31574616 15.7947612,6.70523878 L12,10.5 L8.20523878,6.70523878 C7.81574616,6.31574616 7.18188858,6.31811142 6.79392296,6.70607704 L6.70607704,6.79392296 C6.31612146,7.18387854 6.31424414,7.81424414 6.70523878,8.20523878 L10.5,12 L6.70523878,15.7947612 C6.31424414,16.1857559 6.31612146,16.8161215 6.70607704,17.206077 L6.79392296,17.293923 C7.18188858,17.6818886 7.81574616,17.6842538 8.20523878,17.2947612 L12,13.5 L15.7947612,17.2947612 C16.1842538,17.6842538 16.8181114,17.6818886 17.206077,17.293923 L17.293923,17.206077 C17.6838785,16.8161215 17.6857559,16.1857559 17.2947612,15.7947612 L13.5,12 L13.5,12 Z" id="path" fill="#FFFFFF"></path>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-copy.svg b/desktop/packages/mullvad-vpn/assets/images/icon-copy.svg
deleted file mode 100644
index 6e1cf4a28d..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-copy.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg data-name="Icons/Copy" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path data-name="Path 5" d="M0 0h24v24H0z" style="fill:none"/>
- <path data-name="Path 6" d="M13.789 1H3.684A1.689 1.689 0 0 0 2 2.684v11.79a.749.749 0 0 0 .829.736.812.812 0 0 0 .855-.736V2.684h10.105a.9.9 0 0 0 .832-.825.91.91 0 0 0-.832-.859zm2.526 3.368H7.053a1.689 1.689 0 0 0-1.685 1.685v11.789a1.689 1.689 0 0 0 1.684 1.684h9.263A1.689 1.689 0 0 0 18 17.842V6.053a1.689 1.689 0 0 0-1.684-1.685zm0 13.474H7.053V6.053h9.263z" transform="translate(2 1.737)" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-cross.svg b/desktop/packages/mullvad-vpn/assets/images/icon-cross.svg
deleted file mode 100644
index 0ac8215f62..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-cross.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="m12.7 10 6.75-6.747a1.907 1.907 0 0 0-2.7-2.7L10 7.3 3.25.556a1.907 1.907 0 0 0-2.7 2.7L7.3 10 .552 16.747a1.907 1.907 0 0 0 2.7 2.7L10 12.7l6.75 6.747a1.907 1.907 0 0 0 2.7-2.7L12.7 10z" transform="translate(2 2)" style="fill:#e34039"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-edit.svg b/desktop/packages/mullvad-vpn/assets/images/icon-edit.svg
deleted file mode 100644
index 48f9f4b7ee..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-edit.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg data-name="icon - edit" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path data-name="Rectangle 18" style="fill:none" d="M0 0h24v24H0z"/>
- <path d="M12 24A12 12 0 0 1 3.515 3.515a12 12 0 1 1 16.97 16.97A11.921 11.921 0 0 1 12 24zm2.439-16.714-8.779 8.78a.525.525 0 0 0-.124.177.507.507 0 0 0-.036.2v1.525a.516.516 0 0 0 .532.532h1.525a.531.531 0 0 0 .2-.035.543.543 0 0 0 .177-.124l8.779-8.779-2.27-2.271zM16.655 5.5a.991.991 0 0 0-.727.293l-.745.745 2.271 2.27.744-.745a1.071 1.071 0 0 0 0-1.49l-.762-.762a1.057 1.057 0 0 0-.753-.31h-.027z" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-extLink.svg b/desktop/packages/mullvad-vpn/assets/images/icon-extLink.svg
deleted file mode 100644
index bed3cb37b3..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-extLink.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-extLink</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <path d="M12.5857864,2 L8.99077797,2 C8.45097518,2 8,1.55228475 8,1 C8,0.443864822 8.4463856,0 8.99703014,0 L15.0029699,0 C15.5469637,0 16,0.446385598 16,0.997030139 L16,7.00296986 C16,7.54696369 15.5522847,8 15,8 C14.4438648,8 14,7.55641359 14,7.00922203 L14,3.41421356 L6.70710678,10.7071068 C6.31658249,11.0976311 5.68341751,11.0976311 5.29289322,10.7071068 C4.90236893,10.3165825 4.90236893,9.68341751 5.29289322,9.29289322 L12.5857864,2 Z M8.46446609,4 L6.46446609,6 L2,6 L2,14 L10,14 L10,9.53553391 L12,7.53553391 L12,14.9975267 C12,15.5511774 11.544239,16 10.9975267,16 L1.00247329,16 C0.448822582,16 0,15.544239 0,14.9975267 L0,5.00247329 C0,4.44882258 0.455760956,4 1.00247329,4 L8.46446609,4 Z" id="path" fill="currentColor" fill-rule="evenodd"></path>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-fastest.svg b/desktop/packages/mullvad-vpn/assets/images/icon-fastest.svg
deleted file mode 100755
index 4c915da6d6..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-fastest.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-fastest</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <path fill="#FFFFFF" d="M21.1507481,6.83280665 C24.8128031,10.5070481 24.963038,16.3056835 21.4959142,20.1552329 C18.0287905,24.0047824 12.1077149,24.6135147 7.89218032,21.5538019 C7.56927452,21.3111241 7.40378985,20.9190527 7.4580628,20.5252773 C7.51233574,20.131502 7.77812095,19.7958465 8.15529969,19.644749 C8.53247843,19.4936516 8.96374829,19.5500675 9.28665406,19.7927454 C11.5190533,21.5357122 14.5521978,21.9470531 17.1883493,20.8643366 C19.8245009,19.7816201 21.6398874,17.3788972 21.917643,14.604963 C22.1953986,11.8310288 20.890873,9.13180475 18.5192016,7.57316921 C17.4963669,6.86336234 16.3093972,6.41068921 15.0637596,6.25537178 C13.0068849,5.98676172 10.9251308,6.53023229 9.28173528,7.76484883 C8.78601466,8.13151903 8.08013307,8.04356746 7.69509115,7.56715586 C7.31004923,7.09074425 7.38788476,6.40161565 7.87004581,6.01816824 C9.32618858,4.91172269 11.0690124,4.22078431 12.9044157,4.02230413 L12.9044157,2.72367467 L11.7017744,2.72367467 C11.3810313,2.7211743 11.0761771,2.58728319 10.861863,2.354788 C10.647549,2.12229281 10.543565,1.81266216 10.5753741,1.50171705 C10.6494879,0.921669603 11.1609089,0.489587303 11.7607997,0.500191003 L16.3672359,0.500191003 C16.6892225,0.500064398 16.9962796,0.632463774 17.2126847,0.864738483 C17.4290898,1.09701319 17.5347009,1.40754432 17.5034738,1.71975262 C17.42936,2.29980007 16.917939,2.73188237 16.3180481,2.72127867 L15.1744321,2.72127867 L15.1744321,4.01990814 C17.4372686,4.26696772 19.5456874,5.2593463 21.1507481,6.83280665 Z M18.3814758,10.6663992 C18.6486569,10.3452379 18.6236955,9.87935381 18.323645,9.58703751 C18.0235945,9.29472121 17.5453839,9.27040316 17.2157252,9.53069739 L14.3111864,11.804497 C13.4337266,11.681255 12.5738342,12.1191557 12.1768555,12.8914065 C11.7798767,13.6636572 11.9349913,14.5967747 12.561864,15.2074889 C13.1887368,15.8182032 14.1465429,15.9693195 14.9392261,15.5825734 C15.7319094,15.1958273 16.1813962,14.3580998 16.0548935,13.5032576 L18.3888539,10.6663992 L18.3814758,10.6663992 Z M8.48981192,11.3252979 C9.03312521,11.3252979 9.47356765,10.8962084 9.47356765,10.3668998 C9.47356765,9.83759109 9.03312521,9.40850163 8.48981192,9.40850163 L0.983755727,9.40850163 C0.440442441,9.40850163 5.46094129e-17,9.83759109 0,10.3668998 C-5.46094129e-17,10.8962084 0.440442441,11.3252979 0.983755727,11.3252979 L8.48981192,11.3252979 Z M8.48981192,12.822795 L2.83321649,12.822795 C2.28990321,12.822795 1.84946077,13.2518844 1.84946077,13.7811931 C1.84946077,14.3105018 2.28990321,14.7395912 2.83321649,14.7395912 L8.48981192,14.7395912 C9.03312521,14.7395912 9.47356765,14.3105018 9.47356765,13.7811931 C9.47356765,13.2518844 9.03312521,12.822795 8.48981192,12.822795 Z M9.47356765,17.1859025 C9.47356765,16.6565938 9.03312521,16.2275043 8.48981192,16.2275043 L4.36541604,16.2275043 C3.82210275,16.2275043 3.38166031,16.6565938 3.38166031,17.1859025 C3.38166031,17.7152111 3.82210275,18.1443006 4.36541604,18.1443006 L8.48981192,18.1443006 C8.75072118,18.1430328 9.00042697,18.0408412 9.18399521,17.8602073 C9.36756345,17.6795734 9.46995668,17.4352944 9.46864887,17.1811105 L9.47356765,17.1859025 Z" fill-rule="nonzero"></path>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-filter-round.svg b/desktop/packages/mullvad-vpn/assets/images/icon-filter-round.svg
deleted file mode 100644
index 9df0dd5ccc..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-filter-round.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path fill="#FFFFFF" d="M12 24A12 12 0 0 1 3.515 3.515a12 12 0 1 1 16.97 16.97A11.922 11.922 0 0 1 12 24zm-1.555-7.956V17.6h3.111v-1.556zm-3.112-3.889v1.556h9.333v-1.556zM5 8.267v1.556h14V8.267z" transform="translate(0 0)"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-filter.svg b/desktop/packages/mullvad-vpn/assets/images/icon-filter.svg
deleted file mode 100644
index da766cb06c..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-filter.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path fill="none" d="M0 0h24v24H0z"/>
- <path d="M9.222 16.667h3.556v-1.778H9.222zM3 6v1.778h16V6zm2.667 6.222h10.666v-1.778H5.667z" transform="translate(1 .667)"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-info.svg b/desktop/packages/mullvad-vpn/assets/images/icon-info.svg
deleted file mode 100644
index cb2a243e78..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-info.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg data-name="icon - info" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 24A12 12 0 0 1 3.515 3.515a12 12 0 1 1 16.97 16.97A11.922 11.922 0 0 1 12 24zm0-15a1.5 1.5 0 0 0-1.5 1.5V18a1.5 1.5 0 1 0 3 0v-7.5A1.5 1.5 0 0 0 12 9zm0-4.5A1.5 1.5 0 1 0 13.5 6 1.5 1.5 0 0 0 12 4.5z" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-language.svg b/desktop/packages/mullvad-vpn/assets/images/icon-language.svg
index 8d3c8ab1a1..2c62878774 100644
--- a/desktop/packages/mullvad-vpn/assets/images/icon-language.svg
+++ b/desktop/packages/mullvad-vpn/assets/images/icon-language.svg
@@ -1 +1,68 @@
-<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="m11.988281 3.085938-9.28125-2.828126v17.4375l9.28125-2.59375z" fill="#040606"/><path d="m11.765625 3.078125 9.640625-2.828125v17.4375l-9.640625-2.59375z" fill="#fff"/><path d="m.300781 20.75 11.464844-3.300781v-14.375l-11.464844 3.300781z" fill="#fff"/><g fill="#040606"><path d="m16.992188 20.964844 1.625 2.308594.855468-2.144532z"/><path d="m4.199219 8.03125c-.0625-.054688.078125.421875.273437.589844.347656.300781.617188.339844.761719.34375.316406.011718.710937-.066406.945313-.152344.222656-.082031.621093-.257812.769531-.511719.03125-.054687.117187-.144531.0625-.371093-.039063-.171876-.167969-.234376-.324219-.222657-.15625.007813-.628906.117188-.855469.175781-.230469.0625-.699219.183594-.90625.222657-.203125.039062-.65625-.015625-.726562-.074219"/><path d="m9.984375 13.6875c-.089844-.027344-1.960937-.695312-2.226563-.804688-.214843-.089843-.746093-.285156-.996093-.371093.703125-.9375 1.148437-1.644531 1.207031-1.753907.109375-.199218.855469-1.457031.875-1.535156.015625-.078125.035156-.367187.019531-.4375-.015625-.070312-.289062.066406-.660156.171875-.371094.109375-1.078125.507813-1.351563.554688-.273437.050781-1.148437.335937-1.597656.464843-.449218.128907-1.296875.351563-1.644531.433594-.347656.082032-.652344.085938-.847656.136719 0 0 .023437.238281.078125.308594.050781.070312.234375.246093.449218.292969.214844.046874.570313.027343.730469-.003907.164063-.03125.445313-.148437.480469-.199219.039062-.054687-.019531-.214843.046875-.265624.0625-.046876.917969-.21875 1.238281-.304688.320313-.085938 1.554688-.453125 1.722656-.433594-.054687.152344-1.046874 1.847656-1.363281 2.355469-.320312.503906-2.175781 2.730469-2.574219 3.121094-.296874.300781-1.023437 1.0625-1.277343 1.234375.0625.015625.515625-.019532.597656-.0625.507813-.269532 1.359375-1.183594 1.636719-1.464844.8125-.824219 1.527344-1.691406 2.097656-2.433594.109375.039063 1.003906.667969 1.238281.808594.230469.140625 1.152344.582031 1.351563.65625.199218.074219.964844.378906 1 .277344.03125-.105469-.140625-.714844-.230469-.746094"/><path d="m5.664062 22.09375c.179688.09375.347657.171875.539063.25.375.160156.804687.332031 1.210937.460938.558594.183593 1.117188.328124 1.671876.4375.308593.0625.648437.113281.976562.15625.03125 0 .917969.09375 1.09375.09375h.898438c.347656-.023438.675781-.042969 1.023437-.085938.28125-.035156.585937-.078125.886719-.136719.21875-.042969.449218-.085937.667968-.144531.207032-.050781.445313-.121094.675782-.191406.148437-.042969.308594-.101563.46875-.152344.128906-.050781.289062-.113281.4375-.164062.179687-.070313.386718-.164063.585937-.25.160157-.066407.339844-.152344.507813-.238282.128906-.0625.429687-.257812.585937-.257812.179688 0 .300781.136718.300781.257812 0 .246094-.390624.324219-.566406.4375-.191406.109375-.417968.195313-.617187.292969-.398438.179687-.808594.332031-1.195313.460937-.507812.164063-1.066406.320313-1.5625.421876-.191406.035156-.378906.078124-.566406.101562-.101562.019531-1.136719.15625-1.425781.15625h-1.3125c-.347657-.027344-.71875-.058594-1.066407-.101562-.308593-.042969-.636718-.097657-.945312-.15625-.238281-.042969-.496094-.101563-.726562-.164063-.398438-.09375-.785157-.214844-1.164063-.34375-.6875-.222656-1.402344-.515625-2.078125-.902344-.121094-.066406-.128906-.136719-.128906-.214843 0-.128907.109375-.246094.285156-.246094.160156 0 .480469.195312.539062.222656" fill-rule="evenodd"/><path d="m12.0625 3.039062v14.433594c-.007812.042969-.027344.085938-.070312.128906-.019532.023438-.058594.058594-.085938.066407-.25.085937-11.457031 3.335937-11.605469 3.335937-.121093 0-.2304685-.070312-.2890622-.183594 0-.007812-.0117188-.015624-.0117188-.03125v-14.441406c.0195312-.042968.03125-.101562.0703125-.136718.0820315-.09375.2187495-.113282.3085935-.136719.167969-.050781 11.207032-3.25 11.367188-3.25.097656 0 .316406.0625.316406.214843zm-.605469 14.21875-10.847656 3.117188v-13.8125l10.847656-3.117188z" fill-rule="evenodd"/><path d="m21.707031.273438v17.378906c-.007812.199218-.167969.285156-.316406.285156-.132813 0-1.066406-.277344-1.226563-.320312-1.253906-.335938-2.515624-.667969-3.761718-1.003907-.277344-.078125-.566406-.15625-.835938-.234375-.238281-.058594-.496094-.125-.734375-.195312-1.066406-.285156-2.152343-.566406-3.214843-.875-.042969-.011719-.140626-.128906-.140626-.15625v-12.136719c.019532-.042969.039063-.09375.089844-.128906.078125-.078125 3.492188-1.058594 4.835938-1.445313.359375-.109375 4.847656-1.441406 4.988281-1.441406.175781 0 .316406.113281.316406.273438zm-.605469 17.050781-9.027343-2.421875v-11.636719l9.027343-2.648437z" fill-rule="evenodd"/><path d="m24 20.964844-12.0625-3.316406.050781-14.441407 12.011719 3.296875z"/></g><path d="m17.207031 7.328125 1.554688.40625 2.832031 8.804687-1.597656-.417968-.570313-1.808594-3.300781-.859375-.707031 1.472656-1.597657-.417969zm.710938 2.332031-1.183594 2.46875 2.175781.570313z" fill="#fff" fill-rule="evenodd"/></svg>
+<svg width="16" height="19" viewBox="0 0 16 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g id="Language-Icon-Fireworks [Converted]">
+ <path
+ id="Fill 1"
+ d="M7.99265 2.4425L1.80328 0.203491V14.0097L7.99265 11.9575V2.4425Z"
+ fill="#000105" />
+ <path
+ id="Fill 2"
+ d="M7.84454 2.43615L14.2711 0.197144V14.0033L7.84454 11.9512V2.43615Z"
+ fill="#FFFFFE" />
+ <path
+ id="Fill 3"
+ d="M0.19812 16.4269L7.84599 13.8142V2.43384L0.19812 5.04654V16.4269Z"
+ fill="#FFFFFE" />
+ <path
+ id="Fill 4"
+ d="M11.3289 16.5986L12.4104 18.4259L12.9836 16.7285L11.3289 16.5986Z"
+ fill="#000105" />
+ <path
+ id="Fill 5"
+ d="M2.79811 6.35674C2.75794 6.31636 2.85142 6.69085 2.9812 6.82544C3.04391 6.90299 3.12097 6.96705 3.20794 7.01393C3.29492 7.06081 3.39009 7.08958 3.48797 7.09859C3.70377 7.10051 3.91787 7.05936 4.11834 6.97745C4.32665 6.90182 4.50659 6.76116 4.63283 6.57526C4.66044 6.53201 4.67855 6.48313 4.68588 6.432C4.69322 6.38087 4.68962 6.32871 4.67532 6.27915C4.67325 6.2525 4.66589 6.22657 4.6537 6.20294C4.64151 6.17931 4.62473 6.15849 4.60441 6.14173C4.58409 6.12498 4.56064 6.11266 4.53551 6.10552C4.51037 6.09838 4.48408 6.09658 4.45824 6.10022C4.26471 6.13342 4.07368 6.18051 3.88658 6.24115C3.73208 6.28865 3.42308 6.38682 3.28325 6.41691C3.11919 6.44137 2.95174 6.42061 2.79811 6.35674Z"
+ fill="#000105" />
+ <path
+ id="Fill 6"
+ d="M6.65638 10.8388C6.59613 10.8166 5.34929 10.2846 5.17316 10.2006C5.0287 10.1294 4.67411 9.97578 4.50725 9.90611C4.97694 9.16267 5.27358 8.60292 5.31375 8.51741C5.38714 8.35907 5.88387 7.36386 5.89546 7.30211C5.91103 7.18725 5.91568 7.07111 5.90936 6.95533C5.89855 6.89991 5.71623 7.00679 5.46826 7.09309C5.22028 7.17939 4.74905 7.4945 4.56751 7.5325C4.38597 7.5705 3.80117 7.79852 3.50221 7.89986C3.20325 8.00121 2.63854 8.17855 2.40602 8.24268C2.17349 8.30681 1.96955 8.31156 1.83745 8.35194C1.84417 8.43517 1.86238 8.51701 1.89152 8.595C1.96461 8.70357 2.07004 8.78496 2.19203 8.82698C2.35326 8.85912 2.51903 8.85912 2.68026 8.82698C2.79662 8.79806 2.90565 8.74408 3.00008 8.66863C3.02557 8.62746 2.98695 8.4992 3.02943 8.46041C3.07192 8.42161 3.64126 8.28544 3.85602 8.22289C4.2316 8.0821 4.61523 7.96497 5.00475 7.87215C4.96921 7.9925 4.30949 9.33448 4.09473 9.73509C3.87997 10.1357 2.64472 11.8981 2.37821 12.2085C2.18122 12.4444 1.69608 13.0485 1.52844 13.1847C1.66253 13.1907 1.79667 13.1741 1.92551 13.1356C2.33034 12.792 2.69623 12.403 3.0163 11.9757C3.5203 11.363 3.9875 10.7194 4.41532 10.0486C4.49257 10.0803 5.08509 10.5775 5.24037 10.6883C5.39564 10.7992 6.01288 11.1499 6.14266 11.2077C6.27244 11.2655 6.78694 11.5078 6.80857 11.4262C6.80322 11.2206 6.75026 11.0193 6.65406 10.8388"
+ fill="#000105" />
+ <path
+ id="Fill 7"
+ d="M3.77635 17.4918C3.89224 17.5641 4.0119 17.63 4.1348 17.6889C4.39791 17.8264 4.66818 17.9491 4.94439 18.0563C5.3082 18.1967 5.68057 18.3125 6.05913 18.4031C6.26462 18.4506 6.49019 18.4917 6.70958 18.5258C6.72967 18.5258 7.31987 18.6002 7.43961 18.6002H8.03676C8.26851 18.5796 8.48791 18.5662 8.72043 18.5321C8.90661 18.5052 9.1121 18.4712 9.31063 18.4236C9.45664 18.3896 9.6096 18.3556 9.7556 18.3081C9.90161 18.2606 10.0546 18.213 10.2067 18.1584C10.3064 18.1244 10.4122 18.0792 10.5158 18.0357C10.6046 17.9953 10.7104 17.9486 10.8101 17.9066C10.9298 17.852 11.0689 17.7776 11.2017 17.7095C11.3076 17.6549 11.4273 17.5868 11.5401 17.5187C11.6266 17.4736 11.8252 17.3152 11.9318 17.3152C11.9843 17.3164 12.0343 17.3383 12.0714 17.3764C12.1085 17.4144 12.1299 17.4657 12.1311 17.5195C12.1311 17.7166 11.8723 17.7776 11.7525 17.8663C11.6328 17.9549 11.4737 18.0246 11.3408 18.0975C11.0824 18.2355 10.8165 18.3582 10.5443 18.4648C10.2036 18.5966 9.85561 18.7079 9.50222 18.7981C9.3763 18.8251 9.25038 18.8591 9.12368 18.8773C9.05725 18.8908 8.36739 19 8.17504 19H7.29978C7.06803 18.9794 6.82237 18.9525 6.58984 18.9209C6.38435 18.8868 6.16496 18.8464 5.95947 18.7981C5.80034 18.7641 5.62806 18.719 5.47511 18.6691C5.21174 18.5926 4.95257 18.5017 4.69873 18.3967C4.21072 18.2132 3.7443 17.9742 3.30821 17.6842C3.27956 17.6669 3.25646 17.6415 3.24177 17.611C3.22708 17.5804 3.22144 17.5462 3.22555 17.5124C3.22502 17.4863 3.22964 17.4605 3.23912 17.4363C3.2486 17.4121 3.26275 17.3902 3.28072 17.3718C3.29869 17.3534 3.3201 17.3389 3.34368 17.3291C3.36725 17.3194 3.3925 17.3147 3.41791 17.3152C3.54665 17.3518 3.66803 17.4116 3.77635 17.4918Z"
+ fill="#000105" />
+ <g id="Group 11">
+ <g id="Clip path group">
+ <mask
+ id="mask0_519_2530"
+ style="mask-type: luminance"
+ maskUnits="userSpaceOnUse"
+ x="0"
+ y="0"
+ width="15"
+ height="17">
+ <g id="clip-path">
+ <path id="Clip 9" d="M0 0H14.4723V16.6263H0V0Z" fill="white" />
+ </g>
+ </mask>
+ <g mask="url(#mask0_519_2530)">
+ <g id="Group 11_2">
+ <path
+ id="Fill 8"
+ d="M0.198536 16.6279C0.156998 16.6257 0.116933 16.6114 0.0830126 16.5867C0.0490921 16.562 0.0227135 16.528 0.00695261 16.4886C0.00749474 16.4857 0.00749474 16.4827 0.00695261 16.4798C0.00271452 16.4732 0.000311045 16.4656 0 16.4577L0 5.0259C0 5.0164 0.00695261 5.00531 0.0100427 4.99423C0.0158898 4.96527 0.0283306 4.93815 0.0463508 4.91505C0.09062 4.86341 0.150924 4.82902 0.217076 4.81767L0.251839 4.80738C0.322138 4.78284 7.72513 2.23743 7.83019 2.23743C7.90203 2.23743 8.04263 2.28889 8.04263 2.40765V13.8331C8.03539 13.8705 8.0195 13.9055 7.99628 13.9352C7.98174 13.9585 7.96114 13.9772 7.9368 13.9891C7.87268 14.0152 0.317503 16.6279 0.198536 16.6279ZM7.63783 2.72672L0.404797 5.19612V16.1315L7.63783 13.6621V2.72672Z"
+ fill="#000105" />
+ <path
+ id="Fill 10"
+ d="M14.2596 14.1998C14.0213 14.1421 13.7863 14.0707 13.5558 13.986H13.552L13.4438 13.9496L12.5523 13.6677C12.0209 13.4999 11.4708 13.3257 10.9355 13.1547L10.7501 13.0937C10.6242 13.0526 10.4975 13.0146 10.3785 12.9702C10.1916 12.914 10.0255 12.861 9.88718 12.8119L9.57277 12.7129C8.97175 12.5237 8.34988 12.3273 7.74423 12.1191C7.70212 12.0884 7.66964 12.0457 7.65076 11.9964L7.65076 2.38719V2.37531C7.66104 2.33978 7.68053 2.30777 7.70715 2.28268C7.75968 2.22805 9.77362 1.53925 10.7408 1.2083L10.9347 1.1418C11.2159 1.03887 14.1684 0.000123964 14.2596 0.000123964C14.2877 -0.000864301 14.3157 0.00406493 14.3418 0.0146068C14.368 0.0251486 14.3918 0.0410789 14.4117 0.0614123C14.4316 0.0817457 14.4472 0.10605 14.4576 0.132822C14.468 0.159593 14.4729 0.188263 14.472 0.217058V13.9757C14.4731 14.0049 14.4684 14.034 14.4581 14.0612C14.4479 14.0885 14.4324 14.1133 14.4125 14.1343C14.3927 14.1552 14.3689 14.1718 14.3426 14.1831C14.3163 14.1943 14.2881 14.2 14.2596 14.1998ZM14.0672 0.489413L8.04937 2.58433V11.7969L14.0672 13.7152V0.489413Z"
+ fill="#000105" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <path
+ id="Fill 12"
+ d="M16 16.5993L7.95972 13.9724L7.99371 2.53821L16 5.15091V16.5993Z"
+ fill="#000105" />
+ <path
+ id="Fill 13"
+ d="M14.3965 13.0951L13.3327 12.7642L12.9503 11.3335L10.751 10.6502L10.2782 11.8196L9.21368 11.4847L11.4733 5.80249L12.5092 6.12393L14.3957 13.0911L14.3965 13.0951ZM11.9468 7.64801L11.1573 9.60279L12.6081 10.0533L11.9468 7.64801Z"
+ fill="#FFFFFE" />
+ </g>
+</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-more.svg b/desktop/packages/mullvad-vpn/assets/images/icon-more.svg
deleted file mode 100644
index bee80a60d4..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-more.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg data-name="More icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
- <rect data-name="Rectangle 19" width="32" height="32" rx="16" style="fill:none"/>
- <path d="M9 18a9 9 0 1 1 9-9 9.01 9.01 0 0 1-9 9zm4.3-10.2a1.2 1.2 0 0 0-.032 2.39h.064A1.2 1.2 0 0 0 13.3 7.8zM9 7.8a1.2 1.2 0 0 0-.032 2.39h.064A1.2 1.2 0 0 0 9 7.8zm-4.3 0a1.2 1.2 0 0 0-.032 2.39h.065A1.2 1.2 0 0 0 4.7 7.8z" transform="translate(7 7)" style="fill:rgba(255,255,255)"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-obscure.svg b/desktop/packages/mullvad-vpn/assets/images/icon-obscure.svg
deleted file mode 100644
index 23f4044080..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-obscure.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg data-name="Icons/stop showing account number" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <path data-name="Path 1" d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" style="fill:none"/>
- <path data-name="Path 2" d="M12 6a9.77 9.77 0 0 1 8.82 5.5 9.647 9.647 0 0 1-2.41 3.12l1.41 1.41A11.8 11.8 0 0 0 23 11.5 11.834 11.834 0 0 0 8.36 4.57l1.65 1.65A10.108 10.108 0 0 1 12 6zm-1.07 1.14L13 9.21a2.5 2.5 0 0 1 1.28 1.28l2.07 2.07a4.679 4.679 0 0 0 .14-1.07A4.483 4.483 0 0 0 12 7a4.244 4.244 0 0 0-1.07.14zM2.01 3.87l2.68 2.68A11.738 11.738 0 0 0 1 11.5 11.827 11.827 0 0 0 12 19a11.73 11.73 0 0 0 4.32-.82l3.42 3.42a1 1 0 0 0 1.41-1.41C20.8 19.807 3.791 2.777 3.42 2.45a1.1 1.1 0 0 0-1.41 0 1.045 1.045 0 0 0 0 1.42zm7.5 7.5 2.61 2.61A.5.5 0 0 1 12 14a2.5 2.5 0 0 1-2.5-2.5c0-.05.01-.08.01-.13zm-3.4-3.4 1.75 1.75a4.6 4.6 0 0 0-.36 1.78 4.505 4.505 0 0 0 6.27 4.14l.98.98A10.432 10.432 0 0 1 12 17a9.77 9.77 0 0 1-8.82-5.5 9.9 9.9 0 0 1 2.93-3.53z" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-reload.svg b/desktop/packages/mullvad-vpn/assets/images/icon-reload.svg
deleted file mode 100644
index 6d443ac8b4..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-reload.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g id="icon">
-<mask id="mask0_774_19809" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
-<rect id="box" width="24" height="24" fill="#D9D9D9"/>
-</mask>
-<g mask="url(#mask0_774_19809)">
-<path id="vector" fill-rule="evenodd" clip-rule="evenodd" d="M6 12C6 8.68629 8.68629 6 12 6C13.7762 6 15.3729 6.77144 16.4724 8H15C14.4477 8 14 8.44772 14 9C14 9.55228 14.4477 10 15 10H19C19.5523 10 20 9.55228 20 9V5C20 4.44772 19.5523 4 19 4C18.4477 4 18 4.44772 18 5V6.70853C16.535 5.04867 14.3903 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C14.13 20 16.0674 19.1663 17.5001 17.8094C17.9011 17.4296 17.9183 16.7967 17.5386 16.3957C17.1588 15.9947 16.5259 15.9775 16.1249 16.3572C15.0487 17.3764 13.5983 18 12 18C8.68629 18 6 15.3137 6 12Z" fill="white"/>
-</g>
-</g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-remove.svg b/desktop/packages/mullvad-vpn/assets/images/icon-remove.svg
deleted file mode 100644
index 17e3a5130c..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-remove.svg
+++ /dev/null
@@ -1,23 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <defs>
- <path id="lypxbt7e6a" d="M19.5 12c0 .552-.448 1-1 1h-13c-.552 0-1-.448-1-1s.448-1 1-1h13c.552 0 1 .448 1 1zM12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12z"/>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <g>
- <g>
- <g>
- <g>
- <g transform="translate(-280 -279) translate(0 212) translate(0 53) translate(237 14) translate(43)">
- <mask id="wzem7yftrb" fill="#fff">
- <use xlink:href="#lypxbt7e6a"/>
- </mask>
- <g fill="#FFF" mask="url(#wzem7yftrb)">
- <path d="M0 0H24V24H0z"/>
- </g>
- </g>
- </g>
- </g>
- </g>
- </g>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-search.svg b/desktop/packages/mullvad-vpn/assets/images/icon-search.svg
deleted file mode 100644
index 8c54192c53..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-search.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <defs>
- <path id="d6xp5m7c6a" d="M7.5 0C11.642 0 15 3.358 15 7.5c0 1.77-.613 3.397-1.64 4.68l4.169 4.294c.55.566.54 1.487-.02 2.057-.56.57-1.46.574-2.01.008l-4.352-4.484c-1.08.602-2.323.945-3.647.945C3.358 15 0 11.642 0 7.5 0 3.358 3.358 0 7.5 0zm0 2C4.462 2 2 4.462 2 7.5S4.462 13 7.5 13 13 10.538 13 7.5 10.538 2 7.5 2z"/>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <g transform="translate(3 3)">
- <mask id="ybpe0o1wtb" fill="#fff">
- <use xlink:href="#d6xp5m7c6a"/>
- </mask>
- <use fill="#D8D8D8" xlink:href="#d6xp5m7c6a"/>
- <g fill="#294D73" mask="url(#ybpe0o1wtb)">
- <path d="M0 0H24V24H0z" transform="translate(-3 -3)"/>
- </g>
- <path fill="#FBFCFD" fill-opacity=".2" d="M8.608 12.175s-3.092.026-4.914-1.796c-.585-.585-.947-1.986-1.086-4.204.525 1.415 1.28 2.638 2.266 3.668 1.522 1.523 3.734 2.332 3.734 2.332z" mask="url(#ybpe0o1wtb)" transform="rotate(7 5.608 9.175)"/>
- </g>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-settings.svg b/desktop/packages/mullvad-vpn/assets/images/icon-settings.svg
deleted file mode 100755
index 392841687b..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-settings.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-settings</title>
- <desc>Mullvad VPN app</desc>
- <defs></defs>
- <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <path d="M21.2552027,12.0000012 C21.2552027,12.4080002 21.2181943,12.792001 21.1688441,13.1760007 L23.7718756,15.1560004 C24.0062723,15.3360012 24.0679568,15.6600006 23.9199162,15.924001 L21.4525887,20.0760014 C21.304548,20.3400006 20.9837951,20.4480008 20.700053,20.3400006 L17.6282305,19.1400005 C16.9867248,19.6079998 16.2958725,20.016 15.5433381,20.316 L15.0745457,23.4959999 C15.037536,23.7839996 14.7784667,24 14.4700507,24 L9.53539566,24 C9.22697972,24 8.96791028,23.7839996 8.9309007,23.4959999 L8.46210833,20.316 C7.70957385,20.016 7.01872221,19.62 6.37721707,19.1400005 L3.30539454,20.3400006 C3.03398819,20.4360005 2.700899,20.3400006 2.55285948,20.0760014 L0.0855319329,15.924001 C-0.062507572,15.6600006 -0.000824444944,15.336 0.233571734,15.1560004 L2.83660217,13.1760007 C2.78725567,12.792001 2.7502455,12.3960011 2.7502455,12.0000012 C2.7502455,11.6040012 2.78725567,11.2080012 2.83660217,10.8240016 L0.23357145,8.84400074 C-0.000824444944,8.66400004 -0.0748444934,8.34000059 0.0855319329,8.07600026 L2.55285948,3.92400037 C2.70089958,3.66000059 3.02165186,3.55200039 3.30539454,3.66000059 L6.37721765,4.86000071 C7.01872279,4.39200082 7.70957502,3.9840006 8.4621095,3.68400057 L8.93090187,0.504000134 C8.96791146,0.216000094 9.2269809,0 9.53539685,0 L14.4700519,0 C14.7784679,0 15.0375373,0.216000094 15.0745481,0.50400071 L15.5433404,3.68400114 C16.2958761,3.98400117 16.9867272,4.38000112 17.6282328,4.86000128 L20.7000554,3.66000116 C20.9714629,3.56400067 21.3045504,3.66000116 21.452591,3.92400093 L23.9199186,8.0760014 C24.0679568,8.34000175 24.0062746,8.66400233 23.7718779,8.84400188 L21.1688466,10.8240016 C21.2181919,11.2080012 21.2552027,11.5920021 21.2552027,12.0000012 Z M12,17 C14.7571433,17 17,14.7571433 17,12 C17,9.24285657 14.7571433,7 12,7 C9.24285657,7 7,9.24285657 7,12 C7,14.7571433 9.24285657,17 12,17 Z" id="icon" fill="#FFFFFF"></path>
- </g>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-tick.svg b/desktop/packages/mullvad-vpn/assets/images/icon-tick.svg
deleted file mode 100755
index 16c701574a..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-tick.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <title>icon-tick</title>
- <path d="M2.92646877,10.7979185 C2.25699855,10.1340272 1.17157288,10.1340272 0.502102661,10.7979185 C-0.167367554,11.4618098 -0.167367554,12.5381902 0.502102661,13.2020815 L7.35924552,20.0020815 C8.02871573,20.6659728 9.11414141,20.6659728 9.78361162,20.0020815 L23.4978973,6.40208153 C24.1673676,5.73819023 24.1673676,4.66180977 23.4978973,3.99791847 C22.8284271,3.33402718 21.7430014,3.33402718 21.0735312,3.99791847 L8.57142857,16.3958369 L2.92646877,10.7979185 Z" fill="currentColor"/>
-</svg> \ No newline at end of file
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-unobscure.svg b/desktop/packages/mullvad-vpn/assets/images/icon-unobscure.svg
deleted file mode 100644
index cef3c44ea2..0000000000
--- a/desktop/packages/mullvad-vpn/assets/images/icon-unobscure.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg data-name="Icons/show account number" xmlns="http://www.w3.org/2000/svg" width="24" height="24">
- <path data-name="Path 3" d="M0 0h24v24H0z" style="fill:none"/>
- <path data-name="Path 4" d="M12 6a9.77 9.77 0 0 1 8.82 5.5 9.822 9.822 0 0 1-17.64 0A9.77 9.77 0 0 1 12 6m0-2a11.827 11.827 0 0 0-11 7.5 11.817 11.817 0 0 0 22 0A11.827 11.827 0 0 0 12 4zm0 5a2.5 2.5 0 1 1-2.5 2.5A2.5 2.5 0 0 1 12 9m0-2a4.5 4.5 0 1 0 4.5 4.5A4.507 4.507 0 0 0 12 7z" style="fill:#294d73"/>
-</svg>
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-fail.svg b/desktop/packages/mullvad-vpn/assets/images/negative.svg
index 544d0d4ed7..544d0d4ed7 100755
--- a/desktop/packages/mullvad-vpn/assets/images/icon-fail.svg
+++ b/desktop/packages/mullvad-vpn/assets/images/negative.svg
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-success.svg b/desktop/packages/mullvad-vpn/assets/images/positive.svg
index 5a9e943406..5a9e943406 100755
--- a/desktop/packages/mullvad-vpn/assets/images/icon-success.svg
+++ b/desktop/packages/mullvad-vpn/assets/images/positive.svg
diff --git a/desktop/packages/mullvad-vpn/assets/images/icon-spinner.svg b/desktop/packages/mullvad-vpn/assets/images/spinner.svg
index 580d56a349..580d56a349 100644
--- a/desktop/packages/mullvad-vpn/assets/images/icon-spinner.svg
+++ b/desktop/packages/mullvad-vpn/assets/images/spinner.svg
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/Account.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/Account.tsx
index 204a77501c..04115f8005 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/Account.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/Account.tsx
@@ -4,6 +4,8 @@ import { formatDate, hasExpired } from '../../shared/account-expiry';
import { urls } from '../../shared/constants';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
+import { Flex, Icon } from '../lib/components';
+import { Spacings } from '../lib/foundations';
import { useHistory } from '../lib/history';
import { useEffectEvent } from '../lib/utility-hooks';
import { useSelector } from '../redux/store';
@@ -17,7 +19,6 @@ import {
AccountRows,
AccountRowValue,
DeviceRowValue,
- StyledDeviceNameRow,
} from './AccountStyles';
import * as AppButton from './AppButton';
import { AriaDescribed, AriaDescription, AriaDescriptionGroup } from './AriaGroup';
@@ -90,10 +91,8 @@ export default function Account() {
<AppButton.GreenButton>
<AppButton.Label>{messages.gettext('Buy more credit')}</AppButton.Label>
<AriaDescription>
- <AppButton.Icon
- source="icon-extLink"
- height={16}
- width={16}
+ <Icon
+ icon="external"
aria-label={messages.pgettext('accessibility', 'Opens externally')}
/>
</AriaDescription>
@@ -119,10 +118,10 @@ export default function Account() {
function DeviceNameRow() {
const deviceName = useSelector((state) => state.account.deviceName);
return (
- <StyledDeviceNameRow>
+ <Flex $gap={Spacings.spacing3} $alignItems="center">
<DeviceRowValue>{deviceName}</DeviceRowValue>
<DeviceInfoButton />
- </StyledDeviceNameRow>
+ </Flex>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ApiAccessMethods.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ApiAccessMethods.tsx
index ebe2cc0895..646a2013b0 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ApiAccessMethods.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ApiAccessMethods.tsx
@@ -6,7 +6,7 @@ import { AccessMethodSetting } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
import { useApiAccessMethodTest } from '../lib/api-access-methods';
-import { Container, Flex } from '../lib/components';
+import { Container, Flex, Spinner } from '../lib/components';
import { Colors, Spacings } from '../lib/foundations';
import { useHistory } from '../lib/history';
import { generateRoutePath } from '../lib/routeHelpers';
@@ -21,7 +21,6 @@ import {
ContextMenuItem,
ContextMenuTrigger,
} from './ContextMenu';
-import ImageView from './ImageView';
import InfoButton from './InfoButton';
import { BackAction } from './KeyboardNavigation';
import { Layout, SettingsContainer, SettingsContent, SettingsNavigationScrollbars } from './Layout';
@@ -30,14 +29,6 @@ import { NavigationContainer } from './NavigationContainer';
import SettingsHeader, { HeaderSubTitle, HeaderTitle } from './SettingsHeader';
import { SmallButton, SmallButtonColor } from './SmallButton';
-const StyledMethodInfoButton = styled(InfoButton)({
- marginRight: Spacings.spacing1,
-});
-
-const StyledMethodTriggerImage = styled(ImageView)({
- marginRight: Spacings.spacing1,
-});
-
const StyledNameLabel = styled(Cell.Label)({
display: 'block',
overflow: 'hidden',
@@ -235,8 +226,8 @@ function ApiAccessMethod(props: ApiAccessMethodProps) {
<StyledNameLabel>{props.method.name}</StyledNameLabel>
{testing && (
<Cell.SubLabel>
- <Flex $gap={Spacings.spacing2}>
- <ImageView source="icon-spinner" width={10} />
+ <Flex $gap={Spacings.spacing1} $alignItems="center">
+ <Spinner size="small" />
{messages.pgettext('api-access-methods-view', 'Testing...')}
</Flex>
</Cell.SubLabel>
@@ -253,61 +244,56 @@ function ApiAccessMethod(props: ApiAccessMethodProps) {
<Cell.SubLabel>{messages.pgettext('api-access-methods-view', 'In use')}</Cell.SubLabel>
)}
</Cell.LabelContainer>
- {props.method.type === 'direct' && (
- <StyledMethodInfoButton
- message={[
- messages.pgettext(
- 'api-access-methods-view',
- 'With the “Direct” method, the app communicates with a Mullvad API server directly without any intermediate proxies.',
- ),
- messages.pgettext(
- 'api-access-methods-view',
- 'This can be useful when you are not affected by censorship.',
- ),
- ]}
- />
- )}
- {props.method.type === 'bridges' && (
- <StyledMethodInfoButton
- message={[
- messages.pgettext(
- 'api-access-methods-view',
- 'With the “Mullvad bridges” method, the app communicates with a Mullvad API server via a Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks.',
- ),
- messages.pgettext(
- 'api-access-methods-view',
- 'This can be useful if the API is censored but Mullvad’s bridge servers are not.',
- ),
- ]}
- />
- )}
- {props.method.type === 'encrypted-dns-proxy' && (
- <StyledMethodInfoButton
- message={[
- messages.pgettext(
- 'api-access-methods-view',
- 'With the “Encrypted DNS proxy” method, the app will communicate with our Mullvad API through a proxy address. It does this by retrieving an address from a DNS over HTTPS (DoH) server and then using that to reach our API servers.',
- ),
- messages.pgettext(
- 'api-access-methods-view',
- 'If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP when connecting. The DoH servers are hosted by one of the following providers: Quad9 or CloudFlare.',
- ),
- ]}
- />
- )}
- <ContextMenuContainer>
- <ContextMenuTrigger>
- <StyledMethodTriggerImage
- source="icon-more"
- tintColor={Colors.white}
- tintHoverColor={Colors.white80}
- height={36}
- width={36}
+ <Flex $gap={Spacings.spacing3} $alignItems="center">
+ {props.method.type === 'direct' && (
+ <InfoButton
+ message={[
+ messages.pgettext(
+ 'api-access-methods-view',
+ 'With the “Direct” method, the app communicates with a Mullvad API server directly without any intermediate proxies.',
+ ),
+ messages.pgettext(
+ 'api-access-methods-view',
+ 'This can be useful when you are not affected by censorship.',
+ ),
+ ]}
+ />
+ )}
+ {props.method.type === 'bridges' && (
+ <InfoButton
+ message={[
+ messages.pgettext(
+ 'api-access-methods-view',
+ 'With the “Mullvad bridges” method, the app communicates with a Mullvad API server via a Mullvad bridge server. It does this by sending the traffic obfuscated by Shadowsocks.',
+ ),
+ messages.pgettext(
+ 'api-access-methods-view',
+ 'This can be useful if the API is censored but Mullvad’s bridge servers are not.',
+ ),
+ ]}
+ />
+ )}
+
+ {props.method.type === 'encrypted-dns-proxy' && (
+ <InfoButton
+ message={[
+ messages.pgettext(
+ 'api-access-methods-view',
+ 'With the “Encrypted DNS proxy” method, the app will communicate with our Mullvad API through a proxy address. It does this by retrieving an address from a DNS over HTTPS (DoH) server and then using that to reach our API servers.',
+ ),
+ messages.pgettext(
+ 'api-access-methods-view',
+ 'If you are not connected to our VPN, then the Encrypted DNS proxy will use your own non-VPN IP when connecting. The DoH servers are hosted by one of the following providers: Quad9 or CloudFlare.',
+ ),
+ ]}
/>
- </ContextMenuTrigger>
- <ContextMenu items={menuItems} align="right" />
- </ContextMenuContainer>
- <Cell.Switch isOn={props.method.enabled} onChange={toggle} />
+ )}
+ <ContextMenuContainer>
+ <ContextMenuTrigger />
+ <ContextMenu items={menuItems} align="right" />
+ </ContextMenuContainer>
+ <Cell.Switch isOn={props.method.enabled} onChange={toggle} />
+ </Flex>
{/* Confirmation dialog for method removal */}
<ModalAlert
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/AppButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/AppButton.tsx
index 26ddf6a217..ceec46c62f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/AppButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/AppButton.tsx
@@ -14,7 +14,6 @@ import {
transparentButton,
} from './AppButtonStyles';
import { measurements } from './common-styles';
-import ImageView from './ImageView';
interface ILabelProps {
textOffset?: number;
@@ -25,16 +24,6 @@ export function Label(props: ILabelProps) {
return <StyledLabel $textOffset={props.textOffset ?? 0}>{props.children}</StyledLabel>;
}
-interface IIconProps {
- source: string;
- width?: number;
- height?: number;
-}
-
-export function Icon(props: IIconProps) {
- return <ImageView {...props} tintColor={Colors.white} />;
-}
-
export interface IProps extends React.HTMLAttributes<HTMLButtonElement> {
children?: React.ReactNode;
className?: string;
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ChevronButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ChevronButton.tsx
index c0ec34a592..8c64634654 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ChevronButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ChevronButton.tsx
@@ -1,8 +1,8 @@
import * as React from 'react';
import styled from 'styled-components';
+import { Icon } from '../lib/components';
import { Colors } from '../lib/foundations';
-import { Icon } from './cell/Label';
interface IProps extends React.HTMLAttributes<HTMLButtonElement> {
up: boolean;
@@ -17,6 +17,9 @@ const StyledIcon = styled(Icon)({
flex: 0,
alignSelf: 'stretch',
justifyContent: 'center',
+ '&&:hover': {
+ backgroundColor: Colors.white,
+ },
});
export default function ChevronButton(props: IProps) {
@@ -24,13 +27,7 @@ export default function ChevronButton(props: IProps) {
return (
<Button {...otherProps}>
- <StyledIcon
- tintColor={Colors.white80}
- tintHoverColor={Colors.white}
- source={up ? 'icon-chevron-up' : 'icon-chevron-down'}
- height={24}
- width={24}
- />
+ <StyledIcon color={Colors.white60} icon={up ? 'chevron-up' : 'chevron-down'} />
</Button>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ClipboardLabel.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ClipboardLabel.tsx
index bccf15d3d0..c7c675f584 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ClipboardLabel.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ClipboardLabel.tsx
@@ -4,9 +4,9 @@ import styled from 'styled-components';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
import { useScheduler } from '../../shared/scheduler';
-import { Colors } from '../lib/foundations';
+import { Flex, Icon, IconButton } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
import { useBoolean } from '../lib/utility-hooks';
-import ImageView from './ImageView';
const COPIED_ICON_DURATION = 2000;
@@ -28,18 +28,6 @@ const StyledLabel = styled.span({
flex: 1,
});
-const StyledButton = styled.button({
- cursor: 'default',
- padding: 0,
- marginLeft: '20px',
- backgroundColor: 'transparent',
- border: 'none',
-});
-
-const StyledCopyButton = styled(StyledButton)({
- width: '24px',
-});
-
export default function ClipboardLabel(props: IProps) {
const { value, obscureValue, displayValue, message, ...otherProps } = props;
@@ -64,42 +52,38 @@ export default function ClipboardLabel(props: IProps) {
<StyledLabel aria-hidden={obscured} {...otherProps}>
{obscured ? '●●●● ●●●● ●●●● ●●●●' : (displayValue ?? value)}
</StyledLabel>
- {obscureValue !== false && (
- <StyledButton
- onClick={toggleObscured}
- aria-label={
- obscured
- ? // This line is here to prevent the following one to be moved up here by prettier
- // TRANSLATORS: Provided to accessibility tools such as screenreaders to describe
- // TRANSLATORS: the button which unobscures the account number.
- messages.pgettext('accessibility', 'Show account number')
- : // This line is here to prevent the following one to be moved up here by prettier
- // TRANSLATORS: Provided to accessibility tools such as screenreaders to describe
- // TRANSLATORS: the button which obscures the account number.
- messages.pgettext('accessibility', 'Hide account number')
- }>
- <ImageView
- source={obscured ? 'icon-unobscure' : 'icon-obscure'}
- tintColor={Colors.white}
- tintHoverColor={Colors.white80}
- width={24}
- />
- </StyledButton>
- )}
- <StyledCopyButton
- onClick={onCopy}
- aria-label={
- // TRANSLATORS: Provided to accessibility tools such as screenreaders to describe a button
- // TRANSLATORS: which copies the account number to the clipboard.
- messages.pgettext('accessibility', 'Copy account number')
- }>
- <ImageView
- source={justCopied ? 'icon-tick' : 'icon-copy'}
- tintColor={justCopied ? Colors.green : Colors.white}
- tintHoverColor={justCopied ? Colors.green : Colors.white80}
- width={justCopied ? 22 : 24}
- />
- </StyledCopyButton>
+ <Flex $gap={Spacings.spacing5}>
+ {obscureValue !== false && (
+ <IconButton
+ onClick={toggleObscured}
+ aria-label={
+ obscured
+ ? // This line is here to prevent the following one to be moved up here by prettier
+ // TRANSLATORS: Provided to accessibility tools such as screenreaders to describe
+ // TRANSLATORS: the button which unobscures the account number.
+ messages.pgettext('accessibility', 'Show account number')
+ : // This line is here to prevent the following one to be moved up here by prettier
+ // TRANSLATORS: Provided to accessibility tools such as screenreaders to describe
+ // TRANSLATORS: the button which obscures the account number.
+ messages.pgettext('accessibility', 'Hide account number')
+ }>
+ {obscured ? <IconButton.Icon icon="show" /> : <IconButton.Icon icon="hide" />}
+ </IconButton>
+ )}
+ {justCopied ? (
+ <Icon icon="checkmark" color={Colors.green}></Icon>
+ ) : (
+ <IconButton
+ onClick={onCopy}
+ aria-label={
+ // TRANSLATORS: Provided to accessibility tools such as screenreaders to describe a button
+ // TRANSLATORS: which copies the account number to the clipboard.
+ messages.pgettext('accessibility', 'Copy account number')
+ }>
+ <IconButton.Icon icon={'copy'} />
+ </IconButton>
+ )}
+ </Flex>
</StyledLabelContainer>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ContextMenu.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ContextMenu.tsx
index 5b6e43c4f3..24a78472a2 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ContextMenu.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ContextMenu.tsx
@@ -1,6 +1,7 @@
import React, { useCallback, useContext, useEffect, useMemo } from 'react';
import styled from 'styled-components';
+import { IconButton } from '../lib/components';
import { Colors } from '../lib/foundations';
import { useBoolean, useStyledRef } from '../lib/utility-hooks';
import { smallText } from './common-styles';
@@ -86,18 +87,14 @@ export function ContextMenuContainer(props: React.PropsWithChildren) {
);
}
-const StyledTrigger = styled.button({
- borderWidth: 0,
- padding: 0,
- margin: 0,
- cursor: 'default',
- backgroundColor: 'transparent',
-});
-
-export function ContextMenuTrigger(props: React.PropsWithChildren) {
+export function ContextMenuTrigger() {
const { toggleVisibility } = useContext(menuContext);
- return <StyledTrigger onClick={toggleVisibility}>{props.children}</StyledTrigger>;
+ return (
+ <IconButton onClick={toggleVisibility}>
+ <IconButton.Icon icon="more-horizontal-circle" />
+ </IconButton>
+ );
}
interface StyledMenuProps {
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettings.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettings.tsx
index 051f6b938f..1be8d0be2e 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettings.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettings.tsx
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
-import { Colors } from '../lib/foundations';
+import { IconButton } from '../lib/components';
import { formatHtml } from '../lib/html-formatter';
import { IpAddress } from '../lib/ip';
import { useBoolean, useMounted, useStyledRef } from '../lib/utility-hooks';
@@ -19,14 +19,12 @@ import {
} from './AriaGroup';
import * as Cell from './cell';
import {
- StyledAddCustomDnsButton,
+ AddServerContainer,
StyledAddCustomDnsLabel,
StyledButton,
- StyledContainer,
StyledCustomDnsFooter,
+ StyledItemContainer,
StyledLabel,
- StyledRemoveButton,
- StyledRemoveIcon,
} from './CustomDnsSettingsStyles';
import List, { stringValueAsKey } from './List';
import { ModalAlert, ModalAlertType } from './Modal';
@@ -243,23 +241,20 @@ export default function CustomDnsSettings() {
</div>
)}
- <StyledAddCustomDnsButton
- ref={addButtonRef}
- onClick={showInput}
- disabled={inputVisible}
- tabIndex={-1}>
- <StyledAddCustomDnsLabel tabIndex={-1}>
- {messages.pgettext('vpn-settings-view', 'Add a server')}
- </StyledAddCustomDnsLabel>
- <Cell.Icon
- source="icon-add"
- width={18}
- height={18}
- tintColor={Colors.white40}
- tintHoverColor={Colors.white60}
- tabIndex={-1}
- />
- </StyledAddCustomDnsButton>
+ <AddServerContainer>
+ <StyledButton
+ ref={addButtonRef}
+ onClick={showInput}
+ disabled={inputVisible}
+ tabIndex={-1}>
+ <StyledAddCustomDnsLabel tabIndex={-1}>
+ {messages.pgettext('vpn-settings-view', 'Add a server')}
+ </StyledAddCustomDnsLabel>
+ </StyledButton>
+ <IconButton variant="secondary" onClick={showInput}>
+ <IconButton.Icon icon="add-circle" />
+ </IconButton>
+ </AddServerContainer>
</Accordion>
<StyledCustomDnsFooter>
@@ -355,25 +350,21 @@ function CellListItem(props: ICellListItemProps) {
/>
</div>
) : (
- <StyledContainer>
+ <StyledItemContainer>
<StyledButton onClick={startEditing}>
<AriaDescription>
<StyledLabel>{props.children}</StyledLabel>
</AriaDescription>
</StyledButton>
<AriaDescribed>
- <StyledRemoveButton
+ <IconButton
+ variant="secondary"
onClick={onRemove}
aria-label={messages.pgettext('accessibility', 'Remove item')}>
- <StyledRemoveIcon
- source="icon-close"
- width={18}
- height={18}
- tintColor={editing ? Colors.black : Colors.white40}
- />
- </StyledRemoveButton>
+ <IconButton.Icon icon="cross-circle" />
+ </IconButton>
</AriaDescribed>
- </StyledContainer>
+ </StyledItemContainer>
)}
</AriaDescriptionGroup>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettingsStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettingsStyles.tsx
index 18b98ff6e3..59122c1b49 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettingsStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/CustomDnsSettingsStyles.tsx
@@ -2,16 +2,11 @@ import styled from 'styled-components';
import { Colors } from '../lib/foundations';
import * as Cell from './cell';
-import ImageView from './ImageView';
export const StyledCustomDnsFooter = styled(Cell.CellFooter)({
marginBottom: '2px',
});
-export const StyledAddCustomDnsButton = styled(Cell.CellButton)({
- backgroundColor: Colors.blue40,
-});
-
export const StyledAddCustomDnsLabel = styled(Cell.Label)<{ $paddingLeft?: number }>((props) => ({
fontFamily: 'Open Sans',
fontWeight: 400,
@@ -23,9 +18,20 @@ export const StyledAddCustomDnsLabel = styled(Cell.Label)<{ $paddingLeft?: numbe
marginRight: '25px',
}));
-export const StyledContainer = styled(Cell.Container)({
+export const StyledItemContainer = styled(Cell.Container)({
display: 'flex',
backgroundColor: Colors.blue40,
+ '&&:hover': {
+ backgroundColor: Colors.blue80,
+ },
+});
+
+export const AddServerContainer = styled(Cell.Container)({
+ display: 'flex',
+ backgroundColor: Colors.blue20,
+ '&&:hover': {
+ backgroundColor: Colors.blue60,
+ },
});
export const StyledButton = styled.button({
@@ -54,9 +60,3 @@ export const StyledRemoveButton = styled.button({
border: 'none',
padding: 0,
});
-
-export const StyledRemoveIcon = styled(ImageView)({
- [StyledRemoveButton + ':hover &&']: {
- backgroundColor: Colors.white80,
- },
-});
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/DeviceInfoButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/DeviceInfoButton.tsx
index 090bb9c8df..6100fe292c 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/DeviceInfoButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/DeviceInfoButton.tsx
@@ -1,29 +1,20 @@
-import styled from 'styled-components';
-
import { messages } from '../../shared/gettext';
+import { IconButton } from '../lib/components';
import { useBoolean } from '../lib/utility-hooks';
import * as AppButton from './AppButton';
-import { InfoIcon } from './InfoButton';
import { ModalAlert, ModalAlertType, ModalMessage } from './Modal';
-const StyledInfoButton = styled.button({
- margin: '0 0 0 10px',
- borderWidth: 0,
- padding: 0,
- cursor: 'default',
- backgroundColor: 'transparent',
-});
-
export default function DeviceInfoButton() {
const [deviceHelpVisible, showDeviceHelp, hideDeviceHelp] = useBoolean();
return (
<>
- <StyledInfoButton
+ <IconButton
+ size="small"
onClick={showDeviceHelp}
aria-label={messages.pgettext('accessibility', 'More information')}>
- <InfoIcon size={16} />
- </StyledInfoButton>
+ <IconButton.Icon icon="info-circle" />
+ </IconButton>
<ModalAlert
isOpen={deviceHelpVisible}
type={ModalAlertType.info}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/DeviceRevokedView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/DeviceRevokedView.tsx
index a26510db90..3125c1c3e1 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/DeviceRevokedView.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/DeviceRevokedView.tsx
@@ -2,13 +2,14 @@ import styled from 'styled-components';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
-import { Colors } from '../lib/foundations';
+import { Flex } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
+import { IconBadge } from '../lib/icon-badge';
import { useSelector } from '../redux/store';
import { AppMainHeader } from './app-main-header';
import * as AppButton from './AppButton';
import { bigText, measurements, smallText } from './common-styles';
import CustomScrollbars from './CustomScrollbars';
-import ImageView from './ImageView';
import { Container, Footer, Layout } from './Layout';
export const StyledCustomScrollbars = styled(CustomScrollbars)({
@@ -28,13 +29,6 @@ export const StyledBody = styled.div({
padding: `0 ${measurements.horizontalViewMargin}`,
});
-export const StyledStatusIcon = styled.div({
- alignSelf: 'center',
- width: '60px',
- height: '60px',
- marginBottom: '18px',
-});
-
export const StyledTitle = styled.span(bigText, {
lineHeight: '38px',
marginBottom: '8px',
@@ -61,9 +55,9 @@ export function DeviceRevokedView() {
<StyledCustomScrollbars fillContainer>
<StyledContainer>
<StyledBody>
- <StyledStatusIcon>
- <ImageView source="icon-fail" height={60} width={60} />
- </StyledStatusIcon>
+ <Flex $justifyContent="center" $margin={{ bottom: Spacings.spacing5 }}>
+ <IconBadge state="negative" />
+ </Flex>
<StyledTitle data-testid="title">
{messages.pgettext('device-management', 'Device is inactive')}
</StyledTitle>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ErrorView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ErrorView.tsx
index 849838024d..c9cf1b1f93 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ErrorView.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ErrorView.tsx
@@ -1,10 +1,10 @@
import React from 'react';
import styled from 'styled-components';
-import { Colors } from '../lib/foundations';
+import { Flex, Logo } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
import { AppMainHeader } from './app-main-header';
import { measurements } from './common-styles';
-import ImageView from './ImageView';
import { Container, Layout } from './Layout';
const StyledContainer = styled(Container)({
@@ -14,23 +14,6 @@ const StyledContainer = styled(Container)({
justifyContent: 'end',
});
-const StyledContent = styled.div({
- display: 'flex',
- flex: 1,
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'end',
-});
-
-const Logo = styled(ImageView)({
- marginBottom: '12px',
-});
-
-const Title = styled(ImageView)({
- opacity: 0.6,
- marginBottom: '9px',
-});
-
const Subtitle = styled.span({
fontFamily: 'Open Sans',
fontSize: '14px',
@@ -60,12 +43,18 @@ export default function ErrorView(props: ErrorViewProps) {
{!props.settingsUnavailable && <AppMainHeader.SettingsButton />}
</AppMainHeader>
<StyledContainer>
- <StyledContent>
- <Logo height={106} width={106} source="logo-icon" />
- <Title height={18} source="logo-text" />
+ <Flex $flexDirection="column" $gap={Spacings.spacing3}>
+ <Flex
+ $flexDirection="column"
+ $alignItems="center"
+ $justifyContent="end"
+ $gap={Spacings.spacing4}>
+ <Logo variant="icon" size="2" />
+ <Logo variant="text" size="2" />
+ </Flex>
<Subtitle role="alert">{props.children}</Subtitle>
- </StyledContent>
- <StyledFooterContainer>{props.footer}</StyledFooterContainer>
+ <StyledFooterContainer>{props.footer}</StyledFooterContainer>
+ </Flex>
</StyledContainer>
</Layout>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountAddTime.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountAddTime.tsx
index 62a79a2064..8a72a30cfa 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountAddTime.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountAddTime.tsx
@@ -9,8 +9,10 @@ import { formatRelativeDate } from '../../shared/date-helper';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
import useActions from '../lib/actionsHook';
-import { Colors } from '../lib/foundations';
+import { Flex, Icon } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
import { transitions, useHistory } from '../lib/history';
+import { IconBadge } from '../lib/icon-badge';
import { generateRoutePath } from '../lib/routeHelpers';
import { RoutePath } from '../lib/routes';
import account from '../redux/account/actions';
@@ -20,7 +22,6 @@ import * as AppButton from './AppButton';
import { AriaDescribed, AriaDescription, AriaDescriptionGroup } from './AriaGroup';
import { hugeText, measurements, tinyText } from './common-styles';
import CustomScrollbars from './CustomScrollbars';
-import ImageView from './ImageView';
import { Container, Footer, Layout } from './Layout';
import {
RedeemVoucherContainer,
@@ -165,9 +166,9 @@ export function TimeAdded(props: ITimeAddedProps) {
<StyledCustomScrollbars fillContainer>
<StyledContainer>
<StyledBody>
- <StyledStatusIcon>
- <ImageView source="icon-success" height={60} width={60} />
- </StyledStatusIcon>
+ <Flex $justifyContent="center" $margin={{ bottom: Spacings.spacing5 }}>
+ <IconBadge state="positive" />
+ </Flex>
<StyledTitle>
{props.title ?? messages.pgettext('connect-view', 'Time was successfully added')}
</StyledTitle>
@@ -233,10 +234,8 @@ export function SetupFinished() {
{messages.pgettext('connect-view', 'Learn about privacy')}
</AppButton.Label>
<AriaDescription>
- <AppButton.Icon
- height={16}
- width={16}
- source="icon-extLink"
+ <Icon
+ icon="external"
aria-label={messages.pgettext('accessibility', 'Opens externally')}
/>
</AriaDescription>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorView.tsx
index fa59ac7d76..785d6405e1 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorView.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorView.tsx
@@ -6,7 +6,10 @@ import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
import { capitalizeEveryWord } from '../../shared/string-helpers';
import { useAppContext } from '../context';
+import { Flex, Icon } from '../lib/components';
+import { Spacings } from '../lib/foundations';
import { useHistory } from '../lib/history';
+import { IconBadge } from '../lib/icon-badge';
import { RoutePath } from '../lib/routes';
import { useSelector } from '../redux/store';
import { AppMainHeader } from './app-main-header';
@@ -24,10 +27,8 @@ import {
StyledDeviceLabel,
StyledMessage,
StyledModalCellContainer,
- StyledStatusIcon,
StyledTitle,
} from './ExpiredAccountErrorViewStyles';
-import ImageView from './ImageView';
import { Footer, Layout } from './Layout';
import { ModalAlert, ModalAlertType, ModalMessage } from './Modal';
@@ -121,8 +122,8 @@ function WelcomeView() {
</StyledAccountNumberContainer>
</StyledAccountNumberMessage>
- <StyledDeviceLabel>
- <span>
+ <Flex $alignItems="center" $gap={Spacings.spacing1} $margin={{ bottom: Spacings.spacing5 }}>
+ <StyledDeviceLabel>
{sprintf(
// TRANSLATORS: A label that will display the newly created device name to inform the user
// TRANSLATORS: about it.
@@ -133,9 +134,9 @@ function WelcomeView() {
deviceName: capitalizeEveryWord(account.deviceName ?? ''),
},
)}
- </span>
+ </StyledDeviceLabel>
<DeviceInfoButton />
- </StyledDeviceLabel>
+ </Flex>
<StyledMessage>
{sprintf('%(introduction)s %(recoveryMessage)s', {
@@ -155,9 +156,9 @@ function Content() {
return (
<>
- <StyledStatusIcon>
- <ImageView source="icon-fail" height={60} width={60} />
- </StyledStatusIcon>
+ <Flex $justifyContent="center" $margin={{ bottom: Spacings.spacing5 }}>
+ <IconBadge state="negative" />
+ </Flex>
<StyledTitle data-testid="title">
{messages.pgettext('connect-view', 'Out of time')}
</StyledTitle>
@@ -201,10 +202,8 @@ function ExternalPaymentButton() {
<AppButton.GreenButton>
<AppButton.Label>{buttonText}</AppButton.Label>
<AriaDescription>
- <AppButton.Icon
- source="icon-extLink"
- height={16}
- width={16}
+ <Icon
+ icon="external"
aria-label={messages.pgettext('accessibility', 'Opens externally')}
/>
</AriaDescription>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorViewStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorViewStyles.tsx
index 1cb2fcde1e..81ba2496a8 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorViewStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ExpiredAccountErrorViewStyles.tsx
@@ -52,13 +52,6 @@ export const StyledAccountNumberMessage = styled.span(tinyText, {
color: Colors.white,
});
-export const StyledStatusIcon = styled.div({
- alignSelf: 'center',
- width: '60px',
- height: '60px',
- marginBottom: '18px',
-});
-
export const StyledAccountNumberContainer = styled.div({
display: 'flex',
height: '50px',
@@ -66,9 +59,6 @@ export const StyledAccountNumberContainer = styled.div({
});
export const StyledDeviceLabel = styled.span(tinyText, {
- display: 'flex',
- alignItems: 'middle',
lineHeight: '20px',
- marginBottom: '18px',
color: Colors.white,
});
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/Filter.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/Filter.tsx
index 93a76d7774..d63caffe6d 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/Filter.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/Filter.tsx
@@ -3,6 +3,7 @@ import styled from 'styled-components';
import { Ownership } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
+import { Icon } from '../lib/components';
import { useRelaySettingsUpdater } from '../lib/constraint-updater';
import {
EndpointType,
@@ -22,7 +23,6 @@ import { AriaInputGroup, AriaLabel } from './AriaGroup';
import * as Cell from './cell';
import Selector from './cell/Selector';
import { normalText } from './common-styles';
-import ImageView from './ImageView';
import { BackAction } from './KeyboardNavigation';
import { Footer, Layout, SettingsContainer } from './Layout';
import { NavigationContainer } from './NavigationContainer';
@@ -239,11 +239,7 @@ function FilterByOwnership(props: IFilterByOwnershipProps) {
<AriaLabel>
<Cell.Label>{messages.pgettext('filter-view', 'Ownership')}</Cell.Label>
</AriaLabel>
- <ImageView
- tintColor={Colors.white80}
- source={expanded ? 'icon-chevron-up' : 'icon-chevron-down'}
- height={24}
- />
+ <Icon color={Colors.white80} icon={expanded ? 'chevron-up' : 'chevron-down'} />
</Cell.CellButton>
<Accordion expanded={expanded}>
@@ -289,11 +285,7 @@ function FilterByProvider(props: IFilterByProviderProps) {
<>
<Cell.CellButton onClick={toggleExpanded}>
<Cell.Label>{messages.pgettext('filter-view', 'Providers')}</Cell.Label>
- <ImageView
- tintColor={Colors.white80}
- source={expanded ? 'icon-chevron-up' : 'icon-chevron-down'}
- height={24}
- />
+ <Icon color={Colors.white80} icon={expanded ? 'chevron-up' : 'chevron-down'} />
</Cell.CellButton>
<Accordion expanded={expanded}>
<CheckboxRow
@@ -358,7 +350,7 @@ function CheckboxRow(props: ICheckboxRowProps) {
return (
<StyledRow onClick={onToggle}>
<StyledCheckbox role="checkbox" aria-label={props.label} aria-checked={props.checked}>
- {props.checked && <ImageView source="icon-tick" width={18} tintColor={Colors.green} />}
+ {props.checked && <Icon icon="checkmark" color={Colors.green} />}
</StyledCheckbox>
<StyledRowTitle aria-hidden $bold={props.$bold}>
{props.label}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ImageView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ImageView.tsx
deleted file mode 100644
index 20ec42236d..0000000000
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ImageView.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, { useMemo } from 'react';
-import styled from 'styled-components';
-
-import { NonTransientProps } from '../lib/types';
-
-export interface IImageViewProps
- extends NonTransientProps<IImageMaskProps, 'tintColor' | 'tintHoverColor'> {
- source: string;
- onClick?: (event: React.MouseEvent) => void;
- className?: string;
-}
-
-interface IImageMaskProps extends React.HTMLAttributes<HTMLElement> {
- width?: number;
- height?: number;
- disabled?: boolean;
- $tintColor?: string;
- $tintHoverColor?: string;
-}
-
-const Wrapper = styled.div({
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
-});
-
-const ImageMask = styled.div<IImageMaskProps>((props) => {
- const maskWidth = props.width ? `${props.width}px` : 'auto';
- const maskHeight = props.height ? `${props.height}px` : 'auto';
- return {
- maskRepeat: 'no-repeat',
- maskSize: `${maskWidth} ${maskHeight}`,
- maskPosition: 'center',
- lineHeight: 0,
- backgroundColor: props.$tintColor,
- '&&:hover': {
- backgroundColor: (!props.disabled && props.$tintHoverColor) || props.$tintColor,
- },
- };
-});
-
-const HiddenImage = styled.img({ visibility: 'hidden' });
-
-export default function ImageView(props: IImageViewProps) {
- const url = props.source.startsWith('data:')
- ? props.source
- : `../../assets/images/${props.source}.svg`;
-
- const style = useMemo(() => ({ WebkitMaskImage: `url('${url}')` }), [url]);
-
- if (props.tintColor) {
- const { source: _source, tintColor, tintHoverColor, ...otherProps } = props;
- return (
- <ImageMask
- style={style}
- $tintColor={tintColor}
- $tintHoverColor={tintHoverColor}
- {...otherProps}>
- <HiddenImage src={url} width={props.width} height={props.height} />
- </ImageMask>
- );
- } else {
- const { source: _source, width, height, ...otherProps } = props;
- return (
- <Wrapper {...otherProps}>
- <img src={url} width={width} height={height} aria-hidden={true} />
- </Wrapper>
- );
- }
-}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/InfoButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/InfoButton.tsx
index 90dd080529..4c4b991829 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/InfoButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/InfoButton.tsx
@@ -1,29 +1,8 @@
import { messages } from '../../shared/gettext';
import { Button, IconButton, IconButtonProps } from '../lib/components';
-import { Colors } from '../lib/foundations';
import { useBoolean } from '../lib/utility-hooks';
-import ImageView from './ImageView';
import { ModalAlert, ModalAlertType } from './Modal';
-interface IInfoIconProps {
- className?: string;
- size?: number;
- tintColor?: string;
- tintHoverColor?: string;
-}
-
-export function InfoIcon(props: IInfoIconProps) {
- return (
- <ImageView
- source="icon-info"
- width={props.size ?? 18}
- tintColor={props.tintColor ?? Colors.white}
- tintHoverColor={props.tintHoverColor ?? Colors.white80}
- className={props.className}
- />
- );
-}
-
export interface InfoButtonProps extends Omit<IconButtonProps, 'icon'> {
title?: string;
message?: string | Array<string>;
@@ -36,11 +15,11 @@ export default function InfoButton({ title, message, children, ...props }: InfoB
return (
<>
<IconButton
- icon="icon-info"
onClick={show}
aria-label={messages.pgettext('accessibility', 'More information')}
- {...props}
- />
+ {...props}>
+ <IconButton.Icon icon="info-circle" />
+ </IconButton>
<ModalAlert
isOpen={isOpen}
title={title}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/Login.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/Login.tsx
index d7a2473389..bbd4a32584 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/Login.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/Login.tsx
@@ -1,5 +1,6 @@
import React, { useCallback } from 'react';
import { sprintf } from 'sprintf-js';
+import styled from 'styled-components';
import { Url } from '../../shared/constants';
import { AccountDataError, AccountNumber } from '../../shared/daemon-rpc-types';
@@ -7,16 +8,16 @@ import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
import { formatAccountNumber } from '../lib/account';
import useActions from '../lib/actionsHook';
-import { Box, Button, Flex, Label, LabelTiny, TitleMedium } from '../lib/components';
+import { Box, Button, Flex, Icon, Label, LabelTiny, Spinner, TitleMedium } from '../lib/components';
import { Colors, Spacings } from '../lib/foundations';
import { formatHtml } from '../lib/html-formatter';
+import { IconBadge } from '../lib/icon-badge';
import accountActions from '../redux/account/actions';
import { LoginState } from '../redux/account/reducers';
import { useSelector } from '../redux/store';
import Accordion from './Accordion';
import { AppMainHeader } from './app-main-header';
import * as AppButton from './AppButton';
-import ImageView from './ImageView';
import { Container, Layout } from './Layout';
import {
StyledAccountDropdownContainer,
@@ -240,28 +241,23 @@ class Login extends React.Component<IProps, IState> {
}
private getStatusIcon() {
- const statusIconPath = this.getStatusIconPath();
- return (
- <StyledStatusIcon>
- {statusIconPath ? <ImageView source={statusIconPath} height={48} width={48} /> : null}
- </StyledStatusIcon>
- );
+ return <StyledStatusIcon>{this.getStatusIconPath()}</StyledStatusIcon>;
}
- private getStatusIconPath(): string | undefined {
+ private getStatusIconPath() {
if (this.props.isPerformingPostUpgrade) {
- return 'icon-spinner';
+ return <Spinner size="big" />;
}
switch (this.props.loginState.type) {
case 'logging in':
- return 'icon-spinner';
+ return <Spinner size="big" />;
case 'failed':
- return 'icon-fail';
+ return <IconBadge state="negative" />;
case 'ok':
- return 'icon-success';
+ return <IconBadge state="positive" />;
default:
- return undefined;
+ return null;
}
}
@@ -353,10 +349,8 @@ class Login extends React.Component<IProps, IState> {
$visible={
this.props.loginState.type !== 'logging in' && !this.props.isPerformingPostUpgrade
}
- source="icon-arrow"
- height={16}
- width={24}
- tintColor="rgb(255, 255, 255)"
+ icon="chevron-right"
+ size="large"
/>
</StyledInputButton>
</StyledAccountInputBackdrop>
@@ -420,6 +414,10 @@ interface AccountDropdownItemProps {
onSelect: (value: AccountNumber) => void;
}
+const StyledIcon = styled(Icon)({
+ backgroundColor: 'rgba(84, 113, 143, 1)',
+});
+
function AccountDropdownItem({ label, onRemove, onSelect, value }: AccountDropdownItemProps) {
const handleSelect = useCallback(() => {
onSelect(value);
@@ -469,7 +467,7 @@ function AccountDropdownItem({ label, onRemove, onSelect, value }: AccountDropdo
accountNumber: label,
},
)}>
- <ImageView source="icon-close" height={16} width={16} />
+ <StyledIcon icon="cross-circle" size="small" />
</StyledAccountDropdownItemIconButton>
</Box>
</Flex>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/LoginStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/LoginStyles.tsx
index ebfe29618d..99d7fd044f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/LoginStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/LoginStyles.tsx
@@ -1,12 +1,11 @@
import styled from 'styled-components';
-import { Colors } from '../lib/foundations';
-import { Spacings } from '../lib/foundations';
+import { Icon } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
import { buttonReset } from '../lib/styles';
import * as Cell from './cell';
import { hugeText, largeText, measurements, smallText, tinyText } from './common-styles';
import FormattableTextInput from './FormattableTextInput';
-import ImageView from './ImageView';
import { Footer } from './Layout';
export const StyledAccountDropdownContainer = styled.ul({
@@ -14,26 +13,7 @@ export const StyledAccountDropdownContainer = styled.ul({
flexDirection: 'column',
});
-export const StyledAccountDropdownRemoveButton = styled.button({
- border: 'none',
- background: 'none',
-});
-
-export const StyledAccountDropdownRemoveIcon = styled(ImageView)({
- justifyContent: 'center',
- paddingTop: '10px',
- paddingRight: '12px',
- paddingBottom: '12px',
- paddingLeft: '12px',
- marginLeft: '0px',
-});
-
-export const StyledInputSubmitIcon = styled(ImageView)<{ $visible: boolean }>((props) => ({
- flex: 0,
- borderWidth: '0px',
- width: '48px',
- alignItems: 'center',
- justifyContent: 'center',
+export const StyledInputSubmitIcon = styled(Icon)<{ $visible: boolean }>((props) => ({
opacity: props.$visible ? 1 : 0,
}));
@@ -144,7 +124,6 @@ export const StyledAccountInputBackdrop = styled.div({
export const StyledInputButton = styled.button<{ $visible: boolean }>((props) => ({
display: 'flex',
- flex: 0,
borderWidth: 0,
width: '48px',
alignItems: 'center',
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/Modal.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/Modal.tsx
index a78105379c..3409ddac14 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/Modal.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/Modal.tsx
@@ -3,13 +3,14 @@ import ReactDOM from 'react-dom';
import styled from 'styled-components';
import log from '../../shared/logging';
+import { Icon, IconProps, Spinner } from '../lib/components';
import { Colors } from '../lib/foundations';
+import { IconBadge } from '../lib/icon-badge';
import { useEffectEvent } from '../lib/utility-hooks';
import { useWillExit } from '../lib/will-exit';
import * as AppButton from './AppButton';
import { measurements, normalText, tinyText } from './common-styles';
import CustomScrollbars from './CustomScrollbars';
-import ImageView from './ImageView';
import { BackAction } from './KeyboardNavigation';
import { SmallButtonGrid } from './SmallButton';
@@ -315,36 +316,30 @@ class ModalAlertImpl extends React.Component<IModalAlertImplProps, IModalAlertSt
};
private renderTypeIcon(type: ModalAlertType) {
- let source = '';
+ let source: IconProps['icon'] | undefined = undefined;
let color = undefined;
switch (type) {
case ModalAlertType.info:
- source = 'icon-info';
+ source = 'info-circle';
color = Colors.white;
break;
case ModalAlertType.caution:
- source = 'icon-alert';
+ source = 'alert-circle';
color = Colors.white;
break;
case ModalAlertType.warning:
- source = 'icon-alert';
+ source = 'alert-circle';
color = Colors.red;
break;
-
case ModalAlertType.loading:
- source = 'icon-spinner';
- break;
+ return <Spinner size="big" />;
case ModalAlertType.success:
- source = 'icon-success';
- break;
+ return <IconBadge state="positive" />;
case ModalAlertType.failure:
- source = 'icon-fail';
- break;
+ return <IconBadge state="negative" />;
}
- return (
- <ImageView height={44} width={44} source={source} tintColor={this.props.iconColor ?? color} />
- );
+ return <Icon size="big" icon={source} color={color} />;
}
private onTransitionEnd = (event: React.TransitionEvent<HTMLDivElement>) => {
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/NotificationBanner.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/NotificationBanner.tsx
index d2496447ed..9ce77d8e78 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/NotificationBanner.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/NotificationBanner.tsx
@@ -3,12 +3,11 @@ import styled from 'styled-components';
import { messages } from '../../shared/gettext';
import { InAppNotificationIndicatorType } from '../../shared/notifications/notification';
-import { IconButton } from '../lib/components';
+import { Icon, IconButton } from '../lib/components';
import { Colors } from '../lib/foundations';
import { useEffectEvent, useLastDefinedValue, useStyledRef } from '../lib/utility-hooks';
import * as AppButton from './AppButton';
import { tinyText } from './common-styles';
-import ImageView from './ImageView';
const NOTIFICATION_AREA_ID = 'notification-area';
@@ -37,7 +36,7 @@ export const NotificationActionButton = styled(AppButton.SimpleButton)({
border: 'none',
});
-export const NotificationActionButtonInner = styled(ImageView)({
+export const NotificationActionButtonInner = styled(Icon)({
[NotificationActionButton + ':hover &&']: {
backgroundColor: Colors.white80,
},
@@ -53,12 +52,7 @@ export function NotificationOpenLinkAction(props: NotificationActionProps) {
<NotificationActionButton
aria-describedby={NOTIFICATION_AREA_ID}
aria-label={messages.gettext('Open URL')}>
- <NotificationActionButtonInner
- height={12}
- width={12}
- tintColor={Colors.white60}
- source="icon-extLink"
- />
+ <NotificationActionButtonInner size="small" icon="external" color={Colors.white60} />
</NotificationActionButton>
</AppButton.BlockingButton>
);
@@ -70,12 +64,7 @@ export function NotificationTroubleshootDialogAction(props: NotificationActionPr
aria-describedby={NOTIFICATION_AREA_ID}
aria-label={messages.gettext('Troubleshoot')}
onClick={props.onClick}>
- <NotificationActionButtonInner
- height={12}
- width={12}
- tintColor={Colors.white60}
- source="icon-info"
- />
+ <NotificationActionButtonInner size="small" icon="info-circle" />
</NotificationActionButton>
);
}
@@ -84,12 +73,12 @@ export function NotificationCloseAction(props: NotificationActionProps) {
return (
<IconButton
aria-describedby={NOTIFICATION_AREA_ID}
+ variant="secondary"
aria-label={messages.pgettext('accessibility', 'Close notification')}
onClick={props.onClick}
- icon="icon-close"
- size="small"
- variant="secondary"
- />
+ size="small">
+ <IconButton.Icon icon="cross-circle" />
+ </IconButton>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/PageSlider.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/PageSlider.tsx
index 422bec3d50..897297a243 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/PageSlider.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/PageSlider.tsx
@@ -2,9 +2,9 @@ import { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import { NonEmptyArray } from '../../shared/utils';
+import { IconButton } from '../lib/components';
import { Colors } from '../lib/foundations';
import { useStyledRef } from '../lib/utility-hooks';
-import { Icon } from './cell';
const PAGE_GAP = 16;
@@ -160,18 +160,6 @@ const StyledPageIndicator = styled.div<{ $current: boolean }>((props) => ({
},
}));
-const StyledArrow = styled(Icon)((props) => ({
- backgroundColor: props.disabled ? Colors.white20 : props.tintColor,
-
- [`${StyledTransparentButton}:hover &&`]: {
- backgroundColor: props.disabled ? Colors.white20 : props.tintHoverColor,
- },
-}));
-
-const StyledLeftArrow = styled(StyledArrow)({
- transform: 'scaleX(-100%)',
-});
-
interface ControlsProps {
pageNumber: number;
numberOfPages: number;
@@ -197,26 +185,12 @@ function Controls(props: ControlsProps) {
))}
</StyledPageIndicators>
<StyledArrows>
- <StyledTransparentButton onClick={props.prev}>
- <StyledLeftArrow
- disabled={!props.hasPrev}
- height={12}
- width={7}
- source="icon-chevron"
- tintColor={Colors.white}
- tintHoverColor={Colors.white60}
- />
- </StyledTransparentButton>
- <StyledTransparentButton onClick={props.next}>
- <StyledArrow
- disabled={!props.hasNext}
- height={12}
- width={7}
- source="icon-chevron"
- tintColor={Colors.white}
- tintHoverColor={Colors.white60}
- />
- </StyledTransparentButton>
+ <IconButton disabled={!props.hasPrev} onClick={props.prev}>
+ <IconButton.Icon icon="chevron-left" />
+ </IconButton>
+ <IconButton disabled={!props.hasNext} onClick={props.next}>
+ <IconButton.Icon icon="chevron-right" />
+ </IconButton>
</StyledArrows>
</StyledControlsContainer>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ProblemReport.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ProblemReport.tsx
index e4213d871f..86064e1fd7 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/ProblemReport.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/ProblemReport.tsx
@@ -16,14 +16,16 @@ import { messages } from '../../shared/gettext';
import { getDownloadUrl } from '../../shared/version';
import { useAppContext } from '../context';
import useActions from '../lib/actionsHook';
+import { Flex, Icon, Spinner } from '../lib/components';
+import { Spacings } from '../lib/foundations';
import { useHistory } from '../lib/history';
+import { IconBadge } from '../lib/icon-badge';
import { useEffectEvent } from '../lib/utility-hooks';
import { useSelector } from '../redux/store';
import support from '../redux/support/actions';
import { AppNavigationHeader } from './';
import * as AppButton from './AppButton';
import { AriaDescribed, AriaDescription, AriaDescriptionGroup } from './AriaGroup';
-import ImageView from './ImageView';
import { BackAction } from './KeyboardNavigation';
import { Footer, Layout, SettingsContainer } from './Layout';
import { ModalAlert, ModalAlertType } from './Modal';
@@ -187,10 +189,8 @@ function Form() {
{messages.pgettext('support-view', 'View app logs')}
</AppButton.Label>
<AriaDescription>
- <AppButton.Icon
- source="icon-extLink"
- height={16}
- width={16}
+ <Icon
+ icon="external"
aria-label={messages.pgettext('accessibility', 'Opens externally')}
/>
</AriaDescription>
@@ -211,7 +211,7 @@ function Sending() {
<StyledContent>
<StyledForm>
<StyledStatusIcon>
- <ImageView source="icon-spinner" height={60} width={60} />
+ <Spinner size="big" />
</StyledStatusIcon>
<StyledSendStatus>{messages.pgettext('support-view', 'Sending...')}</StyledSendStatus>
</StyledForm>
@@ -234,9 +234,11 @@ function Sent() {
return (
<StyledContent>
<StyledForm>
- <StyledStatusIcon>
- <ImageView source="icon-success" height={60} width={60} />
- </StyledStatusIcon>
+ <Flex
+ $justifyContent="center"
+ $margin={{ top: Spacings.spacing6, bottom: Spacings.spacing5 }}>
+ <IconBadge state="positive" />
+ </Flex>
<StyledSendStatus>{messages.pgettext('support-view', 'Sent')}</StyledSendStatus>
<StyledSentMessage>
@@ -259,9 +261,11 @@ function Failed() {
return (
<StyledContent>
<StyledForm>
- <StyledStatusIcon>
- <ImageView source="icon-fail" height={60} width={60} />
- </StyledStatusIcon>
+ <Flex
+ $justifyContent="center"
+ $margin={{ top: Spacings.spacing6, bottom: Spacings.spacing5 }}>
+ <IconBadge state="negative" />
+ </Flex>
<StyledSendStatus>{messages.pgettext('support-view', 'Failed to send')}</StyledSendStatus>
<StyledSentMessage>
{messages.pgettext(
@@ -353,10 +357,8 @@ function OutdatedVersionWarningDialog() {
<AppButton.GreenButton disabled={isOffline} onClick={openDownloadLink}>
<AppButton.Label>{messages.pgettext('support-view', 'Upgrade app')}</AppButton.Label>
<AriaDescription>
- <AppButton.Icon
- height={16}
- width={16}
- source="icon-extLink"
+ <Icon
+ icon="external"
aria-label={messages.pgettext('accessibility', 'Opens externally')}
/>
</AriaDescription>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx
index c88d68a087..d39f6ce1d3 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucher.tsx
@@ -6,9 +6,11 @@ import { VoucherResponse } from '../../shared/daemon-rpc-types';
import { formatRelativeDate } from '../../shared/date-helper';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
+import { Flex, Spinner } from '../lib/components';
+import { Spacings } from '../lib/foundations';
+import { IconBadge } from '../lib/icon-badge';
import { useSelector } from '../redux/store';
import * as AppButton from './AppButton';
-import ImageView from './ImageView';
import { ModalAlert } from './Modal';
import {
StyledEmptyResponse,
@@ -16,9 +18,6 @@ import {
StyledInput,
StyledLabel,
StyledProgressResponse,
- StyledProgressWrapper,
- StyledSpinner,
- StyledStatusIcon,
StyledTitle,
} from './RedeemVoucherStyles';
@@ -154,14 +153,12 @@ export function RedeemVoucherResponse() {
if (submitting) {
return (
- <>
- <StyledProgressWrapper>
- <StyledSpinner source="icon-spinner" height={20} width={20} />
- <StyledProgressResponse>
- {messages.pgettext('redeem-voucher-view', 'Verifying voucher...')}
- </StyledProgressResponse>
- </StyledProgressWrapper>
- </>
+ <Flex $alignItems="center" $margin={{ top: Spacings.spacing3 }} $gap={Spacings.spacing3}>
+ <Spinner size="medium" />
+ <StyledProgressResponse>
+ {messages.pgettext('redeem-voucher-view', 'Verifying voucher...')}
+ </StyledProgressResponse>
+ </Flex>
);
}
@@ -229,9 +226,11 @@ export function RedeemVoucherAlert(props: IRedeemVoucherAlertProps) {
</AppButton.BlueButton>,
]}
close={props.onClose}>
- <StyledStatusIcon>
- <ImageView source="icon-success" height={60} width={60} />
- </StyledStatusIcon>
+ <Flex
+ $justifyContent="center"
+ $margin={{ top: Spacings.spacing6, bottom: Spacings.spacing5 }}>
+ <IconBadge state="positive" />
+ </Flex>
<StyledTitle>
{messages.pgettext('redeem-voucher-view', 'Voucher was successfully redeemed.')}
</StyledTitle>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx
index 93d39a57df..6dc538c3b3 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/RedeemVoucherStyles.tsx
@@ -3,7 +3,6 @@ import styled from 'styled-components';
import { Colors } from '../lib/foundations';
import { normalText, smallText, tinyText } from './common-styles';
import FormattableTextInput from './FormattableTextInput';
-import ImageView from './ImageView';
export const StyledLabel = styled.span(smallText, {
color: Colors.white,
@@ -31,12 +30,6 @@ export const StyledResponse = styled.span(tinyText, {
color: Colors.white,
});
-export const StyledProgressWrapper = styled.div({
- display: 'flex',
- alignItems: 'center',
- marginTop: '8px',
-});
-
export const StyledProgressResponse = styled(StyledResponse)({
marginTop: 0,
});
@@ -50,18 +43,6 @@ export const StyledEmptyResponse = styled.span({
marginTop: '8px',
});
-export const StyledSpinner = styled(ImageView)({
- marginRight: '8px',
-});
-
-export const StyledStatusIcon = styled.div({
- alignSelf: 'center',
- width: '60px',
- height: '60px',
- marginBottom: '18px',
- marginTop: '25px',
-});
-
export const StyledTitle = styled.span(smallText, {
lineHeight: '22px',
fontWeight: 400,
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/RelayStatusIndicator.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/RelayStatusIndicator.tsx
index 97fb6471b1..6c15358b01 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/RelayStatusIndicator.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/RelayStatusIndicator.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components';
import { Styles } from 'styled-components/dist/types';
-import { Colors } from '../lib/foundations';
+import { Colors, Spacings } from '../lib/foundations';
import * as Cell from './cell';
const indicatorStyles: Styles<
@@ -17,9 +17,9 @@ const StyledRelayStatus = styled.div<{ $active: boolean }>(indicatorStyles, (pro
backgroundColor: props.$active ? Colors.green90 : Colors.red95,
}));
-const TickIcon = styled(Cell.Icon)({
+const TickIcon = styled(Cell.CellIcon)({
marginLeft: '3px',
- marginRight: '8px',
+ marginRight: Spacings.spacing3,
});
interface IProps {
@@ -29,7 +29,7 @@ interface IProps {
export default function RelayStatusIndicator(props: IProps) {
return props.selected ? (
- <TickIcon tintColor={Colors.white} source="icon-tick" width={18} />
+ <TickIcon color={Colors.white} icon="checkmark" />
) : (
<StyledRelayStatus $active={props.active} />
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/SearchBar.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/SearchBar.tsx
index dc9810e299..5d4a672676 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/SearchBar.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/SearchBar.tsx
@@ -2,10 +2,10 @@ import { useCallback, useEffect } from 'react';
import styled from 'styled-components';
import { messages } from '../../shared/gettext';
+import { Icon, IconButton } from '../lib/components';
import { Colors } from '../lib/foundations';
import { useEffectEvent, useStyledRef } from '../lib/utility-hooks';
import { normalText } from './common-styles';
-import ImageView from './ImageView';
export const StyledSearchContainer = styled.div({
position: 'relative',
@@ -34,38 +34,27 @@ export const StyledSearchInput = styled.input.attrs({ type: 'text' })({
},
});
-export const StyledClearButton = styled.button({
+// TODO: The focus styling can be removed once we implement the new colors from foundations
+export const StyledClearButton = styled(IconButton)({
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
right: '9px',
- border: 'none',
- background: 'none',
- padding: 0,
+ [`${StyledSearchInput}:focus ~ && > div`]: {
+ backgroundColor: Colors.blue40,
+ },
});
-export const StyledSearchIcon = styled(ImageView)({
+export const StyledSearchIcon = styled(Icon)({
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
- left: '9px',
+ left: '8px',
[`${StyledSearchInput}:focus ~ &&`]: {
backgroundColor: Colors.blue,
},
});
-export const StyledClearIcon = styled(ImageView)({
- '&&:hover': {
- backgroundColor: Colors.white60,
- },
- [`${StyledSearchInput}:focus ~ ${StyledClearButton} &&`]: {
- backgroundColor: Colors.blue40,
- },
- [`${StyledSearchInput}:focus ~ ${StyledClearButton} &&:hover`]: {
- backgroundColor: Colors.blue,
- },
-});
-
interface ISearchBarProps {
searchTerm: string;
onSearch: (searchTerm: string) => void;
@@ -107,10 +96,10 @@ export default function SearchBar(props: ISearchBarProps) {
onInput={onInput}
placeholder={messages.gettext('Search for...')}
/>
- <StyledSearchIcon source="icon-search" width={24} tintColor={Colors.white60} />
+ <StyledSearchIcon icon="search" color={Colors.white60} />
{props.searchTerm.length > 0 && (
- <StyledClearButton onClick={onClear}>
- <StyledClearIcon source="icon-close" width={18} tintColor={Colors.white40} />
+ <StyledClearButton variant="secondary" onClick={onClear}>
+ <IconButton.Icon icon="cross-circle" />
</StyledClearButton>
)}
</StyledSearchContainer>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/SettingsImport.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/SettingsImport.tsx
index 03c0696705..2d1580863f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/SettingsImport.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/SettingsImport.tsx
@@ -6,8 +6,8 @@ import { messages } from '../../shared/gettext';
import { useScheduler } from '../../shared/scheduler';
import { useAppContext } from '../context';
import useActions from '../lib/actionsHook';
-import { Flex } from '../lib/components';
-import { Colors } from '../lib/foundations';
+import { Flex, Icon, IconProps } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
import { transitions, useHistory } from '../lib/history';
import { RoutePath } from '../lib/routes';
import { useBoolean, useEffectEvent } from '../lib/utility-hooks';
@@ -15,7 +15,6 @@ import settingsImportActions from '../redux/settings-import/actions';
import { useSelector } from '../redux/store';
import { AppNavigationHeader } from './';
import { measurements, normalText, tinyText } from './common-styles';
-import ImageView from './ImageView';
import { BackAction } from './KeyboardNavigation';
import { Footer, Layout, SettingsContainer } from './Layout';
import { ModalAlert, ModalAlertType } from './Modal';
@@ -208,10 +207,7 @@ const StyledStatusTitle = styled.div(normalText, {
fontWeight: 'bold',
lineHeight: '20px',
color: Colors.white,
-});
-
-const StyledStatusImage = styled(ImageView)({
- margin: '5px',
+ gap: Spacings.spacing1,
});
const StyledStatusSubTitle = styled.div(tinyText, {
@@ -236,10 +232,15 @@ function SettingsImportStatus(props: ImportStatusProps) {
title = messages.pgettext('settings-import', 'NO OVERRIDES IMPORTED');
}
- let icon = undefined;
+ let iconProps: Pick<IconProps, 'icon' | 'color'> | undefined = undefined;
let subtitle;
if (props.status !== undefined) {
- icon = props.status.successful ? 'icon-checkmark' : 'icon-cross';
+ iconProps = props.status.successful
+ ? {
+ icon: 'checkmark',
+ color: Colors.green,
+ }
+ : { icon: 'cross', color: Colors.red };
if (props.status.successful) {
subtitle =
@@ -276,7 +277,7 @@ function SettingsImportStatus(props: ImportStatusProps) {
<StyledStatusContainer>
<StyledStatusTitle data-testid="status-title">
{title}
- {icon !== undefined && <StyledStatusImage source={icon} width={13} />}
+ {iconProps !== undefined && <Icon {...iconProps} size="medium" />}
</StyledStatusTitle>
{subtitle !== undefined && (
<StyledStatusSubTitle data-testid="status-subtitle">{subtitle}</StyledStatusSubTitle>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/SettingsTextImport.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/SettingsTextImport.tsx
index baccb60f42..70d774d702 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/SettingsTextImport.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/SettingsTextImport.tsx
@@ -3,6 +3,7 @@ import styled from 'styled-components';
import { messages } from '../../shared/gettext';
import useActions from '../lib/actionsHook';
+import { IconButton } from '../lib/components';
import { Colors } from '../lib/foundations';
import { useHistory } from '../lib/history';
import { useCombinedRefs, useRefCallback, useStyledRef } from '../lib/utility-hooks';
@@ -59,11 +60,9 @@ export default function SettingsTextImport() {
messages.pgettext('settings-import', 'Import via text')
}
titleVisible>
- <AppNavigationHeader.IconButton
- icon="icon-check"
- onClick={save}
- aria-label={messages.gettext('Save')}
- />
+ <AppNavigationHeader.IconButton onClick={save} aria-label={messages.gettext('Save')}>
+ <IconButton.Icon icon="checkmark" />
+ </AppNavigationHeader.IconButton>
</AppNavigationHeader>
<StyledTextArea ref={combinedTextAreaRef} />
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettings.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettings.tsx
index 1fba8b4d53..c80d7a1276 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettings.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettings.tsx
@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { sprintf } from 'sprintf-js';
+import styled from 'styled-components';
import {
IApplication,
@@ -10,7 +11,7 @@ import {
import { strings } from '../../shared/constants';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
-import { Button, Container, Flex, FootnoteMini } from '../lib/components';
+import { Button, Container, Flex, FootnoteMini, IconButton, Spinner } from '../lib/components';
import { Colors, Spacings } from '../lib/foundations';
import { useHistory } from '../lib/history';
import { formatHtml } from '../lib/html-formatter';
@@ -22,7 +23,6 @@ import * as AppButton from './AppButton';
import * as Cell from './cell';
import { measurements } from './common-styles';
import { CustomScrollbarsRef } from './CustomScrollbars';
-import ImageView from './ImageView';
import { BackAction } from './KeyboardNavigation';
import { Layout, SettingsContainer } from './Layout';
import List from './List';
@@ -30,7 +30,6 @@ import { ModalAlert, ModalAlertType } from './Modal';
import { NavigationContainer } from './NavigationContainer';
import SettingsHeader, { HeaderSubTitle, HeaderTitle } from './SettingsHeader';
import {
- StyledActionIcon,
StyledBrowseButton,
StyledCellButton,
StyledCellLabel,
@@ -171,9 +170,6 @@ function LinuxSplitTunnelingSettings(props: IPlatformSplitTunnelingSettingsProps
</SettingsHeader>
<StyledSearchBar searchTerm={searchTerm} onSearch={setSearchTerm} />
- {filteredApplications !== undefined && filteredApplications.length > 0 && (
- <ApplicationList applications={filteredApplications} rowRenderer={rowRenderer} />
- )}
{searchTerm !== '' &&
(filteredApplications === undefined || filteredApplications.length === 0) && (
@@ -187,9 +183,15 @@ function LinuxSplitTunnelingSettings(props: IPlatformSplitTunnelingSettingsProps
</StyledNoResult>
)}
- <StyledBrowseButton onClick={launchWithFilePicker}>
- {messages.pgettext('split-tunneling-view', 'Find another app')}
- </StyledBrowseButton>
+ <Flex $flexDirection="column" $gap={Spacings.spacing5}>
+ {filteredApplications !== undefined && filteredApplications.length > 0 && (
+ <ApplicationList applications={filteredApplications} rowRenderer={rowRenderer} />
+ )}
+
+ <StyledBrowseButton onClick={launchWithFilePicker}>
+ {messages.pgettext('split-tunneling-view', 'Find another app')}
+ </StyledBrowseButton>
+ </Flex>
<ModalAlert
isOpen={browseError !== undefined}
@@ -285,7 +287,7 @@ function LinuxApplicationRow(props: ILinuxApplicationRowProps) {
)}
<StyledCellLabel $lookDisabled={disabled}>{props.application.name}</StyledCellLabel>
{props.application.warning && (
- <StyledCellWarningIcon source="icon-alert" tintColor={warningColor} width={18} />
+ <StyledCellWarningIcon icon="alert-circle" color={warningColor} />
)}
</StyledCellButton>
<ModalAlert
@@ -485,7 +487,7 @@ export function SplitTunnelingSettings(props: IPlatformSplitTunnelingSettingsPro
</SettingsHeader>
{loadingDiskPermissions && (
<Flex $justifyContent="center" $margin={{ top: Spacings.spacing6 }}>
- <ImageView source="icon-spinner" height={48} />
+ <Spinner size="big" />
</Flex>
)}
@@ -493,45 +495,44 @@ export function SplitTunnelingSettings(props: IPlatformSplitTunnelingSettingsPro
<StyledSearchBar searchTerm={searchTerm} onSearch={setSearchTerm} />
)}
+ {canEditSplitTunneling && searchTerm !== '' && !showSplitSection && !showNonSplitSection && (
+ <StyledNoResult>
+ <StyledNoResultText>
+ {formatHtml(
+ sprintf(messages.gettext('No result for <b>%(searchTerm)s</b>.'), { searchTerm }),
+ )}
+ </StyledNoResultText>
+ <StyledNoResultText>{messages.gettext('Try a different search.')}</StyledNoResultText>
+ </StyledNoResult>
+ )}
+
<Flex
$flexDirection="column"
- $gap={Spacings.spacing6}
+ $gap={Spacings.spacing5}
$margin={{ bottom: measurements.verticalViewMargin }}>
- <Flex $flexDirection="column" $gap={Spacings.spacing5}>
- <Accordion expanded={showSplitSection}>
- <Cell.Section sectionTitle={excludedTitle}>
- <ApplicationList
- data-testid="split-applications"
- applications={filteredSplitApplications}
- rowRenderer={excludedRowRenderer}
- />
- </Cell.Section>
- </Accordion>
-
- <Accordion expanded={showNonSplitSection}>
- <Cell.Section sectionTitle={allTitle}>
- <ApplicationList
- data-testid="non-split-applications"
- applications={filteredNonSplitApplications}
- rowRenderer={includedRowRenderer}
- />
- </Cell.Section>
- </Accordion>
- </Flex>
+ {(showSplitSection || showNonSplitSection) && (
+ <Flex $flexDirection="column" $gap={Spacings.spacing5}>
+ <Accordion expanded={showSplitSection}>
+ <Cell.Section sectionTitle={excludedTitle}>
+ <ApplicationList
+ data-testid="split-applications"
+ applications={filteredSplitApplications}
+ rowRenderer={excludedRowRenderer}
+ />
+ </Cell.Section>
+ </Accordion>
- {canEditSplitTunneling &&
- searchTerm !== '' &&
- !showSplitSection &&
- !showNonSplitSection && (
- <StyledNoResult>
- <StyledNoResultText>
- {formatHtml(
- sprintf(messages.gettext('No result for <b>%(searchTerm)s</b>.'), { searchTerm }),
- )}
- </StyledNoResultText>
- <StyledNoResultText>{messages.gettext('Try a different search.')}</StyledNoResultText>
- </StyledNoResult>
- )}
+ <Accordion expanded={showNonSplitSection}>
+ <Cell.Section sectionTitle={allTitle}>
+ <ApplicationList
+ data-testid="non-split-applications"
+ applications={filteredNonSplitApplications}
+ rowRenderer={includedRowRenderer}
+ />
+ </Cell.Section>
+ </Accordion>
+ </Flex>
+ )}
{canEditSplitTunneling && (
<Container size="3">
@@ -592,10 +593,10 @@ interface IApplicationListProps<T extends IApplication> {
}
function ApplicationList<T extends IApplication>(props: IApplicationListProps<T>) {
- if (props.applications === undefined) {
+ if (props.applications == undefined) {
return (
<StyledSpinnerRow>
- <ImageView source="icon-spinner" height={60} width={60} />
+ <Spinner size="big" />
</StyledSpinnerRow>
);
} else {
@@ -616,6 +617,10 @@ function applicationGetKey<T extends IApplication>(application: T): string {
return application.absolutepath;
}
+const StyledContainer = styled(Cell.Container)({
+ backgroundColor: Colors.blue40,
+});
+
interface IApplicationRowProps {
application: ISplitTunnelingApplication;
onAdd?: (application: ISplitTunnelingApplication) => void;
@@ -639,41 +644,31 @@ function ApplicationRow(props: IApplicationRowProps) {
}, [propsOnDelete, props.application]);
return (
- <Cell.CellButton>
+ <StyledContainer>
{props.application.icon ? (
<StyledIcon source={props.application.icon} width={35} height={35} />
) : (
<StyledIconPlaceholder />
)}
<StyledCellLabel>{props.application.name}</StyledCellLabel>
- {props.onDelete && (
- <StyledActionIcon
- source="icon-close"
- width={18}
- onClick={onDelete}
- tintColor={Colors.white40}
- tintHoverColor={Colors.white60}
- />
- )}
- {props.onAdd && (
- <StyledActionIcon
- source="icon-add"
- width={18}
- onClick={onAdd}
- tintColor={Colors.white40}
- tintHoverColor={Colors.white60}
- />
- )}
- {props.onRemove && (
- <StyledActionIcon
- source="icon-remove"
- width={18}
- onClick={onRemove}
- tintColor={Colors.white40}
- tintHoverColor={Colors.white60}
- />
- )}
- </Cell.CellButton>
+ <Flex $gap={Spacings.spacing3}>
+ {props.onDelete && (
+ <IconButton variant="secondary" onClick={onDelete}>
+ <IconButton.Icon icon="cross-circle" />
+ </IconButton>
+ )}
+ {props.onAdd && (
+ <IconButton variant="secondary" onClick={onAdd}>
+ <IconButton.Icon icon="add-circle" />
+ </IconButton>
+ )}
+ {props.onRemove && (
+ <IconButton variant="secondary" onClick={onRemove}>
+ <IconButton.Icon icon="remove-circle" />
+ </IconButton>
+ )}
+ </Flex>
+ </StyledContainer>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettingsStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettingsStyles.tsx
index af8b55e243..a2a8160b93 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettingsStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/SplitTunnelingSettingsStyles.tsx
@@ -4,7 +4,6 @@ import { Colors, Spacings } from '../lib/foundations';
import * as AppButton from './AppButton';
import * as Cell from './cell';
import { measurements, normalText } from './common-styles';
-import ImageView from './ImageView';
import { NavigationScrollbars } from './NavigationScrollbars';
import SearchBar from './SearchBar';
import { SmallButton } from './SmallButton';
@@ -38,15 +37,11 @@ const disabledApplication = (props: DisabledApplicationProps) => ({
opacity: props.$lookDisabled ? 0.6 : undefined,
});
-export const StyledIcon = styled(Cell.UntintedIcon)<DisabledApplicationProps>(disabledApplication, {
+export const StyledIcon = styled(Cell.CellImage)<DisabledApplicationProps>(disabledApplication, {
marginRight: Spacings.spacing4,
});
-export const StyledActionIcon = styled(ImageView)({
- marginLeft: Spacings.spacing3,
-});
-
-export const StyledCellWarningIcon = styled(Cell.Icon)({
+export const StyledCellWarningIcon = styled(Cell.CellTintedIcon)({
marginLeft: Spacings.spacing3,
marginRight: Spacings.spacing1,
});
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/Support.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/Support.tsx
index a5c29ae453..7eb86d974b 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/Support.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/Support.tsx
@@ -99,10 +99,8 @@ function FaqButton() {
}
</Cell.Label>
<AriaDescription>
- <Cell.Icon
- height={16}
- width={16}
- source="icon-extLink"
+ <Cell.CellTintedIcon
+ icon="external"
aria-label={messages.pgettext('accessibility', 'Opens externally')}
/>
</AriaDescription>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/TooManyDevices.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/TooManyDevices.tsx
index ed797ead33..ce1f4f3fd1 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/TooManyDevices.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/TooManyDevices.tsx
@@ -7,9 +7,11 @@ import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
import { capitalizeEveryWord } from '../../shared/string-helpers';
import { useAppContext } from '../context';
-import { Colors } from '../lib/foundations';
+import { Button, Flex, IconButton, Spinner } from '../lib/components';
+import { Colors, Spacings } from '../lib/foundations';
import { transitions, useHistory } from '../lib/history';
import { formatHtml } from '../lib/html-formatter';
+import { IconBadge, IconBadgeProps } from '../lib/icon-badge';
import { RoutePath } from '../lib/routes';
import { useBoolean } from '../lib/utility-hooks';
import { useSelector } from '../redux/store';
@@ -18,7 +20,6 @@ import * as AppButton from './AppButton';
import * as Cell from './cell';
import { bigText, measurements, normalText, tinyText } from './common-styles';
import CustomScrollbars from './CustomScrollbars';
-import ImageView from './ImageView';
import { Footer, Layout, SettingsContainer } from './Layout';
import List from './List';
import { ModalAlert, ModalAlertType, ModalContainer, ModalMessage } from './Modal';
@@ -28,7 +29,6 @@ const StyledCustomScrollbars = styled(CustomScrollbars)({
});
const StyledContainer = styled(SettingsContainer)({
- paddingTop: '14px',
minHeight: '100%',
});
@@ -39,13 +39,6 @@ const StyledBody = styled.div({
paddingBottom: 'auto',
});
-const StyledStatusIcon = styled.div({
- alignSelf: 'center',
- width: '60px',
- height: '60px',
- marginBottom: '18px',
-});
-
const StyledTitle = styled.span(bigText, {
lineHeight: '38px',
margin: `0 ${measurements.horizontalViewMargin} 8px`,
@@ -84,14 +77,6 @@ const StyledDeviceDate = styled.span(tinyText, {
color: Colors.white60,
});
-const StyledRemoveDeviceButton = styled.button({
- cursor: 'default',
- padding: 0,
- marginLeft: 8,
- backgroundColor: 'transparent',
- border: 'none',
-});
-
export default function TooManyDevices() {
const { reset } = useHistory();
const { removeDevice, login, cancelLogin } = useAppContext();
@@ -115,7 +100,7 @@ export default function TooManyDevices() {
reset(RoutePath.login, { transition: transitions.pop });
}, [reset, cancelLogin]);
- const iconSource = getIconSource(devices);
+ const imageSource = getIconSource(devices);
const title = getTitle(devices);
const subtitle = getSubtitle(devices);
@@ -130,9 +115,11 @@ export default function TooManyDevices() {
<StyledCustomScrollbars fillContainer>
<StyledContainer>
<StyledBody>
- <StyledStatusIcon>
- <ImageView key={iconSource} source={iconSource} height={60} width={60} />
- </StyledStatusIcon>
+ <Flex
+ $justifyContent="center"
+ $margin={{ top: Spacings.spacing6, bottom: Spacings.spacing5 }}>
+ <IconBadge key={imageSource} state={imageSource} />
+ </Flex>
{devices !== undefined && (
<>
<StyledTitle data-testid="title">{title}</StyledTitle>
@@ -145,15 +132,16 @@ export default function TooManyDevices() {
{devices !== undefined && (
<Footer>
<AppButton.ButtonGroup>
- <AppButton.GreenButton onClick={continueLogin} disabled={continueButtonDisabled}>
+ <Button
+ variant="success"
+ onClick={continueLogin}
+ disabled={continueButtonDisabled}>
{
// TRANSLATORS: Button for continuing login process.
messages.pgettext('device-management', 'Continue with login')
}
- </AppButton.GreenButton>
- <AppButton.BlueButton onClick={cancel}>
- {messages.gettext('Back')}
- </AppButton.BlueButton>
+ </Button>
+ <Button onClick={cancel}>{messages.gettext('Back')}</Button>
</AppButton.ButtonGroup>
</Footer>
)}
@@ -197,7 +185,7 @@ function Device(props: IDeviceProps) {
const handleError = useCallback(
async (error: Error) => {
- log.error(`Failede to remove device: ${error.message}`);
+ log.error(`Failed to remove device: ${error.message}`);
let devices: Array<IDevice> | undefined = undefined;
try {
@@ -246,9 +234,10 @@ function Device(props: IDeviceProps) {
</StyledDeviceDate>
</StyledDeviceInfo>
{deleting ? (
- <ImageView source="icon-spinner" width={24} />
+ <Spinner />
) : (
- <StyledRemoveDeviceButton
+ <IconButton
+ variant="secondary"
onClick={showConfirmation}
aria-label={sprintf(
// TRANSLATORS: Button action description provided to accessibility tools such as screen
@@ -258,14 +247,8 @@ function Device(props: IDeviceProps) {
messages.pgettext('accessibility', 'Remove device named %(deviceName)s'),
{ deviceName: props.device.name },
)}>
- <ImageView
- source="icon-close"
- width={18}
- height={18}
- tintColor={Colors.white40}
- tintHoverColor={Colors.white60}
- />
- </StyledRemoveDeviceButton>
+ <IconButton.Icon icon="cross-circle" />
+ </IconButton>
)}
</Cell.Container>
<ModalAlert
@@ -316,15 +299,11 @@ function Device(props: IDeviceProps) {
);
}
-function getIconSource(devices?: Array<IDevice>): string {
- if (devices) {
- if (devices.length === 5) {
- return 'icon-fail';
- } else {
- return 'icon-success';
- }
+function getIconSource(devices: Array<IDevice>): IconBadgeProps['state'] {
+ if (devices.length === 5) {
+ return 'negative';
} else {
- return 'icon-spinner';
+ return 'positive';
}
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/UserInterfaceSettings.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/UserInterfaceSettings.tsx
index 13c29a7ea7..b92c1a38f0 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/UserInterfaceSettings.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/UserInterfaceSettings.tsx
@@ -250,7 +250,7 @@ function LanguageButton() {
return (
<Cell.CellNavigationButton onClick={navigate}>
<LabelStack>
- <Cell.UntintedIcon width={24} height={24} source="icon-language" />
+ <Cell.CellImage source="icon-language" />
<Cell.Label>
{
// TRANSLATORS: Navigation button to the 'Language' settings view
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderAccountButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderAccountButton.tsx
index f66ba6d17f..7eee31e980 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderAccountButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderAccountButton.tsx
@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { messages } from '../../../../shared/gettext';
-import { IconButtonProps, MainHeader } from '../../../lib/components';
+import { IconButton, IconButtonProps, MainHeader } from '../../../lib/components';
import { transitions, useHistory } from '../../../lib/history';
import { RoutePath } from '../../../lib/routes';
import { useSelector } from '../../../redux/store';
@@ -22,11 +22,11 @@ export const AppMainHeaderBarAccountButton = (props: MainHeaderBarAccountButtonP
return (
<MainHeader.IconButton
- icon="icon-account"
onClick={openAccount}
data-testid="account-button"
aria-label={messages.gettext('Account settings')}
- {...props}
- />
+ {...props}>
+ <IconButton.Icon icon="account-circle" />
+ </MainHeader.IconButton>
);
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderSettingsButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderSettingsButton.tsx
index d738f502a3..f7bb352b04 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderSettingsButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/app-main-header/components/AppMainHeaderSettingsButton.tsx
@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { messages } from '../../../../shared/gettext';
-import { IconButtonProps, MainHeader } from '../../../lib/components';
+import { IconButton, IconButtonProps, MainHeader } from '../../../lib/components';
import { transitions, useHistory } from '../../../lib/history';
import { RoutePath } from '../../../lib/routes';
@@ -17,10 +17,8 @@ export function AppMainHeaderSettingsButton(props: MainHeaderSettingsButtonProps
}, [history, props.disabled]);
return (
- <MainHeader.IconButton
- icon="icon-settings"
- onClick={openSettings}
- aria-label={messages.gettext('Settings')}
- />
+ <MainHeader.IconButton onClick={openSettings} aria-label={messages.gettext('Settings')}>
+ <IconButton.Icon icon="settings-filled" />{' '}
+ </MainHeader.IconButton>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/app-navigation-header/components/AppNavigationHeaderBackButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/app-navigation-header/components/AppNavigationHeaderBackButton.tsx
index 9ab08bf576..73bcd69d46 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/app-navigation-header/components/AppNavigationHeaderBackButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/app-navigation-header/components/AppNavigationHeaderBackButton.tsx
@@ -17,16 +17,12 @@ export const AppNavigationHeaderBackButton = () => {
if (!parentBackAction) return null;
- const iconSource = backIcon ? 'icon-back' : 'icon-close-down';
+ const iconSource = backIcon ? 'chevron-left-circle' : 'chevron-down-circle';
const ariaLabel = backIcon ? messages.gettext('Back') : messages.gettext('Close');
return (
- <IconButton
- variant="secondary"
- size="medium"
- icon={iconSource}
- aria-label={ariaLabel}
- onClick={parentBackAction}
- />
+ <IconButton variant="secondary" aria-label={ariaLabel} onClick={parentBackAction}>
+ <IconButton.Icon icon={iconSource} />
+ </IconButton>
);
};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/CellButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/CellButton.tsx
index fd5e86d7d1..cd4bb87c32 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/CellButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/CellButton.tsx
@@ -1,11 +1,10 @@
import React, { useContext } from 'react';
import styled from 'styled-components';
-import { Box } from '../../lib/components';
+import { Box, IconProps } from '../../lib/components';
import { Colors, Spacings } from '../../lib/foundations';
-import { IImageViewProps } from '../ImageView';
import { CellDisabledContext } from './Container';
-import { Icon } from './Label';
+import { CellTintedIcon } from './Label';
import { Row } from './Row';
import { CellSectionContext } from './Section';
@@ -60,13 +59,13 @@ export const CellButton = styled(
interface ICellNavigationButtonProps extends ICellButtonProps {
isAriaDescription?: boolean;
- icon?: IImageViewProps;
+ icon?: IconProps;
}
export function CellNavigationButton({
children,
icon = {
- source: 'icon-chevron',
+ icon: 'chevron-right',
},
...props
}: ICellNavigationButtonProps) {
@@ -74,7 +73,7 @@ export function CellNavigationButton({
<CellButton {...props}>
{children}
<Box $height="24px" $width="24px" center>
- <Icon {...icon} />
+ <CellTintedIcon {...icon} />
</Box>
</CellButton>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/Input.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/Input.tsx
index f4c5428157..7d219a533f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/Input.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/Input.tsx
@@ -1,10 +1,10 @@
import React, { useCallback, useContext, useEffect, useState } from 'react';
import styled from 'styled-components';
+import { IconButton } from '../../lib/components';
import { Colors } from '../../lib/foundations';
import { useBoolean, useCombinedRefs, useEffectEvent, useStyledRef } from '../../lib/utility-hooks';
import { normalText } from '../common-styles';
-import ImageView from '../ImageView';
import { BackAction } from '../KeyboardNavigation';
import StandaloneSwitch from '../Switch';
import { CellDisabledContext, Container } from './Container';
@@ -256,12 +256,6 @@ const StyledCellInputRowContainer = styled(Container)({
marginBottom: '1px',
});
-const StyledSubmitButton = styled.button({
- border: 'none',
- backgroundColor: 'transparent',
- padding: '10px 0',
-});
-
const StyledInputWrapper = styled.div<{ $marginLeft: number }>(normalText, (props) => ({
position: 'relative',
flex: 1,
@@ -298,6 +292,16 @@ const StyledInputFiller = styled.div({
marginRight: '25px',
});
+// TODO: This can be removed once we implement the new colors from foundations
+const StyledIconButton = styled(IconButton)<{ $disabled: boolean }>(({ $disabled }) => ({
+ ['> div']: {
+ backgroundColor: $disabled ? Colors.blue60 : Colors.blue,
+ },
+ ['&&:hover > div']: {
+ backgroundColor: $disabled ? Colors.blue60 : Colors.blue80,
+ },
+}));
+
interface IRowInputProps {
initialValue?: string;
onChange?: (value: string) => void;
@@ -395,14 +399,9 @@ export function RowInput(props: IRowInputProps) {
placeholder={props.placeholder}
/>
</StyledInputWrapper>
- <StyledSubmitButton onClick={submit}>
- <ImageView
- source="icon-check"
- height={18}
- tintColor={value === '' ? Colors.blue60 : Colors.blue}
- tintHoverColor={value === '' ? Colors.blue60 : Colors.blue80}
- />
- </StyledSubmitButton>
+ <StyledIconButton variant="secondary" onClick={submit} $disabled={value === ''}>
+ <IconButton.Icon icon="checkmark-circle" />
+ </StyledIconButton>
</StyledCellInputRowContainer>
</BackAction>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/Label.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/Label.tsx
index 8b5cacb82d..d111540a6a 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/Label.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/Label.tsx
@@ -1,9 +1,9 @@
import React, { useContext } from 'react';
import styled from 'styled-components';
+import { Icon, IconProps, Image, ImageProps } from '../../lib/components';
import { Colors, Spacings } from '../../lib/foundations';
import { buttonText, normalText, tinyText } from '../common-styles';
-import ImageView, { IImageViewProps } from '../ImageView';
import { CellButton } from './CellButton';
import { CellDisabledContext } from './Container';
@@ -33,22 +33,26 @@ const StyledSubText = styled.span<{ disabled: boolean }>(tinyText, (props) => ({
margin: `0 ${Spacings.spacing3}`,
}));
-const StyledIconContainer = styled.div<{ disabled: boolean }>((props) => ({
- opacity: props.disabled ? 0.4 : 1,
+const StyledImage = styled(Image)<ImageProps & { disabled?: boolean }>(({ disabled }) => ({
+ opacity: disabled ? 0.4 : 1,
}));
-const StyledTintedIcon = styled(ImageView).attrs((props: IImageViewProps) => ({
- tintColor: props.tintColor ?? Colors.white,
- tintHoverColor: props.tintHoverColor ?? props.tintColor ?? Colors.white60,
-}))((props: IImageViewProps) => ({
- '&&:hover': {
- backgroundColor: props.tintHoverColor,
- },
- [`${CellButton}:not(:disabled):hover &&`]: {
- backgroundColor: props.tintHoverColor,
- },
+const StyledIcon = styled(Icon)<IconProps & { disabled?: boolean }>(({ disabled }) => ({
+ opacity: disabled ? 0.4 : 1,
}));
+const StyledTintedIcon = styled(Icon)<IconProps & { disabled?: boolean }>(
+ ({ color, disabled }) => ({
+ opacity: disabled ? 0.4 : 1,
+ '&&:hover': {
+ backgroundColor: color,
+ },
+ [`${CellButton}:not(:disabled):hover &&`]: {
+ backgroundColor: color,
+ },
+ }),
+);
+
const StyledSubLabel = styled.div<{ disabled: boolean }>(tinyText, {
display: 'flex',
alignItems: 'center',
@@ -84,22 +88,19 @@ export function SubText(props: React.HTMLAttributes<HTMLDivElement>) {
return <StyledSubText disabled={disabled} {...props} />;
}
-export function UntintedIcon(props: IImageViewProps) {
+export function CellImage(props: ImageProps) {
+ const disabled = useContext(CellDisabledContext);
+ return <StyledImage disabled={disabled} {...props} />;
+}
+
+export function CellIcon(props: IconProps) {
const disabled = useContext(CellDisabledContext);
- return (
- <StyledIconContainer disabled={disabled}>
- <ImageView {...props} />
- </StyledIconContainer>
- );
+ return <StyledIcon disabled={disabled} {...props} />;
}
-export function Icon(props: IImageViewProps) {
+export function CellTintedIcon(props: IconProps) {
const disabled = useContext(CellDisabledContext);
- return (
- <StyledIconContainer disabled={disabled}>
- <StyledTintedIcon {...props} />
- </StyledIconContainer>
- );
+ return <StyledTintedIcon disabled={disabled} {...props} />;
}
export function SubLabel(props: React.HTMLAttributes<HTMLDivElement>) {
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/Selector.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/Selector.tsx
index 7de9a01305..34e285f267 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/Selector.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/Selector.tsx
@@ -2,12 +2,12 @@ import { useCallback, useRef, useState } from 'react';
import styled from 'styled-components';
import { messages } from '../../../shared/gettext';
+import { Icon } from '../../lib/components';
import { Colors, Spacings } from '../../lib/foundations';
import { useHistory } from '../../lib/history';
import { RoutePath } from '../../lib/routes';
import { useStyledRef } from '../../lib/utility-hooks';
import { AriaDetails, AriaInput, AriaLabel } from '../AriaGroup';
-import ImageView from '../ImageView';
import InfoButton from '../InfoButton';
import * as Cell from '.';
@@ -136,7 +136,7 @@ export default function Selector<T, U>(props: SelectorProps<T, U>) {
}
}
-const StyledCellIcon = styled(Cell.Icon)<{ $visible: boolean }>((props) => ({
+const StyledCellIcon = styled(Icon)<{ $visible: boolean }>((props) => ({
opacity: props.$visible ? 1 : 0,
marginRight: '8px',
}));
@@ -157,10 +157,6 @@ const StyledSelectorCell = styled.div({
display: 'flex',
});
-const StyledSideButtonImage = styled(ImageView)({
- padding: '0 3px',
-});
-
const StyledSideButton = styled(Cell.SideButton)({
marginBottom: '1px',
});
@@ -193,12 +189,7 @@ function SelectorCell<T>(props: SelectorCellProps<T>) {
aria-selected={props.isSelected}
aria-disabled={props.disabled}
data-testid={props['data-testid']}>
- <StyledCellIcon
- $visible={props.isSelected}
- source="icon-tick"
- width={18}
- tintColor={Colors.white}
- />
+ <StyledCellIcon $visible={props.isSelected} icon="checkmark" />
<SelectorCellLabel subLabel={props.subLabel}>{props.children}</SelectorCellLabel>
</Cell.CellButton>
{props.details && (
@@ -207,12 +198,7 @@ function SelectorCell<T>(props: SelectorCellProps<T>) {
$backgroundColorHover={Colors.blue80}
aria-label={props.details.ariaLabel}
onClick={navigate}>
- <StyledSideButtonImage
- source="icon-chevron"
- width={7}
- tintColor={Colors.white}
- tintHoverColor={Colors.white80}
- />
+ <Icon icon="chevron-right" />
</StyledSideButton>
)}
</StyledSelectorCell>
@@ -362,12 +348,7 @@ export function SelectorWithCustomItem<T, U>(props: SelectorWithCustomItemProps<
role="option"
aria-selected={customIsSelected}
aria-disabled={props.disabled}>
- <StyledCellIcon
- $visible={customIsSelected}
- source="icon-tick"
- width={18}
- tintColor={Colors.white}
- />
+ <StyledCellIcon $visible={customIsSelected} icon="checkmark" />
<Cell.ValueLabel>{messages.gettext('Custom')}</Cell.ValueLabel>
<AriaInput>
<Cell.AutoSizingTextInput
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsRow.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsRow.tsx
index 7b62dd251a..baf64edca4 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsRow.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsRow.tsx
@@ -1,10 +1,10 @@
import React, { useCallback, useContext, useMemo, useState } from 'react';
import styled from 'styled-components';
+import { Icon } from '../../lib/components';
import { Colors } from '../../lib/foundations';
import { AriaInputGroup, AriaLabel } from '../AriaGroup';
import { measurements, smallNormalText, tinyText } from '../common-styles';
-import ImageView from '../ImageView';
import { StyledSettingsGroup, useSettingsGroupContext } from './SettingsGroup';
const StyledSettingsRow = styled.label<{ $invalid: boolean }>((props) => ({
@@ -64,7 +64,7 @@ const StyledSettingsRowErrorMessage = styled.div(tinyText, {
color: Colors.white60,
});
-const StyledErrorMessageAlertIcon = styled(ImageView)({
+const StyledErrorMessageAlertIcon = styled(Icon)({
marginRight: '5px',
});
@@ -132,7 +132,7 @@ export function SettingsRow(props: React.PropsWithChildren<IndentedRowProps>) {
export function SettingsRowErrorMessage(props: React.PropsWithChildren) {
return (
<StyledSettingsRowErrorMessage>
- <StyledErrorMessageAlertIcon source="icon-alert" tintColor={Colors.red} width={12} />
+ <StyledErrorMessageAlertIcon icon="alert-circle" color={Colors.red} size="small" />
{props.children}
</StyledSettingsRowErrorMessage>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsSelect.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsSelect.tsx
index aa7b64bbec..6d0ef951bb 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsSelect.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsSelect.tsx
@@ -2,12 +2,12 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import { useScheduler } from '../../../shared/scheduler';
+import { Icon } from '../../lib/components';
import { Colors } from '../../lib/foundations';
import { useBoolean, useEffectEvent } from '../../lib/utility-hooks';
import { AriaInput } from '../AriaGroup';
import { smallNormalText } from '../common-styles';
import CustomScrollbars from '../CustomScrollbars';
-import ImageView from '../ImageView';
export interface SettingsSelectItem<T extends string> {
value: T;
@@ -77,7 +77,7 @@ const StyledInvisibleItemsInner = styled.div({
whiteSpace: 'nowrap',
});
-const StyledChevron = styled(ImageView)({
+const StyledChevron = styled(Icon)({
marginLeft: '6px',
marginRight: '5px',
});
@@ -155,7 +155,7 @@ export function SettingsSelect<T extends string>(props: SettingsSelectProps<T>)
<StyledSelectedText>
{props.items.find((item) => item.value === value)?.label ?? ''}
</StyledSelectedText>
- <StyledChevron tintColor={Colors.white60} source="icon-chevron-down" width={22} />
+ <StyledChevron color={Colors.white60} icon="chevron-down" />
</StyledSelectedContainerInner>
<StyledInvisibleItems>
{props.items.map((item) => (
@@ -224,7 +224,7 @@ const StyledItem = styled.div<{ $selected: boolean }>((props) => ({
},
}));
-const TickIcon = styled(ImageView)({
+const TickIcon = styled(Icon)({
marginLeft: '5px',
marginRight: '6px',
});
@@ -248,7 +248,7 @@ function Item<T extends string>(props: ItemProps<T>) {
role="option"
$selected={props.selected}
aria-selected={props.selected}>
- {props.selected && <TickIcon tintColor={Colors.white} source="icon-tick" width={12} />}
+ {props.selected && <TickIcon icon="checkmark" size="small" />}
{props.item.label}
</StyledItem>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanel.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanel.tsx
index 34e98abeea..8a5685b35e 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanel.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanel.tsx
@@ -1,13 +1,13 @@
import { useCallback, useEffect } from 'react';
import styled from 'styled-components';
+import { IconButton } from '../../lib/components';
import { useBoolean } from '../../lib/utility-hooks';
import { useSelector } from '../../redux/store';
import CustomScrollbars from '../CustomScrollbars';
import { BackAction } from '../KeyboardNavigation';
import ConnectionActionButton from './ConnectionActionButton';
import ConnectionDetails from './ConnectionDetails';
-import ConnectionPanelChevron from './ConnectionPanelChevron';
import ConnectionStatus from './ConnectionStatus';
import FeatureIndicators from './FeatureIndicators';
import Hostname from './Hostname';
@@ -48,7 +48,7 @@ const StyledCustomScrollbars = styled(CustomScrollbars)({
flexShrink: 1,
});
-const StyledConnectionPanelChevron = styled(ConnectionPanelChevron)({
+const StyledConnectionPanelChevron = styled(IconButton)({
position: 'absolute',
top: '16px',
right: '16px',
@@ -96,7 +96,11 @@ export default function ConnectionPanel() {
<BackAction disabled={!expanded} action={collapse}>
<StyledConnectionPanel $expanded={expanded}>
{allowExpand && (
- <StyledConnectionPanelChevron pointsUp={!expanded} onToggle={toggleExpanded} />
+ <StyledConnectionPanelChevron
+ onClick={toggleExpanded}
+ data-testid="connection-panel-chevron">
+ <IconButton.Icon icon={expanded ? 'chevron-down' : 'chevron-up'} />
+ </StyledConnectionPanelChevron>
)}
<StyledConnectionStatusContainer
$expanded={expanded}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanelChevron.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanelChevron.tsx
deleted file mode 100644
index f660662910..0000000000
--- a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/ConnectionPanelChevron.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import styled from 'styled-components';
-
-import { Colors } from '../../lib/foundations';
-import ImageView from '../ImageView';
-
-const Container = styled.button({
- display: 'flex',
- alignItems: 'center',
- width: '100%',
- background: 'none',
- border: 'none',
-});
-
-const Chevron = styled(ImageView)({
- [Container + ':hover &&']: {
- backgroundColor: Colors.white80,
- },
-});
-
-interface IProps {
- pointsUp: boolean;
- onToggle?: () => void;
- className?: string;
-}
-
-export default function ConnectionPanelChevron(props: IProps) {
- return (
- <Container
- data-testid="connection-panel-chevron"
- className={props.className}
- onClick={props.onToggle}>
- <Chevron
- source={props.pointsUp ? 'icon-chevron-up' : 'icon-chevron-down'}
- width={24}
- height={24}
- tintColor={Colors.white}
- />
- </Container>
- );
-}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/FeatureIndicators.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/FeatureIndicators.tsx
index a80371ae77..bed486d138 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/FeatureIndicators.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/FeatureIndicators.tsx
@@ -9,7 +9,6 @@ import { Colors } from '../../lib/foundations';
import { useStyledRef } from '../../lib/utility-hooks';
import { useSelector } from '../../redux/store';
import { tinyText } from '../common-styles';
-import { InfoIcon } from '../InfoButton';
import { ConnectionPanelAccordion } from './styles';
const LINE_HEIGHT = 22;
@@ -118,15 +117,6 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) {
const ellipsis = messages.gettext('%(amount)d more...');
- // Returns an optional callback for clickable feature indicators, or undefined.
- const getFeatureIndicatorOnClick = (indicator: FeatureIndicator) => {
- // NOTE: With the "smart routing" feature indicator removed, this function now does nothing, should it be removed?
- switch (indicator) {
- default:
- return undefined;
- }
- };
-
useEffect(() => {
// We need to defer the visibility logic one painting cycle to make sure the elements are
// rendered and available.
@@ -198,14 +188,11 @@ export default function FeatureIndicators(props: FeatureIndicatorsProps) {
ref={featureIndicatorsContainerRef}
$expanded={props.expanded}>
{sortedIndicators.map((indicator) => {
- const onClick = getFeatureIndicatorOnClick(indicator);
return (
<StyledFeatureIndicatorLabel
key={indicator.toString()}
- data-testid="feature-indicator"
- onClick={onClick}>
+ data-testid="feature-indicator">
{getFeatureIndicatorLabel(indicator)}
- {onClick ? <InfoIcon size={10} /> : null}
</StyledFeatureIndicatorLabel>
);
})}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/MainView.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/MainView.tsx
index 06a4ec8e69..c01ab92c89 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/MainView.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/MainView.tsx
@@ -1,8 +1,8 @@
import styled from 'styled-components';
+import { Spinner } from '../../lib/components';
import { useSelector } from '../../redux/store';
import { AppMainHeader } from '../app-main-header';
-import ImageView from '../ImageView';
import { Container, Layout } from '../Layout';
import Map from '../Map';
import NotificationArea from '../NotificationArea';
@@ -21,7 +21,7 @@ const Content = styled.div({
maxHeight: '100%',
});
-const StatusIcon = styled(ImageView)({
+const StatusIcon = styled(Spinner)({
position: 'absolute',
alignSelf: 'center',
marginTop: 94,
@@ -59,7 +59,7 @@ export default function MainView() {
<StyledNotificationArea />
<StyledMain>
- {showSpinner ? <StatusIcon source="icon-spinner" height={60} width={60} /> : null}
+ {showSpinner ? <StatusIcon size="big" /> : null}
<ConnectionPanel />
</StyledMain>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/SelectLocationButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/SelectLocationButton.tsx
index 045fc65f58..c484c0312d 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/main-view/SelectLocationButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/main-view/SelectLocationButton.tsx
@@ -6,12 +6,11 @@ import { ICustomList } from '../../../shared/daemon-rpc-types';
import { messages, relayLocations } from '../../../shared/gettext';
import log from '../../../shared/logging';
import { useAppContext } from '../../context';
-import { Button, ButtonProps } from '../../lib/components';
+import { Button, ButtonProps, Icon } from '../../lib/components';
import { transitions, useHistory } from '../../lib/history';
import { RoutePath } from '../../lib/routes';
import { IRelayLocationCountryRedux, RelaySettingsRedux } from '../../redux/settings/reducers';
import { useSelector } from '../../redux/store';
-import ImageView from '../ImageView';
import { MultiButton } from '../MultiButton';
export default function SelectLocationButtons() {
@@ -134,7 +133,7 @@ function ReconnectButton(props: ButtonProps) {
size="auto"
aria-label={messages.gettext('Reconnect')}
{...props}>
- <ImageView height={24} width={24} source="icon-reload" tintColor="white" />
+ <Icon icon="reconnect" />
</StyledReconnectButton>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomListDialogs.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomListDialogs.tsx
index b9a64fbfa0..b22f0e3a91 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomListDialogs.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomListDialogs.tsx
@@ -103,7 +103,7 @@ const StyledSelectListItemLabel = styled(Cell.Label)(normalText, {
fontWeight: 'normal',
});
-const StyledSelectListItemIcon = styled(Cell.Icon)({
+const StyledSelectListItemIcon = styled(Cell.CellTintedIcon)({
[`${Cell.CellButton}:not(:disabled):hover &&`]: {
backgroundColor: Colors.white80,
},
@@ -130,7 +130,7 @@ function SelectList(props: SelectListProps) {
<StyledSelectListItemLabel>
{props.list.name} {disabled && messages.pgettext('select-location-view', '(Added)')}
</StyledSelectListItemLabel>
- <StyledSelectListItemIcon source="icon-add" width={18} />
+ <StyledSelectListItemIcon icon="add-circle" />
</Cell.CellButton>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomLists.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomLists.tsx
index c6dcfafb78..07dd98f19a 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomLists.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/CustomLists.tsx
@@ -49,9 +49,7 @@ const StyledAddListCellButton = styled(StyledCellButton)({
marginLeft: 'auto',
});
-const StyledSideButtonIcon = styled(Cell.Icon)({
- padding: '3px',
-
+const StyledSideButtonIcon = styled(Cell.CellIcon)({
[`${StyledCellButton}:disabled &&, ${StyledAddListCellButton}:disabled &&`]: {
backgroundColor: Colors.white40,
},
@@ -104,7 +102,7 @@ export default function CustomLists(props: CustomListsProps) {
$backgroundColor={Colors.blue}
$backgroundColorHover={Colors.blue80}
onClick={showAddList}>
- <StyledSideButtonIcon source="icon-add" tintColor={Colors.white60} width={18} />
+ <StyledSideButtonIcon icon="add-circle" color={Colors.white60} />
</StyledCellButton>
</StyledCellContainer>
@@ -200,7 +198,7 @@ function AddListForm(props: AddListFormProps) {
$backgroundColorHover={Colors.blue80}
disabled={!nameValid}
onClick={createList}>
- <StyledSideButtonIcon source="icon-check" tintColor={Colors.white60} width={18} />
+ <StyledSideButtonIcon icon="checkmark" color={Colors.white60} />
</StyledAddListCellButton>
</StyledCellContainer>
<Cell.CellFooter>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRow.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRow.tsx
index a47c1dd646..98a13e1af0 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRow.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRow.tsx
@@ -157,7 +157,7 @@ function LocationRow<C extends LocationSpecification>(props: IProps<C>) {
{props.allowAddToCustomList ? (
<StyledHoverIconButton onClick={showAddToListDialog} $isLast {...background}>
- <StyledHoverIcon source="icon-add" />
+ <StyledHoverIcon icon="add-circle" />
</StyledHoverIconButton>
) : null}
@@ -166,7 +166,7 @@ function LocationRow<C extends LocationSpecification>(props: IProps<C>) {
'country' in props.source.location &&
props.level === 1 ? (
<StyledHoverIconButton onClick={onRemoveFromList} $isLast {...background}>
- <StyledHoverIcon source="icon-remove" />
+ <StyledHoverIcon icon="remove-circle" />
</StyledHoverIconButton>
) : null}
@@ -174,10 +174,10 @@ function LocationRow<C extends LocationSpecification>(props: IProps<C>) {
{'customList' in props.source.location && !('country' in props.source.location) ? (
<>
<StyledHoverIconButton onClick={showEditDialog} {...background}>
- <StyledHoverIcon source="icon-edit" />
+ <StyledHoverIcon icon="edit-circle" />
</StyledHoverIconButton>
<StyledHoverIconButton onClick={showDeleteDialog} $isLast {...background}>
- <StyledHoverIcon source="icon-close" />
+ <StyledHoverIcon icon="cross-circle" />
</StyledHoverIconButton>
</>
) : null}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRowStyles.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRowStyles.tsx
index dbdc6cceef..89fdb7079f 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRowStyles.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/LocationRowStyles.tsx
@@ -1,11 +1,11 @@
import styled from 'styled-components';
import { Styles } from 'styled-components/dist/types';
+import { Icon } from '../../lib/components';
import { Colors } from '../../lib/foundations';
import * as Cell from '../cell';
import { buttonColor, ButtonColors } from '../cell/styles';
import { measurements, normalText } from '../common-styles';
-import ImageView from '../ImageView';
import InfoButton from '../InfoButton';
export const StyledLocationRowContainer = styled(Cell.Container)({
@@ -82,11 +82,8 @@ export const StyledHoverIconButton = styled.button<ButtonColors & HoverButtonPro
hoverButton,
);
-export const StyledHoverIcon = styled(ImageView).attrs({
- width: 18,
- height: 18,
- tintColor: Colors.white60,
- tintHoverColor: Colors.white,
+export const StyledHoverIcon = styled(Icon).attrs({
+ color: Colors.white60,
})({
[`${StyledHoverIconButton}:hover &&`]: {
backgroundColor: Colors.white,
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SelectLocation.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SelectLocation.tsx
index d650fd1802..ca74447798 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SelectLocation.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SelectLocation.tsx
@@ -4,10 +4,10 @@ import { sprintf } from 'sprintf-js';
import { strings } from '../../../shared/constants';
import { Ownership } from '../../../shared/daemon-rpc-types';
import { messages } from '../../../shared/gettext';
-import { IconButton } from '../../lib/components';
+import { FilterChip, Flex, IconButton, LabelTiny } from '../../lib/components';
import { useRelaySettingsUpdater } from '../../lib/constraint-updater';
import { daitaFilterActive, filterSpecialLocations } from '../../lib/filter-locations';
-import { Colors } from '../../lib/foundations';
+import { Spacings } from '../../lib/foundations';
import { useHistory } from '../../lib/history';
import { formatHtml } from '../../lib/html-formatter';
import { useNormalRelaySettings } from '../../lib/relay-settings-hooks';
@@ -16,7 +16,6 @@ import { useSelector } from '../../redux/store';
import { AppNavigationHeader } from '../';
import * as Cell from '../cell';
import { useFilteredProviders } from '../Filter';
-import ImageView from '../ImageView';
import { BackAction } from '../KeyboardNavigation';
import { Layout, SettingsContainer } from '../Layout';
import { NavigationContainer } from '../NavigationContainer';
@@ -34,11 +33,8 @@ import {
import { LocationType, SpecialBridgeLocationType, SpecialLocation } from './select-location-types';
import { useSelectLocationContext } from './SelectLocationContainer';
import {
- StyledClearFilterButton,
StyledContent,
StyledDaitaSettingsButton,
- StyledFilter,
- StyledFilterRow,
StyledNavigationBarAttachment,
StyledScopeBar,
StyledSearchBar,
@@ -137,11 +133,11 @@ export default function SelectLocation() {
}
titleVisible>
<IconButton
- icon="icon-filter-round"
variant="secondary"
onClick={onViewFilter}
- aria-label={messages.gettext('Filter')}
- />
+ aria-label={messages.gettext('Filter')}>
+ <IconButton.Icon icon="filter-circle" />
+ </IconButton>
</AppNavigationHeader>
<StyledNavigationBarAttachment>
@@ -159,58 +155,52 @@ export default function SelectLocation() {
{locationType === LocationType.entry && daita && !directOnly ? null : (
<>
{showFilters && (
- <StyledFilterRow>
- {messages.pgettext('select-location-view', 'Filtered:')}
+ <Flex
+ $gap={Spacings.spacing3}
+ $alignItems="center"
+ $flexWrap="wrap"
+ $margin={{ horizontal: Spacings.spacing3, bottom: Spacings.spacing5 }}>
+ <LabelTiny>
+ {messages.pgettext('select-location-view', 'Filtered:')}
+ </LabelTiny>
{showOwnershipFilter && (
- <StyledFilter>
- {ownershipFilterLabel(ownership)}
- <StyledClearFilterButton
- aria-label={messages.gettext('Clear')}
- onClick={onClearOwnership}>
- <ImageView
- height={16}
- width={16}
- source="icon-close"
- tintColor={Colors.white60}
- tintHoverColor={Colors.white80}
- />
- </StyledClearFilterButton>
- </StyledFilter>
+ <FilterChip
+ aria-label={messages.gettext('Clear')}
+ onClick={onClearOwnership}>
+ <FilterChip.Text>{ownershipFilterLabel(ownership)}</FilterChip.Text>
+ <FilterChip.Icon icon="cross" />
+ </FilterChip>
)}
{showProvidersFilter && (
- <StyledFilter>
- {sprintf(
- messages.pgettext(
- 'select-location-view',
- 'Providers: %(numberOfProviders)d',
- ),
- { numberOfProviders: filteredProviders.length },
- )}
- <StyledClearFilterButton
- aria-label={messages.gettext('Clear')}
- onClick={onClearProviders}>
- <ImageView
- height={16}
- width={16}
- source="icon-close"
- tintColor={Colors.white60}
- tintHoverColor={Colors.white80}
- />
- </StyledClearFilterButton>
- </StyledFilter>
+ <FilterChip
+ aria-label={messages.gettext('Clear')}
+ onClick={onClearProviders}>
+ <FilterChip.Text>
+ {sprintf(
+ messages.pgettext(
+ 'select-location-view',
+ 'Providers: %(numberOfProviders)d',
+ ),
+ { numberOfProviders: filteredProviders.length },
+ )}
+ </FilterChip.Text>
+ <FilterChip.Icon icon="cross" />
+ </FilterChip>
)}
{showDaitaFilter && (
- <StyledFilter>
- {sprintf(
- messages.pgettext('select-location-view', 'Setting: %(settingName)s'),
- { settingName: 'DAITA' },
- )}
- </StyledFilter>
+ <FilterChip as="div">
+ <FilterChip.Text>
+ {sprintf(
+ messages.pgettext('select-location-view', 'Setting: %(settingName)s'),
+ { settingName: 'DAITA' },
+ )}
+ </FilterChip.Text>
+ </FilterChip>
)}
- </StyledFilterRow>
+ </Flex>
)}
<StyledSearchBar searchTerm={searchValue} onSearch={updateSearchTerm} />
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SpecialLocationList.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SpecialLocationList.tsx
index fb8227b4fd..e53e3d41b2 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SpecialLocationList.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/select-location/SpecialLocationList.tsx
@@ -2,12 +2,11 @@ import React, { useCallback } from 'react';
import styled from 'styled-components';
import { messages } from '../../../shared/gettext';
-import { Colors } from '../../lib/foundations';
+import { Icon } from '../../lib/components';
import { useHistory } from '../../lib/history';
import { RoutePath } from '../../lib/routes';
import { useSelector } from '../../redux/store';
import * as Cell from '../cell';
-import ImageView from '../ImageView';
import InfoButton from '../InfoButton';
import { SpecialLocationIndicator } from '../RelayStatusIndicator';
import {
@@ -43,8 +42,6 @@ const StyledSpecialLocationInfoButton = styled(InfoButton)({
},
});
-const StyledSpecialLocationSideButton = styled(ImageView)({ padding: '0 3px' });
-
interface SpecialLocationRowProps<T> {
source: SpecialLocation<T>;
selectedElementRef: React.Ref<HTMLDivElement>;
@@ -115,7 +112,7 @@ export function CustomBridgeLocationRow(
const bridgeSettings = useSelector((state) => state.settings.bridgeSettings);
const bridgeConfigured = bridgeSettings.custom !== undefined;
- const icon = bridgeConfigured ? 'icon-edit' : 'icon-add';
+ const icon = bridgeConfigured ? 'edit-circle' : 'add-circle';
const selectedRef = props.source.selected ? props.selectedElementRef : undefined;
const background = getButtonColor(props.source.selected, 0, props.source.disabled);
@@ -151,12 +148,7 @@ export function CustomBridgeLocationRow(
: messages.pgettext('accessibility', 'Add new custom bridge')
}
onClick={navigate}>
- <StyledSpecialLocationSideButton
- source={icon}
- width={20}
- tintColor={Colors.white}
- tintHoverColor={Colors.white80}
- />
+ <Icon icon={icon} />
</Cell.SideButton>
</StyledLocationRowContainerWithMargin>
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx
index 5280ec9df7..967ad3cd95 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/app-info/components/AppVersionListItem.tsx
@@ -36,7 +36,7 @@ export function AppVersionListItem() {
const message = !consistentVersion ? inconsistentVersionMessage : updateAvailableMessage;
- alertIcon = <Cell.UntintedIcon source="icon-alert" width={18} tintColor={Colors.red} />;
+ alertIcon = <Cell.CellIcon icon="alert-circle" color={Colors.red} />;
footer = (
<Cell.CellFooter>
<Cell.CellFooterText>{message}</Cell.CellFooterText>
@@ -50,7 +50,7 @@ export function AppVersionListItem() {
disabled={isOffline}
onClick={openDownloadLink}
icon={{
- source: 'icon-extLink',
+ icon: 'external',
'aria-label': messages.pgettext('accessibility', 'Opens externally'),
}}>
<LabelStack>
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/box/Box.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/box/Box.tsx
index 387264b8d2..49639a0709 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/box/Box.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/box/Box.tsx
@@ -12,7 +12,9 @@ const StyledBox = styled(Layout)<BoxProps>((props) => ({
display: 'block',
boxSizing: 'border-box',
height: props.$height,
+ minHeight: props.$height,
width: props.$width,
+ minWidth: props.$width,
}));
const StyledCenter = styled.div({
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChip.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChip.tsx
new file mode 100644
index 0000000000..a6a8839735
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChip.tsx
@@ -0,0 +1,80 @@
+import { forwardRef } from 'react';
+import styled, { WebTarget } from 'styled-components';
+
+import { Colors, Radius, Spacings } from '../../foundations';
+import { buttonReset } from '../../styles';
+import { Flex } from '../flex';
+import { FilterChipIcon, FilterChipText } from './components';
+import { FilterChipProvider } from './FilterChipContext';
+
+export interface FilterChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+ as?: WebTarget;
+}
+
+const variables = {
+ background: Colors.blue,
+ hover: Colors.blue60,
+ disabled: Colors.blue50,
+} as const;
+
+const StyledButton = styled.button({
+ ...buttonReset,
+
+ display: 'flex',
+ alignItems: 'center',
+
+ borderRadius: Radius.radius8,
+ minWidth: '32px',
+ minHeight: '24px',
+ background: 'var(--background)',
+ '&:not(:disabled):hover': {
+ background: 'var(--hover)',
+ },
+ '&:disabled': {
+ background: 'var(--disabled)',
+ },
+ '&:focus-visible': {
+ outline: `2px solid ${Colors.white}`,
+ },
+});
+
+const FilterChip = forwardRef<HTMLButtonElement, FilterChipProps>(
+ ({ children, disabled, style, onClick, ...props }, ref) => {
+ return (
+ <FilterChipProvider disabled={disabled}>
+ <StyledButton
+ ref={ref}
+ style={
+ {
+ '--background': variables.background,
+ '--hover': onClick ? variables.hover : variables.background,
+ '--disabled': variables.disabled,
+ ...style,
+ } as React.CSSProperties
+ }
+ disabled={disabled}
+ onClick={onClick}
+ {...props}>
+ <Flex
+ $flex={1}
+ $gap={Spacings.spacing1}
+ $alignItems="center"
+ $justifyContent="space-between"
+ $padding={{
+ horizontal: Spacings.spacing3,
+ }}>
+ {children}
+ </Flex>
+ </StyledButton>
+ </FilterChipProvider>
+ );
+ },
+);
+
+FilterChip.displayName = 'FilterChip';
+
+const FilterChipNamespace = Object.assign(FilterChip, {
+ Text: FilterChipText,
+ Icon: FilterChipIcon,
+});
+export { FilterChipNamespace as FilterChip };
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChipContext.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChipContext.tsx
new file mode 100644
index 0000000000..b2a23ab07b
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/FilterChipContext.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+interface FilterChipContextProps {
+ disabled?: boolean;
+}
+const FilterChipContext = React.createContext<FilterChipContextProps | undefined>(undefined);
+
+export const useFilterChipContext = (): FilterChipContextProps => {
+ const context = React.useContext(FilterChipContext);
+ if (!context) {
+ throw new Error('useFilterChipContext must be used within a FilterChipContext');
+ }
+ return context;
+};
+
+interface FilterChipProviderProps {
+ disabled?: boolean;
+ children: React.ReactNode;
+}
+
+export const FilterChipProvider = ({ disabled, children }: FilterChipProviderProps) => {
+ return <FilterChipContext.Provider value={{ disabled }}>{children}</FilterChipContext.Provider>;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipIcon.tsx
new file mode 100644
index 0000000000..d2138362ff
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipIcon.tsx
@@ -0,0 +1,14 @@
+import styled from 'styled-components';
+
+import { Colors } from '../../../foundations';
+import { Icon, IconProps } from '../../icon';
+import { useFilterChipContext } from '../FilterChipContext';
+
+type FilterChipIconProps = Omit<IconProps, 'size'>;
+
+export const StyledIcon = styled(Icon)({});
+
+export const FilterChipIcon = ({ ...props }: FilterChipIconProps) => {
+ const { disabled } = useFilterChipContext();
+ return <Icon size="small" color={disabled ? Colors.white40 : Colors.white} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx
new file mode 100644
index 0000000000..b79446de1f
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/FilterChipText.tsx
@@ -0,0 +1,14 @@
+import styled from 'styled-components';
+
+import { Colors } from '../../../foundations';
+import { BodySmallSemiBoldProps, LabelTiny } from '../../typography';
+import { useFilterChipContext } from '../FilterChipContext';
+
+export type FilterChipTextProps = Omit<BodySmallSemiBoldProps, 'color'>;
+
+export const StyledText = styled(LabelTiny)``;
+
+export const FilterChipText = (props: FilterChipTextProps) => {
+ const { disabled } = useFilterChipContext();
+ return <StyledText color={disabled ? Colors.white40 : Colors.white} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/index.ts
new file mode 100644
index 0000000000..24f52f3100
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/components/index.ts
@@ -0,0 +1,2 @@
+export * from './FilterChipIcon';
+export * from './FilterChipText';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/index.ts
new file mode 100644
index 0000000000..51fc121fcf
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/filter-chip/index.ts
@@ -0,0 +1 @@
+export * from './FilterChip';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/flex/Flex.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/flex/Flex.tsx
index 4709b96be5..28b2159cb9 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/flex/Flex.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/flex/Flex.tsx
@@ -13,6 +13,7 @@ export interface FlexProps extends LayoutProps {
$flexGrow?: React.CSSProperties['flexGrow'];
$flexShrink?: React.CSSProperties['flexShrink'];
$flexBasis?: React.CSSProperties['flexBasis'];
+ $flexWrap?: React.CSSProperties['flexWrap'];
children?: React.ReactNode;
}
@@ -26,6 +27,7 @@ export const Flex = styled(Layout)<FlexProps>(
$flexGrow,
$flexShrink,
$flexBasis,
+ $flexWrap,
}) => ({
display: 'flex',
gap: $gap,
@@ -36,5 +38,6 @@ export const Flex = styled(Layout)<FlexProps>(
flexGrow: $flexGrow,
flexShrink: $flexShrink,
flexBasis: $flexBasis,
+ flexWrap: $flexWrap,
}),
);
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx
index 586ab0e76d..7db42fdcf7 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButton.tsx
@@ -1,41 +1,17 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
-import ImageView from '../../../components/ImageView';
import { Colors } from '../../foundations';
import { buttonReset } from '../../styles';
+import { IconProps, iconSizes } from '../icon/Icon';
+import { IconButtonIcon } from './components/IconButtonIcon';
+import { IconButtonProvider } from './IconButtonContext';
-export interface IconButtonProps
- extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
+export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary';
- size?: 'small' | 'medium';
- icon: string;
+ size?: IconProps['size'];
}
-const variants = {
- primary: {
- background: Colors.white,
- hover: Colors.white60,
- disabled: Colors.white50,
- },
- secondary: {
- background: Colors.white60,
- hover: Colors.white80,
- disabled: Colors.white50,
- },
-} as const;
-
-const sizes = {
- small: 16,
- medium: 24,
-};
-
-// TODO: This should be removed when we have updated to the new icons from design system
-const iconSizes = {
- small: 14,
- medium: 20,
-};
-
const StyledButton = styled.button({
...buttonReset,
@@ -45,36 +21,35 @@ const StyledButton = styled.button({
borderRadius: '100%',
'&:focus-visible': {
outline: `2px solid ${Colors.white}`,
+ outlineOffset: '1px',
},
});
-export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
- ({ icon, variant = 'primary', size: sizeProp = 'medium', disabled, style, ...props }, ref) => {
- const styles = variants[variant];
- const size = sizes[sizeProp];
- const iconSize = iconSizes[sizeProp];
+const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
+ ({ variant = 'primary', size: sizeProp = 'medium', disabled, style, ...props }, ref) => {
+ const size = iconSizes[sizeProp];
return (
- <StyledButton
- ref={ref}
- disabled={disabled}
- style={
- {
- '--size': `${size}px`,
- ...style,
- } as React.CSSProperties
- }
- {...props}>
- <ImageView
- source={icon}
- tintColor={styles.background}
- tintHoverColor={styles.hover}
+ <IconButtonProvider size={sizeProp} variant={variant} disabled={disabled}>
+ <StyledButton
+ ref={ref}
disabled={disabled}
- height={iconSize}
- width={iconSize}
+ style={
+ {
+ '--size': `${size}px`,
+ ...style,
+ } as React.CSSProperties
+ }
+ {...props}
/>
- </StyledButton>
+ </IconButtonProvider>
);
},
);
+const IconButtonNamespace = Object.assign(IconButton, {
+ Icon: IconButtonIcon,
+});
+
+export { IconButtonNamespace as IconButton };
+
IconButton.displayName = 'Button';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButtonContext.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButtonContext.tsx
new file mode 100644
index 0000000000..ebe100b1d5
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/IconButtonContext.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+
+import { IconButtonProps } from './IconButton';
+interface IconButtonContextProps {
+ disabled?: boolean;
+ variant: IconButtonProps['variant'];
+ size: IconButtonProps['size'];
+}
+
+const IconButtonContext = React.createContext<IconButtonContextProps | undefined>(undefined);
+
+export const useIconButtonContext = (): IconButtonContextProps => {
+ const context = React.useContext(IconButtonContext);
+ if (!context) {
+ throw new Error('useButtonContext must be used within a IconButtonProvider');
+ }
+ return context;
+};
+interface IconButtonProviderProps extends IconButtonContextProps {
+ children: React.ReactNode;
+}
+export const IconButtonProvider = ({ children, ...props }: IconButtonProviderProps) => {
+ return <IconButtonContext.Provider value={props}>{children}</IconButtonContext.Provider>;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx
new file mode 100644
index 0000000000..a65d887469
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/components/IconButtonIcon.tsx
@@ -0,0 +1,43 @@
+import styled from 'styled-components';
+
+import { Colors } from '../../../foundations';
+import { Icon, IconProps } from '../../icon/Icon';
+import { useIconButtonContext } from '../IconButtonContext';
+export type IconButtonIconProps = IconProps;
+
+const variants = {
+ primary: {
+ background: Colors.white,
+ hover: Colors.white60,
+ disabled: Colors.white50,
+ },
+ secondary: {
+ background: Colors.white60,
+ hover: Colors.white80,
+ disabled: Colors.white50,
+ },
+} as const;
+
+const StyledIcon = styled(Icon)<IconButtonIconProps & { $hoverColor: string; $disabled?: boolean }>(
+ ({ $hoverColor, $disabled }) => ({
+ ...(!$disabled && {
+ '&&:hover': {
+ backgroundColor: $hoverColor,
+ },
+ }),
+ }),
+);
+
+export const IconButtonIcon = (props: IconButtonIconProps) => {
+ const { variant = 'primary', size, disabled } = useIconButtonContext();
+ const styles = variants[variant];
+ return (
+ <StyledIcon
+ color={disabled ? styles.disabled : styles.background}
+ size={size}
+ $hoverColor={styles.hover}
+ $disabled={disabled}
+ {...props}
+ />
+ );
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/index.ts
index 1a85f0f725..cfe09746a9 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/index.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon-button/index.ts
@@ -1 +1,2 @@
export * from './IconButton';
+export * from './IconButtonContext';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/Icon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/Icon.tsx
new file mode 100644
index 0000000000..7cf51a109f
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/Icon.tsx
@@ -0,0 +1,41 @@
+import styled from 'styled-components';
+
+import { Colors } from '../../foundations';
+import { TransientProps } from '../../types';
+import { icons } from './types';
+
+export type IconProps = {
+ icon: keyof typeof icons;
+ size?: 'tiny' | 'small' | 'medium' | 'large' | 'big';
+ color?: Colors;
+ className?: string;
+} & React.HTMLAttributes<HTMLDivElement>;
+
+const StyledIcon = styled.div<
+ TransientProps<Pick<IconProps, 'color'>> & { $size: number; $src: string }
+>`
+ width: ${({ $size }) => $size}px;
+ height: ${({ $size }) => $size}px;
+ mask: url(${({ $src }) => $src}) no-repeat center;
+ mask-size: contain;
+ background-color: ${({ $color }) => $color || 'currentColor'};
+`;
+
+export const iconSizes = {
+ tiny: 14,
+ small: 18,
+ medium: 24,
+ large: 32,
+ big: 48,
+};
+
+export const Icon = ({
+ icon: iconProp,
+ size = 'medium',
+ color = Colors.white,
+ ...props
+}: IconProps) => {
+ const icon = icons[iconProp];
+ const src = iconProp.startsWith('data:') ? iconProp : `../../assets/icons/${icon}.svg`;
+ return <StyledIcon $src={src} $size={iconSizes[size]} $color={color} role="img" {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/index.ts
new file mode 100644
index 0000000000..e263cc0e6d
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/index.ts
@@ -0,0 +1 @@
+export * from './Icon';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/types.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/types.ts
new file mode 100644
index 0000000000..19440d2207
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/icon/types.ts
@@ -0,0 +1,34 @@
+export const icons = {
+ 'account-circle': 'icon-account-circle',
+ 'add-circle': 'icon-add-circle',
+ 'alert-circle': 'icon-alert-circle',
+ 'checkmark-circle': 'icon-checkmark-circle',
+ checkmark: 'icon-checkmark',
+ 'chevron-down-circle': 'icon-chevron-down-circle',
+ 'chevron-down': 'icon-chevron-down',
+ 'chevron-left-circle': 'icon-chevron-left-circle',
+ 'chevron-left': 'icon-chevron-left',
+ 'chevron-right-circle': 'icon-chevron-right-circle',
+ 'chevron-right': 'icon-chevron-right',
+ 'chevron-up-circle': 'icon-chevron-up-circle',
+ 'chevron-up': 'icon-chevron-up',
+ copy: 'icon-copy',
+ 'cross-circle': 'icon-cross-circle',
+ cross: 'icon-cross',
+ 'edit-circle': 'icon-edit-circle',
+ external: 'icon-external',
+ 'filter-circle': 'icon-filter-circle',
+ grabber: 'icon-grabber',
+ hide: 'icon-hide',
+ 'info-circle': 'icon-info-circle',
+ 'more-horizontal-circle': 'icon-more-horizontal-circle',
+ 'more-horizontal': 'icon-more-horizontal',
+ 'more-vertical-circle': 'icon-more-vertical-circle',
+ 'more-vertical': 'icon-more-vertical',
+ reconnect: 'icon-reconnect',
+ 'remove-circle': 'icon-remove-circle',
+ 'search-circle': 'icon-search-circle',
+ search: 'icon-search',
+ 'settings-filled': 'icon-settings-filled',
+ show: 'icon-show',
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/image/Image.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/image/Image.tsx
new file mode 100644
index 0000000000..1bf58c5040
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/image/Image.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+
+export interface ImageProps {
+ source: string;
+ onClick?: (event: React.MouseEvent) => void;
+ width?: number;
+ height?: number;
+ className?: string;
+}
+
+export const Image = ({ source, ...props }: ImageProps) => {
+ const url = source.startsWith('data:') ? source : `../../assets/images/${source}.svg`;
+
+ return <img src={url} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/image/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/image/index.ts
new file mode 100644
index 0000000000..4bbac90149
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/image/index.ts
@@ -0,0 +1 @@
+export * from './Image';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/index.ts
index 6ca0b4a51c..a425560461 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/index.ts
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/index.ts
@@ -1,11 +1,15 @@
export * from './box';
export * from './button';
+export * from './filter-chip';
export * from './container';
export * from './flex';
+export * from './image';
+export * from './icon';
export * from './icon-button';
export * from './layout';
export * from './logo';
export * from './main-header';
export * from './navigation-header';
+export * from './spinner';
export * from './theme';
export * from './typography';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/logo/Logo.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/logo/Logo.tsx
index c30f35b3e0..94387051f7 100644
--- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/logo/Logo.tsx
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/logo/Logo.tsx
@@ -1,6 +1,6 @@
-import ImageView from '../../../components/ImageView';
import { Spacings } from '../../foundations';
import { Flex } from '../flex';
+import { Image } from '../image';
export interface LogoProps {
variant?: 'icon' | 'text' | 'both';
@@ -21,19 +21,19 @@ export const Logo = ({ variant = 'icon', size: sizeProp = '1' }: LogoProps) => {
switch (variant) {
case 'icon': {
const logoSize = logoSizes[sizeProp];
- return <ImageView source="logo-icon" height={logoSize} />;
+ return <Image source="logo-icon" height={logoSize} />;
}
case 'text': {
const textSize = textSizes[sizeProp];
- return <ImageView source="logo-text" height={textSize} />;
+ return <Image source="logo-text" height={textSize} />;
}
case 'both': {
const logoSize = logoSizes[sizeProp];
const textSize = textSizes[sizeProp];
return (
<Flex $flex={1} $alignItems="center" $gap={Spacings.spacing3}>
- <ImageView source="logo-icon" height={logoSize} />
- <ImageView source="logo-text" height={textSize} />
+ <Image source="logo-icon" height={logoSize} />
+ <Image source="logo-text" height={textSize} />
</Flex>
);
}
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/Spinner.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/Spinner.tsx
new file mode 100644
index 0000000000..21f02b1652
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/Spinner.tsx
@@ -0,0 +1,23 @@
+import styled from 'styled-components';
+
+export interface SpinnerProps extends React.ImgHTMLAttributes<HTMLImageElement> {
+ size?: 'small' | 'medium' | 'big';
+ alt?: string;
+ className?: string;
+}
+
+const StyledSpinner = styled.img<{ $size: number }>`
+ width: ${({ $size }) => $size}px;
+ height: ${({ $size }) => $size}px;
+`;
+
+const sizes = {
+ small: 16,
+ medium: 24,
+ big: 48,
+};
+
+export const Spinner = ({ size = 'medium', ...props }: SpinnerProps) => {
+ const src = '../../assets/images/spinner.svg';
+ return <StyledSpinner src={src} $size={sizes[size]} {...props} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/index.ts
new file mode 100644
index 0000000000..b259397be4
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/spinner/index.ts
@@ -0,0 +1 @@
+export * from './Spinner';
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/IconBadge.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/IconBadge.tsx
new file mode 100644
index 0000000000..1263664858
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/IconBadge.tsx
@@ -0,0 +1,14 @@
+import { Image } from '../components';
+
+export interface IconBadgeProps {
+ state: 'positive' | 'negative';
+}
+
+const sources = {
+ positive: 'positive',
+ negative: 'negative',
+};
+
+export const IconBadge = ({ state }: IconBadgeProps) => {
+ return <Image source={sources[state]} width={48} height={48} />;
+};
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/index.ts
new file mode 100644
index 0000000000..97a338a50a
--- /dev/null
+++ b/desktop/packages/mullvad-vpn/src/renderer/lib/icon-badge/index.ts
@@ -0,0 +1 @@
+export * from './IconBadge';
diff --git a/ios/convert-assets.rb b/ios/convert-assets.rb
index 637068cfe6..b2dea9c83f 100755
--- a/ios/convert-assets.rb
+++ b/ios/convert-assets.rb
@@ -10,47 +10,70 @@ XCASSETS_DIR = File.join(SCRIPT_DIR, "MullvadVPN/Supporting Files/Assets.xcasset
# graphical assets sources
APPICON_PATH = File.join(ROOT_DIR, "graphics/icon-square.svg")
-GRAPHICAL_ASSETS_DIR = File.join(
- ROOT_DIR,
- "desktop/packages/mullvad-vpn/assets/images"
-)
ADDITIONAL_ASSETS_DIR = File.join(SCRIPT_DIR, "AdditionalAssets")
# app icon output
XCASSETS_APPICON_PATH = File.join(XCASSETS_DIR, "AppIcon.appiconset/AppIcon.png")
XCASSETS_APPICON_SIZE = 1024
-# graphical assets to import
-GRAPHICAL_ASSETS = [
- "icon-account.svg",
- "icon-alert.svg",
- "icon-arrow.svg",
- "icon-back.svg",
- "icon-chevron-down.svg",
- "icon-chevron-up.svg",
- "icon-chevron.svg",
- "icon-extLink.svg",
- "icon-fail.svg",
- "icon-info.svg",
- "icon-settings.svg",
- "icon-spinner.svg",
- "icon-success.svg",
- "icon-tick.svg",
+ICON_ASSETS_DIR = File.join(
+ ROOT_DIR,
+ "desktop/packages/mullvad-vpn/assets/icons"
+)
+ICON_ASSETS = [
+ 'icon-account-circle.svg',
+ 'icon-add-circle.svg',
+ 'icon-alert-circle.svg',
+ 'icon-checkmark-circle.svg',
+ 'icon-checkmark.svg',
+ 'icon-chevron-down-circle.svg',
+ 'icon-chevron-down.svg',
+ 'icon-chevron-left-circle.svg',
+ 'icon-chevron-left.svg',
+ 'icon-chevron-right-circle.svg',
+ 'icon-chevron-right.svg',
+ 'icon-chevron-up-circle.svg',
+ 'icon-chevron-up.svg',
+ 'icon-copy.svg',
+ 'icon-cross-circle.svg',
+ 'icon-cross.svg',
+ 'icon-edit-circle.svg',
+ 'icon-external.svg',
+ 'icon-filter-circle.svg',
+ 'icon-grabber.svg',
+ 'icon-hide.svg',
+ 'icon-info-circle.svg',
+ 'icon-more-horizontal-circle.svg',
+ 'icon-more-horizontal.svg',
+ 'icon-more-vertical-circle.svg',
+ 'icon-more-vertical.svg',
+ 'icon-reconnect.svg',
+ 'icon-remove-circle.svg',
+ 'icon-search-circle.svg',
+ 'icon-search.svg',
+ 'icon-settings-filled.svg',
+ 'icon-show.svg',
+]
+
+IMAGE_ASSETS_DIR = File.join(
+ ROOT_DIR,
+ "desktop/packages/mullvad-vpn/assets/images"
+)
+IMAGE_ASSETS = [
+ "daita-off-illustration.svg",
+ "daita-on-illustration.svg",
"location-marker-secure.svg",
"location-marker-unsecure.svg",
- "logo-icon.svg",
- "logo-text.svg",
- "icon-close.svg",
- "icon-close-sml.svg",
- "icon-copy.svg",
- "icon-obscure.svg",
- "icon-unobscure.svg"
+ "multihop-illustration.svg",
+ "negative.svg",
+ "positive.svg",
+ "spinner.svg",
]
# graphical assets to resize.
RESIZE_ASSETS = {
- "icon-info.svg" => ["icon-info.svg", 18, 18],
- "icon-tick.svg" => ["icon-tick-sml.svg", 16, 16]
+ "icon-info-circle.svg" => ["icon-info-circle.svg", 18, 18],
+ "icon-checkmark.svg" => ["icon-checkmark-sml.svg", 16, 16]
}
# Additional assets generated from SVG -> vector PDF
@@ -75,10 +98,9 @@ SVG_CONVERT_ENVIRONMENT_VARIABLES = {
SVG_CONVERT_DEFAULT_OPTIONS = ["--dpi-x=72", "--dpi-y=72"]
# Functions
-
-def generate_graphical_assets()
- for asset_name in GRAPHICAL_ASSETS do
- svg_file = File.join(GRAPHICAL_ASSETS_DIR, asset_name)
+def generate_graphical_assets(assets, asset_dir)
+ for asset_name in assets do
+ svg_file = File.join(asset_dir, asset_name)
image_name = pascal_case(File.basename(svg_file, ".svg"))
output_dir = File.join(XCASSETS_DIR, "#{image_name}.imageset")
@@ -98,7 +120,7 @@ def generate_resized_assets()
RESIZE_ASSETS.each do |asset_name, resize_options|
(new_asset_name, width, height) = resize_options
- svg_file = File.join(GRAPHICAL_ASSETS_DIR, asset_name)
+ svg_file = File.join(ICON_ASSETS_DIR, asset_name)
image_name = pascal_case(File.basename(new_asset_name, ".svg"))
output_dir = File.join(XCASSETS_DIR, "#{image_name}.imageset")
@@ -170,7 +192,8 @@ OptionParser.new do |opts|
end
opts.on("--import-desktop-assets", "Import assets from the desktop app") do |v|
- generate_graphical_assets
+ generate_graphical_assets(ICON_ASSETS, ICON_ASSETS_DIR)
+ generate_graphical_assets(IMAGE_ASSETS, IMAGE_ASSETS_DIR)
generate_resized_assets
end