зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1657476 support multiple recommendation badges r=fluent-reviewers,rpl,flod
Differential Revision: https://phabricator.services.mozilla.com/D86124
This commit is contained in:
Родитель
f339ca9f42
Коммит
fb21940df8
|
@ -457,11 +457,20 @@ addon-detail-private-browsing-help = When allowed, the extension will have acces
|
|||
addon-detail-private-browsing-allow = Allow
|
||||
addon-detail-private-browsing-disallow = Don’t Allow
|
||||
|
||||
# This is the tooltip text for the recommended badge for an extension in about:addons. The
|
||||
# badge is a small icon displayed next to an extension when it is recommended on AMO.
|
||||
## This is the tooltip text for the recommended badges for an extension in about:addons. The
|
||||
## badge is a small icon displayed next to an extension when it is recommended on AMO.
|
||||
|
||||
addon-badge-recommended2 =
|
||||
.title = { -brand-product-name } only recommends extensions that meet our standards for security and performance
|
||||
.aria-label = { addon-badge-recommended2.title }
|
||||
addon-badge-line =
|
||||
.title = This extension was created by the makers of { -brand-product-name }
|
||||
.aria-label = { addon-badge-line.title }
|
||||
addon-badge-verified =
|
||||
.title = This extension has been code-reviewed for safety
|
||||
.aria-label = { addon-badge-verified.title }
|
||||
|
||||
##
|
||||
|
||||
available-updates-heading = Available Updates
|
||||
recent-updates-heading = Recent Updates
|
||||
|
|
|
@ -315,12 +315,14 @@ addon-card[expanded] .update-postponed-bar + .addon-card-message {
|
|||
.addon-badge {
|
||||
display: inline-block;
|
||||
margin-inline-end: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-size: 16px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
flex-shrink: 0;
|
||||
border-radius: 11px;
|
||||
-moz-context-properties: fill;
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.addon-badge-private-browsing-allowed {
|
||||
|
@ -330,10 +332,21 @@ addon-card[expanded] .update-postponed-bar + .addon-card-message {
|
|||
.addon-badge-recommended {
|
||||
background-color: var(--orange-50);
|
||||
background-image: url("chrome://mozapps/skin/extensions/recommended.svg");
|
||||
background-size: 10px;
|
||||
border-radius: 8px;
|
||||
fill: #fff;
|
||||
-moz-context-properties: fill;
|
||||
}
|
||||
|
||||
.addon-badge-line {
|
||||
background-color: #fff;
|
||||
background-image: url("chrome://mozapps/skin/extensions/line.svg");
|
||||
background-size: 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #CFCFD8;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.addon-badge-verified {
|
||||
background-color: var(--green-70);
|
||||
background-image: url("chrome://mozapps/skin/extensions/check.svg");
|
||||
}
|
||||
|
||||
.theme-enable-button {
|
||||
|
|
|
@ -133,6 +133,18 @@
|
|||
data-l10n-id="addon-badge-recommended2"
|
||||
hidden>
|
||||
</a>
|
||||
<a class="addon-badge addon-badge-line"
|
||||
is="support-link"
|
||||
support-page="recommended-extensions-program"
|
||||
data-l10n-id="addon-badge-line"
|
||||
hidden>
|
||||
</a>
|
||||
<a class="addon-badge addon-badge-verified"
|
||||
is="support-link"
|
||||
support-page="recommended-extensions-program"
|
||||
data-l10n-id="addon-badge-verified"
|
||||
hidden>
|
||||
</a>
|
||||
<a class="addon-badge addon-badge-private-browsing-allowed"
|
||||
is="support-link"
|
||||
support-page="extensions-pb"
|
||||
|
|
|
@ -3158,6 +3158,11 @@ class AddonCard extends HTMLElement {
|
|||
// Hide the more options button if it's empty.
|
||||
moreOptionsButton.hidden = this.options.visibleItems.length === 0;
|
||||
|
||||
// Ensure all badges are initially hidden.
|
||||
for (let node of card.querySelectorAll(".addon-badge")) {
|
||||
node.hidden = true;
|
||||
}
|
||||
|
||||
// Set the private browsing badge visibility.
|
||||
if (
|
||||
!allowPrivateBrowsingByDefault &&
|
||||
|
@ -3172,10 +3177,15 @@ class AddonCard extends HTMLElement {
|
|||
});
|
||||
}
|
||||
|
||||
// Show the recommended badge if needed.
|
||||
card.querySelector(
|
||||
".addon-badge-recommended"
|
||||
).hidden = !addon.isRecommended;
|
||||
// Show the recommended badges if needed.
|
||||
// Plugins don't have recommendationStates, so ensure a default.
|
||||
let states = addon.recommendationStates || [];
|
||||
for (let badgeName of states) {
|
||||
let badge = card.querySelector(`.addon-badge-${badgeName}`);
|
||||
if (badge) {
|
||||
badge.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update description.
|
||||
card.querySelector(".addon-description").textContent = addon.description;
|
||||
|
|
|
@ -936,7 +936,7 @@ AddonWrapper = class {
|
|||
return null;
|
||||
}
|
||||
|
||||
get isRecommended() {
|
||||
get recommendationStates() {
|
||||
let addon = addonFor(this);
|
||||
let state = addon.recommendationState;
|
||||
if (
|
||||
|
@ -946,9 +946,13 @@ AddonWrapper = class {
|
|||
addon.isCorrectlySigned &&
|
||||
!this.temporarilyInstalled
|
||||
) {
|
||||
return state.states.includes("recommended");
|
||||
return state.states;
|
||||
}
|
||||
return false;
|
||||
return [];
|
||||
}
|
||||
|
||||
get isRecommended() {
|
||||
return this.recommendationStates.includes("recommended");
|
||||
}
|
||||
|
||||
get applyBackgroundUpdates() {
|
||||
|
|
|
@ -868,8 +868,8 @@ add_task(async function testPrivateBrowsingExtension() {
|
|||
await updated;
|
||||
|
||||
// It's still allowed in PB.
|
||||
ok(!badge.hidden, "The PB badge is shown");
|
||||
ok(await hasPrivateAllowed(id), "PB is allowed");
|
||||
ok(!badge.hidden, "The PB badge is shown");
|
||||
|
||||
// Disallow PB.
|
||||
updated = BrowserTestUtils.waitForEvent(card, "update");
|
||||
|
|
|
@ -8,17 +8,33 @@ const SUPPORT_URL = Services.urlFormatter.formatURL(
|
|||
Services.prefs.getStringPref("app.support.baseURL")
|
||||
);
|
||||
const SUMO_URL = SUPPORT_URL + "recommended-extensions-program";
|
||||
const SUPPORTED_BADGES = ["recommended", "line", "verified"];
|
||||
|
||||
async function checkRecommendedBadge(id, hidden) {
|
||||
async function checkRecommendedBadge(id, badges = []) {
|
||||
async function checkBadge() {
|
||||
let card = win.document.querySelector(`addon-card[addon-id="${id}"]`);
|
||||
let badge = card.querySelector(".addon-badge-recommended");
|
||||
is(badge.hidden, hidden, `badge is ${hidden ? "hidden" : "shown"}`);
|
||||
if (!hidden) {
|
||||
info("Verify the badge links to the support page");
|
||||
let tabLoaded = BrowserTestUtils.waitForNewTab(gBrowser, SUMO_URL);
|
||||
EventUtils.synthesizeMouseAtCenter(badge, {}, win);
|
||||
BrowserTestUtils.removeTab(await tabLoaded);
|
||||
for (let badgeName of SUPPORTED_BADGES) {
|
||||
let badge = card.querySelector(`.addon-badge-${badgeName}`);
|
||||
let hidden = !badges.includes(badgeName);
|
||||
is(
|
||||
badge.hidden,
|
||||
hidden,
|
||||
`badge ${badgeName} is ${hidden ? "hidden" : "shown"}`
|
||||
);
|
||||
if (!hidden) {
|
||||
info(`Verify the ${badgeName} badge links to the support page`);
|
||||
let tabLoaded = BrowserTestUtils.waitForNewTab(gBrowser, SUMO_URL);
|
||||
EventUtils.synthesizeMouseAtCenter(badge, {}, win);
|
||||
BrowserTestUtils.removeTab(await tabLoaded);
|
||||
}
|
||||
}
|
||||
for (let badgeName of badges) {
|
||||
if (!SUPPORTED_BADGES.includes(badgeName)) {
|
||||
ok(
|
||||
!card.querySelector(`.addon-badge-${badgeName}`),
|
||||
`no badge element for ${badgeName}`
|
||||
);
|
||||
}
|
||||
}
|
||||
return card;
|
||||
}
|
||||
|
@ -47,22 +63,65 @@ add_task(async function testNotRecommended() {
|
|||
});
|
||||
await extension.startup();
|
||||
|
||||
await checkRecommendedBadge(id, true);
|
||||
await checkRecommendedBadge(id);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function testRecommended() {
|
||||
let id = "recommended@mochi.test";
|
||||
async function test_badged_addon(addon) {
|
||||
let provider = new MockProvider();
|
||||
provider.createAddons([
|
||||
{
|
||||
id,
|
||||
isRecommended: true,
|
||||
name: "Recommended",
|
||||
type: "extension",
|
||||
},
|
||||
]);
|
||||
provider.createAddons([addon]);
|
||||
await checkRecommendedBadge(addon.id, addon.recommendationStates);
|
||||
|
||||
await checkRecommendedBadge(id, false);
|
||||
provider.unregister();
|
||||
}
|
||||
|
||||
add_task(async function testRecommended() {
|
||||
await test_badged_addon({
|
||||
id: "recommended@mochi.test",
|
||||
isRecommended: true,
|
||||
recommendationStates: ["recommended"],
|
||||
name: "Recommended",
|
||||
type: "extension",
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function testLine() {
|
||||
await test_badged_addon({
|
||||
id: "line@mochi.test",
|
||||
isRecommended: false,
|
||||
recommendationStates: ["line"],
|
||||
name: "Line",
|
||||
type: "extension",
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function testVerified() {
|
||||
await test_badged_addon({
|
||||
id: "verified@mochi.test",
|
||||
isRecommended: false,
|
||||
recommendationStates: ["verified"],
|
||||
name: "Verified",
|
||||
type: "extension",
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function testOther() {
|
||||
await test_badged_addon({
|
||||
id: "other@mochi.test",
|
||||
isRecommended: false,
|
||||
recommendationStates: ["other"],
|
||||
name: "No Badge",
|
||||
type: "extension",
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function testMultiple() {
|
||||
await test_badged_addon({
|
||||
id: "multiple@mochi.test",
|
||||
isRecommended: false,
|
||||
recommendationStates: ["verified", "recommended", "other"],
|
||||
name: "Multiple",
|
||||
type: "extension",
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,6 +34,19 @@ async function installAddonWithRecommendations(id, recommendation) {
|
|||
return install.addon;
|
||||
}
|
||||
|
||||
function checkRecommended(addon, recommended = true) {
|
||||
equal(
|
||||
addon.isRecommended,
|
||||
recommended,
|
||||
"The add-on isRecommended state is correct"
|
||||
);
|
||||
equal(
|
||||
addon.recommendationStates.includes("recommended"),
|
||||
recommended,
|
||||
"The add-on recommendationStates is correct"
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await ExtensionTestUtils.startAddonManager();
|
||||
});
|
||||
|
@ -42,7 +55,7 @@ add_task(async function text_no_file() {
|
|||
const id = "no-recommendations-file@test.web.extension";
|
||||
let addon = await installAddonWithRecommendations(id, null);
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -51,7 +64,7 @@ add_task(async function text_malformed_file() {
|
|||
const id = "no-recommendations-file@test.web.extension";
|
||||
let addon = await installAddonWithRecommendations(id, "This is not JSON");
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -64,7 +77,24 @@ add_task(async function test_valid_recommendation_file() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(addon.isRecommended, "The add-on is recommended");
|
||||
checkRecommended(addon);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
||||
add_task(async function test_multiple_valid_recommendation_file() {
|
||||
const id = "recommended@test.web.extension";
|
||||
let addon = await installAddonWithRecommendations(id, {
|
||||
addon_id: id,
|
||||
states: ["recommended", "something"],
|
||||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
checkRecommended(addon);
|
||||
ok(
|
||||
addon.recommendationStates.includes("something"),
|
||||
"The add-on recommendationStates contains something"
|
||||
);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -82,7 +112,7 @@ add_task(async function test_unsigned() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
AddonTestUtils.useRealCertChecks = false;
|
||||
|
@ -98,7 +128,7 @@ add_task(async function test_temporary() {
|
|||
});
|
||||
let addon = await XPIInstall.installTemporaryAddon(xpi);
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -127,7 +157,7 @@ add_task(async function test_temporary_directory() {
|
|||
|
||||
let addon = await XPIInstall.installTemporaryAddon(extDir);
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
extDir.remove(true);
|
||||
|
@ -150,7 +180,7 @@ add_task(async function test_builtin() {
|
|||
});
|
||||
await extension.awaitMessage("started");
|
||||
|
||||
ok(!extension.addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(extension.addon, false);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
@ -172,7 +202,7 @@ add_task(async function test_theme() {
|
|||
});
|
||||
let { addon } = await AddonTestUtils.promiseInstallFile(xpi);
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -185,7 +215,11 @@ add_task(async function test_not_recommended() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
ok(
|
||||
addon.recommendationStates.includes("something"),
|
||||
"The add-on recommendationStates contains something"
|
||||
);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -197,7 +231,7 @@ add_task(async function test_id_missing() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -206,11 +240,15 @@ add_task(async function test_expired() {
|
|||
const id = "expired@test.web.extension";
|
||||
let addon = await installAddonWithRecommendations(id, {
|
||||
addon_id: id,
|
||||
states: ["recommended"],
|
||||
states: ["recommended", "something"],
|
||||
validity: { not_before, not_after: not_before },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
ok(
|
||||
!addon.recommendationStates.length,
|
||||
"The add-on recommendationStates does not contain anything"
|
||||
);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -223,7 +261,7 @@ add_task(async function test_not_valid_yet() {
|
|||
validity: { not_before: not_after, not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -235,7 +273,7 @@ add_task(async function test_states_missing() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -247,7 +285,7 @@ add_task(async function test_validity_missing() {
|
|||
states: ["recommended"],
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -260,7 +298,7 @@ add_task(async function test_not_before_missing() {
|
|||
validity: { not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -273,7 +311,7 @@ add_task(async function test_bad_states() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(!addon.isRecommended, "The add-on is not recommended");
|
||||
checkRecommended(addon, false);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
@ -286,13 +324,13 @@ add_task(async function test_recommendation_persist_restart() {
|
|||
validity: { not_before, not_after },
|
||||
});
|
||||
|
||||
ok(addon.isRecommended, "The add-on is recommended");
|
||||
checkRecommended(addon);
|
||||
|
||||
await AddonTestUtils.promiseRestartManager();
|
||||
|
||||
addon = await AddonManager.getAddonByID(id);
|
||||
|
||||
ok(addon.isRecommended, "The add-on is still recommended");
|
||||
checkRecommended(addon);
|
||||
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="context-fill" fill-opacity="context-fill-opacity" stroke="context-stroke none" stroke-width="0.5" d="M6 14a1 1 0 0 1-.707-.293l-3-3a1 1 0 0 1 1.414-1.414l2.157 2.157 6.316-9.023a1 1 0 0 1 1.639 1.146l-7 10a1 1 0 0 1-.732.427A.863.863 0 0 1 6 14z"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 566 B |
|
@ -0,0 +1,99 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
||||
<defs>
|
||||
<radialGradient id="a" cx="14.305" cy="3.031" r="18.199" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff36e"/>
|
||||
<stop offset=".5" stop-color="#fc4055"/>
|
||||
<stop offset="1" stop-color="#e31587"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="b" cx="1.315" cy="3.784" r="10.76" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".001" stop-color="#c60084"/>
|
||||
<stop offset="1" stop-color="#fc4055" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="c" cx="15.858" cy="1.995" r="21.371" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ffde67" stop-opacity=".6"/>
|
||||
<stop offset=".093" stop-color="#ffd966" stop-opacity=".581"/>
|
||||
<stop offset=".203" stop-color="#ffca65" stop-opacity=".525"/>
|
||||
<stop offset=".321" stop-color="#feb262" stop-opacity=".432"/>
|
||||
<stop offset=".446" stop-color="#fe8f5e" stop-opacity=".302"/>
|
||||
<stop offset=".573" stop-color="#fd6459" stop-opacity=".137"/>
|
||||
<stop offset=".664" stop-color="#fc4055" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="d" cx="8.451" cy="8.902" r="27.546" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".153" stop-color="#810220"/>
|
||||
<stop offset=".167" stop-color="#920b27" stop-opacity=".861"/>
|
||||
<stop offset=".216" stop-color="#cb2740" stop-opacity=".398"/>
|
||||
<stop offset=".253" stop-color="#ef394f" stop-opacity=".11"/>
|
||||
<stop offset=".272" stop-color="#fc4055" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="e" cx="6.368" cy="8.555" r="27.542" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".113" stop-color="#810220"/>
|
||||
<stop offset=".133" stop-color="#920b27" stop-opacity=".861"/>
|
||||
<stop offset=".204" stop-color="#cb2740" stop-opacity=".398"/>
|
||||
<stop offset=".257" stop-color="#ef394f" stop-opacity=".11"/>
|
||||
<stop offset=".284" stop-color="#fc4055" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="f" cx="13.937" cy="2.416" r="17.079" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ff9640"/>
|
||||
<stop offset=".8" stop-color="#fc4055"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="g" cx="13.937" cy="2.416" r="17.079" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".084" stop-color="#ffde67"/>
|
||||
<stop offset=".147" stop-color="#ffdc66" stop-opacity=".968"/>
|
||||
<stop offset=".246" stop-color="#ffd562" stop-opacity=".879"/>
|
||||
<stop offset=".369" stop-color="#ffcb5d" stop-opacity=".734"/>
|
||||
<stop offset=".511" stop-color="#ffbc55" stop-opacity=".533"/>
|
||||
<stop offset=".667" stop-color="#ffaa4b" stop-opacity=".28"/>
|
||||
<stop offset=".822" stop-color="#ff9640" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="h" cx="10.011" cy="7.729" r="8.36" gradientTransform="matrix(.247 .969 -1.011 .258 15.352 -3.965)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".363" stop-color="#fc4055"/>
|
||||
<stop offset=".443" stop-color="#fd604d" stop-opacity=".633"/>
|
||||
<stop offset=".545" stop-color="#fe8644" stop-opacity=".181"/>
|
||||
<stop offset=".59" stop-color="#ff9640" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="i" cx="8.575" cy="8.439" r="8.353" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".216" stop-color="#fc4055" stop-opacity=".8"/>
|
||||
<stop offset=".267" stop-color="#fd5251" stop-opacity=".633"/>
|
||||
<stop offset=".41" stop-color="#fe8345" stop-opacity=".181"/>
|
||||
<stop offset=".474" stop-color="#ff9640" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="j" cx="17.326" cy=".487" r="28.887" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".054" stop-color="#fff36e"/>
|
||||
<stop offset=".457" stop-color="#ff9640"/>
|
||||
<stop offset=".639" stop-color="#ff9640"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="k" x1="8.117" y1="-.134" x2="12.46" y2="12.441" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#b833e1"/>
|
||||
<stop offset=".371" stop-color="#9059ff"/>
|
||||
<stop offset=".614" stop-color="#5b6df8"/>
|
||||
<stop offset="1" stop-color="#0090ed"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="l" x1="5.542" y1=".065" x2="13.614" y2="8.137" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".805" stop-color="#722291" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#592acb" stop-opacity=".5"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="m" x1="11.836" y1="1.378" x2="3.632" y2="15.587" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff36e" stop-opacity=".8"/>
|
||||
<stop offset=".094" stop-color="#fff36e" stop-opacity=".699"/>
|
||||
<stop offset=".752" stop-color="#fff36e" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g style="isolation:isolate">
|
||||
<path d="M14.389 3.14A7.894 7.894 0 0 0 8.318 0a7 7 0 0 0-3.867.97A7.472 7.472 0 0 1 8.059.1a7.1 7.1 0 0 1 7.071 6.087 7 7 0 0 1-6.9 8.2 7.151 7.151 0 0 1-3.949-1.127C1.268 11.3 1.258 7.441 1.26 6.825a8.626 8.626 0 0 1 1.189-4.266A6.656 6.656 0 0 0 .576 4.984a7.734 7.734 0 0 0-.519 4.035c.012.1.023.207.036.31a8.013 8.013 0 1 0 14.3-6.189z" fill="url(#a)"/>
|
||||
<path d="M14.389 3.14A7.894 7.894 0 0 0 8.318 0a7 7 0 0 0-3.867.97A7.472 7.472 0 0 1 8.059.1a7.1 7.1 0 0 1 7.071 6.087 7 7 0 0 1-6.9 8.2 7.151 7.151 0 0 1-3.949-1.127C1.268 11.3 1.258 7.441 1.26 6.825a8.626 8.626 0 0 1 1.189-4.266A6.656 6.656 0 0 0 .576 4.984a7.734 7.734 0 0 0-.519 4.035c.012.1.023.207.036.31a8.013 8.013 0 1 0 14.3-6.189z" fill="url(#b)" opacity=".67"/>
|
||||
<path d="M14.389 3.14A7.894 7.894 0 0 0 8.318 0a7 7 0 0 0-3.867.97A7.472 7.472 0 0 1 8.059.1a7.1 7.1 0 0 1 7.071 6.087 7 7 0 0 1-6.9 8.2 7.151 7.151 0 0 1-3.949-1.127C1.268 11.3 1.258 7.441 1.26 6.825a8.626 8.626 0 0 1 1.189-4.266A6.656 6.656 0 0 0 .576 4.984a7.734 7.734 0 0 0-.519 4.035c.012.1.023.207.036.31a8.013 8.013 0 1 0 14.3-6.189z" fill="url(#c)"/>
|
||||
<path d="M14.389 3.14A7.894 7.894 0 0 0 8.318 0a7 7 0 0 0-3.867.97A7.472 7.472 0 0 1 8.059.1a7.1 7.1 0 0 1 7.071 6.087 7 7 0 0 1-6.9 8.2 7.151 7.151 0 0 1-3.949-1.127C1.268 11.3 1.258 7.441 1.26 6.825a8.626 8.626 0 0 1 1.189-4.266A6.656 6.656 0 0 0 .576 4.984a7.734 7.734 0 0 0-.519 4.035c.012.1.023.207.036.31a8.013 8.013 0 1 0 14.3-6.189z" fill="url(#d)"/>
|
||||
<path d="M14.389 3.14A7.894 7.894 0 0 0 8.318 0a7 7 0 0 0-3.867.97A7.472 7.472 0 0 1 8.059.1a7.1 7.1 0 0 1 7.071 6.087 7 7 0 0 1-6.9 8.2 7.151 7.151 0 0 1-3.949-1.127C1.268 11.3 1.258 7.441 1.26 6.825a8.626 8.626 0 0 1 1.189-4.266A6.656 6.656 0 0 0 .576 4.984a7.734 7.734 0 0 0-.519 4.035c.012.1.023.207.036.31a8.013 8.013 0 1 0 14.3-6.189z" fill="url(#e)"/>
|
||||
<path d="M15.325 5.965C14.875 1.9 11.253.078 8.059.1a7.765 7.765 0 0 0-3.608.872 3.913 3.913 0 0 0-.712.54c.026-.021.1-.085.23-.172l.013-.009.011-.007A5.337 5.337 0 0 1 5.531.609 8.713 8.713 0 0 1 8.168.3a6.65 6.65 0 0 1 6.25 6.4 4.818 4.818 0 0 1-4.58 4.869 4.731 4.731 0 0 1-2.967-.72A5.425 5.425 0 0 1 5.06 8.242a4.552 4.552 0 0 1 .285-3.149A4.726 4.726 0 0 1 8.464 2.7a4.3 4.3 0 0 0-1.782-.585A5.4 5.4 0 0 0 1.7 5.177a6.035 6.035 0 0 0-.2 4.638 6.683 6.683 0 0 0 2.4 3.234A7.177 7.177 0 0 0 7.326 14.4s.153.018.309.029a8.085 8.085 0 0 0 5.439-1.6c2.811-2.377 2.315-6.285 2.251-6.864z" fill="url(#f)"/>
|
||||
<path d="M15.325 5.965C14.875 1.9 11.253.078 8.059.1a7.765 7.765 0 0 0-3.608.872 3.913 3.913 0 0 0-.712.54c.026-.021.1-.085.23-.172l.013-.009.011-.007A5.337 5.337 0 0 1 5.531.609 8.713 8.713 0 0 1 8.168.3a6.65 6.65 0 0 1 6.25 6.4 4.818 4.818 0 0 1-4.58 4.869 4.731 4.731 0 0 1-2.967-.72A5.425 5.425 0 0 1 5.06 8.242a4.552 4.552 0 0 1 .285-3.149A4.726 4.726 0 0 1 8.464 2.7a4.3 4.3 0 0 0-1.782-.585A5.4 5.4 0 0 0 1.7 5.177a6.035 6.035 0 0 0-.2 4.638 6.683 6.683 0 0 0 2.4 3.234A7.177 7.177 0 0 0 7.326 14.4s.153.018.309.029a8.085 8.085 0 0 0 5.439-1.6c2.811-2.377 2.315-6.285 2.251-6.864z" fill="url(#g)"/>
|
||||
<path d="M15.325 5.965C14.875 1.9 11.253.078 8.059.1a7.765 7.765 0 0 0-3.608.872 3.913 3.913 0 0 0-.712.54c.026-.021.1-.085.23-.172l.013-.009.011-.007A5.337 5.337 0 0 1 5.531.609 8.713 8.713 0 0 1 8.168.3a6.65 6.65 0 0 1 6.25 6.4 4.818 4.818 0 0 1-4.58 4.869 4.731 4.731 0 0 1-2.967-.72A5.425 5.425 0 0 1 5.06 8.242a4.552 4.552 0 0 1 .285-3.149A4.726 4.726 0 0 1 8.464 2.7a4.3 4.3 0 0 0-1.782-.585A5.4 5.4 0 0 0 1.7 5.177a6.035 6.035 0 0 0-.2 4.638 6.683 6.683 0 0 0 2.4 3.234A7.177 7.177 0 0 0 7.326 14.4s.153.018.309.029a8.085 8.085 0 0 0 5.439-1.6c2.811-2.377 2.315-6.285 2.251-6.864z" style="mix-blend-mode:multiply" opacity=".53" fill="url(#h)"/>
|
||||
<path d="M15.325 5.965C14.875 1.9 11.253.078 8.059.1a7.765 7.765 0 0 0-3.608.872 3.913 3.913 0 0 0-.712.54c.026-.021.1-.085.23-.172l.013-.009.011-.007A5.337 5.337 0 0 1 5.531.609 8.713 8.713 0 0 1 8.168.3a6.65 6.65 0 0 1 6.25 6.4 4.818 4.818 0 0 1-4.58 4.869 4.731 4.731 0 0 1-2.967-.72A5.425 5.425 0 0 1 5.06 8.242a4.552 4.552 0 0 1 .285-3.149A4.726 4.726 0 0 1 8.464 2.7a4.3 4.3 0 0 0-1.782-.585A5.4 5.4 0 0 0 1.7 5.177a6.035 6.035 0 0 0-.2 4.638 6.683 6.683 0 0 0 2.4 3.234A7.177 7.177 0 0 0 7.326 14.4s.153.018.309.029a8.085 8.085 0 0 0 5.439-1.6c2.811-2.377 2.315-6.285 2.251-6.864z" style="mix-blend-mode:multiply" opacity=".53" fill="url(#i)"/>
|
||||
<path d="M9.24 11.568a5.148 5.148 0 0 0 3.183-.815 5.67 5.67 0 0 0 2.39-4.234C14.957 3.381 13.094 0 8.168.3a8.713 8.713 0 0 0-2.637.309 5.745 5.745 0 0 0-1.538.715l-.011.007-.013.009c-.076.054-.151.11-.224.168a6.7 6.7 0 0 1 4.2-.787c2.827.371 5.413 2.571 5.413 5.475a4.076 4.076 0 0 1-3.747 3.817A2.849 2.849 0 0 1 6.9 8.156a2.75 2.75 0 0 1 .919-2.729 2.875 2.875 0 0 0-1.81.919A3.07 3.07 0 0 0 5.735 9.6c.84 1.746 3.031 1.929 3.505 1.968z" fill="url(#j)"/>
|
||||
<path d="M14.4 3.745a4.5 4.5 0 0 0-.976-1.629 6.056 6.056 0 0 0-1.819-1.3A8.086 8.086 0 0 0 9.82.184 7.96 7.96 0 0 0 6.507.165a5.727 5.727 0 0 0-2.768 1.346 6.415 6.415 0 0 1 1.606-.64 6.712 6.712 0 0 1 6.234 1.619 5.417 5.417 0 0 1 .866 1.061 4.693 4.693 0 0 1 .123 4.773 3.8 3.8 0 0 1-2.914 1.691A4.726 4.726 0 0 0 14 7.839a4.88 4.88 0 0 0 .4-4.094z" fill="url(#k)"/>
|
||||
<path d="M14.4 3.745a4.5 4.5 0 0 0-.976-1.629 6.056 6.056 0 0 0-1.819-1.3A8.086 8.086 0 0 0 9.82.184 7.96 7.96 0 0 0 6.507.165a5.727 5.727 0 0 0-2.768 1.346 6.415 6.415 0 0 1 1.606-.64 6.712 6.712 0 0 1 6.234 1.619 5.417 5.417 0 0 1 .866 1.061 4.693 4.693 0 0 1 .123 4.773 3.8 3.8 0 0 1-2.914 1.691A4.726 4.726 0 0 0 14 7.839a4.88 4.88 0 0 0 .4-4.094z" fill="url(#l)"/>
|
||||
<path d="M8.318 0h-.073c.134 0 .269.013.4.022C8.538.021 8.429 0 8.318 0zM3.747 1.5a3.951 3.951 0 0 1 .453-.359 3.547 3.547 0 0 0-.453.364zm1.7-.653c-.032.008-.066.01-.1.019-.07.022-.147.046-.223.068.101-.029.209-.056.319-.082zm-1.7.658zm0 0zM14.389 3.14a8.12 8.12 0 0 0-.675-.77 6.368 6.368 0 0 0-.747-.677c-.072-.063-.156-.116-.233-.176a5.136 5.136 0 0 1 .693.6 4.5 4.5 0 0 1 .973 1.628 4.88 4.88 0 0 1-.4 4.094 4.723 4.723 0 0 1-4.342 2.175 2.609 2.609 0 0 0 .578-.07 2.81 2.81 0 0 1-.625.069A2.849 2.849 0 0 1 6.9 8.156a2.749 2.749 0 0 1 .919-2.729 2.875 2.875 0 0 0-1.81.919A3.07 3.07 0 0 0 5.735 9.6c.03.062.073.109.107.167a4.744 4.744 0 0 1-.782-1.525 4.552 4.552 0 0 1 .285-3.149A4.726 4.726 0 0 1 8.464 2.7a4.3 4.3 0 0 0-1.782-.585A5.4 5.4 0 0 0 1.7 5.177a5.133 5.133 0 0 0-.414 1.17 8.715 8.715 0 0 1 1.163-3.788A6.656 6.656 0 0 0 .576 4.984a7.734 7.734 0 0 0-.519 4.035c.012.1.023.207.036.31a8.013 8.013 0 1 0 14.3-6.189zM4.541.923c-.026.016-.065.033-.09.049.011-.007.025-.011.036-.018s.037-.02.054-.031zm-.09.049c-.017.01-.028.019-.044.029.025-.016.053-.03.079-.046a.378.378 0 0 0-.035.017z" fill="url(#m)"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 12 KiB |
|
@ -15,6 +15,8 @@
|
|||
skin/classic/mozapps/extensions/category-available.svg (../../shared/extensions/category-available.svg)
|
||||
skin/classic/mozapps/extensions/extension.svg (../../shared/extensions/extension.svg)
|
||||
skin/classic/mozapps/extensions/recommended.svg (../../shared/extensions/recommended.svg)
|
||||
skin/classic/mozapps/extensions/line.svg (../../shared/extensions/line.svg)
|
||||
skin/classic/mozapps/extensions/check.svg (../../shared/extensions/check.svg)
|
||||
#ifndef ANDROID
|
||||
skin/classic/mozapps/extensions/rating-star.svg (../../shared/extensions/rating-star.svg)
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче