mirror of
https://github.com/pebble-dev/clay.git
synced 2026-09-06 09:07:19 -04:00
add sunlight colors to color picker and tests
This commit is contained in:
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"extends": "pebble",
|
"extends": "pebble",
|
||||||
"env" : {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"browser": true
|
"browser": true
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"Pebble": true
|
"Pebble": true
|
||||||
},
|
},
|
||||||
"rules" : {
|
"rules": {
|
||||||
"new-cap": [0],
|
"new-cap": [0],
|
||||||
"max-params": [1],
|
"max-params": [2, 4],
|
||||||
"require-jsdoc": [2, {
|
"require-jsdoc": [2, {
|
||||||
"require": {
|
"require": {
|
||||||
"FunctionDeclaration": true,
|
"FunctionDeclaration": true,
|
||||||
|
|||||||
+10
-2
@@ -41,8 +41,16 @@ module.exports = [
|
|||||||
{
|
{
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"appKey": "background",
|
"appKey": "background",
|
||||||
"value": "0xFF0000",
|
"value": "FF0000",
|
||||||
"label": "Background Color"
|
"label": "Background Color",
|
||||||
|
"sunlight": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"appKey": "background",
|
||||||
|
"value": "00FF00",
|
||||||
|
"label": "Sunny Color",
|
||||||
|
"sunlight": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ window.returnTo = '$$RETURN_TO$$';
|
|||||||
window.clayConfig = require('./config.js');
|
window.clayConfig = require('./config.js');
|
||||||
window.claySettings = {};
|
window.claySettings = {};
|
||||||
window.customFn = require('./custom-fn.js');
|
window.customFn = require('./custom-fn.js');
|
||||||
|
window.clayComponents = require('../src/scripts/components');
|
||||||
|
|
||||||
var platform = window.navigator.userAgent.match(/Android/) ? 'android' : 'ios';
|
var platform = window.navigator.userAgent.match(/Android/) ? 'android' : 'ios';
|
||||||
document.documentElement.classList.add('platform-' + platform);
|
document.documentElement.classList.add('platform-' + platform);
|
||||||
|
|||||||
+1
-1
@@ -104,5 +104,5 @@ gulp.task('default', ['clay']);
|
|||||||
gulp.task('dev', ['dev-js'], function() {
|
gulp.task('dev', ['dev-js'], function() {
|
||||||
gulp.watch('src/styles/**/*.scss', ['sass']);
|
gulp.watch('src/styles/**/*.scss', ['sass']);
|
||||||
gulp.watch(['src/scripts/**/*.js', 'src/templates/**/*.tpl'], ['js']);
|
gulp.watch(['src/scripts/**/*.js', 'src/templates/**/*.tpl'], ['js']);
|
||||||
gulp.watch(['dev/**/*.js'], ['dev-js']);
|
gulp.watch(['src/scripts/**/*.js', 'dev/**/*.js'], ['dev-js']);
|
||||||
});
|
});
|
||||||
|
|||||||
+105
-18
@@ -4,26 +4,109 @@ module.exports = {
|
|||||||
name: 'color',
|
name: 'color',
|
||||||
template: require('../../templates/components/color.tpl'),
|
template: require('../../templates/components/color.tpl'),
|
||||||
style: require('../../styles/clay/components/color.scss'),
|
style: require('../../styles/clay/components/color.scss'),
|
||||||
manipulator: 'val',
|
manipulator: 'color',
|
||||||
defaults: {
|
defaults: {
|
||||||
label: ''
|
label: ''
|
||||||
},
|
},
|
||||||
initialize: function(minified) {
|
initialize: function(minified) {
|
||||||
var HTML = minified.HTML;
|
var HTML = minified.HTML;
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var useSunlight = self.config.sunlight !== false;
|
||||||
|
var sunlightColorMap = {
|
||||||
|
'000000': '000000',
|
||||||
|
'000055': '001e41',
|
||||||
|
'0000aa': '004387',
|
||||||
|
'0000ff': '0068ca',
|
||||||
|
'005500': '2b4a2c',
|
||||||
|
'005555': '27514f',
|
||||||
|
'0055aa': '16638d',
|
||||||
|
'0055ff': '007dce',
|
||||||
|
'00aa00': '5e9860',
|
||||||
|
'00aa55': '5c9b72',
|
||||||
|
'00aaaa': '57a5a2',
|
||||||
|
'00aaff': '4cb4db',
|
||||||
|
'00ff00': '8ee391',
|
||||||
|
'00ff55': '8ee69e',
|
||||||
|
'00ffaa': '8aebc0',
|
||||||
|
'00ffff': '84f5f1',
|
||||||
|
'550000': '4a161b',
|
||||||
|
'550055': '482748',
|
||||||
|
'5500aa': '40488a',
|
||||||
|
'5500ff': '2f6bcc',
|
||||||
|
'555500': '564e36',
|
||||||
|
'555555': '545454',
|
||||||
|
'5555aa': '4f6790',
|
||||||
|
'5555ff': '4180d0',
|
||||||
|
'55aa00': '759a64',
|
||||||
|
'55aa55': '759d76',
|
||||||
|
'55aaaa': '71a6a4',
|
||||||
|
'55aaff': '69b5dd',
|
||||||
|
'55ff00': '9ee594',
|
||||||
|
'55ff55': '9de7a0',
|
||||||
|
'55ffaa': '9becc2',
|
||||||
|
'55ffff': '95f6f2',
|
||||||
|
'aa0000': '99353f',
|
||||||
|
'aa0055': '983e5a',
|
||||||
|
'aa00aa': '955694',
|
||||||
|
'aa00ff': '8f74d2',
|
||||||
|
'aa5500': '9d5b4d',
|
||||||
|
'aa5555': '9d6064',
|
||||||
|
'aa55aa': '9a7099',
|
||||||
|
'aa55ff': '9587d5',
|
||||||
|
'aaaa00': 'afa072',
|
||||||
|
'aaaa55': 'aea382',
|
||||||
|
'aaaaaa': 'ababab',
|
||||||
|
'ffffff': 'ffffff',
|
||||||
|
'aaaaff': 'a7bae2',
|
||||||
|
'aaff00': 'c9e89d',
|
||||||
|
'aaff55': 'c9eaa7',
|
||||||
|
'aaffaa': 'c7f0c8',
|
||||||
|
'aaffff': 'c3f9f7',
|
||||||
|
'ff0000': 'e35462',
|
||||||
|
'ff0055': 'e25874',
|
||||||
|
'ff00aa': 'e16aa3',
|
||||||
|
'ff00ff': 'de83dc',
|
||||||
|
'ff5500': 'e66e6b',
|
||||||
|
'ff5555': 'e6727c',
|
||||||
|
'ff55aa': 'e37fa7',
|
||||||
|
'ff55ff': 'e194df',
|
||||||
|
'ffaa00': 'f1aa86',
|
||||||
|
'ffaa55': 'f1ad93',
|
||||||
|
'ffaaaa': 'efb5b8',
|
||||||
|
'ffaaff': 'ecc3eb',
|
||||||
|
'ffff00': 'ffeeab',
|
||||||
|
'ffff55': 'fff1b5',
|
||||||
|
'ffffaa': 'fff6d3'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string|boolean|number} color
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function cssColor(color) {
|
||||||
|
if (color === false) { return 'transparent'; }
|
||||||
|
if (typeof color === 'number') {
|
||||||
|
color = color.toString(16);
|
||||||
|
}
|
||||||
|
while (color.length < 6) {
|
||||||
|
color = '0' + color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '#' + (useSunlight ? sunlightColorMap[color] : color);
|
||||||
|
}
|
||||||
|
|
||||||
/* eslint-disable comma-spacing, no-multi-spaces, max-len,
|
/* eslint-disable comma-spacing, no-multi-spaces, max-len,
|
||||||
standard/array-bracket-even-spacing */
|
standard/array-bracket-even-spacing */
|
||||||
var layout = self.config.layout || [
|
var layout = self.config.layout || [
|
||||||
[false , false , '#55FF00', '#AAFF55', false , '#FFFF55', '#FFFFAA', false , false ],
|
[false , false , '55ff00', 'aaff55', false , 'ffff55', 'ffffaa', false , false ],
|
||||||
[false , '#AAFFAA', '#55FF55', '#00FF00', '#AAFF00', '#FFFF00', '#FFAA55', '#FFAAAA', false ],
|
[false , 'aaffaa', '55ff55', '00ff00', 'aaff00', 'ffff00', 'ffaa55', 'ffaaaa', false ],
|
||||||
['#55FFAA', '#00FF55', '#00AA00', '#55AA00', '#AAAA55', '#AAAA00', '#FFAA00', '#FF5500', '#FF5555'],
|
['55ffaa', '00ff55', '00aa00', '55aa00', 'aaaa55', 'aaaa00', 'ffaa00', 'ff5500', 'ff5555'],
|
||||||
['#AAFFFF', '#00FFAA', '#00AA55', '#55AA55', '#005500', '#555500', '#AA5500', '#FF0000', '#FF0055'],
|
['aaffff', '00ffaa', '00aa55', '55aa55', '005500', '555500', 'aa5500', 'ff0000', 'ff0055'],
|
||||||
[false , '#55AAAA', '#00AAAA', '#005555', '#FFFFFF', '#000000', '#AA5555', '#AA0000', false ],
|
[false , '55aaaa', '00aaaa', '005555', 'ffffff', '000000', 'aa5555', 'aa0000', false ],
|
||||||
['#55FFFF', '#00FFFF', '#00AAFF', '#0055AA', '#AAAAAA', '#555555', '#550000', '#AA0055', '#FF55AA'],
|
['55ffff', '00ffff', '00aaff', '0055aa', 'aaaaaa', '555555', '550000', 'aa0055', 'ff55aa'],
|
||||||
['#55AAFF', '#0055FF', '#0000FF', '#0000AA', '#000055', '#550055', '#AA00AA', '#FF00AA', '#FFAAFF'],
|
['55aaff', '0055ff', '0000ff', '0000aa', '000055', '550055', 'aa00aa', 'ff00aa', 'ffaaff'],
|
||||||
[false , '#5555AA', '#5555FF', '#5500FF', '#5500AA', '#AA00FF', '#FF00FF', '#FF55FF', false ],
|
[false , '5555aa', '5555ff', '5500ff', '5500aa', 'aa00ff', 'ff00ff', 'ff55ff', false ],
|
||||||
[false , false , false , '#AAAAFF', '#AA55FF', '#AA55AA', false , false , false ]
|
[false , false , false , 'aaaaff', 'aa55ff', 'aa55aa', false , false , false ]
|
||||||
];
|
];
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
|
|
||||||
@@ -35,8 +118,8 @@ module.exports = {
|
|||||||
for (var i = 0; i < layout.length; i++) {
|
for (var i = 0; i < layout.length; i++) {
|
||||||
for (var j = 0; j < layout[i].length; j++) {
|
for (var j = 0; j < layout[i].length; j++) {
|
||||||
|
|
||||||
var color = layout[i][j] || 'transparent';
|
var color = layout[i][j];
|
||||||
var selectable = (color !== 'transparent' ? ' selectable' : '');
|
var selectable = (color ? ' selectable' : '');
|
||||||
|
|
||||||
var roundedTL = (i === 0 && j === 0) || i === 0 && !layout[i][j - 1] ||
|
var roundedTL = (i === 0 && j === 0) || i === 0 && !layout[i][j - 1] ||
|
||||||
!layout[i][j - 1] && !layout[i - 1][j] ?
|
!layout[i][j - 1] && !layout[i - 1][j] ?
|
||||||
@@ -62,11 +145,11 @@ module.exports = {
|
|||||||
grid += '<i ' +
|
grid += '<i ' +
|
||||||
'class="color-box ' + selectable + roundedTL + roundedTR + roundedBL +
|
'class="color-box ' + selectable + roundedTL + roundedTR + roundedBL +
|
||||||
roundedBR + '" ' +
|
roundedBR + '" ' +
|
||||||
'data-value="' + color.replace(/^#/, '0x').toLowerCase() + '" ' +
|
'data-value="' + parseInt(color, 16) + '" ' +
|
||||||
'style="' +
|
'style="' +
|
||||||
'width:' + itemWidth + '%; ' +
|
'width:' + itemWidth + '%; ' +
|
||||||
'height:' + itemHeight + '%; ' +
|
'height:' + itemHeight + '%; ' +
|
||||||
'background:' + color + ';">' +
|
'background:' + cssColor(color) + ';">' +
|
||||||
'</i>';
|
'</i>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,14 +167,18 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.on('change', function() {
|
self.on('change', function() {
|
||||||
var value = self.get().replace(/^0x/, '').toLowerCase();
|
var value = self.get();
|
||||||
$valueDisplay.set('$background-color', '#' + value);
|
$valueDisplay.set('$background-color', cssColor(value));
|
||||||
$elem.select('.color-box').set('-selected');
|
$elem.select('.color-box').set('-selected');
|
||||||
$elem.select('.color-box[data-value="0x' + value + '"]').set('+selected');
|
$elem.select('.color-box[data-value="' + value + '"]').set('+selected');
|
||||||
});
|
});
|
||||||
|
|
||||||
$elem.select('.color-box.selectable').on('click', function(ev) {
|
$elem.select('.color-box.selectable').on('click', function(ev) {
|
||||||
self.set(ev.target.dataset.value);
|
self.set(parseInt(ev.target.dataset.value, 10));
|
||||||
|
$picker.set('-show');
|
||||||
|
});
|
||||||
|
|
||||||
|
$picker.on('click', function() {
|
||||||
$picker.set('-show');
|
$picker.set('-show');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ var returnTo = window.returnTo || 'pebblejs://close#';
|
|||||||
var customFn = window.customFn || function() {};
|
var customFn = window.customFn || function() {};
|
||||||
var clayComponents = window.clayComponents || {};
|
var clayComponents = window.clayComponents || {};
|
||||||
|
|
||||||
|
var platform = window.navigator.userAgent.match(/Android/) ? 'android' : 'ios';
|
||||||
|
document.documentElement.classList.add('platform-' + platform);
|
||||||
|
|
||||||
// Register the passed components
|
// Register the passed components
|
||||||
_.eachObj(clayComponents, function(key, component) {
|
_.eachObj(clayComponents, function(key, component) {
|
||||||
ClayConfig.registerComponent(component);
|
ClayConfig.registerComponent(component);
|
||||||
|
|||||||
@@ -47,5 +47,21 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
disable: disable,
|
disable: disable,
|
||||||
enable: enable
|
enable: enable
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
get: function() {
|
||||||
|
return parseInt(this.$manipulatorTarget.get('value'), 16);
|
||||||
|
},
|
||||||
|
set: function(value) {
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'number': value = value.toString(16); break;
|
||||||
|
case 'string': value = value.replace(/^#|^0x/, ''); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$manipulatorTarget.set('value', value || '000000');
|
||||||
|
return this.trigger('change');
|
||||||
|
},
|
||||||
|
disable: disable,
|
||||||
|
enable: enable
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('chai').assert;
|
||||||
|
var fixture = require('../../fixture');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ClayItem} colorItem
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function openPicker(colorItem) {
|
||||||
|
colorItem.$element.select('label')[0].click();
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('component - color', function() {
|
||||||
|
it('shows the sunlit colors in the value display', function() {
|
||||||
|
var clayConfig = fixture.clayConfig([
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
sunlight: true,
|
||||||
|
id: '1',
|
||||||
|
value: 'ff0000'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
var colorItem = clayConfig.getItemById('1');
|
||||||
|
|
||||||
|
assert.strictEqual(colorItem.get(), 0xff0000);
|
||||||
|
assert.strictEqual(
|
||||||
|
colorItem.$element.select('.value')[0].style.backgroundColor,
|
||||||
|
'rgb(227, 84, 98)'
|
||||||
|
);
|
||||||
|
colorItem.set('0000FF');
|
||||||
|
assert.strictEqual(
|
||||||
|
colorItem.$element.select('.value')[0].style.backgroundColor,
|
||||||
|
'rgb(0, 104, 202)'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the normal colors in the value display', function() {
|
||||||
|
var clayConfig = fixture.clayConfig([
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
sunlight: false,
|
||||||
|
id: '1',
|
||||||
|
value: 'ff0000'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
var colorItem = clayConfig.getItemById('1');
|
||||||
|
|
||||||
|
assert.strictEqual(colorItem.get(), 0xff0000);
|
||||||
|
assert.strictEqual(
|
||||||
|
colorItem.$element.select('.value')[0].style.backgroundColor,
|
||||||
|
'rgb(255, 0, 0)'
|
||||||
|
);
|
||||||
|
colorItem.set('0000FF');
|
||||||
|
assert.strictEqual(
|
||||||
|
colorItem.$element.select('.value')[0].style.backgroundColor,
|
||||||
|
'rgb(0, 0, 255)'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the picker when the label is clicked', function() {
|
||||||
|
var clayConfig = fixture.clayConfig(['color']);
|
||||||
|
var colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
var $picker = colorItem.$element.select('.picker-wrap');
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), false);
|
||||||
|
openPicker(colorItem);
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only shows the picker if the item is enabled', function() {
|
||||||
|
var clayConfig = fixture.clayConfig(['color']);
|
||||||
|
var colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
var $picker = colorItem.$element.select('.picker-wrap');
|
||||||
|
colorItem.disable();
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), false);
|
||||||
|
openPicker(colorItem);
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), false);
|
||||||
|
colorItem.enable();
|
||||||
|
openPicker(colorItem);
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the value and closes picker when the user makes a selection', function() {
|
||||||
|
var clayConfig = fixture.clayConfig([{type: 'color', sunlight: false}]);
|
||||||
|
var colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
var $picker = colorItem.$element.select('.picker-wrap');
|
||||||
|
assert.strictEqual(colorItem.get(), 0x000000);
|
||||||
|
openPicker(colorItem);
|
||||||
|
colorItem.$element.select('[data-value="16711680"]')[0].click();
|
||||||
|
assert.strictEqual(colorItem.get(), 0xff0000);
|
||||||
|
assert.strictEqual(
|
||||||
|
colorItem.$element.select('.value')[0].style.backgroundColor,
|
||||||
|
'rgb(255, 0, 0)'
|
||||||
|
);
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('closes the picker if a user clicks the background', function() {
|
||||||
|
var clayConfig = fixture.clayConfig([{type: 'color', sunlight: false}]);
|
||||||
|
var colorItem = clayConfig.getItemsByType('color')[0];
|
||||||
|
var $picker = colorItem.$element.select('.picker-wrap');
|
||||||
|
assert.strictEqual(colorItem.get(), 0x000000);
|
||||||
|
openPicker(colorItem);
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), true);
|
||||||
|
$picker[0].click();
|
||||||
|
assert.strictEqual($picker.get('classList').contains('show'), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -9,17 +9,21 @@ describe('manipulators', function() {
|
|||||||
/**
|
/**
|
||||||
* @param {string} itemType
|
* @param {string} itemType
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
|
* @param {*} expected
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
function testSetGet(itemType, value) {
|
function testSetGet(itemType, value, expected) {
|
||||||
|
expected = typeof expected === 'undefined' ? value : expected;
|
||||||
|
|
||||||
describe('.set() and .get()', function() {
|
describe('.set() and .get()', function() {
|
||||||
it('sets and gets the value then triggers a "change" event', function() {
|
it('sets: "' + value + '" and gets: "' + expected + '" then triggers "change"',
|
||||||
|
function() {
|
||||||
var handlerSpy = sinon.spy();
|
var handlerSpy = sinon.spy();
|
||||||
var clayItem = fixture.clayItem(itemType);
|
var clayItem = fixture.clayItem(itemType);
|
||||||
clayItem.on('change', handlerSpy);
|
clayItem.on('change', handlerSpy);
|
||||||
|
|
||||||
clayItem.set(value);
|
clayItem.set(value);
|
||||||
assert.strictEqual(clayItem.get(), value);
|
assert.strictEqual(clayItem.get(), expected);
|
||||||
assert.strictEqual(handlerSpy.callCount, 1, 'handler not called once');
|
assert.strictEqual(handlerSpy.callCount, 1, 'handler not called once');
|
||||||
assert(handlerSpy.calledOn(clayItem), 'handler not called on clayItem');
|
assert(handlerSpy.calledOn(clayItem), 'handler not called on clayItem');
|
||||||
});
|
});
|
||||||
@@ -80,4 +84,17 @@ describe('manipulators', function() {
|
|||||||
testDisable('toggle');
|
testDisable('toggle');
|
||||||
testEnable('toggle');
|
testEnable('toggle');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('color', function() {
|
||||||
|
testSetGet('color', 'FF0000', 0xff0000);
|
||||||
|
testSetGet('color', '#FF0000', 0xff0000);
|
||||||
|
testSetGet('color', '0xFF0000', 0xff0000);
|
||||||
|
testSetGet('color', '#ff0000', 0xff0000);
|
||||||
|
testSetGet('color', 0xff0000, 0xff0000);
|
||||||
|
testSetGet('color', '', 0x000000);
|
||||||
|
testSetGet('color', false, 0x000000);
|
||||||
|
testSetGet('color', undefined, 0x000000);
|
||||||
|
testDisable('color');
|
||||||
|
testEnable('color');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user