kopia lustrzana https://github.com/wagtail/wagtail
Implement CSS variables for admin color theming (#6409)
Co-authored-by: JNaftali <jmarantz@thelabnyc.com> Co-authored-by: Thibaud Colas <thibaudcolas@gmail.com>pull/6676/head
rodzic
454002fbd7
commit
8e79c61564
|
|
@ -492,6 +492,7 @@ Contributors
|
|||
* Bohreromir
|
||||
* Fernando Cordeiro
|
||||
* Matthias Rohmer
|
||||
* Joshua Marantz
|
||||
|
||||
Translators
|
||||
===========
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ No CSS should be produced by these files.
|
|||
@import 'tools/mixins.fonts';
|
||||
@import 'tools/mixins.general';
|
||||
@import 'tools/mixins.grid';
|
||||
@import 'tools/various.colors';
|
||||
|
|
|
|||
|
|
@ -414,7 +414,6 @@ ul.listing {
|
|||
|
||||
&.bicolor {
|
||||
background: $color-teal-darker;
|
||||
border: solid 1px darken($color-teal-darker, 10%);
|
||||
|
||||
&:active {
|
||||
color: $color-white;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
&:hover {
|
||||
color: $color-white;
|
||||
border-top-color: darken($color-teal-darker, 8);
|
||||
border-top-color: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
:root {
|
||||
@include define-color('color-primary', #007d7e);
|
||||
@include define-color('color-primary-darker', css-darken(css-adjust-hue(get-color('color-primary'), 1), 4%));
|
||||
@include define-color('color-primary-dark', css-darken(css-adjust-hue(get-color('color-primary'), 1), 7%));
|
||||
|
||||
@include define-color('color-input-focus', css-lighten(css-desaturate(get-color('color-primary'), 40%), 72%));
|
||||
@include define-color('color-input-focus-border', css-lighten(css-saturate(get-color('color-primary'), 12%), 10%));
|
||||
}
|
||||
|
|
@ -28,9 +28,9 @@ $breakpoints: (
|
|||
);
|
||||
|
||||
// colours
|
||||
$color-teal: #007d7e;
|
||||
$color-teal-darker: darken(adjust-hue($color-teal, 1), 4);
|
||||
$color-teal-dark: darken(adjust-hue($color-teal, 1), 7);
|
||||
$color-teal: var(--color-primary);
|
||||
$color-teal-darker: var(--color-primary-darker);
|
||||
$color-teal-dark: var(--color-primary-dark);
|
||||
|
||||
$color-blue: #71b2d4;
|
||||
$color-red: #cd3238;
|
||||
|
|
@ -59,8 +59,8 @@ $color-header-bg: $color-teal;
|
|||
|
||||
$color-fieldset-hover: $color-grey-5;
|
||||
$color-input-border: $color-grey-4;
|
||||
$color-input-focus: lighten(desaturate($color-teal, 40), 72);
|
||||
$color-input-focus-border: lighten(saturate($color-teal, 12), 10);
|
||||
$color-input-focus: var(--color-input-focus);
|
||||
$color-input-focus-border: var(--color-input-focus-border);
|
||||
$color-input-error-bg: lighten(saturate($color-red, 28), 45);
|
||||
|
||||
$color-button: $color-teal;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ These are base styles for bare HTML elements.
|
|||
@import 'elements/elements';
|
||||
@import 'elements/typography';
|
||||
@import 'elements/forms';
|
||||
@import 'elements/root';
|
||||
|
||||
|
||||
/* OBJECTS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
// $color is either a color or an hsl tuple
|
||||
@mixin define-color($name, $color) {
|
||||
$h: null;
|
||||
$s: null;
|
||||
$l: null;
|
||||
|
||||
@if type-of($color) == color {
|
||||
$h: hue($color) / 1deg; // Cast to unitless
|
||||
$s: saturation($color);
|
||||
$l: lightness($color);
|
||||
} @else {
|
||||
$h: nth($color, 1);
|
||||
$s: nth($color, 2);
|
||||
$l: nth($color, 3);
|
||||
}
|
||||
|
||||
--#{$name}-hue: #{$h};
|
||||
--#{$name}-saturation: #{$s};
|
||||
--#{$name}-lightness: #{$l};
|
||||
--#{$name}: hsl(#{ var(--#{$name}-hue), var(--#{$name}-saturation), var(--#{$name}-lightness) });
|
||||
}
|
||||
|
||||
@function get-color($name) {
|
||||
@return (var(--#{$name}-hue), var(--#{$name}-saturation), var(--#{$name}-lightness));
|
||||
}
|
||||
|
||||
@function css-darken($hsl-tuple, $darken-by) {
|
||||
$h: nth($hsl-tuple, 1);
|
||||
$s: nth($hsl-tuple, 2);
|
||||
$l: nth($hsl-tuple, 3);
|
||||
@return ($h, $s, calc(#{$l} - #{$darken-by + 0%}));
|
||||
}
|
||||
@function css-lighten($hsl-tuple, $lighten-by) {
|
||||
$h: nth($hsl-tuple, 1);
|
||||
$s: nth($hsl-tuple, 2);
|
||||
$l: nth($hsl-tuple, 3);
|
||||
@return ($h, $s, calc(#{$l} + #{$lighten-by + 0%}));
|
||||
}
|
||||
@function css-saturate($hsl-tuple, $saturate-by) {
|
||||
$h: nth($hsl-tuple, 1);
|
||||
$s: nth($hsl-tuple, 2);
|
||||
$l: nth($hsl-tuple, 3);
|
||||
@return ($h, calc(#{$s} + #{$saturate-by + 0%}), $l);
|
||||
}
|
||||
@function css-desaturate($hsl-tuple, $desaturate-by) {
|
||||
$h: nth($hsl-tuple, 1);
|
||||
$s: nth($hsl-tuple, 2);
|
||||
$l: nth($hsl-tuple, 3);
|
||||
@return ($h, calc(#{$s} - #{$desaturate-by + 0%}), $l);
|
||||
}
|
||||
@function css-adjust-hue($hsl-tuple, $adjust-by) {
|
||||
$h: nth($hsl-tuple, 1);
|
||||
$s: nth($hsl-tuple, 2);
|
||||
$l: nth($hsl-tuple, 3);
|
||||
@return (calc(#{$h} + #{$adjust-by}), $s, $l);
|
||||
}
|
||||
@function css-transparentize($hsl-tuple, $alpha) {
|
||||
$h: nth($hsl-tuple, 1);
|
||||
$s: nth($hsl-tuple, 2);
|
||||
$l: nth($hsl-tuple, 3);
|
||||
@return ($h, $s, $l, $alpha);
|
||||
}
|
||||
|
|
@ -2,7 +2,10 @@ $header-padding-vertical: 6px;
|
|||
$action-font-size: 18px;
|
||||
|
||||
|
||||
@import '../../../../node_modules/react-streamfield/src/scss/index';
|
||||
@use '../../../../node_modules/react-streamfield/src/scss/index' with (
|
||||
$teal: $color-teal,
|
||||
$error-color: $color-red,
|
||||
);
|
||||
|
||||
|
||||
.c-sf-container {
|
||||
|
|
|
|||
|
|
@ -91,6 +91,53 @@ To replace the welcome message on the dashboard, create a template file ``dashbo
|
|||
|
||||
{% block branding_welcome %}Welcome to Frank's Site{% endblock %}
|
||||
|
||||
.. _custom_user_interface_colors:
|
||||
|
||||
Custom user interface colors
|
||||
============================
|
||||
|
||||
|
||||
.. warning::
|
||||
CSS variables are not supported in Internet Explorer, so the admin will appear with the default colors when viewed in that browser.
|
||||
|
||||
The default Wagtail colors conform to the WCAG2.1 AA level color contrast requirements. When customizing the admin colors you should test the contrast using tools like `Axe <https://www.deque.com/axe/browser-extensions/>`_.
|
||||
|
||||
To customize the primary color used in the admin user interface, inject a CSS file using the hook :ref:`insert_global_admin_css` and override the variables within the ``:root`` selector:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
:root {
|
||||
--color-primary-hue: 25;
|
||||
}
|
||||
|
||||
``color-primary`` is an `hsl color <https://en.wikipedia.org/wiki/HSL_and_HSV>`_ composed of 3 CSS variables - ``--color-primary-hue`` (0-360 with no unit), ``--color-primary-saturation`` (a percentage), and ``--color-primary-lightness`` (also a percentage). Separating the color into 3 allows us to calculate variations on the color to use alongside the primary color. If needed, you can also control those variations manually by setting ``hue``, ``saturation``, and ``lightness`` variables for the following colors: ``color-primary-darker``, ``color-primary-dark``, ``color-input-focus``, and ``color-input-focus-border``:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
:root {
|
||||
--color-primary-hue: 25;
|
||||
--color-primary-saturation: 100%;
|
||||
--color-primary-lightness: 25%;
|
||||
--color-primary-darker-hue: 24;
|
||||
--color-primary-darker-saturation: 100%;
|
||||
--color-primary-darker-lightness: 20%;
|
||||
--color-primary-dark-hue: 23;
|
||||
--color-primary-dark-saturation: 100%;
|
||||
--color-primary-dark-lightness: 15%;
|
||||
}
|
||||
|
||||
If instead you intend to set all available colors, you can use any valid css colors:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
:root {
|
||||
--color-primary: mediumaquamarine;
|
||||
--color-primary-darker: rebeccapurple;
|
||||
--color-primary-dark: hsl(330, 100%, 70%);
|
||||
--color-input-focus: rgb(204, 0, 102);
|
||||
--color-input-focus-border: #4d0026;
|
||||
}
|
||||
|
||||
Specifying a site or page in the branding
|
||||
=========================================
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ In-place StreamField updating
|
|||
|
||||
StreamField values now formally support being updated in-place from Python code, allowing blocks to be inserted, modified and deleted rather than having to assign a new list of blocks to the field. For further details, see :ref:`modifying_streamfield_data`. This feature was developed by Matt Westcott.
|
||||
|
||||
Admin color themes
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Wagtail’s admin now uses CSS custom properties for its primary teal color. Applying brand colors for the whole user interface only takes a few lines of CSS, and third-party extensions can reuse Wagtail’s CSS variables to support the same degree of customization. Read on :ref:`custom_user_interface_colors`. This feature was developed by Joshua Marantz.
|
||||
|
||||
Other features
|
||||
~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ var sass = require('gulp-dart-sass');
|
|||
var postcss = require('gulp-postcss');
|
||||
var autoprefixer = require('autoprefixer');
|
||||
var cssnano = require('cssnano');
|
||||
var postcssCustomProperties = require('postcss-custom-properties');
|
||||
var postcssCalc = require('postcss-calc');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var size = require('gulp-size');
|
||||
var config = require('../config');
|
||||
|
|
@ -69,6 +71,8 @@ gulp.task('styles:sass', function () {
|
|||
.pipe(postcss([
|
||||
cssnano(cssnanoConfig),
|
||||
autoprefixer(autoprefixerConfig),
|
||||
postcssCustomProperties(),
|
||||
postcssCalc(),
|
||||
]))
|
||||
.pipe(size({ title: 'Wagtail CSS' }))
|
||||
.pipe(config.isProduction ? gutil.noop() : sourcemaps.write())
|
||||
|
|
|
|||
|
|
@ -3499,8 +3499,7 @@
|
|||
"cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
||||
},
|
||||
"cssnano": {
|
||||
"version": "4.1.10",
|
||||
|
|
@ -7308,8 +7307,7 @@
|
|||
"indexes-of": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
|
||||
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
|
|
@ -7654,6 +7652,12 @@
|
|||
"unc-path-regex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"is-url-superb": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz",
|
||||
"integrity": "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-utf8": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
|
||||
|
|
@ -11778,7 +11782,6 @@
|
|||
"version": "7.0.35",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
|
||||
"integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
|
|
@ -11788,14 +11791,12 @@
|
|||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
|
|
@ -11803,10 +11804,9 @@
|
|||
}
|
||||
},
|
||||
"postcss-calc": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz",
|
||||
"integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==",
|
||||
"dev": true,
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz",
|
||||
"integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==",
|
||||
"requires": {
|
||||
"postcss": "^7.0.27",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
|
|
@ -11852,6 +11852,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"postcss-custom-properties": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-10.0.0.tgz",
|
||||
"integrity": "sha512-55BPj5FudpCiPZzBaO+MOeqmwMDa+nV9/0QBJBfhZjYg6D9hE+rW9lpMBLTJoF4OTXnS5Po4yM1nMlgkPbCxFg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss": "^7.0.17",
|
||||
"postcss-values-parser": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"postcss-discard-comments": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz",
|
||||
|
|
@ -12355,7 +12365,6 @@
|
|||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz",
|
||||
"integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"indexes-of": "^1.0.1",
|
||||
|
|
@ -12402,8 +12411,26 @@
|
|||
"postcss-value-parser": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
|
||||
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ=="
|
||||
},
|
||||
"postcss-values-parser": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-4.0.0.tgz",
|
||||
"integrity": "sha512-R9x2D87FcbhwXUmoCXJR85M1BLII5suXRuXibGYyBJ7lVDEpRIdKZh4+8q5S+/+A4m0IoG1U5tFw39asyhX/Hw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "^1.1.4",
|
||||
"is-url-superb": "^4.0.0",
|
||||
"postcss": "^7.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
|
|
@ -15389,8 +15416,7 @@
|
|||
"uniq": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
|
||||
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
|
||||
},
|
||||
"uniqs": {
|
||||
"version": "2.0.0",
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
"gulp-util": "~3.0.8",
|
||||
"jest": "^26.6.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-custom-properties": "^10.0.0",
|
||||
"react-axe": "^3.1.0",
|
||||
"react-test-renderer": "^16.13.1",
|
||||
"redux-mock-store": "^1.3.0",
|
||||
|
|
@ -89,6 +90,7 @@
|
|||
"draftail": "^1.2.1",
|
||||
"element-closest": "^2.0.2",
|
||||
"focus-trap-react": "^3.1.0",
|
||||
"postcss-calc": "^7.0.5",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.4.0",
|
||||
"react-dom": "^16.4.0",
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
@import 'wagtailadmin/scss/helpers';
|
||||
@import '../../../../../../client/src/components/StreamField/StreamField';
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue