diff --git a/.eslintrc.js b/.eslintrc.js
index 467a3a6..eab0580 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -19,7 +19,9 @@ module.exports = {
"OS": true,
"ADDON_UNINSTALL": true,
"ADDON_DISABLE": true,
- "proxifiedContainers": true
+ "proxifiedContainers": true,
+ "MozillaVPN": true,
+ "MozillaVPN_Background": true
},
"plugins": [
"promise",
diff --git a/.stylelintrc b/.stylelintrc
index 5debd45..afed108 100644
--- a/.stylelintrc
+++ b/.stylelintrc
@@ -14,7 +14,7 @@
ignoreProperties:
["inset-block-end", "inset-block-start"]
}],
- "property-blacklist": [
+ "property-disallowed-list": [
"/(min[-]|max[-])height/",
"/width/",
"/top/",
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 80ea76e..c416bbe 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -42,64 +42,52 @@
"message": "A better way to manage all the things you do online"
},
"onboarding-1-description": {
- "message": "Use containers to organize tasks, manage accounts, and keep your focus where you want it."
- },
- "onboarding-1-sec-header": {
- "message": "A simple and secure way to manage your online life"
- },
- "onboarding-1-sec-description": {
- "message" : "Use containers to organize tasks, manage accounts, and store sensitive data."
+ "message": "Use Containers to organize tasks, manage accounts, and keep your focus where you want it."
},
"onboarding-2-header": {
- "message": "Put containers to work for you."
+ "message": "Put Containers to work for you."
},
"onboarding-2-description": {
- "message": "Features like color-coding and separate container tabs help you find things easily, focus your attention, and minimize distractions."
- },
- "onboarding-2-sec-description": {
- "message": "Color-coding helps you categorize your online life, find things easily, and minimize distractions."
+ "message": "Features like color-coding and separate Container tabs help you find things easily, focus your attention, and minimize distractions."
},
"onboarding-3-header": {
"message": "A place for everything, and everything in its place."
},
"onboarding-3-description": {
- "message": "Start with the containers we've created, or create your own."
- },
- "onboarding-3-sec-header": {
- "message": "Set boundaries for your browsing."
- },
- "onboarding-3-sec-description": {
- "message": "Cookies are stored within a container, so you can segment sensitive data and browsing history to stay organized and to limit the impact of online trackers."
+ "message": "Start with the Containers we’ve created, or create your own."
},
"onboarding-4-header": {
- "message": "Always open sites in the containers you want."
+ "message": "Always open sites in the Containers you want."
},
"onboarding-4-description": {
- "message": "Right-click inside a container tab to assign the site to always open in the container."
+ "message": "Right-click inside a Container tab to assign the site to always open in the Container."
},
"onboarding-5-header": {
"message": "Container tabs when you need them."
},
"onboarding-5-description": {
- "message": "Long-press the New Tab button to create a new container tab."
+ "message": "Long-press the New Tab button to create a new Container tab."
},
"onboarding-6-header": {
"message": "Syncing Containers is now Available!"
},
"onboarding-6-description": {
- "message": "Turn on Sync to share container and site assignments with any computer connected to your Firefox Account."
+ "message": "Turn on Sync to share Container and site assignments with any computer connected to your Firefox account."
},
"onboarding-7-header": {
- "message": "Firefox Account is required to sync."
+ "message": "Firefox account is required to sync."
},
"onboarding-7-description": {
- "message": "Click Sign In to confirm that your Firefox Account is active."
+ "message": "Click Sign In to confirm that your Firefox account is active."
+ },
+ "onboarding-8-description": {
+ "message": "This is a really exciting message about how Container proxies are now supported and about how it’s now really easy to do with Mozilla VPN..."
},
"oneHundredTabsHeader": {
"message": "100 tabs!"
},
"youHaveOpened": {
- "message": "You've opened 100 Container tabs."
+ "message": "You’ve opened 100 Container tabs."
},
"spreadTheWord": {
"message": "If you enjoy Containers, help us spread the word!"
@@ -138,7 +126,7 @@
"message": "OK"
},
"sitesAssignedToThisContainer": {
- "message": "Sites assigned to this container"
+ "message": "Sites assigned to this Container"
},
"options": {
"message": "Options"
@@ -189,10 +177,10 @@
"message": "Next"
},
"openThisSiteConfirmation": {
- "message": "Open this site in your assigned container?"
+ "message": "Open this site in your assigned Container?"
},
"wouldYouStillLikeToOpenConfirmation": {
- "message": "Would you still like to open in this current container?"
+ "message": "Would you still like to open in this current Container?"
},
"rememberMyDecision": {
"message": "Remember my decision for this site"
@@ -215,29 +203,29 @@
"tabBehavior": {
"message": "Tab behavior:"
},
- "firefoxAccountsSync": {
- "message": "Firefox Accounts Sync:"
- },
"enableBookMarkMenus": {
"message": "Enable Bookmark Menus"
},
+ "firefoxAccountsSync": {
+ "message": "Firefox accounts sync:"
+ },
"enableSync": {
- "message": "Enable Sync"
+ "message": "Enable sync"
},
"enableBookMarkMenusDescription": {
- "message": "This setting allows you to open a bookmark or folder of bookmarks in a container."
+ "message": "This setting allows you to open a bookmark or folder of bookmarks in a Container."
},
"enableSyncDescription": {
- "message": "This setting allows you to sync your containers and site assignments across devices."
+ "message": "This setting allows you to sync your Containers and site assignments across devices."
},
"replaceTab": {
- "message": "This setting allows you to sync your containers and site assignments across devices."
+ "message": "This setting allows you to sync your Containers and site assignments across devices."
},
"replaceTabDescription": {
- "message": "Replace the current tab if a page which is assigned to another container is opened (instead of keeping the current tab open). Opening tabs with middle mouse button is not affected."
+ "message": "Replace the current tab if a page which is assigned to another Container is opened (instead of keeping the current tab open). Opening tabs with middle mouse button is not affected."
},
"editWhichContainer": {
- "message": "Edit which container is opened when using the numbered shortcuts."
+ "message": "Edit which Container is opened when using the numbered shortcuts."
},
"keyboardShortCut": {
"message": "Container to open with Keyboard Shortcut $keyId$",
@@ -266,5 +254,59 @@
"content": "$1"
}
}
+ },
+ "chooseLocation": {
+ "message": "Choose location"
+ },
+ "hide": {
+ "message": "Hide"
+ },
+ "show": {
+ "message": "Show"
+ },
+ "protectEachContainer": {
+ "message": "Protect each Container with Mozilla VPN"
+ },
+ "protectThisContainer": {
+ "message": "Protect this Container with Mozilla VPN"
+ },
+ "advancedProxySettings": {
+ "message": "Advanced proxy settings"
+ },
+ "proxyInputLabel": {
+ "message": "Enter custom proxy"
+ },
+ "useCustomLocation": {
+ "message": "Use custom location for this Container"
+ },
+ "clearproxylabel": {
+ "message": "Clear proxy"
+ },
+ "moz-vpn-connected": {
+ "message": "Mozilla VPN is on"
+ },
+ "moz-vpn-disconnected": {
+ "message": "Mozilla VPN is off"
+ },
+ "invalidProxyAlert": {
+ "message": "Please enter a valid proxy URL"
+ },
+ "mozillaVpnMustBeOn": {
+ "message": "Mozilla VPN app must be on to use this feature."
+ },
+ "learnMore": {
+ "message": "Learn more"
+ },
+ "proxyNowAvailable": {
+ "message": "Mozilla VPN and proxy integration is now available!"
+ },
+ "getMozillaVpn": {
+ "message": "Get Mozilla VPN"
+ },
+ "integratewithmozillavpn": {
+ "message": "Integrate your Containers with Mozilla VPN"
+ },
+ "applyToThisContainer": {
+ "message": "Apply to this Container"
}
}
diff --git a/src/css/confirm-page.css b/src/css/confirm-page.css
index 49990f3..3ff1e14 100644
--- a/src/css/confirm-page.css
+++ b/src/css/confirm-page.css
@@ -5,8 +5,8 @@
main {
background: url(/img/onboarding-4.png) no-repeat;
- background-position: -10px -15px;
- background-size: 300px;
+ background-position: 200px 0;
+ background-size: 120px;
margin-inline-start: -350px;
padding-inline-start: 350px;
}
@@ -20,7 +20,7 @@ button .container-name,
font-weight: bold;
}
-@media only screen and (max-width: 1300px) {
+@media only screen and (max-width: 900px) {
main {
background: none;
}
diff --git a/src/css/popup.css b/src/css/popup.css
index a69774c..7c75e33 100644
--- a/src/css/popup.css
+++ b/src/css/popup.css
@@ -1,4 +1,33 @@
+@font-face {
+ font-family: "Metropolis";
+ font-style: normal;
+ font-weight: 800;
+ src: url("/fonts/Metropolis-Medium.woff2") format("woff2");
+}
+
+@font-face {
+ font-family: "Metropolis-Light";
+ font-style: normal;
+ font-weight: 300;
+ src: url("/fonts/Metropolis-Light.woff2") format("woff2");
+}
+
+@font-face {
+ font-family: "Inter";
+ font-style: normal;
+ font-weight: 400;
+ src: url("/fonts/Inter-Regular.woff2") format("woff2");
+}
+
+@font-face {
+ font-family: "Inter-Medium";
+ font-style: normal;
+ font-weight: 500;
+ src: url("/fonts/Inter-Medium.woff2") format("woff2");
+}
+
/* General Rules and Resets */
+
* {
font-size: inherit;
margin-block-end: 0;
@@ -15,33 +44,85 @@ html {
background-color: #fefefe;
box-sizing: border-box;
font-size: 12px;
+ overscroll-behavior: none;
}
body {
- color: #000;
- font-family: Roboto, Noto, "San Francisco", Ubuntu, "Segoe UI", "Fira Sans", message-box, Arial, sans-serif;
+ font-family: var(--fontInter);
font-size: 13px;
- inline-size: calc(var(--overflow-size) + 299px);
-
- /* inline-size: 320px; */
- letter-spacing: -0.1px;
- max-inline-size: calc(var(--overflow-size) + 299px);
+ inline-size: 352px;
+ letter-spacing: -0.125px;
+ min-inline-size: 352px;
+ background-color: var(--bgColor);
--highlight-blue: #1296f8;
- --hr-grey: #e3e3e3;
- --text-grey: #737373;
+ --hr-grey: #cececf91;
+ --text-grey: #262726eb;
+
+ color: var(--text-grey);
}
html,
body {
block-size: 100%; /* Bugfix: issue 948 */
+ max-block-size: 650px;
+ min-block-size: 300px;
+
+ /* stylelint-disable */
+ scrollbar-width: none;
+ /* stylelint-enable */
+ transition: height 0.1s ease-in-out;
}
:root {
+ --fontInter: "Inter", sans-serif;
+ --fontInterMedium: "Inter-Medium", sans-serif;
+ --fontMetropolis: "Metropolis", sans-serif;
+ --fontMetropolisLight: "Metropolis-Light", sans-serif;
--primary-action-color: #248aeb;
--title-text-color: #000;
- --text-normal-color: #4a4a4a;
- --text-heading-color: #000;
+ --text-normal-color: #262726;
+ --text-heading-color: #3d3d3d;
+ --iconArrowLeft: url("/img/arrow-icon-left.svg");
+ --iconArrowRight: url("/img/arrow-icon-right.svg");
+ --iconCloseX: url("/img/close.svg");
+ --iconGear: url("/img/gear-icon.svg");
+ --iconProxyWarning: url("/img/proxy-warning.svg");
+ --logoMozillaVpn: url("/img/moz-vpn-logo.svg");
+ --menuItemHeight: 28px;
+ --marginInline: 16px;
+ --footerHeight: 48px;
+ --bgColor: #fefffe;
+ --blue20: #0df;
+ --blue30: #00b3f4;
+ --blue40: #0090ed;
+ --blue50: #0060df;
+ --blue60: #0250bb;
+ --blue70: #054096;
+ --red30: #ff848b;
+ --red40: #ff6a75;
+ --red50: #ff4f5e;
+ --red60: #e22850;
+ --red70: #c50042;
+ --alertColor: var(--red50);
+ --primaryCtaDefault: var(--blue50);
+ --primaryCtaHover: var(--blue60);
+ --primaryCtaActive: var(--blue70);
+ --primaryCtafocus: rgba(0, 97, 223, 0.4);
+ --controllerDefault: var(--bgColor);
+ --controllerHover: var(--grey10);
+ --controllerActive: var(--grey20);
+ --green50: #3fe1b0;
+ --green60: #3ad4b3;
+ --green70: #1cc4a0;
+ --green80: #00a49a;
+ --grey10: #e7e7e7;
+ --grey20: #cececf;
+ --grey30: #9e9e9e;
+ --grey40: #6d6e6e;
+ --grey50: #3d3d3d;
+ --panelSize: 560px;
+ --rowHeight: 48px;
/* calculated from 12px */
--font-size-heading: 1.33rem; /* 16px */
@@ -58,16 +139,13 @@ body {
--small-text-size: 0.833rem; /* 10px */
--small-radius: 3px;
--icon-button-size: calc(calc(var(--block-line-separation-size) * 2) + 1.66rem); /* 20px */
- --column-panel-inline-size: calc(var(--overflow-size) + 267px);
--inactive-opacity: 0.3;
--overflow-size: 1px;
--icon-fit: 8;
-}
-@media (min-resolution: 1dppx) {
- html {
- font-size: 14px;
- }
+ background: var(--bgColor);
+ margin-block: 0;
+ margin-inline: 0;
}
*,
@@ -76,21 +154,10 @@ body {
box-sizing: inherit;
}
-form {
- margin-block-end: 0;
- margin-block-start: 0;
- margin-inline-end: 0;
- margin-inline-start: 0;
-}
-
table {
border: 0;
border-spacing: 0;
inline-size: 100%;
- margin-block-end: 0;
- margin-block-start: 0;
- margin-inline-end: 0;
- margin-inline-start: 0;
}
/* Helper Classes */
@@ -101,9 +168,11 @@ table {
.scrollable {
flex: 1;
inline-size: 100%;
- max-block-size: 400px;
- overflow-x: hidden;
+ block-size: 100%;
+ overscroll-behavior: none;
overflow-y: auto;
+ overflow-x: hidden;
+ padding-block-end: 8px;
}
.offpage {
@@ -114,27 +183,28 @@ table {
display: none !important;
}
-/* Effect borrowed from tabs in Firefox, ensure that the element flexes to the full width */
+/* effect borrowed from tabs in firefox, ensure that the element flexes to the full width */
.truncate-text {
- inline-size: 100%;
+ inline-size: calc(100vw - 80px);
overflow: hidden;
position: relative;
white-space: nowrap;
+ text-overflow: ellipsis;
}
.truncate-text::after {
- background: white;
+ background: var(--bgColor);
content: " ";
- height: 100%;
- inline-size: 50px;
+ block-size: 100%;
+ inline-size: 100px;
inset-inline-end: 0;
- mask-image: linear-gradient(to right, transparent, white 70%);
+ mask-image: linear-gradient(to right, transparent, var(--bgColor) 70%);
position: absolute;
}
.hover-highlight:hover .truncate-text::after,
.hover-highlight:focus .truncate-text::after {
- background: var(--highlight-blue);
+ background-color: var(--highlight-blue);
mask-image: linear-gradient(to right, transparent, var(--highlight-blue) 50%);
}
@@ -242,8 +312,9 @@ table {
}
/* Buttons */
+
.button {
- color: black;
+ color: var(--text-heading-color);
}
.button.primary {
@@ -261,22 +332,1007 @@ table {
background-color: rgba(0, 0, 0, 0.05);
}
+/* Mozilla VPN status icon */
+
+.moz-vpn-status-icon {
+ color: var(--text-heading-color);
+ background-size: 17px;
+ background-position: left center;
+ font-size: 13px;
+ padding-inline-start: 22px;
+ padding-inline-end: 32px;
+}
+
+.moz-vpn-status-icon.connected {
+ background-image: url("/img/moz-vpn-status-icons/moz-vpn-connected.svg");
+}
+
+.moz-vpn-status-icon.disconnected {
+ background-image: url("/img/moz-vpn-status-icons/moz-vpn-disconnected.svg");
+}
+
+.moz-vpn-logotype.vpn-status-container-list {
+ color: var(--text-heading-color);
+ background-size: 16px;
+ background-position: left center;
+ font-size: 12px;
+ padding-inline-start: 19px;
+ padding-inline-end: 22px;
+ margin-inline-end: 20px;
+ align-items: center;
+}
+
+.moz-vpn-connection-status-indicator.container-list-status-icon {
+ block-size: 16px;
+ inline-size: 16px;
+}
+
+/* Toggle Switch */
+
+.switch {
+ display: inline-block;
+ block-size: 24px;
+ position: relative;
+ inline-size: 45px;
+}
+
+.switch .switch-input {
+ block-size: 0;
+ opacity: 0;
+ inline-size: 0;
+}
+
+.slider {
+ background-color: var(--grey20);
+ border-radius: 24px;
+ inset-block-end: 0;
+ box-shadow: 0 0 0 2px var(--bgColor), 0 0 0 4px var(--bgColor);
+ inset-inline-start: 0;
+ position: absolute;
+ inset-inline-end: 0;
+ inset-block-start: 0;
+ transition: 0.1s ease-in-out;
+}
+
+.slider::before {
+ background-color: #fff;
+ border-radius: 50%;
+ inset-block-end: 3px;
+ content: "";
+ block-size: 18px;
+ inset-inline-start: 3px;
+ position: absolute;
+ transition: 0.1s ease-in-out;
+ inline-size: 18px;
+}
+
+input:hover + .slider {
+ background-color: var(--grey30);
+}
+
+input:focus + .slider {
+ box-shadow: 0 0 0 2px var(--bgColor), 0 0 0 4px var(--grey30);
+}
+
+input:active + .slider {
+ background-color: var(--grey40);
+}
+
+input:checked + .slider {
+ background-color: var(--green50);
+}
+
+input:checked:hover + .slider {
+ background-color: var(--green60);
+}
+
+input:checked:focus + .slider {
+ box-shadow: 0 0 0 2px var(--bgColor), 0 0 0 4px var(--green70);
+}
+
+input:checked:active + .slider {
+ background-color: var(--green70);
+}
+
+input:checked + .slider::before {
+ transform: translateX(21px);
+}
+
+.hidden {
+ visibility: hidden;
+}
+
+/* Primary CTA Buttons */
+
+.primary-cta {
+ background-color: var(--primaryCtaDefault);
+ border: transparent;
+ border-radius: 4px;
+ color: #fff;
+ transition: background-color 0.2s ease-in-out;
+}
+
+.primary-cta:hover {
+ background-color: var(--primaryCtaHover);
+}
+
+.primary-cta:focus {
+ outline: none;
+ box-shadow: 0 0 0 1px var(--blue60), 0 0 0 4px var(--primaryCtafocus);
+}
+
+.primary-cta:active {
+ background-color: var(--primaryCtaActive);
+}
+
+/* Mozilla VPN tout */
+
+#moz-vpn-tout {
+ opacity: 0;
+ background-color: var(--bgColor);
+ visibility: visible;
+ max-block-size: 500px;
+ position: absolute;
+ inset-block-end: var(--footerHeight);
+ inset-inline-start: 0;
+ inset-inline-end: 0;
+ box-shadow: 0 0 7px 0 #9498a25e;
+ animation: appear 0.2s ease-out 0.5s forwards;
+ transition: opacity 0.1s ease-in-out, max-height 0.3s ease-in-out;
+}
+
+#moz-vpn-tout.disappear {
+ animation: hideTout 0.2s ease-in forwards;
+}
+
+@keyframes appear {
+ 0% {
+ opacity: 0;
+ transform: translateY(10%);
+ }
+
+ 100% {
+ opacity: 1;
+ transform: translateY(0%);
+ }
+}
+
+@keyframes hideTout {
+ 0% {
+ transform: translateY(0%);
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 1;
+ }
+
+ 100% {
+ transform: translateY(20%);
+ opacity: 0;
+ }
+}
+
+/* Mozilla VPN Controller UI in Container Management Panel */
+
+.moz-vpn-content,
+.moz-vpn-controller-content {
+ display: flex;
+ position: relative;
+ flex-direction: column;
+ padding-block: 16px;
+ transition: max-height 0.3s ease-in-out, padding-block-end 0.2s ease-in-out;
+
+ /* max-block-size: 56px; */
+ min-block-size: 56px;
+ box-shadow: 0 0 0 1px var(--hr-grey);
+}
+
+.moz-vpn-connection-status-indicator {
+ position: absolute;
+ inset-inline-end: 0;
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ size: 0;
+ color: rgba(0, 0, 0, 0);
+ block-size: 24px;
+ inline-size: 24px;
+}
+
+.current-country-flag {
+ display: inline-block;
+ background-repeat: no-repeat;
+ background-position: left center;
+ background-size: contain;
+ block-size: 16px;
+ inline-size: 16px;
+}
+
+.moz-vpn-controller-content.show-server-button {
+ padding-block-end: 56px;
+ transition: 0.2s ease-in-out;
+}
+
+.dismiss-moz-vpn-tout {
+ margin-inline-start: auto;
+ block-size: 24px;
+ inline-size: 24px;
+ background: var(--bgColor);
+ background-image: var(--iconCloseX);
+ border: none;
+ border-radius: 4px;
+}
+
+.flag-img {
+ block-size: 13px;
+ margin-inline-end: 4px;
+ opacity: 0.9;
+}
+
+.page-action-flag {
+ margin-inline-end: var(--marginInline);
+}
+
+.display-none {
+ display: none;
+}
+
+.proxy-disabled {
+ opacity: 0.4;
+}
+
+fieldset.proxies {
+ position: absolute;
+ inset-block-start: 120px;
+ inset-inline-start: 0;
+ inset-inline-end: 0;
+ block-size: 60px;
+ display: flex;
+ background: #5cabff;
+ justify-content: center;
+ align-content: center;
+ align-items: center;
+ flex-direction: row;
+ pointer-events: none;
+}
+
+input.proxies {
+ font-size: 6px;
+ block-size: 20px;
+ max-block-size: 20px;
+ padding-block: 0 !important;
+ padding-inline: 0 !important;
+ display: inline-flex;
+ inline-size: 40% !important;
+ pointer-events: none;
+}
+
+.moz-vpn-cta {
+ block-size: 32px;
+ margin-block: 16px;
+ margin-inline: var(--marginInline);
+ text-align: center;
+}
+
+.apply-to-container {
+ block-size: 32px;
+ inline-size: 100%;
+ text-align: center;
+ margin-block: 16px;
+}
+
+#moz-vpn-current-server {
+ align-items: center;
+ border: none;
+ display: flex;
+ block-size: 48px;
+ margin-block-start: 8px;
+ background-image: var(--iconArrowRight);
+ background-position: calc(100% - 24px) center;
+ background-repeat: no-repeat;
+ background-size: 9px;
+ outline: none;
+ padding-inline-start: 20px;
+ visibility: visible;
+ position: absolute;
+ inset-block-end: 0;
+ inline-size: 100%;
+ opacity: 0;
+ transition: opacity 0.2s ease-in-out;
+}
+
+.moz-vpn-controller-content.show-server-button #moz-vpn-current-server {
+ opacity: 1;
+}
+
+.moz-vpn-controller-content.show-server-button #moz-vpn-current-server[disabled] {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+@keyframes serverButtonAppear {
+ 0% {
+ opacity: 0;
+ visibility: hidden;
+ z-index: -1;
+ }
+
+ 90% {
+ z-index: -1;
+ visibility: hidden;
+ }
+
+ 100% {
+ visibility: visible;
+ z-index: 1;
+ opacity: 1;
+ }
+}
+
+#moz-vpn-current-server.hidden {
+ block-size: 0;
+ opacity: 0;
+ visibility: hidden;
+ z-index: -1;
+}
+
+.current-city-name {
+ padding-inline-start: 12px;
+}
+
+.collapsible-content {
+ max-block-size: 0;
+ opacity: 0;
+ visibility: hidden;
+ background-color: var(--bgColor);
+ transition: max-height 0.2s ease-in-out, opacity 0.2s ease-in-out, visibility 0.2s ease-in-out;
+}
+
+.moz-vpn-subtitle {
+ font-size: 12px;
+ flex: 0 1 80%;
+ color: var(--text-normal-color);
+}
+
+.collapsible-content > .flx-row.flx-space-between {
+ inline-size: calc(100% - 40px);
+ margin-inline: auto;
+ padding-block-start: 12px;
+}
+
+[disabled] {
+ pointer-events: none;
+ opacity: 0.5;
+}
+
+#current-proxy {
+ font-size: 12px;
+ color: var(--grey30);
+ line-height: 13px;
+}
+
+.expanded .collapsible-content {
+ max-block-size: 500px;
+ opacity: 1;
+ visibility: visible;
+}
+
+.hide-label,
+.show-label {
+ line-height: 100%;
+ position: absolute;
+ inset-inline-end: 0;
+ transition: visibility 0.2s ease-in-out, color 0.2s ease-in-out, opacity 0.2s ease-in-out;
+}
+
+.expanded .hide-label,
+.show-label {
+ visibility: visible;
+ opacity: 1;
+}
+
+/* stylelint-disable */
+.hide-label,
+.expanded .show-label {
+ visibility: hidden;
+ opacity: 0;
+}
+
+/* stylelint-enable */
+
+.expand-collapse {
+ inline-size: 50%;
+ margin-inline-start: auto;
+ pointer-events: all;
+}
+
+.button-wrapper {
+ margin-inline: 20px;
+}
+
+/* Advanced Proxy Settings Button */
+
+#edit-advanced-proxy-input {
+ padding-inline-end: 40px;
+}
+
+#edit-advanced-proxy-input.valid:focus {
+ box-shadow: 0 0 0 3px #3fe1b030;
+ border-color: var(--green80);
+}
+
+.advanced-proxy-settings-btn {
+ background-color: var(--bgColor);
+ box-shadow: 0 0 0 1px var(--hr-grey);
+ background-image: var(--iconGear), var(--iconArrowRight);
+ background-position: 16px center, calc(100% - 24px) center;
+ background-repeat: no-repeat;
+ background-size: 24px 24px, 9px;
+ border: none;
+ color: var(--text-grey);
+ block-size: 56px;
+ min-block-size: 56px;
+ line-height: 19px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ outline: none;
+ padding-inline-start: 44px;
+ z-index: 2;
+ transition: opacity 0.1s ease-in-out, background-color 0.1s ease-in-out;
+}
+
+.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ pointer-events: none;
+}
+
+.advanced-proxy-settings-btn:hover,
+.advanced-proxy-settings-btn:focus {
+ background-color: var(--grey10);
+ outline: none;
+}
+
+#clear-advanced-proxy-input {
+ position: absolute;
+ inset-inline-end: 8px;
+ inset-block-start: 7px;
+ border: none;
+ block-size: 22px;
+ inline-size: 22px;
+ border-radius: 50%;
+ background-image: var(--iconCloseX);
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: 16px;
+ font-size: 1;
+ color: var(--bgColor);
+}
+
+.proxy-title-container-color {
+ block-size: 12px;
+ inline-size: 12px;
+ z-index: 10;
+ border-radius: 50%;
+}
+
+.advanced-proxy-panel-content {
+ padding-block: 16px;
+ padding-inline: 20px;
+ margin-block-start: 56px;
+ display: flex;
+ flex-direction: column;
+}
+
+.advanced-proxy-input-wrapper {
+ margin-block-start: 12px;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+}
+
+.proxy-validity {
+ position: absolute;
+ inset-block-start: 42px;
+ inset-inline-start: 16px;
+ visibility: hidden;
+ opacity: 0;
+ background-color: var(--alertColor);
+ color: white;
+ border-radius: 4px;
+ padding-block: 2px;
+ padding-inline: 4px;
+ transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out;
+}
+
+.proxy-validity::after {
+ content: "";
+ block-size: 8px;
+ inline-size: 8px;
+ background-color: var(--alertColor);
+ inset-block-start: -4px;
+ position: absolute;
+ transform: rotate(45deg);
+ inset-inline-start: 12px;
+}
+
+.invalid .proxy-validity {
+ opacity: 1;
+ z-index: 10;
+ visibility: visible;
+}
+
+.invalid .proxy-host.primary-input {
+ border-color: var(--red50);
+ box-shadow: 0 0 0 3px #ff848b70;
+}
+
+.invalid button {
+ pointer-events: none;
+ opacity: 0.5;
+}
+
+/* Mozilla VPN Server list */
+
+.moz-vpn-logo,
+.moz-vpn-logotype {
+ color: var(--text-heading-color);
+ background-image: var(--logoMozillaVpn);
+ background-repeat: no-repeat;
+ background-size: 24px;
+ background-position: left center;
+ font-family: var(--fontMetropolis);
+ font-size: 15px;
+ line-height: 24px;
+ padding-inline-start: 28px;
+ position: relative;
+ padding-inline-end: 32px;
+}
+
+#moz-vpn-server-list-panel {
+ block-size: var(--panelSize);
+ max-block-size: var(--panelSize);
+ min-block-size: var(--panelSize);
+}
+
+.proxy-panel-title {
+ line-height: var(--rowHeight);
+ block-size: var(--rowHeight);
+ border-block-end: 1px solid var(--hr-grey);
+ position: fixed;
+ z-index: 1;
+ background-color: var(--bgColor);
+ box-shadow: 0 0 13px -2px #b5b5b500;
+ transition: box-shadow 0.5s ease;
+}
+
+.drop-shadow {
+ box-shadow: 0 0 13px -2px #b5b5b54d;
+}
+
+.moz-vpn-server-list {
+ padding-block-start: 4px;
+ font-size: 15px;
+ color: var(--grey50);
+ position: absolute;
+ inset-block-start: var(--rowHeight);
+ inset-inline-start: 0;
+ inset-inline-end: 0;
+ overflow: scroll;
+ overscroll-behavior: none;
+ block-size: calc(var(--panelSize) - var(--rowHeight));
+ min-block-size: calc(var(--panelSize) - var(--rowHeight));
+}
+
+#moz-vpn-return {
+ z-index: 2;
+}
+
+.server-list-item {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ background-color: var(--bgColor);
+}
+
+.server-country-flag {
+ inline-size: 16px;
+ margin-inline-start: 16px;
+ margin-block: auto;
+ pointer-events: none;
+}
+
+.server-country-name {
+ padding-block: 0;
+ padding-inline-end: 0;
+ padding-inline-start: 20px;
+ font-family: var(--fontMetropolis);
+ pointer-events: none;
+ color: var(--text-heading-color);
+}
+
+.server-city-list-item,
+.server-city-list-visibility-btn {
+ block-size: 40px;
+ margin-block-start: 4px;
+ margin-block-end: 4px;
+ margin-inline-start: 8px;
+ margin-inline-end: 8px;
+ inline-size: calc(100% - 16px);
+}
+
+.server-city-list-visibility-btn {
+ display: flex;
+ background-color: var(--bgColor);
+ border-radius: 4px;
+ border: none;
+ transition: background-color 0.3s ease;
+}
+
+.server-city-list-visibility-btn:hover {
+ background-color: var(--grey10);
+}
+
+.server-city-list-visibility-btn:active {
+ background-color: var(--grey20);
+}
+
+.toggle {
+ background-image: url("/img/arrow-toggle.svg");
+ background-position: center center;
+ background-repeat: no-repeat;
+ block-size: 24px;
+ margin-inline-start: 8px;
+ pointer-events: none;
+ transform: rotate(-90deg);
+ transition: transform 0.275s ease-in-out;
+ inline-size: 24px;
+}
+
+.expanded .toggle {
+ transform: rotate(0deg);
+}
+
+.server-city-list {
+ block-size: 0;
+ opacity: 0;
+ transition: height 0.3s ease-in-out, opacity 0.3s ease, visibility 0.4s ease;
+ list-style-type: none;
+ visibility: hidden;
+}
+
+.expanded .server-city-list {
+ opacity: 1;
+ visibility: visible;
+}
+
+.server-city-list-item {
+ align-items: center;
+ display: flex;
+ position: relative;
+}
+
+.server-city-name {
+ font-family: var(--fontMetropolisLight);
+ font-weight: 300;
+ color: var(--text-grey);
+ padding-inline-start: 18px;
+}
+
+/* ----- controller buttons ------- */
+
+.controller {
+ background-color: var(--bgColor);
+ color: var(--text-grey);
+ transition: background-color 0.1s ease-in-out;
+}
+
+.controller:hover,
+.controller:focus {
+ background-color: var(--controllerHover);
+}
+
+.controller:active {
+ background-color: var(--controllerActive);
+}
+
+/* WARNING MODAL ---- */
+
+.modal-warning {
+ position: absolute;
+ inset-block-start: 0;
+ inset-block-end: 0;
+ inset-inline-start: 0;
+ background-color: #42404c89;
+ z-index: 4;
+ display: flex;
+ justify-content: center;
+}
+
+.modal-content {
+ background-color: var(--bgColor);
+ inline-size: 80%;
+ block-size: 80%;
+ margin-inline: auto;
+ margin-block: auto;
+ border-radius: 16px;
+ box-shadow: 1px 2px 10px 10px var(--bgDark);
+ padding-block: 20px;
+ padding-inline: 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+}
+
+/* ----- MozillaVPN Proxy Unavailable-Specific -------- */
+
+[data-moz-proxy-warning="proxy-unavailable"] {
+ position: relative;
+}
+
+.flag-img.proxy-unavailable {
+ opacity: 0.5;
+}
+
+/* ----- MozillaVPN Status Tooltips -------- */
+
+.tooltip {
+ opacity: 0;
+ position: absolute;
+ z-index: 10;
+ inset-block-start: 24px;
+ inset-inline-end: -3px;
+ font-size: 11px;
+ font-family: var(--fontInter) !important;
+ font-weight: 300;
+ color: var(--text-normal-color);
+ background-color: var(--bgColor);
+ padding-inline: 8px;
+ padding-block: 4px;
+ border-radius: 4px;
+ box-shadow: 0 0 12px 3px #0000001c;
+ transform: translateY(-2px);
+ transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
+ min-inline-size: 170px;
+ line-height: 1.3;
+ text-align: center;
+ pointer-events: none;
+}
+
+.tooltip::before {
+ content: "";
+ block-size: 7px;
+ inline-size: 7px;
+ border-radius: 1px;
+ transform: rotate(45deg);
+ background: inherit;
+ position: absolute;
+ inset-block-start: -3px;
+ inset-inline-end: 9px;
+}
+
+[data-moz-proxy-warning="proxy-unavailable"]:hover .tooltip,
+[data-moz-proxy-warning="proxy-unavailable"]:active .tooltip {
+ opacity: 1;
+ transform: translateY(0);
+ transition: opacity 0.2s ease-in-out 0.5s, transform 0.2s ease-in-out 0.5s;
+}
+
+.moz-vpn-logotype.vpn-status-container-list:hover .tooltip {
+ opacity: 1;
+ transform: translateY(0);
+ transition: opacity 0.2s ease-in-out 1s, transform 0.2s ease-in-out 1s;
+}
+
+.tooltip.proxy-unavailable::after {
+ inset-inline-start: 4px;
+ inset-inline-end: auto;
+}
+
+.tooltip.proxy-unavailable::before {
+ inset-inline-start: 12px;
+}
+
+.tooltip.proxy-unavailable {
+ inset-inline-start: 32px;
+ inset-block-start: 32px;
+ padding-inline-start: 32px;
+ text-align: left;
+ background-image: var(--iconProxyWarning);
+ background-size: 24px 24px;
+ background-repeat: no-repeat;
+ background-position: 4px 4px;
+}
+
+/* ------------ SERVER LIST RADIO BUTTONS ------------ */
+
+.server-radio-btn {
+ block-size: 20px;
+ opacity: 0;
+ position: fixed;
+ inline-size: 20px;
+}
+
+.server-radio-control {
+ border-radius: 50%;
+ border: 2px solid var(--grey40);
+ block-size: 20px;
+ margin-inline-start: 46px;
+ pointer-events: none;
+ position: relative;
+ inline-size: 20px;
+ transition: border 0.1s ease-in-out;
+}
+
+.server-radio-btn:checked + .server-radio-control {
+ border-color: var(--primaryCtaDefault);
+ transition: border-color 0.2s ease;
+}
+
+.server-radio-control::after {
+ background-color: var(--grey40);
+ border-radius: 50%;
+ inset-block-end: 0;
+ content: "";
+ block-size: 12px;
+ inset-inline-start: 0;
+ margin-inline: auto;
+ margin-block: auto;
+ opacity: 0;
+ position: absolute;
+ inset-inline-end: 0;
+ inset-block-start: 0;
+ transition: opacity 0.1s ease-in-out;
+ inline-size: 12px;
+}
+
+/* Unchecked radio button styles */
+
+.server-city-list-item:hover .server-radio-control {
+ border: 2px solid var(--grey50);
+}
+
+.server-city-list-item:hover .server-radio-control::after {
+ opacity: 0.3;
+}
+
+.server-city-list-item:active .server-radio-control::after {
+ opacity: 0.5;
+}
+
+/* Checked radio button rules */
+
+.server-city-list-item:hover .server-radio-btn:checked + .server-radio-control {
+ border: 2px solid var(--primaryCtaDefault);
+}
+
+.server-radio-btn:checked + .server-radio-control::after {
+ background-color: var(--primaryCtaDefault);
+ opacity: 1;
+}
+
+/* Helpers */
+
+.add-bg-color {
+ background-color: var(--bgColor);
+ z-index: 2;
+}
+
+.flx-space-between {
+ justify-content: space-between;
+}
+
+.flx-row {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+}
+
+/* stylelint-disable */
+
+v-padding-hack16 {
+ block-size: 16px;
+}
+
+v-padding-hack-4 {
+ block-size: 4px;
+ inline-size: 100%;
+}
+
+v-padding-hack-footer {
+ block-size: var(--footerHeight);
+ inline-size: 100%;
+}
+
+/* stylelint-enable */
+
+.flx-col {
+ display: flex;
+ flex-direction: column;
+}
+
+fieldset,
+.options-header {
+ padding-block-end: 16px;
+}
+
+.options-header {
+ display: none;
+}
+
+/* ------ Input ----- */
+
+input[type=text] {
+ block-size: 36px;
+ border-radius: 4px;
+ background-color: var(--bgColor);
+ color: var(--text-grey);
+ padding-block: 8px;
+ padding-inline: 8px;
+}
+
+/* Blue links */
+
+.blue-link {
+ box-sizing: content-box;
+ text-decoration: none;
+ align-items: center;
+ background-color: transparent;
+ border: none;
+ color: var(--primaryCtaDefault);
+ display: flex;
+ block-size: 24px;
+ line-height: 24px;
+ position: relative;
+ margin-inline: auto;
+ transition: color 0.1s ease-in-out;
+}
+
+.blue-link,
+.hide-show-label {
+ block-size: 24px;
+ line-height: 24px;
+}
+
+.blue-link:hover {
+ color: var(--primaryCtaHover);
+}
+
+.blue-link:focus,
+.blue-link:focus .hide-show-label {
+ text-decoration: underline;
+ outline: none;
+}
+
+/* ------------ ------------ ------------ ------------ */
+
/* Panels keep everything together */
.panel {
display: flex;
flex-direction: column;
justify-content: space-between;
- min-block-size: 400px;
+ position: relative;
+ max-block-size: 601px;
+ background-color: var(--bgColor);
+ transition: height 0.1s ease-in-out;
+}
+
+.container-panel {
+ min-block-size: 500px;
+}
+
+.delete-container-panel {
+ min-block-size: 300px;
}
.panel.onboarding,
.achievement-panel {
align-items: center;
- block-size: 360px;
- margin-block-end: 16px;
- margin-block-start: 16px;
- margin-inline-end: 16px;
- margin-inline-start: 16px;
+ margin-block: var(--marginInline);
+ margin-inline: var(--marginInline);
min-block-size: 360px;
}
@@ -311,6 +1367,7 @@ table {
margin-inline-end: 0;
margin-inline-start: 0;
max-inline-size: 80%;
+ font-family: var(--fontMetropolis);
}
.onboarding p {
@@ -338,8 +1395,9 @@ table {
align-items: center;
display: flex;
flex-direction: row;
- height: 44px;
+ block-size: 44px;
inline-size: 100%;
+ font-family: var(--fontMetropolis);
}
.half-onboarding-button {
@@ -350,7 +1408,7 @@ table {
display: flex;
flex: 1 0 auto;
font-size: 14px;
- height: 44px;
+ block-size: 44px;
inline-size: 50%;
justify-content: center;
margin-inline-end: 4px;
@@ -360,7 +1418,7 @@ table {
.grey-button {
background-color: #e3e3e3;
- color: #000;
+ color: var(--grey50);
}
.onboarding-button:hover,
@@ -421,6 +1479,20 @@ manage things like container crud */
filter: url('/img/filters.svg#fill');
}
+.usercontext-icon::before {
+ transform: scale(1);
+ transform-origin: center;
+ transition: fill 0.1s ease-in-out, transform 0.1s ease-in-out;
+}
+
+.radio-container:active .usercontext-icon::before {
+ transform: scale(0.95);
+}
+
+#edit-container-panel-choose-icon .radio-container:hover .usercontext-icon::before {
+ fill: var(--grey50) !important;
+}
+
.mac-icon {
background-image: url('/img/multiaccountcontainer-16.svg');
background-position: center center;
@@ -442,11 +1514,11 @@ manage things like container crud */
fill: #0094fb;
}
-/* Panel Footer */
+/* Panel footer */
.panel-footer {
align-items: center;
background: #efefef;
- block-size: var(--icon-button-size);
+ block-size: var(--footerHeight);
border-block-end: 1px solid #d8d8d8;
color: #000;
display: flex;
@@ -455,6 +1527,10 @@ manage things like container crud */
justify-content: space-between;
}
+#container-info-panel {
+ block-size: 100vh;
+}
+
.container-info-has-tabs,
.container-info-tab-row {
align-items: center;
@@ -516,8 +1592,9 @@ manage things like container crud */
.radio-choice > .radio-container {
align-items: center;
- block-size: 25px;
+ block-size: 32px;
display: flex;
+ justify-content: center;
flex: 0 0 calc(100% / var(--icon-fit));
}
@@ -557,6 +1634,9 @@ manage things like container crud */
-moz-appearance: none;
display: inline;
opacity: 0;
+ position: absolute;
+ margin-block: auto;
+ margin-inline: auto;
}
.radio-choice > .radio-container > [type="radio"]:checked + label {
@@ -576,42 +1656,27 @@ manage things like container crud */
display: flex;
flex-direction: row;
flex-wrap: wrap;
- inline-size: 80%;
- margin-block-end: 10px;
- margin-inline-end: 0;
- margin-inline-start: 0;
- padding-block-end: 0;
- padding-block-start: 0;
- padding-inline-end: 0;
- padding-inline-start: 0;
}
-.edit-container-panel fieldset:last-of-type {
- margin-block-start: 16px;
+#edit-container-choose-color {
+ justify-content: space-between;
}
.edit-container-panel input[type="text"] {
- block-size: 36px;
- border-radius: 3px;
- font-size: 14px;
inline-size: 100%;
- padding-block-end: 5px;
- padding-block-start: 5px;
- padding-inline-end: 5px;
- padding-inline-start: 5px;
+ margin-inline: 4px;
+}
+
+input[type="text"]:focus {
+ box-shadow: 0 0 0 3px var(--primaryCtafocus);
+ outline: none;
+ border-color: var(--blue70);
}
.edit-container-panel legend,
.options-header {
+ margin-inline: 4px;
flex: 1 0;
- font-size: 14px !important;
- margin-block-end: 4px;
- margin-block-start: -6px;
-}
-
-.options-header {
- margin-block-end: 8px;
- margin-block-start: 6px;
}
/* Achievement panel elements */
@@ -643,8 +1708,8 @@ manage things like container crud */
}
.cta-icon {
- height: 18px;
- padding-right: 0.5em;
+ block-size: 18px;
+ padding-inline-end: 0.5em;
vertical-align: middle;
}
@@ -665,31 +1730,38 @@ manage things like container crud */
}
h3.title {
- block-size: 40px;
+ block-size: 48px;
color: #000;
- font-size: 13px;
+ font-family: var(--fontMetropolis);
+ font-size: 14px;
font-weight: bold;
inline-size: 100%;
letter-spacing: -0.1px;
- line-height: 40px;
+ line-height: 48px;
text-align: center;
}
.menu {
border-style: none;
inline-size: 100%;
+ padding-block: 8px;
}
.menu-item {
cursor: pointer;
- height: 24px;
+ block-size: var(--menuItemHeight);
inline-size: 100%;
- line-height: 24px;
+ line-height: var(--menuItemHeight);
+}
+
+.menu-text {
+ display: flex;
+ flex: 1;
}
.menu-item td {
+ align-items: center;
display: flex;
- max-inline-size: 300px;
}
.menu-item.drag-over td {
@@ -702,9 +1774,13 @@ h3.title {
font-style: italic;
}
+.hover-highlight {
+ transition: background-color 0.1s ease-in-out, color 0.1s ease-in-out;
+}
+
.hover-highlight:hover,
.hover-highlight:focus {
- background: var(--highlight-blue);
+ background-color: var(--highlight-blue);
color: #fff;
}
@@ -712,155 +1788,162 @@ h3.title {
display: flex;
inline-size: calc(100% - 40px);
max-inline-size: 260px;
-}
-
-.menu-text {
- line-height: 24px;
+ cursor: default;
}
.menu-icon {
display: block;
- height: 16px;
+ block-size: 16px;
inline-size: 23px;
- margin-block-end: 4px;
- margin-block-start: 4px;
+ margin-block-end: auto;
+ margin-block-start: auto;
margin-inline-end: 8px;
- margin-inline-start: 16px;
+ margin-inline-start: var(--marginInline);
text-align: center;
}
-/* Maintain 1:1 square ratio for Favicons of websites added to a specific container */
+/* Maintain 1:1 square ratio for favicons of websites added to a specific container */
#edit-sites-assigned .menu-icon,
#container-info-table .menu-icon {
inline-size: 16px;
}
.menu-right-float {
- height: 24px;
- inline-size: 60px;
text-align: right;
+ margin-inline-start: auto;
+ margin-inline-end: 0;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ padding-inline-start: 16px;
}
.container-count {
- opacity: 0.6;
- padding-block-end: 0;
- padding-block-start: 0;
- padding-inline-end: 6px;
- padding-inline-start: 0;
- text-align: right;
+ opacity: 0.7;
+ text-align: center;
+ min-inline-size: 24px;
+ margin-inline-end: 4px;
}
.menu-arrow {
- display: inline-block;
- float: right;
- height: 24px;
- inline-size: 18px;
- padding-block-end: 6px;
- padding-block-start: 6px;
- padding-inline-end: 12px;
- padding-inline-start: 0;
+ align-items: center;
+ display: flex;
+ justify-content: flex-end;
+ block-size: 24px;
+ margin-inline-end: 20px;
text-align: center;
}
.menu-arrow img {
- height: 12px;
+ block-size: 24px;
inline-size: 12px;
padding-block-end: 2px;
padding-block-start: 2px;
padding-inline-end: 2px;
padding-inline-start: 2px;
+ opacity: 0.9;
}
hr {
border: 0;
border-block-start: 1px solid var(--hr-grey);
display: block;
- margin-block-end: 0;
- margin-block-start: 6px;
- margin-inline-end: 0;
- margin-inline-start: 0;
- padding-block-end: 6px;
- padding-block-start: 0;
- padding-inline-end: 0;
- padding-inline-start: 0;
+}
+
+.sub-header-wrapper {
+ margin-block-start: 12px;
}
.sub-header {
- color: var(--text-grey);
- height: 24px;
+ color: var(--text-heading-color);
+ block-size: 24px;
line-height: 24px;
padding-block-end: 0;
padding-block-start: 0;
- padding-inline-end: 16px;
- padding-inline-start: 16px;
+ padding-inline-start: 20px;
+ font-family: var(--fontInterMedium);
}
.edit-form {
color: var(--text-grey);
flex: 1;
- padding-block-end: 0;
- padding-block-start: 0;
+ padding-block-end: 16px;
+ padding-block-start: 16px;
padding-inline-end: 16px;
padding-inline-start: 16px;
}
-.identities-list {
- margin-block-end: 41px;
- margin-block-start: 0;
- margin-inline-end: 0;
- margin-inline-start: 0;
-}
-
.bottom-btn {
- background-color: var(--hr-grey);
- border: solid 1px #d9d9d9;
- cursor: pointer;
- height: 41px;
- inline-size: 100%;
inset-block-end: 0;
- line-height: 41px;
- overflow: hidden;
- padding-block-end: 0;
- padding-block-start: 0;
+ box-shadow: 0 0 0 1px var(--hr-grey);
+ cursor: pointer;
+ block-size: var(--footerHeight);
+ inline-size: 100%;
+ line-height: var(--footerHeight);
padding-inline-end: 16px;
padding-inline-start: 16px;
-}
-
-.delete-container {
- background-color: #fff;
- border-block-start: solid 1px var(--hr-grey);
- cursor: default;
- display: flex;
- height: 65px;
- inline-size: 100%;
- justify-content: space-between;
- padding-block-end: 27px;
- padding-block-start: 9px;
- padding-inline-end: 18px;
- padding-inline-start: 17px;
+ position: absolute;
+ text-align: center;
+ font-size: 14px;
+ font-family: var(--fontMetropolis);
+ color: var(--text-heading-color);
+ pointer-events: all;
}
.delete-btn {
- background-color: rgba(12, 12, 13, 0.1);
- border: 0;
- border-radius: 2px;
+ background-color: var(--bgColor);
+ border: none;
+ border-left: none;
+ border-right: none;
+ border-block-end: none;
+ box-shadow: 0 0 0 1px var(--hr-grey);
+ color: var(--alertColor);
+ cursor: default;
+ display: flex;
+ block-size: var(--rowHeight);
+ justify-content: center;
+ line-height: var(--rowHeight);
+ pointer-events: all;
+ transition: background-color 0.1s ease-in-out, border-color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+}
+
+.alert-text {
+ font-family: var(--fontMetropolis);
+ background-color: var(--bgColor);
+ color: var(--alertColor);
cursor: pointer;
- height: 30px;
- inline-size: 100%;
- line-height: 30px;
text-align: center;
}
+.alert-text:hover,
+.alert-text:focus {
+ background-color: rgba(255, 79, 94, 0.05);
+ box-shadow: 0 0 0 1px rgba(255, 79, 94, 0.05);
+}
+
+.delete-btn:active {
+ background-color: rgba(255, 79, 94, 0.1);
+ box-shadow: 0 0 0 1px var(--alertColor);
+}
+
+.delete-btn:focus {
+ box-shadow: 0 0 0 1px var(--alertColor);
+ outline: none;
+}
+
.btn-return.arrow-left {
- background-color: rgba(255, 255, 255, 1);
- background-image: url("/img/arrow-icon-left.svg");
+ background-image: var(--iconArrowLeft);
border: 0;
cursor: pointer;
- height: 1.2rem;
- inline-size: 1.2rem;
- inset-block-start: 15px;
- left: 15px;
+ inset-block-start: 8px;
+ inset-inline-start: 8px;
position: absolute;
+ z-index: 2;
+ block-size: 32px;
+ inline-size: 32px;
+ background-repeat: no-repeat;
+ border-radius: 4px;
+ background-position: center center;
}
input {
@@ -869,8 +1952,6 @@ input {
}
.form-header {
- height: 23px;
- line-height: 23px;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 0;
@@ -878,11 +1959,15 @@ input {
}
.edit-container-panel-name-input {
- height: 29px;
+ color: var(--text-grey);
+ block-size: 32px;
}
.container-options {
- height: 23px;
+ block-size: 24px;
+ margin-inline: 4px;
+ display: flex;
+ justify-content: space-between;
}
.site-isolation {
@@ -891,20 +1976,16 @@ input {
.options-label {
cursor: pointer;
- padding-inline-start: 4px;
-}
-
-.manage-assigned-sites-list {
- color: var(--highlight-blue);
+ pointer-events: none;
}
.info-icon {
cursor: pointer;
- height: 16px;
+ block-size: 16px;
inline-size: 16px;
- inset-block-start: 13px;
+ inset-block-start: 16px;
position: absolute;
- right: 13px;
+ inset-inline-end: 20px;
text-align: center;
text-decoration: none;
}
@@ -918,9 +1999,8 @@ input {
.trash-button {
display: inline-block;
- float: right;
- height: 16px;
- inline-size: 16px;
+ block-size: 20px;
+ inline-size: 20px;
margin-block-end: 4px;
margin-block-start: 4px;
margin-inline-end: 10px;
@@ -939,48 +2019,104 @@ tr:hover > td > .trash-button {
.move-button {
cursor: move;
display: inline-block;
- height: 100%;
- inline-size: 16px;
- margin-block-end: 4px;
- margin-block-start: 4px;
- margin-inline-end: 10px;
- margin-inline-start: auto;
- text-align: center;
}
.move-button > img {
- height: 16px;
+ block-size: 16px;
+ margin-inline-end: 20px;
+ margin-inline-start: 8px;
}
@media (prefers-color-scheme: dark) {
:root {
+ --iconCloseX: url("/img/close-light.svg");
+ --iconGear: url("/img/gear-icon-light.svg");
+ --iconArrowRight: url("/img/arrow-icon-right-light.svg");
+ --iconArrowLeft: url("/img/arrow-icon-left-light.svg");
+ --iconProxyWarning: url("/img/proxy-warning-light.svg");
+ --logoMozillaVpn: url("/img/moz-vpn-logo-light.svg");
+ --bgColor: #42404c;
--title-text-color: #fff;
--text-normal-color: #f9f9fa;
--text-heading-color: #fff;
- }
-
- html {
- background-color: #4a4a4a;
+ --primaryCtaDefault: var(--blue40);
+ --primaryCtaHover: var(--blue50);
+ --primaryCtaActive: var(--blue60);
+ --highlight-blue: #52515d;
+ --bottomButtons: var(--highlight-blue);
+ --controllerHover: var(--highlight-blue);
+ --controllerActive: rgb(90, 89, 102);
+ --bgDark: #2b2932;
}
body {
- color: #fff;
+ color: #ffffffd1;
+ --highlight-blue: #52515d;
--hr-grey: #38383d;
- --text-grey: #f9f9fa;
+ --text-grey: #fefffe;
+ }
+
+ .tooltip {
+ background-color: var(--controllerActive);
+ }
+
+ #moz-vpn-tout {
+ box-shadow: 0 0 21px 3px #323139;
+ }
+
+ .blue-link {
+ color: #36abfc;
+ }
+
+ .blue-link:hover {
+ color: var(--blue20);
+ }
+
+ .drop-shadow {
+ box-shadow: 0 0 13px -2px #323139;
+ }
+
+ .server-radio-control {
+ border-color: var(--grey40);
+ }
+
+ .server-radio-control::after {
+ background-color: var(--grey30);
+ }
+
+ .server-city-list-item:hover .server-radio-control {
+ border-color: var(--grey30);
+ }
+
+ .server-city-list-item:active .server-radio-control {
+ border-color: var(--grey20);
+ }
+
+ .primary-cta:focus {
+ box-shadow: 0 0 0 1px #00ddffd6, 0 0 0 3px var(--primaryCtaHover);
+ }
+
+ .slider {
+ background-color: var(--grey30);
+ }
+
+ input:hover + .slider {
+ background-color: var(--grey40);
+ }
+
+ input:focus + .slider {
+ box-shadow: 0 0 0 2px var(--bgColor), 0 0 0 4px var(--grey20);
}
h3.title {
color: #fff;
}
+ .delete-btn,
.bottom-btn {
- background-color: #737373;
- border: solid 1px #737373;
- }
-
- .btn-return.arrow-left {
- background-color: transparent;
+ background-color: var(--bottomButtons);
+ box-shadow: 0 0 0 1px #73737300;
}
.onboarding-title,
@@ -992,24 +2128,19 @@ tr:hover > td > .trash-button {
border: solid 1px #737373;
}
- #edit-container-panel-name-input {
- background-color: #38383d;
- color: #fff;
+ input[type=text] {
+ background-color: rgba(43, 41, 50, 0.79) !important;
}
.delete-container {
background-color: #4a4a4a;
}
- .delete-btn {
- background-color: #737373;
- color: #f9f9fa;
- }
-
+ .delete-btn,
.cancel-button,
.grey-button {
- background-color: #737373;
- color: #fff;
+ background-color: var(--bottomButtons);
+ color: #f9f9fa;
}
.button.secondary:hover,
@@ -1021,11 +2152,16 @@ tr:hover > td > .trash-button {
border-block-end: solid 1px #4a4a4a;
}
+ input[type="text"]:focus {
+ box-shadow: 0 0 0 3px var(--blue50);
+ border-color: var(--blue30);
+ }
+
+ .trash-button,
img.menu-icon,
.menu-icon > img,
.menu-arrow > img,
- .info-icon > img,
- .btn-return.arrow-left {
+ .info-icon > img {
filter: invert(1);
}
@@ -1035,15 +2171,34 @@ tr:hover > td > .trash-button {
}
.truncate-text::after {
- background: #4a4a4a;
- mask-image: linear-gradient(to right, transparent, #4a4a4a 70%);
+ background: var(--bgColor);
+ mask-image: linear-gradient(to right, transparent, var(--bgColor) 70%);
}
[data-identity-color="grey"] {
--identity-icon-color: #ededf0;
}
- [type="radio"]:checked + [data-identity-color="grey"] {
- --identity-icon-color: #616161;
+ .radio-choice > .radio-container > [type="radio"]:checked + label {
+ background: var(--bgDark);
+ }
+
+ #edit-container-panel-choose-icon .radio-container:hover .usercontext-icon::before {
+ fill: #fff !important;
}
}
+
+/* OVERFLOW MENU */
+
+.overflow body,
+.overflow html {
+ inline-size: 100%;
+}
+
+.overflow .container-panel {
+ min-block-size: 100%;
+}
+
+.overflow .panel.onboarding {
+ margin-block: auto;
+}
diff --git a/src/fonts/Inter-Medium.woff2 b/src/fonts/Inter-Medium.woff2
new file mode 100644
index 0000000..7d0fbe9
Binary files /dev/null and b/src/fonts/Inter-Medium.woff2 differ
diff --git a/src/fonts/Inter-Regular.woff2 b/src/fonts/Inter-Regular.woff2
new file mode 100644
index 0000000..554aed6
Binary files /dev/null and b/src/fonts/Inter-Regular.woff2 differ
diff --git a/src/fonts/Metropolis-Light.woff2 b/src/fonts/Metropolis-Light.woff2
new file mode 100755
index 0000000..d276865
Binary files /dev/null and b/src/fonts/Metropolis-Light.woff2 differ
diff --git a/src/fonts/Metropolis-Medium.woff2 b/src/fonts/Metropolis-Medium.woff2
new file mode 100755
index 0000000..d5aabb6
Binary files /dev/null and b/src/fonts/Metropolis-Medium.woff2 differ
diff --git a/src/img/arrow-icon-left-light.svg b/src/img/arrow-icon-left-light.svg
new file mode 100644
index 0000000..5a35ea8
--- /dev/null
+++ b/src/img/arrow-icon-left-light.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/arrow-icon-right-light.svg b/src/img/arrow-icon-right-light.svg
new file mode 100644
index 0000000..d8549ce
--- /dev/null
+++ b/src/img/arrow-icon-right-light.svg
@@ -0,0 +1,24 @@
+
+
+
diff --git a/src/img/arrow-icon-right.svg b/src/img/arrow-icon-right.svg
index fa99e25..ba8df85 100644
--- a/src/img/arrow-icon-right.svg
+++ b/src/img/arrow-icon-right.svg
@@ -16,7 +16,7 @@
-
+
diff --git a/src/img/arrow-toggle.svg b/src/img/arrow-toggle.svg
new file mode 100644
index 0000000..a16112c
--- /dev/null
+++ b/src/img/arrow-toggle.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/close-light.svg b/src/img/close-light.svg
new file mode 100644
index 0000000..a2a88f1
--- /dev/null
+++ b/src/img/close-light.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/close.svg b/src/img/close.svg
new file mode 100644
index 0000000..1a004fc
--- /dev/null
+++ b/src/img/close.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/flags/AC.png b/src/img/flags/AC.png
new file mode 100644
index 0000000..8e7a630
Binary files /dev/null and b/src/img/flags/AC.png differ
diff --git a/src/img/flags/AD.png b/src/img/flags/AD.png
new file mode 100644
index 0000000..69972df
Binary files /dev/null and b/src/img/flags/AD.png differ
diff --git a/src/img/flags/AE.png b/src/img/flags/AE.png
new file mode 100644
index 0000000..11d2bb6
Binary files /dev/null and b/src/img/flags/AE.png differ
diff --git a/src/img/flags/AF.png b/src/img/flags/AF.png
new file mode 100644
index 0000000..7a37ec2
Binary files /dev/null and b/src/img/flags/AF.png differ
diff --git a/src/img/flags/AG.png b/src/img/flags/AG.png
new file mode 100644
index 0000000..8602fff
Binary files /dev/null and b/src/img/flags/AG.png differ
diff --git a/src/img/flags/AI.png b/src/img/flags/AI.png
new file mode 100644
index 0000000..73f0c20
Binary files /dev/null and b/src/img/flags/AI.png differ
diff --git a/src/img/flags/AL.png b/src/img/flags/AL.png
new file mode 100644
index 0000000..a6d4573
Binary files /dev/null and b/src/img/flags/AL.png differ
diff --git a/src/img/flags/AM.png b/src/img/flags/AM.png
new file mode 100644
index 0000000..16ef38a
Binary files /dev/null and b/src/img/flags/AM.png differ
diff --git a/src/img/flags/AO.png b/src/img/flags/AO.png
new file mode 100644
index 0000000..9349525
Binary files /dev/null and b/src/img/flags/AO.png differ
diff --git a/src/img/flags/AQ.png b/src/img/flags/AQ.png
new file mode 100644
index 0000000..d21e4ba
Binary files /dev/null and b/src/img/flags/AQ.png differ
diff --git a/src/img/flags/AR.png b/src/img/flags/AR.png
new file mode 100644
index 0000000..a7d8a31
Binary files /dev/null and b/src/img/flags/AR.png differ
diff --git a/src/img/flags/AS.png b/src/img/flags/AS.png
new file mode 100644
index 0000000..a5cdfcc
Binary files /dev/null and b/src/img/flags/AS.png differ
diff --git a/src/img/flags/AT.png b/src/img/flags/AT.png
new file mode 100644
index 0000000..3937efe
Binary files /dev/null and b/src/img/flags/AT.png differ
diff --git a/src/img/flags/AU.png b/src/img/flags/AU.png
new file mode 100644
index 0000000..84a5180
Binary files /dev/null and b/src/img/flags/AU.png differ
diff --git a/src/img/flags/AW.png b/src/img/flags/AW.png
new file mode 100644
index 0000000..e250be9
Binary files /dev/null and b/src/img/flags/AW.png differ
diff --git a/src/img/flags/AX.png b/src/img/flags/AX.png
new file mode 100644
index 0000000..a5444fc
Binary files /dev/null and b/src/img/flags/AX.png differ
diff --git a/src/img/flags/AZ.png b/src/img/flags/AZ.png
new file mode 100644
index 0000000..4f0c1c8
Binary files /dev/null and b/src/img/flags/AZ.png differ
diff --git a/src/img/flags/BA.png b/src/img/flags/BA.png
new file mode 100644
index 0000000..3ffe114
Binary files /dev/null and b/src/img/flags/BA.png differ
diff --git a/src/img/flags/BB.png b/src/img/flags/BB.png
new file mode 100644
index 0000000..e6fb3ed
Binary files /dev/null and b/src/img/flags/BB.png differ
diff --git a/src/img/flags/BD.png b/src/img/flags/BD.png
new file mode 100644
index 0000000..c1c933e
Binary files /dev/null and b/src/img/flags/BD.png differ
diff --git a/src/img/flags/BE.png b/src/img/flags/BE.png
new file mode 100644
index 0000000..d309207
Binary files /dev/null and b/src/img/flags/BE.png differ
diff --git a/src/img/flags/BF.png b/src/img/flags/BF.png
new file mode 100644
index 0000000..29064ff
Binary files /dev/null and b/src/img/flags/BF.png differ
diff --git a/src/img/flags/BG.png b/src/img/flags/BG.png
new file mode 100644
index 0000000..0519f96
Binary files /dev/null and b/src/img/flags/BG.png differ
diff --git a/src/img/flags/BH.png b/src/img/flags/BH.png
new file mode 100644
index 0000000..28c3ec6
Binary files /dev/null and b/src/img/flags/BH.png differ
diff --git a/src/img/flags/BI.png b/src/img/flags/BI.png
new file mode 100644
index 0000000..7133116
Binary files /dev/null and b/src/img/flags/BI.png differ
diff --git a/src/img/flags/BJ.png b/src/img/flags/BJ.png
new file mode 100644
index 0000000..3ac1d99
Binary files /dev/null and b/src/img/flags/BJ.png differ
diff --git a/src/img/flags/BL.png b/src/img/flags/BL.png
new file mode 100644
index 0000000..aa9bb06
Binary files /dev/null and b/src/img/flags/BL.png differ
diff --git a/src/img/flags/BM.png b/src/img/flags/BM.png
new file mode 100644
index 0000000..1353129
Binary files /dev/null and b/src/img/flags/BM.png differ
diff --git a/src/img/flags/BN.png b/src/img/flags/BN.png
new file mode 100644
index 0000000..f861221
Binary files /dev/null and b/src/img/flags/BN.png differ
diff --git a/src/img/flags/BO.png b/src/img/flags/BO.png
new file mode 100644
index 0000000..21c555b
Binary files /dev/null and b/src/img/flags/BO.png differ
diff --git a/src/img/flags/BQ.png b/src/img/flags/BQ.png
new file mode 100644
index 0000000..be922b0
Binary files /dev/null and b/src/img/flags/BQ.png differ
diff --git a/src/img/flags/BR.png b/src/img/flags/BR.png
new file mode 100644
index 0000000..642f3a5
Binary files /dev/null and b/src/img/flags/BR.png differ
diff --git a/src/img/flags/BS.png b/src/img/flags/BS.png
new file mode 100644
index 0000000..f959101
Binary files /dev/null and b/src/img/flags/BS.png differ
diff --git a/src/img/flags/BT.png b/src/img/flags/BT.png
new file mode 100644
index 0000000..ee668fb
Binary files /dev/null and b/src/img/flags/BT.png differ
diff --git a/src/img/flags/BV.png b/src/img/flags/BV.png
new file mode 100644
index 0000000..d3a19fd
Binary files /dev/null and b/src/img/flags/BV.png differ
diff --git a/src/img/flags/BW.png b/src/img/flags/BW.png
new file mode 100644
index 0000000..4aeeb13
Binary files /dev/null and b/src/img/flags/BW.png differ
diff --git a/src/img/flags/BY.png b/src/img/flags/BY.png
new file mode 100644
index 0000000..fc2051b
Binary files /dev/null and b/src/img/flags/BY.png differ
diff --git a/src/img/flags/BZ.png b/src/img/flags/BZ.png
new file mode 100644
index 0000000..0c23f80
Binary files /dev/null and b/src/img/flags/BZ.png differ
diff --git a/src/img/flags/CA.png b/src/img/flags/CA.png
new file mode 100644
index 0000000..fe777da
Binary files /dev/null and b/src/img/flags/CA.png differ
diff --git a/src/img/flags/CC.png b/src/img/flags/CC.png
new file mode 100644
index 0000000..f232d71
Binary files /dev/null and b/src/img/flags/CC.png differ
diff --git a/src/img/flags/CD.png b/src/img/flags/CD.png
new file mode 100644
index 0000000..f0855b2
Binary files /dev/null and b/src/img/flags/CD.png differ
diff --git a/src/img/flags/CF.png b/src/img/flags/CF.png
new file mode 100644
index 0000000..18a6891
Binary files /dev/null and b/src/img/flags/CF.png differ
diff --git a/src/img/flags/CG.png b/src/img/flags/CG.png
new file mode 100644
index 0000000..113face
Binary files /dev/null and b/src/img/flags/CG.png differ
diff --git a/src/img/flags/CH.png b/src/img/flags/CH.png
new file mode 100644
index 0000000..bc50b99
Binary files /dev/null and b/src/img/flags/CH.png differ
diff --git a/src/img/flags/CI.png b/src/img/flags/CI.png
new file mode 100644
index 0000000..e19e84b
Binary files /dev/null and b/src/img/flags/CI.png differ
diff --git a/src/img/flags/CK.png b/src/img/flags/CK.png
new file mode 100644
index 0000000..e5ca391
Binary files /dev/null and b/src/img/flags/CK.png differ
diff --git a/src/img/flags/CL.png b/src/img/flags/CL.png
new file mode 100644
index 0000000..d4d91d0
Binary files /dev/null and b/src/img/flags/CL.png differ
diff --git a/src/img/flags/CM.png b/src/img/flags/CM.png
new file mode 100644
index 0000000..457a061
Binary files /dev/null and b/src/img/flags/CM.png differ
diff --git a/src/img/flags/CN.png b/src/img/flags/CN.png
new file mode 100644
index 0000000..dcc0fb1
Binary files /dev/null and b/src/img/flags/CN.png differ
diff --git a/src/img/flags/CO.png b/src/img/flags/CO.png
new file mode 100644
index 0000000..0d2cf35
Binary files /dev/null and b/src/img/flags/CO.png differ
diff --git a/src/img/flags/CP.png b/src/img/flags/CP.png
new file mode 100644
index 0000000..662adc7
Binary files /dev/null and b/src/img/flags/CP.png differ
diff --git a/src/img/flags/CR.png b/src/img/flags/CR.png
new file mode 100644
index 0000000..69b41ac
Binary files /dev/null and b/src/img/flags/CR.png differ
diff --git a/src/img/flags/CU.png b/src/img/flags/CU.png
new file mode 100644
index 0000000..00e3299
Binary files /dev/null and b/src/img/flags/CU.png differ
diff --git a/src/img/flags/CV.png b/src/img/flags/CV.png
new file mode 100644
index 0000000..88ac363
Binary files /dev/null and b/src/img/flags/CV.png differ
diff --git a/src/img/flags/CW.png b/src/img/flags/CW.png
new file mode 100644
index 0000000..83a5a7d
Binary files /dev/null and b/src/img/flags/CW.png differ
diff --git a/src/img/flags/CX.png b/src/img/flags/CX.png
new file mode 100644
index 0000000..b6f3608
Binary files /dev/null and b/src/img/flags/CX.png differ
diff --git a/src/img/flags/CY.png b/src/img/flags/CY.png
new file mode 100644
index 0000000..5c333b0
Binary files /dev/null and b/src/img/flags/CY.png differ
diff --git a/src/img/flags/CZ.png b/src/img/flags/CZ.png
new file mode 100644
index 0000000..ecad9fd
Binary files /dev/null and b/src/img/flags/CZ.png differ
diff --git a/src/img/flags/DE.png b/src/img/flags/DE.png
new file mode 100644
index 0000000..2933ab8
Binary files /dev/null and b/src/img/flags/DE.png differ
diff --git a/src/img/flags/DG.png b/src/img/flags/DG.png
new file mode 100644
index 0000000..aee82ba
Binary files /dev/null and b/src/img/flags/DG.png differ
diff --git a/src/img/flags/DJ.png b/src/img/flags/DJ.png
new file mode 100644
index 0000000..24602c1
Binary files /dev/null and b/src/img/flags/DJ.png differ
diff --git a/src/img/flags/DK.png b/src/img/flags/DK.png
new file mode 100644
index 0000000..095ff86
Binary files /dev/null and b/src/img/flags/DK.png differ
diff --git a/src/img/flags/DM.png b/src/img/flags/DM.png
new file mode 100644
index 0000000..05f78c9
Binary files /dev/null and b/src/img/flags/DM.png differ
diff --git a/src/img/flags/DO.png b/src/img/flags/DO.png
new file mode 100644
index 0000000..4cb2f4a
Binary files /dev/null and b/src/img/flags/DO.png differ
diff --git a/src/img/flags/DZ.png b/src/img/flags/DZ.png
new file mode 100644
index 0000000..8bdb882
Binary files /dev/null and b/src/img/flags/DZ.png differ
diff --git a/src/img/flags/EA.png b/src/img/flags/EA.png
new file mode 100644
index 0000000..fddf21a
Binary files /dev/null and b/src/img/flags/EA.png differ
diff --git a/src/img/flags/EC.png b/src/img/flags/EC.png
new file mode 100644
index 0000000..05b0a2a
Binary files /dev/null and b/src/img/flags/EC.png differ
diff --git a/src/img/flags/EE.png b/src/img/flags/EE.png
new file mode 100644
index 0000000..94d8d46
Binary files /dev/null and b/src/img/flags/EE.png differ
diff --git a/src/img/flags/EG.png b/src/img/flags/EG.png
new file mode 100644
index 0000000..29dfd5b
Binary files /dev/null and b/src/img/flags/EG.png differ
diff --git a/src/img/flags/EH.png b/src/img/flags/EH.png
new file mode 100644
index 0000000..29d0791
Binary files /dev/null and b/src/img/flags/EH.png differ
diff --git a/src/img/flags/ER.png b/src/img/flags/ER.png
new file mode 100644
index 0000000..fd25d0e
Binary files /dev/null and b/src/img/flags/ER.png differ
diff --git a/src/img/flags/ES.png b/src/img/flags/ES.png
new file mode 100644
index 0000000..5c449da
Binary files /dev/null and b/src/img/flags/ES.png differ
diff --git a/src/img/flags/ET.png b/src/img/flags/ET.png
new file mode 100644
index 0000000..4f4e7fc
Binary files /dev/null and b/src/img/flags/ET.png differ
diff --git a/src/img/flags/EU.png b/src/img/flags/EU.png
new file mode 100644
index 0000000..4f0b5d7
Binary files /dev/null and b/src/img/flags/EU.png differ
diff --git a/src/img/flags/FI.png b/src/img/flags/FI.png
new file mode 100644
index 0000000..34096f2
Binary files /dev/null and b/src/img/flags/FI.png differ
diff --git a/src/img/flags/FJ.png b/src/img/flags/FJ.png
new file mode 100644
index 0000000..3f4c0e0
Binary files /dev/null and b/src/img/flags/FJ.png differ
diff --git a/src/img/flags/FK.png b/src/img/flags/FK.png
new file mode 100644
index 0000000..5b2ecff
Binary files /dev/null and b/src/img/flags/FK.png differ
diff --git a/src/img/flags/FM.png b/src/img/flags/FM.png
new file mode 100644
index 0000000..0fc25e8
Binary files /dev/null and b/src/img/flags/FM.png differ
diff --git a/src/img/flags/FO.png b/src/img/flags/FO.png
new file mode 100644
index 0000000..7f8e443
Binary files /dev/null and b/src/img/flags/FO.png differ
diff --git a/src/img/flags/FR.png b/src/img/flags/FR.png
new file mode 100644
index 0000000..662adc7
Binary files /dev/null and b/src/img/flags/FR.png differ
diff --git a/src/img/flags/GA.png b/src/img/flags/GA.png
new file mode 100644
index 0000000..6f73a37
Binary files /dev/null and b/src/img/flags/GA.png differ
diff --git a/src/img/flags/GB.png b/src/img/flags/GB.png
new file mode 100644
index 0000000..af56765
Binary files /dev/null and b/src/img/flags/GB.png differ
diff --git a/src/img/flags/GD.png b/src/img/flags/GD.png
new file mode 100644
index 0000000..66f160e
Binary files /dev/null and b/src/img/flags/GD.png differ
diff --git a/src/img/flags/GE.png b/src/img/flags/GE.png
new file mode 100644
index 0000000..31af128
Binary files /dev/null and b/src/img/flags/GE.png differ
diff --git a/src/img/flags/GF.png b/src/img/flags/GF.png
new file mode 100644
index 0000000..99ff31b
Binary files /dev/null and b/src/img/flags/GF.png differ
diff --git a/src/img/flags/GG.png b/src/img/flags/GG.png
new file mode 100644
index 0000000..72ac329
Binary files /dev/null and b/src/img/flags/GG.png differ
diff --git a/src/img/flags/GH.png b/src/img/flags/GH.png
new file mode 100644
index 0000000..2b19dbd
Binary files /dev/null and b/src/img/flags/GH.png differ
diff --git a/src/img/flags/GI.png b/src/img/flags/GI.png
new file mode 100644
index 0000000..26d4ef7
Binary files /dev/null and b/src/img/flags/GI.png differ
diff --git a/src/img/flags/GL.png b/src/img/flags/GL.png
new file mode 100644
index 0000000..5df66b3
Binary files /dev/null and b/src/img/flags/GL.png differ
diff --git a/src/img/flags/GM.png b/src/img/flags/GM.png
new file mode 100644
index 0000000..4d1a3b4
Binary files /dev/null and b/src/img/flags/GM.png differ
diff --git a/src/img/flags/GN.png b/src/img/flags/GN.png
new file mode 100644
index 0000000..813c3ca
Binary files /dev/null and b/src/img/flags/GN.png differ
diff --git a/src/img/flags/GP.png b/src/img/flags/GP.png
new file mode 100644
index 0000000..97a3dd9
Binary files /dev/null and b/src/img/flags/GP.png differ
diff --git a/src/img/flags/GQ.png b/src/img/flags/GQ.png
new file mode 100644
index 0000000..02b7aec
Binary files /dev/null and b/src/img/flags/GQ.png differ
diff --git a/src/img/flags/GR.png b/src/img/flags/GR.png
new file mode 100644
index 0000000..0478442
Binary files /dev/null and b/src/img/flags/GR.png differ
diff --git a/src/img/flags/GS.png b/src/img/flags/GS.png
new file mode 100644
index 0000000..da4bbff
Binary files /dev/null and b/src/img/flags/GS.png differ
diff --git a/src/img/flags/GT.png b/src/img/flags/GT.png
new file mode 100644
index 0000000..23cec33
Binary files /dev/null and b/src/img/flags/GT.png differ
diff --git a/src/img/flags/GU.png b/src/img/flags/GU.png
new file mode 100644
index 0000000..75c0945
Binary files /dev/null and b/src/img/flags/GU.png differ
diff --git a/src/img/flags/GW.png b/src/img/flags/GW.png
new file mode 100644
index 0000000..cf8c941
Binary files /dev/null and b/src/img/flags/GW.png differ
diff --git a/src/img/flags/GY.png b/src/img/flags/GY.png
new file mode 100644
index 0000000..2e102fd
Binary files /dev/null and b/src/img/flags/GY.png differ
diff --git a/src/img/flags/HK.png b/src/img/flags/HK.png
new file mode 100644
index 0000000..412b684
Binary files /dev/null and b/src/img/flags/HK.png differ
diff --git a/src/img/flags/HM.png b/src/img/flags/HM.png
new file mode 100644
index 0000000..9972434
Binary files /dev/null and b/src/img/flags/HM.png differ
diff --git a/src/img/flags/HN.png b/src/img/flags/HN.png
new file mode 100644
index 0000000..e161777
Binary files /dev/null and b/src/img/flags/HN.png differ
diff --git a/src/img/flags/HR.png b/src/img/flags/HR.png
new file mode 100644
index 0000000..2dafc9a
Binary files /dev/null and b/src/img/flags/HR.png differ
diff --git a/src/img/flags/HT.png b/src/img/flags/HT.png
new file mode 100644
index 0000000..afbf028
Binary files /dev/null and b/src/img/flags/HT.png differ
diff --git a/src/img/flags/HU.png b/src/img/flags/HU.png
new file mode 100644
index 0000000..b2f43f7
Binary files /dev/null and b/src/img/flags/HU.png differ
diff --git a/src/img/flags/IC.png b/src/img/flags/IC.png
new file mode 100644
index 0000000..44cb511
Binary files /dev/null and b/src/img/flags/IC.png differ
diff --git a/src/img/flags/ID.png b/src/img/flags/ID.png
new file mode 100644
index 0000000..4e8df64
Binary files /dev/null and b/src/img/flags/ID.png differ
diff --git a/src/img/flags/IE.png b/src/img/flags/IE.png
new file mode 100644
index 0000000..bbbeada
Binary files /dev/null and b/src/img/flags/IE.png differ
diff --git a/src/img/flags/IL.png b/src/img/flags/IL.png
new file mode 100644
index 0000000..6c390c3
Binary files /dev/null and b/src/img/flags/IL.png differ
diff --git a/src/img/flags/IM.png b/src/img/flags/IM.png
new file mode 100644
index 0000000..99304fc
Binary files /dev/null and b/src/img/flags/IM.png differ
diff --git a/src/img/flags/IN.png b/src/img/flags/IN.png
new file mode 100644
index 0000000..fcacf4c
Binary files /dev/null and b/src/img/flags/IN.png differ
diff --git a/src/img/flags/IO.png b/src/img/flags/IO.png
new file mode 100644
index 0000000..7ef54ae
Binary files /dev/null and b/src/img/flags/IO.png differ
diff --git a/src/img/flags/IQ.png b/src/img/flags/IQ.png
new file mode 100644
index 0000000..81de697
Binary files /dev/null and b/src/img/flags/IQ.png differ
diff --git a/src/img/flags/IR.png b/src/img/flags/IR.png
new file mode 100644
index 0000000..5147905
Binary files /dev/null and b/src/img/flags/IR.png differ
diff --git a/src/img/flags/IS.png b/src/img/flags/IS.png
new file mode 100644
index 0000000..349e9ef
Binary files /dev/null and b/src/img/flags/IS.png differ
diff --git a/src/img/flags/IT.png b/src/img/flags/IT.png
new file mode 100644
index 0000000..2cd1da7
Binary files /dev/null and b/src/img/flags/IT.png differ
diff --git a/src/img/flags/JE.png b/src/img/flags/JE.png
new file mode 100644
index 0000000..bc974c1
Binary files /dev/null and b/src/img/flags/JE.png differ
diff --git a/src/img/flags/JM.png b/src/img/flags/JM.png
new file mode 100644
index 0000000..2a48a73
Binary files /dev/null and b/src/img/flags/JM.png differ
diff --git a/src/img/flags/JO.png b/src/img/flags/JO.png
new file mode 100644
index 0000000..5161701
Binary files /dev/null and b/src/img/flags/JO.png differ
diff --git a/src/img/flags/JP.png b/src/img/flags/JP.png
new file mode 100644
index 0000000..dd515aa
Binary files /dev/null and b/src/img/flags/JP.png differ
diff --git a/src/img/flags/KE.png b/src/img/flags/KE.png
new file mode 100644
index 0000000..468ab95
Binary files /dev/null and b/src/img/flags/KE.png differ
diff --git a/src/img/flags/KG.png b/src/img/flags/KG.png
new file mode 100644
index 0000000..58f07a7
Binary files /dev/null and b/src/img/flags/KG.png differ
diff --git a/src/img/flags/KH.png b/src/img/flags/KH.png
new file mode 100644
index 0000000..cf9c1a6
Binary files /dev/null and b/src/img/flags/KH.png differ
diff --git a/src/img/flags/KI.png b/src/img/flags/KI.png
new file mode 100644
index 0000000..ee10d01
Binary files /dev/null and b/src/img/flags/KI.png differ
diff --git a/src/img/flags/KM.png b/src/img/flags/KM.png
new file mode 100644
index 0000000..1035f14
Binary files /dev/null and b/src/img/flags/KM.png differ
diff --git a/src/img/flags/KN.png b/src/img/flags/KN.png
new file mode 100644
index 0000000..e021417
Binary files /dev/null and b/src/img/flags/KN.png differ
diff --git a/src/img/flags/KP.png b/src/img/flags/KP.png
new file mode 100644
index 0000000..7e05f75
Binary files /dev/null and b/src/img/flags/KP.png differ
diff --git a/src/img/flags/KR.png b/src/img/flags/KR.png
new file mode 100644
index 0000000..8ff7ccd
Binary files /dev/null and b/src/img/flags/KR.png differ
diff --git a/src/img/flags/KW.png b/src/img/flags/KW.png
new file mode 100644
index 0000000..76f53c2
Binary files /dev/null and b/src/img/flags/KW.png differ
diff --git a/src/img/flags/KY.png b/src/img/flags/KY.png
new file mode 100644
index 0000000..158d589
Binary files /dev/null and b/src/img/flags/KY.png differ
diff --git a/src/img/flags/KZ.png b/src/img/flags/KZ.png
new file mode 100644
index 0000000..d7e3401
Binary files /dev/null and b/src/img/flags/KZ.png differ
diff --git a/src/img/flags/LA.png b/src/img/flags/LA.png
new file mode 100644
index 0000000..44f5e8d
Binary files /dev/null and b/src/img/flags/LA.png differ
diff --git a/src/img/flags/LB.png b/src/img/flags/LB.png
new file mode 100644
index 0000000..f506228
Binary files /dev/null and b/src/img/flags/LB.png differ
diff --git a/src/img/flags/LC.png b/src/img/flags/LC.png
new file mode 100644
index 0000000..1b7e53a
Binary files /dev/null and b/src/img/flags/LC.png differ
diff --git a/src/img/flags/LI.png b/src/img/flags/LI.png
new file mode 100644
index 0000000..9a69e9a
Binary files /dev/null and b/src/img/flags/LI.png differ
diff --git a/src/img/flags/LK.png b/src/img/flags/LK.png
new file mode 100644
index 0000000..8f8d0b3
Binary files /dev/null and b/src/img/flags/LK.png differ
diff --git a/src/img/flags/LR.png b/src/img/flags/LR.png
new file mode 100644
index 0000000..8ed6a5a
Binary files /dev/null and b/src/img/flags/LR.png differ
diff --git a/src/img/flags/LS.png b/src/img/flags/LS.png
new file mode 100644
index 0000000..051b53a
Binary files /dev/null and b/src/img/flags/LS.png differ
diff --git a/src/img/flags/LT.png b/src/img/flags/LT.png
new file mode 100644
index 0000000..69de64e
Binary files /dev/null and b/src/img/flags/LT.png differ
diff --git a/src/img/flags/LU.png b/src/img/flags/LU.png
new file mode 100644
index 0000000..d7a507d
Binary files /dev/null and b/src/img/flags/LU.png differ
diff --git a/src/img/flags/LV.png b/src/img/flags/LV.png
new file mode 100644
index 0000000..5505550
Binary files /dev/null and b/src/img/flags/LV.png differ
diff --git a/src/img/flags/LY.png b/src/img/flags/LY.png
new file mode 100644
index 0000000..426e931
Binary files /dev/null and b/src/img/flags/LY.png differ
diff --git a/src/img/flags/MA.png b/src/img/flags/MA.png
new file mode 100644
index 0000000..49d5f2f
Binary files /dev/null and b/src/img/flags/MA.png differ
diff --git a/src/img/flags/MC.png b/src/img/flags/MC.png
new file mode 100644
index 0000000..cc71565
Binary files /dev/null and b/src/img/flags/MC.png differ
diff --git a/src/img/flags/MD.png b/src/img/flags/MD.png
new file mode 100644
index 0000000..72ab452
Binary files /dev/null and b/src/img/flags/MD.png differ
diff --git a/src/img/flags/ME.png b/src/img/flags/ME.png
new file mode 100644
index 0000000..ed5d0c4
Binary files /dev/null and b/src/img/flags/ME.png differ
diff --git a/src/img/flags/MF.png b/src/img/flags/MF.png
new file mode 100644
index 0000000..662adc7
Binary files /dev/null and b/src/img/flags/MF.png differ
diff --git a/src/img/flags/MG.png b/src/img/flags/MG.png
new file mode 100644
index 0000000..460baba
Binary files /dev/null and b/src/img/flags/MG.png differ
diff --git a/src/img/flags/MH.png b/src/img/flags/MH.png
new file mode 100644
index 0000000..6b69a8d
Binary files /dev/null and b/src/img/flags/MH.png differ
diff --git a/src/img/flags/MK.png b/src/img/flags/MK.png
new file mode 100644
index 0000000..9db397c
Binary files /dev/null and b/src/img/flags/MK.png differ
diff --git a/src/img/flags/ML.png b/src/img/flags/ML.png
new file mode 100644
index 0000000..d7db739
Binary files /dev/null and b/src/img/flags/ML.png differ
diff --git a/src/img/flags/MM.png b/src/img/flags/MM.png
new file mode 100644
index 0000000..d4b642c
Binary files /dev/null and b/src/img/flags/MM.png differ
diff --git a/src/img/flags/MN.png b/src/img/flags/MN.png
new file mode 100644
index 0000000..7f2225c
Binary files /dev/null and b/src/img/flags/MN.png differ
diff --git a/src/img/flags/MO.png b/src/img/flags/MO.png
new file mode 100644
index 0000000..2fe5c8c
Binary files /dev/null and b/src/img/flags/MO.png differ
diff --git a/src/img/flags/MP.png b/src/img/flags/MP.png
new file mode 100644
index 0000000..c9d6d57
Binary files /dev/null and b/src/img/flags/MP.png differ
diff --git a/src/img/flags/MQ.png b/src/img/flags/MQ.png
new file mode 100644
index 0000000..aa46f11
Binary files /dev/null and b/src/img/flags/MQ.png differ
diff --git a/src/img/flags/MR.png b/src/img/flags/MR.png
new file mode 100644
index 0000000..e976797
Binary files /dev/null and b/src/img/flags/MR.png differ
diff --git a/src/img/flags/MS.png b/src/img/flags/MS.png
new file mode 100644
index 0000000..fd6b759
Binary files /dev/null and b/src/img/flags/MS.png differ
diff --git a/src/img/flags/MT.png b/src/img/flags/MT.png
new file mode 100644
index 0000000..9265b06
Binary files /dev/null and b/src/img/flags/MT.png differ
diff --git a/src/img/flags/MU.png b/src/img/flags/MU.png
new file mode 100644
index 0000000..b48e01b
Binary files /dev/null and b/src/img/flags/MU.png differ
diff --git a/src/img/flags/MV.png b/src/img/flags/MV.png
new file mode 100644
index 0000000..c666d7a
Binary files /dev/null and b/src/img/flags/MV.png differ
diff --git a/src/img/flags/MW.png b/src/img/flags/MW.png
new file mode 100644
index 0000000..e58fe38
Binary files /dev/null and b/src/img/flags/MW.png differ
diff --git a/src/img/flags/MX.png b/src/img/flags/MX.png
new file mode 100644
index 0000000..61775bf
Binary files /dev/null and b/src/img/flags/MX.png differ
diff --git a/src/img/flags/MY.png b/src/img/flags/MY.png
new file mode 100644
index 0000000..108dd99
Binary files /dev/null and b/src/img/flags/MY.png differ
diff --git a/src/img/flags/MZ.png b/src/img/flags/MZ.png
new file mode 100644
index 0000000..1a33e0c
Binary files /dev/null and b/src/img/flags/MZ.png differ
diff --git a/src/img/flags/NA.png b/src/img/flags/NA.png
new file mode 100644
index 0000000..860139d
Binary files /dev/null and b/src/img/flags/NA.png differ
diff --git a/src/img/flags/NC.png b/src/img/flags/NC.png
new file mode 100644
index 0000000..81fa763
Binary files /dev/null and b/src/img/flags/NC.png differ
diff --git a/src/img/flags/NE.png b/src/img/flags/NE.png
new file mode 100644
index 0000000..1f1dc36
Binary files /dev/null and b/src/img/flags/NE.png differ
diff --git a/src/img/flags/NF.png b/src/img/flags/NF.png
new file mode 100644
index 0000000..599da68
Binary files /dev/null and b/src/img/flags/NF.png differ
diff --git a/src/img/flags/NG.png b/src/img/flags/NG.png
new file mode 100644
index 0000000..6cbb424
Binary files /dev/null and b/src/img/flags/NG.png differ
diff --git a/src/img/flags/NI.png b/src/img/flags/NI.png
new file mode 100644
index 0000000..3f14038
Binary files /dev/null and b/src/img/flags/NI.png differ
diff --git a/src/img/flags/NL.png b/src/img/flags/NL.png
new file mode 100644
index 0000000..619bf8c
Binary files /dev/null and b/src/img/flags/NL.png differ
diff --git a/src/img/flags/NO.png b/src/img/flags/NO.png
new file mode 100644
index 0000000..d758735
Binary files /dev/null and b/src/img/flags/NO.png differ
diff --git a/src/img/flags/NP.png b/src/img/flags/NP.png
new file mode 100644
index 0000000..48acf5f
Binary files /dev/null and b/src/img/flags/NP.png differ
diff --git a/src/img/flags/NR.png b/src/img/flags/NR.png
new file mode 100644
index 0000000..1748da9
Binary files /dev/null and b/src/img/flags/NR.png differ
diff --git a/src/img/flags/NU.png b/src/img/flags/NU.png
new file mode 100644
index 0000000..9bd5ec1
Binary files /dev/null and b/src/img/flags/NU.png differ
diff --git a/src/img/flags/NZ.png b/src/img/flags/NZ.png
new file mode 100644
index 0000000..0d193b3
Binary files /dev/null and b/src/img/flags/NZ.png differ
diff --git a/src/img/flags/OM.png b/src/img/flags/OM.png
new file mode 100644
index 0000000..41176aa
Binary files /dev/null and b/src/img/flags/OM.png differ
diff --git a/src/img/flags/PA.png b/src/img/flags/PA.png
new file mode 100644
index 0000000..6174229
Binary files /dev/null and b/src/img/flags/PA.png differ
diff --git a/src/img/flags/PE.png b/src/img/flags/PE.png
new file mode 100644
index 0000000..f7e5409
Binary files /dev/null and b/src/img/flags/PE.png differ
diff --git a/src/img/flags/PF.png b/src/img/flags/PF.png
new file mode 100644
index 0000000..f89b755
Binary files /dev/null and b/src/img/flags/PF.png differ
diff --git a/src/img/flags/PG.png b/src/img/flags/PG.png
new file mode 100644
index 0000000..d75762c
Binary files /dev/null and b/src/img/flags/PG.png differ
diff --git a/src/img/flags/PH.png b/src/img/flags/PH.png
new file mode 100644
index 0000000..a0adbef
Binary files /dev/null and b/src/img/flags/PH.png differ
diff --git a/src/img/flags/PK.png b/src/img/flags/PK.png
new file mode 100644
index 0000000..311ca9a
Binary files /dev/null and b/src/img/flags/PK.png differ
diff --git a/src/img/flags/PL.png b/src/img/flags/PL.png
new file mode 100644
index 0000000..8d6921d
Binary files /dev/null and b/src/img/flags/PL.png differ
diff --git a/src/img/flags/PM.png b/src/img/flags/PM.png
new file mode 100644
index 0000000..357a863
Binary files /dev/null and b/src/img/flags/PM.png differ
diff --git a/src/img/flags/PN.png b/src/img/flags/PN.png
new file mode 100644
index 0000000..a7ced0f
Binary files /dev/null and b/src/img/flags/PN.png differ
diff --git a/src/img/flags/PR.png b/src/img/flags/PR.png
new file mode 100644
index 0000000..867df29
Binary files /dev/null and b/src/img/flags/PR.png differ
diff --git a/src/img/flags/PS.png b/src/img/flags/PS.png
new file mode 100644
index 0000000..9756c04
Binary files /dev/null and b/src/img/flags/PS.png differ
diff --git a/src/img/flags/PT.png b/src/img/flags/PT.png
new file mode 100644
index 0000000..246e2ce
Binary files /dev/null and b/src/img/flags/PT.png differ
diff --git a/src/img/flags/PW.png b/src/img/flags/PW.png
new file mode 100644
index 0000000..8a7aea6
Binary files /dev/null and b/src/img/flags/PW.png differ
diff --git a/src/img/flags/PY.png b/src/img/flags/PY.png
new file mode 100644
index 0000000..8bc9da3
Binary files /dev/null and b/src/img/flags/PY.png differ
diff --git a/src/img/flags/QA.png b/src/img/flags/QA.png
new file mode 100644
index 0000000..3630990
Binary files /dev/null and b/src/img/flags/QA.png differ
diff --git a/src/img/flags/RE.png b/src/img/flags/RE.png
new file mode 100644
index 0000000..8010d88
Binary files /dev/null and b/src/img/flags/RE.png differ
diff --git a/src/img/flags/RO.png b/src/img/flags/RO.png
new file mode 100644
index 0000000..ce8f8e8
Binary files /dev/null and b/src/img/flags/RO.png differ
diff --git a/src/img/flags/RS.png b/src/img/flags/RS.png
new file mode 100644
index 0000000..0485b86
Binary files /dev/null and b/src/img/flags/RS.png differ
diff --git a/src/img/flags/RU.png b/src/img/flags/RU.png
new file mode 100644
index 0000000..9af1cb8
Binary files /dev/null and b/src/img/flags/RU.png differ
diff --git a/src/img/flags/RW.png b/src/img/flags/RW.png
new file mode 100644
index 0000000..2802d1a
Binary files /dev/null and b/src/img/flags/RW.png differ
diff --git a/src/img/flags/SA.png b/src/img/flags/SA.png
new file mode 100644
index 0000000..5f90f43
Binary files /dev/null and b/src/img/flags/SA.png differ
diff --git a/src/img/flags/SB.png b/src/img/flags/SB.png
new file mode 100644
index 0000000..385dbaa
Binary files /dev/null and b/src/img/flags/SB.png differ
diff --git a/src/img/flags/SC.png b/src/img/flags/SC.png
new file mode 100644
index 0000000..908f6b8
Binary files /dev/null and b/src/img/flags/SC.png differ
diff --git a/src/img/flags/SD.png b/src/img/flags/SD.png
new file mode 100644
index 0000000..5ef2fd9
Binary files /dev/null and b/src/img/flags/SD.png differ
diff --git a/src/img/flags/SE.png b/src/img/flags/SE.png
new file mode 100644
index 0000000..2cf2258
Binary files /dev/null and b/src/img/flags/SE.png differ
diff --git a/src/img/flags/SG.png b/src/img/flags/SG.png
new file mode 100644
index 0000000..454b82a
Binary files /dev/null and b/src/img/flags/SG.png differ
diff --git a/src/img/flags/SH.png b/src/img/flags/SH.png
new file mode 100644
index 0000000..2d0df51
Binary files /dev/null and b/src/img/flags/SH.png differ
diff --git a/src/img/flags/SI.png b/src/img/flags/SI.png
new file mode 100644
index 0000000..86bffaf
Binary files /dev/null and b/src/img/flags/SI.png differ
diff --git a/src/img/flags/SJ.png b/src/img/flags/SJ.png
new file mode 100644
index 0000000..d758735
Binary files /dev/null and b/src/img/flags/SJ.png differ
diff --git a/src/img/flags/SK.png b/src/img/flags/SK.png
new file mode 100644
index 0000000..276c387
Binary files /dev/null and b/src/img/flags/SK.png differ
diff --git a/src/img/flags/SL.png b/src/img/flags/SL.png
new file mode 100644
index 0000000..de88763
Binary files /dev/null and b/src/img/flags/SL.png differ
diff --git a/src/img/flags/SM.png b/src/img/flags/SM.png
new file mode 100644
index 0000000..ddecba8
Binary files /dev/null and b/src/img/flags/SM.png differ
diff --git a/src/img/flags/SN.png b/src/img/flags/SN.png
new file mode 100644
index 0000000..843bda4
Binary files /dev/null and b/src/img/flags/SN.png differ
diff --git a/src/img/flags/SO.png b/src/img/flags/SO.png
new file mode 100644
index 0000000..a4c573d
Binary files /dev/null and b/src/img/flags/SO.png differ
diff --git a/src/img/flags/SR.png b/src/img/flags/SR.png
new file mode 100644
index 0000000..77cd1d3
Binary files /dev/null and b/src/img/flags/SR.png differ
diff --git a/src/img/flags/SS.png b/src/img/flags/SS.png
new file mode 100644
index 0000000..9cbf721
Binary files /dev/null and b/src/img/flags/SS.png differ
diff --git a/src/img/flags/ST.png b/src/img/flags/ST.png
new file mode 100644
index 0000000..f209bcd
Binary files /dev/null and b/src/img/flags/ST.png differ
diff --git a/src/img/flags/SV.png b/src/img/flags/SV.png
new file mode 100644
index 0000000..333063f
Binary files /dev/null and b/src/img/flags/SV.png differ
diff --git a/src/img/flags/SX.png b/src/img/flags/SX.png
new file mode 100644
index 0000000..72401f5
Binary files /dev/null and b/src/img/flags/SX.png differ
diff --git a/src/img/flags/SY.png b/src/img/flags/SY.png
new file mode 100644
index 0000000..3dae2a2
Binary files /dev/null and b/src/img/flags/SY.png differ
diff --git a/src/img/flags/SZ.png b/src/img/flags/SZ.png
new file mode 100644
index 0000000..0cf3fb1
Binary files /dev/null and b/src/img/flags/SZ.png differ
diff --git a/src/img/flags/TA.png b/src/img/flags/TA.png
new file mode 100644
index 0000000..15e4c3e
Binary files /dev/null and b/src/img/flags/TA.png differ
diff --git a/src/img/flags/TC.png b/src/img/flags/TC.png
new file mode 100644
index 0000000..d3da08b
Binary files /dev/null and b/src/img/flags/TC.png differ
diff --git a/src/img/flags/TD.png b/src/img/flags/TD.png
new file mode 100644
index 0000000..77184f4
Binary files /dev/null and b/src/img/flags/TD.png differ
diff --git a/src/img/flags/TF.png b/src/img/flags/TF.png
new file mode 100644
index 0000000..2c17f5e
Binary files /dev/null and b/src/img/flags/TF.png differ
diff --git a/src/img/flags/TG.png b/src/img/flags/TG.png
new file mode 100644
index 0000000..d9b238a
Binary files /dev/null and b/src/img/flags/TG.png differ
diff --git a/src/img/flags/TH.png b/src/img/flags/TH.png
new file mode 100644
index 0000000..218a284
Binary files /dev/null and b/src/img/flags/TH.png differ
diff --git a/src/img/flags/TJ.png b/src/img/flags/TJ.png
new file mode 100644
index 0000000..2fc5e4e
Binary files /dev/null and b/src/img/flags/TJ.png differ
diff --git a/src/img/flags/TK.png b/src/img/flags/TK.png
new file mode 100644
index 0000000..122903d
Binary files /dev/null and b/src/img/flags/TK.png differ
diff --git a/src/img/flags/TL.png b/src/img/flags/TL.png
new file mode 100644
index 0000000..2f69d8d
Binary files /dev/null and b/src/img/flags/TL.png differ
diff --git a/src/img/flags/TM.png b/src/img/flags/TM.png
new file mode 100644
index 0000000..8e6fbb1
Binary files /dev/null and b/src/img/flags/TM.png differ
diff --git a/src/img/flags/TN.png b/src/img/flags/TN.png
new file mode 100644
index 0000000..0838b93
Binary files /dev/null and b/src/img/flags/TN.png differ
diff --git a/src/img/flags/TO.png b/src/img/flags/TO.png
new file mode 100644
index 0000000..6a680b1
Binary files /dev/null and b/src/img/flags/TO.png differ
diff --git a/src/img/flags/TR.png b/src/img/flags/TR.png
new file mode 100644
index 0000000..a80ec23
Binary files /dev/null and b/src/img/flags/TR.png differ
diff --git a/src/img/flags/TT.png b/src/img/flags/TT.png
new file mode 100644
index 0000000..7052a39
Binary files /dev/null and b/src/img/flags/TT.png differ
diff --git a/src/img/flags/TV.png b/src/img/flags/TV.png
new file mode 100644
index 0000000..44880af
Binary files /dev/null and b/src/img/flags/TV.png differ
diff --git a/src/img/flags/TW.png b/src/img/flags/TW.png
new file mode 100644
index 0000000..d5d14ae
Binary files /dev/null and b/src/img/flags/TW.png differ
diff --git a/src/img/flags/TZ.png b/src/img/flags/TZ.png
new file mode 100644
index 0000000..87c990d
Binary files /dev/null and b/src/img/flags/TZ.png differ
diff --git a/src/img/flags/UA.png b/src/img/flags/UA.png
new file mode 100644
index 0000000..81db6c2
Binary files /dev/null and b/src/img/flags/UA.png differ
diff --git a/src/img/flags/UG.png b/src/img/flags/UG.png
new file mode 100644
index 0000000..f560449
Binary files /dev/null and b/src/img/flags/UG.png differ
diff --git a/src/img/flags/UM.png b/src/img/flags/UM.png
new file mode 100644
index 0000000..6d18cb7
Binary files /dev/null and b/src/img/flags/UM.png differ
diff --git a/src/img/flags/UN.png b/src/img/flags/UN.png
new file mode 100644
index 0000000..ea7fc4c
Binary files /dev/null and b/src/img/flags/UN.png differ
diff --git a/src/img/flags/US.png b/src/img/flags/US.png
new file mode 100644
index 0000000..0ba0642
Binary files /dev/null and b/src/img/flags/US.png differ
diff --git a/src/img/flags/UY.png b/src/img/flags/UY.png
new file mode 100644
index 0000000..aa981ca
Binary files /dev/null and b/src/img/flags/UY.png differ
diff --git a/src/img/flags/UZ.png b/src/img/flags/UZ.png
new file mode 100644
index 0000000..ae196dd
Binary files /dev/null and b/src/img/flags/UZ.png differ
diff --git a/src/img/flags/VA.png b/src/img/flags/VA.png
new file mode 100644
index 0000000..f0fe36f
Binary files /dev/null and b/src/img/flags/VA.png differ
diff --git a/src/img/flags/VC.png b/src/img/flags/VC.png
new file mode 100644
index 0000000..234bf65
Binary files /dev/null and b/src/img/flags/VC.png differ
diff --git a/src/img/flags/VE.png b/src/img/flags/VE.png
new file mode 100644
index 0000000..70a249f
Binary files /dev/null and b/src/img/flags/VE.png differ
diff --git a/src/img/flags/VG.png b/src/img/flags/VG.png
new file mode 100644
index 0000000..7201718
Binary files /dev/null and b/src/img/flags/VG.png differ
diff --git a/src/img/flags/VI.png b/src/img/flags/VI.png
new file mode 100644
index 0000000..0feb6ae
Binary files /dev/null and b/src/img/flags/VI.png differ
diff --git a/src/img/flags/VN.png b/src/img/flags/VN.png
new file mode 100644
index 0000000..5282bd4
Binary files /dev/null and b/src/img/flags/VN.png differ
diff --git a/src/img/flags/VU.png b/src/img/flags/VU.png
new file mode 100644
index 0000000..6047a7b
Binary files /dev/null and b/src/img/flags/VU.png differ
diff --git a/src/img/flags/WF.png b/src/img/flags/WF.png
new file mode 100644
index 0000000..15746da
Binary files /dev/null and b/src/img/flags/WF.png differ
diff --git a/src/img/flags/WS.png b/src/img/flags/WS.png
new file mode 100644
index 0000000..5356f6d
Binary files /dev/null and b/src/img/flags/WS.png differ
diff --git a/src/img/flags/XK.png b/src/img/flags/XK.png
new file mode 100644
index 0000000..043e9b5
Binary files /dev/null and b/src/img/flags/XK.png differ
diff --git a/src/img/flags/YE.png b/src/img/flags/YE.png
new file mode 100644
index 0000000..e858bb2
Binary files /dev/null and b/src/img/flags/YE.png differ
diff --git a/src/img/flags/YT.png b/src/img/flags/YT.png
new file mode 100644
index 0000000..642b133
Binary files /dev/null and b/src/img/flags/YT.png differ
diff --git a/src/img/flags/ZA.png b/src/img/flags/ZA.png
new file mode 100644
index 0000000..4535007
Binary files /dev/null and b/src/img/flags/ZA.png differ
diff --git a/src/img/flags/ZM.png b/src/img/flags/ZM.png
new file mode 100644
index 0000000..6283325
Binary files /dev/null and b/src/img/flags/ZM.png differ
diff --git a/src/img/flags/ZW.png b/src/img/flags/ZW.png
new file mode 100644
index 0000000..d87fd6a
Binary files /dev/null and b/src/img/flags/ZW.png differ
diff --git a/src/img/gear-icon-light.svg b/src/img/gear-icon-light.svg
new file mode 100644
index 0000000..c52fe68
--- /dev/null
+++ b/src/img/gear-icon-light.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/gear-icon.svg b/src/img/gear-icon.svg
new file mode 100644
index 0000000..ce8b1cb
--- /dev/null
+++ b/src/img/gear-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/info.svg b/src/img/info.svg
new file mode 100644
index 0000000..a5f000a
--- /dev/null
+++ b/src/img/info.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/moz-vpn-connected.svg b/src/img/moz-vpn-connected.svg
new file mode 100644
index 0000000..c28a9e9
--- /dev/null
+++ b/src/img/moz-vpn-connected.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/img/moz-vpn-disconnected.svg b/src/img/moz-vpn-disconnected.svg
new file mode 100644
index 0000000..bd7b5fd
--- /dev/null
+++ b/src/img/moz-vpn-disconnected.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/img/moz-vpn-logo-light.svg b/src/img/moz-vpn-logo-light.svg
new file mode 100644
index 0000000..305e401
--- /dev/null
+++ b/src/img/moz-vpn-logo-light.svg
@@ -0,0 +1,14 @@
+
diff --git a/src/img/moz-vpn-logo.svg b/src/img/moz-vpn-logo.svg
new file mode 100644
index 0000000..79449c4
--- /dev/null
+++ b/src/img/moz-vpn-logo.svg
@@ -0,0 +1,14 @@
+
diff --git a/src/img/moz-vpn-onboarding.svg b/src/img/moz-vpn-onboarding.svg
new file mode 100644
index 0000000..488645f
--- /dev/null
+++ b/src/img/moz-vpn-onboarding.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/img/moz-vpn-status-icons/moz-vpn-connected.svg b/src/img/moz-vpn-status-icons/moz-vpn-connected.svg
new file mode 100644
index 0000000..31e5581
--- /dev/null
+++ b/src/img/moz-vpn-status-icons/moz-vpn-connected.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/img/moz-vpn-status-icons/moz-vpn-disconnected.svg b/src/img/moz-vpn-status-icons/moz-vpn-disconnected.svg
new file mode 100644
index 0000000..c90bf81
--- /dev/null
+++ b/src/img/moz-vpn-status-icons/moz-vpn-disconnected.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/img/no-connection.svg b/src/img/no-connection.svg
new file mode 100644
index 0000000..02b8663
--- /dev/null
+++ b/src/img/no-connection.svg
@@ -0,0 +1,21 @@
+
+
diff --git a/src/img/onboarding-moz-vpn.svg b/src/img/onboarding-moz-vpn.svg
new file mode 100644
index 0000000..cd451b2
--- /dev/null
+++ b/src/img/onboarding-moz-vpn.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/img/proxy-warning-light.svg b/src/img/proxy-warning-light.svg
new file mode 100644
index 0000000..72b5332
--- /dev/null
+++ b/src/img/proxy-warning-light.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/proxy-warning.svg b/src/img/proxy-warning.svg
new file mode 100644
index 0000000..ce5a29d
--- /dev/null
+++ b/src/img/proxy-warning.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js
index eefbbda..7593ef7 100644
--- a/src/js/background/assignManager.js
+++ b/src/js/background/assignManager.js
@@ -186,13 +186,23 @@ window.assignManager = {
async handleProxifiedRequest(requestInfo) {
// The following blocks potentially dangerous requests for privacy that come without a tabId
- if(requestInfo.tabId === -1)
- return Utils.getBogusProxy();
+
+ if(requestInfo.tabId === -1) {
+ return {type: "direct"};
+ }
const tab = await browser.tabs.get(requestInfo.tabId);
- const proxy = await proxifiedContainers.retrieveFromBackground(tab.cookieStoreId);
+ const result = await proxifiedContainers.retrieve(tab.cookieStoreId);
+ if (!result || !result.proxy) {
+ return {type: "direct"};
+ }
- return proxy;
+ if (!result.proxy.mozProxyEnabled) {
+ return result.proxy;
+ }
+
+ // Let's add the isolation key.
+ return [{ ...result.proxy, connectionIsolationKey: "" + MozillaVPN_Background.isolationKey }];
},
// Before a request is handled by the browser we decide if we should
diff --git a/src/js/background/backgroundLogic.js b/src/js/background/backgroundLogic.js
index e33ee6a..05cad39 100644
--- a/src/js/background/backgroundLogic.js
+++ b/src/js/background/backgroundLogic.js
@@ -41,9 +41,11 @@ const backgroundLogic = {
async deleteContainer(userContextId, removed = false) {
await this._closeTabs(userContextId);
+
if (!removed) {
await browser.contextualIdentities.remove(this.cookieStoreId(userContextId));
}
+
assignManager.deleteContainer(userContextId);
// Now remove the identity->proxy association in proxifiedContainers also
@@ -53,25 +55,13 @@ const backgroundLogic = {
},
async createOrUpdateContainer(options) {
- let donePromise;
if (options.userContextId !== "new") {
- donePromise = browser.contextualIdentities.update(
+ return await browser.contextualIdentities.update(
this.cookieStoreId(options.userContextId),
options.params
);
-
- proxifiedContainers.set(this.cookieStoreId(options.userContextId), options.proxy);
- } else {
- donePromise = browser.contextualIdentities.create(options.params);
-
- // We cannot yet access the new cookieStoreId via this.cookieStoreId(...), so we take this from the resolved promise
- donePromise.then((identity) => {
- proxifiedContainers.set(identity.cookieStoreId, options.proxy);
- }).catch(() => {
- // Empty because this should never happen theoretically.
- });
}
- await donePromise;
+ return await browser.contextualIdentities.create(options.params);
},
async openNewTab(options) {
@@ -160,7 +150,7 @@ const backgroundLogic = {
}
return await identityState.storageArea.set(cookieStoreId, containerState);
} catch (error) {
- console.error(`No container: ${cookieStoreId}`);
+ // console.error(`No container: ${cookieStoreId}`);
}
},
@@ -376,4 +366,4 @@ const backgroundLogic = {
};
-backgroundLogic.init();
\ No newline at end of file
+backgroundLogic.init();
diff --git a/src/js/background/badge.js b/src/js/background/badge.js
index 7b6ccf3..b38d2a3 100644
--- a/src/js/background/badge.js
+++ b/src/js/background/badge.js
@@ -1,4 +1,4 @@
-const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0"];
+const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0", "8.0.0"];
const badge = {
async init() {
const currentWindow = await browser.windows.getCurrent();
diff --git a/src/js/background/index.html b/src/js/background/index.html
index b29b062..818dbb4 100644
--- a/src/js/background/index.html
+++ b/src/js/background/index.html
@@ -16,6 +16,7 @@
+
diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js
index b3270e5..37182bb 100644
--- a/src/js/background/messageHandler.js
+++ b/src/js/background/messageHandler.js
@@ -83,10 +83,10 @@ const messageHandler = {
break;
case "reloadInContainer":
response = assignManager.reloadPageInContainer(
- m.url,
- m.currentUserContextId,
- m.newUserContextId,
- m.tabIndex,
+ m.url,
+ m.currentUserContextId,
+ m.newUserContextId,
+ m.tabIndex,
m.active,
true
);
@@ -94,7 +94,7 @@ const messageHandler = {
case "assignAndReloadInContainer":
tab = await assignManager.reloadPageInContainer(
m.url,
- m.currentUserContextId,
+ m.currentUserContextId,
m.newUserContextId,
m.tabIndex,
m.active,
@@ -106,6 +106,22 @@ const messageHandler = {
return assignManager._setOrRemoveAssignment(tab.id, m.url, m.newUserContextId, m.value);
});
break;
+
+ case "MozillaVPN_attemptPort":
+ MozillaVPN_Background.maybeInitPort();
+ break;
+ case "MozillaVPN_queryServers":
+ MozillaVPN_Background.postToApp("servers");
+ break;
+ case "MozillaVPN_queryStatus":
+ response = MozillaVPN_Background.postToApp("status");
+ break;
+ case "MozillaVPN_getConnectionStatus":
+ response = MozillaVPN_Background.getConnectionStatus();
+ break;
+ case "MozillaVPN_getInstallationStatus":
+ response = MozillaVPN_Background.getInstallationStatus();
+ break;
}
return response;
});
diff --git a/src/js/background/mozillaVpnBackground.js b/src/js/background/mozillaVpnBackground.js
new file mode 100644
index 0000000..8a12730
--- /dev/null
+++ b/src/js/background/mozillaVpnBackground.js
@@ -0,0 +1,105 @@
+const MozillaVPN_Background = {
+ MOZILLA_VPN_SERVERS_KEY: "mozillaVpnServers",
+ MOZILLA_VPN_HIDDEN_TOUTS_LIST_KEY: "mozillaVpnHiddenToutsList",
+
+ _isolationKey: 0,
+
+ async maybeInitPort() {
+ if (this.port && this.port.error === null) {
+ return;
+ }
+ try {
+ /*
+ Find a way to not spam the console when MozillaVPN client is not installed
+ File at path ".../../MozillaVPN/..." is not executable.` thrown by resource://gre/modules/Subprocess.jsm:152`
+ Which does is not caught by this try/catch
+ */
+ this.port = await browser.runtime.connectNative("mozillavpn");
+ this.port.onMessage.addListener(response => this.handleResponse(response));
+
+ this.port.onMessage.addListener(this.handleResponse);
+ this.postToApp("status");
+ this.postToApp("servers");
+
+ // When the mozillavpn dies or the VPN disconnects, we need to increase
+ // the isolation key in order to create new proxy connections. Otherwise
+ // we could see random timeout when the browser tries to connect to an
+ // invalid proxy connection.
+ this.port.onDisconnect.addListener(() => this.increaseIsolationKey());
+
+ } catch(e) {
+ this._installed = false;
+ this._connected = false;
+ }
+ },
+
+ async init() {
+ const { mozillaVpnServers } = await browser.storage.local.get(this.MOZILLA_VPN_SERVERS_KEY);
+ if (typeof(mozillaVpnServers) === "undefined") {
+ await browser.storage.local.set({ [this.MOZILLA_VPN_SERVERS_KEY]:[] });
+ await browser.storage.local.set({ [this.MOZILLA_VPN_HIDDEN_TOUTS_LIST_KEY]:[] });
+ this._installed = false;
+ this._connected = false;
+ }
+ this.maybeInitPort();
+ },
+
+ getConnectionStatus() {
+ return this._connected;
+ },
+
+ getInstallationStatus() {
+ return this._installed;
+ },
+
+ // Post messages to MozillaVPN client
+ postToApp(message) {
+ try {
+ this.port.postMessage({t: message});
+ } catch(e) {
+ if (e.message === "Attempt to postMessage on disconnected port") {
+ this._installed = false;
+ this._connected = false;
+ }
+ }
+ },
+
+ // Handle responses from MozillaVPN client
+ async handleResponse(response) {
+ if (response.error && response.error === "vpn-client-down") {
+ MozillaVPN_Background._connected = false;
+ return;
+ }
+ MozillaVPN_Background._installed = true;
+ if (response.servers) {
+ const servers = response.servers.countries;
+ browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_SERVERS_KEY]: servers});
+ return;
+ }
+
+ if ((response.status && response.status.vpn) || response.t === "status") {
+ const status = response.status ? response.status.vpn : response.vpn;
+
+ if (status === "StateOn") {
+ MozillaVPN_Background._connected = true;
+ }
+
+ if (status === "StateOff" || status === "StateDisconnecting") {
+ MozillaVPN_Background._connected = false;
+ }
+
+ // Let's increase the network key isolation at any vpn status change.
+ MozillaVPN_Background.increaseIsolationKey();
+ }
+ },
+
+ increaseIsolationKey() {
+ ++this._isolationKey;
+ },
+
+ get isolationKey() {
+ return this._isolationKey;
+ },
+};
+
+MozillaVPN_Background.init();
diff --git a/src/js/mozillaVpn.js b/src/js/mozillaVpn.js
new file mode 100644
index 0000000..3f6a78d
--- /dev/null
+++ b/src/js/mozillaVpn.js
@@ -0,0 +1,246 @@
+const MozillaVPN = {
+
+ async handleContainerList(identities) {
+ const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
+ const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
+ this.handleStatusIndicatorsInContainerLists(mozillaVpnInstalled);
+
+ const proxies = await this.getProxies(identities);
+ if (Object.keys(proxies).length === 0) {
+ return;
+ }
+
+ for (const el of document.querySelectorAll("[data-cookie-store-id]")) {
+ const cookieStoreId = el.dataset.cookieStoreId;
+
+ if (!proxies[cookieStoreId]) {
+ continue;
+ }
+ const { proxy } = proxies[cookieStoreId];
+
+ if (typeof(proxy) !== "undefined") {
+ const flag = el.querySelector(".flag-img");
+ if (proxy.countryCode) {
+ flag.src = `/img/flags/${proxy.countryCode.toUpperCase()}.png`;
+ }
+ if (typeof(proxy.mozProxyEnabled) === "undefined" && typeof(proxy.countryCode) !== "undefined") {
+ flag.classList.add("proxy-disabled");
+ }
+ if (!mozillaVpnConnected && proxy.mozProxyEnabled) {
+ flag.classList.add("proxy-unavailable");
+ const menuItemName = el.querySelector(".menu-item-name");
+ if (menuItemName) {
+ el.querySelector(".menu-item-name").dataset.mozProxyWarning = "proxy-unavailable";
+ }
+ }
+ }
+ }
+ },
+
+ async setStatusIndicatorIcons(mozillaVpnInstalled) {
+
+ const statusIconEls = document.querySelectorAll(".moz-vpn-connection-status-indicator");
+
+ if (!mozillaVpnInstalled) {
+ statusIconEls.forEach(el => {
+ el.style.backgroundImage = "none";
+ if (el.querySelector(".tooltip")) {
+ el.querySelector(".tooltip").textContent = "";
+ }
+ el.textContent = "";
+ });
+ return;
+ }
+
+ const connectedIndicatorSrc = "url(./img/moz-vpn-connected.svg)";
+ const disconnectedIndicatorSrc = "url(./img/moz-vpn-disconnected.svg)";
+
+ const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
+ const connectionStatusStringId = mozillaVpnConnected ? "moz-vpn-connected" : "moz-vpn-disconnected";
+ const connectionStatusLocalizedString = browser.i18n.getMessage(connectionStatusStringId);
+
+ statusIconEls.forEach(el => {
+ el.style.backgroundImage = mozillaVpnConnected ? connectedIndicatorSrc : disconnectedIndicatorSrc;
+ if (el.querySelector(".tooltip")) {
+ el.querySelector(".tooltip").textContent = connectionStatusLocalizedString;
+ } else {
+ el.textContent = connectionStatusLocalizedString;
+ }
+ });
+ },
+
+ async handleStatusIndicatorsInContainerLists(mozillaVpnInstalled) {
+ const mozVpnLogotypes = document.querySelectorAll(".moz-vpn-logotype.vpn-status-container-list");
+
+ try {
+ if (!mozillaVpnInstalled) {
+ mozVpnLogotypes.forEach(el => {
+ el.style.display = "none";
+ });
+ return;
+ }
+ mozVpnLogotypes.forEach(el => {
+ el.style.display = "flex";
+ el.classList.remove("display-none");
+ });
+ this.setStatusIndicatorIcons(mozillaVpnInstalled);
+ } catch (e) {
+ mozVpnLogotypes.forEach(el => {
+ el.style.display = "none";
+ });
+ return;
+ }
+ },
+
+ handleMozillaCtaClick(buttonIdentifier) {
+ browser.tabs.create({
+ url: MozillaVPN.attachUtmParameters("https://www.mozilla.org/products/vpn", buttonIdentifier),
+ });
+ },
+
+ getRandomInteger(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+ },
+
+ proxyIsDisabled(proxy) {
+ return (
+ // Mozilla VPN proxy is disabled, last location data is stored
+ (proxy.mozProxyEnabled === undefined && proxy.countryCode !== undefined && proxy.cityName !== undefined) ||
+ // Mozilla VPN proxy is enabled but Mozilla VPN is not connected
+ proxy.mozProxyEnabled !== undefined
+ );
+ },
+
+ attachUtmParameters(baseUrl, utmContent) {
+ const url = new URL(baseUrl);
+ const utmParameters = {
+ utm_source: "multi.account.containers",
+ utm_medium: "mac-browser-addon",
+ utm_content: utmContent,
+ utm_campaign: "vpn-better-together",
+ };
+
+ for (const param in utmParameters) {
+ url.searchParams.append(param, utmParameters[param]);
+ }
+ return url.href;
+ },
+
+ async getProxies(identities) {
+ const proxies = {};
+ const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
+
+ if (mozillaVpnInstalled) {
+ for (const identity of identities) {
+ try {
+ const proxy = await proxifiedContainers.retrieve(identity.cookieStoreId);
+ proxies[identity.cookieStoreId] = proxy;
+ } catch (e) {
+ proxies[identity.cookieStoreId] = {};
+ }
+ }
+ }
+ return proxies;
+ },
+
+ getMozillaProxyInfoObj() {
+ return {
+ countryCode: undefined,
+ cityName: undefined,
+ mozProxyEnabled: undefined
+ };
+ },
+
+
+ async getProxyWarnings(proxyObj) {
+ if (!proxyObj) {
+ return "";
+ }
+
+ const { proxy } = proxyObj;
+
+ if (typeof(proxy) === "undefined") {
+ return "";
+ }
+
+ const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
+ if (typeof(proxy.mozProxyEnabled) !== "undefined" && !mozillaVpnConnected) {
+ return "proxy-unavailable";
+ }
+ },
+
+ async getFlag(proxyObj) {
+ const flag = {
+ imgCode: "default",
+ elemClasses: "display-none",
+ imgAlt: "",
+ };
+
+ if (!proxyObj) {
+ return flag;
+ }
+
+ const { proxy } = proxyObj;
+ const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
+ if (typeof(proxy) === "undefined" || !mozillaVpnInstalled) {
+ return flag;
+ }
+
+ const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
+ if (mozillaVpnInstalled && typeof(proxy.cityName) !== "undefined") {
+ flag.imgCode = proxy.countryCode.toUpperCase();
+ flag.imgAlt = proxy.cityName;
+ flag.elemClasses = typeof(proxy.mozProxyEnabled) === "undefined" || !mozillaVpnConnected ? "proxy-disabled" : "";
+ }
+
+ return flag;
+ },
+
+ getProxy(countryCode, cityName, mozProxyEnabled, mozillaVpnServers) {
+ const selectedServerCountry = mozillaVpnServers.find(({code}) => code === countryCode);
+ const selectedServerCity = selectedServerCountry.cities.find(({name}) => name === cityName);
+ const proxyServer = this.pickServerBasedOnWeight(selectedServerCity.servers);
+ return proxifiedContainers.parseProxy(
+ this.makeProxyString(proxyServer.socksName),
+ {
+ countryCode: countryCode,
+ cityName: cityName,
+ mozProxyEnabled,
+ }
+ );
+ },
+
+ makeProxyString(socksName) {
+ return `socks://${socksName}.mullvad.net:1080`;
+ },
+
+ async pickRandomLocation() {
+ const { mozillaVpnServers } = await browser.storage.local.get("mozillaVpnServers");
+ const randomInteger = this.getRandomInteger(0, mozillaVpnServers.length - 1);
+ const randomServerCountry = mozillaVpnServers[randomInteger];
+
+ return {
+ randomServerCountryCode: randomServerCountry.code,
+ randomServerCityName: randomServerCountry.cities[0].name,
+ };
+
+ },
+
+ pickServerBasedOnWeight(serverList) {
+ const filteredServerList = serverList.filter(server => typeof(server.socksName) !== "undefined" && server.socksName !== "");
+
+ const sumWeight = filteredServerList.reduce((sum, { weight }) => sum + weight, 0);
+ let randomInteger = this.getRandomInteger(0, sumWeight);
+
+ let nextServer = {};
+ for (const server of filteredServerList) {
+ if (server.weight >= randomInteger) {
+ return nextServer = server;
+ }
+ randomInteger = (randomInteger - server.weight);
+ }
+ return nextServer;
+ }
+};
+
+window.MozillaVPN = MozillaVPN;
diff --git a/src/js/pageAction.js b/src/js/pageAction.js
index 91445ce..bc0ba3c 100644
--- a/src/js/pageAction.js
+++ b/src/js/pageAction.js
@@ -1,22 +1,23 @@
async function init() {
const fragment = document.createDocumentFragment();
-
const identities = await browser.contextualIdentities.query({});
- identities.forEach(identity => {
+ for (const identity of identities) {
const tr = document.createElement("tr");
tr.classList.add("menu-item", "hover-highlight");
+ tr.setAttribute("data-cookie-store-id", identity.cookieStoreId);
const td = document.createElement("td");
-
- td.innerHTML = Utils.escaped`
+ td.innerHTML = Utils.escaped`
- `;
-
+
+
+ `;
+
tr.appendChild(td);
fragment.appendChild(tr);
@@ -24,12 +25,13 @@ async function init() {
Utils.alwaysOpenInContainer(identity);
window.close();
});
- });
+ }
const list = document.querySelector("#picker-identities-list");
-
list.innerHTML = "";
list.appendChild(fragment);
+
+ MozillaVPN.handleContainerList(identities);
}
init();
diff --git a/src/js/popup.js b/src/js/popup.js
index ce91c91..33ddb09 100644
--- a/src/js/popup.js
+++ b/src/js/popup.js
@@ -21,6 +21,8 @@ const P_ONBOARDING_4 = "onboarding4";
const P_ONBOARDING_5 = "onboarding5";
const P_ONBOARDING_6 = "onboarding6";
const P_ONBOARDING_7 = "onboarding7";
+const P_ONBOARDING_8 = "onboarding8";
+
const P_CONTAINERS_LIST = "containersList";
const OPEN_NEW_CONTAINER_PICKER = "new-tab";
const MANAGE_CONTAINERS_PICKER = "manage";
@@ -32,6 +34,9 @@ const P_CONTAINER_DELETE = "containerDelete";
const P_CONTAINERS_ACHIEVEMENT = "containersAchievement";
const P_CONTAINER_ASSIGNMENTS = "containerAssignments";
+const P_MOZILLA_VPN_SERVER_LIST = "moz-vpn-server-list";
+const P_ADVANCED_PROXY_SETTINGS = "advanced-proxy-settings-panel";
+
function addRemoveSiteIsolation() {
const identity = Logic.currentIdentity();
browser.runtime.sendMessage({
@@ -57,6 +62,10 @@ const Logic = {
_onboardingVariation: null,
async init() {
+ browser.runtime.sendMessage({
+ method: "MozillaVPN_attemptPort"
+ }),
+
// Remove browserAction "upgraded" badge when opening panel
this.clearBrowserActionBadge();
@@ -74,16 +83,19 @@ const Logic = {
const onboardingData = await browser.storage.local.get([ONBOARDING_STORAGE_KEY]);
let onboarded = onboardingData[ONBOARDING_STORAGE_KEY];
if (!onboarded) {
- onboarded = 0;
+ onboarded = 9;
this.setOnboardingStage(onboarded);
}
switch (onboarded) {
- case 7:
+ case 8:
this.showAchievementOrContainersListPanel();
break;
+ case 7:
+ this.showPanel(P_ONBOARDING_8);
+ break;
case 6:
- this.showPanel(P_ONBOARDING_7);
+ this.showPanel(P_ONBOARDING_8);
break;
case 5:
this.showPanel(P_ONBOARDING_6);
@@ -148,7 +160,7 @@ const Logic = {
async clearBrowserActionBadge() {
const extensionInfo = await getExtensionInfo();
const storage = await browser.storage.local.get({ browserActionBadgesClicked: [] });
- browser.browserAction.setBadgeBackgroundColor({ color: null });
+ browser.browserAction.setBadgeBackgroundColor({ color: "#ffffff" });
browser.browserAction.setBadgeText({ text: "" });
storage.browserActionBadgesClicked.push(extensionInfo.version);
// use set and spread to create a unique array
@@ -243,8 +255,8 @@ const Logic = {
}
},
- async showPanel(panel, currentIdentity = null, backwards = false) {
- if (!backwards || !this._currentPanel) {
+ async showPanel(panel, currentIdentity = null, backwards = false, addToPreviousPanelPath = true) {
+ if ((!backwards && addToPreviousPanelPath) || !this._currentPanel) {
this._previousPanelPath.push(this._currentPanel);
}
@@ -375,7 +387,7 @@ const Logic = {
const closeContEl = document.querySelector("#close-container-picker-panel");
if (!this._listenerSet) {
Utils.addEnterHandler(closeContEl, () => {
- Logic.showPreviousPanel();
+ Logic.showPanel(P_CONTAINERS_LIST);
});
this._listenerSet = true;
}
@@ -585,12 +597,12 @@ Logic.registerPanel(P_ONBOARDING_6, {
Logic.showPanel(P_ONBOARDING_7);
});
Utils.addEnterHandler(document.querySelector("#no-sync"), async () => {
- await Logic.setOnboardingStage(7);
+ await Logic.setOnboardingStage(6);
await browser.storage.local.set({syncEnabled: false});
await browser.runtime.sendMessage({
method: "resetSync"
});
- Logic.showPanel(P_CONTAINERS_LIST);
+ Logic.showPanel(P_ONBOARDING_8);
});
},
@@ -599,9 +611,7 @@ Logic.registerPanel(P_ONBOARDING_6, {
return Promise.resolve(null);
},
});
-
-// P_ONBOARDING_6: Sixth page for Onboarding: new tab long-press behavior
-// ----------------------------------------------------------------------------
+// -----------------------------------------------------------------------
Logic.registerPanel(P_ONBOARDING_7, {
panelSelector: ".onboarding-panel-7",
@@ -614,10 +624,27 @@ Logic.registerPanel(P_ONBOARDING_7, {
url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync",
});
await Logic.setOnboardingStage(7);
- Logic.showPanel(P_CONTAINERS_LIST);
+ Logic.showPanel(P_ONBOARDING_8);
});
Utils.addEnterHandler(document.querySelector("#no-sign-in"), async () => {
await Logic.setOnboardingStage(7);
+ Logic.showPanel(P_ONBOARDING_8);
+ });
+ },
+
+ // This method is called when the panel is shown.
+ prepare() {
+ return Promise.resolve(null);
+ },
+});
+
+Logic.registerPanel(P_ONBOARDING_8, {
+ panelSelector: ".onboarding-panel-8",
+
+ // This method is called when the object is registered.
+ initialize() {
+ Utils.addEnterHandler(document.querySelector("#onboarding-done-btn"), async () => {
+ await Logic.setOnboardingStage(8);
Logic.showPanel(P_CONTAINERS_LIST);
});
},
@@ -635,6 +662,24 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
// This method is called when the object is registered.
async initialize() {
+ const mozillaVpnToutName = "moz-tout-main-panel";
+
+ await browser.runtime.sendMessage({ method: "MozillaVPN_queryStatus" });
+ Utils.addEnterHandler(document.querySelector("#moz-vpn-learn-more"), () => {
+ MozillaVPN.handleMozillaCtaClick("mac-main-panel-btn");
+ window.close();
+ });
+ Utils.addEnterHandler(document.querySelector(".dismiss-moz-vpn-tout"), async() => {
+ const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
+ if (typeof(mozillaVpnHiddenToutsList) === "undefined") {
+ await browser.storage.local.set({ "mozillaVpnHiddenToutsList": [] });
+ }
+ document.querySelector("#moz-vpn-tout").classList.add("disappear");
+ mozillaVpnHiddenToutsList.push({
+ name: mozillaVpnToutName
+ });
+ await browser.storage.local.set({ mozillaVpnHiddenToutsList });
+ });
Utils.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => {
if (!e.target.classList.contains("disable-edit-containers")) {
Logic.showPanel(MANAGE_CONTAINERS_PICKER);
@@ -663,6 +708,13 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
}
});
+ const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
+ const mozillaVpnToutShouldBeHidden = mozillaVpnHiddenToutsList && mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnToutName);
+
+ const mozVpnTout = document.getElementById("moz-vpn-tout");
+ if (mozillaVpnToutShouldBeHidden) {
+ mozVpnTout.remove();
+ }
},
unregister() {
@@ -671,37 +723,54 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
// This method is called when the panel is shown.
async prepare() {
const fragment = document.createDocumentFragment();
+ const identities = Logic.identities();
- Logic.identities().forEach(identity => {
+ for (const identity of identities) {
const tr = document.createElement("tr");
tr.classList.add("menu-item", "hover-highlight", "keyboard-nav", "keyboard-right-arrow-override");
tr.setAttribute("tabindex", "0");
+ tr.setAttribute("data-cookie-store-id", identity.cookieStoreId);
const td = document.createElement("td");
const openTabs = identity.numberOfOpenTabs || "" ;
+ // TODO get UX and content decision on how to message and block clicks to containers with Mozilla VPN proxy configs
+ // when Mozilla VPN app is disconnected.
+
td.innerHTML = Utils.escaped`
-
+
+