Poll creator:
Non-anonymous mode support; Multiple choice mode support; Quiz mode support; Fix revote rights;
This commit is contained in:
parent
bc4c892880
commit
8d9a8b6261
@ -2,7 +2,7 @@ import appChatsManager from "../../lib/appManagers/appChatsManager";
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import appPollsManager from "../../lib/appManagers/appPollsManager";
|
||||
import appPollsManager, { Poll } from "../../lib/appManagers/appPollsManager";
|
||||
import $rootScope from "../../lib/rootScope";
|
||||
import { findUpClassName } from "../../lib/utils";
|
||||
import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu";
|
||||
@ -67,7 +67,7 @@ export class ChatContextMenu {
|
||||
icon: 'edit',
|
||||
text: 'Edit',
|
||||
onClick: this.onEditClick,
|
||||
verify: (peerID: number, msgID: number) => appMessagesManager.canEditMessage(msgID)
|
||||
verify: (peerID: number, msgID: number) => appMessagesManager.canEditMessage(msgID, 'text')
|
||||
}, {
|
||||
icon: 'copy',
|
||||
text: 'Copy',
|
||||
@ -84,8 +84,8 @@ export class ChatContextMenu {
|
||||
onClick: this.onRetractVote,
|
||||
verify: (peerID: number, msgID) => {
|
||||
const message = appMessagesManager.getMessage(msgID);
|
||||
const poll = message.media?.poll;
|
||||
return poll && !poll.pFlags.closed;
|
||||
const poll = message.media?.poll as Poll;
|
||||
return poll && poll.chosenIndexes.length && !poll.pFlags.closed && !poll.pFlags.quiz;
|
||||
}
|
||||
}, {
|
||||
icon: 'lock',
|
||||
@ -94,7 +94,7 @@ export class ChatContextMenu {
|
||||
verify: (peerID: number, msgID) => {
|
||||
const message = appMessagesManager.getMessage(msgID);
|
||||
const poll = message.media?.poll;
|
||||
return appMessagesManager.canEditMessage(msgID) && message.fromID == $rootScope.myID && message.fwd_from === undefined && poll && !poll.pFlags.closed;
|
||||
return appMessagesManager.canEditMessage(msgID, 'poll') && poll && !poll.pFlags.closed;
|
||||
}
|
||||
}, {
|
||||
icon: 'forward',
|
||||
|
17
src/components/checkbox.ts
Normal file
17
src/components/checkbox.ts
Normal file
@ -0,0 +1,17 @@
|
||||
const CheckboxField = (text: string, name: string) => {
|
||||
const label = document.createElement('label');
|
||||
label.classList.add('checkbox-field');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'checkbox';
|
||||
input.id = 'input-' + name;
|
||||
|
||||
const span = document.createElement('span');
|
||||
span.innerText = text;
|
||||
|
||||
label.append(input, span);
|
||||
|
||||
return {label, input, span};
|
||||
};
|
||||
|
||||
export default CheckboxField;
|
@ -1,7 +1,11 @@
|
||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../lib/appManagers/appPeersManager";
|
||||
import appPollsManager, { Poll } from "../lib/appManagers/appPollsManager";
|
||||
import $rootScope from "../lib/rootScope";
|
||||
import { findUpTag, whichChild } from "../lib/utils";
|
||||
import CheckboxField from "./checkbox";
|
||||
import { PopupElement } from "./popup";
|
||||
import RadioField from "./radioField";
|
||||
import Scrollable from "./scrollable";
|
||||
import { toast } from "./toast";
|
||||
|
||||
@ -23,6 +27,13 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
private scrollable: Scrollable;
|
||||
private tempID = 0;
|
||||
|
||||
private anonymousCheckboxField: ReturnType<typeof CheckboxField>;
|
||||
private multipleCheckboxField: PopupCreatePoll['anonymousCheckboxField'];
|
||||
private quizCheckboxField: PopupCreatePoll['anonymousCheckboxField'];
|
||||
|
||||
private correctAnswers: Uint8Array[];
|
||||
private quizSolutionInput: HTMLInputElement;
|
||||
|
||||
constructor() {
|
||||
super('popup-create-poll popup-new-media', null, {closable: true, withConfirm: 'CREATE', body: true});
|
||||
|
||||
@ -38,11 +49,71 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
d.classList.add('caption');
|
||||
d.innerText = 'Options';
|
||||
|
||||
this.questions = document.createElement('div');
|
||||
this.questions = document.createElement('form');
|
||||
this.questions.classList.add('poll-create-questions');
|
||||
|
||||
const dd = document.createElement('div');
|
||||
dd.classList.add('poll-create-settings');
|
||||
|
||||
const settingsCaption = document.createElement('div');
|
||||
settingsCaption.classList.add('caption');
|
||||
settingsCaption.innerText = 'Settings';
|
||||
|
||||
const peerID = $rootScope.selectedPeerID;
|
||||
|
||||
if(!appPeersManager.isBroadcast(peerID)) {
|
||||
this.anonymousCheckboxField = CheckboxField('Anonymous Voting', 'anonymous');
|
||||
this.anonymousCheckboxField.input.checked = true;
|
||||
dd.append(this.anonymousCheckboxField.label);
|
||||
}
|
||||
|
||||
this.multipleCheckboxField = CheckboxField('Multiple Answers', 'multiple');
|
||||
this.quizCheckboxField = CheckboxField('Quiz Mode', 'quiz');
|
||||
|
||||
this.multipleCheckboxField.input.addEventListener('change', () => {
|
||||
const checked = this.multipleCheckboxField.input.checked;
|
||||
this.quizCheckboxField.input.toggleAttribute('disabled', checked);
|
||||
});
|
||||
|
||||
this.quizCheckboxField.input.addEventListener('change', () => {
|
||||
const checked = this.quizCheckboxField.input.checked;
|
||||
|
||||
(Array.from(this.questions.children) as HTMLElement[]).map(el => {
|
||||
el.classList.toggle('radio-field', checked);
|
||||
});
|
||||
|
||||
quizElements.forEach(el => el.classList.toggle('hide', !checked));
|
||||
|
||||
this.multipleCheckboxField.input.toggleAttribute('disabled', checked);
|
||||
});
|
||||
|
||||
dd.append(this.multipleCheckboxField.label, this.quizCheckboxField.label);
|
||||
|
||||
const quizElements: HTMLElement[] = [];
|
||||
|
||||
const quizSolutionCaption = document.createElement('div');
|
||||
quizSolutionCaption.classList.add('caption');
|
||||
quizSolutionCaption.innerText = 'Explanation';
|
||||
|
||||
const quizHr = document.createElement('hr');
|
||||
|
||||
const quizSolutionContainer = document.createElement('div');
|
||||
quizSolutionContainer.classList.add('poll-create-questions');
|
||||
|
||||
const quizSolutionField = InputField('Add a Comment (Optional)', 'Add a Comment (Optional)', 'solution');
|
||||
this.quizSolutionInput = quizSolutionField.firstElementChild as HTMLInputElement;
|
||||
|
||||
const quizSolutionSubtitle = document.createElement('div');
|
||||
quizSolutionSubtitle.classList.add('subtitle');
|
||||
quizSolutionSubtitle.innerText = 'Users will see this comment after choosing a wrong answer, good for educational purposes.';
|
||||
|
||||
quizSolutionContainer.append(quizSolutionField, quizSolutionSubtitle);
|
||||
|
||||
quizElements.push(quizHr, quizSolutionCaption, quizSolutionContainer);
|
||||
quizElements.forEach(el => el.classList.add('hide'));
|
||||
|
||||
this.body.parentElement.insertBefore(hr, this.body);
|
||||
this.body.append(d, this.questions);
|
||||
this.body.append(d, this.questions, document.createElement('hr'), settingsCaption, dd, ...quizElements);
|
||||
|
||||
this.confirmBtn.addEventListener('click', this.onSubmitClick);
|
||||
|
||||
@ -54,17 +125,22 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
const question = this.questionInput.value;
|
||||
|
||||
if(!question.trim()) {
|
||||
toast('Please enter a question');
|
||||
toast('Please enter a question.');
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.quizCheckboxField.input.checked && !this.correctAnswers?.length) {
|
||||
toast('Please choose the correct answer.');
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = Array.from(this.questions.children).map((el, idx) => {
|
||||
const input = (el.firstElementChild as HTMLInputElement);
|
||||
const input = el.querySelector('input[type="text"]') as HTMLInputElement;
|
||||
return input.value;
|
||||
}).filter(v => !!v.trim());
|
||||
|
||||
if(answers.length < 2) {
|
||||
toast('Please enter at least two options');
|
||||
toast('Please enter at least two options.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -74,8 +150,23 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
//const randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
|
||||
//const randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString();
|
||||
|
||||
const pFlags: Poll['pFlags'] = {};
|
||||
|
||||
if(this.anonymousCheckboxField && !this.anonymousCheckboxField.input.checked) {
|
||||
pFlags.public_voters = true;
|
||||
}
|
||||
|
||||
if(this.multipleCheckboxField.input.checked) {
|
||||
pFlags.multiple_choice = true;
|
||||
}
|
||||
|
||||
if(this.quizCheckboxField.input.checked) {
|
||||
pFlags.quiz = true;
|
||||
}
|
||||
|
||||
const poll: Poll = {
|
||||
_: 'poll',
|
||||
pFlags,
|
||||
question,
|
||||
answers: answers.map((value, idx) => {
|
||||
return {
|
||||
@ -88,17 +179,22 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
};
|
||||
//poll.id = randomIDS;
|
||||
|
||||
appMessagesManager.sendOther($rootScope.selectedPeerID, appPollsManager.getInputMediaPoll(poll));
|
||||
const inputMediaPoll = appPollsManager.getInputMediaPoll(poll, this.correctAnswers, this.quizSolutionInput ? this.quizSolutionInput.value : undefined);
|
||||
|
||||
appMessagesManager.sendOther($rootScope.selectedPeerID, inputMediaPoll);
|
||||
};
|
||||
|
||||
onInput = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
|
||||
const radioLabel = findUpTag(target, 'LABEL');
|
||||
if(target.value.length) {
|
||||
target.parentElement.classList.add('is-filled');
|
||||
radioLabel.classList.remove('hidden-widget');
|
||||
radioLabel.firstElementChild.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
const isLast = !target.parentElement.nextElementSibling;
|
||||
const isLast = !radioLabel.nextElementSibling;
|
||||
if(isLast && target.value.length && this.questions.childElementCount < 10) {
|
||||
this.appendMoreField();
|
||||
}
|
||||
@ -106,27 +202,44 @@ export default class PopupCreatePoll extends PopupElement {
|
||||
|
||||
onDeleteClick = (e: MouseEvent) => {
|
||||
const target = e.target as HTMLSpanElement;
|
||||
target.parentElement.remove();
|
||||
findUpTag(target, 'LABEL').remove();
|
||||
|
||||
Array.from(this.questions.children).forEach((el, idx) => {
|
||||
const label = el.firstElementChild.nextElementSibling as HTMLLabelElement;
|
||||
const label = el.querySelector('label') as HTMLLabelElement;
|
||||
label.innerText = 'Option ' + (idx + 1);
|
||||
});
|
||||
};
|
||||
|
||||
private appendMoreField() {
|
||||
const tempID = this.tempID++;
|
||||
const idx = this.questions.childElementCount + 1;
|
||||
const questionField = InputField('Add an Option', 'Option ' + idx, 'question-' + this.tempID++);
|
||||
const questionField = InputField('Add an Option', 'Option ' + idx, 'question-' + tempID);
|
||||
(questionField.firstElementChild as HTMLInputElement).addEventListener('input', this.onInput);
|
||||
|
||||
const radioField = RadioField('', 'question');
|
||||
radioField.main.append(questionField);
|
||||
radioField.label.classList.add('hidden-widget');
|
||||
radioField.input.disabled = true;
|
||||
if(!this.quizCheckboxField.input.checked) {
|
||||
radioField.label.classList.remove('radio-field');
|
||||
}
|
||||
radioField.input.addEventListener('change', () => {
|
||||
const checked = radioField.input.checked;
|
||||
if(checked) {
|
||||
const idx = whichChild(radioField.label);
|
||||
this.correctAnswers = [new Uint8Array([idx])];
|
||||
}
|
||||
});
|
||||
|
||||
const deleteBtn = document.createElement('span');
|
||||
deleteBtn.classList.add('btn-icon', 'tgico-close');
|
||||
questionField.append(deleteBtn);
|
||||
|
||||
deleteBtn.addEventListener('click', this.onDeleteClick, {once: true});
|
||||
|
||||
this.questions.append(questionField);
|
||||
this.questions.append(radioField.label);
|
||||
|
||||
this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);
|
||||
this.scrollable.scrollIntoView(this.questions.lastElementChild as HTMLElement, true);
|
||||
//this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);
|
||||
}
|
||||
}
|
18
src/components/radioField.ts
Normal file
18
src/components/radioField.ts
Normal file
@ -0,0 +1,18 @@
|
||||
const RadioField = (text: string, name: string) => {
|
||||
const label = document.createElement('label');
|
||||
label.classList.add('radio-field');
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'radio';
|
||||
input.id = input.name = 'input-radio-' + name;
|
||||
|
||||
const main = document.createElement('div');
|
||||
main.classList.add('radio-field-main');
|
||||
main.innerText = text;
|
||||
|
||||
label.append(input, main);
|
||||
|
||||
return {label, input, main};
|
||||
};
|
||||
|
||||
export default RadioField;
|
@ -667,9 +667,9 @@ export class AppMessagesManager {
|
||||
noWebPage: true,
|
||||
newMedia: any
|
||||
}> = {}) {
|
||||
if(!this.canEditMessage(messageID)) {
|
||||
/* if(!this.canEditMessage(messageID)) {
|
||||
return Promise.reject({type: 'MESSAGE_EDIT_FORBIDDEN'});
|
||||
}
|
||||
} */
|
||||
|
||||
if(messageID < 0) {
|
||||
if(this.tempFinalizeCallbacks[messageID] === undefined) {
|
||||
@ -2397,8 +2397,6 @@ export class AppMessagesManager {
|
||||
apiMessage.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !apiMessage.pending);
|
||||
}
|
||||
|
||||
apiMessage.canBeEdited = this.canMessageBeEdited(apiMessage);
|
||||
|
||||
if(!options.isEdited) {
|
||||
this.messagesStorage[mid] = apiMessage;
|
||||
(this.messagesStorageByPeerID[peerID] ?? (this.messagesStorageByPeerID[peerID] = {}))[mid] = apiMessage;
|
||||
@ -2588,15 +2586,18 @@ export class AppMessagesManager {
|
||||
}
|
||||
}
|
||||
|
||||
public canMessageBeEdited(message: any) {
|
||||
public canMessageBeEdited(message: any, kind: 'text' | 'poll') {
|
||||
const goodMedias = [
|
||||
'messageMediaPhoto',
|
||||
'messageMediaDocument',
|
||||
'messageMediaWebPage',
|
||||
'messageMediaPending',
|
||||
'messageMediaPoll'
|
||||
'messageMediaPending'
|
||||
];
|
||||
|
||||
if(kind == 'poll') {
|
||||
goodMedias.push('messageMediaPoll');
|
||||
}
|
||||
|
||||
if(message._ != 'message' ||
|
||||
message.deleted ||
|
||||
message.fwd_from ||
|
||||
@ -2615,13 +2616,13 @@ export class AppMessagesManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public canEditMessage(messageID: number) {
|
||||
public canEditMessage(messageID: number, kind: 'text' | 'poll' = 'text') {
|
||||
if(!this.messagesStorage[messageID]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const message = this.messagesStorage[messageID];
|
||||
if(!message || !message.canBeEdited) {
|
||||
if(!message || !this.canMessageBeEdited(message, kind)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { InputMedia } from "../../layer";
|
||||
import { logger, LogLevels } from "../logger";
|
||||
import apiManager from "../mtproto/mtprotoworker";
|
||||
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
|
||||
@ -140,10 +141,19 @@ class AppPollsManager {
|
||||
};
|
||||
}
|
||||
|
||||
public getInputMediaPoll(poll: Poll) {
|
||||
public getInputMediaPoll(poll: Poll, correctAnswers?: Uint8Array[], solution?: string): InputMedia.inputMediaPoll {
|
||||
let solution_entities: any[];
|
||||
if(solution) {
|
||||
solution_entities = [];
|
||||
solution = RichTextProcessor.parseMarkdown(solution, solution_entities);
|
||||
}
|
||||
|
||||
return {
|
||||
_: 'inputMediaPoll',
|
||||
poll
|
||||
poll,
|
||||
correct_answers: correctAnswers,
|
||||
solution,
|
||||
solution_entities
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.radio-field {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hidden-widget, .radio-field:first-child:last-child {
|
||||
.btn-icon {
|
||||
pointer-events: none;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.input-field {
|
||||
margin-top: 25px;
|
||||
.btn-icon {
|
||||
@ -19,13 +30,6 @@
|
||||
opacity: 1;
|
||||
transition: opacity .2s ease;
|
||||
}
|
||||
|
||||
&:not(.is-filled), &:first-child:last-child {
|
||||
.btn-icon {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
/* &:last-child:not(:nth-child(10)) {
|
||||
.btn-icon {
|
||||
display: none;
|
||||
@ -36,14 +40,24 @@
|
||||
.caption {
|
||||
color: #707579;
|
||||
font-weight: 500;
|
||||
padding: 16px 24px 0;
|
||||
padding: 1rem 1.5rem 0;
|
||||
}
|
||||
|
||||
.poll-create-questions {
|
||||
padding: 0px 20px 32.5px;
|
||||
padding: 0px 1.25rem 2.03125rem;
|
||||
}
|
||||
|
||||
.poll-create-settings {
|
||||
padding: 0 .5rem .5rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-bottom: 1px solid #edeff1;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin-top: .875rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
@ -72,6 +72,7 @@ $floating-left-sidebar: 925px;
|
||||
}
|
||||
|
||||
:root {
|
||||
--z-below: -1;
|
||||
--color-gray: #c4c9cc;
|
||||
--color-gray-hover: rgba(112, 117, 121, .08);
|
||||
--layer-transition: .2s ease-in-out;
|
||||
@ -675,7 +676,7 @@ hr {
|
||||
margin: 1.25rem 0;
|
||||
display: block;
|
||||
text-align: left;
|
||||
padding: 0 18px;
|
||||
padding: 0 1.125rem;
|
||||
/* font-weight: 500; */
|
||||
position: relative;
|
||||
|
||||
@ -684,23 +685,138 @@ hr {
|
||||
}
|
||||
}
|
||||
|
||||
[type="checkbox"] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
.radio-field {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-left: 3.5rem;
|
||||
text-align: left;
|
||||
margin: 1.25rem 0;
|
||||
line-height: 1.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
&.hidden-widget {
|
||||
cursor: default;
|
||||
|
||||
.radio-field-main {
|
||||
&::before, &::after {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> input {
|
||||
&:checked {
|
||||
& ~ .radio-field-main {
|
||||
&::before {
|
||||
border-color: $button-primary-background;
|
||||
}
|
||||
|
||||
&::after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.radio-field-main {
|
||||
&::before, &::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: .25rem;
|
||||
top: 50%;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
&::before {
|
||||
border: 2px solid #8d969c;
|
||||
border-radius: 50%;
|
||||
background-color: white;
|
||||
opacity: 1;
|
||||
transition: border-color .1s ease, opacity .1s ease;
|
||||
}
|
||||
|
||||
&::after {
|
||||
left: .5625rem;
|
||||
width: .625rem;
|
||||
height: .625rem;
|
||||
border-radius: 50%;
|
||||
background: $button-primary-background;
|
||||
opacity: 0;
|
||||
transition: opacity .1s ease;
|
||||
}
|
||||
|
||||
/* .label {
|
||||
display: block;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.subLabel {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1rem;
|
||||
color: var(--color-text-secondary);
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
[type="checkbox"], [type="radio"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
|
||||
opacity: 0;
|
||||
z-index: var(--z-below);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
[type="checkbox"] {
|
||||
& + span {
|
||||
position: relative;
|
||||
padding-left: calc(18px + 2.25rem);
|
||||
padding-left: 3.5rem;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
user-select: none;
|
||||
|
||||
transition: .2s opacity;
|
||||
}
|
||||
|
||||
&:not(:checked) + span:before {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 2px solid transparent;
|
||||
left: 6px;
|
||||
top: 10px;
|
||||
transform: rotateZ(45deg);
|
||||
transform-origin: 100% 100%;
|
||||
}
|
||||
|
||||
&:checked + span:before {
|
||||
top: 4px;
|
||||
left: -1px;
|
||||
width: 8px;
|
||||
height: 14px;
|
||||
border-top: 2px solid transparent;
|
||||
border-left: 2px solid transparent;
|
||||
border-right: 2px solid #fff;
|
||||
border-bottom: 2px solid #fff;
|
||||
transform: rotateZ(45deg);
|
||||
transform-origin: 100% 100%;
|
||||
}
|
||||
|
||||
&:not(:checked) + span:after {
|
||||
background-color: transparent;
|
||||
border-color: #8d969c;
|
||||
}
|
||||
|
||||
&:checked + span:after {
|
||||
background-color: $button-primary-background;
|
||||
}
|
||||
}
|
||||
|
||||
[type="checkbox"] {
|
||||
& + span {
|
||||
&:before, &:after {
|
||||
content: '';
|
||||
left: 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user