mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-05-23 04:15:26 +00:00
(js,css) Replace sortable library
This commit is contained in:
@@ -12,6 +12,7 @@ Enhancements
|
||||
- [web] all batch operations can now be performed on selected messages in advanced search mode
|
||||
- [web] add date picker to change date, week, or month of current Calendar view
|
||||
- [web] style cancelled events in Calendar module
|
||||
- [web] replace sortable library for better support with Firefox
|
||||
- [oc] better handling of nested attachments with OpenChange
|
||||
|
||||
Bug fixes
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="title"
|
||||
const:jsFiles="Common.js, vendor/ng-sortable.min.js, Preferences.js, Preferences.services.js, Mailer.services.js, Contacts.services.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js">
|
||||
const:jsFiles="vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/ng-sortable.min.js, Common.js, Preferences.js, Preferences.services.js, Mailer.services.js, Contacts.services.js">
|
||||
|
||||
<main layout-fill="layout-fill" ui-view="preferences"
|
||||
ng-controller="navController"><!-- preferences --> </main>
|
||||
@@ -675,13 +675,16 @@
|
||||
<md-tab id="mailFiltersTab"
|
||||
aria-controls="mailFiltersTab-content"
|
||||
label:label="Filters">
|
||||
<div role="tabpanel" aria-labelledby="mailFiltersView"
|
||||
<md-content role="tabpanel" aria-labelledby="mailFiltersView"
|
||||
id="mailFiltersView-content">
|
||||
|
||||
<div class="md-padding" ng-sortable="{ animation: 150, draggable: '.layout-row', handle: '.sg-sortable-grip', ghostClass: 'sg-sortable-ghost', chosenClass: 'sg-sortable-chosen' }">
|
||||
<div class="sg-list-sortable"
|
||||
ng-model="app.preferences.defaults.SOGoSieveFilters"
|
||||
as-sortable="{ scrollableContainer: '#mailFiltersView-content', containment: '.sg-list-sortable', containerPositioning: 'relative', orderChanged: preferencesForm.$setDirty }">
|
||||
<div layout="row" layout-align="start center"
|
||||
ng-repeat="item in app.preferences.defaults.SOGoSieveFilters track by $index">
|
||||
<md-button class="md-icon-button" md-no-ink="md-no-ink">
|
||||
ng-repeat="item in app.preferences.defaults.SOGoSieveFilters"
|
||||
as-sortable-item="as-sortable-item">
|
||||
<md-button class="md-icon-button" md-no-ink="md-no-ink"
|
||||
as-sortable-item-handle="as-sortable-item-handle">
|
||||
<md-icon class="sg-sortable-grip">drag_handle</md-icon>
|
||||
</md-button>
|
||||
<md-checkbox
|
||||
@@ -709,7 +712,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FIXME: move up/down to be replaced by DnD? -->
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button type="button"
|
||||
ng-click="app.addMailFilter($event, preferencesForm)"
|
||||
@@ -717,7 +719,7 @@
|
||||
<var:string label:value="Create Filter"/>
|
||||
</md-button>
|
||||
</div>
|
||||
</div>
|
||||
</md-content>
|
||||
</md-tab>
|
||||
</var:if>
|
||||
<!-- END OF MAIL > FILTERS -->
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="title"
|
||||
const:jsFiles="vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, Common.js, vendor/ng-sortable.min.js, Preferences.services.js, Contacts.services.js, Mailer.services.js, vendor/angular-file-upload.min.js, Scheduler.js, Scheduler.services.js, vendor/FileSaver.min.js">
|
||||
const:jsFiles="vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/ng-sortable.min.js, Common.js, Preferences.services.js, Contacts.services.js, Mailer.services.js, vendor/angular-file-upload.min.js, Scheduler.js, Scheduler.services.js, vendor/FileSaver.min.js">
|
||||
<script type="text/javascript">
|
||||
var firstDayOfWeek = <var:string value="firstDayOfWeek"/>;
|
||||
var dayStartHour = <var:string value="dayStartHour"/>;
|
||||
@@ -36,8 +36,8 @@
|
||||
md-component-id="left" md-is-locked-open="isGtMedium"
|
||||
ng-class="{ 'sg-close': leftIsClose }">
|
||||
<var:component className="UIxSidenavToolbarTemplate" />
|
||||
<md-content class="md-flex" md-scroll-y="md-scroll-y"
|
||||
ng-class="{'sg-list-sortable': !app.sortableCalendars.disabled}"
|
||||
<md-content id="sidenav-content" class="md-flex" md-scroll-y="md-scroll-y"
|
||||
ng-class="{'sg-list-sortable': app.sortableMode}"
|
||||
md-colors="::{ backgroundColor: 'default-background-300' }">
|
||||
<!-- User's calendars -->
|
||||
<section>
|
||||
@@ -52,8 +52,10 @@
|
||||
</md-button>
|
||||
</div>
|
||||
</md-subheader>
|
||||
<md-list ng-sortable="app.sortableCalendars">
|
||||
<md-list-item ng-repeat="calendar in app.service.$calendars | filter:app.filter">
|
||||
<md-list ng-model="app.service.$calendars"
|
||||
as-sortable="app.sortableCalendars" is-disabled="!app.sortableMode">
|
||||
<md-list-item ng-repeat="calendar in app.service.$calendars | filter:app.filter"
|
||||
as-sortable-item="as-sortable-item">
|
||||
<md-checkbox ng-model="calendar.active"
|
||||
ng-class="calendar.getClassName('checkbox')"
|
||||
ng-true-value="1"
|
||||
@@ -76,8 +78,11 @@
|
||||
sg-enter="app.renameFolder(calendar)"
|
||||
sg-escape="app.revertEditing(calendar)"/>
|
||||
</md-input-container>
|
||||
<md-menu class="md-secondary" label:aria-label="Options"
|
||||
md-colors="::{color: 'accent-400'}">
|
||||
<md-button class="md-secondary md-icon-button" md-no-ink="md-no-ink"
|
||||
as-sortable-item-handle="as-sortable-item-handle">
|
||||
<md-icon md-colors="::{color: 'accent-400'}">drag_handle</md-icon>
|
||||
</md-button>
|
||||
<md-menu class="md-secondary sg-list-sortable-hide" label:aria-label="Options">
|
||||
<md-button class="md-icon-button" label:aria-label="Options"
|
||||
ng-click="$mdOpenMenu()"
|
||||
md-menu-origin="md-menu-origin">
|
||||
@@ -152,8 +157,10 @@
|
||||
</md-button>
|
||||
</div>
|
||||
</md-subheader>
|
||||
<md-list ng-sortable="app.sortableSubscriptions">
|
||||
<md-list-item ng-repeat="calendar in app.service.$subscriptions | filter:app.filter">
|
||||
<md-list ng-model="app.service.$subscriptions"
|
||||
as-sortable="app.sortableCalendars" is-disabled="!app.sortableMode">
|
||||
<md-list-item ng-repeat="calendar in app.service.$subscriptions | filter:app.filter"
|
||||
as-sortable-item="as-sortable-item">
|
||||
<md-checkbox ng-model="calendar.active"
|
||||
ng-class="calendar.getClassName('checkbox')"
|
||||
ng-true-value="1"
|
||||
@@ -177,8 +184,11 @@
|
||||
sg-enter="app.renameFolder(calendar)"
|
||||
sg-escape="app.revertEditing(calendar)"/>
|
||||
</md-input-container>
|
||||
<md-menu class="md-secondary" label:aria-label="Options"
|
||||
md-colors="::{color: 'accent-400'}">
|
||||
<md-button class="md-secondary md-icon-button" md-no-ink="md-no-ink"
|
||||
as-sortable-item-handle="as-sortable-item-handle">
|
||||
<md-icon md-colors="::{color: 'accent-400'}">drag_handle</md-icon>
|
||||
</md-button>
|
||||
<md-menu class="md-secondary sg-list-sortable-hide" label:aria-label="Options">
|
||||
<md-button class="md-icon-button" label:aria-label="Options"
|
||||
ng-click="$mdOpenMenu()"
|
||||
md-menu-origin="md-menu-origin">
|
||||
@@ -229,8 +239,10 @@
|
||||
</md-button>
|
||||
</div>
|
||||
</md-subheader>
|
||||
<md-list ng-sortable="app.sortableWebCalendars">
|
||||
<md-list-item ng-repeat="calendar in app.service.$webcalendars | filter:app.filter">
|
||||
<md-list ng-model="app.service.$webcalendars"
|
||||
as-sortable="app.sortableCalendars" is-disabled="!app.sortableMode">
|
||||
<md-list-item ng-repeat="calendar in app.service.$webcalendars | filter:app.filter"
|
||||
as-sortable-item="as-sortable-item">
|
||||
<md-checkbox ng-model="calendar.active"
|
||||
ng-class="calendar.getClassName('checkbox')"
|
||||
ng-true-value="1"
|
||||
@@ -256,8 +268,11 @@
|
||||
sg-enter="app.renameFolder(calendar)"
|
||||
sg-escape="app.revertEditing(calendar)"/>
|
||||
</md-input-container>
|
||||
<md-menu class="md-secondary" label:aria-label="Options"
|
||||
md-colors="::{color: 'accent-400'}">
|
||||
<md-button class="md-secondary md-icon-button" md-no-ink="md-no-ink"
|
||||
as-sortable-item-handle="as-sortable-item-handle">
|
||||
<md-icon md-colors="::{color: 'accent-400'}">drag_handle</md-icon>
|
||||
</md-button>
|
||||
<md-menu class="md-secondary sg-list-sortable-hide" label:aria-label="Options">
|
||||
<md-button class="md-icon-button" label:aria-label="Options"
|
||||
ng-click="$mdOpenMenu()"
|
||||
md-menu-origin="md-menu-origin">
|
||||
@@ -294,7 +309,7 @@
|
||||
<md-toolbar class="sg-toolbar-multiple sg-toolbar-tools--dense">
|
||||
<div class="md-toolbar-tools sg-toolbar-tools--dense"
|
||||
md-colors="::{backgroundColor: 'background-500'}"
|
||||
ng-show="app.sortableCalendars.disabled">
|
||||
ng-hide="app.sortableMode">
|
||||
<md-input-container class="md-flex" md-no-float="md-no-float">
|
||||
<md-icon>search</md-icon>
|
||||
<input ng-model="app.filter.name" type="search" label:placeholder="Filter"/>
|
||||
@@ -306,7 +321,7 @@
|
||||
</div>
|
||||
<div class="md-toolbar-tools sg-toolbar-tools--dense ng-hide" layout-align="center center"
|
||||
md-colors="::{backgroundColor: 'accent-600'}"
|
||||
ng-hide="app.sortableCalendars.disabled">
|
||||
ng-show="app.sortableMode">
|
||||
<md-button ng-click="app.resetSort()"><var:string label:value="Reset"/></md-button>
|
||||
<div class="md-flex"><!-- spacer --></div>
|
||||
<md-button ng-click="app.toggleSortableMode()"><var:string label:value="Done"/></md-button>
|
||||
|
||||
@@ -17,7 +17,6 @@ module.exports = function(grunt) {
|
||||
|
||||
};
|
||||
var custom_vendor_files = {
|
||||
'js/vendor/ng-sortable.min.js': ['bower_components/Sortable/Sortable.js', 'bower_components/Sortable/ng-sortable.js'],
|
||||
'js/vendor/angular-file-upload.min.js': ['bower_components/angular-file-upload/dist/angular-file-upload.js', 'js/Common/angular-file-upload.trump.js'],
|
||||
'js/vendor/FileSaver.min.js': ['bower_components/file-saver.js/FileSaver.js']
|
||||
};
|
||||
@@ -134,6 +133,7 @@ module.exports = function(grunt) {
|
||||
'<%= src %>/angular-material/angular-material{,.min}.js{,.map}',
|
||||
'<%= src %>/angular-ui-router/release/angular-ui-router{,.min}.js',
|
||||
//'<%= src %>/ng-file-upload/ng-file-upload{,.min}.js{,map}',
|
||||
'<%= src %>/ng-sortable/dist/ng-sortable.min.js{,map}',
|
||||
'<%= src %>/lodash/dist/lodash{,.min}.js'
|
||||
];
|
||||
for (var j = 0; j < js.length; j++) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"angular-material": "1.1.0-rc.5-master-7f01138",
|
||||
"file-saver.js": "latest",
|
||||
"lodash": "latest",
|
||||
"Sortable": "latest",
|
||||
"ng-sortable": "latest",
|
||||
"breakpoint-sass": ">=2.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.PreferencesUI', ['ui.router', 'ck', 'SOGo.Common', 'SOGo.MailerUI', 'SOGo.ContactsUI', 'SOGo.Authentication', 'ng-sortable'])
|
||||
angular.module('SOGo.PreferencesUI', ['ui.router', 'ck', 'SOGo.Common', 'SOGo.MailerUI', 'SOGo.ContactsUI', 'SOGo.Authentication', 'as.sortable'])
|
||||
.config(configure)
|
||||
.run(runBlock);
|
||||
|
||||
|
||||
@@ -28,20 +28,15 @@
|
||||
// vm.today = today;
|
||||
|
||||
vm.filter = { name: '' };
|
||||
vm.sortableMode = false;
|
||||
vm.toggleSortableMode = toggleSortableMode;
|
||||
vm.resetSort = resetSort;
|
||||
vm.sortableCalendars = {
|
||||
disabled: true,
|
||||
animation: 150,
|
||||
draggable: 'md-list-item',
|
||||
handle: '.md-menu',
|
||||
ghostClass: 'sg-sortable-ghost',
|
||||
chosenClass: 'sg-sortable-chosen',
|
||||
setData: sortable_setData,
|
||||
onEnd: sortable_onEnd
|
||||
scrollableContainer: '#sidenav-content',
|
||||
containment: 'md-list',
|
||||
orderChanged: _sortableEnd,
|
||||
accept: _sortableAccept
|
||||
};
|
||||
vm.sortableSubscriptions = angular.copy(vm.sortableCalendars);
|
||||
vm.sortableWebCalendars = angular.copy(vm.sortableCalendars);
|
||||
|
||||
Preferences.ready().then(function() {
|
||||
vm.categories = _.map(Preferences.defaults.SOGoCalendarCategories, function(name) {
|
||||
@@ -88,18 +83,19 @@
|
||||
true // compare for object equality
|
||||
);
|
||||
|
||||
function sortable_setData(dataTransfer, dragEl) {
|
||||
dataTransfer.clearData();
|
||||
/**
|
||||
* Only allow to sort items within the same list.
|
||||
*/
|
||||
function _sortableAccept(sourceItemHandleScope, destSortableScope, destItemScope) {
|
||||
return sourceItemHandleScope.sortableScope.element[0] == destSortableScope.element[0];
|
||||
}
|
||||
|
||||
function sortable_onEnd() {
|
||||
function _sortableEnd() {
|
||||
Calendar.saveFoldersOrder(_.flatMap(Calendar.$findAll(), 'id'));
|
||||
}
|
||||
|
||||
function toggleSortableMode() {
|
||||
vm.sortableCalendars.disabled = !vm.sortableCalendars.disabled;
|
||||
vm.sortableSubscriptions.disabled = !vm.sortableSubscriptions.disabled;
|
||||
vm.sortableWebCalendars.disabled = !vm.sortableWebCalendars.disabled;
|
||||
vm.sortableMode = !vm.sortableMode;
|
||||
vm.filter.name = '';
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.SchedulerUI', ['ngCookies', 'ui.router', 'angularFileUpload', 'ck', 'SOGo.Common', 'SOGo.PreferencesUI', 'SOGo.ContactsUI', 'SOGo.MailerUI', 'ng-sortable'])
|
||||
angular.module('SOGo.SchedulerUI', ['ngCookies', 'ui.router', 'angularFileUpload', 'ck', 'SOGo.Common', 'SOGo.PreferencesUI', 'SOGo.ContactsUI', 'SOGo.MailerUI', 'as.sortable'])
|
||||
.config(configure)
|
||||
.run(runBlock);
|
||||
|
||||
|
||||
+1
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -229,40 +229,64 @@ div.md-tile-left {
|
||||
min-width: $sg-font-size-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Classes for ng-sortable */
|
||||
&-sortable-grip {
|
||||
&:hover {
|
||||
cursor: move;
|
||||
}
|
||||
/**
|
||||
* Sortable list items are provided by the ng-sortable library. CSS classes are
|
||||
* from ng-sortable are prefixed by as-. Basic rules come from the CSS file
|
||||
* bundled with the library.
|
||||
*
|
||||
* 1. We hide sortable handles when not inside a .sg-list-sortable;
|
||||
* 2. Elements wih the class .sg-list-sortable-hide are hidden when the list is
|
||||
* currently sortable;
|
||||
* 3. Dragged element is highligh with a whiteframe.
|
||||
*
|
||||
* See https://github.com/a5hik/ng-sortable
|
||||
*/
|
||||
|
||||
.as-sortable-item {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.as-sortable-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.as-sortable-un-selectable {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.as-sortable-item-handle {
|
||||
display: none; /* [1] */
|
||||
}
|
||||
|
||||
.sg-list-sortable {
|
||||
.as-sortable-item-handle {
|
||||
cursor: move;
|
||||
display: block; /* [1] */
|
||||
}
|
||||
|
||||
&-sortable-chosen {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
&-sortable-ghost {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&-list-sortable {
|
||||
._md-secondary-container > .md-menu {
|
||||
.md-button {
|
||||
display: none;
|
||||
}
|
||||
&:before {
|
||||
@extend .material-icons;
|
||||
content: "\e8fe";
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
.sg-list-sortable-hide {
|
||||
display: none; /* [2] */
|
||||
}
|
||||
}
|
||||
|
||||
.as-sortable-drag { /* [3] */
|
||||
@extend .md-whiteframe-1dp;
|
||||
background-color: rgba(255,255,255,0.4);
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/**
|
||||
* A md-avatar can either include a md-icon or an img.
|
||||
*/
|
||||
|
||||
.card-picture {
|
||||
.md-avatar {
|
||||
display: block;
|
||||
// From md-list-item > .md-avatar:first-child
|
||||
|
||||
// From md-list-item ._md-list-item-inner .md-avatar
|
||||
width: $list-item-primary-avatar-width;
|
||||
height: $list-item-primary-avatar-width;
|
||||
margin-top: $baseline-grid;
|
||||
@@ -270,14 +294,13 @@ div.md-tile-left {
|
||||
margin-right: $list-item-primary-width - $list-item-primary-avatar-width;
|
||||
border-radius: 50%;
|
||||
box-sizing: content-box;
|
||||
|
||||
img {
|
||||
width: initial !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Avatar placeholder
|
||||
// ------------------------------------
|
||||
.md-avatar:before,
|
||||
.md-avatar md-icon,
|
||||
sg-avatar-image md-icon,
|
||||
@@ -297,20 +320,20 @@ sg-avatar-image .material-icons {
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------*\
|
||||
SG-AVATAR-IMAGE DIRECTIVE
|
||||
\*------------------------------------*/
|
||||
|
||||
sg-avatar-image img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/*------------------------------------*\
|
||||
SELECTABLE AVATARS
|
||||
\*------------------------------------*/
|
||||
/**
|
||||
* In the middle list of the main view, we allow items selection through a
|
||||
* checkbox that replaces the avatar when
|
||||
*
|
||||
* 1. the mouse cursor is over the selectable avatar;
|
||||
* 2. the list is marked as selectable.
|
||||
*/
|
||||
|
||||
.sg-list-selectable .sg-avatar-selectable,
|
||||
.sg-avatar-selectable:hover {
|
||||
.sg-avatar-selectable:hover, /* [1] */
|
||||
.sg-list-selectable .sg-avatar-selectable { /* [2] */
|
||||
font-family: 'Material Icons';
|
||||
font-size: $sg-avatar-width;
|
||||
height: 100%;
|
||||
@@ -328,71 +351,3 @@ sg-avatar-image img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
//.md-tile-left-accepted:before {
|
||||
// @extend .md-tile-left;
|
||||
// background-color: rgba(0, 255, 0, 0.3) !important;
|
||||
// content: "\e5ca"; // check
|
||||
// color: rgba(0, 0, 0, 0.5);
|
||||
//}
|
||||
//.md-tile-left-declined:before {
|
||||
// @extend .md-tile-left;
|
||||
// background-color: rgba(255, 0, 0, 0.3) !important;
|
||||
// content: "\e15b"; // remove
|
||||
// color: rgba(0, 0, 0, 0.5);
|
||||
//}
|
||||
//.md-tile-left-delegated:before {
|
||||
// @extend .md-tile-left;
|
||||
// background-color: rgba(192, 192, 192, 0.3) !important;
|
||||
// content: "\e5c8"; // arrow-forward
|
||||
// color: rgba(0, 0, 0, 0.5);
|
||||
//}
|
||||
//.md-tile-left-needs-action:before {
|
||||
// @extend .md-tile-left;
|
||||
// background-color: rgba(255, 255, 0, 0.3) !important;
|
||||
// content: "?";
|
||||
//}
|
||||
//.md-tile-left-tentative:before {
|
||||
// @extend .md-tile-left;
|
||||
// background-color: rgba(255, 255, 0, 0.3) !important;
|
||||
// content: "\e7fd"; // person
|
||||
//}
|
||||
//.sg-avatar {
|
||||
// @extend .md-tile-left-card;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-list-avatar {
|
||||
// @extend .md-tile-left-list;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-selected-avatar {
|
||||
// @extend .md-tile-left-selected;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-accepted {
|
||||
// @extend .md-tile-left-accepted;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-declined {
|
||||
// @extend .md-tile-left-declined;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-delegated {
|
||||
// @extend .md-tile-left-delegated;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-needs-action {
|
||||
// @extend .md-tile-left-needs-action;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
//.sg-tentative {
|
||||
// @extend .md-tile-left-tentative;
|
||||
// margin-right: 0;
|
||||
// margin-left: 0;
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user