Commit 0d3f8d2e authored by effulgentsia's avatar effulgentsia
Browse files

Issue #3066006 by bnjmnm, lauriii, katherined, KondratievaS, Lendude, ckrina,...

Issue #3066006 by bnjmnm, lauriii, katherined, KondratievaS, Lendude, ckrina, saschaeggi, phenaproxima: Convert Views UI to new design system
parent 5d0f5371
......@@ -81,6 +81,8 @@ libraries-override:
views_ui/admin.styling:
css:
component:
css/views_ui.admin.css: css/components/views_ui.admin.css
theme:
css/views_ui.admin.theme.css: css/theme/views_ui.admin.theme.css
......
......@@ -19,6 +19,7 @@
use Drupal\file\FileInterface;
use Drupal\views\Form\ViewsForm;
use Drupal\views\ViewExecutable;
use Drupal\views_ui\Form\Ajax\ViewsFormInterface;
/**
* Implements hook_theme_suggestions_HOOK_alter() for form_element.
......@@ -376,6 +377,12 @@ function claro_form_alter(array &$form, FormStateInterface $form_state, $form_id
$form['actions']['delete'] = _claro_convert_link_to_action_link($form['actions']['delete'], 'trash', 'default', 'danger');
}
if (($form_object instanceof ViewsForm || $form_object instanceof ViewsFormInterface) && isset($form['override']['#prefix'])) {
// Replace form--inline class so positioning of override form elements don't
// have to depend on floats.
$form['override']['#prefix'] = str_replace('form--inline', 'form--flex', $form['override']['#prefix']);
}
if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) {
if (isset($form['header'])) {
$form['header']['#attributes']['class'][] = 'media-library-views-form__header';
......@@ -586,6 +593,31 @@ function claro_views_ui_display_top_alter(&$element) {
if (!empty($element['extra_actions'])) {
$element['extra_actions']['#dropbutton_type'] = 'small';
}
// Add a class to each item in the add display dropdown so they can be styled
// with a single selector.
if (isset($element['add_display'])) {
foreach ($element['add_display'] as &$display_item) {
if (isset($display_item['#type']) && in_array($display_item['#type'], ['submit', 'button'], TRUE)) {
$display_item['#attributes']['class'][] = 'views-tabs__action-list-button';
}
}
}
// Rearrange top bar contents so floats aren't necessary for positioning.
if (isset($element['extra_actions'], $element['tabs'], $element['add_display'])) {
$element['extra_actions']['#weight'] = 10;
$element['extra_actions']['#theme_wrappers'] = [
'container' => [
'#attributes' => [
'class' => ['views-display-top__extra-actions-wrapper'],
],
],
];
$element['#attributes']['class'] = array_diff($element['#attributes']['class'], ['clearfix']);
}
}
/**
......@@ -636,10 +668,18 @@ function claro_views_ui_display_tab_alter(&$element) {
$dummy_dropbutton['prefix']['#markup'] = preg_replace($prefix_regex, '$1$2 ' . $classes . '$3', $prefix);
}
}
// If the top details have both actions and title, the `actions` weights need
// to be adjusted so the DOM order matches the order of appearance.
if (isset($element['details']['top']['actions'], $element['details']['top']['display_title'])) {
$top = &$element['details']['top'];
$top['actions']['#weight'] = 10;
$top['#attributes']['class'] = array_diff($top['#attributes']['class'], ['clearfix']);
}
}
/**
* Implements hook_preprocess_HOOK for views_exposed_form.
* Implements hook_preprocess_HOOK() for views_exposed_form.
*/
function claro_preprocess_views_exposed_form(&$variables) {
$form = &$variables['form'];
......@@ -1413,3 +1453,111 @@ function claro_preprocess_links__media_library_menu(array &$variables) {
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for the Views UI rearrange filter form.
*/
function claro_preprocess_views_ui_rearrange_filter_form(array &$variables) {
foreach ($variables['table']['#rows'] as &$row) {
// Remove the container-inline class from the operator table cell.
if (isset($row['data'][0]['class'])) {
$row['data'][0]['class'] = array_diff($row['data'][0]['class'], ['container-inline']);
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for the Views UI config form.
*/
function claro_form_views_ui_config_item_form_alter(array &$form, FormStateInterface $form_state) {
$type = $form_state->get('type');
if ($type === 'filter') {
// Remove clearfix classes from several elements. They add unwanted
// whitespace and are no longer needed because uses of `float:` in this form
// have been removed.
// @todo Many of the changes to classes within this conditional may not be
// needed or require refactoring in https://drupal.org/node/3164890
unset($form['options']['clear_markup_start']);
unset($form['options']['clear_markup_end']);
$form['options']['expose_button']['#prefix'] = str_replace('clearfix', '', $form['options']['expose_button']['#prefix']);
if (isset($form['options']['group_button']['#prefix'])) {
$form['options']['group_button']['#prefix'] = str_replace('clearfix', '', $form['options']['group_button']['#prefix']);
}
// Remove `views-(direction)-(amount)` classes, replace with
// `views-group-box--operator`, and add a `views-config-group-region`
// wrapper.
if (isset($form['options']['operator']['#prefix'])) {
foreach (['views-left-30', 'views-left-40'] as $left_class) {
if (strpos($form['options']['operator']['#prefix'], $left_class) !== FALSE) {
$form['options']['operator']['#prefix'] = '<div class="views-config-group-region">' . str_replace($left_class, 'views-group-box--operator', $form['options']['operator']['#prefix']);
$form['options']['value']['#suffix'] = $form['options']['value']['#suffix'] . '</div>';
}
}
}
// Some instances of this form input have an added wrapper that needs to be
// removed in order to style these forms consistently.
// @see \Drupal\views\Plugin\views\filter\InOperator::valueForm
$wrapper_div_to_remove = '<div id="edit-options-value-wrapper">';
if (isset($form['options']['value']['#prefix']) && strpos($form['options']['value']['#prefix'], $wrapper_div_to_remove) !== FALSE) {
$form['options']['value']['#prefix'] = str_replace($wrapper_div_to_remove, '', $form['options']['value']['#prefix']);
$form['options']['value']['#suffix'] = preg_replace('/<\/div>/', '', $form['options']['value']['#suffix'], 1);
}
if (isset($form['options']['value']['#prefix'])) {
foreach (['views-right-70', 'views-right-60'] as $right_class) {
if (strpos($form['options']['value']['#prefix'], $right_class) !== FALSE) {
$form['options']['value']['#prefix'] = str_replace($right_class, 'views-group-box--value', $form['options']['value']['#prefix']);
}
}
}
// If the form includes a `value` field, the `.views-group-box--value` and
// `.views-group-box` classes must be present in a wrapper div. Add them
// here if it they are not yet present.
if (!isset($form['options']['value']['#prefix']) || strpos($form['options']['value']['#prefix'], 'views-group-box--value') === FALSE) {
$prefix = $form['options']['value']['#prefix'] ?? '';
$suffix = $form['options']['value']['#suffix'] ?? '';
$form['options']['value']['#prefix'] = '<div class="views-group-box views-group-box--value">' . $prefix;
$form['options']['value']['#suffix'] = $suffix . '</div>';
}
// If operator or value have no children, remove them from the render array
// so their prefixes and suffixes aren't added without any content.
foreach (['operator', 'value'] as $form_item) {
if (isset($form['options'][$form_item]) && count($form['options'][$form_item]) === 2 && isset($form['options'][$form_item]['#prefix']) && $form['options'][$form_item]['#suffix']) {
unset($form['options'][$form_item]);
}
}
}
}
/**
* Implements hook_form_FORM_ID_alter() for Views UI add handler form.
*/
function claro_form_views_ui_add_handler_form_alter(array &$form, FormStateInterface $form_state) {
// Remove container-inline class to allow more control over styling.
if (isset($form['selected']['#attributes']['class'])) {
$form['selected']['#attributes']['class'] = array_diff($form['selected']['#attributes']['class'], ['container-inline']);
}
// Move all form elements in controls to its parent, this places them all in
// the same div, which makes it possible to position them with flex styling
// instead of floats.
if (isset($form['override']['controls'])) {
foreach (Element::children($form['override']['controls']) as $key) {
$form['override']["controls_$key"] = $form['override']['controls'][$key];
// The wrapper array for controls is removed after this loop completes.
// The wrapper ensured that its child elements were hidden in browsers
// without JavaScript. To replicate this functionality, the `.js-show`
// class is added to each item previously contained in the wrapper.
if (isset($form['override']['controls']['#id']) && $form['override']['controls']['#id'] === 'views-filterable-options-controls') {
$form['override']["controls_$key"]['#wrapper_attributes']['class'][] = 'js-show';
}
}
unset($form['override']['controls']);
}
}
......@@ -102,6 +102,10 @@
--input-padding-horizontal: calc(var(--space-m) - var(--input-border-size));
--input-font-size: var(--font-size-base);
--input-line-height: var(--space-l);
--input-padding-vertical--small: calc(var(--space-xs) - (var(--input-border-size) * 2));
--input-padding-horizontal--small: calc(var(--space-m) - var(--input-border-size));
--input-font-size--small: var(--font-size-xs);
--input-line-height--small: 1.3125rem;
--input--extrasmall-padding-vertical: calc(0.15rem - var(--input-border-size));
--input--extrasmall-padding-horizontal: calc(var(--space-xs) - var(--input-border-size));
--input--extrasmall-font-size: var(--font-size-s);
......
......@@ -93,22 +93,11 @@
.ui-dialog > .ui-dialog-content {
overflow: auto;
padding-right: 1.5rem;
padding-left: 1.5rem;
padding: 1rem 1.5rem;
color: #222330;
background: #fff;
}
/**
* @todo it should not be necessary to specify not(.views-ui-dialog) after
* https://drupal.org/node/3066006
*/
.ui-dialog:not(.views-ui-dialog) > .ui-dialog-content {
padding-top: 1rem;
padding-bottom: 1rem;
}
.ui-dialog > .ui-dialog-buttonpane {
color: #222330;
border-bottom-right-radius: 4px;
......
......@@ -86,21 +86,11 @@
.ui-dialog > .ui-dialog-content {
overflow: auto;
padding-right: var(--space-l);
padding-left: var(--space-l);
padding: var(--space-m) var(--space-l);
color: var(--color-text);
background: var(--color-white);
}
/**
* @todo it should not be necessary to specify not(.views-ui-dialog) after
* https://drupal.org/node/3066006
*/
.ui-dialog:not(.views-ui-dialog) > .ui-dialog-content {
padding-top: var(--space-m);
padding-bottom: var(--space-m);
}
.ui-dialog > .ui-dialog-buttonpane {
color: var(--color-text);
border-bottom-right-radius: var(--jui-dialog-border-radius);
......
......@@ -37,6 +37,10 @@
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.views-exposed-form--preview.views-exposed-form--preview {
margin-top: 0;
}
.views-exposed-form__item.views-exposed-form__item {
margin: 0.75rem 0.5rem 0 0; /* LTR */
}
......
......@@ -31,6 +31,9 @@
background-color: var(--color-white);
box-shadow: var(--details-box-shadow);
}
.views-exposed-form--preview.views-exposed-form--preview {
margin-top: 0;
}
.views-exposed-form__item.views-exposed-form__item {
margin: var(--space-s) var(--space-xs) 0 0; /* LTR */
......
......@@ -51,9 +51,76 @@ details.fieldset-no-legend {
margin-right: 0;
}
/* @group Dependent options
.views-ui-dialog .form--flex {
display: flex;
overflow: hidden;
flex-wrap: wrap;
}
.views-ui-dialog .form-item {
margin-top: 1rem;
margin-bottom: 1rem;
}
.views-ui-dialog .form-type--boolean {
margin-right: 0;
margin-left: 0;
}
.views-ui-dialog .form-type--boolean .form-boolean {
top: 0;
float: none;
margin: 0 0.25rem 0 0; /* LTR */
transform: none;
}
[dir="rtl"] .views-ui-dialog .form-type--boolean .form-boolean {
margin-right: 0;
margin-left: 0.25rem;
}
.views-ui-dialog .form-boolean-group .form-type--boolean {
margin-top: 0.4em;
margin-bottom: 0.4em;
}
.views-ui-dialog .form-item:first-of-type.description {
margin: 0 0 1.5rem 0;
padding-bottom: 0.75rem;
border-bottom: 0.0625rem solid #d4d4d8;
font-weight: bold;
}
/* So "remove" link appears next to the checkbox. */
.views-ui-dialog .draggable .form-type--checkbox {
display: inline-block;
margin: 0 0.25rem;
}
.views-ui-dialog .form-element {
min-height: calc(2.3125rem - 2px); /* iOS. */
padding: calc(0.5rem - 2px) calc(1rem - 1px);
font-size: 0.79rem;
line-height: 1.3125rem;
}
.views-ui-dialog .form-element--type-select {
padding-right: calc(2rem + 2px);
background-position: 100% 56%;
}
/**
* Elements must communicate width to table rendering.
* @todo revisit in https://drupal.org/node/3135457
*/
.views-ui-dialog td .form-element {
width: auto;
}
/* @group Dependent options */
/* This is necessary to supercede the Claro .form-item
* reset declaration that sets the margin to zero.
*/
......@@ -92,27 +159,11 @@ details.fieldset-no-legend {
/* @group Lists */
.views-admin ul.secondary,
.views-admin .item-list ul {
margin: 0;
padding: 0;
}
.views-displays ul.secondary li a,
.views-displays ul.secondary li.is-active a,
.views-displays ul.secondary li.is-active a.is-active {
padding: 2px 7px 3px;
}
.views-displays ul.secondary li a {
color: #0074bd;
}
.views-displays ul.secondary li.is-active a,
.views-displays ul.secondary li.is-active a.is-active {
border: 1px solid transparent;
}
.views-admin .links li {
padding-right: 0; /* LTR */
}
......@@ -129,26 +180,16 @@ details.fieldset-no-legend {
padding-left: 12px;
}
.views-display-top ul.secondary {
float: left; /* LTR */
background-color: transparent;
}
[dir="rtl"] .views-display-top ul.secondary {
float: right;
}
.views-display-top .secondary .action-list li {
float: none;
margin: 0;
.views-display-top__extra-actions-wrapper {
margin: 0.25rem 0.5rem 0.5rem;
}
/* @end */
/* @group Tables */
.views-ui-rearrange-filter-form table td,
.views-ui-rearrange-filter-form table th {
.views-ui-rearrange-filter-form td,
.views-ui-rearrange-filter-form th {
vertical-align: top;
}
......@@ -172,8 +213,10 @@ details.fieldset-no-legend {
*/
.views-tabs {
display: flex;
overflow: visible;
margin: 0 200px 0 0; /* LTR */
flex-wrap: wrap;
margin: 0 1.5rem 0 0; /* LTR */
padding: 0;
list-style: none;
text-align: left; /* LTR */
......@@ -182,82 +225,14 @@ details.fieldset-no-legend {
[dir="rtl"] .views-tabs {
margin-right: 0;
margin-left: 200px;
margin-left: 1.5rem;
text-align: right;
}
.views-tabs > li {
float: left; /* LTR */
padding: 0;
border-right: 0 none; /* LTR */
}
[dir="rtl"] .views-tabs > li {
float: right;
border-right: 1px solid #bfbfbf;
border-left: 0 none;
}
.views-tabs .open > a {
position: relative;
z-index: 51;
}
.views-tabs .views-display-deleted-link {
text-decoration: line-through;
}
.views-tabs .add {
position: relative;
}
.views-tabs .action-list {
position: absolute;
z-index: 50;
top: 23px;
left: 0; /* LTR */
margin: 0;
}
[dir="rtl"] .views-tabs .action-list {
right: 0;
left: auto;
}
.views-tabs .action-list li {
display: block;
}
.views-tab a:hover > .icon.add {
background-position: center -25px;
}
.views-tab .open > a {
border-radius: 7px 7px 0 0;
}
.views-tab .open > a:hover,
.views-tab .open > a:focus {
color: #008bcb;
background-color: #f1f1f1;
}
.views-tab .action-list li:first-child {
border-radius: 0 7px 0 0; /* LTR */
}
[dir="rtl"] .views-tab .action-list li:first-child {
border-radius: 7px 0 0 0;
}
.views-tab .action-list li:last-child {
border-radius: 0 0 7px 7px;
}
.views-tab .action-list input.form-submit {
color: #008bcb;
}
.views-tabs li,
.views-tabs li.is-active {
width: auto;
......@@ -294,7 +269,7 @@ details.fieldset-no-legend {
.views-tabs a {
display: inline-block;
padding: 3px 7px;
padding: 10px;
border: 1px solid #cbcbcb;
border-radius: 7px;
font-size: small;
......@@ -305,7 +280,7 @@ details.fieldset-no-legend {
.views-tabs li.is-active a.is-active.error,
.views-tabs .error {
padding: 1px 6px;
padding: 8px;
border: 2px solid #ed541d;
}
......@@ -325,58 +300,128 @@ details.fieldset-no-legend {
background-color: #555;
}
.views-tabs .open > a {
.views-tabs .add {
position: relative;
border-bottom: 1px solid transparent;
background-color: #f1f1f1;
}
.views-tabs .open > a:hover {
color: #0074bd;
background-color: #f1f1f1;
.views-tabs .add a {
padding: 9px 13px 9px 9px;
color: #545560;
border: none;
border-radius: 2px;
background-color: transparent;
font-size: 1rem;
font-weight: 700;
}
.views-tabs .add a::before {
display: inline-block;
width: 1em;
height: calc(1em - 2px);
content: "";
/* Copy of icon from .action-link--icon-plus */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' stroke-width='2' stroke='%23545560'%3E%3Cpath d='m3 8h10'/%3E%3Cpath d='m8 3v10'/%3E%3C/svg%3E");
}
.views-tabs .add a:hover {
color: #0036b1;
background-color: #f0f5fd;
}
.views-tabs .add a:hover::before {
/* Copy of icon from .action-link--icon-plus:hover */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' stroke-width='2' stroke='%230036b1'%3E%3Cpath d='m3 8h10'/%3E%3Cpath d='m8 3v10'/%3E%3C/svg%3E");
}
.views-tabs .add a:focus {
background-color: #e6ecf8;
box-shadow: 0 0 0 3px #26a769;
}
.views-tabs .add.open a {
color: #fff;
background-color: #003cc5;
}
.views-tabs .add.open a::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' stroke-width='2' stroke='%23FFFFFF'%3E%3Cpath d='m3 8h10'/%3E%3Cpath d='m8 3v10'/%3E%3C/svg%3E");
}
/* Hide core icon, added via JS that isn't accessible via theme function. */
.views-tabs .add .icon.add {
display: none;
}
.views-tabs .action-list {
position: absolute;
z-index: 50;
top: 38px;
left: -2px; /* LTR */
margin: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
[dir="rtl"] .views-tabs .action-list {
right: 0;
left: auto;
}
.views-tabs .action-list li {
display: block;
}
.views-tabs .action-list li {
padding: 2px 9px;