Browse Source

[Web] Improve responsive design (#4171)

Complete styling for mobile devices

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
Kristian Feldsam 4 years ago
parent
commit
f73ac284e5

+ 94 - 77
data/web/admin.php

@@ -12,7 +12,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
 ?>
 <div class="container">
 
-  <ul class="nav nav-tabs" role="tablist">
+  <ul class="nav nav-tabs responsive-tabs" role="tablist">
     <li class="dropdown active">
       <a class="dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['access'];?><span class="caret"></span></a>
       <ul class="dropdown-menu">
@@ -52,15 +52,16 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
   <div class="tab-content" style="padding-top:20px">
   <div role="tabpanel" class="tab-pane active" id="tab-config-admins">
     <div class="panel panel-danger">
-      <div class="panel-heading"><?=$lang['admin']['admin_details'];?></div>
+      <div class="panel-heading xs-show"><?=$lang['admin']['admin_details'];?></div>
       <div class="panel-body">
         <div class="table-responsive">
           <table class="table table-striped table-condensed" id="adminstable"></table>
         </div>
         <div class="mass-actions-admin">
           <div class="btn-group">
-            <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="admins" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-            <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="admins" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+            <div class="clearfix visible-xs"></div>
             <ul class="dropdown-menu">
               <li><a data-action="edit_selected" data-id="admins" data-api-url='edit/admin' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
               <li><a data-action="edit_selected" data-id="admins" data-api-url='edit/admin' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
@@ -69,7 +70,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               <li role="separator" class="divider"></li>
               <li><a data-action="delete_selected" data-id="admins" data-api-url='delete/admin' href="#"><?=$lang['mailbox']['remove'];?></a></li>
             </ul>
-            <a class="btn btn-sm btn-success" data-id="add_admin" data-toggle="modal" data-target="#addAdminModal" href="#"><i class="bi bi-person-plus-fill"></i> <?=$lang['admin']['add_admin'];?></a>
+            <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-id="add_admin" data-toggle="modal" data-target="#addAdminModal" href="#"><i class="bi bi-person-plus-fill"></i> <?=$lang['admin']['add_admin'];?></a>
           </div>
         </div>
 
@@ -118,8 +119,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         <i class="bi bi-shield-fill-check"></i>
         <?=$lang['fido2']['fido2_auth'];?></legend>
         <div class="row">
-          <div class="col-sm-3 col-xs-5 text-right"><?=$lang['fido2']['known_ids'];?>:</div>
-          <div class="col-sm-9 col-xs-7">
+          <div class="col-sm-3 col-xs-12 text-right text-xs-left space20"><?=$lang['fido2']['known_ids'];?>:</div>
+          <div class="col-sm-9 col-xs-12">
               <div class="table-responsive">
               <table class="table table-striped table-hover table-condensed" id="fido2_keys">
                 <tr>
@@ -155,7 +156,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         </div>
         <div class="row">
           <div class="col-sm-offset-3 col-sm-9">
-            <button class="btn btn-sm btn-primary" id="register-fido2"><?=$lang['fido2']['set_fido2'];?></button>
+            <button class="btn btn-sm btn-primary visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline" id="register-fido2"><?=$lang['fido2']['set_fido2'];?></button>
           </div>
         </div>
         <br>
@@ -192,7 +193,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             <div class="col-sm-offset-3 col-sm-9">
               <p class="help-block"><?=$lang['admin']['license_info'];?></p>
               <div class="btn-group">
-                <button class="btn btn-sm btn-success" name="license_validate_now" type="submit" href="#"><?=$lang['admin']['validate_license_now'];?></button>
+                <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" name="license_validate_now" type="submit" href="#"><?=$lang['admin']['validate_license_now'];?></button>
               </div>
             </div>
           </div>
@@ -247,8 +248,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
                     <div class="form-group">
                       <div class="col-sm-offset-3 col-sm-9">
                         <div class="btn-group">
-                          <button class="btn btn-sm btn-success" name="admin_api[ro]" type="submit" href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
-                          <button class="btn btn-sm btn-default admin-ays-dialog" name="admin_api_regen_key[ro]" type="submit" href="#" <?=(!empty($api_ro['api_key'])) ?: 'disabled';?>><?=$lang['admin']['regen_api_key'];?></button>
+                          <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" name="admin_api[ro]" type="submit" href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                          <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default admin-ays-dialog" name="admin_api_regen_key[ro]" type="submit" href="#" <?=(!empty($api_ro['api_key'])) ?: 'disabled';?>><?=$lang['admin']['regen_api_key'];?></button>
                         </div>
                       </div>
                     </div>
@@ -292,8 +293,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
                     <div class="form-group">
                       <div class="col-sm-offset-3 col-sm-9">
                         <div class="btn-group">
-                          <button class="btn btn-sm btn-success" name="admin_api[rw]" type="submit" href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
-                          <button class="btn btn-sm btn-default admin-ays-dialog" name="admin_api_regen_key[rw]" type="submit" <?=(!empty($api_rw['api_key'])) ?: 'disabled';?> href="#"><?=$lang['admin']['regen_api_key'];?></button>
+                          <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" name="admin_api[rw]" type="submit" href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                          <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default admin-ays-dialog" name="admin_api_regen_key[rw]" type="submit" <?=(!empty($api_rw['api_key'])) ?: 'disabled';?> href="#"><?=$lang['admin']['regen_api_key'];?></button>
                         </div>
                       </div>
                     </div>
@@ -307,15 +308,15 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
     </div>
 
     <div class="panel panel-default">
-    <div class="panel-heading"><?=$lang['admin']['domain_admins'];?></div>
+    <div class="panel-heading xs-show"><?=$lang['admin']['domain_admins'];?></div>
         <div class="panel-body">
           <div class="table-responsive">
             <table class="table table-striped table-condensed" id="domainadminstable"></table>
           </div>
           <div class="mass-actions-admin">
             <div class="btn-group">
-              <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="domain_admins" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-              <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+              <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="domain_admins" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+              <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
               <ul class="dropdown-menu">
                 <li><a data-action="edit_selected" data-id="domain_admins" data-api-url='edit/domain-admin' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                 <li><a data-action="edit_selected" data-id="domain_admins" data-api-url='edit/domain-admin' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
@@ -324,7 +325,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
                 <li role="separator" class="divider"></li>
                 <li><a data-action="delete_selected" data-id="domain_admins" data-api-url='delete/domain-admin' href="#"><?=$lang['mailbox']['remove'];?></a></li>
               </ul>
-              <a class="btn btn-sm btn-success" data-id="add_domain_admin" data-toggle="modal" data-target="#addDomainAdminModal" href="#"><i class="bi bi-person-plus-fill"></i> <?=$lang['admin']['add_domain_admin'];?></a>
+              <div class="clearfix visible-xs"></div>
+              <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-id="add_domain_admin" data-toggle="modal" data-target="#addDomainAdminModal" href="#"><i class="bi bi-person-plus-fill"></i> <?=$lang['admin']['add_domain_admin'];?></a>
             </div>
           </div>
         </div>
@@ -349,8 +351,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
           </div>
           <div class="mass-actions-admin">
             <div class="btn-group">
-              <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="oauth2_clients" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-              <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+              <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="oauth2_clients" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+              <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
               <ul class="dropdown-menu">
                 <li><a data-action="delete_selected" data-id="oauth2_clients" data-api-url='delete/oauth2-client' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 <li role="separator" class="divider"></li>
@@ -358,7 +360,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
                 <li role="separator" class="divider"></li>
                 <li><a data-action="edit_selected" data-id="oauth2_clients" data-api-url='edit/oauth2-client' data-api-attr='{"renew_secret":"1"}' href="#"><?=$lang['admin']['oauth2_renew_secret'];?></a></li>
               </ul>
-              <a class="btn btn-sm btn-success" data-id="add_oauth2_client" data-toggle="modal" data-target="#addOAuth2ClientModal" href="#"><i class="bi bi-plus-lg"></i> Add OAuth2 client</a>
+              <div class="clearfix visible-xs"></div>
+              <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-id="add_oauth2_client" data-toggle="modal" data-target="#addOAuth2ClientModal" href="#"><i class="bi bi-plus-lg"></i> Add OAuth2 client</a>
             </div>
           </div>
         </div>
@@ -372,7 +375,10 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
       </div>
       <div class="panel-body">
         <div class="row">
-          <div class="col-sm-9">
+          <div class="col-xs-12 visible-xs">
+            <img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI">
+          </div>
+          <div class="col-sm-9 col-xs-12">
           <form class="form-horizontal" autocapitalize="none" data-id="admin" autocorrect="off" role="form" method="post">
             <div class="form-group">
               <div class="col-sm-offset-3 col-sm-9">
@@ -395,12 +401,12 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             </div>
             <div class="form-group">
               <div class="col-sm-offset-3 col-sm-9">
-                <button type="submit" class="btn btn-sm btn-success" id="rspamd_ui" name="rspamd_ui" href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                <button type="submit" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" id="rspamd_ui" name="rspamd_ui" href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
               </div>
             </div>
           </form>
           </div>
-          <div class="col-sm-3">
+          <div class="col-sm-3 hidden-xs">
             <img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI">
           </div>
         </div>
@@ -418,14 +424,15 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         </div>
         <div class="mass-actions-admin">
           <div class="btn-group btn-group-sm">
-            <button type="button" id="toggle_multi_select_all" data-id="rlyhosts" class="btn btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
-            <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
-            <ul class="dropdown-menu">
+            <button type="button" id="toggle_multi_select_all" data-id="rlyhosts" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+            <ul class="dropdown-menu top100">
               <li><a data-action="edit_selected" data-id="rlyhosts" data-api-url='edit/relayhost' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
               <li><a data-action="edit_selected" data-id="rlyhosts" data-api-url='edit/relayhost' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
               <li role="separator" class="divider"></li>
               <li><a data-action="delete_selected" data-id="rlyhosts" data-api-url='delete/relayhost' href="#"><?=$lang['admin']['remove'];?></a></li>
             </ul>
+            <div class="clearfix visible-xs"></div>
           </div>
         </div>
         <legend><?=$lang['admin']['add_relayhost'];?></legend>
@@ -445,7 +452,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
                 <label for="rlyhost_password"><?=$lang['admin']['password'];?></label>
                 <input class="form-control" id="rlyhost_password" name="password">
               </div>
-              <button class="btn btn-default" data-action="add_item" data-id="rlyhost" data-api-url='add/relayhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+              <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="rlyhost" data-api-url='add/relayhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
             </form>
           </div>
         </div>
@@ -461,14 +468,15 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         </div>
         <div class="mass-actions-admin">
           <div class="btn-group btn-group-sm">
-            <button type="button" id="toggle_multi_select_all" data-id="transports" class="btn btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
-            <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
-            <ul class="dropdown-menu">
+            <button type="button" id="toggle_multi_select_all" data-id="transports" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+            <ul class="dropdown-menu top100">
               <li><a data-action="edit_selected" data-id="transports" data-api-url='edit/transport' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
               <li><a data-action="edit_selected" data-id="transports" data-api-url='edit/transport' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
               <li role="separator" class="divider"></li>
               <li><a data-action="delete_selected" data-id="transports" data-api-url='delete/transport' href="#"><?=$lang['admin']['remove'];?></a></li>
             </ul>
+            <div class="clearfix visible-xs"></div>
           </div>
         </div>
         <legend><?=$lang['admin']['add_transport'];?></legend>
@@ -503,7 +511,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
                 </label>
               </div>
               <p class="help-block"><?=$lang['admin']['credentials_transport_warning'];?></p>
-              <button class="btn btn-default" data-action="add_item" data-id="transport" data-api-url='add/transport' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+              <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="transport" data-api-url='add/transport' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
             </form>
           </div>
         </div>
@@ -516,9 +524,10 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
       <div class="panel-heading"><?=$lang['admin']['dkim_keys'];?></div>
       <div class="panel-body">
         <div class="btn-group" data-toggle="button" style="margin-bottom: 20px;">
-          <a class="btn btn-sm btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_valid"><?=$lang['admin']['dkim_key_valid'];?></a>
-          <a class="btn btn-sm btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_unused"><?=$lang['admin']['dkim_key_unused'];?></a>
-          <a class="btn btn-sm btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_missing"><?=$lang['admin']['dkim_key_missing'];?></a>
+          <a class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_valid"><?=$lang['admin']['dkim_key_valid'];?></a>
+          <a class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_unused"><?=$lang['admin']['dkim_key_unused'];?></a>
+          <a class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_missing"><?=$lang['admin']['dkim_key_missing'];?></a>
+          <div class="clearfix visible-xs"></div>
         </div>
         <?php
         foreach(mailbox('get', 'domains') as $domain) {
@@ -617,8 +626,9 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         ?>
         <div class="mass-actions-admin">
           <div class="btn-group btn-group-sm">
-            <button type="button" id="toggle_multi_select_all" data-id="dkim" class="btn btn-default"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></button>
-            <button type="button" data-action="delete_selected" name="delete_selected" data-id="dkim" data-api-url="delete/dkim" class="btn btn-danger"><i class="bi bi-trash"></i> <?=$lang['admin']['remove'];?></button>
+            <button type="button" id="toggle_multi_select_all" data-id="dkim" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></button>
+            <button type="button" data-action="delete_selected" name="delete_selected" data-id="dkim" data-api-url="delete/dkim" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger"><i class="bi bi-trash"></i> <?=$lang['admin']['remove'];?></button>
+            <div class="clearfix visible-xs"></div>
           </div>
         </div>
 
@@ -634,12 +644,12 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             <input class="form-control input-sm" id="dkim_selector" name="dkim_selector" value="dkim" required>
           </div>
           <div class="form-group">
-            <select data-width="200px" data-style="btn btn-default btn-sm" class="form-control" id="key_size" name="key_size" title="<?=$lang['admin']['dkim_key_length'];?>" required>
+            <select data-style="btn btn-default btn-sm" class="form-control" id="key_size" name="key_size" title="<?=$lang['admin']['dkim_key_length'];?>" required>
               <option data-subtext="bits">1024</option>
               <option data-subtext="bits">2048</option>
             </select>
           </div>
-          <button class="btn btn-sm btn-default" data-action="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+          <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
         </form>
 
         <legend data-target="#import_dkim" style="margin-top:40px;cursor:pointer" unselectable="on" data-toggle="collapse">
@@ -664,7 +674,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               <input type="checkbox" name="overwrite_existing" value="1"> <?=$lang['admin']['dkim_overwrite_key'];?>
             </label>
           </div>
-          <button class="btn btn-sm btn-default" data-action="add_item" data-id="dkim_import" data-api-url='add/dkim_import' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['import'];?></button>
+          <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="dkim_import" data-api-url='add/dkim_import' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['import'];?></button>
         </form>
         </div>
 
@@ -710,7 +720,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               </select>
               </div>
             </div>
-            <button class="btn btn-sm btn-default" data-action="add_item" data-id="dkim_duplicate" data-api-url='add/dkim_duplicate' data-api-attr='{}' href="#"><i class="bi bi-clipboard-plus"></i> <?=$lang['admin']['duplicate'];?></button>
+            <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="dkim_duplicate" data-api-url='add/dkim_duplicate' data-api-attr='{}' href="#"><i class="bi bi-clipboard-plus"></i> <?=$lang['admin']['duplicate'];?></button>
           </form>
         </div>
       </div>
@@ -727,14 +737,15 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         </div>
         <div class="mass-actions-admin">
           <div class="btn-group btn-group-sm">
-            <button type="button" id="toggle_multi_select_all" data-id="fwdhosts" class="btn btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
-            <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
-            <ul class="dropdown-menu">
+            <button type="button" id="toggle_multi_select_all" data-id="fwdhosts" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+            <ul class="dropdown-menu top100">
               <li><a data-action="edit_selected" data-id="fwdhosts" data-api-url='edit/fwdhost' data-api-attr='{"keep_spam":"0"}' href="#">Enable spam filter</a></li>
               <li><a data-action="edit_selected" data-id="fwdhosts" data-api-url='edit/fwdhost' data-api-attr='{"keep_spam":"1"}' href="#">Disable spam filter</a></li>
               <li role="separator" class="divider"></li>
               <li><a data-action="delete_selected" data-id="fwdhosts" data-api-url='delete/fwdhost' href="#"><?=$lang['admin']['remove'];?></a></li>
             </ul>
+            <div class="clearfix visible-xs"></div>
           </div>
         </div>
         <legend><?=$lang['admin']['add_forwarding_host'];?></legend>
@@ -750,7 +761,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               <option value="0"><?=$lang['admin']['inactive'];?></option>
             </select>
           </div>
-          <button class="btn btn-default" data-action="add_item" data-id="fwdhost" data-api-url='add/fwdhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+          <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="fwdhost" data-api-url='add/fwdhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
         </form>
       </div>
     </div>
@@ -801,12 +812,15 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             <textarea class="form-control" id="f2b_blacklist" name="blacklist" rows="5"><?=$f2b_data['blacklist'];?></textarea>
           </div>
           <div class="btn-group">
-            <button class="btn btn-sm btn-success" data-action="edit_selected" data-item="self" data-id="f2b" data-api-url='edit/fail2ban' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
-            <a href="#" role="button" class="btn btn-sm btn-default" data-toggle="modal" data-container="netfilter-mailcow" data-target="#RestartContainer"><i class="bi bi-arrow-repeat"></i> <?= $lang['header']['restart_netfilter']; ?></a>
+            <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="self" data-id="f2b" data-api-url='edit/fail2ban' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+            <a href="#" role="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-toggle="modal" data-container="netfilter-mailcow" data-target="#RestartContainer"><i class="bi bi-arrow-repeat"></i> <?= $lang['header']['restart_netfilter']; ?></a>
+            <div class="clearfix visible-xs"></div>
           </div>
         </form>
-        <hr>
-        <h4><?=$lang['admin']['f2b_filter'];?></h4>
+        <legend data-target="#f2b_regex_filters" style="margin-top:40px;cursor:pointer" unselectable="on" data-toggle="collapse">
+          <i style="font-size:10pt;" class="bi bi-plus-square"></i> <?=$lang['admin']['f2b_filter'];?>
+        </legend>
+        <div id="f2b_regex_filters" class="collapse">
         <p class="help-block"><?=$lang['admin']['f2b_regex_info'];?></p>
         <form class="form-inline" data-id="f2b_regex" role="form" method="post">
           <table class="table table-condensed" id="f2b_regex_table">
@@ -820,9 +834,9 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               foreach ($f2b_data['regex'] as $regex_id => $regex_val) {
             ?>
             <tr>
-              <td><input disabled class="input-sm form-control" style="text-align:center" data-id="f2b_regex" type="text" name="app" required value="<?=$regex_id;?>"></td>
-              <td><input class="input-sm form-control regex-input" data-id="f2b_regex" type="text" name="regex" required value="<?=htmlspecialchars($regex_val);?>"></td>
-              <td><a href="#" role="button" class="btn btn-xs btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
+              <td><input disabled class="input-sm input-xs-lg form-control" style="text-align:center" data-id="f2b_regex" type="text" name="app" required value="<?=$regex_id;?>"></td>
+              <td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required value="<?=htmlspecialchars($regex_val);?>"></td>
+              <td><a href="#" role="button" class="btn btn-xs btn-xs-lg btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
             </tr>
             <?php
               }
@@ -830,12 +844,13 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             ?>
           </table>
           <p><div class="btn-group">
-            <button class="btn btn-sm btn-success" data-action="edit_selected" data-item="admin" data-id="f2b_regex" data-reload="no" data-api-url='edit/fail2ban' data-api-attr='{"action":"edit-regex"}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
-            <button class="btn btn-sm btn-default admin-ays-dialog" data-action="edit_selected" data-item="self" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"reset-regex"}' href="#"><?=$lang['admin']['reset_default'];?></button>
-            <button class="btn btn-sm btn-default" type="button" id="add_f2b_regex_row"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add_row'];?></button>
+            <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="admin" data-id="f2b_regex" data-reload="no" data-api-url='edit/fail2ban' data-api-attr='{"action":"edit-regex"}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+            <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default admin-ays-dialog" data-action="edit_selected" data-item="self" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"reset-regex"}' href="#"><?=$lang['admin']['reset_default'];?></button>
+            <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="button" id="add_f2b_regex_row"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add_row'];?></button>
           </div></p>
         </form>
-        <hr>
+        </div>
+
         <p class="help-block"><?=$lang['admin']['ban_list_info'];?></p>
         <?php
         if (empty($f2b_data['active_bans']) && empty($f2b_data['perm_bans'])):
@@ -886,7 +901,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         <?php $q_data = quarantine('settings');
         if (empty($q_data['retention_size']) || empty($q_data['max_size'])):
         ?>
-        <div class="panel-body"><div class="alert alert-info"><?=$lang['quarantine']['disabled_by_config'];?></div></div>
+        <div class="alert alert-info"><?=$lang['quarantine']['disabled_by_config'];?></div>
         <?php
         endif;
         ?>
@@ -972,7 +987,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
           <div id="quarantine_template" class="collapse" >
             <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="40" name="html_tmpl"><?=$q_data['html_tmpl'];?></textarea>
           </div>
-          <button class="btn btn-sm btn-success" data-action="edit_selected" data-item="self" data-id="quarantine" data-api-url='edit/quarantine' data-api-attr='{"action":"settings"}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+          <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="self" data-id="quarantine" data-api-url='edit/quarantine' data-api-attr='{"action":"settings"}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
         </form>
       </div>
     </div>
@@ -1014,7 +1029,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
           <div class="col-sm-10">
             <div class="form-group">
               <br>
-              <a type="button" class="btn btn-sm btn-success" data-action="edit_selected"
+              <a type="button" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected"
                 data-item="quota_notification"
                 data-id="quota_notification"
                 data-api-url='edit/quota_notification'
@@ -1124,7 +1139,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
         <form class="form-inline" role="form" method="post" enctype="multipart/form-data">
           <p>
             <input type="file" name="main_logo" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml"><br>
-            <button name="submit_main_logo" type="submit" class="btn btn-xs btn-default"><i class="bi bi-upload"></i> <?=$lang['admin']['upload'];?></button>
+            <button name="submit_main_logo" type="submit" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><i class="bi bi-upload"></i> <?=$lang['admin']['upload'];?></button>
           </p>
         </form>
         <?php
@@ -1143,7 +1158,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             </div>
             <hr>
             <form class="form-inline" role="form" method="post">
-              <p><button name="reset_main_logo" type="submit" class="btn btn-xs btn-default"><?=$lang['admin']['reset_default'];?></button></p>
+              <p><button name="reset_main_logo" type="submit" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><?=$lang['admin']['reset_default'];?></button></p>
             </form>
           </div>
         </div>
@@ -1163,9 +1178,9 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               foreach ($row as $key => $val) {
             ?>
             <tr>
-              <td><input class="input-sm form-control" data-id="app_links" type="text" name="app" required value="<?=$key;?>"></td>
-              <td><input class="input-sm form-control" data-id="app_links" type="text" name="href" required value="<?=$val;?>"></td>
-              <td><a href="#" role="button" class="btn btn-xs btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
+              <td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required value="<?=$key;?>"></td>
+              <td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required value="<?=$val;?>"></td>
+              <td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
             </tr>
             <?php
               }
@@ -1173,15 +1188,16 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
             foreach ($MAILCOW_APPS as $app) {
             ?>
             <tr>
-              <td><input class="input-sm form-control" value="<?=htmlspecialchars($app['name']);?>" disabled></td>
-              <td><input class="input-sm form-control" value="<?=htmlspecialchars($app['link']);?>" disabled></td>
+              <td><input class="input-sm input-xs-lg form-control" value="<?=htmlspecialchars($app['name']);?>" disabled></td>
+              <td><input class="input-sm input-xs-lg form-control" value="<?=htmlspecialchars($app['link']);?>" disabled></td>
               <td>&nbsp;</td>
             </tr>
             <?php } ?>
           </table>
           <p><div class="btn-group">
-            <button class="btn btn-sm btn-success" data-action="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
-            <button class="btn btn-sm btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
+            <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+            <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
+            <div class="clearfix visible-xs"></div>
           </div></p>
         </form>
         <legend data-target="#ui_texts" style="padding-top:20px" unselectable="on"><?=$lang['admin']['ui_texts'];?></legend>
@@ -1225,7 +1241,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
               <label for="ui_footer"><?=$lang['admin']['ui_footer'];?>:</label>
               <textarea class="form-control" id="ui_footer" name="ui_footer" rows="7"><?=$ui_texts['ui_footer'];?></textarea>
             </div>
-            <button class="btn btn-sm btn-success" data-action="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+            <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
           </form>
         </div>
       </div>
@@ -1266,7 +1282,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
           <div class="form-group">
             <div class="col-sm-offset-3 col-sm-9">
               <div class="btn-group">
-                <button class="btn btn-sm btn-success" data-item="passwordpolicy" data-action="edit_selected" data-id="passwordpolicy" data-api-url='edit/passwordpolicy' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-item="passwordpolicy" data-action="edit_selected" data-id="passwordpolicy" data-api-url='edit/passwordpolicy' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
               </div>
             </div>
           </div>
@@ -1357,7 +1373,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" type="submit" id="mass_send" name="mass_send" disabled><i class="bi bi-envelope-fill"></i> <?=$lang['admin']['send'];?></button>
+              <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" type="submit" id="mass_send" name="mass_send" disabled><i class="bi bi-envelope-fill"></i> <?=$lang['admin']['send'];?></button>
             </div>
           </div>
         </form>
@@ -1379,23 +1395,24 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
       </div>
       <div class="mass-actions-admin">
         <div class="btn-group">
-          <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="mailqitems" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-          <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
-          <ul class="dropdown-menu">
+          <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="mailqitems" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+          <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+          <ul class="dropdown-menu top33">
             <li><a data-toggle="tooltip" title="postqueue -i" data-action="edit_selected" data-id="mailqitems" data-api-url='edit/mailq' data-api-attr='{"action":"deliver"}' href="#"><?=$lang['admin']['queue_deliver_mail'];?></a></li>
             <li><a data-toggle="tooltip" title="postsuper -H" data-action="edit_selected" data-id="mailqitems" data-api-url='edit/mailq' data-api-attr='{"action":"unhold"}' href="#"><?=$lang['admin']['queue_unhold_mail'];?></a></li>
             <li><a data-toggle="tooltip" title="postsuper -h" data-action="edit_selected" data-id="mailqitems" data-api-url='edit/mailq' data-api-attr='{"action":"hold"}' href="#"><?=$lang['admin']['queue_hold_mail'];?></a></li>
             <li role="separator" class="divider"></li>
             <li><a data-toggle="tooltip" title="postsuper -d" data-action="delete_selected" data-id="mailqitems" data-api-url='delete/mailq' href="#"><?=$lang['mailbox']['remove'];?></a></li>
           </ul>
-          <a class="btn btn-sm btn-primary"
+          <div class="clearfix visible-xs"></div>
+          <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-primary"
             data-action="edit_selected"
             data-item="mailqitems-all"
             data-api-url='edit/mailq'
             data-api-attr='{"action":"flush"}'
             data-toggle="tooltip" title="postqueue -f"
             href="#"><i class="bi bi-check-all"></i> <?=$lang['admin']['flush_queue'];?></a>
-          <a class="btn btn-sm btn-danger"
+          <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger"
             id="super_delete"
             data-action="edit_selected"
             data-item="mailqitems-all"
@@ -1453,8 +1470,8 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
           </div>
           <div class="form-group">
             <div class="col-sm-offset-3 col-sm-9">
-              <button class="btn btn-xs btn-default validate_rspamd_regex" data-regex-map="<?=$rspamd_regex_map;?>" href="#"><?=$lang['add']['validate'];?></button>
-              <button class="btn btn-xs btn-success submit_rspamd_regex" data-action="edit_selected" data-id="<?=$rspamd_regex_map;?>" data-item="<?=htmlspecialchars($rspamd_regex_map);?>" data-api-url='edit/rspamd-map' data-api-attr='{}' href="#" disabled><?=$lang['edit']['save'];?></button>
+              <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_rspamd_regex" data-regex-map="<?=$rspamd_regex_map;?>" href="#"><?=$lang['add']['validate'];?></button>
+              <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success submit_rspamd_regex" data-action="edit_selected" data-id="<?=$rspamd_regex_map;?>" data-item="<?=htmlspecialchars($rspamd_regex_map);?>" data-api-url='edit/rspamd-map' data-api-attr='{}' href="#" disabled><?=$lang['edit']['save'];?></button>
             </div>
           </div>
         </form>

+ 241 - 0
data/web/css/build/014-responsive.css

@@ -0,0 +1,241 @@
+.space20 {
+  margin-bottom: 20px;
+}
+
+.btn-xs-lg>.lang-sm:after {
+  margin-left: 4px;
+}
+
+.bootstrap-select {
+	max-width: 350px;
+}
+
+
+@media (max-width: 767px) {	
+	.xs-show {
+		display: block !important;
+	}
+	
+	.js-tabcollapse-panel-group .panel{
+	  border: none;
+	  box-shadow: none;
+	}
+	
+	.js-tabcollapse-panel-group .panel-body {
+	  padding: 10px 0;
+	}
+	
+	.js-tabcollapse-panel-group .js-tabcollapse-panel-body .panel-body {
+		padding: 0;
+	}
+	
+	.js-tabcollapse-panel-body .panel-heading {
+	  display: none;
+	}
+	
+	.js-tabcollapse-panel-body .well,
+	.panel-body .form-inline.well {
+		border: none;
+		padding: 0;
+		margin: 0;
+		box-shadow: none;
+		background-color: #fff;
+	}
+	
+	.js-tabcollapse-panel-heading {
+	  display: block;
+	  height: 37px;
+	  line-height: 37px;
+	  text-indent: 15px;
+	}
+	.js-tabcollapse-panel-heading:hover {
+	  text-decoration: none;
+	}
+	.js-tabcollapse-panel-heading {
+	  position: relative;
+	}
+	.js-tabcollapse-panel-heading:after {
+	  content: '';
+	  display: block;
+	  position: absolute;
+	  top: 17px;
+	  right: 17px;
+	  width: 0;
+	  height: 0;
+	  margin-left: 2px;
+	  vertical-align: middle;
+	  border-bottom: 4px dashed;
+	  border-right: 4px solid transparent;
+	  border-left: 4px solid transparent;
+	}
+	.js-tabcollapse-panel-heading.collapsed:after {
+	  border-bottom: none;
+	  border-top: 4px dashed;
+	}
+	
+  .recent-login-success {
+	margin-top: 10px !important;
+  }
+  .pull-xs-right {
+	float: right !important;
+  }
+  .pull-xs-right .dropdown-menu {
+	right: 0;
+	left: auto;
+  }
+  .text-xs-left {
+    text-align: left;
+  }
+  .text-xs-bold {
+    font-weight: bold;
+  }
+  .text-xs-bold .small {
+    font-weight: normal;
+    text-align: justify;
+  }
+  .help-block {
+    text-align: justify;
+  }
+  .btn.visible-xs-block {
+    width: 100%;
+    float: none;
+    white-space: normal;
+  }
+  .btn-group.footable-actions .btn.btn-xs-half,
+  .btn.visible-xs-block.btn-xs-half {
+    width: 50%;
+    float: left;
+  }
+  .btn-group.footable-actions .btn.btn-xs-third,
+  .btn.visible-xs-block.btn-xs-third {
+    width: 33.33%;
+    float: left;
+  }
+  .btn-group.footable-actions .btn.btn-xs-quart,
+  .btn.visible-xs-block.btn-xs-quart {
+    width: 25%;
+    float: left;
+  }
+  .btn.visible-xs-block.btn-sm,
+  .btn-xs-lg {
+    padding: 15px 16px 13px;
+    line-height: 15px;
+  }
+  .input-xs-lg {
+	height: 47px;
+    padding: 13px 16px;
+  }
+  .btn-group:not(.input-group-btn) {
+    display: block;
+  }
+  .mass-actions-user .btn-group {
+    float: none;
+  }
+  div[class^='mass-actions'] .dropdown-menu,
+  .panel-xs-lg .dropdown-menu,
+  .dropdown-menu.login {
+    width: 100%;
+  }
+  div[class^='mass-actions'] .btn-group .dropdown-menu {
+	top: 50%;
+  }
+  div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
+  div.mass-actions-quarantine .btn-group .dropdown-menu,
+  .panel-xs-lg .dropdown-menu {
+    top: 100%;
+  }
+  div[class^='mass-actions'] .dropdown-menu>li>a,
+  .panel-xs-lg .dropdown-menu>li>a,
+  .dropdown-menu.login>li>a {
+    padding: 8px 20px;
+  }
+  div[class^='mass-actions'] .dropdown-header {
+	  font-size: 14px;
+	  font-weight: bold;
+  }
+  .space20 {
+    margin-bottom: 10px;
+  }
+  .top100 {
+	  top: 100% !important;
+  }
+  .top33 {
+	  top: 33% !important;
+  }
+  .footable-filtering .form {
+    width: 65%;
+  }
+  .btn-xs-lg>.lang-sm:after {
+    top: 1px;
+  }
+  table.footable>tfoot>tr.footable-paging>td {
+    text-align: left;
+  }
+  .footable-first-visible {
+	  min-width: 55px;
+  }
+  table>tbody>tr>td>span.footable-toggle {
+	  font-size: 24px;
+	  margin-right: 14px !important;
+  }
+  table>tbody>tr>td>span.footable-toggle + input {
+	  position: absolute;
+	  left: 38px;
+  }
+  .pagination {
+    margin-bottom: 5px;
+  }
+  tr.footable-filtering>th>form {
+	  width: 270px;
+  }
+  .mass-actions-mailbox {
+    padding: 0;
+  }
+  .panel-xs-lg .panel-heading {
+	  height: 66px;
+	  line-height: 47px;
+  }
+  .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
+	  width: 100%;
+  }
+  .btn-group:not(.bootstrap-select) {
+	  width: auto !important;
+  }
+  .bootstrap-select {
+	  max-width: 100%;
+  }
+  .img-responsive {
+	  margin: 0 auto;
+  }
+  .recent-login-success {
+	  font-size: 16px;
+  }
+  .btn-group.footable-actions {
+	position: absolute;
+    width: 90vw !important;
+    left: 0;
+    height: 36px;
+    margin-top: -8px;
+  }
+  .btn-group.footable-actions .btn {
+	padding: 10px 16px 7px;
+    line-height: 15px;
+    display: block;
+    width: 100%;
+  }
+  .btn-group.footable-actions:after {
+	  content: "";
+	  display: block;
+	  clear: both;
+  }
+  .bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
+	  margin-right: 14px;
+	  white-space: normal;
+  }
+}
+
+@media (max-width: 350px) {
+  .mailcow-logo img {
+    max-width: 250px;
+  }
+}

