MOBILE-4565 a11y: Improve quiz styles

main
Pau Ferrer Ocaña 2024-04-23 13:31:51 +02:00
parent a67cf4de7f
commit 4a20edc06a
19 changed files with 309 additions and 276 deletions

View File

@ -27,8 +27,8 @@
<ion-list class="ion-no-margin">
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()"
[attr.aria-label]="'addon.messages.contacts' | translate" [detail]="true" button>
<ion-item class="ion-text-wrap" (click)="gotoContacts()" [attr.aria-label]="'addon.messages.contacts' | translate"
[detail]="true" button>
<ion-icon name="fas-address-book" slot="start" aria-hidden="true" />
<ion-label>
<p class="item-heading">{{ 'addon.messages.contacts' | translate }}</p>

View File

@ -27,7 +27,7 @@
<core-loading [hideUntil]="loaded" [message]="loadingMessage">
<ion-list>
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()" [detail]="true" button>
<ion-item class="ion-text-wrap" (click)="gotoContacts()" [detail]="true" button>
<ion-icon name="fas-address-book" slot="start" aria-hidden="true" />
<ion-label>
<p class="item-heading">{{ 'addon.messages.contacts' | translate }}</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -47,7 +47,7 @@
</h2>
</ion-label>
<div *ngIf="question.status || question.readableMark" slot="end"
class="ion-text-wrap ion-margin-horizontal addon-mod_quiz-question-note">
class="ion-text-wrap ion-margin-start addon-mod_quiz-question-note">
<p *ngIf="question.status" class="block">{{question.status}}</p>
<p *ngIf="question.readableMark" [innerHTML]="question.readableMark"></p>
</div>

View File

@ -6,6 +6,8 @@ $quiz-timer-iterations: 15 !default;
:host {
.addon-mod_quiz-question-note p {
font-weight: normal;
font-size: var(--mdl-typography-fontSize-md);
margin-top: 2px;
margin-bottom: 2px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,18 +1,20 @@
<section class="addon-qtype-match-container" *ngIf="question && question.loaded">
<ion-item class="ion-text-wrap">
<ion-item class="ion-text-wrap question-text">
<ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId" />
</ion-label>
</ion-item>
<ion-item class="ion-text-wrap" *ngFor="let row of question.rows">
<ion-item class="ion-text-wrap question-rows" *ngFor="let row of question.rows">
<ion-select id="{{row.id}}" [name]="row.name" [(ngModel)]="row.selected" interface="action-sheet" [disabled]="row.disabled"
[cancelText]="'core.cancel' | translate"
[ngClass]="{'addon-qtype-match-correct': row.isCorrect === 1,'addon-qtype-match-incorrect': row.isCorrect === 0}">
<div slot="label" class="flew-row">
<core-format-text [component]="component" [componentId]="componentId" [text]="row.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId" />
<div slot="label" class="flex-row ion-text-wrap">
<div>
<core-format-text [component]="component" [componentId]="componentId" [text]="row.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId" />
</div>
<label class="accesshide" for="{{row.id}}" *ngIf="row.accessibilityLabel">
{{ row.accessibilityLabel }}
</label>

View File

@ -15,11 +15,14 @@
flex-grow: 1;
}
div.flew-row {
div.flex-row {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
ion-item.question-rows {
--inner-padding-top: var(--mdl-spacing-2);
--inner-padding-bottom: var(--mdl-spacing-2);
}
}

View File

@ -51,7 +51,6 @@
border-top: 1px solid var(--info);
background: var(--background);
flex-shrink: 1;
font-size: 1.1rem;
.icon {
color: var(--info);

View File

@ -1014,7 +1014,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
// Draft saved, notify the user.
this.lastDraft = newText;
this.showMessage('core.editor.autosavesucceeded', this.SAVE_MESSAGE_CLEAR_TIME);
} catch (error) {
} catch {
// Error saving draft.
}
}, this.DRAFT_AUTOSAVE_FREQUENCY);

View File

