Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 269 additions & 0 deletions css/component/color-categorization.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
/**
* Color categorization swatches.
* Color names stay in the control for screen readers.
*/

.basic-page-color-category-details > summary .basic-page-color-category__selected {
display: none;
align-items: center;
gap: 0.25rem;
margin-inline-start: 0.5rem;
}

.basic-page-color-category-details:not([open]) > summary .basic-page-color-category__selected:not(:empty) {
display: inline-flex;
}

.basic-page-color-category__dot {
width: 0.75rem;
height: 0.75rem;
border-radius: 50%;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}

.basic-page-color-category__dot--blue {
background-color: #0088ff;
}

.basic-page-color-category__dot--green {
background-color: #34c759;
}

.basic-page-color-category__dot--purple {
background-color: #663399;
}

.basic-page-color-category__dot--pink {
background-color: #ff69b4;
}

.basic-page-color-category__dot--orange {
background-color: #ff8d28;
}

.basic-page-color-category__dot--yellow {
background-color: #ffcc00;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28);
}

.basic-page-color-category__dot--red {
background-color: #ff383c;
}

.views-exposed-form .category-column {
width: max-content;
min-width: 4.5rem;
border: var(--input-border-size) solid var(--input-border-color);
border-radius: var(--base-border-radius);
background-color: var(--input-bg-color);
}

.views-exposed-form .category-column__toggle {
display: flex;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
min-height: calc(((var(--input-padding-vertical) + var(--input-border-size)) * 2) + var(--input-line-height));
margin: 0;
gap: 0.35rem;
padding-inline: 0.65rem;
list-style: none;
cursor: pointer;
}

.views-exposed-form .category-column__selected {
display: none;
align-items: center;
gap: 0.25rem;
margin-inline-end: auto;
}

.views-exposed-form .category-column:not([open]) .category-column__selected:not(:empty) {
display: flex;
}

.views-exposed-form .category-column__dot {
width: 0.75rem;
height: 0.75rem;
border-radius: 50%;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}

.views-exposed-form .category-column__dot--blue {
background-color: #0088ff;
}

.views-exposed-form .category-column__dot--green {
background-color: #34c759;
}

.views-exposed-form .category-column__dot--purple {
background-color: #663399;
}

.views-exposed-form .category-column__dot--pink {
background-color: #ff69b4;
}

.views-exposed-form .category-column__dot--orange {
background-color: #ff8d28;
}

.views-exposed-form .category-column__dot--yellow {
background-color: #ffcc00;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28);
}

.views-exposed-form .category-column__dot--red {
background-color: #ff383c;
}

.views-exposed-form .category-column__toggle::-webkit-details-marker {
display: none;
}

.views-exposed-form .category-column__toggle::marker {
content: "";
}