+ 1 - 1
data/web/css/site/quarantine.css

@@ -35,7 +35,7 @@
 
 .mass-actions-quarantine {
   user-select: none;
-  padding: 10px 0 10px 10px;
+  padding: 10px;
 }
 
 .inputMissingAttr {

+ 51 - 50
data/web/debug.php

@@ -130,9 +130,10 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
                 $started = '?';
               }
               ?>
-              <small>(<?=$lang['debug']['started_on'];?> <span class="parse_date"><?=$started;?></span>),
-              <a href data-toggle="modal" data-container="<?=$container;?>" data-target="#RestartContainer"><?=$lang['debug']['restart_container'];?></a></small>
+              <br class="visible-xs" />
+              <small>(<?=$lang['debug']['started_on'];?> <span class="parse_date"><?=$started;?></span>)</small>
               <i class="pull-right bi <?=($container_info['State'] !== false && !empty($container_info['State'])) ? (($container_info['State']['Running'] == 1) ? 'bi-app-indicator text-success' : 'bi-app text-danger') : 'default'; ?>"></i>
+              <a href data-toggle="modal" data-container="<?=$container;?>" data-target="#RestartContainer" class="btn btn-sm btn-text pull-right"><?=$lang['debug']['restart_container'];?></a>
               </li>
               <?php
               }
