Browse Source

Add custom fields

pull/64/head
brantje 2 years ago
parent
commit
f5e5f04c4a
No known key found for this signature in database GPG Key ID: 5FF1D117F918687F
12 changed files with 538 additions and 112 deletions
  1. +12
    -0
      _locales/en/messages.json
  2. +105
    -8
      css/browser_action.css
  3. +2
    -1
      html/browser_action/browser_action.html
  4. +135
    -63
      html/browser_action/views/edit_credential.html
  5. +10
    -0
      html/browser_action/views/settings.html
  6. +12
    -0
      icons/icon_white.svg
  7. +1
    -28
      js/ui/popup/controllers/list.js
  8. +44
    -1
      js/ui/popup/controllers/main.js
  9. +28
    -9
      style/browser_action.scss
  10. +59
    -0
      style/css/material-tabs.css
  11. +18
    -2
      style/partials/material-input.scss
  12. +112
    -0
      style/partials/material-tabs.scss

+ 12
- 0
_locales/en/messages.json View File

@@ -283,6 +283,18 @@
"message": "Done",
"description": "Done"
},
"custom_fields": {
"message": "Custom Fields",
"description": "Custom fields"
},
"general": {
"message": "General",
"description": "Custom fields"
},
"value": {
"message": "Value",
"description": "Custom fields"
},
"list": {
"message": "List",
"description": "List"


+ 105
- 8
css/browser_action.css View File

@@ -78,7 +78,8 @@ input:focus, select.input-md:focus {

select.input-md {
background-color: #fff;
cursor: pointer; }
cursor: pointer;
margin-top: -3px; }

/* LABEL ======================================= */
.group label {
@@ -101,6 +102,14 @@ select.ng-valid:not(.ng-empty) ~ label {
font-size: 14px;
color: #1565c0; }

.col33 {
width: 29%;
float: left; }
.col33:first-child {
padding-right: 10px; }
.col33:not(:first-child) {
padding-left: 10px; }

/* BOTTOM BARS ================================= */
.bar {
position: relative;
@@ -138,7 +147,7 @@ input:focus ~ .bar:before, input:focus ~ .bar:after {
pointer-events: none;
opacity: 0.5; }

.group .mdi-content-copy, .pwField .mdi {
.group .mdi-content-copy, .pwField .mdi, .group .mdi-delete {
/*position: absolute;
right: 0;*/
margin-top: 5px;
@@ -157,7 +166,7 @@ input:focus ~ .bar:before, input:focus ~ .bar:after {
border-bottom-right-radius: 16px;
border-bottom-left-radius: 16px;
border-top-left-radius: 16px; }
.group .mdi-content-copy:hover, .pwField .mdi:hover {
.group .mdi-content-copy:hover, .pwField .mdi:hover, .group .mdi-delete:hover {
text-decoration: none;
background-color: #e4e4e4; }

@@ -167,9 +176,15 @@ input:focus ~ .bar:before, input:focus ~ .bar:after {
.mdi-content-copy ~ input {
width: calc(100% - 32px); }

.mdi-delete ~ input {
width: calc(100% - 32px); }

.mdi-content-copy ~ .bar {
width: calc(100% - 32px); }

.mdi-delete ~ .bar {
width: calc(100% - 32px); }

/* active state */
input:focus ~ .highlight, select.input-md ~ .highlight {
-webkit-animation: inputHighlighter 0.3s ease;
@@ -431,6 +446,75 @@ input:focus ~ .highlight, select.input-md ~ .highlight {
.md-btn.red:hover, .btn.red:focus {
background-color: #f4511e; }

.tab-wrap {
width: 100%;
height: 600px;
/*position: absolute;*/ }
.tab-wrap label:not(.ng-binding) {
cursor: pointer;
color: rgba(0, 0, 0, 0.8);
background-color: #fff;
box-sizing: border-box;
display: inline-flex !important;
align-items: center;
justify-content: center;
text-align: center;
height: 56px;
transition: color 0.2s ease;
width: 100%;
border-bottom: 1px solid #c9c9c9; }
.tab-wrap .slide {
background: #1565c0;
width: calc(100% / 2);
height: 4px;
position: relative;
left: 0;
top: 52px;
transition: left 0.3s ease-out; }
.tab-wrap .tab-label-content {
width: calc(100% / 2);
float: left; }
.tab-wrap .tab-label-content .tab-content {
position: absolute;
top: 100px;
left: 16px;
line-height: 130%;
display: none;
width: 100%;
padding-right: 20px; }
.tab-wrap .tab-label-content .tab-content .custom_field {
float: left;
margin-bottom: 15px; }
.tab-wrap .tab-label-content .tab-content .custom_field .field {
float: left;
width: 50%; }
.tab-wrap .tab-label-content .tab-content .custom_field .field:first-child {
padding-right: 10px; }
.tab-wrap .tab-label-content .tab-content .custom_field .field:not(:first-child) {
padding-left: 10px; }
@media screen and (max-width: 800px) {
.tab-wrap h1 {
padding: 40px 0 90px 10%; }
.tab-wrap .tab-wrap {
width: 80%;
margin-left: 10%;
top: -106px; } }

input[type="radio"][name="tabs"] {
position: absolute;
z-index: -1; }
input[type="radio"][name="tabs"]:checked + .tab-label-content label:not(.ng-binding) {
color: rgba(0, 0, 0, 0.8); }
input[type="radio"][name="tabs"]:checked + .tab-label-content .tab-content {
display: block;
margin-top: 40px; }
input[type="radio"][name="tabs"]:nth-of-type(1):checked ~ .slide {
left: calc((100% / 2) * 0); }
input[type="radio"][name="tabs"]:nth-of-type(2):checked ~ .slide {
left: calc((100% / 2) * 1); }
input[type="radio"][name="tabs"]:first-of-type:checked ~ .slide {
left: 0; }

body {
width: 450px;
min-height: 350px;
@@ -485,7 +569,7 @@ body.toggled {
overflow-y: auto; }

#wrapper.toggled #page-content-wrapper {
position: absolute;
/*position: absolute;*/
margin-right: -250px;
/* width: calc(100% - 250px);*/ }

@@ -499,7 +583,8 @@ body.toggled {
width: 250px;
margin: 0;
padding: 0;
list-style: none; }
list-style: none;
height: 100%; }
.sidebar-nav li {
line-height: 55px; }
.sidebar-nav li a {
@@ -517,17 +602,28 @@ body.toggled {
background-color: #e4e4e4; }
.sidebar-nav li a:active, .sidebar-nav li a:focus {
text-decoration: none; }
.sidebar-nav li.bottom {
position: absolute;
bottom: 0;
font-size: 12px;
text-align: center;
width: 100%;
margin-bottom: 15px;
line-height: 0; }
.sidebar-nav > .sidebar-brand {
height: 50px;
font-size: 18px;
line-height: 50px;
text-indent: 20px;
text-align: center;
background-color: #1565c0;
border-right: 1px solid #104d92; }
.sidebar-nav > .sidebar-brand span {
display: block;
text-decoration: none;
color: #fff; }
.sidebar-nav > .sidebar-brand span img {
height: 32px;
margin-right: 10px; }
.sidebar-nav > .sidebar-brand span:hover {
color: #fff;
background: none; }
@@ -542,9 +638,10 @@ body.toggled {
position: absolute;
background-color: transparent;
width: calc(100% - 250px);
height: 350px;
height: 100%;
z-index: 9999999;
right: 0; }
right: 0;
top: 0; }

.edit_credential {
padding-top: 30px;


+ 2
- 1
html/browser_action/browser_action.html View File

@@ -63,7 +63,7 @@
<ul class="sidebar-nav">
<li class="sidebar-brand">
<span>
Passman
<img src="/icons/icon_white.svg" /> Passman
<i class="mdi mdi-close" ng-click="toggleMenu()"></i>
</span>
</li>
@@ -81,6 +81,7 @@
title="{{'donate_button_title' | translate}}"
rel="nofollow noopener noreferrer"><i class="mdi mdi-credit-card"></i> Donate</a>
</li>
<li class="bottom">{{'credentials_in_db' | translate:credential_amount}}</li>
</ul>
</div>
<!-- /#sidebar-wrapper -->


+ 135
- 63
html/browser_action/views/edit_credential.html View File

@@ -1,48 +1,139 @@
<div class="edit_credential">
<div class="group">
<copy-text text="credential.label"></copy-text>
<input type="text" ng-model="credential.label" required>
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'label' | translate}}</label>
</div>
<div class="group">
<copy-text text="credential.username"></copy-text>
<input type="text" ng-model="credential.username">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'username' | translate}}</label>
</div>
<div class="group">
<copy-text text="credential.email"></copy-text>
<input type="text" ng-model="credential.email">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{ 'email' | translate}}</label>
</div>
<div class="group pwField">
<copy-text text="credential.password"></copy-text>
<i class="mdi mdi-refresh pointer" ng-click="generatePassword()"></i>
<i class="pointer mdi" ng-class="{'mdi-eye': !pwFieldShown, 'mdi-eye-off': pwFieldShown}" ng-click="togglePwField()"></i>
<input type="text" ng-model="credential.password" ng-if="pwFieldShown">
<input type="password" ng-model="credential.password" ng-if="!pwFieldShown">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'password' | translate}}</label>
</div>
<div class="group">
<input type="password" ng-model="credential.password_repeat">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'password_repeat' | translate}}</label>
<div class="tab-wrap">

<input type="radio" name="tabs" id="tab1" checked>
<div class="tab-label-content" id="tab1-content">
<label for="tab1">General</label>
<div class="tab-content">
<div class="group">
<copy-text text="credential.label"></copy-text>
<input type="text" ng-model="credential.label" required>
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'label' | translate}}</label>
</div>
<div class="group">
<copy-text text="credential.username"></copy-text>
<input type="text" ng-model="credential.username">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'username' | translate}}</label>
</div>
<div class="group">
<copy-text text="credential.email"></copy-text>
<input type="text" ng-model="credential.email">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{ 'email' | translate}}</label>
</div>
<div class="group pwField">
<copy-text text="credential.password"></copy-text>
<i class="mdi mdi-refresh pointer" ng-click="generatePassword()"></i>
<i class="pointer mdi" ng-class="{'mdi-eye': !pwFieldShown, 'mdi-eye-off': pwFieldShown}"
ng-click="togglePwField()"></i>
<input type="text" ng-model="credential.password" ng-if="pwFieldShown">
<input type="password" ng-model="credential.password" ng-if="!pwFieldShown">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'password' | translate}}</label>
</div>
<div class="group">
<input type="password" ng-model="credential.password_repeat">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'password_repeat' | translate}}</label>
</div>
<div class="group">
<copy-text text="credential.url"></copy-text>
<input type="text" ng-model="credential.url">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'url' | translate}}</label>
</div>
<div style="margin-left: -15px;" ng-include="'save_btn.html'"></div>
</div>
</div>
<div class="group">
<copy-text text="credential.url"></copy-text>
<input type="text" ng-model="credential.url">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'url' | translate}}</label>

