Compare commits

...

9 Commits

Author SHA1 Message Date
luke crouch 31ac365e6d Merge pull request #974 from mozilla/bump-version-to-4.1.0
bump version to 4.1.0
2017-11-16 09:50:59 -06:00
groovecoder df8471a4dd bump version to 4.1.0 2017-11-16 09:47:18 -06:00
groovecoder 18539f2540 ignore webextension/web-ext-artifacts 2017-11-16 15:38:34 +00:00
Jonathan Kingston 7c1105a2b7 Change (un)install changes to only work for >57. Fixes #858 and Fixes #900 2017-11-16 15:38:34 +00:00
groovecoder 31298146f3 when user reaches container tab count, show achievement panel 2017-11-16 15:30:02 +00:00
groovecoder 4e6eee220c start containerTabsOpened counter 2017-11-16 15:30:02 +00:00
baku a7be3c9935 TextEncoder/TextDecoder from Cu.importGlobalProperties - #949 2017-11-14 19:36:34 +00:00
luke crouch f512473986 Merge pull request #882 from mozilla/update-README-distribute-steps
add steps for signing, AMO, and GitHub to README
2017-09-29 14:21:22 -05:00
groovecoder 8166a37722 add steps for signing, AMO, and GitHub to README 2017-09-29 13:15:16 -05:00
13 changed files with 279 additions and 42 deletions
+2
View File
@@ -8,3 +8,5 @@ README.html
.vimrc .vimrc
.env .env
addon.env addon.env
webextension/web-ext-artifacts/*
+31 -10
View File
@@ -78,23 +78,44 @@ To build a local testpilot-containers.xpi, use the plain [`jpm
xpi`](https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/jpm#jpm_xpi) command, xpi`](https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/jpm#jpm_xpi) command,
or run `npm run build`. or run `npm run build`.
### Signing an .xpi
To sign an .xpi, use [`jpm
sign`](https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/jpm#jpm_sign)
command.
Note: You will need to be [an author on the AMO
add-on](https://addons.mozilla.org/en-US/developers/addon/containers-experiment/ownership).
### Testing ### Testing
TBD TBD
### Distributing ### Distributing
TBD #### Make the new version
1. Bump the version number in `package.json`, `install.rdf`, and
`manifest.json`
2. Commit the version number bump
3. Create a git tag for the version: `git tag <version>`
4. Push the tag up to GitHub: `git push --tags`
#### Publish to AMO
While the add-on is an Embedded Web Extension, we have to use the [Mozilla
Internal Signing
Service](https://mana.mozilla.org/wiki/display/FIREFOX/Internal+Extension+Signing)
to sign it as a Mozilla extension exempt from AMO's Web Extension restrictions.
So, to distribute the add-on to AMO:
1. Use `jpm xpi` to build the `.xpi` file
2. [Submit the `.xpi` to the Internal Signing Service and download the signed `.xpi`](https://mana.mozilla.org/wiki/display/SVCOPS/Sign+a+Mozilla+Internal+Extension)
3. [Upload the signed `.xpi` file to
AMO](https://addons.mozilla.org/en-US/developers/addon/multi-account-containers/versions/submit/)
#### Publish to GitHub
Finally, we also publish the release to GitHub for those followers.
1. [Make the new release on
GitHub](https://github.com/mozilla/multi-account-containers/releases/new)
* Use the version number for "Tag version" and "Release title"
* Release notes: copy the output of `git log --no-merges --pretty=format:"%h %s" <previous-version>..<new-version>`
* Attach binaries: select the signed `.xpi` file
### Links ### Links
Facebook & Twitter icons CC-Attrib http://fairheadcreative.com.
- [Licence](./LICENSE.txt) - [Licence](./LICENSE.txt)
- [Contributing](./CONTRIBUTING.md) - [Contributing](./CONTRIBUTING.md)
- [Code Of Conduct](./CODE_OF_CONDUCT.md) - [Code Of Conduct](./CODE_OF_CONDUCT.md)
+42 -25
View File
@@ -31,7 +31,7 @@ const Cu = Components.utils;
const Cc = Components.classes; const Cc = Components.classes;
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const { TextDecoder, TextEncoder } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); Cu.importGlobalProperties(["TextEncoder", "TextDecoder"]);
XPCOMUtils.defineLazyModuleGetter(this, "OS", XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm"); "resource://gre/modules/osfile.jsm");
@@ -130,41 +130,58 @@ async function install() {
} }
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
async function uninstall(aData, aReason) { async function uninstall({resourceURI}, aReason) {
if (aReason === ADDON_UNINSTALL if (checkLegacyFirefox()) {
|| aReason === ADDON_DISABLE) { if (aReason === ADDON_UNINSTALL) {
const config = await getConfig(); unloadStyles(resourceURI);
const storedPrefs = config.savedConfiguration.prefs || {}; await removeChanges();
PREFS.forEach((pref) => { }
let value = pref.default;
if (pref.name in storedPrefs) {
value = storedPrefs[pref.name];
}
if ("int" === pref.type) {
Services.prefs.setIntPref(pref.name, value);
} else {
Services.prefs.setBoolPref(pref.name, value);
}
});
} }
} }
async function removeChanges() {
const config = await getConfig();
const storedPrefs = config.savedConfiguration.prefs || {};
PREFS.forEach((pref) => {
let value = pref.default;
if (pref.name in storedPrefs) {
value = storedPrefs[pref.name];
}
if ("int" === pref.type) {
Services.prefs.setIntPref(pref.name, value);
} else {
Services.prefs.setBoolPref(pref.name, value);
}
});
}
function checkLegacyFirefox() {
const version = Services.appinfo.version;
const versionMatch = version.match(/^([0-9]+)\./)[1];
if (Number(versionMatch) <= 56) {
return true;
}
return false;
}
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
function startup({webExtension, resourceURI}) { function startup({webExtension, resourceURI}) {
const version = Services.appinfo.version; if (checkLegacyFirefox()) {
const versionMatch = version.match(/^([0-9]+)\./)[1];
if (versionMatch === "55"
|| versionMatch === "56") {
loadStyles(resourceURI); loadStyles(resourceURI);
// Reset prefs that may have changed, or are legacy
install();
} }
// Reset prefs that may have changed, or are legacy
install();
// Start the embedded webextension. // Start the embedded webextension.
webExtension.startup(); webExtension.startup();
} }
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
function shutdown({resourceURI}) { function shutdown({resourceURI}, aReason) {
unloadStyles(resourceURI); if (checkLegacyFirefox()) {
unloadStyles(resourceURI);
if (aReason === ADDON_DISABLE) {
removeChanges();
}
}
} }
+1 -1
View File
@@ -16,7 +16,7 @@
<em:maxVersion>*</em:maxVersion> <em:maxVersion>*</em:maxVersion>
</Description> </Description>
</em:targetApplication> </em:targetApplication>
<em:version>4.0.3</em:version> <em:version>4.1.0</em:version>
<em:unpack>false</em:unpack> <em:unpack>false</em:unpack>
</Description> </Description>
</RDF> </RDF>
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "testpilot-containers", "name": "testpilot-containers",
"title": "Multi-Account Containers", "title": "Multi-Account Containers",
"description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", "description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.",
"version": "4.0.3", "version": "4.1.0",
"author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston",
"bugs": { "bugs": {
"url": "https://github.com/mozilla/testpilot-containers/issues" "url": "https://github.com/mozilla/testpilot-containers/issues"
+52 -1
View File
@@ -242,7 +242,8 @@ table {
min-block-size: 400px; min-block-size: 400px;
} }
.panel.onboarding { .panel.onboarding,
.achievement-panel {
align-items: center; align-items: center;
block-size: 360px; block-size: 360px;
margin-block-end: 16px; margin-block-end: 16px;
@@ -887,3 +888,53 @@ span ~ .panel-header-text {
font-size: 14px !important; font-size: 14px !important;
padding-block-end: 6px; padding-block-end: 6px;
} }
/* Achievement panel elements */
.share-ctas {
padding-block-end: 0.5em;
padding-block-start: 0.5em;
padding-inline-end: 0.5em;
padding-inline-start: 0.5em;
text-align: center;
}
.cta-link {
text-decoration: none;
}
.cta {
color: #fff;
font-size: 0.7em;
font-weight: bold;
margin-block-end: 0.4em;
margin-block-start: 0.4em;
margin-inline-end: 0.4em;
margin-inline-start: 0.4em;
padding-block-end: 0.5em;
padding-block-start: 0.5em;
padding-inline-end: 0.5em;
padding-inline-start: 0.5em;
text-transform: uppercase;
}
.cta-icon {
height: 18px;
padding-right: 0.5em;
vertical-align: middle;
}
.fb-share-cta {
background: #375496;
}
.fb-share-cta .cta-icon {
margin-block-start: -5px;
}
.tweet-cta {
background: #37bae7;
}
.amo-rate-cta {
background: #0f1126;
}
+1
View File
@@ -0,0 +1 @@
<svg width="32px" height="33px" viewBox="0 0 32 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch --> <desc>Created with Sketch.</desc> <defs> <linearGradient x1="74.0423237%" y1="18.5882821%" x2="0%" y2="100%" id="linearGradient-1"> <stop stop-color="#00FEFF" offset="0%"/> <stop stop-color="#3D85FF" offset="100%"/> </linearGradient> </defs> <g id="Specs" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Header-Copy" transform="translate(-182.000000, -152.000000)" fill="url(#linearGradient-1)"> <path d="M205.58574,176.859518 L205.58574,169.287998 C205.58574,169.287998 205.800116,167.315137 207.086372,167.315137 C208.372629,167.315137 208.265441,169.394639 210.677171,169.394639 C211.909834,169.394639 214,168.754792 214,165.022352 C214,161.289912 211.909834,160.810027 210.677171,160.810027 C208.265441,160.810027 208.372629,162.782888 207.086372,162.782888 C205.800116,162.782888 205.58574,160.756707 205.58574,160.756707 L205.58574,157.664114 C205.58574,156.491061 204.621048,155.531291 203.44198,155.531291 L197.814608,155.531291 C197.814608,155.531291 195.992412,155.211368 195.992412,153.931674 C195.992412,152.65198 198.028985,152.545339 198.028985,150.145914 C198.028985,148.91954 197.332262,147 193.580682,147 C189.829101,147 189.293161,148.91954 189.293161,150.145914 C189.293161,152.545339 191.115357,152.65198 191.115357,153.931674 C191.115357,155.211368 189.293161,155.531291 189.293161,155.531291 L184.148135,155.531291 C182.969067,155.531291 182.004375,156.491061 182.004375,157.664114 L182.004375,161.823118 C182.004375,161.823118 181.789999,165.022352 184.362512,165.022352 C186.023926,165.022352 186.07752,162.836209 188.274874,162.836209 C189.346755,162.836209 190.418635,163.8493 190.418635,166.035443 C190.418635,168.274907 189.346755,169.394639 188.274874,169.394639 C186.131114,169.394639 186.023926,167.208496 184.362512,167.208496 C181.789999,167.208496 182.004375,170.301089 182.004375,170.301089 L182.004375,176.859518 C182.004375,178.032571 182.969067,178.992341 184.148135,178.992341 L191.115357,178.992341 C191.115357,178.992341 194.49178,179.205623 194.49178,176.646236 C194.49178,174.993299 192.348019,174.726696 192.348019,172.540552 C192.348019,171.474141 193.527088,170.141127 195.778036,170.141127 C198.028985,170.141127 199.315241,171.474141 199.315241,172.540552 C199.315241,174.673375 197.225074,174.993299 197.225074,176.646236 C197.225074,179.258944 200.601497,178.992341 200.601497,178.992341 L203.44198,178.992341 C204.621048,178.992341 205.58574,178.032571 205.58574,176.859518 Z" id="Shape-Copy-23" transform="translate(198.000000, 163.000000) rotate(-42.000000) translate(-198.000000, -163.000000) "/> </g> </g> </svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-14 -14 48 48" enable-background="new -14 -14 48 48" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="90.0527" y1="-99.7603" x2="90.0527" y2="-106.3809" gradientTransform="matrix(7.2338 0 0 -7.2338 -641.4998 -735.5619)">
<stop offset="0" style="stop-color:#4B71B8"/>
<stop offset="1" style="stop-color:#293F7E"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M33.931,27.993c0,3.304-2.689,5.983-6.002,5.983H-8.082c-3.315,0-6.001-2.683-6.001-5.983V-7.928
c0-3.308,2.687-5.988,6.001-5.988h36.011c3.312,0,6.002,2.681,6.002,5.988V27.993z"/>
<path fill="#FFFFFF" d="M25.613-4.557c0,0-3.707,0-6.166,0c-3.662,0-7.732,1.535-7.732,6.835c0.019,1.845,0,3.613,0,5.603H7.481
v6.728h4.366v19.37h8.021V14.48h5.295l0.479-6.618h-5.913c0,0,0.016-2.946,0-3.8c0-2.093,2.184-1.974,2.312-1.974
c1.042,0,3.059,0.003,3.578,0v-6.646H25.613z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="23.9995" y1="0" x2="23.9995" y2="48.0005">
<stop offset="0" style="stop-color:#4BD0EF"/>
<stop offset="1" style="stop-color:#29AAE1"/>
</linearGradient>
<path fill-rule="evenodd" clip-rule="evenodd" fill="url(#SVGID_1_)" d="M48,42c0,3.313-2.687,6-6,6H6c-3.313,0-6-2.687-6-6V6
c0-3.313,2.687-6,6-6h36c3.313,0,6,2.687,6,6V42z"/>
<path fill="#29AAE1" d="M40.231,13.413c-1.12,0.497-2.323,0.833-3.588,0.984c1.291-0.774,2.28-1.998,2.747-3.457
c-1.206,0.716-2.543,1.236-3.968,1.516c-1.139-1.214-2.763-1.972-4.56-1.972c-3.449,0-6.246,2.796-6.246,6.247
c0,0.49,0.055,0.966,0.161,1.424c-5.192-0.261-9.795-2.749-12.876-6.528c-0.538,0.923-0.846,1.996-0.846,3.141
c0,2.167,1.103,4.08,2.779,5.199c-1.024-0.032-1.987-0.313-2.83-0.781c0,0.026,0,0.053,0,0.079c0,3.026,2.153,5.551,5.011,6.125
c-0.525,0.143-1.076,0.219-1.646,0.219c-0.403,0-0.794-0.038-1.176-0.11c0.795,2.48,3.102,4.287,5.835,4.338
c-2.138,1.675-4.832,2.675-7.758,2.675c-0.504,0-1.002-0.03-1.491-0.089c2.765,1.773,6.048,2.808,9.576,2.808
c11.49,0,17.774-9.519,17.774-17.774c0-0.271-0.006-0.54-0.019-0.809C38.334,15.766,39.394,14.666,40.231,13.413z"/>
<path fill="#FFFFFF" d="M40.231,14.739c-1.12,0.497-2.323,0.833-3.588,0.984c1.291-0.773,2.28-1.998,2.747-3.456
c-1.206,0.716-2.543,1.236-3.968,1.516c-1.139-1.214-2.763-1.972-4.56-1.972c-3.449,0-6.246,2.796-6.246,6.247
c0,0.489,0.055,0.966,0.161,1.424c-5.192-0.261-9.795-2.748-12.876-6.527c-0.538,0.923-0.846,1.996-0.846,3.141
c0,2.167,1.103,4.079,2.779,5.199c-1.024-0.032-1.987-0.313-2.83-0.781c0,0.026,0,0.052,0,0.079c0,3.027,2.153,5.551,5.011,6.125
c-0.525,0.144-1.076,0.219-1.646,0.219c-0.403,0-0.794-0.038-1.176-0.11c0.795,2.481,3.102,4.287,5.835,4.338
c-2.138,1.676-4.832,2.675-7.758,2.675c-0.504,0-1.002-0.03-1.491-0.089c2.765,1.773,6.048,2.808,9.576,2.808
c11.49,0,17.774-9.519,17.774-17.774c0-0.271-0.006-0.54-0.019-0.808C38.334,17.092,39.394,15.992,40.231,14.739z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -112,6 +112,14 @@ const messageHandler = {
// lets remember the last tab created so we can close it if it looks like a redirect // lets remember the last tab created so we can close it if it looks like a redirect
this.lastCreatedTab = tab; this.lastCreatedTab = tab;
if (tab.cookieStoreId) { if (tab.cookieStoreId) {
// Don't count firefox-default, firefox-private, nor our own confirm page loads
if (tab.cookieStoreId !== "firefox-default" &&
tab.cookieStoreId !== "firefox-private" &&
!tab.url.startsWith("moz-extension")) {
// increment the counter of container tabs opened
this.incrementCountOfContainerTabsOpened();
}
this.unhideContainer(tab.cookieStoreId); this.unhideContainer(tab.cookieStoreId);
} }
setTimeout(() => { setTimeout(() => {
@@ -120,6 +128,24 @@ const messageHandler = {
}); });
}, },
async incrementCountOfContainerTabsOpened() {
const key = "containerTabsOpened";
const count = await browser.storage.local.get({[key]: 0});
const countOfContainerTabsOpened = ++count[key];
browser.storage.local.set({[key]: countOfContainerTabsOpened});
// When the user opens their _ tab, give them the achievement
if (countOfContainerTabsOpened === 100) {
const storage = await browser.storage.local.get({achievements: []});
storage.achievements.push({"name": "manyContainersOpened", "done": false});
// use set and spread to create a unique array
const achievements = [...new Set(storage.achievements)];
browser.storage.local.set({achievements});
browser.browserAction.setBadgeBackgroundColor({color: "rgba(0,217,0,255)"});
browser.browserAction.setBadgeText({text: "NEW"});
}
},
async unhideContainer(cookieStoreId) { async unhideContainer(cookieStoreId) {
if (!this.unhideQueue.includes(cookieStoreId)) { if (!this.unhideQueue.includes(cookieStoreId)) {
this.unhideQueue.push(cookieStoreId); this.unhideQueue.push(cookieStoreId);
+56 -3
View File
@@ -22,6 +22,7 @@ const P_CONTAINERS_EDIT = "containersEdit";
const P_CONTAINER_INFO = "containerInfo"; const P_CONTAINER_INFO = "containerInfo";
const P_CONTAINER_EDIT = "containerEdit"; const P_CONTAINER_EDIT = "containerEdit";
const P_CONTAINER_DELETE = "containerDelete"; const P_CONTAINER_DELETE = "containerDelete";
const P_CONTAINERS_ACHIEVEMENT = "containersAchievement";
/** /**
* Escapes any occurances of &, ", <, > or / with XML entities. * Escapes any occurances of &, ", <, > or / with XML entities.
@@ -90,8 +91,8 @@ const Logic = {
// Routing to the correct panel. // Routing to the correct panel.
// If localStorage is disabled, we don't show the onboarding. // If localStorage is disabled, we don't show the onboarding.
const data = await browser.storage.local.get([ONBOARDING_STORAGE_KEY]); const onboardingData = await browser.storage.local.get([ONBOARDING_STORAGE_KEY]);
let onboarded = data[ONBOARDING_STORAGE_KEY]; let onboarded = onboardingData[ONBOARDING_STORAGE_KEY];
if (!onboarded) { if (!onboarded) {
onboarded = 0; onboarded = 0;
this.setOnboardingStage(onboarded); this.setOnboardingStage(onboarded);
@@ -99,7 +100,7 @@ const Logic = {
switch (onboarded) { switch (onboarded) {
case 5: case 5:
this.showPanel(P_CONTAINERS_LIST); this.showAchievementOrContainersListPanel();
break; break;
case 4: case 4:
this.showPanel(P_ONBOARDING_5); this.showPanel(P_ONBOARDING_5);
@@ -121,6 +122,37 @@ const Logic = {
}, },
async showAchievementOrContainersListPanel() {
// Do we need to show an achievement panel?
let showAchievements = false;
const achievementsStorage = await browser.storage.local.get({achievements: []});
for (const achievement of achievementsStorage.achievements) {
if (!achievement.done) {
showAchievements = true;
}
}
if (showAchievements) {
this.showPanel(P_CONTAINERS_ACHIEVEMENT);
} else {
this.showPanel(P_CONTAINERS_LIST);
}
},
// In case the user wants to click multiple actions,
// they have to click the "Done" button to stop the panel
// from showing
async setAchievementDone(achievementName) {
const achievementsStorage = await browser.storage.local.get({achievements: []});
const achievements = achievementsStorage.achievements;
achievements.forEach((achievement, index, achievementsArray) => {
if (achievement.name === achievementName) {
achievement.done = true;
achievementsArray[index] = achievement;
}
});
browser.storage.local.set({achievements});
},
setOnboardingStage(stage) { setOnboardingStage(stage) {
return browser.storage.local.set({ return browser.storage.local.set({
[ONBOARDING_STORAGE_KEY]: stage [ONBOARDING_STORAGE_KEY]: stage
@@ -1015,4 +1047,25 @@ Logic.registerPanel(P_CONTAINER_DELETE, {
}, },
}); });
// P_CONTAINERS_ACHIEVEMENT: Page for achievement.
// ----------------------------------------------------------------------------
Logic.registerPanel(P_CONTAINERS_ACHIEVEMENT, {
panelSelector: ".achievement-panel",
// This method is called when the object is registered.
initialize() {
// Set done and move to the containers list panel.
Logic.addEnterHandler(document.querySelector("#achievement-done-button"), async function () {
await Logic.setAchievementDone("manyContainersOpened");
Logic.showPanel(P_CONTAINERS_LIST);
});
},
// This method is called when the panel is shown.
prepare() {
return Promise.resolve(null);
},
});
Logic.init(); Logic.init();
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Firefox Multi-Account Containers", "name": "Firefox Multi-Account Containers",
"version": "4.0.3", "version": "4.1.0",
"description": "Multi-Account Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.", "description": "Multi-Account Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.",
"icons": { "icons": {
+28
View File
@@ -67,6 +67,34 @@
<a href="#" id="onboarding-longpress-button" class="onboarding-button">Done</a> <a href="#" id="onboarding-longpress-button" class="onboarding-button">Done</a>
</div> </div>
<div class="panel achievement-panel hide" id="achievement-panel">
<img class="onboarding-img" alt="You achieved a Containers milestone!" src="/img/onboarding-3.png" />
<h3 class="onboarding-title">100 tabs!</h3>
<p>You've opened 100 Container tabs.</p>
<p>If you enjoy Containers, help us spread the word!</p>
<p class="share-ctas">
<a class="cta-link" href="https://mzl.la/2gJtIZ4" id="achievement-rate-button" target="_blank">
<span class="cta amo-rate-cta">
<img src="/img/amo-icon.svg" class="cta-icon" alt="addons.mozilla.org Icon">
Rate
</span>
</a>
<a class="cta-link" href="https://bit.ly/fb-share-mac-addon" target="_blank">
<span class="cta fb-share-cta">
<img src="/img/webicon-facebook.svg" class="cta-icon" alt="Facebook Icon">
Share
</span>
</a>
<a class="cta-link" href="http://bit.ly/tweet-100-tabs-mac-addon" target="_blank">
<span class="cta tweet-cta">
<img src="/img/webicon-twitter.svg" class="cta-icon" alt="Twitter Icon">
Tweet
</span>
</a>
</p>
<a href="#" id="achievement-done-button" class="onboarding-button">Done</a>
</div>
<div class="panel container-panel hide" id="container-panel"> <div class="panel container-panel hide" id="container-panel">
<div id="current-tab"> <div id="current-tab">
<h3>Current Tab</h3> <h3>Current Tab</h3>