@@ -143,12 +144,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-postfix-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Postfix <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_postfix_logs" data-table="postfix_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_postfix_logs" data-table="postfix_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -160,12 +161,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-ui">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">mailcow UI <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="mailcow_ui" data-table="ui_logs" data-log-url="ui" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="mailcow_ui" data-table="ui_logs" data-log-url="ui" data-nrows="10000">+ 10000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_ui_logs" data-table="ui_logs"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="mailcow_ui" data-table="ui_logs" data-log-url="ui" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="mailcow_ui" data-table="ui_logs" data-log-url="ui" data-nrows="10000">+ 10000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_ui_logs" data-table="ui_logs"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -177,12 +178,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-sasl">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">SASL <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="sasl_log_table" data-table="sasl_logs" data-log-url="ui" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="sasl_log_table" data-table="sasl_logs" data-log-url="ui" data-nrows="10000">+ 10000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_sasl_logs" data-table="sasl_logs"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="sasl_log_table" data-table="sasl_logs" data-log-url="ui" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="sasl_log_table" data-table="sasl_logs" data-log-url="ui" data-nrows="10000">+ 10000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_sasl_logs" data-table="sasl_logs"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -194,12 +195,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-dovecot-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Dovecot <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_dovecot_logs" data-table="dovecot_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_dovecot_logs" data-table="dovecot_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -211,12 +212,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-sogo-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">SOGo <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_sogo_logs" data-table="sogo_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_sogo_logs" data-table="sogo_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -228,12 +229,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-netfilter-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Netfilter <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="netfilter_log" data-log-url="netfilter" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="netfilter_log" data-log-url="netfilter" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_netfilter_logs" data-table="netfilter_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="netfilter_log" data-log-url="netfilter" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="netfilter_log" data-log-url="netfilter" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_netfilter_logs" data-table="netfilter_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -245,12 +246,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-rspamd-history">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Rspamd history <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_rspamd_history" data-table="rspamd_history"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_rspamd_history" data-table="rspamd_history"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -267,12 +268,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-autodiscover-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Autodiscover <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_autodiscover_logs" data-table="autodiscover_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_autodiscover_logs" data-table="autodiscover_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -284,12 +285,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-watchdog-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Watchdog <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="watchdog" data-table="watchdog_log" data-log-url="watchdog" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="watchdog" data-table="watchdog_log" data-log-url="watchdog" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_watchdog_logs" data-table="watchdog_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="watchdog" data-table="watchdog_log" data-log-url="watchdog" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="watchdog" data-table="watchdog_log" data-log-url="watchdog" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_watchdog_logs" data-table="watchdog_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -301,12 +302,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-acme-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">ACME <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="acme_log" data-log-url="acme" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="acme_log" data-log-url="acme" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_acme_logs" data-table="acme_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="acme_log" data-log-url="acme" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="general_syslog" data-table="acme_log" data-log-url="acme" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_acme_logs" data-table="acme_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -318,12 +319,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-api-logs">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">API <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="apilog" data-table="api_log" data-log-url="api" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="apilog" data-table="api_log" data-log-url="api" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_api_logs" data-table="api_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="apilog" data-table="api_log" data-log-url="api" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="apilog" data-table="api_log" data-log-url="api" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_api_logs" data-table="api_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">
@@ -335,12 +336,12 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
         </div>
 
         <div role="tabpanel" class="tab-pane" id="tab-api-rl">