<input type="radio" name="tabs" id="tab2">
<div class="tab-label-content" id="tab2-content">
<label for="tab2">Custom fields</label>
<div class="tab-content">
<div class="custom_field" ng-repeat="custom_field in credential.custom_fields" ng-if="custom_field.field_type !== 'file'">
<div class="field">
<div class="group">
<input type="text" ng-model="custom_field.label">
<span class="highlight"></span>
<span class="bar"></span>
</div>
</div>
<div class="field">
<div class="group">
<i class="mdi mdi-delete"></i>
<input type="password" ng-model="custom_field.value" ng-if="custom_field.field_type === 'password'">
<input type="text" ng-model="custom_field.value" ng-if="custom_field.field_type === 'text'">
<span class="highlight"></span>
<span class="bar"></span>
</div>
</div>
</div>
<h4 style="margin-left: 5px; margin-bottom: 30px;">Add custom field</h4>
<div class="col33" style="padding-left: 0">
<div class="group">
<input type="text" ng-model="new_custom_field.label" placeholder="Label">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'label' | translate}}</label>
</div>
</div>
<div class="col33">
<div class="group">
<input type="password" ng-model="new_custom_field.value" ng-if="new_custom_field.field_type === 'password'">
<input type="text" ng-model="new_custom_field.value" ng-if="new_custom_field.field_type === 'text'" placeholder="Value">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'value' | translate}}</label>
</div>
</div>
<div class="col33">
<div class="group">
<select class="input-md" name="type" ng-model="new_custom_field.field_type">
<option value="text">Text</option>
<option value="password">Password</option>
</select>
<span class="highlight"></span>
<span class="bar"></span>