@ -21,7 +21,9 @@
[attr.aria-current]="courses.getItemAriaCurrent(course)" class="ion-text-wrap" button [detail]="true"
(click)="courses.select(course)">
<ion-label>
<core-format-text [text]="course.courseFullName" [contextInstanceId]="course.courseid" contextLevel="course" />
<p class="item-heading">
<core-format-text [text]="course.courseFullName" [contextInstanceId]="course.courseid" contextLevel="course" />
</p>
</ion-label>
<ion-badge slot="end" color="light">
<span class="sr-only" *ngIf="course.grade && course.grade !== '-'">

View File

@ -11,11 +11,9 @@ ion-item.item.divider {
ion-label h2,
ion-label p.item-heading {
font-size: var(--item-divider-font-size);
font-weight: 500;
line-height: 1.5;
font: var(--mdl-typography-subtitle-font-md);
}
ion-label h2.big {
font-size: var(--item-divider-font-size-big);
font: var(--mdl-typography-subtitle-font-lg);
}
}

View File

@ -1,8 +1,13 @@
ion-item {
ion-item.item {
--detail-icon-color: var(--ion-item-detail-icon-color);
--detail-icon-font-size: var(--ion-item-detail-icon-font-size);
--detail-icon-opacity: var(--ion-item-detail-icon-opacity);
ion-input.in-item,
&.item-label > ion-label.label-stacked {
font-size: var(--mdl-typography-fontSize-lg);
}
> ion-icon[slot] {
color: var(--ion-item-icon-color);
}
@ -64,7 +69,7 @@ div.fake-ion-item {
}
.md div.fake-ion-item {
font-size: 16px;
font-size: var(--text-size);
font-weight: normal;
text-transform: none;
@include padding(null, 16px, null, 16px);
@ -139,3 +144,175 @@ div.fake-ion-item {
}
}
// Item Headings.
// Some styles taken from ion-label
ion-item.item.item-label > ion-label,
.fake-ion-item > ion-label,
ion-item .in-item {
font-size: var(--text-size);
p {
--color: var(--subdued-text-color);
color: var(--color);
@include margin(2px, 0);
}
.item-heading {
@include margin(2px, 0);
font-size: 1rem;
font-weight: normal;
text-overflow: inherit;
overflow: inherit;
--color: initial;
color: var(--color);
&.item-heading-secondary {
@include margin(2px, 0);
font-size: var(--text-size);
font-weight: normal;
line-height: normal;
--color: var(--subdued-text-color);
}
}
}
// Correctly inherit ion-text-wrap onto labels.
.item > ion-label,
.fake-ion-item,
.item.ion-text-wrap > ion-checkbox::part(label),
ion-checkbox.ion-text-wrap::part(label) {
core-format-text,
core-format-text > *:not(pre) {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.item.ion-text-wrap > ion-label,
ion-item > .in-item,
.fake-ion-item.ion-text-wrap,
.item.ion-text-wrap > ion-checkbox::part(label),
ion-checkbox.ion-text-wrap::part(label) {
core-format-text,
core-format-text > *:not(pre) {
white-space: normal;
overflow: inherit;
}
}
.item.ion-text-wrap > ion-label,
.item.ion-text-wrap ion-checkbox::part(label),
ion-checkbox.ion-text-wrap::part(label),
.item.ion-text-wrap ion-radio::part(label),
ion-radio.ion-text-wrap::part(label) {
white-space: normal !important;
}
ion-item .core-input-errors-wrapper {
width: 100%;
}
ion-item.item.item-file {
ion-thumbnail {
--size: 32px;
width: var(--size);
height: var(--size);
}
p.item-heading {
font-size: var(--text-size);
}
p {
font-size: var(--mdl-typography-fontSize-sm);
}
ion-label {
margin-top: 8px;
margin-bottom: 8px;
}
ion-button {
--a11y-sizing-minTargetSize: 40px;
}
&.item-directory ion-icon {
@include margin-horizontal(0px, 16px);
}
[slot=end] {
@include margin-horizontal(16px, null);
}
}
.item-dimmed {
opacity: 0.7;
--background: var(--light);
ion-item {
--background: var(--light);
}
}
// Make links clickable when inside radio or checkbox items. Style part.
@media (hover: hover) {
ion-item.item-multiple-inputs:not(.item-rte):hover::part(native) {
color: var(--color-hover);
&::after {
background: var(--background-hover);
opacity: var(--background-hover-opacity);
}
}
ion-item.ion-color.item-multiple-inputs:hover::part(native) {
color: #{current-color(contrast)};
&::after {
background: #{current-color(contrast)};
}
}
}
// It fixes the click on links where ion-ripple-effect is present.
// Make links clickable when inside radio or checkbox items. Pointer and cursor part.
ion-item.item-multiple-inputs:not(.only-links):not(.item-rte),
ion-item.ion-activatable:not(.only-links) {
cursor: pointer;
ion-label {
z-index: 3;
pointer-events: none;
ion-anchor, a,
ion-button, button,
ion-item.ion-focusable,
audio, video, select, input, iframe {
pointer-events: visible;
}
}
ion-checkbox, ion-datetime, ion-radio, ion-select{
position: static;
}
}
ion-item.item-multiple-inputs.only-links {
a {
cursor: pointer;
}
}
// Case with ion-input + ion-select inside.
ion-item.item-input.item-multiple-inputs {
.flex-row {
width: 100%;
ion-select {
position: relative;
}
}
}

View File

@ -0,0 +1,81 @@
// Select.
ion-select {
&::part(text) {
white-space: normal;
}
&::part(icon) {
opacity: 1;
}
}
ion-select-popover {
ion-list ion-radio-group ion-item.select-interface-option ion-radio.hydrated::part(container) {
opacity: 1;
}
ion-item {
font-size: var(--text-size);
}
ion-item.core-select-option-border-bottom {
border-bottom: 1px solid var(--stroke);
}
ion-item.core-select-option-title {
cursor: pointer;
ion-radio::part(container) {
display: none;
}
}
}
// Case with ion-input + ion-select inside.
ion-item.item-input.item-multiple-inputs {
.flex-row {
width: 100%;
ion-select {
position: relative;
}
}
}
.select-alert.ios {
.alert-checkbox-icon {
border-radius: 2px;
}
.alert-radio-icon {
height: var(--size);
width: var(--size);
min-width: var(--size);
border-radius: var(--border-radius);
border-width: var(--outer-border-width);
border-style: var(--border-style);
border-color: var(--color);
@include margin(10px, 8px, 10px, 8px);
display: flex;
align-items: center;
justify-content: center;
.alert-radio-inner {
top: auto;
left: auto;
position: static;
border-radius: var(--inner-border-radius);
width: calc(50% + var(--outer-border-width));
height: calc(50% + var(--outer-border-width));
transform: scale3d(0, 0, 0);
transition: transform 280ms cubic-bezier(.4, 0, .2, 1);
background: var(--contrast-background);
border: 0 !important;
}
}
button[aria-checked=true] .alert-radio-icon {
border-color: var(--color-checked);
background: var(--color-checked);
.alert-radio-inner {
transform: scale3d(1, 1, 1);
}
}
}

View File

@ -72,77 +72,6 @@ html[dir=rtl] {
.font-lg { font-size: 1.7rem; }
.font-sm { font-size: 1.2rem; }
// Item Headings.
// Some styles taken from ion-label
.item > ion-label,
.fake-ion-item > ion-label,
ion-item .in-item {
p {
--color: var(--subdued-text-color);
color: var(--color);
@include margin(2px, 0);
font-size: 0.875rem;
}
.item-heading {
@include margin(2px, 0);
font-size: 1rem;
font-weight: normal;
text-overflow: inherit;
overflow: inherit;
--color: initial;
color: var(--color);
&.item-heading-secondary {
@include margin(2px, 0);
font-size: var(--text-size);
font-weight: normal;
line-height: normal;
--color: var(--subdued-text-color);
}
}
}
// Correctly inherit ion-text-wrap onto labels.
.item > ion-label,
.fake-ion-item,
.item.ion-text-wrap > ion-checkbox::part(label),
ion-checkbox.ion-text-wrap::part(label) {
core-format-text,
core-format-text > *:not(pre) {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.item.ion-text-wrap > ion-label,
ion-item > .in-item,
.fake-ion-item.ion-text-wrap,
.item.ion-text-wrap > ion-checkbox::part(label),
ion-checkbox.ion-text-wrap::part(label) {
core-format-text,
core-format-text > *:not(pre) {
white-space: normal;
overflow: inherit;
}
}
.item.ion-text-wrap > ion-label,
.item.ion-text-wrap ion-checkbox::part(label),
ion-checkbox.ion-text-wrap::part(label),
.item.ion-text-wrap ion-radio::part(label),
ion-radio.ion-text-wrap::part(label) {
white-space: normal !important;
}
ion-item .core-input-errors-wrapper {
width: 100%;
}
@each $color-name, $unused in $colors {
.text-#{$color-name},
@ -566,47 +495,6 @@ body.core-iframe-fullscreen ion-router-outlet {
}
}
.item.item-file {
ion-thumbnail {
--size: 32px;
width: var(--size);
height: var(--size);
}
p.item-heading {
font-size: var(--text-size);
}
p {
font-size: 12px;
}
ion-label {
margin-top: 8px;
margin-bottom: 8px;
}
ion-button {
--a11y-sizing-minTargetSize: 40px;
}
&.item-directory ion-icon {
@include margin-horizontal(0px, 16px);
}
[slot=end] {
@include margin-horizontal(16px, null);
}
}
.item-dimmed {
opacity: 0.7;
--background: var(--light);
ion-item {
--background: var(--light);
}
}
// Extra text colors.
.text-gray {
color: var(--gray-500);
@ -626,24 +514,39 @@ body.core-iframe-fullscreen ion-router-outlet {
--background: var(--color-tint);
--color: var(--color-shade);
ion-item {
ion-item.item {
--background: var(--color-tint);
--color: var(--color-shade);
--inner-border-width: 0px;
--border-width: 0px;
font-size: var(--text-size);
ion-label, ion-label > p {
&.item-label > ion-label,
&.item-label > ion-label > p {
--color: var(--color-shade);
}
> ion-icon[slot] {
color: var(--color-shade);
@include margin-horizontal(null, 16px);
}
}
ion-label {
white-space: normal !important;
}
ion-item > ion-icon[slot] {
color: var(--color-shade);
@include margin-horizontal(null, 16px);
}
ion-item.item.core-#{$color-name}-item {
--color-base: var(--ion-color-#{$color-name});
--color-shade: var(--ion-color-#{$color-name}-shade);
--border-width: 0 0 3px 0;
--border-color: var(--color-base);
--inner-border-width: 0px;
> ion-icon[slot] {
color: var(--color-base);
}
}
@ -748,7 +651,7 @@ ion-toolbar h1 .core-bar-button-image img {
// Radio.
ion-radio,
input[type=radio],
.select-alert.ios .alert-radio-icon {
.select-alert .alert-radio-icon {
--border-radius: 50%;
--border-width: 2px;
--outer-border-width: 2px;
@ -761,7 +664,6 @@ input[type=radio],
}
}
.ios ion-radio,
.ios input[type=radio],
.select-alert.ios .alert-radio-icon {
@ -803,43 +705,6 @@ input[type=radio],
}
}
.select-alert.ios {
.alert-radio-icon {
height: var(--size);
width: var(--size);
min-width: var(--size);
border-radius: var(--border-radius);
border-width: var(--outer-border-width);
border-style: var(--border-style);
border-color: var(--color);
@include margin(10px, 8px, 10px, 8px);
display: flex;
align-items: center;
justify-content: center;
.alert-radio-inner {
top: auto;
left: auto;
position: static;
border-radius: var(--inner-border-radius);
width: calc(50% + var(--outer-border-width));
height: calc(50% + var(--outer-border-width));
transform: scale3d(0, 0, 0);
transition: transform 280ms cubic-bezier(.4, 0, .2, 1);
background: var(--contrast-background);
border: 0 !important;
}
}
button[aria-checked=true] .alert-radio-icon {
border-color: var(--color-checked);
background: var(--color-checked);
.alert-radio-inner {
transform: scale3d(1, 1, 1);
}
}
}
// Checkbox.
ion-checkbox,
@ -857,48 +722,10 @@ input[type=checkbox] {
}
}
.ios input[type=checkbox] {
--outer-border-width: 1px;
}
.select-alert.ios .alert-checkbox-icon {
border-radius: 2px;
}
// Select.
ion-select {
&::part(text) {
white-space: normal;
}
&::part(icon) {
opacity: 1;
}
&::part(label) {
max-width: none;
}
}
ion-select-popover {
ion-list ion-radio-group ion-item.select-interface-option ion-radio.hydrated::part(container) {
opacity: 1;
}
ion-item {
font-size: 14px;
}
ion-item.core-select-option-border-bottom {
border-bottom: 1px solid var(--stroke);
}
ion-item.core-select-option-title {
cursor: pointer;
ion-radio::part(container) {
display: none;
}
}
}
ion-badge {
line-height: 1.1;
padding: 2px 8px;
@ -1048,65 +875,6 @@ ion-datetime.datetime-disabled {
opacity: .65 !important;
}
// Make links clickable when inside radio or checkbox items. Style part.
@media (hover: hover) {
ion-item.item-multiple-inputs:not(.item-rte):hover::part(native) {
color: var(--color-hover);
&::after {
background: var(--background-hover);
opacity: var(--background-hover-opacity);
}
}
ion-item.ion-color.item-multiple-inputs:hover::part(native) {
color: #{current-color(contrast)};
&::after {
background: #{current-color(contrast)};
}
}
}
// It fixes the click on links where ion-ripple-effect is present.
// Make links clickable when inside radio or checkbox items. Pointer and cursor part.
ion-item.item-multiple-inputs:not(.only-links):not(.item-rte),
ion-item.ion-activatable:not(.only-links) {
cursor: pointer;
ion-label {
z-index: 3;
pointer-events: none;
ion-anchor, a,
ion-button, button,
ion-item.ion-focusable,
audio, video, select, input, iframe {
pointer-events: visible;
}
}
ion-checkbox, ion-datetime, ion-radio, ion-select{
position: static;
}
}
ion-item.item-multiple-inputs.only-links {
a {
cursor: pointer;
}
}
// Case with ion-input + ion-select inside.
ion-item.item-input.item-multiple-inputs {
.flex-row {
width: 100%;
ion-select {
position: relative;
}
}
}
ion-item-divider.item,
ion-item.item,
td {

View File

@ -201,8 +201,6 @@ html {
--item-divider-min-height: calc(var(--a11y-sizing-minTargetSize) + 8px);
--item-divider-border-width: 0px;
--item-divider-font-size: 16px;
--item-divider-font-size-big: 20px;
--spacer-vertical: 8px;
@ -250,4 +248,6 @@ html {
--a11y-min-target-size: var(--a11y-sizing-minTargetSize);
--a11y-focus-width: var(--a11y-shadow-focus-boxShadowSpread);
--a11y-focus-color: var(--a11y-shadow-focus-boxShadowColor);
--item-divider-font-size: var(--mdl-typography-subtitle-fontSize-md);
--item-divider-font-size-big: var(--mdl-typography-subtitle-fontSize-lg);
}

View File

@ -42,6 +42,7 @@ html {
@import "components/ion-note.scss";
@import "components/ion-popover.scss";
@import "components/ion-searchbar.scss";
@import "components/ion-select.scss";
@import "components/ion-spinner.scss";
@import "components/ion-toast.scss";
@import "components/swiper.scss";