-          <div class="panel panel-default">
+          <div class="panel panel-xs-lg panel-default">
             <div class="panel-heading">Ratelimits <span class="badge badge-info table-lines"></span>
               <div class="btn-group pull-right">
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="rllog" data-table="rl_log" data-log-url="ratelimited" data-nrows="100">+ 100</button>
-                <button class="btn btn-xs btn-default add_log_lines" data-post-process="rllog" data-table="rl_log" data-log-url="ratelimited" data-nrows="1000">+ 1000</button>
-                <button class="btn btn-xs btn-default refresh_table" data-draw="draw_rl_logs" data-table="rl_log"><?=$lang['admin']['refresh'];?></button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="rllog" data-table="rl_log" data-log-url="ratelimited" data-nrows="100">+ 100</button>
+                <button class="btn btn-xs btn-xs-lg btn-default add_log_lines" data-post-process="rllog" data-table="rl_log" data-log-url="ratelimited" data-nrows="1000">+ 1000</button>
+                <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_rl_logs" data-table="rl_log"><?=$lang['admin']['refresh'];?></button>
               </div>
             </div>
             <div class="panel-body">

+ 60 - 54
data/web/edit.php

@@ -82,7 +82,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editalias" data-item="<?=htmlspecialchars($alias);?>" data-api-url='edit/alias' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editalias" data-item="<?=htmlspecialchars($alias);?>" data-api-url='edit/alias' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -157,7 +157,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
         </div>
         <div class="form-group">
           <div class="col-sm-offset-2 col-sm-10">
-            <button class="btn btn-success" data-action="edit_selected" data-api-reload-location="/admin" data-id="editdomainadmin" data-item="<?=$domain_admin;?>" data-api-url='edit/domain-admin' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+            <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-api-reload-location="/admin" data-id="editdomainadmin" data-item="<?=$domain_admin;?>" data-api-url='edit/domain-admin' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
           </div>
         </div>
       </form>
@@ -180,7 +180,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
               </select>
             </div>
             <div class="form-group">
-              <button class="btn btn-default" data-action="edit_selected" data-id="daacl" data-item="<?=htmlspecialchars($domain_admin);?>" data-api-url='edit/da-acl' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="daacl" data-item="<?=htmlspecialchars($domain_admin);?>" data-api-url='edit/da-acl' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
             </div>
           </div>
         </div>
@@ -237,7 +237,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
         </div>
         <div class="form-group">
           <div class="col-sm-offset-2 col-sm-10">
-            <button class="btn btn-success" data-action="edit_selected" data-api-reload-location="/admin" data-id="editadmin" data-item="<?=$admin;?>" data-api-url='edit/admin' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+            <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-api-reload-location="/admin" data-id="editadmin" data-item="<?=$admin;?>" data-api-url='edit/admin' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
           </div>
         </div>
       </form>
@@ -259,7 +259,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
         $rlyhosts = relayhost('get');
         if (!empty($result)) {
         ?>
-          <ul class="nav nav-tabs" role="tablist">
+          <ul class="nav nav-tabs responsive-tabs" role="tablist">
             <li class="active"><a data-toggle="tab" href="#dedit"><?=$lang['edit']['domain'];?></a></li>
             <li><a data-toggle="tab" href="#dratelimit"><?=$lang['edit']['ratelimit'];?></a></li>
             <li><a data-toggle="tab" href="#dspamfilter"><?=$lang['edit']['spam_filter'];?></a></li>
@@ -364,7 +364,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
               </div>
               <div class="form-group">
                 <div class="col-sm-offset-2 col-sm-10">
-                  <button class="btn btn-success" data-action="edit_selected" data-id="editdomain" data-item="<?=$domain;?>" data-api-url='edit/domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+                  <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editdomain" data-item="<?=$domain;?>" data-api-url='edit/domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
                 </div>
               </div>
             </form>
@@ -373,10 +373,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             ?>
             <hr>
             <div class="row">
-              <div class="col-xs-2">
+              <div class="col-xs-12 col-sm-2">
                 <p>Domain: <strong><?=htmlspecialchars($result['domain_name']);?></strong> (<?=$dkim['dkim_selector'];?>._domainkey)</p>
               </div>
-              <div class="col-xs-10">
+              <div class="col-xs-12 col-sm-10">
                 <pre><?=$dkim['dkim_txt'];?></pre>
               </div>
             </div>
@@ -399,7 +399,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                   </select>
                 </div>
                 <div class="form-group">
-                  <button data-acl="<?=$_SESSION['acl']['ratelimit'];?>" class="btn btn-default" data-action="edit_selected" data-id="domratelimit" data-item="<?=$domain;?>" data-api-url='edit/rl-domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+                  <button data-acl="<?=$_SESSION['acl']['ratelimit'];?>" class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="domratelimit" data-item="<?=$domain;?>" data-api-url='edit/rl-domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
                 </div>
               </form>
             </div>
@@ -408,13 +408,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                 <div class="col-sm-6">
                   <h4><?=$lang['user']['spamfilter_wl'];?></h4>
                   <p><?=$lang['user']['spamfilter_wl_desc'];?></p>
-                  <div class="mass-actions-user">
-                    <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
-                      <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                      <a class="btn btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_domain" data-api-url='delete/domain-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
-                    </div>
-                  </div>
-                  <form class="form-inline" data-id="add_wl_policy_domain">
+                  <form class="form-inline space20" data-id="add_wl_policy_domain">
                     <div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
                       <input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
                       <span class="input-group-btn">
@@ -425,17 +419,18 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                   <div class="table-responsive">
                     <table class="table table-striped table-condensed" id="wl_policy_domain_table"></table>
                   </div>
-                </div>
-                <div class="col-sm-6">
-                  <h4><?=$lang['user']['spamfilter_bl'];?></h4>
-                  <p><?=$lang['user']['spamfilter_bl_desc'];?></p>
                   <div class="mass-actions-user">
                     <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
-                      <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                      <a class="btn btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_domain" data-api-url='delete/domain-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+                      <a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                      <a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_domain" data-api-url='delete/domain-policy' href="#"><?=$lang['mailbox']['remove'];?></a>
+                      <div class="clearfix visible-xs"></div>
                     </div>
                   </div>
-                  <form class="form-inline" data-id="add_bl_policy_domain">
+                </div>
+                <div class="col-sm-6">
+                  <h4><?=$lang['user']['spamfilter_bl'];?></h4>
+                  <p><?=$lang['user']['spamfilter_bl_desc'];?></p>
+                  <form class="form-inline space20" data-id="add_bl_policy_domain">
                     <div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
                       <input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
                       <span class="input-group-btn">
@@ -446,6 +441,12 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                   <div class="table-responsive">
                     <table class="table table-striped table-condensed" id="bl_policy_domain_table"></table>
                   </div>
+                  <div class="mass-actions-user">
+                    <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
+                      <a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                      <a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_domain" data-api-url='delete/domain-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+                    </div>
+                  </div>
                 </div>
               </div>
             </div>
@@ -471,7 +472,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                     </div>
                     <div class="form-group">
                       <div class="col-sm-offset-2 col-sm-10">
-                        <button class="btn btn-success" data-action="edit_selected" data-id="quota_bcc" data-item="quota_bcc" data-api-url='edit/quota_notification_bcc' data-api-attr='{"domain":"<?=$domain;?>"}' href="#"><?=$lang['edit']['save'];?></button>
+                        <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="quota_bcc" data-item="quota_bcc" data-api-url='edit/quota_notification_bcc' data-api-attr='{"domain":"<?=$domain;?>"}' href="#"><?=$lang['edit']['save'];?></button>
                       </div>
                     </div>
                   </form>
@@ -522,7 +523,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-default" data-action="edit_selected" data-id="oauth2client" data-item="<?=$oauth2client;?>" data-api-url='edit/oauth2-client' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="oauth2client" data-item="<?=$oauth2client;?>" data-api-url='edit/oauth2-client' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
               </div>
             </div>
           </form>
@@ -568,7 +569,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editaliasdomain" data-item="<?=$alias_domain;?>" data-api-url='edit/alias-domain' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editaliasdomain" data-item="<?=$alias_domain;?>" data-api-url='edit/alias-domain' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -587,7 +588,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
               </select>
             </div>
             <div class="form-group">
-              <button class="btn btn-default" data-action="edit_selected" data-id="domratelimit" data-item="<?=$alias_domain;?>" data-api-url='edit/rl-domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="domratelimit" data-item="<?=$alias_domain;?>" data-api-url='edit/rl-domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
             </div>
           </form>
           <?php
@@ -595,10 +596,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
           ?>
           <hr>
           <div class="row">
-            <div class="col-xs-2">
+            <div class="col-xs-12 col-sm-2">
               <p>Domain: <strong><?=htmlspecialchars($result['alias_domain']);?></strong> (<?=$dkim['dkim_selector'];?>._domainkey)</p>
             </div>
-            <div class="col-xs-10">
+            <div class="col-xs-12 col-sm-10">
             <pre><?=$dkim['dkim_txt'];?></pre>
             </div>
           </div>
@@ -709,7 +710,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
           <div class="form-group">
             <label class="control-label col-sm-2" for="relayhost"><?=$lang['edit']['relayhost'];?></label>
             <div class="col-sm-10">
-              <select data-acl="<?=$_SESSION['acl']['mailbox_relayhost'];?>" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
+              <select data-acl="<?=$_SESSION['acl']['mailbox_relayhost'];?>" data-live-search="true" id="relayhost" name="relayhost" class="form-control space20">
                 <?php
                 foreach ($rlyhosts as $rlyhost) {
                 ?>
@@ -719,6 +720,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                 ?>
                 <option value="" <?=($result['attributes']['relayhost'] == "0") ? 'selected' : null;?>>None</option>
               </select>
+              <p class="visible-xs" style="margin: 0;padding: 0">&nbsp;</p>
               <small class="help-block"><?=$lang['edit']['mailbox_relayhost_info'];?></small>
             </div>
           </div>
@@ -726,30 +728,31 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             <label class="control-label col-sm-2"><?=$lang['user']['quarantine_notification'];?></label>
             <div class="col-sm-10">
             <div class="btn-group" data-acl="<?=$_SESSION['acl']['quarantine_notification'];?>">
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_notification == "never") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_notification == "never") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_notification"
                 data-api-url='edit/quarantine_notification'
                 data-api-attr='{"quarantine_notification":"never"}'><?=$lang['user']['never'];?></button>
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_notification == "hourly") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_notification == "hourly") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_notification"
                 data-api-url='edit/quarantine_notification'
                 data-api-attr='{"quarantine_notification":"hourly"}'><?=$lang['user']['hourly'];?></button>
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_notification == "daily") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_notification == "daily") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_notification"
                 data-api-url='edit/quarantine_notification'
                 data-api-attr='{"quarantine_notification":"daily"}'><?=$lang['user']['daily'];?></button>
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_notification == "weekly") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_notification == "weekly") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_notification"
                 data-api-url='edit/quarantine_notification'
                 data-api-attr='{"quarantine_notification":"weekly"}'><?=$lang['user']['weekly'];?></button>
+                <div class="clearfix visible-xs"></div>
             </div>
             <p class="help-block"><small><?=$lang['user']['quarantine_notification_info'];?></small></p>
             </div>