</div>
</div>

<span><i class="mdi mdi-plus" style="font-size: 30px; padding-top: 10px; display: inline-block; float: left; padding-left: 25px;" ng-click="addCustomField(new_custom_field)"></i></span>

<div class="clearfix" style="margin-bottom: 30px;"></div>
<div style="margin-left: -15px;" ng-include="'save_btn.html'"></div>
</div>
</div>


<div class="slide"></div>

</div>
<div class="clearfix"></div>

<script type="text/ng-template" id="save_btn.html">
<button class="md-btn default" ng-click="saveCredential()" ng-disabled="saving">
<span>
<i ng-show="saving"
ng-class="{'fa-spinner fa-spin': saving}"
class="fa"></i>
{{'save' | translate}}
</span>
</button>
<button class="md-btn" ng-click="cancel()">
<span>{{'cancel' | translate}}</span>
</button>
</script>
<!--
<div class="edit_credential">

<button class="md-btn default" ng-click="saveCredential()" ng-disabled="saving">
<span>{{'save' | translate}}</span>
</button>
@@ -107,26 +198,7 @@
</td>
</tr>
</table>
<h4>Add custom field</h4>
<div class="col-xs-3 pad5">
<input class="form-control" type="text" ng-model="new_custom_field.label" placeholder="Label">
</div>
<div class="col-xs-3 pad5">
<input class="form-control" type="password" ng-model="new_custom_field.value" ng-if="new_custom_field.field_type === 'password'">
<input class="form-control" type="text" ng-model="new_custom_field.value" ng-if="new_custom_field.field_type === 'text'" placeholder="Value">
</div>
<div class="col-xs-3 pad5">
<select class="form-control" name="type" ng-model="new_custom_field.field_type">
<option value="text">Text</option>
<option value="password">Password</option>
</select>
</div>
<div class="col-xs-3 pad5">
<button class="btn btn-default" ng-click="addCustomField(new_custom_field)">
<i class="fa fa-plus"></i>
</button>
</div>
<div class="clearfix"></div>


