зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1511636 toggle private browsing via about:addons r=rpl,mstriemer,flod,kmag
Differential Revision: https://phabricator.services.mozilla.com/D13621 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
050ca2e7d4
Коммит
db03082008
|
@ -39,6 +39,7 @@
|
|||
to the add-on name for extensions that are not webextensions, which
|
||||
will stop working in Firefox 57. -->
|
||||
<!ENTITY addon.legacy.label "LEGACY">
|
||||
<!ENTITY addon.privateBrowsing.label "ALLOWED IN PRIVATE WINDOWS">
|
||||
<!-- LOCALIZATION NOTE (addon.disabled.postfix): This is used in a normal list
|
||||
to signify that an add-on is disabled, in the form
|
||||
"<Addon name> <1.0> (disabled)" -->
|
||||
|
|
|
@ -126,6 +126,20 @@ detail-update-manual =
|
|||
.label = Off
|
||||
.tooltiptext = Don’t automatically install updates
|
||||
|
||||
# Used as a description for the option to allow or block an add-on in private windows.
|
||||
detail-private-browsing =
|
||||
.value = Run in Private Windows
|
||||
|
||||
detail-private-browsing-description = Extension will work in Private Windows, and have access to your online activities. <label data-l10n-name="detail-private-browsing-learn-more">Learn more</label>
|
||||
|
||||
detail-private-browsing-on =
|
||||
.label = Allow
|
||||
.tooltiptext = Enable in Private Browsing
|
||||
|
||||
detail-private-browsing-off =
|
||||
.label = Don’t Allow
|
||||
.tooltiptext = Disable in Private Browsing
|
||||
|
||||
detail-home =
|
||||
.label = Homepage
|
||||
|
||||
|
|
|
@ -107,6 +107,21 @@ row[unsupported="true"] {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.addon .privateBrowsing-notice {
|
||||
display: none;
|
||||
}
|
||||
.addon[privateBrowsing="true"] .privateBrowsing-notice-container {
|
||||
/* 40px is width and margin of .icon-container */
|
||||
margin-inline-start: 40px;
|
||||
}
|
||||
.addon[privateBrowsing="true"] .privateBrowsing-notice {
|
||||
margin: 4px 0 0;
|
||||
display: inline-block;
|
||||
}
|
||||
.addon[active="false"] .privateBrowsing-notice {
|
||||
background-color: var(--purple-70-a40);
|
||||
}
|
||||
|
||||
#addons-page:not([warning]) #list-view > .global-warning-container {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ ChromeUtils.defineModuleGetter(this, "Extension",
|
|||
"resource://gre/modules/Extension.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ExtensionParent",
|
||||
"resource://gre/modules/ExtensionParent.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ExtensionPermissions",
|
||||
"resource://gre/modules/ExtensionPermissions.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Preferences",
|
||||
|
@ -34,6 +36,9 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "WEBEXT_PERMISSION_PROMPTS",
|
|||
XPCOMUtils.defineLazyPreferenceGetter(this, "XPINSTALL_ENABLED",
|
||||
"xpinstall.enabled", true);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "allowPrivateBrowsingByDefault",
|
||||
"extensions.allowPrivateBrowsingByDefault", true);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "SUPPORT_URL", "app.support.baseURL",
|
||||
"", null, val => Services.urlFormatter.formatURL(val));
|
||||
|
||||
|
@ -2634,13 +2639,13 @@ var gListView = {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
var gDetailView = {
|
||||
node: null,
|
||||
_addon: null,
|
||||
_loadingTimer: null,
|
||||
_autoUpdate: null,
|
||||
isRoot: false,
|
||||
restartingAddon: false,
|
||||
|
||||
initialize() {
|
||||
this.node = document.getElementById("detail-view");
|
||||
|
@ -2651,6 +2656,36 @@ var gDetailView = {
|
|||
this._autoUpdate.addEventListener("command", () => {
|
||||
this._addon.applyBackgroundUpdates = this._autoUpdate.value;
|
||||
}, true);
|
||||
|
||||
document.getElementById("detail-private-browsing-learnmore-link")
|
||||
.setAttribute("href", SUPPORT_URL + "extensions-pb");
|
||||
|
||||
this._privateBrowsing = document.getElementById("detail-privateBrowsing");
|
||||
this._privateBrowsing.addEventListener("command", async () => {
|
||||
let addon = this._addon;
|
||||
let policy = WebExtensionPolicy.getByID(addon.id);
|
||||
let extension = policy && policy.extension;
|
||||
|
||||
let perms = {permissions: ["internal:privateBrowsingAllowed"], origins: []};
|
||||
if (this._privateBrowsing.value == "1") {
|
||||
await ExtensionPermissions.add(addon.id, perms, extension);
|
||||
} else {
|
||||
await ExtensionPermissions.remove(addon.id, perms, extension);
|
||||
}
|
||||
|
||||
// Reload the extension if it is already enabled. This ensures any change
|
||||
// on the private browsing permission is properly handled.
|
||||
if (addon.isActive) {
|
||||
try {
|
||||
this.restartingAddon = true;
|
||||
await addon.reload();
|
||||
} finally {
|
||||
this.restartingAddon = false;
|
||||
this.updateState();
|
||||
this._updateView(addon, false);
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
shutdown() {
|
||||
|
@ -2661,7 +2696,12 @@ var gDetailView = {
|
|||
this.onPropertyChanged(["applyBackgroundUpdates"]);
|
||||
},
|
||||
|
||||
_updateView(aAddon, aIsRemote, aScrollToPreferences) {
|
||||
async _updateView(aAddon, aIsRemote, aScrollToPreferences) {
|
||||
// Skip updates to avoid flickering while restarting the addon.
|
||||
if (this.restartingAddon) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSearchLabel(aAddon.type);
|
||||
|
||||
// Set the preview image for themes, if available.
|
||||
|
@ -2791,6 +2831,25 @@ var gDetailView = {
|
|||
document.getElementById("detail-findUpdates-btn").hidden = false;
|
||||
}
|
||||
|
||||
// Only type = "extension" will ever get privateBrowsingAllowed, other types have
|
||||
// no code that would be affected by the setting. The permission is read directly
|
||||
// from ExtensionPermissions so we can get it whether or not the extension is
|
||||
// currently active.
|
||||
let privateBrowsingRow = document.getElementById("detail-privateBrowsing-row");
|
||||
let privateBrowsingFooterRow = document.getElementById("detail-privateBrowsing-row-footer");
|
||||
if (allowPrivateBrowsingByDefault || aAddon.type != "extension" ||
|
||||
aAddon.incognito == "not_allowed") {
|
||||
this._privateBrowsing.hidden = true;
|
||||
privateBrowsingRow.hidden = true;
|
||||
privateBrowsingFooterRow.hidden = true;
|
||||
} else {
|
||||
let perms = await ExtensionPermissions.get(aAddon.id);
|
||||
this._privateBrowsing.hidden = false;
|
||||
privateBrowsingRow.hidden = false;
|
||||
privateBrowsingFooterRow.hidden = false;
|
||||
this._privateBrowsing.value = perms.permissions.includes("internal:privateBrowsingAllowed") ? "1" : "0";
|
||||
}
|
||||
|
||||
document.getElementById("detail-prefs-btn").hidden = !aIsRemote &&
|
||||
!gViewController.commands.cmd_showItemPreferences.isEnabled(aAddon);
|
||||
|
||||
|
@ -2869,6 +2928,11 @@ var gDetailView = {
|
|||
},
|
||||
|
||||
updateState() {
|
||||
// Skip updates to avoid flickering while restarting the addon.
|
||||
if (this.restartingAddon) {
|
||||
return;
|
||||
}
|
||||
|
||||
gViewController.updateCommands();
|
||||
|
||||
var pending = this._addon.pendingOperations;
|
||||
|
|
|
@ -686,6 +686,9 @@
|
|||
</xul:hbox>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
<xul:hbox class="description-container privateBrowsing-notice-container">
|
||||
<xul:label anonid="privateBrowsing" class="description privateBrowsing-notice" value="&addon.privateBrowsing.label;"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
|
@ -902,6 +905,13 @@
|
|||
this.setAttribute("legacy", legacyWarning);
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "legacy").href = SUPPORT_URL + "webextensions";
|
||||
|
||||
if (!allowPrivateBrowsingByDefault) {
|
||||
ExtensionPermissions.get(this.mAddon.id).then((perms) => {
|
||||
let allowed = perms.permissions.includes("internal:privateBrowsingAllowed");
|
||||
this.setAttribute("privateBrowsing", allowed);
|
||||
});
|
||||
}
|
||||
|
||||
if (!("applyBackgroundUpdates" in this.mAddon) ||
|
||||
(this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE ||
|
||||
(this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT &&
|
||||
|
|
|
@ -536,6 +536,22 @@
|
|||
<column flex="2"/>
|
||||
</columns>
|
||||
<rows id="detail-rows">
|
||||
<row class="detail-row-complex" id="detail-privateBrowsing-row">
|
||||
<label class="detail-row-label" data-l10n-id="detail-private-browsing"/>
|
||||
<hbox align="center">
|
||||
<radiogroup id="detail-privateBrowsing" orient="horizontal">
|
||||
<radio data-l10n-id="detail-private-browsing-on"
|
||||
value="1"/>
|
||||
<radio data-l10n-id="detail-private-browsing-off"
|
||||
value="0"/>
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</row>
|
||||
<hbox class="detail-row-footer" id="detail-privateBrowsing-row-footer">
|
||||
<description class="indent preferences-description" data-l10n-id="detail-private-browsing-description">
|
||||
<label id="detail-private-browsing-learnmore-link" class="learnMore text-link" data-l10n-name="detail-private-browsing-learn-more"/>
|
||||
</description>
|
||||
</hbox>
|
||||
<row class="detail-row-complex" id="detail-updates-row">
|
||||
<label class="detail-row-label" data-l10n-id="detail-update-type"/>
|
||||
<hbox align="center">
|
||||
|
|
|
@ -108,7 +108,7 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "version", "type",
|
|||
"softDisabled", "foreignInstall",
|
||||
"strictCompatibility", "locales", "targetApplications",
|
||||
"targetPlatforms", "signedState",
|
||||
"seen", "dependencies",
|
||||
"seen", "dependencies", "incognito",
|
||||
"userPermissions", "icons", "iconURL",
|
||||
"blocklistState", "blocklistURL", "startupData",
|
||||
"previewImage", "hidden", "installTelemetryInfo"];
|
||||
|
@ -732,6 +732,10 @@ AddonWrapper = class {
|
|||
return addon.optionsBrowserStyle;
|
||||
}
|
||||
|
||||
get incognito() {
|
||||
return addonFor(this).incognito;
|
||||
}
|
||||
|
||||
async getBlocklistURL() {
|
||||
return addonFor(this).blocklistURL;
|
||||
}
|
||||
|
|
|
@ -434,6 +434,7 @@ async function loadManifestFromWebManifest(aUri, aPackage) {
|
|||
addon.dependencies = Object.freeze(Array.from(extension.dependencies));
|
||||
addon.startupData = extension.startupData;
|
||||
addon.hidden = manifest.hidden;
|
||||
addon.incognito = manifest.incognito;
|
||||
|
||||
if (addon.type === "theme" && await aPackage.hasResource("preview.png")) {
|
||||
addon.previewImage = "preview.png";
|
||||
|
|
|
@ -104,7 +104,7 @@ const XPI_PERMISSION = "install";
|
|||
|
||||
const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60;
|
||||
|
||||
const DB_SCHEMA = 28;
|
||||
const DB_SCHEMA = 29;
|
||||
|
||||
function encoded(strings, ...values) {
|
||||
let result = [];
|
||||
|
|
|
@ -107,6 +107,7 @@ skip-if = verify
|
|||
[browser_webapi_theme.js]
|
||||
[browser_webapi_uninstall.js]
|
||||
[browser_webext_icon.js]
|
||||
[browser_webext_incognito.js]
|
||||
[browser_webext_options.js]
|
||||
tags = webextensions
|
||||
skip-if = os == 'linux' || (os == 'mac' && debug) # bug 1483347
|
||||
|
|
|
@ -75,6 +75,18 @@ async function test() {
|
|||
contributionAmount: null,
|
||||
updateDate: gDate,
|
||||
permissions: 0,
|
||||
}, {
|
||||
id: "addon-theme@tests.mozilla.org",
|
||||
name: "Test add-on theme",
|
||||
version: "2.3",
|
||||
description: "Short description",
|
||||
creator: { name: "Mozilla", url: null },
|
||||
type: "theme",
|
||||
iconURL: "chrome://foo/skin/icon.png",
|
||||
contributionURL: "http://foo.com",
|
||||
contributionAmount: null,
|
||||
updateDate: gDate,
|
||||
permissions: 0,
|
||||
}, {
|
||||
id: "addon3@tests.mozilla.org",
|
||||
name: "Test add-on 3",
|
||||
|
@ -143,8 +155,9 @@ async function end_test() {
|
|||
}
|
||||
|
||||
// Opens and tests the details view for add-on 2
|
||||
add_test(function() {
|
||||
open_details("addon2@tests.mozilla.org", "extension", function() {
|
||||
add_test(async function() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
|
||||
open_details("addon2@tests.mozilla.org", "extension", async () => {
|
||||
is(get("detail-name").textContent, "Test add-on 2", "Name should be correct");
|
||||
is_element_visible(get("detail-version"), "Version should not be hidden");
|
||||
is(get("detail-version").value, "2.2", "Version should be correct");
|
||||
|
@ -163,6 +176,10 @@ add_test(function() {
|
|||
is_element_visible(get("detail-dateUpdated"), "Update date should not be hidden");
|
||||
is(get("detail-dateUpdated").value, formatDate(gDate), "Update date should be correct");
|
||||
|
||||
is_element_visible(get("detail-privateBrowsing-row"), "Private browsing should not be hidden");
|
||||
is_element_visible(get("detail-privateBrowsing-row-footer"), "Private browsing footer should not be hidden");
|
||||
is(get("detail-privateBrowsing").value, "0", "Private browsing should be off");
|
||||
|
||||
is_element_hidden(get("detail-rating-row"), "Rating should be hidden");
|
||||
|
||||
is_element_hidden(get("detail-homepage-row"), "Homepage should not be visible");
|
||||
|
@ -181,6 +198,28 @@ add_test(function() {
|
|||
is_element_hidden(get("detail-error-link"), "Error link should be hidden");
|
||||
is_element_hidden(get("detail-pending"), "Pending message should be hidden");
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Opens and tests the details view for add-on theme
|
||||
add_test(async function() {
|
||||
// This is a duplicate of addon-2, so we're only testing that private browsing is
|
||||
// not visible.
|
||||
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
|
||||
open_details("addon-theme@tests.mozilla.org", "theme", async () => {
|
||||
is(get("detail-name").textContent, "Test add-on theme", "Name should be correct");
|
||||
is_element_visible(get("detail-version"), "Version should not be hidden");
|
||||
is(get("detail-version").value, "2.3", "Version should be correct");
|
||||
is(get("detail-icon").src, "chrome://foo/skin/icon.png", "Icon should be correct");
|
||||
|
||||
is_element_hidden(get("detail-privateBrowsing-row"), "Private browsing should be hidden");
|
||||
is_element_hidden(get("detail-privateBrowsing-row-footer"), "Private browsing footer should be hidden");
|
||||
is(get("detail-privateBrowsing").value, "0", "Private browsing should be off");
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
const {ExtensionPermissions} = ChromeUtils.import("resource://gre/modules/ExtensionPermissions.jsm", {});
|
||||
|
||||
var gManagerWindow;
|
||||
|
||||
function get_test_items() {
|
||||
var items = {};
|
||||
|
||||
for (let item of gManagerWindow.document.getElementById("addon-list").childNodes) {
|
||||
items[item.mAddon.id] = item;
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function get(aId) {
|
||||
return gManagerWindow.document.getElementById(aId);
|
||||
}
|
||||
|
||||
async function hasPrivateAllowed(id) {
|
||||
let perms = await ExtensionPermissions.get(id);
|
||||
return perms.permissions.length == 1 &&
|
||||
perms.permissions[0] == "internal:privateBrowsingAllowed";
|
||||
}
|
||||
|
||||
add_task(async function test_addon() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
|
||||
|
||||
let addons = new Map([
|
||||
["@test-default", {
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: {id: "@test-default"},
|
||||
},
|
||||
},
|
||||
}],
|
||||
["@test-override", {
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: {id: "@test-override"},
|
||||
},
|
||||
},
|
||||
incognitoOverride: "spanning",
|
||||
}],
|
||||
["@test-override-permanent", {
|
||||
useAddonManager: "permanent",
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: {id: "@test-override-permanent"},
|
||||
},
|
||||
},
|
||||
incognitoOverride: "spanning",
|
||||
}],
|
||||
["@test-not-allowed", {
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: {id: "@test-not-allowed"},
|
||||
},
|
||||
incognito: "not_allowed",
|
||||
},
|
||||
}],
|
||||
]);
|
||||
let extensions = [];
|
||||
for (let definition of addons.values()) {
|
||||
let extension = ExtensionTestUtils.loadExtension(definition);
|
||||
extensions.push(extension);
|
||||
await extension.startup();
|
||||
}
|
||||
|
||||
gManagerWindow = await open_manager("addons://list/extension");
|
||||
let doc = gManagerWindow.document;
|
||||
let items = get_test_items();
|
||||
for (let [id, definition] of addons.entries()) {
|
||||
ok(items[id], `${id} listed`);
|
||||
let badge = doc.getAnonymousElementByAttribute(items[id], "anonid", "privateBrowsing");
|
||||
if (definition.incognitoOverride == "spanning") {
|
||||
is_element_visible(badge, `private browsing badge is visible`);
|
||||
} else {
|
||||
is_element_hidden(badge, `private browsing badge is hidden`);
|
||||
}
|
||||
}
|
||||
await close_manager(gManagerWindow);
|
||||
|
||||
for (let [id, definition] of addons.entries()) {
|
||||
gManagerWindow = await open_manager("addons://detail/" + encodeURIComponent(id));
|
||||
ok(true, `==== ${id} detail opened`);
|
||||
if (definition.manifest.incognito == "not_allowed") {
|
||||
is_element_hidden(get("detail-privateBrowsing-row"), "Private browsing should be hidden");
|
||||
is_element_hidden(get("detail-privateBrowsing-row-footer"), "Private browsing footer should be hidden");
|
||||
ok(!await hasPrivateAllowed(id), "Private browsing permission not set");
|
||||
} else {
|
||||
is_element_visible(get("detail-privateBrowsing-row"), "Private browsing should be visible");
|
||||
is_element_visible(get("detail-privateBrowsing-row-footer"), "Private browsing footer should be visible");
|
||||
let privateBrowsing = gManagerWindow.document.getElementById("detail-privateBrowsing");
|
||||
if (definition.incognitoOverride == "spanning") {
|
||||
is(privateBrowsing.value, "1", "Private browsing should be on");
|
||||
ok(await hasPrivateAllowed(id), "Private browsing permission set");
|
||||
EventUtils.synthesizeMouseAtCenter(privateBrowsing.lastChild, { clickCount: 1 }, gManagerWindow);
|
||||
await TestUtils.waitForCondition(() => privateBrowsing.value == "0");
|
||||
is(privateBrowsing.value, "0", "Private browsing should be off");
|
||||
ok(!await hasPrivateAllowed(id), "Private browsing permission removed");
|
||||
} else {
|
||||
is(privateBrowsing.value, "0", "Private browsing should be off");
|
||||
ok(!await hasPrivateAllowed(id), "Private browsing permission not set");
|
||||
EventUtils.synthesizeMouseAtCenter(privateBrowsing.firstChild, { clickCount: 1 }, gManagerWindow);
|
||||
await TestUtils.waitForCondition(() => privateBrowsing.value == "1");
|
||||
is(privateBrowsing.value, "1", "Private browsing should be on");
|
||||
ok(await hasPrivateAllowed(id), "Private browsing permission set");
|
||||
}
|
||||
}
|
||||
await close_manager(gManagerWindow);
|
||||
}
|
||||
|
||||
for (let extension of extensions) {
|
||||
await extension.unload();
|
||||
}
|
||||
Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault");
|
||||
});
|
|
@ -399,6 +399,19 @@ button.warning {
|
|||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.privateBrowsing-notice {
|
||||
background-color: var(--purple-70);
|
||||
color: #fff;
|
||||
margin: 4px 0 0;
|
||||
padding: 4px 5px 3px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
-moz-user-focus: ignore;
|
||||
transition-property: color, background-color;
|
||||
transition-timing-function: var(--animation-curve);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.legacy-warning {
|
||||
background-color: #FFE900;
|
||||
color: #3E2800;
|
||||
|
@ -407,7 +420,7 @@ button.warning {
|
|||
font-weight: 600;
|
||||
-moz-user-focus: ignore;
|
||||
transition-property: color, background-color;
|
||||
transition-timing-function: cubic-bezier(.07,.95,0,1);
|
||||
transition-timing-function: var(--animation-curve);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
|
@ -793,7 +806,7 @@ button.warning {
|
|||
}
|
||||
|
||||
.preferences-description {
|
||||
font-size: 90.9%;
|
||||
font-size: 1.1rem;
|
||||
color: graytext;
|
||||
margin-top: -2px;
|
||||
margin-inline-start: 2em;
|
||||
|
@ -804,6 +817,18 @@ button.warning {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.detail-row-footer {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.detail-row-footer > .preferences-description {
|
||||
margin-inline-start: 6px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
/* card-width - card-padding - description-margins */
|
||||
width: calc(664px - 32px - 11px);
|
||||
color: var(--grey-60);
|
||||
}
|
||||
|
||||
/*** creator ***/
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@
|
|||
--in-content-table-border-dark-color: #d1d1d1;
|
||||
--in-content-table-header-background: #0a84ff;
|
||||
|
||||
/* The photon animation curve */
|
||||
--animation-curve: cubic-bezier(.07,.95,0,1);
|
||||
|
||||
--blue-40: #45a1ff;
|
||||
--blue-40-a10: rgb(69, 161, 255, 0.1);
|
||||
--blue-50: #0a84ff;
|
||||
|
@ -64,6 +67,8 @@
|
|||
--grey-90-a30: rgba(12, 12, 13, 0.3);
|
||||
--grey-90-a40: rgba(12, 12, 13, 0.4);
|
||||
--grey-90-a50: rgba(12, 12, 13, 0.5);
|
||||
--purple-70: #6200a4;
|
||||
--purple-70-a40: rgba(98, 0, 164, 0.4);
|
||||
--red-50: #ff0039;
|
||||
--red-50-a30: rgba(255, 0, 57, 0.3);
|
||||
--red-60: #d70022;
|
||||
|
|
Загрузка…
Ссылка в новой задаче