@@ -758,24 +761,25 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             <label class="control-label col-sm-2"><?=$lang['user']['quarantine_category'];?></label>
             <div class="col-sm-10">
             <div class="btn-group" data-acl="<?=$_SESSION['acl']['quarantine_category'];?>">
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_category == "reject") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_category == "reject") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_category"
                 data-api-url='edit/quarantine_category'
                 data-api-attr='{"quarantine_category":"reject"}'><?=$lang['user']['q_reject'];?></button>
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_category == "add_header") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_category == "add_header") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_category"
                 data-api-url='edit/quarantine_category'
                 data-api-attr='{"quarantine_category":"add_header"}'><?=$lang['user']['q_add_header'];?></button>
-              <button type="button" class="btn btn-sm btn-default <?=($quarantine_category == "all") ? "active" : null;?>"
+              <button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($quarantine_category == "all") ? "active" : null;?>"
                 data-action="edit_selected"
                 data-item="<?= htmlentities($mailbox); ?>"
                 data-id="quarantine_category"
                 data-api-url='edit/quarantine_category'
                 data-api-attr='{"quarantine_category":"all"}'><?=$lang['user']['q_all'];?></button>
+                <div class="clearfix visible-xs"></div>
             </div>
             <p class="help-block"><small><?=$lang['user']['quarantine_category_info'];?></small></p>
             </div>
@@ -784,18 +788,19 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             <label class="control-label col-sm-2" for="sender_acl"><?=$lang['user']['tls_policy'];?></label>
             <div class="col-sm-10">
               <div class="btn-group" data-acl="<?=$_SESSION['acl']['tls_policy'];?>">
-                <button type="button" class="btn btn-sm btn-default <?=($get_tls_policy['tls_enforce_in'] == "1") ? "active" : null;?>"
+                <button type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($get_tls_policy['tls_enforce_in'] == "1") ? "active" : null;?>"
                   data-action="edit_selected"
                   data-item="<?= htmlentities($mailbox); ?>"
                   data-id="tls_policy"
                   data-api-url='edit/tls_policy'
                   data-api-attr='{"tls_enforce_in":<?=($get_tls_policy['tls_enforce_in'] == "1") ? "0" : "1";?>}'><?=$lang['user']['tls_enforce_in'];?></button>
-                <button type="button" class="btn btn-sm btn-default <?=($get_tls_policy['tls_enforce_out'] == "1") ? "active" : null;?>"
+                <button type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default <?=($get_tls_policy['tls_enforce_out'] == "1") ? "active" : null;?>"
                   data-action="edit_selected"
                   data-item="<?= htmlentities($mailbox); ?>"
                   data-id="tls_policy"
                   data-api-url='edit/tls_policy'
                   data-api-attr='{"tls_enforce_out":<?=($get_tls_policy['tls_enforce_out'] == "1") ? "0" : "1";?>}'><?=$lang['user']['tls_enforce_out'];?></button>
+                  <div class="clearfix visible-xs"></div>
               </div>
             </div>
           </div>
@@ -865,7 +870,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
           <?php } ?>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-success" data-action="edit_selected" data-id="editmailbox" data-item="<?=htmlspecialchars($result['username']);?>" data-api-url='edit/mailbox' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editmailbox" data-item="<?=htmlspecialchars($result['username']);?>" data-api-url='edit/mailbox' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
             </div>
           </div>
         </form>
@@ -940,9 +945,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                 </div>
               </div>
               <div class="btn-group" data-acl="<?=$_SESSION['acl']['pushover'];?>">
-                  <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></a>
-                  <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="pushover-test" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['edit']['pushover_verify'];?></a>
-                  <a id="pushover_delete" class="btn btn-sm btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> <?=$lang['edit']['remove'];?></a>
+                  <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="pushover" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></a>
+                  <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="pushover-test" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> <?=$lang['edit']['pushover_verify'];?></a>
+                  <div class="clearfix visible-xs"></div>
+                  <a id="pushover_delete" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> <?=$lang['edit']['remove'];?></a>
               </div>
             </div>
           </div>
@@ -966,7 +972,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                 </select>
               </div>
               <div class="form-group">
-                <button class="btn btn-default" data-action="edit_selected" data-id="mboxratelimit" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/rl-mbox' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="mboxratelimit" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/rl-mbox' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
               <p class="help-block"><?=$lang['edit']['mbox_rl_info'];?></p>
             </div>
@@ -991,7 +997,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
                 </select>
               </div>
               <div class="form-group">
-                <button class="btn btn-default" data-action="edit_selected" data-id="useracl" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/user-acl' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="useracl" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/user-acl' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </div>
@@ -1035,7 +1041,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editrelayhost" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/relayhost' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editrelayhost" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/relayhost' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1096,7 +1102,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="edittransport" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/transport' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="edittransport" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/transport' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1156,7 +1162,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editresource" data-item="<?=htmlspecialchars($result['name']);?>" data-api-url='edit/resource' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editresource" data-item="<?=htmlspecialchars($result['name']);?>" data-api-url='edit/resource' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1202,7 +1208,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editbcc" data-item="<?=$bcc;?>" data-api-url='edit/bcc' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editbcc" data-item="<?=$bcc;?>" data-api-url='edit/bcc' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1251,7 +1257,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="edit_recipient_map" data-item="<?=$map;?>" data-api-url='edit/recipient_map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="edit_recipient_map" data-item="<?=$map;?>" data-api-url='edit/recipient_map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1312,7 +1318,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="edit_tls_policy_maps" data-item="<?=$map;?>" data-api-url='edit/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="edit_tls_policy_maps" data-item="<?=$map;?>" data-api-url='edit/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1480,7 +1486,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editsyncjob" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/syncjob' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editsyncjob" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/syncjob' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>
@@ -1531,7 +1537,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editfilter" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/filter' data-api-attr='{}' href="#"><?=$lang['edit']['validate_save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editfilter" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/filter' data-api-attr='{}' href="#"><?=$lang['edit']['validate_save'];?></button>
               </div>
             </div>
           </form>
@@ -1579,7 +1585,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-success" data-action="edit_selected" data-id="editapp" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/app-passwd' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editapp" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/app-passwd' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
               </div>
             </div>
           </form>

+ 1 - 1
data/web/inc/ajax/dns_diagnostics.php

@@ -436,7 +436,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
       }
       ?>
     </table>
-    <a id='download-zonefile' data-zonefile="<?=base64_encode($dns_data);?>" download='<?=$_GET['domain'];?>.txt' type='text/csv'>Download</a>
+    <a id='download-zonefile' class="btn btn-sm btn-default visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline" style="margin-top:10px" data-zonefile="<?=base64_encode($dns_data);?>" download='<?=$_GET['domain'];?>.txt' type='text/csv'>Download</a>
     <script>
       var zonefile_dl_link = document.getElementById('download-zonefile');
       var zonefile = atob(zonefile_dl_link.getAttribute('data-zonefile'));

+ 9 - 10
data/web/index.php

@@ -58,11 +58,11 @@ $_SESSION['index_query_string'] = $_SERVER['QUERY_STRING'];
                 <input name="pass_user" type="password" id="pass_user" class="form-control" placeholder="<?= $lang['login']['password']; ?>" required="">
               </div>
             </div>
-            <div class="form-group">
+            <div class="form-group" style="position: relative">
               <div class="btn-group">
                 <div class="btn-group">
-                  <button type="submit" class="btn btn-success" value="Login"><?= $lang['login']['login']; ?></button>
-                  <button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                  <button type="submit" class="btn btn-xs-lg btn-success" value="Login"><?= $lang['login']['login']; ?></button>
+                  <button type="button" class="btn btn-xs-lg btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                     <span class="caret"></span>
                   </button>
                   <ul class="dropdown-menu">
@@ -71,19 +71,18 @@ $_SESSION['index_query_string'] = $_SERVER['QUERY_STRING'];
                 </div>
               </div>
               <?php if(!isset($_SESSION['oauth2_request'])) { ?>
-              <div class="btn-group pull-right">
-                <button type="button" <?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? 'disabled="true"' : '' ?> class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <button type="button" <?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? 'disabled="true"' : '' ?> class="btn btn-xs-lg btn-default pull-right dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                   <span class="flag-icon flag-icon-<?= $_SESSION['mailcow_locale']; ?>"></span> <span class="caret"></span>
                 </button>
-                <ul class="dropdown-menu">
+                <ul class="dropdown-menu pull-right login">
                   <?php
                   foreach ($AVAILABLE_LANGUAGES as $c => $v) {
                   ?>
                   <li<?= ($_SESSION['mailcow_locale'] == $c) ? ' class="active"' : ''; ?>><a href="?<?= http_build_query(array_merge($_GET, array('lang' => $c))) ?>"><span class="flag-icon flag-icon-<?=$c;?>"></span> <?=$v;?></a></li>
                   <?php } ?>
                 </ul>
-              </div>
-              <?php } ?>
+              <?php } ?>              
+              <div class="clearfix"></div>
             </div>
             </form>
             <?php
@@ -99,7 +98,7 @@ $_SESSION['index_query_string'] = $_SERVER['QUERY_STRING'];
               foreach ($MAILCOW_APPS as $app) {
                 if (getenv('SKIP_SOGO') == "y" && preg_match('/^\/SOGo/i', $app['link'])) { continue; }
               ?>
-                <a href="<?= htmlspecialchars($app['link']); ?>" role="button" style="margin-bottom:3pt" title="<?= htmlspecialchars($app['description']); ?>" class="btn btn-primary"><?= htmlspecialchars($app['name']); ?></a>&nbsp;
+                <a href="<?= htmlspecialchars($app['link']); ?>" role="button" style="margin-bottom:3pt" title="<?= htmlspecialchars($app['description']); ?>" class="btn btn-primary btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline"><?= htmlspecialchars($app['name']); ?></a>&nbsp;
               <?php
               }
             }
@@ -108,7 +107,7 @@ $_SESSION['index_query_string'] = $_SERVER['QUERY_STRING'];
               foreach ($app_links as $row) {
                 foreach ($row as $key => $val) {
               ?>
-                <a href="<?= htmlspecialchars($val); ?>" role="button" style="margin-bottom:3pt" class="btn btn-primary"><?= htmlspecialchars($key); ?></a>&nbsp;
+                <a href="<?= htmlspecialchars($val); ?>" role="button" style="margin-bottom:3pt" class="btn btn-primary btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline"><?= htmlspecialchars($key); ?></a>&nbsp;
               <?php
                 }
               }

+ 239 - 0
data/web/js/build/013-bootstrap-tabcollapse.js