<button class="btn btn-success" ng-click="saveCredential()" ng-disabled="saving">{{'save' |
translate}}


+ 10
- 0
html/browser_action/views/settings.html View File

@@ -34,6 +34,13 @@
<span class="bar"></span>
<label>{{'vault_password' | translate}}</label>
</div>
<div class="group">
<input type="text" ng-model="settings.refreshTime"
required ng-debounce="1000">
<span class="highlight"></span>
<span class="bar"></span>
<label>{{'refresh_timer' | translate}}</label>
</div>
<div class="ignored_sites">
<label>{{'ignored_sites' | translate}}</label>
<ul class="ignored_sites">
@@ -88,6 +95,9 @@
<button class="md-btn" ng-click="cancel()">
<span>{{'cancel' | translate}}</span>
</button>
<div class="version">
{{extension}}
</div>
<!--
<h4 align="center">{{'please_enter_nextcloud_credentials' | translate}}:</h4>
<div class="alerts alert alert-warning" ng-if="errors.length > 0">


+ 12
- 0
icons/icon_white.svg View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 68 68" enable-background="new 0 0 68 68" xml:space="preserve">
<g>
<path fill="#FFFFFF" d="M0,34c0,21.9,30,34,34,34c4,0,34-12.1,34-34V0H0V34z M45.4,50.3H22.6v-6.5h22.8V50.3z M21.6,16.2
c0,0,6.5,2.4,9.2,4.1c-0.6-2.6-1.2-10-1.2-10h8.6c0,0-0.6,7.8-1.2,10c1.2-0.6,9.4-4.1,9.4-4.1l2.7,8.3c0,0-7.5,1.8-10.1,1.9
c1.8,1.4,6.7,7.4,6.7,7.4l-7,5.3c0,0-3.8-6.3-5-8.9c-1.2,2.9-5,8.9-5,8.9l-7.2-5.3c0,0,5.7-6.3,7.1-7.4c-1.4-0.1-9.9-1.9-9.9-1.9
L21.6,16.2z"/>
</g>
</svg>

