This stylelint-scss rule is useful because we were inconsistent when
using calc(); sometimes we added interpolation to Sass variables, and
sometimes we didn't. The reason why we originally added interpolation
was that it was necessary until we migrated to Dart Sass in commit
d54971e53. Since then, we can omit the interpolation, which is also what
the Sass documentation recommends [1].
[1] https://sass-lang.com/documentation/values/calculations/
We made a mistake when adding the `calc()` function in commit 6df813fdb,
since the `/` operator originally only affected the `$heading-icon-size`
part of the operation, but affected the whole operation after that
commit. This caused the icon to be positioned on top of another icon.
Note: Since we update to 1.80.1 deprecation warnings are appear when execute the assets:precompile command.
In order to silence this deprecation, we add silence_deprecation option in sass.rb initializer.
The code has also been updated to remove the deprecation warnings that appeared related to the function
darken(), lighten() and "Using / for division" instead of the function calc().
Bumps [sassc-embedded](https://github.com/sass-contrib/sassc-embedded-shim-ruby) from 1.70.1 to 1.80.1.
- [Commits](https://github.com/sass-contrib/sassc-embedded-shim-ruby/compare/v1.70.1...v1.80.1)
---
updated-dependencies:
- dependency-name: sassc-embedded
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Just like it happened with proposals, the button to select/deselect an
investment wasn't very intuitive; for example, it wasn't obvious that
pressing a button saying "selected" would deselect the investment.
So we're using a switch control, like we do to enable/disable features
since commit fabe97e50.
Note that we're making the text of the switch smaller than in other
places because the text in the investments table it is also smaller
(we're using `font-size: inherit` for that purpose). That made the
button look weird because we were using rems instead of ems for the
width of the button, so we're adjusting that as well.
Also note we're changing the width of the switch to `6em` instead of
`6.25em` (which would be 100px if 1em is 16px). We're doing so because
we used 100 for the minimum width because it's a round number, so
now we're using another round number.
We hadn't added this rule before because there was no such rule in
scss-lint. Instead, we were following it without a linter, and so we
unintentionally broke it sometimes.
But now we're using Stylelint, so we can add the rule and let the linter
check we're still following it.
In the previous commit, we used the `calc` function when assiging CSS
properties in order to avoid warnings like:
```
Deprecation Warning: Using / for division outside of calc() is
deprecated and will be removed in Dart Sass 2.0.0.
Recommendation: math.div($global-width, 2) or calc($global-width / 2)
```
In cases like dividing by two, there's a third alternative: multiplying
by 0.5. We're applying this principle to all variable assignments where
we were using divisions, since using the `calc` function here would
sometimes result in errors due to these variables being used in
arithmetical operations. We aren't using `math.div` because it makes the
code harder to read.
The division operator `/` from Sass is deprecated because `/` is used in
CSS for uses other than dividing numbers. That's why we were getting
many warnings like:
```
Deprecation Warning: Using / for division outside of calc() is
deprecated and will be removed in Dart Sass 2.0.0.
Recommendation: math.div($line-height, 2) or calc($line-height / 2)
More info and automated migrator: https://sass-lang.com/d/slash-div
margin-top: $line-height / 2;
```
Since using math.div makes the code harder to read and `calc` is
universally supported by all browsers (although the implementation in
Internet Explorer doesn't work in certain cases), we're using `calc`
when assigning the value to a CSS property.
However, we're also using divisions when assigning Sass variables, and
in those cases using `calc` is trickier because sometimes these
variables are used in other operations. We'll handle these cases in the
next commit.
SCSS Lint was based on Ruby Sass, which has been deprecated since 2018
and doesn't support some of the latest features in Dart Sass.
Since we're going to migrate to Dart Sass, we're also migrating to
Stylelint. In order to provide all the funcionality SCSS Lint had, we
also need to install a few Stylelint plugins. We also need to install
the `postcss-scss` package so Stylelint can read SCSS files.
We're still getting the linting errors we used to get in
`legislation_process.scss` because of the `max-nesting-depth` and
`selector-max-compound-selectors` rules, as well as the warnings we used
to get in `layout.scss` because the `ssb-whatsapp_app` HTML class
contains undescores in their name.
We're also getting a couple of new linting errors, which could be false
positives:
* The `scss/no-unused-private-members` rule reports errors in
`_consul_settings.scss` because of the `$-zf-*` variables, but I'm not
too worried about this one because these lines won't be necessary after
updating Foundation.
* The `scss/selector-no-redundant-nesting-selector` reports an error in
`datepicker_overrides.scss`, but removing the unnecessary nesting
selector would make it harder to understand the code (assuming it'd
work in the first place).
We've changed some files due to few differences between SCSS Lint rules
and their Stylelint equivalents:
* The `@stylistic/string-quotes` rule detects a case in `admin.scss`
that StringQuotes didn't detect.
* The `function-url-quotes` rule detects a case in `mixins/icons.scss`
that UrlQuotes didn't detect.
* The `@stylistic/declaration-bang-space-before` rule detects a case in
`sdg/goals/show.scss` that BangFormat didn't detect.
There are also a couple of rules that don't behave exactly like they
used to:
* The equivalents of SpaceBetweenParens and SpaceAfterComma don't cover
parenthesis or commas in mixin parameters; we haven't found rules that
detect these cases.
* DisableLinterReason probably has an equivalent that behaves
differently but, since we never disable linters inline, we aren't
adding its equivalent rule.
Note we're removing the SpaceAfterVariableColon rule because its
equivalent, `scss/dollar-variable-colon-space-after`, reports cases
where we add spaces to indent several variable assignments (which we do
a lot in the `_consul_settings.scss` file). We might add this rule again
if we stop aligning consecutive assignments.
We're also removing the QualifyingElement rule because its equivalent,
`selector-no-qualifying-type: true`, behaves differently. For example,
in this code:
```
a.qualifying {
color: inherit;
}
p {
&.qualifying {
color: inherit;
}
}
```
With the QualifyingElement from SCSS Lint, the first rule is incorrect
but the second one is correct. With the selector-no-qualifying-type rule
from Stylelint, on the other hand, both rules are incorrect.
Personally, I never liked the QualifyingElement rule, and we were
working around it anyway, so we aren't applying
selector-no-qualifying-type.
For reference, here's a full list of the SCSS Lint rules we had enabled
and their Stylelint equivalents.
BangFormat
"@stylistic/declaration-bang-space-after": "never"
"@stylistic/declaration-bang-space-before": "always"
BorderZero
declaration-property-value-disallowed-list:
border:
- none
ColorKeyword
color-named: "never"
DebugStatement
at-rule-disallowed-list:
- debug
DeclarationOrder
order/order:
- dollar-variables
- custom-properties
- type: at-rule
name: extend
- type: at-rule
name: include
hasBlock: false
- declarations
- type: at-rule
name: include
hasBlock: true
- rules
ElsePlacement # Apparently replaced by the combination of:
scss/at-else-closing-brace-space-after: always-intermediate
scss/at-else-empty-line-before: never
scss/at-if-closing-brace-space-after: always-intermediate
scss/at-if-closing-brace-newline-after: always-last-in-chain
EmptyLineBetweenBlocks:
ignore_single_line_blocks: true
rule-empty-line-before:
- "always-multi-line"
- ignore:
- after-comment
- first-nested
EmptyRule:
block-no-empty: true
FinalNewline
"@stylistic/no-missing-end-of-source-newline": true
HexLength
color-hex-length: "short"
HexNotation
@stylistic/color-hex-case: "lower"
HexValidation
color-no-invalid-hex: true
IdSelector
selector-max-id: 0
ImportPath
scss/load-no-partial-leading-underscore: true
scss/at-import-partial-extension: never
Indentation
"@stylistic/indentation": 2
LeadingZero
@stylistic/number-leading-zero: "always"
NameFormat
scss/at-function-pattern: "^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$"
scss/at-mixin-pattern: "^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$"
scss/dollar-variable-pattern: "^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$"
scss/percent-placeholder-pattern: "^(-?[a-z][a-z0-9]*)(-[a-z0-9]+)*$"
NestingDepth
max-nesting-depth: 4
PlaceholderInExtend
scss/at-extend-no-missing-placeholder: true
PrivateNamingConvention
scss/no-unused-private-members: true
PropertySpelling
property-no-unknown: true
PseudoElement
selector-pseudo-element-colon-notation: "double"
selector-pseudo-element-no-unknown: true
SelectorDepth
selector-max-compound-selectors: 5
SelectorFormat # Not always followed; ssb-whatsapp_app
custom-property-pattern: "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$"
selector-class-pattern: "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$"
Shorthand
shorthand-property-no-redundant-values: true
SingleLinePerProperty
"@stylistic/declaration-block-semicolon-newline-after": always-multi-line
SingleLinePerSelector
@stylistic/selector-list-comma-newline-after": always
SpaceAfterComma
"@stylistic/value-list-comma-space-after": always
SpaceAfterPropertyColon
"@stylistic/declaration-colon-space-after": always-single-line
SpaceAfterPropertyName
"@stylistic/declaration-colon-space-before": never
SpaceAfterVariableName
scss/dollar-variable-colon-space-before: never
SpaceAroundOperator
scss/operator-no-unspaced: true
SpaceBeforeBrace
@stylistic/block-opening-brace-space-before: always
SpaceBetweenParens
"@stylistic/function-parentheses-space-inside": never
"@stylistic/selector-attribute-brackets-space-inside": never
"@stylistic/selector-pseudo-class-parentheses-space-inside": never
"@stylistic/media-feature-parentheses-space-inside": never
StringQuotes
"@stylistic/string-quotes": double
TrailingSemicolon
"@stylistic/declaration-block-trailing-semicolon": always
TrailingWhitespace # Note it was enabled by the gem and not by us
"@stylistic/no-eol-whitespace": true
TrailingZero
"@stylistic/number-no-trailing-zeros": true
UnnecessaryMantissa
"@stylistic/number-no-trailing-zeros": true
UnnecessaryParentReference
scss/selector-no-redundant-nesting-selector: true
UrlQuotes
function-url-quotes: always
VendorPrefixes
value-no-vendor-prefix: true
selector-no-vendor-prefix: true
property-no-vendor-prefix: true
at-rule-no-vendor-prefix: true
media-feature-name-no-vendor-prefix: true
ZeroUnit:
length-zero-no-unit: true
Using the `document` or `documents` classes meant styles defined for the
public list of documents conflict with these ones.
So now we're using HTML classes that match the name of the Ruby
component classes, as we usually do.
The Web Content Accessibility Guidelines version 2.1 added a success
criterion called Non-text Contrast [1], which mentions that the focus
indicator must contrast with the background, and version 2.2 introduced
a specific one regarding focus appearance [2]. According to that
criterion, the focus indicator:
* is at least as large as the area of a 2 CSS pixel thick perimeter of
the unfocused component or sub-component
* has a contrast ratio of at least 3:1 between the same pixels in the
focused and unfocused states.
Our current solution for highlighting elements on focus has a couple of
issues:
* It doesn't offer enough contrast against the default white background
(1.6:1)
* It offers even less contrast against other backgrounds, like the
homepage banner or the featured proposals/debates
Making the color of the outline darker would increase the contrast
against these backgrounds, but it would reduce the contrast against
other backgrounds like our default brand color.
For this reason, most modern browsers use a special double outline with
two different colors [3], and we're choosing to combine an outline and a
box shadow to emulate it, using the brand color as the second color.
However, this double-colored outline doesn't work so well when focusing
on dark buttons surrounded by a light background, so instead we're using
a triple outline, which works well on any color combination [4]. Since I
feel that making the third outline 2px wide makes the overall outline
too wide, I'm making the inner outline just 1px wide since that's enough
to prevent edge cases.
Note that Foundation adds a transition for the `box-shadow` property on
`select` controls, which gets in the way of the focus we use on the
language selector. So we're removing the transition.
Also note that the box-shadow style didn't work properly with the
box-shadow we added on the `:hover` status on cards, so we're changing
the code in order to cover this case.
Finally, note that the box-shadow isn't displayed properly on multiline
links (in Chrome, not even with `box-decoration-break: clone`), like the
ones in debates/proposals/polls/investments/processes titles, so we're
changing the style of these links to `inline-block`.
[1] https://www.w3.org/TR/WCAG21/#non-text-contrast
[2] https://www.w3.org/TR/WCAG22/#focus-appearance
[3] https://www.sarasoueidan.com/blog/focus-indicators/#examining-(current)-browser-focus-indicators-against-wcag-requirements
[4] https://www.erikkroes.nl/blog/the-universal-focus-state/
In some cases, like SDG icons and the proposals map, the image was
bigger than the link containing it, resulting in a funny-looking outline
on focus.
For reasons I don't understand, using `&:active,&:focus:active` didn't
compile to the CSS I was expecting, so I'm repeating the same code for
these two separate cases.
This way it's going to be easier to style the link on focus, since
styles like `box-shadow` weren't working properly when we had an inline
link with block elements inside, and adding the `display: inline-block`
element to the link didn't play well with the layout we were using for
the recommendations.
We're also fixing the focus outline on recommendations, which didn't
look properly because of the border added with:
```
.recommended-index {
// (...)
@include full-width-border(top, 1px solid #fafafa);
}
```
The border was on top of the outline, breaking it. Increasing the
`z-index` of the element containing the outline solves the issue.
In a similar way, we're making sure the button to hide recommendations
stays visible so it's easier to click it.
Some institutions using CONSUL have expressed interest in this feature
since some of their tenants might already have their own domains.
We've considered many options for the user interface to select whether
we're using a subdomain or a domain, like having two separate fields,
using a check box, ... In the end we've chosen radio buttons because
they make it easier to follow a logical sequence: first you decide
whether you're introducing a domain or subdomain, and then you enter it.
We've also considered hiding this option and assuming "if it's got a
dot, it's a domain". However, this wouldn't work with nested subdomains
and it wouldn't work with domains which are simply machine names.
Note that a group of radio buttons (or check boxes) is difficult to
style when the text of the label might expand over more than one line
(as is the case here on small screens); in this case, most solutions
result in the second line of the label appearing immediately under the
radio button, instead of being aligned with the first line of the label.
That's why I've added a container for the input+label combination.
Just like we did with SCSS variables, we use the `--main-header` CSS
variable and, if it isn't defined, we use the `--brand` CSS variable
instead.
Note that we're still using the `inverted-selection` mixin based on the
default `$main-header` color, so it's possible that we get the inverted
selection in the main header when using a dark color with `$main-header`
but a light color with `--main-header`, which doesn't make much sense.
Not sure whether there's anything we can do about it.
Until now, overwriting the styles for a certain tenant was a very
tedious task. For example, if we wanted to use a different brand color
for a tenant, we had to manually overwrite the styles for every element
using that color.
It isn't possible to use different SCSS variables per tenant unless we
generate a different stylesheet per tenant. However, doing so would make
the CSS compilation take way too long on installations with more than a
couple of tenants, and it wouldn't allow to get the colors dynamically
from the database, which we intend to support in the future.
So we're using CSS variables instead. These variables are supported by
97% of the browsers (as of October 2022), and for the other 3% of the
browsers we're using the default colors (SCSS variables) instead.
CSS variables have some limitations: for instance, it isn't possible to
use functions like `lighten`, `darken` or `scale-color` with CSS
variables, so the application might behave in a strange way when we use
these functions.
It also isn't possible to automatically get whether black or white text
makes a better contrast with a certain background color. To overcome
this limitation, we're providing variables ending with `-contrast`. For
instance, since the default `$brand` color is a dark one, when assigning
a light color to `--brand`, we probably want to assign
`--brand-contrast: #{$black}` as well, so the text is still readable.
Back in commit 5dbd69486, I said:
> I'm choosing to use the same color for solid and hollow buttons
> because these elements are usually isolated and so from the UX
> perspective they are similar; links, on the other hand, are often in
> the middle of some text.
However, I made a mistake. The crucial factor is that solid buttons
might have a light background if we choose the brand color to be a light
one, and in this case they automatically get black text. However, hollow
buttons always have a light background and so we can't use a light color
for the text and border of these buttons.
This is consistent with the usage of `$body-background`. This way
Foundation elements using `$body-font-color`, like the `<body>` tag,
will be changed when changing this variable, which wouldn't happen when
using `$text`.
The variables `$anchor-color` and `$anchor-color-hover` are the ones
Foundation uses internally; by using them, we make sure every link will
use the colors we define.
Now we can simplify the default styles for the `<a>` tags, since by
default they already use these variables.
This way we simplify the code a bit.
Note we're only using this function when variables for background colors
are already defined, since that means customizing the variable using the
background color will automatically change the color of the text.
Customization isn't easier when using raw colors.
We were defining (for instance) white text against the `$brand`
background. That meant that, if somebody customized the `$brand` color
so it used a light color, they had to customize the text color as well
in order to guarantee proper contrast between text and background
colors.
So we're using `color-pick-contrast` instead, which means we don't have
to manually calculate whether white or black will be the color which
makes the text more readable.
Should hollow buttons use the same color as links do or the same color
as solid buttons do? In the default scenario, it doesn't matter, since
links and solid buttons use the same color. However, it matters when
people customize the application so links and solid buttons don't use
the same color.
I'm choosing to use the same color for solid and hollow buttons because
these elements are usually isolated and so from the UX perspective they
are similar; links, on the other hand, are often in the middle of some
text.
Note we're talking about links and buttons while many of the "buttons"
we use in the application are actually links styled as buttons. Here,
"buttons" means "things that look like buttons".
We are use a display: block style for labels containing check boxes inside
them, and the label has a width of 100%.
This means that clicking on the blank space on the right of the label text
will check/uncheck the checkbox. To avoid this behaviour we modify the
"display" attribute of the labels.
In order to prevent unexpected behaviour in terms_of_service form labels,
we add specific css for this case when define a checkbox within the
.actions class.
The buttons to create polls associated with a budget were too prominent,
appearing on the table as if they were as used as the link to manage
investments. Most CONSUL installations don't use physical booths, and
would probably wonder what that button is about.
We're moving it to a more discrete place, at the bottom of the budget
page. This way we can also split the action in two: on budgets not
having a poll, we display the button in a not-so-accessible position (at
the bottom of the page), since this button will only be used once per
budget at most. Once the poll has been created, it means this feature is
going to be used, so we display a link to manage ballots more
prominently at the top of the page. If the budget has finished the final
voting stage without creating a poll, we don't show either the link or
the button because this feature can no longer be used.
We're also adding some texts indicating what this feature is about,
since it's probably one of the least understood features in CONSUL
(probably because the interface is very confusing... but that's a
different story).
Since now from the budget page we can access every feature related to
the budget, we can remove the "preview" action from the budgets index
table, since this feature isn't that useful for budgets once they're
published.
Now the budgets table doesn't take as much space as it used to, although
it's still too wide to be handled properly on devices with a small
screen.
Since managing investments is a very common action, with this link
administrators won't have to go back to the index page to manage
investments; they can access it from either the budgets index page or
the budget page.
Since now the links we've got on the budget page are similar to the ones
we've got in the index page table, we're styling them in a similar way.
We're also fixing a small typo en the investments path; it works exactly
the same way as it used to, but passing `budget` instead of `budget_id:
budget.id` is shorter and more consistent with what we do in other
places.
Before, users needed to navigate to the list of groups in order to
add, edit or delete a group.
Also, they need to navigate to the list of groups first, and then to
the list of headings for that group in order to add, edit or delete a
heading.
Now, it's possible to do all these actions for any group or heading
from the participatory budget view to bring simplicity and to reduce
the number of clicks from a user perspective.
Co-Authored-By: Javi Martín <javim@elretirao.net>
Even if it was looking OK using `margin-left`, there were probably edge
cases where it wouldn't behave as we expected.
As mentioned in the previous commit, this won't be necessary once
everyone uses browsers supporting the `gap` property in flexbox layouts,
but this won't happen for a few years.
In a few months we might also consider using the `margin-inline-start`
property, which is currently supported by about 97% of the browsers [1].
[1] https://caniuse.com/css-logical-props
This way we remove duplication and it'll be easier to add better support
for RTL languages.
In a few years this might not be necessary since support for the `gap`
property in a flexbox layout will improve. At the time of writing,
however, only 86.5% of the browsers support it [1].
[1] https://caniuse.com/flexbox-gap
Since the icon was absolutely positioned, in some languages it
overlapped with the text.
Using a flex layout solves this issue. It also improves the appearance
of elements whose text spans over multiple lines; previously the second
line would go under their section icon.
We're also using the `$global-left` variable so the icon is properly
displayed in languages written from right to left. We could use the
`margin-inline-start` property instead, but it isn't universally
supported in every browser yet.
Since the layout is now incompatible with the old (and obsolete) way to
add icons to the menu (using classes which would use the
`[class^="icon-"]` selector), we're removing this code.
We were using buttons with the "Enable" and "Disable" texts to
enable/disable settings. However, when machine learning settings were
introduced in commit 4d27bbeba, a switch control was introduced to
enable/disable them.
In order to keep the interface consistent, we're now using switch
controls in other sections where settings are enabled/disabled. We can
even use the same code in the machine learning settings as well.
We're also removing the confirmation dialog to enable/disable a setting,
since the dialog is really annoying when changing several settings and
this action can be undone immediately. The only setting which might need
a confirmation is the "Skip user verification" one; we might add it in
the future. Removing the confirmation here doesn't make things worse,
though; the "Are you sure?" confirmation dialog was also pretty useless
and users would most likely blindly accept it.
Note Capybara doesn't support finding a button by its `aria-labelledby`
atrribute. Ideally we'd write `click_button "Participatory budgeting"`
instead of `click_button "Yes"`, since from the user's point of view the
"Yes" or "No" texts aren't button labels but indicators of the status of
the setting. This makes the code a little brittle since tests would pass
even if the element referenced by `aria-labelledby` didn't exist.
We were using a focus outline on links, but weren't doing the same for
buttons. Since sometimes browsers use a default outline which is barely
visible, this was very disorienting when browsing using the keyboard; we
were navigating through links that clearly indicated where the keyboard
focus was, and when reaching a button suddenly we had this almost
imperceptible feedback. Even if I'm used to it, my first reaction is
always "where did the focus go?" until I realize it's now on a button.
This is even more confusing because we've got buttons looking like links
and links looking like buttons.
Note that in the rules for the `:focus` styles we're including buttons
and the `[type="button"]` attribute. This seems redundant since those
styles are already covered by the `button` selector. However, Foundation
adds styles to buttons with the `[type]` attribute. Since the attribute
selector has precedence over the tag selector, we need to use the
attribute selector as well in order to override Foundation's styles.
The budget header was supposed to be huge, but only in the participatory
budgets index or show actions. It was still huge, with plenty of empty
space, when there was no budget, or in the "submit my ballot" and
"select a heading" pages.
In commit cc6f9391f we made the images and documents file inputs
invisible (instead of using `display: none`) in order to make it
possible to attach images and documents using the keyboard.
However, since the error messages associated to these inputs has the
same HTML class as the inputs, we were also hiding them (the `display:
none` didn't affect the error messages because they've also got the
`is-visible` class).
Using the `[type=file]` selector we make it more explicit that we only
want to style these inputs.
I'm not adding a test for this scenario because technically the text is
there and I'm not sure how to test for the presence of invisible
elements.
We were hiding the file input and styling the label as a button instead.
Since clicking on a label has the same effect as clicking on the input,
the input worked properly for mouse and touch screen users.
However, hiding the input makes it inaccessible for keyboard users,
since labels don't get keyboard focus, but inputs do.
So we must not hide the input but make it invisible instead. But we
still need to hide the input (alongside the label) after a file has been
attached.
We could add some extra JavaScript to hide the input when we hide the
label. Since the JavaScript is already quite complex and my first few
attempts at changing it failed, I've opted to assume that the input (and
its label) must be hidden whenever there's already a file name, and
implement that rule with CSS.
Note we're using the `:focus-within` pseudoclass to style a label when
focus is on the input. This rule (at the time of writing) is only
supported by 93.5% of the browsers. Keyboard users without a screen
reader and using the other 6.5% of the browsers will still be able to
focus on the field but might not notice the field has received focus.
Since the percentage of affected users will decrease over time and until
now 100% of keyboard users were completely unable to focus on these
fields, for now we think this is a good-enough solution.
This way screen reader users will hear the name of the file before
hearing about the link to destroy it. We were already displaying it this
way visually by having the file name on the left and the destroy link on
the right.
Thanks to this change we can also simplify the code which dynamically
changed the layout.