@@ -0,0 +1,239 @@
+!function ($) {
+
+    "use strict";
+
+    // TABCOLLAPSE CLASS DEFINITION
+    // ======================
+
+    var TabCollapse = function (el, options) {
+        this.options   = options;
+        this.$tabs  = $(el);
+
+        this._accordionVisible = false; //content is attached to tabs at first
+        this._initAccordion();
+        this._checkStateOnResize();
+
+
+        // checkState() has gone to setTimeout for making it possible to attach listeners to
+        // shown-accordion.bs.tabcollapse event on page load.
+        // See https://github.com/flatlogic/bootstrap-tabcollapse/issues/23
+        var that = this;
+        setTimeout(function() {
+          that.checkState();
+        }, 0);
+    };
+
+    TabCollapse.DEFAULTS = {
+        accordionClass: 'visible-xs',
+        tabsClass: 'hidden-xs',
+        accordionTemplate: function(heading, groupId, parentId, active) {
+            return  '<div class="panel panel-default">' +
+                    '   <div class="panel-heading">' +
+                    '      <h4 class="panel-title">' +
+                    '      </h4>' +
+                    '   </div>' +
+                    '   <div id="' + groupId + '" class="panel-collapse collapse ' + (active ? 'in' : '') + '">' +
+                    '       <div class="panel-body js-tabcollapse-panel-body">' +
+                    '       </div>' +
+                    '   </div>' +
+                    '</div>'
+
+        }
+    };
+
+    TabCollapse.prototype.checkState = function(){
+        if (this.$tabs.is(':visible') && this._accordionVisible){
+            this.showTabs();
+            this._accordionVisible = false;
+        } else if (this.$accordion.is(':visible') && !this._accordionVisible){
+            this.showAccordion();
+            this._accordionVisible = true;
+        }
+    };
+
+    TabCollapse.prototype.showTabs = function(){
+        var view = this;
+        this.$tabs.trigger($.Event('show-tabs.bs.tabcollapse'));
+
+        var $panelHeadings = this.$accordion.find('.js-tabcollapse-panel-heading').detach();
+
+        $panelHeadings.each(function() {
+            var $panelHeading = $(this),
+            $parentLi = $panelHeading.data('bs.tabcollapse.parentLi');
+
+            var $oldHeading = view._panelHeadingToTabHeading($panelHeading);
+
+            $parentLi.removeClass('active');
+            if ($parentLi.parent().hasClass('dropdown-menu') && !$parentLi.siblings('li').hasClass('active')) {
+                $parentLi.parent().parent().removeClass('active');
+            }
+
+            if (!$oldHeading.hasClass('collapsed')) {
+                $parentLi.addClass('active');
+                $('.tab-pane').removeClass('active');
+                $($panelHeading.attr('href')).addClass('active');
+                if ($parentLi.parent().hasClass('dropdown-menu')) {
+                    $parentLi.parent().parent().addClass('active');
+                }
+            } else {
+                $oldHeading.removeClass('collapsed');
+            }
+
+            $parentLi.append($panelHeading);
+        });
+
+        if (!$('li').hasClass('active')) {
+            $('li').first().addClass('active')
+        }
+
+        var $panelBodies = this.$accordion.find('.js-tabcollapse-panel-body');
+        $panelBodies.each(function(){
+            var $panelBody = $(this),
+                $tabPane = $panelBody.data('bs.tabcollapse.tabpane');
+            $tabPane.append($panelBody.contents().detach());
+        });
+        this.$accordion.html('');
+
+        if(this.options.updateLinks) {
+            var $tabContents = this.getTabContentElement();
+            $tabContents.find('[data-toggle-was="tab"], [data-toggle-was="pill"]').each(function() {
+                var $el = $(this);
+                var href = $el.attr('href').replace(/-collapse$/g, '');
+                $el.attr({
+                    'data-toggle': $el.attr('data-toggle-was'),
+                    'data-toggle-was': '',
+                    'data-parent': '',
+                    href: href
+                });
+            });
+        }
+
+        this.$tabs.trigger($.Event('shown-tabs.bs.tabcollapse'));
+    };
+
+    TabCollapse.prototype.getTabContentElement = function(){
+        var $tabContents = $(this.options.tabContentSelector);
+        if($tabContents.length === 0) {
+            $tabContents = this.$tabs.siblings('.tab-content');
+        }
+        return $tabContents;
+    };
+
+    TabCollapse.prototype.showAccordion = function(){
+        this.$tabs.trigger($.Event('show-accordion.bs.tabcollapse'));
+
+        var $headings = this.$tabs.find('li:not(.dropdown) [data-toggle="tab"], li:not(.dropdown) [data-toggle="pill"]'),
+            view = this;
+        $headings.each(function(){
+            var $heading = $(this),
+                $parentLi = $heading.parent();
+            $heading.data('bs.tabcollapse.parentLi', $parentLi);
+            view.$accordion.append(view._createAccordionGroup(view.$accordion.attr('id'), $heading.detach()));
+        });
+
+        if(this.options.updateLinks) {
+            var parentId = this.$accordion.attr('id');
+            var $selector = this.$accordion.find('.js-tabcollapse-panel-body');
+            $selector.find('[data-toggle="tab"], [data-toggle="pill"]').each(function() {
+                var $el = $(this);
+                var href = $el.attr('href') + '-collapse';
+                $el.attr({
+                    'data-toggle-was': $el.attr('data-toggle'),
+                    'data-toggle': 'collapse',
+                    'data-parent': '#' + parentId,
+                    href: href
+                });
+            });
+        }
+
+        this.$tabs.trigger($.Event('shown-accordion.bs.tabcollapse'));
+    };
+
+    TabCollapse.prototype._panelHeadingToTabHeading = function($heading) {
+        var href = $heading.attr('href').replace(/-collapse$/g, '');
+        $heading.attr({
+            'data-toggle': 'tab',
+            'href': href,
+            'data-parent': ''
+        });
+        return $heading;
+    };
+
+    TabCollapse.prototype._tabHeadingToPanelHeading = function($heading, groupId, parentId, active) {
+        $heading.addClass('js-tabcollapse-panel-heading ' + (active ? '' : 'collapsed'));
+        $heading.attr({
+            'data-toggle': 'collapse',
+            'data-parent': '#' + parentId,
+            'href': '#' + groupId
+        });
+        return $heading;
+    };
+
+    TabCollapse.prototype._checkStateOnResize = function(){
+        var view = this;
+        $(window).resize(function(){
+            clearTimeout(view._resizeTimeout);
+            view._resizeTimeout = setTimeout(function(){
+                view.checkState();
+            }, 100);
+        });
+    };
+
+
+    TabCollapse.prototype._initAccordion = function(){
+        var randomString = function() {
+            var result = "",
+                possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+            for( var i=0; i < 5; i++ ) {
+                result += possible.charAt(Math.floor(Math.random() * possible.length));
+            }
+            return result;
+        };
+
+        var srcId = this.$tabs.attr('id'),
+            accordionId = (srcId ? srcId : randomString()) + '-accordion';
+
+        this.$accordion = $('<div class="panel-group ' + this.options.accordionClass + '" id="' + accordionId +'"></div>');
+        this.$tabs.after(this.$accordion);
+        this.$tabs.addClass(this.options.tabsClass);
+        this.getTabContentElement().addClass(this.options.tabsClass);
+    };
+
+    TabCollapse.prototype._createAccordionGroup = function(parentId, $heading){
+        var tabSelector = $heading.attr('data-target'),
+            active = $heading.data('bs.tabcollapse.parentLi').is('.active');
+
+        if (!tabSelector) {
+            tabSelector = $heading.attr('href');
+            tabSelector = tabSelector && tabSelector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
+        }
+
+        var $tabPane = $(tabSelector),
+            groupId = $tabPane.attr('id') + '-collapse',
+            $panel = $(this.options.accordionTemplate($heading, groupId, parentId, active));
+        $panel.find('.panel-heading > .panel-title').append(this._tabHeadingToPanelHeading($heading, groupId, parentId, active));
+        $panel.find('.panel-body').append($tabPane.contents().detach())
+            .data('bs.tabcollapse.tabpane', $tabPane);
+
+        return $panel;
+    };
+
+
+
+    // TABCOLLAPSE PLUGIN DEFINITION
+    // =======================
+
+    $.fn.tabCollapse = function (option) {
+        return this.each(function () {
+            var $this   = $(this);
+            var data    = $this.data('bs.tabcollapse');
+            var options = $.extend({}, TabCollapse.DEFAULTS, $this.data(), typeof option === 'object' && option);
+
+            if (!data) $this.data('bs.tabcollapse', new TabCollapse(this, options));
+        });
+    };
+
+    $.fn.tabCollapse.Constructor = TabCollapse;
+
+
+}(window.jQuery);

+ 24 - 0
data/web/js/build/014-mailcow.js

@@ -94,6 +94,7 @@ $(document).ready(function() {
 
   // selectpicker
   $('select').selectpicker({
+    'styleBase': 'btn btn-xs-lg',
     'noneSelectedText': lang_footer.nothing_selected
   });
 
@@ -251,4 +252,27 @@ $(document).ready(function() {
       })
     });
   })
+  
+  // responsive tabs
+  $('.responsive-tabs').tabCollapse({
+    tabsClass: 'hidden-xs',
+    accordionClass: 'js-tabcollapse-panel-group visible-xs'
+  });
+  $(document).on("shown.bs.collapse shown.bs.tab", function (e) {
+	  var target = $(e.target);
+	  
+	  if($(window).width() <= 767) {
+		  var offset = target.offset().top - 112;
+		  $("html, body").stop().animate({
+		    scrollTop: offset
+		  }, 300);
+	  }
+	  
+	  if(target.hasClass('panel-collapse')){
+	    var id = e.target.id.replace(/-collapse$/g, '');
+	    if(id){
+          localStorage.setItem('lastTag', '#'+id);
+        }
+      }
+  });
 });

+ 26 - 26
data/web/js/site/admin.js