+ 1
- 28
js/ui/popup/controllers/list.js View File

@@ -35,27 +35,12 @@
angular.module('passmanExtension')
.controller('ListCtrl', ['$scope', 'Settings', '$location', '$rootScope', function ($scope, Settings, $window, $rootScope) {
$scope.app = 'passman';
var port = API.runtime.connect(null, {
name: "PassmanCommunication"
});

var messageParser = function (message) {
var e = message.split(':');

switch (e[0]) {
case "credential_amount":
$scope.credential_amount = e[1];
$scope.refreshing_credentials = false;
}

$scope.$apply();
};

/**
* Connect to the background service
*/
var initApp = function () {
port.onMessage.addListener(messageParser);
API.runtime.sendMessage(API.runtime.id, {method: "getMasterPasswordSet"}).then(function (isPasswordSet) {
//First check attributes
if (!isPasswordSet) {
@@ -63,22 +48,10 @@
}

getActiveTab();
$scope.refreshing_credentials = true;
setTimeout(function () {
port.postMessage("credential_amount");
}, 500);
});
};

$scope.refreshing_credentials = false;
$scope.refresh = function () {
$scope.refreshing_credentials = true;
API.runtime.sendMessage(API.runtime.id, {method: "getCredentials"}).then(function () {
setTimeout(function () {
port.postMessage("credential_amount");
}, 2000);
});
};


var getActiveTab = function () {
API.tabs.query({currentWindow: true, active: true}).then(function (tab) {


+ 44
- 1
js/ui/popup/controllers/main.js View File

@@ -35,6 +35,49 @@
angular.module('passmanExtension')
.controller('MainCtrl', ['$scope', 'Settings', '$location', '$rootScope', '$timeout', function ($scope, Settings, $window, $rootScope, $timeout) {

var port = API.runtime.connect(null, {
name: "PassmanCommunication"
});

var messageParser = function (message) {
var e = message.split(':');

switch (e[0]) {
case "credential_amount":
$scope.credential_amount = e[1];
$scope.refreshing_credentials = false;
}

$scope.$apply();
};

/**
* Connect to the background service
*/
var initApp = function () {
port.onMessage.addListener(messageParser);
API.runtime.sendMessage(API.runtime.id, {method: "getMasterPasswordSet"}).then(function (isPasswordSet) {
//First check attributes
if (!isPasswordSet) {
return;
}
$scope.refreshing_credentials = true;
setTimeout(function () {
port.postMessage("credential_amount");
}, 500);
});
};


$scope.refreshing_credentials = false;
$scope.refresh = function () {
$scope.refreshing_credentials = true;
API.runtime.sendMessage(API.runtime.id, {method: "getCredentials"}).then(function () {
setTimeout(function () {
port.postMessage("credential_amount");
}, 2000);
});
};

$scope.menuIsOpen = false;
$scope.bodyOverflow = false;
@@ -65,7 +108,7 @@
} else if (settings.hasOwnProperty('isInstalled')) {
window.location = '#!/locked';
} else {
// initApp();
initApp();
}
});



+ 28
- 9
style/browser_action.scss View File

@@ -5,6 +5,7 @@
@import "partials/material-switch";
@import "partials/material-checkbox";
@import "partials/material-buttons";
@import "partials/material-tabs";

$sidebarWidth: 250px;
body {
@@ -71,7 +72,7 @@ body.toggled {
}

#wrapper.toggled #page-content-wrapper {
position: absolute;
/*position: absolute;*/
margin-right: -$sidebarWidth;
/* width: calc(100% - 250px);*/
}
@@ -89,6 +90,7 @@ body.toggled {
margin: 0;
padding: 0;
list-style: none;
height: 100%;
li {
line-height: 55px;
a {
@@ -112,19 +114,31 @@ body.toggled {
text-decoration: none;
}
}
&.bottom {
position: absolute;
bottom: 0;
font-size: 12px;
text-align: center;
width: 100%;
margin-bottom: 15px;
line-height: 0;
}
}
> .sidebar-brand {
height: 50px;
font-size: 18px;
line-height: 50px;
text-indent: 20px;
text-align: center;
background-color: #1565c0;
border-right: 1px solid darken(#1565c0, 10%);
span {

display: block;
text-decoration: none;
color: #fff;
img {
height: 32px;
margin-right: 10px;
}
&:hover {
color: #fff;
background: none;
@@ -144,9 +158,10 @@ body.toggled {
position: absolute;
background-color: transparent;
width: calc(100% - 250px);
height: 350px;
height: 100%;
z-index: 9999999;
right: 0;
top: 0;
}

.edit_credential {
@@ -189,26 +204,30 @@ label, .switch-label, label:not(.input-checkbox):not(.label) {
margin-bottom: 45px;
}
}
.invisible{

.invisible {
visibility: hidden;
}
.master_pw_warning{

.master_pw_warning {
padding-left: 6px;
font-size: 10px;
color: #a94442;
margin-bottom: 15px;
}
.master_pw_warning.big{

.master_pw_warning.big {
font-size: 14px;
text-align: center;

}

.unlock {
width: 350px;
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
margin: -20px auto 10px;
padding: 20px;
.group{
.group {
margin-bottom: 25px;
}
img {


+ 59
- 0
style/css/material-tabs.css View File

@@ -0,0 +1,59 @@
.tab-wrap {
width: 50%;
margin-left: 20%;
position: relative;
display: flex;
top: -106px; }
.tab-wrap label {
cursor: pointer;
color: rgba(255, 255, 255, 0.8);
background-color: #00bcd4;
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
text-align: center;
height: 56px;
transition: color 0.2s ease;
width: 100%; }
.tab-wrap .slide {
background: #ffeb3b;
width: calc(100% / 4);
height: 4px;
position: absolute;
left: 0;
top: calc(100% - 4px);
transition: left 0.3s ease-out; }
.tab-wrap .tab-label-content {
width: 100%; }
.tab-wrap .tab-label-content .tab-content {
position: absolute;
top: 100px;
left: 16px;
line-height: 130%;
display: none; }
@media screen and (max-width: 800px) {
.tab-wrap h1 {
padding: 40px 0 90px 10%; }
.tab-wrap .tab-wrap {
width: 80%;
margin-left: 10%;
top: -106px; } }

input[type="radio"][name="tabs"] {
position: absolute;
z-index: -1; }
input[type="radio"][name="tabs"]:checked + .tab-label-content label {
color: white; }
input[type="radio"][name="tabs"]:checked + .tab-label-content .tab-content {
display: block; }
input[type="radio"][name="tabs"]:nth-of-type(1):checked ~ .slide {
left: calc((100% / 4) * 0); }
input[type="radio"][name="tabs"]:nth-of-type(2):checked ~ .slide {
left: calc((100% / 4) * 1); }
input[type="radio"][name="tabs"]:nth-of-type(3):checked ~ .slide {
left: calc((100% / 4) * 2); }
input[type="radio"][name="tabs"]:nth-of-type(4):checked ~ .slide {
left: calc((100% / 4) * 3); }
input[type="radio"][name="tabs"]:first-of-type:checked ~ .slide {
left: 0; }

+ 18
- 2
style/partials/material-input.scss View File

@@ -27,6 +27,7 @@ input:focus, select.input-md:focus {
select.input-md{
background-color: #fff;
cursor: pointer;
margin-top: -3px;
}
/* LABEL ======================================= */
.group label {
@@ -51,7 +52,16 @@ select.ng-valid:not(.ng-empty) ~ label {
font-size: 14px;
color: #1565c0;
}

.col33{
width: 29%;
float: left;
&:first-child{
padding-right: 10px;
}
&:not(:first-child){
padding-left: 10px;
}
}
/* BOTTOM BARS ================================= */
.bar {
position: relative;
@@ -95,7 +105,7 @@ input:focus ~ .bar:before, input:focus ~ .bar:after {
opacity: 0.5;

}
.group .mdi-content-copy, .pwField .mdi{
.group .mdi-content-copy, .pwField .mdi, .group .mdi-delete{
/*position: absolute;
right: 0;*/
margin-top:5px;
@@ -128,9 +138,15 @@ input:focus ~ .bar:before, input:focus ~ .bar:after {
.mdi-content-copy ~ input{
width: calc(100% - 32px);
}
.mdi-delete ~ input{
width: calc(100% - 32px);
}
.mdi-content-copy ~ .bar{
width: calc(100% - 32px);
}
.mdi-delete ~ .bar{
width: calc(100% - 32px);
}
/* active state */
input:focus ~ .highlight, select.input-md ~ .highlight {
-webkit-animation: inputHighlighter 0.3s ease;


+ 112
- 0
style/partials/material-tabs.scss View File

@@ -0,0 +1,112 @@
$headerBgColor: #fff;
$sliderColor: #1565c0;
$grey: #9e9e9e;

$num-of-tabs: 2;

@mixin tabs {
@for $i from 1 through $num-of-tabs {
&:nth-of-type(#{$i}) {
&:checked {
~ .slide {
left: calc((100% / #{$num-of-tabs}) * #{$i - 1});
}
}
}
}
}

.tab-wrap {
width: 100%;
height: 600px;
/*position: absolute;*/
label:not(.ng-binding) {
cursor: pointer;
color: rgba(0,0,0,0.8);
background-color: $headerBgColor;
box-sizing: border-box;
display: inline-flex !important;
align-items: center;
justify-content: center;
text-align: center;
height: 56px;
transition: color 0.2s ease;
width: 100%;
border-bottom: 1px solid #c9c9c9;
}

.slide {
background: $sliderColor;
width: calc(100% / #{$num-of-tabs});
height: 4px;
position: relative;
left: 0;
top: 52px;
transition: left 0.3s ease-out;
}

.tab-label-content {
width: calc(100% / #{$num-of-tabs});
float: left;
.tab-content {
position: absolute;
top: 100px;
left: 16px;
line-height: 130%;
display: none;
width: 100%;
padding-right: 20px;
.custom_field{
.field{
&:first-child{
padding-right: 10px;
}
&:not(:first-child){
padding-left: 10px;
}
float: left;
width: 50%;
}
float: left;
margin-bottom: 15px;
}
}
}

@media screen and (max-width: 800px) {
h1 {
padding: 40px 0 90px 10%;
}
.tab-wrap {
width: 80%;
margin-left: 10%;
top: -106px;
}
}
}

input[type="radio"][name="tabs"] {
position: absolute;
z-index: -1;
&:checked {
+ .tab-label-content {
label:not(.ng-binding) {
color: rgba(0,0,0,0.8);
}
.tab-content {
display: block;
margin-top: 40px;
}
}
}
@include tabs;
&:first-of-type {
&:checked {
~ .slide {
left: 0;
}
}
}
}



Loading…
Cancel
Save