.views-exposed-form .category-column__caret {
width: 0.875rem;
height: 0.5625rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 9'%3e%3cpath fill='none' stroke-width='1.5' d='M1 1l6 6 6-6' stroke='%23545560'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}

.views-exposed-form .category-column[open] .category-column__caret {
transform: scaleY(-1);
}

.views-exposed-form .category-column .form-element--type-select-multiple {
display: block;
width: 100%;
min-width: 0;
margin: 0;
padding-inline: 0;
border: 0;
border-block-start: var(--input-border-size) solid var(--input-border-color);
border-radius: 0;
box-shadow: none;
text-align: center;
background-image: none;
}

.form-item--field-color-categorization-value option,
.form-item--field-color-categorization option:not([value="_none"]) {
height: 1.375rem;
color: transparent;
-webkit-text-fill-color: transparent;
font-size: 0;
line-height: 1.375rem;
background-repeat: no-repeat;
background-position: center;
background-size: 0.875rem 0.875rem;
}

.form-item--field-color-categorization option:not([value="_none"]) {
background-position: 0.75rem center;
}

.form-item--field-color-categorization-value option[value="blue"],
.form-item--field-color-categorization option[value="blue"] {
background-image: radial-gradient(circle, #0088ff 68%, transparent 70%);
}

.form-item--field-color-categorization-value option[value="green"],
.form-item--field-color-categorization option[value="green"] {
background-image: radial-gradient(circle, #34c759 68%, transparent 70%);
}

.form-item--field-color-categorization-value option[value="purple"],
.form-item--field-color-categorization option[value="purple"] {
background-image: radial-gradient(circle, #663399 68%, transparent 70%);
}

.form-item--field-color-categorization-value option[value="pink"],
.form-item--field-color-categorization option[value="pink"] {
background-image: radial-gradient(circle, #ff69b4 68%, transparent 70%);
}

.form-item--field-color-categorization-value option[value="orange"],
.form-item--field-color-categorization option[value="orange"] {
background-image: radial-gradient(circle, #ff8d28 68%, transparent 70%);
}

.form-item--field-color-categorization-value option[value="yellow"],
.form-item--field-color-categorization option[value="yellow"] {
background-image: radial-gradient(circle, #ffcc00 60%, rgba(0, 0, 0, 0.28) 62%, rgba(0, 0, 0, 0.28) 70%, transparent 72%);
}

.form-item--field-color-categorization-value option[value="red"],
.form-item--field-color-categorization option[value="red"] {
background-image: radial-gradient(circle, #ff383c 68%, transparent 70%);
}

.color-categorization {
display: inline-flex;
gap: 0.35rem;
align-items: center;
}

.color-swatch {
display: inline-block;
width: 0.875rem;
height: 0.875rem;
border-radius: 50%;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
vertical-align: middle;
}

.color-swatch--blue {
background-color: #0088ff;
}

.color-swatch--green {
background-color: #34c759;
}

.color-swatch--purple {
background-color: #663399;
}

.color-swatch--pink {
background-color: #ff69b4;
}

.color-swatch--orange {
background-color: #ff8d28;
}

.color-swatch--yellow {
background-color: #ffcc00;
}

.color-swatch--red {
background-color: #ff383c;
}

@media (forced-colors: active) {
.form-item--field-color-categorization-value option,
.form-item--field-color-categorization option {
height: auto;
color: CanvasText;
-webkit-text-fill-color: CanvasText;
font-size: inherit;
background-image: none;
}

.color-swatch .visually-hidden {
position: static !important;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
clip-path: none;
}
}
6 changes: 6 additions & 0 deletions express_admin.libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ global-styling:
component:
css/component/button.css: {}
css/component/form-warning.css: {}
css/component/color-categorization.css: {}
js:
js/category-column.js: {}
dependencies:
- core/drupal
- core/once

node-form:
css:
Expand Down
88 changes: 88 additions & 0 deletions js/category-column.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* global Drupal, once */
(function (Drupal, once) {
const colors = ['blue', 'green', 'purple', 'pink', 'orange', 'yellow', 'red'];

// One circle per selected color - w/ accessiblescreen reader naming
function fillDots(select, container, className) {
const names = [];
container.replaceChildren();
[...select.selectedOptions].forEach((option) => {
if (!colors.includes(option.value)) {
return;
}
const dot = document.createElement('span');
dot.className = className + ' ' + className + '--' + option.value;
dot.setAttribute('aria-hidden', 'true');
container.appendChild(dot);
names.push(option.textContent.trim());
});
return names;
}

Drupal.behaviors.expressAdminCategoryColumn = {
attach(context) {
// show selected circles in the Color Category summary
once('basic-page-color-category', '.form-item--field-color-categorization select[multiple]', context).forEach((select) => {
const details = select.closest('details');
const summary = details ? details.querySelector(':scope > summary') : null;
if (!details || !summary) {
return;
}

details.classList.add('basic-page-color-category-details');
const selected = document.createElement('span');
selected.className = 'basic-page-color-category__selected';
summary.appendChild(selected);

const render = () => {
fillDots(select, selected, 'basic-page-color-category__dot');
};

select.addEventListener('change', render);
render();
});

// Content View - wrap the Category multiselect in a caret to look nice, otherwise its long
once('category-column', '.form-item--field-color-categorization-value select[multiple]', context).forEach((select) => {
const item = select.closest('.form-item--field-color-categorization-value');
const label = item ? item.querySelector('label') : null;
if (!item || !label) {
return;
}

const labelText = label.textContent.trim();
const details = document.createElement('details');
details.className = 'category-column';

const summary = document.createElement('summary');
summary.className = 'category-column__toggle';

// Screen reader name for the closed control.
const hidden = document.createElement('span');
hidden.className = 'visually-hidden';
hidden.dataset.categoryLabel = labelText;
hidden.textContent = labelText;

const selected = document.createElement('span');
selected.className = 'category-column__selected';

const caret = document.createElement('span');
caret.className = 'category-column__caret';
caret.setAttribute('aria-hidden', 'true');

summary.append(hidden, selected, caret);
details.append(summary);
label.insertAdjacentElement('afterend', details);
details.append(select);

const render = () => {
const names = fillDots(select, selected, 'category-column__dot');
hidden.textContent = names.length ? labelText + ': ' + names.join(', ') : labelText;
};

select.addEventListener('change', render);
render();
});
},
};
})(Drupal, once);
Loading
Loading