@@ -281,10 +281,10 @@ jQuery(function($){
   function process_table_data(data, table) {
     if (table == 'relayhoststable') {
       $.each(data, function (i, item) {
-        item.action = '<div class="btn-group">' +
-          '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
-          '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-          '<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+        item.action = '<div class="btn-group footable-actions">' +
+          '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
+          '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+          '<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
           '</div>';
         if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
         else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; }
@@ -299,10 +299,10 @@ jQuery(function($){
         if (item.username) {
           item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username;
         }
-        item.action = '<div class="btn-group">' +
-          '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
-          '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-          '<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+        item.action = '<div class="btn-group footable-actions">' +
+          '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
+          '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+          '<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
           '</div>';
         item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />';
       });
@@ -313,22 +313,22 @@ jQuery(function($){
           return escapeHtml(i);
         });
         item.recipients = rcpts.join('<hr style="margin:1px!important">');
-        item.action = '<div class="btn-group">' +
+        item.action = '<div class="btn-group footable-actions">' +
           '<a href="#" data-toggle="modal" data-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-default">' + lang.queue_show_message + '</a>' +
           '</div>';
       });
     } else if (table == 'forwardinghoststable') {
       $.each(data, function (i, item) {
-        item.action = '<div class="btn-group">' +
+        item.action = '<div class="btn-group footable-actions">' +
           '<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
           '</div>';
         item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
       });
     } else if (table == 'oauth2clientstable') {
       $.each(data, function (i, item) {
-        item.action = '<div class="btn-group">' +
-          '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-          '<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+        item.action = '<div class="btn-group footable-actions">' +
+          '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+          '<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
           '</div>';
         item.scope = "profile";
         item.grant_types = 'refresh_token password authorization_code';
@@ -339,10 +339,10 @@ jQuery(function($){
         item.selected_domains = escapeHtml(item.selected_domains);
         item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>");
         item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
-        item.action = '<div class="btn-group">' +
-          '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-          '<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
-          '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
+        item.action = '<div class="btn-group footable-actions">' +
+          '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+          '<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+          '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
           '</div>';
       });
     } else if (table == 'adminstable') {
@@ -353,9 +353,9 @@ jQuery(function($){
           item.usr = item.username;
         }
         item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />';
-        item.action = '<div class="btn-group">' +
-          '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-          '<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+        item.action = '<div class="btn-group footable-actions">' +
+          '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+          '<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
           '</div>';
       });
     }
@@ -481,13 +481,13 @@ jQuery(function($){
   function add_table_row(table_id, type) {
     var row = $('<tr />');
     if (type == "app_link") {
-    cols = '<td><input class="input-sm form-control" data-id="app_links" type="text" name="app" required></td>';
-    cols += '<td><input class="input-sm form-control" data-id="app_links" type="text" name="href" required></td>';
-    cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">' + lang.remove_row + '</a></td>';
+    cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>';
+    cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>';
+    cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">' + lang.remove_row + '</a></td>';
     } else if (type == "f2b_regex") {
-    cols = '<td><input style="text-align:center" class="input-sm form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
-    cols += '<td><input class="input-sm form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
-    cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">' + lang.remove_row + '</a></td>';
+    cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
+    cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
+    cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">' + lang.remove_row + '</a></td>';
     }
     row.append(cols);
     table_id.append(row);

+ 42 - 37
data/web/js/site/mailbox.js

@@ -287,15 +287,17 @@ jQuery(function($){
             item.def_quota_for_mbox = humanFileSize(item.def_quota_for_mbox);
             item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
             item.chkbox = '<input type="checkbox" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
-            item.action = '<div class="btn-group">';
+            item.action = '<div class="btn-group footable-actions">';
             if (role == "admin") {
-              item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-                '<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>';
+              item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+                '<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+                 '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-third btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
             }
             else {
-              item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>';
+              item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
             }
-            item.action += '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
+            
             if (item.backupmx == 1) {
               if (item.relay_unknown_only == 1) {
                 item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
@@ -441,19 +443,22 @@ jQuery(function($){
               item.quarantine_category = lang.q_all;
             }
             if (acl_data.login_as === 1) {
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
-              '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-success"><i class="bi bi-person-fill"></i> Login</a>';
+	            var btnSize = 'btn-xs-third';
+	            if (ALLOW_ADMIN_EMAIL_LOGIN) btnSize = 'btn-xs-quart';
+	            
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs ' + btnSize + ' btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs ' + btnSize + ' btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs ' + btnSize + ' btn-success"><i class="bi bi-person-fill"></i> Login</a>';
               if (ALLOW_ADMIN_EMAIL_LOGIN) {
-                item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
+                item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs ' + btnSize + ' btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
               }
               item.action += '</div>';
             }
             else {
             item.action = '<div class="btn-group">' +
-              '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
               '</div>';
             }
             item.in_use = '<div class="progress">' +
@@ -528,9 +533,9 @@ jQuery(function($){
             } else {
               item.multiple_bookings = '<span id="active-script" class="label label-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
             }
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
               '</div>';
             item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
             item.name = escapeHtml(item.name);
@@ -594,9 +599,9 @@ jQuery(function($){
         },
         success: function (data) {
           $.each(data, function (i, item) {
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
               '</div>';
             item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
             item.local_dest = escapeHtml(item.local_dest);
@@ -664,9 +669,9 @@ jQuery(function($){
             $.each(data, function (i, item) {
               item.recipient_map_old = escapeHtml(item.recipient_map_old);
               item.recipient_map_new = escapeHtml(item.recipient_map_new);
-              item.action = '<div class="btn-group">' +
-                '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-                '<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              item.action = '<div class="btn-group footable-actions">' +
+                '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+                '<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
                 '</div>';
               item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
             });
@@ -734,9 +739,9 @@ jQuery(function($){
               } else {
                 item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
               }
-              item.action = '<div class="btn-group">' +
-                '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-                '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              item.action = '<div class="btn-group footable-actions">' +
+                '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+                '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
                 '</div>';
               item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
             });
@@ -799,9 +804,9 @@ jQuery(function($){
         },
         success: function (data) {
           $.each(data, function (i, item) {
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
               '</div>';
             item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
             item.goto = escapeHtml(item.goto.replace(/,/g, " "));
@@ -894,10 +899,10 @@ jQuery(function($){
         },
         success: function (data) {
           $.each(data, function (i, item) {
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
-              '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-question-lg"></i> DNS</a></div>' +
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-third btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-globe2"></i> DNS</a></div>' +
               '</div>';
             item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
             if(item.parent_is_backupmx == '1') {
@@ -974,9 +979,9 @@ jQuery(function($){
               item.exclude  = '<code>' + item.exclude + '</code>';
             }
             item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
               '</div>';
             item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
             if (item.is_running == 1) {
@@ -1052,9 +1057,9 @@ jQuery(function($){
             }
             item.script_data = '<pre style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
             item.filter_type = '<div class="label label-default">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
-            item.action = '<div class="btn-group">' +
-              '<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-              '<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+            item.action = '<div class="btn-group footable-actions">' +
+              '<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+              '<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
               '</div>';
             item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
           });

+ 7 - 7
data/web/js/site/user.js

@@ -144,7 +144,7 @@ jQuery(function($){
         success: function (data) {
           $.each(data, function (i, item) {
             if (acl_data.spam_alias === 1) {
-              item.action = '<div class="btn-group">' +
+              item.action = '<div class="btn-group footable-actions">' +
                 '<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
                 '</div>';
               item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
@@ -204,9 +204,9 @@ jQuery(function($){
             }
             item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1);
             if (acl_data.syncjobs === 1) {
-              item.action = '<div class="btn-group">' +
-                '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-                '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              item.action = '<div class="btn-group footable-actions">' +
+                '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+                '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
                 '</div>';
               item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
             }
@@ -258,9 +258,9 @@ jQuery(function($){
           $.each(data, function (i, item) {
             item.name = escapeHtml(item.name);
             if (acl_data.app_passwds === 1) {
-              item.action = '<div class="btn-group">' +
-                '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
-                '<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+              item.action = '<div class="btn-group footable-actions">' +
+                '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+                '<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
                 '</div>';
               item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />';
             }

+ 50 - 38
data/web/mailbox.php

@@ -7,7 +7,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 ?>
 <div class="container">
 
-  <ul class="nav nav-tabs" role="tablist">
+  <ul class="nav nav-tabs responsive-tabs" role="tablist">
     <li role="presentation" class="active"><a href="#tab-domains" aria-controls="tab-domains" role="tab" data-toggle="tab"><?=$lang['mailbox']['domains'];?></a></li>
     <li role="presentation"><a href="#tab-mailboxes" aria-controls="tab-mailboxes" role="tab" data-toggle="tab"><?=$lang['mailbox']['mailboxes'];?></a></li>
     <?php /* <li class="dropdown">
@@ -62,8 +62,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <? if($_SESSION['mailcow_cc_role'] == "admin"): ?>
                     <li><a data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
@@ -72,8 +72,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                     <li><a data-action="delete_selected" data-id="domain" data-api-url='delete/domain' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                   <? endif; ?>
                 </ul>
+                <div class="clearfix visible-xs"></div>
                 <? if($_SESSION['mailcow_cc_role'] == "admin"): ?>
-                  <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addDomainModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_domain'];?></a>
+                  <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addDomainModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_domain'];?></a>
                 <? endif; ?>
               </div>
             </div>
@@ -111,14 +112,14 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                 </ul>
               </div>
             </div>
-            <div class="mass-actions-mailbox" data-actions-header="true"></div>
+            <div class="mass-actions-mailbox hidden-xs" data-actions-header="true"></div>
             <div class="table-responsive">
               <table id="mailbox_table" class="table table-striped"></table>
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group hidden-md hidden-lg hidden-xl">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li class="dropdown-header"><?=$lang['mailbox']['mailbox'];?></li>
                   <li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
@@ -156,7 +157,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_mailbox'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_mailbox'];?></a>
               </div>
               <div class="btn-group hidden-xs hidden-sm">
                 <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
@@ -248,15 +250,16 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-id="resource" data-api-url='delete/resource' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addResourceModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_resource'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addResourceModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_resource'];?></a>
               </div>
             </div>
           </div>
@@ -288,15 +291,16 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-id="alias-domain" data-api-url='delete/alias-domain' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-acl="<?=$_SESSION['acl']['alias_domains'];?>" data-toggle="modal" data-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_domain_alias'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-acl="<?=$_SESSION['acl']['alias_domains'];?>" data-toggle="modal" data-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_domain_alias'];?></a>
               </div>
             </div>
           </div>
@@ -331,9 +335,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
-                <ul class="dropdown-menu">
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <ul class="dropdown-menu top33">
                   <li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
                   <li role="separator" class="divider"></li>
@@ -344,8 +348,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"0"}' href="#"><?=$lang['mailbox']['sogo_visible_n'];?></a></li>
                   <?php } ?>
                 </ul>
-                <a class="btn btn-sm btn-default" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> <?=$lang['mailbox']['add_alias_expand'];?></a>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addAliasModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_alias'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> <?=$lang['mailbox']['add_alias_expand'];?></a>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addAliasModal"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_alias'];?></a>
               </div>
             </div>
           </div>
@@ -377,8 +382,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group" data-acl="<?=$_SESSION['acl']['syncjobs'];?>">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"last_run":""}' href="#"><?=$lang['mailbox']['last_run_reset'];?></a></li>
                   <li role="separator" class="divider"></li>
@@ -387,7 +392,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['user']['create_syncjob'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['user']['create_syncjob'];?></a>
               </div>
             </div>
           </div>
@@ -422,8 +428,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group" data-acl="<?=$_SESSION['acl']['filters'];?>">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
@@ -433,7 +439,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-text="<?=$lang['user']['eas_reset'];?>?" data-id="filter_item" data-api-url='delete/filter' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_filter'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_filter'];?></a>
               </div>
             </div>
             <div class="panel-body <?=($_SESSION['mailcow_cc_role'] == "admin") ?: 'hidden';?>">
@@ -452,8 +459,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <div class="form-group">
                     <div class="col-sm-10 add_filter_btns">
                       <div class="btn-group">
-                        <button class="btn btn-sm btn-default validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
-                        <button class="btn btn-sm btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                        <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
+                        <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                        <div class="clearfix visible-xs"></div>
                       </div>
                     </div>
                   </div>
@@ -470,8 +478,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <div class="form-group">
                     <div class="col-sm-10 add_filter_btns">
                       <div class="btn-group">
-                        <button class="btn btn-sm btn-default validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
-                        <button class="btn btn-sm btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                        <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
+                        <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> <?=$lang['admin']['save'];?></button>
+                        <div class="clearfix visible-xs"></div>
                       </div>
                     </div>
                   </div>
@@ -509,8 +518,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group" data-acl="<?=$_SESSION['acl']['bcc_maps'];?>">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
@@ -520,7 +529,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-id="bcc" data-api-url='delete/bcc' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_bcc_entry'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_bcc_entry'];?></a>
               </div>
             </div>
           </div>
@@ -550,15 +560,16 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-id="recipient_map" data-api-url='delete/recipient_map' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_recipient_map_entry'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_recipient_map_entry'];?></a>
               </div>
             </div>
           </div>
@@ -591,15 +602,16 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             </div>
             <div class="mass-actions-mailbox">
               <div class="btn-group">
-                <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-                <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+                <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
                 <ul class="dropdown-menu">
                   <li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
                   <li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
                   <li role="separator" class="divider"></li>
                   <li><a data-action="delete_selected" data-id="tls-policy-map" data-api-url='delete/tls-policy-map' href="#"><?=$lang['mailbox']['remove'];?></a></li>
                 </ul>
-                <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_tls_policy_map'];?></a>
+                <div class="clearfix visible-xs"></div>
+                <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> <?=$lang['mailbox']['add_tls_policy_map'];?></a>
               </div>
             </div>
           </div>

+ 6 - 6
data/web/modals/admin.php

@@ -35,7 +35,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="rsetting" data-api-url='add/rsetting' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="rsetting" data-api-url='add/rsetting' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -96,7 +96,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-default" data-action="add_item" data-id="add_domain_admin" data-api-url='add/domain-admin' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_domain_admin" data-api-url='add/domain-admin' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
               </div>
             </div>
           </form>
@@ -124,7 +124,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-4 col-sm-8">
-              <button class="btn btn-default" data-action="edit_selected" data-id="fido2ChangeFn" data-item="null" data-api-url='edit/fido2-fn' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="fido2ChangeFn" data-item="null" data-api-url='edit/fido2-fn' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
             </div>
           </div>
         </form>
@@ -150,7 +150,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-default" data-action="add_item" data-id="add_oauth2_client" data-api-url='add/oauth2-client' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_oauth2_client" data-api-url='add/oauth2-client' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
               </div>
             </div>
           </form>
@@ -196,7 +196,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-default" data-action="add_item" data-id="add_admin" data-api-url='add/admin' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_admin" data-api-url='add/admin' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> <?=$lang['admin']['add'];?></button>
               </div>
             </div>
           </form>
@@ -231,7 +231,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
             </div>
             <div class="form-group">
               <div class="col-sm-offset-2 col-sm-10">
-                <button class="btn btn-default" id="test_transport" href="#"><?=$lang['admin']['relay_run'];?></button>
+                <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="test_transport" href="#"><?=$lang['admin']['relay_run'];?></button>
               </div>
             </div>
           </form>

+ 33 - 17
data/web/modals/footer.php

@@ -4,7 +4,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="YubiOTPModal" tabindex="-1" role="dialog" aria-labelledby="YubiOTPModalLabel">
   <div class="modal-dialog" role="document">
     <div class="modal-content">
-      <div class="modal-header"><b><?=$lang['tfa']['yubi_otp'];?></b></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title"><?=$lang['tfa']['yubi_otp'];?></h3>
+	  </div>
       <div class="modal-body">
       <form role="form" method="post">
         <div class="form-group">
@@ -29,7 +32,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             <input type="hidden" name="tfa_method" value="yubi_otp">
           </div>
         </div>
-        <button class="btn btn-sm btn-default" type="submit" name="set_tfa"><?=$lang['user']['save_changes'];?></button>
+        <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" type="submit" name="set_tfa"><?=$lang['user']['save_changes'];?></button>
       </form>
       </div>
     </div>
@@ -39,7 +42,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="U2FModal" tabindex="-1" role="dialog" aria-labelledby="U2FModalLabel">
   <div class="modal-dialog" role="document">
     <div class="modal-content">
-      <div class="modal-header"><b><?=$lang['tfa']['u2f'];?></b></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title"><?=$lang['tfa']['u2f'];?></h3>
+	  </div>
       <div class="modal-body">
         <form role="form" method="post" id="u2f_reg_form">
           <div class="form-group">
@@ -72,7 +78,10 @@ if (isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="TOTPModal" tabindex="-1" role="dialog" aria-labelledby="TOTPModalLabel">
   <div class="modal-dialog" role="document">
     <div class="modal-content">
-      <div class="modal-header"><b><?=$lang['tfa']['totp'];?></b></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title"><?=$lang['tfa']['totp'];?></h3>
+	  </div>
       <div class="modal-body">
         <form role="form" method="post">
           <div class="form-group">
@@ -98,7 +107,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             <li>
               <p><?=$lang['tfa']['confirm_totp_token'];?>:</p>
               <p><input type="number" style="width:33%" class="form-control" name="totp_confirm_token" autocomplete="off" required></p>
-              <p><button class="btn btn-default" type="submit" name="set_tfa"><?=$lang['tfa']['confirm'];?></button></p>
+              <p><button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" type="submit" name="set_tfa"><?=$lang['tfa']['confirm'];?></button></p>
             </li>
           </ol>
         </form>
@@ -110,14 +119,17 @@ if (isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="DisableTFAModal" tabindex="-1" role="dialog" aria-labelledby="DisableTFAModalLabel">
   <div class="modal-dialog" role="document">
     <div class="modal-content">
-      <div class="modal-header"><b><?=$lang['tfa']['delete_tfa'];?></b></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title"><?=$lang['tfa']['delete_tfa'];?></h3>
+	  </div>
       <div class="modal-body">
         <form role="form" method="post">
           <div class="input-group">
-            <input type="password" class="form-control" name="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
+            <input type="password" class="form-control input-xs-lg" name="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
             <span class="input-group-btn">
               <input type="hidden" name="tfa_method" value="none">
-              <button class="btn btn-danger" type="submit" name="set_tfa"><?=$lang['tfa']['delete_tfa'];?></button>
+              <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" type="submit" name="set_tfa"><?=str_replace(' ', '&nbsp;', $lang['tfa']['delete_tfa']);?></button>
             </span>
           </div>
         </form>
@@ -134,7 +146,10 @@ if (isset($_SESSION['pending_tfa_method'])):
 <div class="modal fade" id="ConfirmTFAModal" tabindex="-1" role="dialog" aria-labelledby="ConfirmTFAModalLabel">
   <div class="modal-dialog" role="document">
     <div class="modal-content">
-      <div class="modal-header"><button type="button" class="close" data-dismiss="modal">&times;</button><b><?=$lang['tfa'][$tfa_method];?></b></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title"><?=$lang['tfa'][$tfa_method];?></h3>
+	  </div>
       <div class="modal-body">
       <?php
       switch ($tfa_method) {
@@ -148,7 +163,7 @@ if (isset($_SESSION['pending_tfa_method'])):
               <input type="hidden" name="tfa_method" value="yubi_otp">
             </div>
           </div>
-          <button class="btn btn-sm btn-default" type="submit" name="verify_tfa_login"><?=$lang['login']['login'];?></button>
+          <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" type="submit" name="verify_tfa_login"><?=$lang['login']['login'];?></button>
         </form>
       <?php
         break;
@@ -182,7 +197,7 @@ if (isset($_SESSION['pending_tfa_method'])):
               <input type="hidden" name="tfa_method" value="totp">
             </div>
           </div>
-          <button class="btn btn-sm btn-default" type="submit" name="verify_tfa_login"><?=$lang['login']['login'];?></button>
+          <button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="submit" name="verify_tfa_login"><?=$lang['login']['login'];?></button>
         </form>
         <?php
         break;
@@ -205,13 +220,13 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admi
   <div class="modal-dialog">
     <div class="modal-content">
     <div class="modal-header">
-      <button type="button" class="close" data-dismiss="modal">&times;</button>
+      <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
       <h4 class="modal-title"><?= $lang['footer']['restart_container']; ?> (<code id="containerName"></code>)</h4>
     </div>
     <div class="modal-body">
       <p><?= $lang['footer']['restart_container_info']; ?></p>
       <hr>
-      <button class="btn btn-md btn-primary" id="triggerRestartContainer"><?= $lang['footer']['restart_now']; ?></button>
+      <button class="btn btn-md visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-primary" id="triggerRestartContainer"><?= $lang['footer']['restart_now']; ?></button>
       <br><br>
       <div id="statusTriggerRestartContainer"></div>
     </div>
@@ -225,15 +240,16 @@ endif;
   <div class="modal-dialog">
     <div class="modal-content">
     <div class="modal-header">
-      <button type="button" class="close" data-dismiss="modal">&times;</button>
-      <h4 class="modal-title"><?= $lang['footer']['confirm_delete']; ?></h4>
+      <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+      <h3 class="modal-title"><?= $lang['footer']['confirm_delete']; ?></h3>
     </div>
     <div class="modal-body">
       <p id="DeleteText"><?= $lang['footer']['delete_these_items']; ?></p>
       <ul id="ItemsToDelete"></ul>
       <hr>
-      <button class="btn btn-sm btn-danger" id="IsConfirmed"><?= $lang['footer']['delete_now']; ?></button>
-      <button class="btn btn-sm btn-default" id="isCanceled"><?= $lang['footer']['cancel']; ?></button>
+      <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" id="IsConfirmed"><?= $lang['footer']['delete_now']; ?></button>
+      <button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="isCanceled"><?= $lang['footer']['cancel']; ?></button>
+      <div class="clearfix visible-xs"></div>
     </div>
     </div>
   </div>

+ 25 - 17
data/web/modals/mailbox.php

@@ -72,7 +72,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           <hr>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_mailbox" data-api-url='add/mailbox' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_mailbox" data-api-url='add/mailbox' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -182,12 +182,13 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <hr>
           <div class="form-group">
-            <div class="col-sm-offset-2 col-sm-10">
+            <div class="col-sm-offset-2 col-sm-10 btn-group">
               <?php if (getenv('SKIP_SOGO') != "y") { ?>
-              <button class="btn btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#"><?=$lang['add']['add_domain_only'];?></button>
-              <button class="btn btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1"}' href="#"><?=$lang['add']['add_domain_restart'];?></button>
+              <button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#"><?=$lang['add']['add_domain_only'];?></button>
+              <button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1"}' href="#"><?=$lang['add']['add_domain_restart'];?></button>
+              <div class="clearfix visible-xs"></div>
               <?php } else { ?>
-              <button class="btn btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#"><?=$lang['add']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#"><?=$lang['add']['add'];?></button>
               <?php } ?>
             </div>
           </div>
@@ -262,7 +263,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_resource" data-api-url='add/resource' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_resource" data-api-url='add/resource' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -320,7 +321,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_alias" data-api-url='add/alias' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_alias" data-api-url='add/alias' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -382,7 +383,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_alias_domain" data-api-url='add/alias-domain' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_alias_domain" data-api-url='add/alias-domain' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -559,7 +560,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -625,9 +626,10 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
             </div>
           </div>
           <div class="form-group">
-            <div class="col-sm-offset-2 col-sm-10 add_filter_btns">
-              <button class="btn btn-default validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
-              <button class="btn btn-success add_sieve_script" data-action="add_item" data-id="add_filter" data-api-url='add/filter' data-api-attr='{}' href="#" disabled><?=$lang['admin']['add'];?></button>
+            <div class="col-sm-offset-2 col-sm-10 add_filter_btns btn-group">
+              <button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
+              <button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success add_sieve_script" data-action="add_item" data-id="add_filter" data-api-url='add/filter' data-api-attr='{}' href="#" disabled><?=$lang['admin']['add'];?></button>
+              <div class="clearfix visible-xs"></div>
             </div>
           </div>
         </form>
@@ -713,7 +715,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-success" data-action="add_item" data-id="add_bcc" data-api-url='add/bcc' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_bcc" data-api-url='add/bcc' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -754,7 +756,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-success" data-action="add_item" data-id="add_recipient_map" data-api-url='add/recipient_map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_recipient_map" data-api-url='add/recipient_map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -810,7 +812,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-success" data-action="add_item" data-id="add_tls_policy_map" data-api-url='add/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_tls_policy_map" data-api-url='add/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
             </div>
           </div>
         </form>
@@ -822,7 +824,10 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
   <div class="modal-dialog modal-lg" role="document">
     <div class="modal-content">
-      <div class="modal-header"><h4 class="modal-title">Log</h4></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title">Log</h3>
+	  </div>
       <div class="modal-body">
         <textarea class="form-control" rows="20" id="logText" spellcheck="false"></textarea>
       </div>
@@ -833,7 +838,10 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="dnsInfoModal" tabindex="-1" role="dialog" aria-labelledby="dnsInfoModalLabel">
   <div class="modal-dialog modal-lg" role="document">
     <div class="modal-content">
-      <div class="modal-header"><h4 class="modal-title"><?=$lang['diagnostics']['dns_records'];?></h4></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+	    <h3 class="modal-title"><?=$lang['diagnostics']['dns_records'];?></h3>
+	  </div>
       <div class="modal-body">
         <p><?=$lang['diagnostics']['dns_records_24hours'];?></p>
         <div class="dns-modal-body"></div>

+ 13 - 6
data/web/modals/user.php

@@ -24,7 +24,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-4 col-sm-8">
-              <button class="btn btn-default" data-action="edit_selected" data-id="fido2ChangeFn" data-item="null" data-api-url='edit/fido2-fn' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="fido2ChangeFn" data-item="null" data-api-url='edit/fido2-fn' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
             </div>
           </div>
         </form>
@@ -182,7 +182,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
 						</div>
 					</div>
 				</form>
@@ -228,7 +228,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-              <button class="btn btn-default" data-action="add_item" data-id="add_apppasswd" data-api-url='add/app-passwd' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_apppasswd" data-api-url='add/app-passwd' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
 						</div>
 					</div>
 				</form>
@@ -240,7 +240,10 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
   <div class="modal-dialog modal-lg" role="document">
     <div class="modal-content">
-      <div class="modal-header"><h4 class="modal-title">Log</h4></div>
+      <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+        <h3 class="modal-title">Log</h3>
+      </div>
       <div class="modal-body">
         <textarea class="form-control textarea-code" rows="20" id="logText" spellcheck="false"></textarea>
       </div>
@@ -251,6 +254,10 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
 <div class="modal fade" id="pwChangeModal" tabindex="-1" role="dialog" aria-labelledby="pwChangeModalLabel">
   <div class="modal-dialog" role="document">
     <div class="modal-content">
+	    <div class="modal-header">
+	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+        <h3 class="modal-title"><?=$lang['user']['change_password'];?></h3>
+      </div>
       <div class="modal-body">
         <form class="form-horizontal" data-cached-form="false" data-id="pwchange" role="form" method="post" autocomplete="off">
           <div class="form-group">
@@ -275,7 +282,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-3 col-sm-9">
-              <button class="btn btn-default" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><?=$lang['user']['change_password'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><?=$lang['user']['change_password'];?></button>
             </div>
           </div>
         </form>
@@ -311,7 +318,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           </div>
           <div class="form-group">
             <div class="col-sm-offset-3 col-sm-9">
-              <button class="btn btn-default" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><?=$lang['user']['change_password'];?></button>
+              <button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><?=$lang['user']['change_password'];?></button>
             </div>
           </div>
         </form>

+ 6 - 5
data/web/quarantine.php

@@ -9,12 +9,12 @@ $quarantine_settings = quarantine('settings');
 <div class="container">
 	<div class="row">
 		<div class="col-md-12">
-      <div class="panel panel-default">
+      <div class="panel panel-default panel-xs-lg">
         <div class="panel-heading">
           <?=$lang['quarantine']['quarantine'];?> <span class="badge badge-info table-lines"></span>
           <div class="btn-group pull-right">
-            <button class="btn btn-xs btn-default refresh_table" data-draw="draw_quarantine_table" data-table="quarantinetable"><?=$lang['quarantine']['refresh'];?></button>
-            <button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown"><?=$lang['quarantine']['table_size'];?> 
+            <button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_quarantine_table" data-table="quarantinetable"><?=$lang['quarantine']['refresh'];?></button>
+            <button type="button" class="btn btn-xs btn-xs-lg btn-default dropdown-toggle" data-toggle="dropdown"><?=$lang['quarantine']['table_size'];?>
               <span class="caret"></span>
             </button>
             <ul class="dropdown-menu" data-table-id="quarantinetable" role="menu">
@@ -47,8 +47,8 @@ $quarantine_settings = quarantine('settings');
         </div>
         <div class="mass-actions-quarantine">
           <div class="btn-group" data-acl="<?=$_SESSION['acl']['quarantine'];?>">
-            <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="qitems" href="#"><i class="bi bi-check-all"></i> <?=$lang['quarantine']['toggle_all'];?></a>
-            <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['quarantine']['quick_actions'];?> <span class="caret"></span></a>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="qitems" href="#"><i class="bi bi-check-all"></i> <?=$lang['quarantine']['toggle_all'];?></a>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['quarantine']['quick_actions'];?> <span class="caret"></span></a>
             <ul class="dropdown-menu">
               <li><a data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"release"}' href="#"><?=$lang['quarantine']['deliver_inbox'];?></a></li>
               <li role="separator" class="divider"></li>
@@ -56,6 +56,7 @@ $quarantine_settings = quarantine('settings');
               <li role="separator" class="divider"></li>
               <li><a data-action="delete_selected" data-id="qitems" data-api-url='delete/qitem' href="#"><?=$lang['quarantine']['remove'];?></a></li>
             </ul>
+            <div class="clearfix visible-xs"></div>
           </div>
         </div>
       </div>

File diff suppressed because it is too large
+ 0 - 665
data/web/user.php


Some files were not shown because too many files changed in this diff