Migrate to new static styles property for lit-element
This commit is contained in:
parent
70e7b98fb8
commit
a0bfd7294a
|
@ -724,7 +724,7 @@
|
|||
},
|
||||
"ansi-escapes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
|
||||
"integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -1806,7 +1806,7 @@
|
|||
},
|
||||
"es6-promisify": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2267,7 +2267,7 @@
|
|||
},
|
||||
"camelcase-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2315,7 +2315,7 @@
|
|||
},
|
||||
"meow": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -2490,7 +2490,7 @@
|
|||
"dependencies": {
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||
"dev": true
|
||||
}
|
||||
|
@ -2547,7 +2547,7 @@
|
|||
},
|
||||
"globby": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "http://registry.npmjs.org/globby/-/globby-8.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz",
|
||||
"integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -3836,7 +3836,7 @@
|
|||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
|
||||
"dev": true
|
||||
}
|
||||
|
@ -4067,7 +4067,7 @@
|
|||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -4099,7 +4099,7 @@
|
|||
},
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||
"dev": true
|
||||
}
|
||||
|
@ -4107,7 +4107,7 @@
|
|||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -4135,7 +4135,7 @@
|
|||
},
|
||||
"p-is-promise": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
|
||||
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -4304,7 +4304,7 @@
|
|||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -4844,7 +4844,7 @@
|
|||
},
|
||||
"safe-regex": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -5168,7 +5168,7 @@
|
|||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -5248,7 +5248,7 @@
|
|||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -5263,7 +5263,7 @@
|
|||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
@ -5278,7 +5278,7 @@
|
|||
},
|
||||
"strip-eof": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -5319,7 +5319,7 @@
|
|||
},
|
||||
"tar": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
|
||||
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
<link rel="apple-touch-icon" href="/assets/icons/apple-touch-180.png">
|
||||
|
||||
<style> html, body {
|
||||
background: #59c6ff;
|
||||
background: linear-gradient(rgb(89, 198, 255), rgb(7, 124, 185));
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overscroll-behavior-y: contain;
|
||||
} </style>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,8 +9,8 @@
|
|||
"@polymer/paper-spinner": "^3.0.0-pre.18",
|
||||
"@webcomponents/webcomponentsjs": "^2.0.0",
|
||||
"autosize": "^4.0.2",
|
||||
"lit-element": "^2.0.1",
|
||||
"lit-html": "^0.14.0",
|
||||
"lit-element": "^2.1.0",
|
||||
"lit-html": "^1.0.0",
|
||||
"localforage": "^1.7.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { localize } from "@padloc/core/lib/locale.js";
|
||||
import { shared } from "../styles";
|
||||
import { element, html, property } from "./base.js";
|
||||
import { element, html, property, css } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
|
||||
const defaultButtonLabel = localize("OK");
|
||||
|
@ -36,34 +35,35 @@ export class AlertDialog extends Dialog<AlertOptions, number> {
|
|||
@property({ reflect: true })
|
||||
horizontal: boolean = false;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
:host([hide-icon]) .info-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([hide-icon]) .info-text,
|
||||
:host([hide-icon]) .info-title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:host([horizontal]) .buttons {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
:host([horizontal]) button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.info-text:not(.small) {
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const { message, dialogTitle, options, icon } = this;
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host([hide-icon]) .info-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([hide-icon]) .info-text,
|
||||
:host([hide-icon]) .info-title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:host([horizontal]) .buttons {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
:host([horizontal]) button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.info-text:not(.small) {
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="info" ?hidden=${!dialogTitle && !message}>
|
||||
<pl-icon class="info-icon" icon="${icon}"></pl-icon>
|
||||
<div class="info-body">
|
||||
|
|
|
@ -4,7 +4,7 @@ import { app, router } from "../init.js";
|
|||
import { AutoLock } from "../mixins/auto-lock.js";
|
||||
import { ErrorHandling } from "../mixins/error-handling.js";
|
||||
import { AutoSync } from "../mixins/auto-sync.js";
|
||||
import { BaseElement, html, property, query, listen } from "./base.js";
|
||||
import { BaseElement, html, css, property, query, listen } from "./base.js";
|
||||
import "./icon.js";
|
||||
import { Input } from "./input.js";
|
||||
import { View } from "./view.js";
|
||||
|
@ -51,109 +51,110 @@ class App extends AutoSync(ErrorHandling(AutoLock(BaseElement))) {
|
|||
this._applyPath(router.path);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${config.cssVars} ${shared}
|
||||
static styles = [
|
||||
config.cssVars,
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
background: linear-gradient(
|
||||
var(--color-gradient-highlight-to) 0%,
|
||||
var(--color-gradient-highlight-from) 100%
|
||||
);
|
||||
overflow: hidden;
|
||||
color: var(--color-foreground);
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: fadeIn 0.5s backwards 0.2s;
|
||||
perspective: 1000px;
|
||||
}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
background: linear-gradient(
|
||||
var(--color-gradient-highlight-to) 0%,
|
||||
var(--color-gradient-highlight-from) 100%
|
||||
);
|
||||
overflow: hidden;
|
||||
color: var(--color-foreground);
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: fadeIn 0.5s backwards 0.2s;
|
||||
perspective: 1000px;
|
||||
}
|
||||
.wrapper {
|
||||
display: flex;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transform-origin: 0 center;
|
||||
transition: transform 0.4s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
will-change: transform, opacity;
|
||||
${mixins.fullbleed()}
|
||||
${mixins.gradientDark()}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transform-origin: 0 center;
|
||||
transition: transform 0.4s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
will-change: transform, opacity;
|
||||
pl-menu {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.views {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
perspective: 1000px;
|
||||
margin: var(--gutter-size);
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.views > * {
|
||||
will-change: opacity;
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
.views > :not(.showing) {
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wrapper:not(.active),
|
||||
:host(.dialog-open) .wrapper {
|
||||
transform: translate3d(0, 0, -150px) rotateX(5deg);
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.views {
|
||||
transition: transform 0.3s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
${mixins.fullbleed()}
|
||||
${mixins.gradientDark()}
|
||||
}
|
||||
|
||||
pl-menu {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.views {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
perspective: 1000px;
|
||||
margin: var(--gutter-size);
|
||||
margin-left: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.views > * {
|
||||
will-change: opacity;
|
||||
${mixins.fullbleed()}
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.views > :not(.showing) {
|
||||
:host([menu-open]) .views {
|
||||
transform: translate(200px, 0);
|
||||
}
|
||||
|
||||
pl-menu {
|
||||
transition: transform 0.3s cubic-bezier(0.6, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
:host(:not([menu-open])) pl-menu {
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
transform: translate(-100px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper:not(.active),
|
||||
:host(.dialog-open) .wrapper {
|
||||
transform: translate3d(0, 0, -150px) rotateX(5deg);
|
||||
@media (min-width: 1200px) {
|
||||
.wrapper {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: rgba(0, 0, 0, 0.5) 0 1px 3px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
max-width: 1200px;
|
||||
max-height: 900px;
|
||||
}
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
@media (max-width: ${config.narrowWidth}px) {
|
||||
.views {
|
||||
transition: transform 0.3s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
.views {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.views > * {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:host([menu-open]) .views {
|
||||
transform: translate(200px, 0);
|
||||
}
|
||||
|
||||
pl-menu {
|
||||
transition: transform 0.3s cubic-bezier(0.6, 0, 0.2, 1),
|
||||
opacity 0.3s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
:host(:not([menu-open])) pl-menu {
|
||||
opacity: 0;
|
||||
transform: translate(-100px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: ${config.wideWidth}px) {
|
||||
.wrapper {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: rgba(0, 0, 0, 0.5) 0 1px 3px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
max-width: 1200px;
|
||||
max-height: 900px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<pl-start id="startView"></pl-start>
|
||||
|
||||
<div class="wrapper">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import "reflect-metadata";
|
||||
import { EventTarget, Event } from "@padloc/core/lib/event-target.js";
|
||||
import { LitElement, html } from "@polymer/lit-element";
|
||||
import { UpdatingElement, PropertyDeclaration } from "@polymer/lit-element/lib/updating-element.js";
|
||||
export { html };
|
||||
import { LitElement, html, css, svg } from "lit-element";
|
||||
import { UpdatingElement, PropertyDeclaration } from "lit-element/lib/updating-element.js";
|
||||
export { html, css, svg };
|
||||
|
||||
export interface BasePrototype extends BaseElement {}
|
||||
|
||||
|
@ -146,12 +146,6 @@ export class BaseElement extends LitElement {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO after upgrading to lit-element > 0.12
|
||||
render() {
|
||||
throw "Not Implemented";
|
||||
return html``;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,6 +164,7 @@ export function property(options?: PropertyDeclaration) {
|
|||
return (proto: Object, name: string) => {
|
||||
options = options || {};
|
||||
if (!options.type) {
|
||||
// @ts-ignore
|
||||
options.type = getType(proto, name);
|
||||
}
|
||||
(proto.constructor as typeof UpdatingElement).createProperty(name, options);
|
||||
|
|
|
@ -2,7 +2,7 @@ import { VaultItem, Field } from "@padloc/core/lib/item.js";
|
|||
import { setClipboard } from "@padloc/core/lib/platform.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, html, property } from "./base.js";
|
||||
import { BaseElement, html, css, property } from "./base.js";
|
||||
|
||||
export class Clipboard extends BaseElement {
|
||||
|
||||
|
@ -17,13 +17,9 @@ export class Clipboard extends BaseElement {
|
|||
return !!this.item && !!this.field;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { item, field, _tMinusClear } = this;
|
||||
return html`
|
||||
${ shared }
|
||||
|
||||
<style>
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
|
@ -61,13 +57,18 @@ export class Clipboard extends BaseElement {
|
|||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0 var(--border-radius) var(--border-radius) 0;
|
||||
}
|
||||
|
||||
.countdown {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
</style>
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { item, field, _tMinusClear } = this;
|
||||
return html`
|
||||
<div class="content">
|
||||
<div class="title">${ $l("Copied To Clipboard:") }</div>
|
||||
<div class="name">${ item!.name } / ${ field!.name }</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Vault } from "@padloc/core/lib/vault.js";
|
|||
import { FieldType, VaultItem } from "@padloc/core/lib/item.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { app } from "../init.js";
|
||||
import { element, html, query } from "./base.js";
|
||||
import { element, html, css, query } from "./base.js";
|
||||
import { Input } from "./input.js";
|
||||
import { Select } from "./select.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
|
@ -88,25 +88,28 @@ export class CreateItemDialog extends Dialog<undefined, VaultItem> {
|
|||
@query("#templateSelect")
|
||||
private _templateSelect: Select<Template>;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
:host {
|
||||
--gutter-size: 12px;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select {
|
||||
text-align: center;
|
||||
margin: var(--gutter-size);
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
--gutter-size: 12px;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select {
|
||||
text-align: center;
|
||||
margin: var(--gutter-size);
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>${$l("Create Vault Item")}</h1>
|
||||
|
||||
<pl-input id="nameInput" .label=${$l("Item Name")} @enter=${() => this._enter()}> </pl-input>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { shared, mixins } from "../styles";
|
||||
import { animateElement } from "../animation";
|
||||
import { BaseElement, html, property, observe, listen } from "./base.js";
|
||||
import { BaseElement, html, css, property, observe, listen } from "./base.js";
|
||||
import { Input } from "./input.js";
|
||||
|
||||
export class Dialog<I, R> extends BaseElement {
|
||||
|
@ -27,84 +27,84 @@ export class Dialog<I, R> extends BaseElement {
|
|||
});
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
${mixins.fullbleed()}
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
:host(:not([open])) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.outer {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.scrim {
|
||||
display: block;
|
||||
background: #000000;
|
||||
opacity: 0;
|
||||
transition: opacity 400ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
transform: translate3d(0, 0, 0);
|
||||
${mixins.fullbleed()}
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
:host([open]) .scrim {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
max-width: var(--pl-dialog-max-width, 400px);
|
||||
z-index: 1;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0 0 5px;
|
||||
overflow: hidden;
|
||||
background: var(--color-tertiary);
|
||||
}
|
||||
|
||||
.outer {
|
||||
transform: translate3d(0, 0, 0);
|
||||
/* transition: transform 400ms cubic-bezier(1, -0.3, 0, 1.3), opacity 400ms cubic-bezier(0.6, 0, 0.2, 1); */
|
||||
transition: transform 400ms cubic-bezier(0.6, 0, 0.2, 1), opacity 400ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
grid-gap: var(--gutter-size);
|
||||
margin: var(--gutter-size);
|
||||
}
|
||||
|
||||
.actions.vertical {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
:host(:not([open])) .outer {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 0, 0) scale(0.8);
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
${mixins.fullbleed()}
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
:host(:not([open])) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.outer {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.scrim {
|
||||
display: block;
|
||||
background: #000000;
|
||||
opacity: 0;
|
||||
transition: opacity 400ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
transform: translate3d(0, 0, 0);
|
||||
${mixins.fullbleed()}
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
:host([open]) .scrim {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
max-width: var(--pl-dialog-max-width, 400px);
|
||||
z-index: 1;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0 0 5px;
|
||||
overflow: hidden;
|
||||
background: var(--color-tertiary);
|
||||
}
|
||||
|
||||
.outer {
|
||||
transform: translate3d(0, 0, 0);
|
||||
/* transition: transform 400ms cubic-bezier(1, -0.3, 0, 1.3), opacity 400ms cubic-bezier(0.6, 0, 0.2, 1); */
|
||||
transition: transform 400ms cubic-bezier(0.6, 0, 0.2, 1), opacity 400ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
grid-gap: var(--gutter-size);
|
||||
margin: var(--gutter-size);
|
||||
}
|
||||
|
||||
.actions.vertical {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
:host(:not([open])) .outer {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 0, 0) scale(0.8);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="scrim"></div>
|
||||
|
||||
<div class="outer" @click=${() => this.dismiss()}>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { localize as $l } from "@padloc/core/lib/locale.js";
|
|||
import { CSV, ImportFormat } from "../import.js";
|
||||
import { supportedFormats, asCSV } from "../export.js";
|
||||
import { app } from "../init.js";
|
||||
import { element, html, query } from "./base.js";
|
||||
import { element, html, css, query } from "./base.js";
|
||||
import { Select } from "./select.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
|
||||
|
@ -14,35 +14,38 @@ export class ExportDialog extends Dialog<void, void> {
|
|||
@query("#vaultSelect")
|
||||
private _vaultSelect: Select<Vault>;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
.inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select,
|
||||
button {
|
||||
text-align: center;
|
||||
margin: 0 10px 10px 10px;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.csv-note {
|
||||
font-size: var(--font-size-micro);
|
||||
text-align: center;
|
||||
padding: 0px 20px 20px 20px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
return html`
|
||||
<style>
|
||||
.inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select,
|
||||
button {
|
||||
text-align: center;
|
||||
margin: 0 10px 10px 10px;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.csv-note {
|
||||
font-size: var(--font-size-micro);
|
||||
text-align: center;
|
||||
padding: 0px 20px 20px 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>${$l("Export Data")}</h1>
|
||||
|
||||
<pl-select
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { FieldType, FieldDef, FIELD_DEFS } from "@padloc/core/lib/item.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { shared } from "../styles";
|
||||
import { BaseElement, element, html, property, query } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, query } from "./base.js";
|
||||
import "./icon.js";
|
||||
import { Input } from "./input.js";
|
||||
import { Select } from "./select.js";
|
||||
|
@ -45,6 +45,80 @@ export class FieldElement extends BaseElement {
|
|||
}
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.field-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.field-buttons.left {
|
||||
margin: 0 -4px 0 4px;
|
||||
}
|
||||
|
||||
:host(:not(:hover)) .field-buttons.right {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.field-header {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.fields-container {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: var(--font-size-tiny);
|
||||
font-weight: bold;
|
||||
color: var(--color-highlight);
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.field-type {
|
||||
width: 95px;
|
||||
font-weight: bold;
|
||||
margin-left: 4px;
|
||||
padding: 0;
|
||||
padding-left: 10px;
|
||||
font-size: var(--font-size-micro);
|
||||
color: var(--color-gradient-warning-to);
|
||||
}
|
||||
|
||||
.field-value {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: 110%;
|
||||
flex: 1;
|
||||
padding: 0 10px;
|
||||
opacity: 1;
|
||||
--rule-width: 1px;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select {
|
||||
height: auto;
|
||||
line-height: 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
pl-input[readonly] {
|
||||
background: transparent;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const fieldDef = FIELD_DEFS[this.type] || FIELD_DEFS.text;
|
||||
let inputType: string;
|
||||
|
@ -67,107 +141,29 @@ export class FieldElement extends BaseElement {
|
|||
}
|
||||
const mask = fieldDef.mask && !this.editing;
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.field-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.field-buttons.left {
|
||||
margin: 0 -4px 0 4px;
|
||||
}
|
||||
|
||||
:host(:not(:hover)) .field-buttons.right {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.field-header {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.fields-container {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: var(--font-size-tiny);
|
||||
font-weight: bold;
|
||||
color: var(--color-highlight);
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.field-type {
|
||||
width: 95px;
|
||||
font-weight: bold;
|
||||
margin-left: 4px;
|
||||
padding: 0;
|
||||
padding-left: 10px;
|
||||
font-size: var(--font-size-micro);
|
||||
color: var(--color-gradient-warning-to);
|
||||
}
|
||||
|
||||
.field-value {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: 110%;
|
||||
flex: 1;
|
||||
padding: 0 10px;
|
||||
opacity: 1;
|
||||
--rule-width: 1px;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select {
|
||||
height: auto;
|
||||
line-height: 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
pl-input[readonly] {
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="field-buttons left" ?hidden=${!this.editing}>
|
||||
|
||||
<pl-icon
|
||||
icon="remove"
|
||||
class="tap"
|
||||
@click=${() => this.dispatch("remove")}>
|
||||
</pl-icon>
|
||||
<pl-icon icon="remove" class="tap" @click=${() => this.dispatch("remove")}> </pl-icon>
|
||||
|
||||
<pl-icon
|
||||
?hidden=${this.type !== "password"}
|
||||
icon="generate"
|
||||
class="tap"
|
||||
@click=${() => this.dispatch("generate")}>
|
||||
@click=${() => this.dispatch("generate")}
|
||||
>
|
||||
</pl-icon>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="fields-container flex">
|
||||
|
||||
<div class="field-header">
|
||||
|
||||
<pl-input class="field-name"
|
||||
<pl-input
|
||||
class="field-name"
|
||||
id="nameInput"
|
||||
placeholder="${$l("Enter Field Name")}"
|
||||
.value=${this.name}
|
||||
@input=${() => (this.name = this._nameInput.value)}
|
||||
@click=${() => !this._nameInput.value && this.dispatch("edit")}
|
||||
?readonly=${!this.editing}>
|
||||
?readonly=${!this.editing}
|
||||
>
|
||||
</pl-input>
|
||||
|
||||
<pl-select
|
||||
|
@ -177,9 +173,9 @@ export class FieldElement extends BaseElement {
|
|||
?hidden=${!this.editing}
|
||||
.options=${Object.values(FIELD_DEFS)}
|
||||
.selected=${fieldDef}
|
||||
@change=${() => (this.type = this._typeSelect.selected!.type)}>
|
||||
@change=${() => (this.type = this._typeSelect.selected!.type)}
|
||||
>
|
||||
</pl-select>
|
||||
|
||||
</div>
|
||||
|
||||
<pl-input
|
||||
|
@ -193,26 +189,21 @@ export class FieldElement extends BaseElement {
|
|||
.value=${this.value}
|
||||
@input=${() => (this.value = this._valueInput.value)}
|
||||
@click=${() => !this._valueInput.value && this.dispatch("edit")}
|
||||
autosize>
|
||||
autosize
|
||||
>
|
||||
</pl-input>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="field-buttons right" ?hidden=${this.editing}>
|
||||
|
||||
<pl-icon
|
||||
.icon=${(this._valueInput ? this._valueInput.masked : mask) ? "show" : "hide"}
|
||||
class="tap"
|
||||
?hidden=${!fieldDef.mask}
|
||||
@click=${() => this._toggleMask()}>
|
||||
</pl-icon>
|
||||
|
||||
<pl-icon
|
||||
icon="copy"
|
||||
class="tap"
|
||||
@click=${() => this.dispatch("copy")}>
|
||||
@click=${() => this._toggleMask()}
|
||||
>
|
||||
</pl-icon>
|
||||
|
||||
<pl-icon icon="copy" class="tap" @click=${() => this.dispatch("copy")}> </pl-icon>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { randomArt } from "@padloc/core/lib/randomart.js";
|
|||
import { getProvider } from "@padloc/core/lib/crypto.js";
|
||||
import { svg } from "lit-html";
|
||||
import { until } from "lit-html/directives/until.js";
|
||||
import { BaseElement, html, element, property } from "./base";
|
||||
import { BaseElement, html, css, element, property } from "./base";
|
||||
|
||||
@element("pl-fingerprint")
|
||||
export class Fingerprint extends BaseElement {
|
||||
|
@ -30,27 +30,29 @@ export class Fingerprint extends BaseElement {
|
|||
return !!this.key;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--color-background);
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: currentColor;
|
||||
pointer-events: none;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--color-background);
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: currentColor;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
${until(this._grid())}
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { randomString, chars } from "@padloc/core/lib/util.js";
|
||||
import { generatePassphrase } from "@padloc/core/lib/diceware.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { shared } from "../styles";
|
||||
import { html, property, query, listen } from "./base.js";
|
||||
import { html, css, property, query, listen } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { Slider } from "./slider.js";
|
||||
import { ToggleButton } from "./toggle-button.js";
|
||||
|
@ -58,78 +57,82 @@ export class Generator extends Dialog<void, string> {
|
|||
@query("#length")
|
||||
private _length: Slider;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
.header {
|
||||
background: var(--color-tertiary);
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 120%;
|
||||
padding: 20px 20px 10px 20px;
|
||||
}
|
||||
|
||||
.charsets {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.charsets > * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
pl-toggle-button {
|
||||
display: block;
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
pl-slider {
|
||||
display: flex;
|
||||
height: var(--row-height);
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
pl-select {
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.result {
|
||||
font-family: var(--font-family-mono);
|
||||
text-align: center;
|
||||
font-size: 120%;
|
||||
overflow-wrap: break-word;
|
||||
font-weight: bold;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: block;
|
||||
margin: -10px auto;
|
||||
font-size: 120%;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const { value } = this;
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
.header {
|
||||
background: var(--color-tertiary);
|
||||
text-align: center;
|
||||
border-bottom: solid 3px var(--color-shade-1);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 120%;
|
||||
padding: 20px 20px 10px 20px;
|
||||
}
|
||||
|
||||
.charsets {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.charsets > * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
pl-toggle-button {
|
||||
display: block;
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
pl-slider {
|
||||
display: flex;
|
||||
height: var(--row-height);
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
pl-select {
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.result {
|
||||
font-family: var(--font-family-mono);
|
||||
text-align: center;
|
||||
font-size: 120%;
|
||||
overflow-wrap: break-word;
|
||||
font-weight: bold;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: block;
|
||||
margin: -10px auto;
|
||||
font-size: 120%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header">
|
||||
<div class="header-title">${$l("Generate Password")}</div>
|
||||
<div class="tabs">
|
||||
<div class="flex tap" ?active=${this.mode === "words"} @click=${() => this._selectMode("words")}>
|
||||
<div
|
||||
class="flex tab tap"
|
||||
?active=${this.mode === "words"}
|
||||
@click=${() => this._selectMode("words")}
|
||||
>
|
||||
${$l("passphrase")}
|
||||
</div>
|
||||
<div class="flex tap" ?active=${this.mode === "chars"} @click=${() => this._selectMode("chars")}>
|
||||
<div
|
||||
class="flex tab tap"
|
||||
?active=${this.mode === "chars"}
|
||||
@click=${() => this._selectMode("chars")}
|
||||
>
|
||||
${$l("random string")}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Org, OrgMember, Group } from "@padloc/core/lib/org.js";
|
|||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { app } from "../init.js";
|
||||
import { prompt } from "../dialog.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import { Input } from "./input.js";
|
||||
|
@ -151,6 +151,25 @@ export class GroupDialog extends Dialog<InputType, void> {
|
|||
return !!this.org;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
pl-toggle-button {
|
||||
display: block;
|
||||
padding: 0 15px 0 0;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
color: var(--color-negative);
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const org = this.org!;
|
||||
const memFilter = this._membersFilter.toLowerCase();
|
||||
|
@ -164,22 +183,6 @@ export class GroupDialog extends Dialog<InputType, void> {
|
|||
const canDelete = this.group && canEdit;
|
||||
|
||||
return html`
|
||||
<style>
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
pl-toggle-button {
|
||||
display: block;
|
||||
padding: 0 15px 0 0;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
color: var(--color-negative);
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<pl-icon icon="group"></pl-icon>
|
||||
<pl-input
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Group } from "@padloc/core/lib/org.js";
|
||||
import { shared } from "../styles";
|
||||
import { BaseElement, element, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, property } from "./base.js";
|
||||
import "./icon.js";
|
||||
|
||||
@element("pl-group-item")
|
||||
|
@ -8,41 +8,42 @@ export class GroupItem extends BaseElement {
|
|||
@property()
|
||||
group: Group;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 120%;
|
||||
margin: 8px;
|
||||
background: #eee;
|
||||
border: solid 1px #ddd;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.group-name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.group-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 120%;
|
||||
margin: 8px;
|
||||
background: #eee;
|
||||
border: solid 1px #ddd;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.group-name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.group-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<pl-icon class="icon" icon="group"></pl-icon>
|
||||
|
||||
<div class="group-info">
|
||||
|
|
|
@ -1,334 +1,335 @@
|
|||
import { BaseElement, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, property } from "./base.js";
|
||||
|
||||
@element("pl-icon")
|
||||
export class PlIcon extends BaseElement {
|
||||
@property({ reflect: true })
|
||||
icon: string = "";
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
:host {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
font-family: "FontAwesome";
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
position: relative;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
font-weight: normal !important;
|
||||
border-radius: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
height: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
:host([icon="add"]) > div::before {
|
||||
content: "\\f067";
|
||||
}
|
||||
|
||||
:host([icon="menu"]) > div::before {
|
||||
content: "\\f0c9";
|
||||
}
|
||||
|
||||
:host([icon="close"]) > div::before {
|
||||
content: "\\f00d";
|
||||
}
|
||||
|
||||
:host([icon="more"]) > div::before {
|
||||
content: "\\f141";
|
||||
}
|
||||
|
||||
:host([icon="delete"]) > div::before {
|
||||
content: "\\f2ed";
|
||||
}
|
||||
|
||||
:host([icon="copy"]) > div::before {
|
||||
/* content: "\\f24d"; */
|
||||
content: "\\f0c5";
|
||||
}
|
||||
|
||||
:host([icon="edit"]) > div::before {
|
||||
content: "\\f303";
|
||||
}
|
||||
|
||||
:host([icon="forward"]) > div::before {
|
||||
content: "\\f054";
|
||||
}
|
||||
|
||||
:host([icon="backward"]) > div::before {
|
||||
content: "\\f053";
|
||||
}
|
||||
|
||||
:host([icon="check"]) > div::before {
|
||||
content: "\\f00c";
|
||||
}
|
||||
|
||||
:host([icon="cancel"]) > div::before {
|
||||
content: "\\f00d";
|
||||
}
|
||||
|
||||
:host([icon="generate"]) > div::before {
|
||||
content: "\\f0d0";
|
||||
}
|
||||
|
||||
:host([icon="tag"]) > div::before {
|
||||
content: "\\f02b";
|
||||
}
|
||||
|
||||
:host([icon="tags"]) > div::before {
|
||||
content: "\\f02c";
|
||||
}
|
||||
|
||||
:host([icon="dropdown"]) > div::before {
|
||||
content: "\\f0d7";
|
||||
}
|
||||
|
||||
:host([icon="dropup"]) > div::before {
|
||||
content: "\\f0d8";
|
||||
}
|
||||
|
||||
:host([icon="settings"]) > div::before {
|
||||
content: "\\f013";
|
||||
}
|
||||
|
||||
:host([icon="cloud"]) > div::before {
|
||||
content: "\\f0c2";
|
||||
}
|
||||
|
||||
:host([icon="lock"]) > div::before {
|
||||
content: "\\f023";
|
||||
}
|
||||
|
||||
:host([icon="refresh"]) > div::before {
|
||||
content: "\\f2f1";
|
||||
}
|
||||
|
||||
:host([icon="unlock"]) > div::before {
|
||||
content: "\\f13e";
|
||||
}
|
||||
|
||||
:host([icon="export"]) > div::before {
|
||||
content: "\\f093";
|
||||
}
|
||||
|
||||
:host([icon="import"]) > div::before {
|
||||
content: "\\f019";
|
||||
}
|
||||
|
||||
:host([icon="search"]) > div::before {
|
||||
content: "\\f002";
|
||||
}
|
||||
|
||||
:host([icon="info"]) > div::before {
|
||||
content: "\\f129";
|
||||
}
|
||||
|
||||
:host([icon="info-round"]) > div::before {
|
||||
content: "\\f05a";
|
||||
}
|
||||
|
||||
:host([icon="download"]) > div::before {
|
||||
content: "\\f019";
|
||||
}
|
||||
|
||||
:host([icon="upload"]) > div::before {
|
||||
content: "\\f093";
|
||||
}
|
||||
|
||||
:host([icon="show"]) > div::before {
|
||||
content: "\\f06e";
|
||||
}
|
||||
|
||||
:host([icon="hide"]) > div::before {
|
||||
content: "\\f070";
|
||||
}
|
||||
|
||||
:host([icon="checked"]) > div::before {
|
||||
content: "\\f14a";
|
||||
}
|
||||
|
||||
:host([icon="checkall"]) > div::before {
|
||||
content: "\\f560";
|
||||
}
|
||||
|
||||
:host([icon="success"]) > div::before {
|
||||
content: "\\f058";
|
||||
}
|
||||
|
||||
:host([icon="unchecked"]) > div::before {
|
||||
content: "\\f146";
|
||||
}
|
||||
|
||||
:host([icon="share"]) > div::before {
|
||||
content: "\\f045";
|
||||
}
|
||||
|
||||
:host([icon="logout"]) > div::before {
|
||||
content: "\\f2f5";
|
||||
}
|
||||
|
||||
:host([icon="mail"]) > div::before {
|
||||
content: "\\f0e0";
|
||||
}
|
||||
|
||||
:host([icon="user"]) > div::before {
|
||||
content: "\\f007";
|
||||
}
|
||||
|
||||
:host([icon="record"]) > div::before {
|
||||
content: "\\f15b";
|
||||
}
|
||||
|
||||
:host([icon="mobile"]) > div::before {
|
||||
content: "\\f10b";
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
:host([icon="database"]) > div::before {
|
||||
content: "\\f1c0";
|
||||
}
|
||||
|
||||
:host([icon="time"]) > div::before {
|
||||
content: "\\f017";
|
||||
}
|
||||
|
||||
:host([icon="error"]) > div::before {
|
||||
content: "\\f071";
|
||||
}
|
||||
|
||||
:host([icon="question"]) > div::before {
|
||||
content: "\\f059";
|
||||
}
|
||||
|
||||
:host([icon="desktop"]) > div::before {
|
||||
content: "\\f109";
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
:host([icon="group"]) > div::before {
|
||||
content: "\\f0c0";
|
||||
}
|
||||
|
||||
:host([icon="vaults"]) > div::before {
|
||||
content: "\\f1b3";
|
||||
}
|
||||
|
||||
:host([icon="vault"]) > div::before {
|
||||
content: "\\f1b2";
|
||||
}
|
||||
|
||||
:host([icon="share"]) > div::before {
|
||||
content: "\\f064";
|
||||
}
|
||||
|
||||
:host([icon="invite"]) > div::before {
|
||||
content: "\\f234";
|
||||
}
|
||||
|
||||
:host([icon="trusted"]) > div::before {
|
||||
content: "\\f4fc";
|
||||
}
|
||||
|
||||
:host([icon="removeuser"]) > div::before {
|
||||
content: "\\f506";
|
||||
}
|
||||
|
||||
:host([icon="org"]) > div::before {
|
||||
content: "\\f1ad";
|
||||
}
|
||||
|
||||
// :host([icon="logo"]) > div::before {
|
||||
// content: "\\f447";
|
||||
// }
|
||||
|
||||
:host([icon="list"]) > div::before {
|
||||
content: "\\f0ca";
|
||||
}
|
||||
|
||||
:host([icon="remove"]) > div::before {
|
||||
content: "\\f056";
|
||||
}
|
||||
|
||||
:host([icon="password"]) > div::before {
|
||||
content: "\\f069";
|
||||
}
|
||||
|
||||
:host([icon="admins"]) > div::before {
|
||||
content: "\\f509";
|
||||
}
|
||||
|
||||
:host([icon="archive"]) > div::before {
|
||||
content: "\\f187";
|
||||
}
|
||||
|
||||
:host([icon="attachment"]) > div::before {
|
||||
content: "\\f0c6";
|
||||
}
|
||||
|
||||
:host([icon="file"]) > div::before {
|
||||
content: "\\f15b";
|
||||
}
|
||||
|
||||
:host([icon="file-video"]) > div::before {
|
||||
content: "\\f1c8";
|
||||
}
|
||||
|
||||
:host([icon="file-pdf"]) > div::before {
|
||||
content: "\\f1c1";
|
||||
}
|
||||
|
||||
:host([icon="file-image"]) > div::before {
|
||||
content: "\\f1c5";
|
||||
}
|
||||
|
||||
:host([icon="file-csv"]) > div::before {
|
||||
content: "\\f6dd";
|
||||
}
|
||||
|
||||
:host([icon="file-code"]) > div::before {
|
||||
content: "\\f1c9";
|
||||
}
|
||||
|
||||
:host([icon="file-archive"]) > div::before {
|
||||
content: "\\f1c6";
|
||||
}
|
||||
|
||||
:host([icon="file-audio"]) > div::before {
|
||||
content: "\\f1c7";
|
||||
}
|
||||
|
||||
:host([icon="file-text"]) > div::before {
|
||||
content: "\\f15c";
|
||||
}
|
||||
|
||||
:host([icon="arrow-down"]) > div::before {
|
||||
content: "\\f309";
|
||||
}
|
||||
|
||||
:host([icon="favorite"]) > div::before {
|
||||
content: "\\f005";
|
||||
}
|
||||
|
||||
:host([icon="logo"]) > div::before {
|
||||
font-family: "Padlock";
|
||||
content: "\\0041";
|
||||
font-size: 110%;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
font-family: "FontAwesome";
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
position: relative;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
font-weight: normal !important;
|
||||
border-radius: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
height: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
:host([icon="add"]) > div::before {
|
||||
content: "\\f067";
|
||||
}
|
||||
|
||||
:host([icon="menu"]) > div::before {
|
||||
content: "\\f0c9";
|
||||
}
|
||||
|
||||
:host([icon="close"]) > div::before {
|
||||
content: "\\f00d";
|
||||
}
|
||||
|
||||
:host([icon="more"]) > div::before {
|
||||
content: "\\f141";
|
||||
}
|
||||
|
||||
:host([icon="delete"]) > div::before {
|
||||
content: "\\f2ed";
|
||||
}
|
||||
|
||||
:host([icon="copy"]) > div::before {
|
||||
/* content: "\\f24d"; */
|
||||
content: "\\f0c5";
|
||||
}
|
||||
|
||||
:host([icon="edit"]) > div::before {
|
||||
content: "\\f303";
|
||||
}
|
||||
|
||||
:host([icon="forward"]) > div::before {
|
||||
content: "\\f054";
|
||||
}
|
||||
|
||||
:host([icon="backward"]) > div::before {
|
||||
content: "\\f053";
|
||||
}
|
||||
|
||||
:host([icon="check"]) > div::before {
|
||||
content: "\\f00c";
|
||||
}
|
||||
|
||||
:host([icon="cancel"]) > div::before {
|
||||
content: "\\f00d";
|
||||
}
|
||||
|
||||
:host([icon="generate"]) > div::before {
|
||||
content: "\\f0d0";
|
||||
}
|
||||
|
||||
:host([icon="tag"]) > div::before {
|
||||
content: "\\f02b";
|
||||
}
|
||||
|
||||
:host([icon="tags"]) > div::before {
|
||||
content: "\\f02c";
|
||||
}
|
||||
|
||||
:host([icon="dropdown"]) > div::before {
|
||||
content: "\\f0d7";
|
||||
}
|
||||
|
||||
:host([icon="dropup"]) > div::before {
|
||||
content: "\\f0d8";
|
||||
}
|
||||
|
||||
:host([icon="settings"]) > div::before {
|
||||
content: "\\f013";
|
||||
}
|
||||
|
||||
:host([icon="cloud"]) > div::before {
|
||||
content: "\\f0c2";
|
||||
}
|
||||
|
||||
:host([icon="lock"]) > div::before {
|
||||
content: "\\f023";
|
||||
}
|
||||
|
||||
:host([icon="refresh"]) > div::before {
|
||||
content: "\\f2f1";
|
||||
}
|
||||
|
||||
:host([icon="unlock"]) > div::before {
|
||||
content: "\\f13e";
|
||||
}
|
||||
|
||||
:host([icon="export"]) > div::before {
|
||||
content: "\\f093";
|
||||
}
|
||||
|
||||
:host([icon="import"]) > div::before {
|
||||
content: "\\f019";
|
||||
}
|
||||
|
||||
:host([icon="search"]) > div::before {
|
||||
content: "\\f002";
|
||||
}
|
||||
|
||||
:host([icon="info"]) > div::before {
|
||||
content: "\\f129";
|
||||
}
|
||||
|
||||
:host([icon="info-round"]) > div::before {
|
||||
content: "\\f05a";
|
||||
}
|
||||
|
||||
:host([icon="download"]) > div::before {
|
||||
content: "\\f019";
|
||||
}
|
||||
|
||||
:host([icon="upload"]) > div::before {
|
||||
content: "\\f093";
|
||||
}
|
||||
|
||||
:host([icon="show"]) > div::before {
|
||||
content: "\\f06e";
|
||||
}
|
||||
|
||||
:host([icon="hide"]) > div::before {
|
||||
content: "\\f070";
|
||||
}
|
||||
|
||||
:host([icon="checked"]) > div::before {
|
||||
content: "\\f14a";
|
||||
}
|
||||
|
||||
:host([icon="checkall"]) > div::before {
|
||||
content: "\\f560";
|
||||
}
|
||||
|
||||
:host([icon="success"]) > div::before {
|
||||
content: "\\f058";
|
||||
}
|
||||
|
||||
:host([icon="unchecked"]) > div::before {
|
||||
content: "\\f146";
|
||||
}
|
||||
|
||||
:host([icon="share"]) > div::before {
|
||||
content: "\\f045";
|
||||
}
|
||||
|
||||
:host([icon="logout"]) > div::before {
|
||||
content: "\\f2f5";
|
||||
}
|
||||
|
||||
:host([icon="mail"]) > div::before {
|
||||
content: "\\f0e0";
|
||||
}
|
||||
|
||||
:host([icon="user"]) > div::before {
|
||||
content: "\\f007";
|
||||
}
|
||||
|
||||
:host([icon="record"]) > div::before {
|
||||
content: "\\f15b";
|
||||
}
|
||||
|
||||
:host([icon="mobile"]) > div::before {
|
||||
content: "\\f10b";
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
:host([icon="database"]) > div::before {
|
||||
content: "\\f1c0";
|
||||
}
|
||||
|
||||
:host([icon="time"]) > div::before {
|
||||
content: "\\f017";
|
||||
}
|
||||
|
||||
:host([icon="error"]) > div::before {
|
||||
content: "\\f071";
|
||||
}
|
||||
|
||||
:host([icon="question"]) > div::before {
|
||||
content: "\\f059";
|
||||
}
|
||||
|
||||
:host([icon="desktop"]) > div::before {
|
||||
content: "\\f109";
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
:host([icon="group"]) > div::before {
|
||||
content: "\\f0c0";
|
||||
}
|
||||
|
||||
:host([icon="vaults"]) > div::before {
|
||||
content: "\\f1b3";
|
||||
}
|
||||
|
||||
:host([icon="vault"]) > div::before {
|
||||
content: "\\f1b2";
|
||||
}
|
||||
|
||||
:host([icon="share"]) > div::before {
|
||||
content: "\\f064";
|
||||
}
|
||||
|
||||
:host([icon="invite"]) > div::before {
|
||||
content: "\\f234";
|
||||
}
|
||||
|
||||
:host([icon="trusted"]) > div::before {
|
||||
content: "\\f4fc";
|
||||
}
|
||||
|
||||
:host([icon="removeuser"]) > div::before {
|
||||
content: "\\f506";
|
||||
}
|
||||
|
||||
:host([icon="org"]) > div::before {
|
||||
content: "\\f1ad";
|
||||
}
|
||||
|
||||
// :host([icon="logo"]) > div::before {
|
||||
// content: "\\f447";
|
||||
// }
|
||||
|
||||
:host([icon="list"]) > div::before {
|
||||
content: "\\f0ca";
|
||||
}
|
||||
|
||||
:host([icon="remove"]) > div::before {
|
||||
content: "\\f056";
|
||||
}
|
||||
|
||||
:host([icon="password"]) > div::before {
|
||||
content: "\\f069";
|
||||
}
|
||||
|
||||
:host([icon="admins"]) > div::before {
|
||||
content: "\\f509";
|
||||
}
|
||||
|
||||
:host([icon="archive"]) > div::before {
|
||||
content: "\\f187";
|
||||
}
|
||||
|
||||
:host([icon="attachment"]) > div::before {
|
||||
content: "\\f0c6";
|
||||
}
|
||||
|
||||
:host([icon="file"]) > div::before {
|
||||
content: "\\f15b";
|
||||
}
|
||||
|
||||
:host([icon="file-video"]) > div::before {
|
||||
content: "\\f1c8";
|
||||
}
|
||||
|
||||
:host([icon="file-pdf"]) > div::before {
|
||||
content: "\\f1c1";
|
||||
}
|
||||
|
||||
:host([icon="file-image"]) > div::before {
|
||||
content: "\\f1c5";
|
||||
}
|
||||
|
||||
:host([icon="file-csv"]) > div::before {
|
||||
content: "\\f6dd";
|
||||
}
|
||||
|
||||
:host([icon="file-code"]) > div::before {
|
||||
content: "\\f1c9";
|
||||
}
|
||||
|
||||
:host([icon="file-archive"]) > div::before {
|
||||
content: "\\f1c6";
|
||||
}
|
||||
|
||||
:host([icon="file-audio"]) > div::before {
|
||||
content: "\\f1c7";
|
||||
}
|
||||
|
||||
:host([icon="file-text"]) > div::before {
|
||||
content: "\\f15c";
|
||||
}
|
||||
|
||||
:host([icon="arrow-down"]) > div::before {
|
||||
content: "\\f309";
|
||||
}
|
||||
|
||||
:host([icon="favorite"]) > div::before {
|
||||
content: "\\f005";
|
||||
}
|
||||
|
||||
:host([icon="logo"]) > div::before {
|
||||
font-family: "Padlock";
|
||||
content: "\\0041";
|
||||
font-size: 110%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div></div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define("pl-icon", PlIcon);
|
||||
|
|
|
@ -4,7 +4,7 @@ import { localize as $l } from "@padloc/core/lib/locale.js";
|
|||
import * as imp from "../import.js";
|
||||
import { prompt, alert } from "../dialog.js";
|
||||
import { app } from "../init.js";
|
||||
import { element, html, query, property } from "./base.js";
|
||||
import { element, html, css, query, property } from "./base.js";
|
||||
import { Select } from "./select.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
|
||||
|
@ -18,35 +18,38 @@ export class ImportDialog extends Dialog<string, void> {
|
|||
@query("#vaultSelect")
|
||||
private _vaultSelect: Select<Vault>;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
.inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select,
|
||||
button {
|
||||
text-align: center;
|
||||
margin: 0 10px 10px 10px;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.csv-note {
|
||||
font-size: var(--font-size-micro);
|
||||
text-align: center;
|
||||
padding: 0px 20px 20px 20px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
return html`
|
||||
<style>
|
||||
.inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
pl-input,
|
||||
pl-select,
|
||||
button {
|
||||
text-align: center;
|
||||
margin: 0 10px 10px 10px;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.csv-note {
|
||||
font-size: var(--font-size-micro);
|
||||
text-align: center;
|
||||
padding: 0px 20px 20px 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>${$l("Import Data")}</h1>
|
||||
|
||||
<pl-select id="formatSelect" .options=${imp.supportedFormats} .label=${$l("Format")} disabled></pl-select>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import autosize from "autosize/src/autosize.js";
|
||||
import { cache } from "lit-html/directives/cache.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, html, property, query, listen } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, query, listen } from "./base.js";
|
||||
|
||||
let activeInput: Input | null = null;
|
||||
|
||||
|
@ -82,6 +82,99 @@ export class Input extends BaseElement {
|
|||
}
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
font-family: inherit;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
:host(:not([multiline])) {
|
||||
padding: 0 10px;
|
||||
height: var(--row-height);
|
||||
}
|
||||
|
||||
input {
|
||||
box-sizing: border-box;
|
||||
text-overflow: ellipsis;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
text-align: inherit;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: inherit;
|
||||
line-height: inherit;
|
||||
caret-color: currentColor;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-placeholder {
|
||||
text-shadow: inherit;
|
||||
color: inherit;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
--fullbleed: {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.mask {
|
||||
pointer-events: none;
|
||||
font-size: 150%;
|
||||
padding: inherit;
|
||||
line-height: inherit;
|
||||
letter-spacing: -4.5px;
|
||||
margin-left: -4px;
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 13px;
|
||||
opacity: 0.5;
|
||||
transition: transform 0.2s, color 0.2s, opacity 0.5s;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
label[float] {
|
||||
transform: scale(0.8) translate(0, -32px);
|
||||
color: var(--color-highlight);
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[disabled],
|
||||
textarea[disabled] {
|
||||
opacity: 1;
|
||||
-webkit-text-fill-color: currentColor;
|
||||
}
|
||||
|
||||
input[invsbl],
|
||||
textarea[invsbl] {
|
||||
opacity: 0;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
|
@ -152,98 +245,6 @@ export class Input extends BaseElement {
|
|||
);
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
font-family: inherit;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
:host(:not([multiline])) {
|
||||
padding: 0 10px;
|
||||
height: var(--row-height);
|
||||
}
|
||||
|
||||
input {
|
||||
box-sizing: border-box;
|
||||
text-overflow: ellipsis;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
text-align: inherit;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: inherit;
|
||||
line-height: inherit;
|
||||
caret-color: currentColor;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
::-webkit-search-cancel-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-placeholder {
|
||||
text-shadow: inherit;
|
||||
color: inherit;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
--fullbleed: {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.mask {
|
||||
pointer-events: none;
|
||||
font-size: 150%;
|
||||
padding: inherit;
|
||||
line-height: inherit;
|
||||
letter-spacing: -4.5px;
|
||||
margin-left: -4px;
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 13px;
|
||||
opacity: 0.5;
|
||||
transition: transform 0.2s, color 0.2s, opacity 0.5s;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
label[float] {
|
||||
transform: scale(0.8) translate(0, -32px);
|
||||
color: var(--color-highlight);
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[disabled],
|
||||
textarea[disabled] {
|
||||
opacity: 1;
|
||||
-webkit-text-fill-color: currentColor;
|
||||
}
|
||||
|
||||
input[invsbl],
|
||||
textarea[invsbl] {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
${input}
|
||||
|
||||
<label for="input" ?float=${focused || !!value || !!placeholder} ?hidden=${!label}>${label}</label>
|
||||
|
|
|
@ -3,9 +3,8 @@ import { Invite } from "@padloc/core/lib/invite.js";
|
|||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { formatDateFromNow } from "../util.js";
|
||||
import { app } from "../init";
|
||||
import { shared } from "../styles";
|
||||
import { alert, dialog } from "../dialog.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import { Input } from "./input.js";
|
||||
|
@ -50,6 +49,78 @@ export class InviteDialog extends Dialog<Invite, void> {
|
|||
return !!this.invite;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
:host {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.invite {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.invite-text {
|
||||
font-size: var(--font-size-small);
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.invite-text.small {
|
||||
font-size: var(--font-size-tiny);
|
||||
}
|
||||
|
||||
.invite-text.error {
|
||||
color: var(--color-error);
|
||||
text-shadow: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.invite-email {
|
||||
font-size: 120%;
|
||||
margin: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
font-size: 200%;
|
||||
font-family: var(--font-family-mono);
|
||||
text-transform: uppercase;
|
||||
margin: 20px;
|
||||
letter-spacing: 5px;
|
||||
font-weight: bold;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.tags {
|
||||
justify-content: center;
|
||||
overflow: visible;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.tag.org {
|
||||
font-size: var(--font-size-small);
|
||||
padding: 4px 16px;
|
||||
}
|
||||
|
||||
.code-input {
|
||||
border-radius: 8px;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const { email, expires, expired, org, accepted, purpose } = this.invite!;
|
||||
const forMe = email === app.account!.email;
|
||||
|
@ -72,77 +143,6 @@ export class InviteDialog extends Dialog<Invite, void> {
|
|||
};
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.invite {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.invite-text {
|
||||
font-size: var(--font-size-small);
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.invite-text.small {
|
||||
font-size: var(--font-size-tiny);
|
||||
}
|
||||
|
||||
.invite-text.error {
|
||||
color: var(--color-error);
|
||||
text-shadow: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.invite-email {
|
||||
font-size: 120%;
|
||||
margin: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
font-size: 200%;
|
||||
font-family: var(--font-family-mono);
|
||||
text-transform: uppercase;
|
||||
margin: 20px;
|
||||
letter-spacing: 5px;
|
||||
font-weight: bold;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.tags {
|
||||
justify-content: center;
|
||||
overflow: visible;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.tag.org {
|
||||
font-size: var(--font-size-small);
|
||||
padding: 4px 16px;
|
||||
}
|
||||
|
||||
.code-input {
|
||||
border-radius: 8px;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="invite">
|
||||
<pl-icon icon="cancel" class="tap close-button" @click=${() => this.done()}></pl-icon>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { localize as $l } from "@padloc/core/lib/locale.js";
|
|||
import { formatDateFromNow } from "../util.js";
|
||||
import { shared } from "../styles";
|
||||
import { app } from "../init";
|
||||
import { BaseElement, element, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, property } from "./base.js";
|
||||
import "./icon.js";
|
||||
|
||||
@element("pl-invite-item")
|
||||
|
@ -16,6 +16,69 @@ export class InviteItem extends BaseElement {
|
|||
return !!this.invite;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 120%;
|
||||
margin: 10px;
|
||||
background: #eee;
|
||||
border: solid 1px #ddd;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.invite-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.invite:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.invite .tags {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.invite-email {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
text-align: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.invite-code-label {
|
||||
font-weight: bold;
|
||||
font-size: var(--font-size-micro);
|
||||
}
|
||||
|
||||
.invite-code-value {
|
||||
font-size: 140%;
|
||||
font-family: var(--font-family-mono);
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
cursor: text;
|
||||
user-select: text;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const inv = this.invite!;
|
||||
const account = app.account!;
|
||||
|
@ -43,68 +106,6 @@ export class InviteItem extends BaseElement {
|
|||
}
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 120%;
|
||||
margin: 10px;
|
||||
background: #eee;
|
||||
border: solid 1px #ddd;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.invite-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.invite:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.invite .tags {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.invite-email {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
text-align: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.invite-code-label {
|
||||
font-weight: bold;
|
||||
font-size: var(--font-size-micro);
|
||||
}
|
||||
|
||||
.invite-code-value {
|
||||
font-size: 140%;
|
||||
font-family: var(--font-family-mono);
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
cursor: text;
|
||||
user-select: text;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<pl-icon class="icon" icon="mail"></pl-icon>
|
||||
|
||||
<div class="invite-info">
|
||||
|
|
|
@ -9,7 +9,7 @@ import { mixins } from "../styles";
|
|||
import { confirm, dialog } from "../dialog.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { setClipboard } from "../clipboard.js";
|
||||
import { element, html, property, query, queryAll, listen } from "./base.js";
|
||||
import { element, html, css, property, query, queryAll, listen } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import "./icon.js";
|
||||
import { Input } from "./input.js";
|
||||
|
@ -75,6 +75,80 @@ export class ItemDialog extends Dialog<string, void> {
|
|||
this.requestUpdate();
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
:host {
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
.inner {
|
||||
max-width: 400px;
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
header {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
pl-input.name {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
pl-tags-input {
|
||||
margin: 5px 5px -5px 5px;
|
||||
}
|
||||
|
||||
:host(:not([editing])) pl-field:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.add-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.add-button pl-icon {
|
||||
width: 30px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.updated {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-tiny);
|
||||
color: #888;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.updated::before {
|
||||
font-family: FontAwesome;
|
||||
font-size: 80%;
|
||||
content: "\\f303\ ";
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: var(--font-size-tiny);
|
||||
color: var(--color-primary);
|
||||
font-weight: bold;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.fabs {
|
||||
position: static;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
if (app.locked || !this._item || !this._vault) {
|
||||
return html``;
|
||||
|
@ -88,78 +162,6 @@ export class ItemDialog extends Dialog<string, void> {
|
|||
const attachments = this._item!.attachments || [];
|
||||
|
||||
return html`
|
||||
<style>
|
||||
|
||||
:host {
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
.inner {
|
||||
max-width: 400px;
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
header {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
pl-input.name {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
pl-tags-input {
|
||||
margin: 5px 5px -5px 5px;
|
||||
}
|
||||
|
||||
:host(:not([editing])) pl-field:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.add-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.add-button pl-icon {
|
||||
width: 30px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.updated {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-tiny);
|
||||
color: #888;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.updated::before {
|
||||
font-family: FontAwesome;
|
||||
font-size: 80%;
|
||||
content: "\\f303\ ";
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: var(--font-size-tiny);
|
||||
color: var(--color-primary);
|
||||
font-weight: bold;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.fabs {
|
||||
position: static;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<div class="header-inner">
|
||||
<pl-input
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Vault } from "@padloc/core/lib/vault.js";
|
|||
import { Tag } from "@padloc/core/lib/item.js";
|
||||
import { app } from "../init.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, property, html, listen } from "./base.js";
|
||||
import { BaseElement, element, css, property, html, listen } from "./base.js";
|
||||
|
||||
@element("pl-items-filter")
|
||||
export class ItemsFilter extends BaseElement {
|
||||
|
@ -15,130 +15,132 @@ export class ItemsFilter extends BaseElement {
|
|||
this.requestUpdate();
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
text-align: center;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
line-height: normal;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
background: var(--color-shade-1);
|
||||
border-bottom: solid 2px var(--color-shade-2);
|
||||
margin-bottom: -2px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
button.vault {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
border-bottom: solid 2px var(--color-shade-4);
|
||||
}
|
||||
|
||||
button.filter-tag {
|
||||
background: var(--color-secondary);
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
border-bottom: solid 2px #222;
|
||||
}
|
||||
|
||||
button.favorites {
|
||||
background: var(--color-negative);
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
border-bottom: solid 2px var(--color-shade-4);
|
||||
}
|
||||
|
||||
button pl-icon {
|
||||
font-size: 85%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: -6px;
|
||||
}
|
||||
|
||||
.list pl-icon {
|
||||
margin-left: -6px;
|
||||
margin-right: 0;
|
||||
font-size: 80%;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
button > div,
|
||||
.option > div {
|
||||
${mixins.ellipsis()}
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.scrim {
|
||||
z-index: 10;
|
||||
border-top: solid 3px #f2f2f2;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
${mixins.fullbleed()}
|
||||
top: 60px;
|
||||
will-change: opacity;
|
||||
transition: opacity 200ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
:host(:not([selecting])) .scrim {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host(:not([selecting])) .list {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 12px 6px 6px 6px;
|
||||
background: var(--color-tertiary);
|
||||
box-sizing: border-box;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
font-size: var(--font-size-tiny);
|
||||
border-bottom: solid 3px var(--color-shade-1);
|
||||
will-change: transform;
|
||||
transition: transform 200ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
.list button {
|
||||
margin-bottom: 6px;
|
||||
border-bottom: none;
|
||||
padding: 5px 10px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 16px 10px 10px 10px;
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.no-tags {
|
||||
font-size: var(--font-size-micro);
|
||||
padding: 5px 10px 15px 10px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { vault, tag } = app.filter;
|
||||
const cl = vault ? "vault" : tag ? "filter-tag" : "all";
|
||||
const label = vault ? vault.toString() : tag || $l("All Items");
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
text-align: center;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
line-height: normal;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
background: var(--color-shade-1);
|
||||
border-bottom: solid 2px var(--color-shade-2);
|
||||
margin-bottom: -2px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
button.vault {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
border-bottom: solid 2px var(--color-shade-4);
|
||||
}
|
||||
|
||||
button.filter-tag {
|
||||
background: var(--color-secondary);
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
border-bottom: solid 2px #222;
|
||||
}
|
||||
|
||||
button.favorites {
|
||||
background: var(--color-negative);
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
border-bottom: solid 2px var(--color-shade-4);
|
||||
}
|
||||
|
||||
button pl-icon {
|
||||
font-size: 85%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: -6px;
|
||||
}
|
||||
|
||||
.list pl-icon {
|
||||
margin-left: -6px;
|
||||
margin-right: 0;
|
||||
font-size: 80%;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
button > div, .option > div {
|
||||
${mixins.ellipsis()}
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.scrim {
|
||||
z-index: 10;
|
||||
border-top: solid 3px #f2f2f2;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
${mixins.fullbleed()}
|
||||
top: 60px;
|
||||
will-change: opacity;
|
||||
transition: opacity 200ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
:host(:not([selecting])) .scrim {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host(:not([selecting])) .list {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 12px 6px 6px 6px;
|
||||
background: var(--color-tertiary);
|
||||
box-sizing: border-box;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
font-size: var(--font-size-tiny);
|
||||
border-bottom: solid 3px var(--color-shade-1);
|
||||
will-change: transform;
|
||||
transition: transform 200ms cubic-bezier(0.6, 0, 0.2, 1);
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
.list button {
|
||||
margin-bottom: 6px;
|
||||
border-bottom: none;
|
||||
padding: 5px 10px;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 16px 10px 10px 10px;
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.no-tags {
|
||||
font-size: var(--font-size-micro);
|
||||
padding: 5px 10px 15px 10px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<button class="tap ${cl}" @click=${() => (this._selecting = !this._selecting)}>
|
||||
<div>${label}</div>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { setClipboard } from "../clipboard.js";
|
|||
import { app, router } from "../init.js";
|
||||
import { dialog, confirm } from "../dialog.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { element, html, property, query, listen } from "./base.js";
|
||||
import { element, html, css, property, query, listen } from "./base.js";
|
||||
import { View } from "./view.js";
|
||||
import { CreateItemDialog } from "./create-item-dialog.js";
|
||||
import { Input } from "./input.js";
|
||||
|
@ -138,203 +138,204 @@ export class ItemsList extends View {
|
|||
this._resizeHandler();
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
header {
|
||||
overflow: visible;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
pl-items-filter {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
grid-column: 1/-1;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
height: 35px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px 5px 10px;
|
||||
background: var(--color-quaternary);
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: -3px;
|
||||
margin-bottom: -8px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
grid-gap: var(--gutter-size);
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item .tags {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
height: var(--row-height);
|
||||
line-height: var(--row-height);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
padding-left: 15px;
|
||||
${mixins.ellipsis()}
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-fields {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.item-fields::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 8px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.item-field {
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-tiny);
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
margin: 0 0 8px 8px;
|
||||
border-radius: 8px;
|
||||
${mixins.shade2()}
|
||||
}
|
||||
|
||||
.item-field > * {
|
||||
transition: transform 0.2s cubic-bezier(1, -0.3, 0, 1.3), opacity 0.2s;
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
${mixins.fullbleed()}
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.item-field:not(.copied) .copied-message,
|
||||
.item-field.copied .item-field-label {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
font-weight: bold;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-background);
|
||||
}
|
||||
|
||||
.copied-message::before {
|
||||
font-family: "FontAwesome";
|
||||
content: "\\f00c\\ ";
|
||||
}
|
||||
|
||||
.item-field-label {
|
||||
padding: 0 15px;
|
||||
pointer-events: none;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item:focus:not([selected]) {
|
||||
border-color: var(--color-highlight);
|
||||
color: #4ca8d9;
|
||||
}
|
||||
|
||||
.item[selected] {
|
||||
background: #e6e6e6;
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
position: relative;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
box-sizing: border-box;
|
||||
border: solid 3px #eee;
|
||||
background: #eee;
|
||||
border-radius: 30px;
|
||||
margin: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.item-check::after {
|
||||
content: "";
|
||||
display: block;
|
||||
${mixins.fullbleed()}
|
||||
background: var(--color-primary);
|
||||
border-radius: inherit;
|
||||
transition: transform 0.2s, opacity 0.2s;
|
||||
transition-timing-function: cubic-bezier(1, -0.3, 0, 1.3);
|
||||
}
|
||||
|
||||
.item-check:not([checked])::after {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.selected-count {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-left: 12px;
|
||||
background: #eee;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 12px 4px;
|
||||
line-height: 1.2em;
|
||||
font-size: var(--font-size-tiny);
|
||||
font-weight: bold;
|
||||
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 4px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
header {
|
||||
overflow: visible;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
pl-items-filter {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
grid-column: 1/-1;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
height: 35px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px 5px 10px;
|
||||
background: var(--color-quaternary);
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: -3px;
|
||||
margin-bottom: -8px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
grid-gap: var(--gutter-size);
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item .tags {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
height: var(--row-height);
|
||||
line-height: var(--row-height);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
padding-left: 15px;
|
||||
${mixins.ellipsis()}
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-fields {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.item-fields::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 8px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.item-field {
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-tiny);
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
margin: 0 0 8px 8px;
|
||||
border-radius: 8px;
|
||||
${mixins.shade2()}
|
||||
}
|
||||
|
||||
.item-field > * {
|
||||
transition: transform 0.2s cubic-bezier(1, -0.3, 0, 1.3), opacity 0.2s;
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
${mixins.fullbleed()}
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.item-field:not(.copied) .copied-message, .item-field.copied .item-field-label {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
font-weight: bold;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-background);
|
||||
}
|
||||
|
||||
.copied-message::before {
|
||||
font-family: "FontAwesome";
|
||||
content: "\\f00c\\ ";
|
||||
}
|
||||
|
||||
.item-field-label {
|
||||
padding: 0 15px;
|
||||
pointer-events: none;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item:focus:not([selected]) {
|
||||
border-color: var(--color-highlight);
|
||||
color: #4ca8d9;
|
||||
}
|
||||
|
||||
.item[selected] {
|
||||
background: #e6e6e6;
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
position: relative;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
box-sizing: border-box;
|
||||
border: solid 3px #eee;
|
||||
background: #eee;
|
||||
border-radius: 30px;
|
||||
margin: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.item-check::after {
|
||||
content: "";
|
||||
display: block;
|
||||
${mixins.fullbleed()}
|
||||
background: var(--color-primary);
|
||||
border-radius: inherit;
|
||||
transition: transform 0.2s, opacity 0.2s;
|
||||
transition-timing-function: cubic-bezier(1, -0.3, 0, 1.3);
|
||||
}
|
||||
|
||||
.item-check:not([checked])::after {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.selected-count {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-left: 12px;
|
||||
background: #eee;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 12px 4px;
|
||||
line-height: 1.2em;
|
||||
font-size: var(--font-size-tiny);
|
||||
font-weight: bold;
|
||||
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header ?hidden=${this._filterShowing}>
|
||||
<pl-icon icon="menu" class="tap menu-button" @click=${() => this.dispatch("toggle-menu")}></pl-icon>
|
||||
|
||||
|
@ -537,11 +538,17 @@ export class ItemsList extends View {
|
|||
@click=${() => this.selectItem(item)}
|
||||
index="${index}"
|
||||
>
|
||||
<div
|
||||
class="item-check"
|
||||
?hidden=${!this.multiSelect}
|
||||
?checked=${this._multiSelect.has(item.item.id)}
|
||||
></div>
|
||||
${cache(
|
||||
this.multiSelect
|
||||
? html`
|
||||
<div
|
||||
class="item-check"
|
||||
?hidden=${!this.multiSelect}
|
||||
?checked=${this._multiSelect.has(item.item.id)}
|
||||
></div>
|
||||
`
|
||||
: ""
|
||||
)}
|
||||
|
||||
<div class="item-body">
|
||||
<div class="item-header">
|
||||
|
@ -567,17 +574,25 @@ export class ItemsList extends View {
|
|||
<div class="item-fields">
|
||||
${item.item.fields.map(
|
||||
(f: Field, i: number) => html`
|
||||
<div class="item-field" @click=${(e: MouseEvent) => this._copyField(item.item, i, e)}>
|
||||
<div
|
||||
class="item-field tap"
|
||||
@click=${(e: MouseEvent) => this._copyField(item.item, i, e)}
|
||||
>
|
||||
<div class="item-field-label">${f.name}</div>
|
||||
|
||||
<div class="copied-message">${$l("copied")}</div>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
|
||||
<div class="item-field" disabled ?hidden=${!!item.item.fields.length}>
|
||||
${$l("No Fields")}
|
||||
</div>
|
||||
${cache(
|
||||
!item.item.fields.length
|
||||
? html`
|
||||
<div class="item-field" disabled ?hidden=${!!item.item.fields.length}>
|
||||
${$l("No Fields")}
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import "@polymer/paper-spinner/paper-spinner-lite.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, html, property, listen } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, listen } from "./base.js";
|
||||
import "./icon.js";
|
||||
|
||||
type ButtonState = "idle" | "loading" | "success" | "fail";
|
||||
|
@ -14,64 +14,66 @@ export class LoadingButton extends BaseElement {
|
|||
|
||||
private _stopTimeout: number;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
height: var(--row-height);
|
||||
}
|
||||
|
||||
:host([state="loading"]) button {
|
||||
cursor: progress;
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
button > * {
|
||||
transition: transform 0.2s cubic-bezier(1, -0.3, 0, 1.3), opacity 0.2s;
|
||||
${mixins.absoluteCenter()}
|
||||
}
|
||||
|
||||
button > .label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
:host(.vertical) .label {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
button.loading .label,
|
||||
button.success .label,
|
||||
button.fail .label,
|
||||
button:not(.loading) .spinner,
|
||||
button:not(.success) .icon-success,
|
||||
button:not(.fail) .icon-fail {
|
||||
opacity: 0.5;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
button pl-icon {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
paper-spinner-lite {
|
||||
line-height: normal;
|
||||
--paper-spinner-color: currentColor;
|
||||
--paper-spinner-stroke-width: 2px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { state, noTab } = this;
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
height: var(--row-height);
|
||||
}
|
||||
|
||||
:host([state="loading"]) button {
|
||||
cursor: progress;
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
button > * {
|
||||
transition: transform 0.2s cubic-bezier(1, -0.3, 0, 1.3), opacity 0.2s;
|
||||
${mixins.absoluteCenter()}
|
||||
}
|
||||
|
||||
button > .label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
:host(.vertical) .label {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
button.loading .label, button.success .label, button.fail .label,
|
||||
button:not(.loading) .spinner,
|
||||
button:not(.success) .icon-success,
|
||||
button:not(.fail) .icon-fail {
|
||||
opacity: 0.5;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
button pl-icon {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
paper-spinner-lite {
|
||||
line-height: normal;
|
||||
--paper-spinner-color: currentColor;
|
||||
--paper-spinner-stroke-width: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<button type="button" class="${state}" tabindex="${noTab ? "-1" : ""}">
|
||||
<div class="label"><slot></slot></div>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { ErrorCode } from "@padloc/core/lib/error.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { StartForm, sharedStyles } from "./start-form.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { StartForm } from "./start-form.js";
|
||||
import { Input } from "./input.js";
|
||||
import { PasswordInput } from "./password-input.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
|
@ -35,29 +35,30 @@ export class Login extends StartForm {
|
|||
super.reset();
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...StartForm.styles,
|
||||
css`
|
||||
.hint {
|
||||
font-size: var(--font-size-tiny);
|
||||
box-sizing: border-box;
|
||||
transition: max-height 0.3s;
|
||||
max-height: 100px;
|
||||
margin: 40px 0 -20px 0;
|
||||
}
|
||||
|
||||
button.signup {
|
||||
background: none;
|
||||
border: none;
|
||||
height: auto;
|
||||
line-height: normal;
|
||||
font-weight: bold;
|
||||
height: var(--row-height);
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${sharedStyles}
|
||||
|
||||
<style>
|
||||
.hint {
|
||||
font-size: var(--font-size-tiny);
|
||||
box-sizing: border-box;
|
||||
transition: max-height 0.3s;
|
||||
max-height: 100px;
|
||||
margin: 40px 0 -20px 0;
|
||||
}
|
||||
|
||||
button.signup {
|
||||
background: none;
|
||||
border: none;
|
||||
height: auto;
|
||||
line-height: normal;
|
||||
font-weight: bold;
|
||||
height: var(--row-height);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div flex></div>
|
||||
|
||||
<form>
|
||||
|
|
|
@ -1,11 +1,75 @@
|
|||
import { svg } from "lit-html";
|
||||
import { BaseElement, element, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, svg, property } from "./base.js";
|
||||
|
||||
@element("pl-logo")
|
||||
export class Logo extends BaseElement {
|
||||
@property({ reflect: true })
|
||||
reveal: boolean = false;
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
:host {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 200px;
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
:host([reveal]) .padloc > * {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 7;
|
||||
}
|
||||
|
||||
.padloc > * {
|
||||
transition: stroke-dashoffset 1.4s cubic-bezier(0.57, 0.25, 0, 0.99);
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
.p {
|
||||
stroke-dashoffset: 234px;
|
||||
stroke-dasharray: 234px;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
.a {
|
||||
stroke-dashoffset: 190px;
|
||||
stroke-dasharray: 190px;
|
||||
transition-delay: 0.1s;
|
||||
}
|
||||
|
||||
.d {
|
||||
stroke-dashoffset: 232px;
|
||||
stroke-dasharray: 232px;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.l {
|
||||
stroke-dashoffset: 155px;
|
||||
stroke-dasharray: 155px;
|
||||
transition-delay: 0.3s;
|
||||
}
|
||||
|
||||
.o {
|
||||
stroke-dashoffset: 168px;
|
||||
stroke-dasharray: 168px;
|
||||
transition-delay: 0.4s;
|
||||
}
|
||||
|
||||
.c {
|
||||
stroke-dashoffset: 237px;
|
||||
stroke-dasharray: 237px;
|
||||
transition-delay: 0.5s;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
_logo() {
|
||||
return svg`
|
||||
<svg viewBox="0 -12 380 120" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
@ -53,69 +117,6 @@ export class Logo extends BaseElement {
|
|||
}
|
||||
render() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 200px;
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
:host([reveal]) .padloc > * {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 7;
|
||||
}
|
||||
|
||||
.padloc > * {
|
||||
transition: stroke-dashoffset 1.4s cubic-bezier(0.57, 0.25, 0, 0.99);
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
.p {
|
||||
stroke-dashoffset: 234px;
|
||||
stroke-dasharray: 234px;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
.a {
|
||||
stroke-dashoffset: 190px;
|
||||
stroke-dasharray: 190px;
|
||||
transition-delay: 0.1s;
|
||||
}
|
||||
|
||||
.d {
|
||||
stroke-dashoffset: 232px;
|
||||
stroke-dasharray: 232px;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.l {
|
||||
stroke-dashoffset: 155px;
|
||||
stroke-dasharray: 155px;
|
||||
transition-delay: 0.3s;
|
||||
}
|
||||
|
||||
.o {
|
||||
stroke-dashoffset: 168px;
|
||||
stroke-dasharray: 168px;
|
||||
transition-delay: 0.4s;
|
||||
}
|
||||
|
||||
.c {
|
||||
stroke-dashoffset: 237px;
|
||||
stroke-dasharray: 237px;
|
||||
transition-delay: 0.5s;
|
||||
}
|
||||
</style>
|
||||
|
||||
${this._logo()}
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { localize as $l } from "@padloc/core/lib/locale.js";
|
|||
import { mixins } from "../styles";
|
||||
import { app } from "../init.js";
|
||||
import { confirm, choose } from "../dialog.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import "./icon.js";
|
||||
|
@ -288,6 +288,53 @@ export class MemberDialog extends Dialog<InputType, void> {
|
|||
return !!this.org && !!this.member;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
pl-toggle-button {
|
||||
display: block;
|
||||
padding: 0 15px 0 0;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
font-size: var(--font-size-small);
|
||||
align-self: flex-start;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin: 8px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 0 8px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.subheader .permission {
|
||||
width: 50px;
|
||||
font-size: var(--font-size-tiny);
|
||||
text-align: center;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item pl-toggle {
|
||||
margin-right: 14px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const org = this.org!;
|
||||
const member = this.member!;
|
||||
|
@ -296,50 +343,6 @@ export class MemberDialog extends Dialog<InputType, void> {
|
|||
const memberIsOwner = org.isOwner(member);
|
||||
|
||||
return html`
|
||||
<style>
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
pl-toggle-button {
|
||||
display: block;
|
||||
padding: 0 15px 0 0;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
font-size: var(--font-size-small);
|
||||
align-self: flex-start;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin: 8px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 0 8px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.subheader .permission {
|
||||
width: 50px;
|
||||
font-size: var(--font-size-tiny);
|
||||
text-align: center;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item pl-toggle {
|
||||
margin-right: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<pl-member-item .member=${member} class="flex"></pl-member-item>
|
||||
<pl-icon
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { OrgMember, OrgRole } from "@padloc/core/lib/org.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { shared } from "../styles";
|
||||
import { BaseElement, element, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, property } from "./base.js";
|
||||
import "./fingerprint.js";
|
||||
|
||||
@element("pl-member-item")
|
||||
|
@ -12,55 +12,56 @@ export class MemberItem extends BaseElement {
|
|||
@property()
|
||||
hideRole: boolean = false;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
pl-fingerprint {
|
||||
color: var(--color-secondary);
|
||||
--color-background: var(--color-tertiary);
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border-radius: 100%;
|
||||
border: solid 1px var(--border-color);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.member-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.name-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.name-wrapper > .tags {
|
||||
margin: 0 0 0 4px;
|
||||
}
|
||||
|
||||
.member-name {
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.member-email {
|
||||
font-size: 90%;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const isAdmin = this.member.role === OrgRole.Admin;
|
||||
const isOwner = this.member.role === OrgRole.Owner;
|
||||
const isSuspended = this.member.role === OrgRole.Suspended;
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
pl-fingerprint {
|
||||
color: var(--color-secondary);
|
||||
--color-background: var(--color-tertiary);
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border-radius: 100%;
|
||||
border: solid 1px var(--border-color);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.member-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.name-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.name-wrapper > .tags {
|
||||
margin: 0 0 0 4px;
|
||||
}
|
||||
|
||||
.member-name {
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.member-email {
|
||||
font-size: 90%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<pl-fingerprint .key=${this.member.publicKey}></pl-fingerprint>
|
||||
|
||||
<div class="member-info">
|
||||
|
|
|
@ -3,7 +3,7 @@ import { FilterParams } from "@padloc/core/lib/app.js";
|
|||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, property, html, listen } from "./base.js";
|
||||
import { BaseElement, element, property, html, css, listen } from "./base.js";
|
||||
import "./logo.js";
|
||||
|
||||
@element("pl-menu")
|
||||
|
@ -30,104 +30,107 @@ export class Menu extends BaseElement {
|
|||
router.go(path);
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--color-tertiary);
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.scroller {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
${mixins.scroll()}
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
li {
|
||||
background: transparent;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
margin: 2px 10px;
|
||||
padding-right: 10px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
li:not([selected]):hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
li[selected] {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
li div {
|
||||
flex: 1;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 100%;
|
||||
margin-top: 30px;
|
||||
padding: 0 20px;
|
||||
opacity: 0.8;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.vault,
|
||||
.menu-tag {
|
||||
height: 35px;
|
||||
font-size: var(--font-size-tiny);
|
||||
}
|
||||
|
||||
.vault pl-icon,
|
||||
.menu-tag pl-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
pl-logo {
|
||||
height: 30px;
|
||||
margin: 15px 0 20px 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.no-tags {
|
||||
font-size: var(--font-size-micro);
|
||||
padding: 0 20px;
|
||||
opacity: 0.5;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer pl-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: var(--font-size-tiny);
|
||||
}
|
||||
|
||||
.syncing {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 5px;
|
||||
--paper-spinner-color: currentColor;
|
||||
--paper-spinner-stroke-width: 2px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--color-tertiary);
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.scroller {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
${mixins.scroll()}
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
li {
|
||||
background: transparent;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
margin: 2px 10px;
|
||||
padding-right: 10px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
li:not([selected]):hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
li[selected] {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
li div {
|
||||
flex: 1;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 100%;
|
||||
margin-top: 30px;
|
||||
padding: 0 20px;
|
||||
opacity: 0.8;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.vault, .menu-tag {
|
||||
height: 35px;
|
||||
font-size: var(--font-size-tiny);
|
||||
}
|
||||
|
||||
.vault pl-icon, .menu-tag pl-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
pl-logo {
|
||||
height: 30px;
|
||||
margin: 15px 0 20px 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.no-tags {
|
||||
font-size: var(--font-size-micro);
|
||||
padding: 0 20px;
|
||||
opacity: 0.5;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer pl-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: var(--font-size-tiny);
|
||||
}
|
||||
|
||||
.syncing {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 5px;
|
||||
--paper-spinner-color: currentColor;
|
||||
--paper-spinner-stroke-width: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="scroller">
|
||||
<pl-logo reveal></pl-logo>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Vault } from "@padloc/core/lib/vault.js";
|
|||
import { VaultItem } from "@padloc/core/lib/item.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { app } from "../init.js";
|
||||
import { element, property, html, query } from "./base.js";
|
||||
import { element, property, html, css, query } from "./base.js";
|
||||
import { Select } from "./select.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
|
||||
|
@ -16,34 +16,37 @@ export class MoveItemsDialog extends Dialog<{ vault: Vault; item: VaultItem }[],
|
|||
@query("#vaultSelect")
|
||||
private _vaultSelect: Select<Vault>;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
pl-input,
|
||||
pl-select {
|
||||
text-align: center;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin: 12px;
|
||||
grid-gap: 12px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const itemsDescription =
|
||||
this.items.length === 1 ? `'${this.items[0].item.name}'` : $l("{0} Items", this.items.length.toString());
|
||||
|
||||
return html`
|
||||
<style>
|
||||
pl-input,
|
||||
pl-select {
|
||||
text-align: center;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin: 12px;
|
||||
grid-gap: 12px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>${$l("Move {0} To", itemsDescription)}</h1>
|
||||
|
||||
<div class="message" ?hidden=${this.vaults.length}>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { getSingleton } from "../singleton.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, property } from "./base.js";
|
||||
|
||||
export type NotificationType = "info" | "warning";
|
||||
|
||||
|
@ -21,50 +21,50 @@ export class Notification extends BaseElement {
|
|||
|
||||
private _hideTimeout: number;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
transition: transform 0.5s cubic-bezier(1, -0.3, 0, 1.3);
|
||||
position: fixed;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
z-index: 10;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--color-background);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
${mixins.gradientDark(true)}
|
||||
}
|
||||
|
||||
:host(:not(.showing)) {
|
||||
transform: translateY(130%);
|
||||
}
|
||||
|
||||
:host([type="warning"]) {
|
||||
${mixins.gradientWarning(true)}
|
||||
}
|
||||
|
||||
.message {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 15px 0 15px 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pl-icon.close-button {
|
||||
margin: auto 5px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
transition: transform 0.5s cubic-bezier(1, -0.3, 0, 1.3);
|
||||
position: fixed;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
z-index: 10;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--color-background);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
${mixins.gradientDark(true)}
|
||||
}
|
||||
|
||||
:host(:not(.showing)) {
|
||||
transform: translateY(130%);
|
||||
}
|
||||
|
||||
:host([type="warning"]) {
|
||||
${mixins.gradientWarning(true)}
|
||||
}
|
||||
|
||||
.message {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 15px 0 15px 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pl-icon.close-button {
|
||||
margin: auto 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="message">${this.message}</div>
|
||||
|
||||
<pl-icon icon="close" class="close-button tap" @click=${() => this.dismiss()}></pl-icon>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { OrgMember, OrgRole, Group } from "@padloc/core/lib/org.js";
|
|||
import { shared, mixins } from "../styles";
|
||||
import { dialog, prompt, choose, confirm } from "../dialog.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { element, html, property, query, observe } from "./base.js";
|
||||
import { element, html, css, property, query, observe } from "./base.js";
|
||||
import { View } from "./view.js";
|
||||
import { Input } from "./input.js";
|
||||
import { VaultDialog } from "./vault-dialog.js";
|
||||
|
@ -146,6 +146,69 @@ export class OrgView extends View {
|
|||
return !!this._org;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.subview {
|
||||
position: relative;
|
||||
${mixins.fullbleed()}
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
header {
|
||||
display: block;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header-inner .title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header > .tabs {
|
||||
margin: -10px;
|
||||
}
|
||||
|
||||
.tabs .spacer {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.new-button {
|
||||
display: flex;
|
||||
font-weight: bold;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.new-button > pl-icon {
|
||||
font-size: 80%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const org = this._org!;
|
||||
const isOwner = org.isOwner(app.account!);
|
||||
|
@ -160,49 +223,6 @@ export class OrgView extends View {
|
|||
: org.members;
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.subview {
|
||||
position: relative;
|
||||
${mixins.fullbleed()}
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
header {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header-inner .title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tabs .spacer {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<div class="header-inner narrow">
|
||||
<pl-icon class="tap menu-button" icon="menu" @click=${() => this.dispatch("toggle-menu")}></pl-icon>
|
||||
|
@ -250,6 +270,14 @@ export class OrgView extends View {
|
|||
<pl-icon icon="cancel" class="tap" @click=${this._clearMembersFilter}></pl-icon>
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="new-button tap"
|
||||
@click=${this._createInvite}
|
||||
?hidden=${!isOwner || members.length < 50}
|
||||
>
|
||||
<pl-icon icon="invite"></pl-icon>
|
||||
<div>${$l("Invite New Member")}</div>
|
||||
</li>
|
||||
${members.map(
|
||||
member => html`
|
||||
<li class="tap member" @click=${() => this._showMember(member)}>
|
||||
|
@ -257,8 +285,8 @@ export class OrgView extends View {
|
|||
</li>
|
||||
`
|
||||
)}
|
||||
<li class="centering padded tap" @click=${this._createInvite} ?hidden=${!isOwner}>
|
||||
<pl-icon icon="invite"></pl-icon>
|
||||
<li class="new-button tap" @click=${this._createInvite} ?hidden=${!isOwner}>
|
||||
<pl-icon icon="add"></pl-icon>
|
||||
<div>${$l("Invite New Member")}</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -273,7 +301,7 @@ export class OrgView extends View {
|
|||
</li>
|
||||
`
|
||||
)}
|
||||
<li class="centering padded tap" @click=${this._createGroup} ?hidden=${!isOwner}>
|
||||
<li class="new-button tap" @click=${this._createGroup} ?hidden=${!isOwner}>
|
||||
<pl-icon icon="add"></pl-icon>
|
||||
<div>${$l("New Group")}</div>
|
||||
</li>
|
||||
|
@ -289,7 +317,7 @@ export class OrgView extends View {
|
|||
</li>
|
||||
`
|
||||
)}
|
||||
<li class="centering padded tap" @click=${this._createVault}>
|
||||
<li class="new-button tap" @click=${this._createVault}>
|
||||
<pl-icon icon="add"></pl-icon>
|
||||
<div>${$l("New Vault")}</div>
|
||||
</li>
|
||||
|
@ -305,18 +333,12 @@ export class OrgView extends View {
|
|||
</li>
|
||||
`
|
||||
)}
|
||||
<li class="centering padded tap" @click=${this._createInvite}>
|
||||
<pl-icon icon="invite"></pl-icon>
|
||||
<li class="new-button tap" @click=${this._createInvite}>
|
||||
<pl-icon icon="add"></pl-icon>
|
||||
<div>${$l("Invite New Member")}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="fabs" ?hidden=${!isOwner}>
|
||||
<div class="flex"></div>
|
||||
|
||||
<pl-icon icon="invite" class="tap fab" @click=${() => this._createInvite()}></pl-icon>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
`;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { element, html } from "./base.js";
|
||||
import { element, html, css } from "./base.js";
|
||||
import { Input } from "./input.js";
|
||||
import "./icon.js";
|
||||
|
||||
|
@ -9,47 +9,36 @@ export class PasswordInput extends Input {
|
|||
this.type = "password";
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...Input.styles,
|
||||
css`
|
||||
input {
|
||||
font-size: 120%;
|
||||
font-family: var(--font-family-mono);
|
||||
}
|
||||
|
||||
.mask-icon {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
opacity: 0.8;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${super.render()}
|
||||
|
||||
<style>
|
||||
/*
|
||||
:host {
|
||||
padding: 5px 10px !important;
|
||||
}
|
||||
|
||||
label {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
label[float] {
|
||||
transform: scale(0.8) translate(0, -38px);
|
||||
}
|
||||
*/
|
||||
|
||||
input {
|
||||
font-size: 120%;
|
||||
font-family: var(--font-family-mono);
|
||||
}
|
||||
|
||||
.mask-icon {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
<pl-icon
|
||||
icon="${this.type === "password" ? "show" : "hide"}"
|
||||
class="mask-icon tap"
|
||||
@click=${this._toggleMasked}>
|
||||
@click=${this._toggleMasked}
|
||||
>
|
||||
</pl-icon>
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { localize } from "@padloc/core/lib/locale.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { Input } from "./input.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
|
@ -50,35 +50,38 @@ export class PromptDialog extends Dialog<PromptOptions, string | null> {
|
|||
@query("pl-input")
|
||||
private _input: Input;
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
pl-input {
|
||||
text-align: center;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
position: relative;
|
||||
margin-top: 15px;
|
||||
font-weight: bold;
|
||||
font-size: var(--font-size-small);
|
||||
color: var(--color-error);
|
||||
text-shadow: none;
|
||||
text-align: center;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
return html`
|
||||
<style>
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
pl-input {
|
||||
text-align: center;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
position: relative;
|
||||
margin-top: 15px;
|
||||
font-weight: bold;
|
||||
font-size: var(--font-size-small);
|
||||
color: var(--color-error);
|
||||
text-shadow: none;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1 ?hidden=${!this.title}>${this.title}</h1>
|
||||
|
||||
<div class="message" ?hidden=${!this.message}>${this.message}</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { StartForm, sharedStyles } from "./start-form.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { StartForm } from "./start-form.js";
|
||||
import { Input } from "./input.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import { alert, choose, prompt } from "../dialog.js";
|
||||
|
@ -33,52 +33,53 @@ export class Recover extends StartForm {
|
|||
super.reset();
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...StartForm.styles,
|
||||
css`
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 300px;
|
||||
margin: 30px auto;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#submitButton {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.recovery-notes {
|
||||
text-align: left;
|
||||
padding: 20px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.recovery-notes ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
.recovery-notes li {
|
||||
margin: 10px 20px 0 20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${sharedStyles}
|
||||
|
||||
<style include="shared">
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 300px;
|
||||
margin: 30px auto;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#submitButton {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.recovery-notes {
|
||||
text-align: left;
|
||||
padding: 20px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.recovery-notes ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
.recovery-notes li {
|
||||
margin: 10px 20px 0 20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div flex></div>
|
||||
|
||||
<form>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { shared } from "../styles";
|
||||
import { BaseElement, element, html, property, query, observe } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, query, observe } from "./base.js";
|
||||
|
||||
@element("pl-select")
|
||||
export class Select<T> extends BaseElement {
|
||||
|
@ -13,66 +13,67 @@ export class Select<T> extends BaseElement {
|
|||
@query("select")
|
||||
private _select: HTMLSelectElement;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
height: var(--row-height);
|
||||
padding: 0 15px;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: var(--color-tertiary);
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 13px;
|
||||
opacity: 0.5;
|
||||
transition: transform 0.2s, color 0.2s, opacity 0.5s;
|
||||
cursor: text;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
label[float] {
|
||||
transform: scale(0.8) translate(0, -32px);
|
||||
color: var(--color-highlight);
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
pl-icon {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: 0;
|
||||
right: 5px;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { options, selected, label } = this;
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
height: var(--row-height);
|
||||
padding: 0 15px;
|
||||
background: var(--shade-2-color);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: var(--color-tertiary);
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 13px;
|
||||
opacity: 0.5;
|
||||
transition: transform 0.2s, color 0.2s, opacity 0.5s;
|
||||
cursor: text;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
label[float] {
|
||||
transform: scale(0.8) translate(0, -32px);
|
||||
color: var(--color-highlight);
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
pl-icon {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: 0;
|
||||
right: 5px;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<select id="selectEl" .selectedIndex=${options.indexOf(selected)} @change=${() => this._changed()}>
|
||||
${options.map(
|
||||
o => html`
|
||||
|
|
|
@ -2,7 +2,7 @@ import { localize as $l } from "@padloc/core/lib/locale.js";
|
|||
import { shared, mixins } from "../styles";
|
||||
import { alert, confirm, prompt, dialog } from "../dialog";
|
||||
import { app } from "../init.js";
|
||||
import { element, html, query, listen } from "./base.js";
|
||||
import { element, html, css, query, listen } from "./base.js";
|
||||
import { View } from "./view.js";
|
||||
import "./icon.js";
|
||||
import { Slider } from "./slider.js";
|
||||
|
@ -32,79 +32,80 @@ export class Settings extends View {
|
|||
return !!app.account;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
${mixins.fullbleed()}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
padding: 0 8px 8px 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.account {
|
||||
font-size: 110%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
pl-fingerprint {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 100%;
|
||||
border: solid 1px var(--border-color);
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.account-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.account-email {
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.account-email {
|
||||
font-weight: bold;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.account pl-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { settings } = app;
|
||||
const account = app.account!;
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
${mixins.fullbleed()}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
padding: 0 8px 8px 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.account {
|
||||
font-size: 110%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
pl-fingerprint {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 100%;
|
||||
border: solid 1px var(--border-color);
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.account-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.account-email {
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.account-email {
|
||||
font-weight: bold;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.account pl-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header class="narrow">
|
||||
<pl-icon class="tap menu-button" icon="menu" @click=${() => this.dispatch("toggle-menu")}></pl-icon>
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ import { generatePassphrase } from "@padloc/core/lib/diceware.js";
|
|||
import { isTouch } from "@padloc/core/lib/platform.js";
|
||||
import { passwordStrength } from "../util.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { StartForm, sharedStyles } from "./start-form.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { StartForm } from "./start-form.js";
|
||||
import { Input } from "./input.js";
|
||||
import { PasswordInput } from "./password-input.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
|
@ -92,88 +92,89 @@ export class Signup extends StartForm {
|
|||
this._step = step;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...StartForm.styles,
|
||||
css`
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.master-password-form {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 300px;
|
||||
margin: 30px auto;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#submitButton {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
pl-input:not([focused]) + .hint {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.master-password {
|
||||
position: relative;
|
||||
background: var(--shade-2-color);
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: 120%;
|
||||
padding: 20px 40px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.master-password-cover {
|
||||
${mixins.fullbleed()}
|
||||
height: 1em;
|
||||
margin: auto;
|
||||
font-weight: bold;
|
||||
text-shadow: none;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.master-password-edit {
|
||||
font-size: 80%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
vertical-align: middle;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 1;
|
||||
text-shadow: none;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.master-password:hover {
|
||||
background: var(--shade-3-color);
|
||||
}
|
||||
|
||||
.master-password:not(:hover) .master-password-value,
|
||||
.master-password:not(:hover) .master-password-edit,
|
||||
.master-password:hover .master-password-cover {
|
||||
opacity: 0;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${sharedStyles}
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.master-password-form {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 300px;
|
||||
margin: 30px auto;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#submitButton {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
pl-input:not([focused]) + .hint {
|
||||
color: rgba(0, 0, 0, 0.2)
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.master-password {
|
||||
position: relative;
|
||||
background: var(--shade-2-color);
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: 120%;
|
||||
padding: 20px 40px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.master-password-cover {
|
||||
${mixins.fullbleed()}
|
||||
height: 1em;
|
||||
margin: auto;
|
||||
font-weight: bold;
|
||||
text-shadow: none;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.master-password-edit {
|
||||
font-size: 80%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
vertical-align: middle;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 1;
|
||||
text-shadow: none;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.master-password:hover {
|
||||
background: var(--shade-3-color);
|
||||
}
|
||||
|
||||
.master-password:not(:hover) .master-password-value,
|
||||
.master-password:not(:hover) .master-password-edit,
|
||||
.master-password:hover .master-password-cover {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="wrapper" hidden>
|
||||
<div flex></div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BaseElement, element, html, property, query } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, query } from "./base.js";
|
||||
import { shared } from "../styles";
|
||||
|
||||
@element("pl-slider")
|
||||
|
@ -13,12 +13,9 @@ export class Slider extends BaseElement {
|
|||
|
||||
@query("input") private _input: HTMLInputElement;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style include="shared">
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -31,7 +28,7 @@ export class Slider extends BaseElement {
|
|||
--knob-size: var(--slider-knob-size, 25px);
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
@ -41,11 +38,11 @@ export class Slider extends BaseElement {
|
|||
min-height: var(--knob-size);
|
||||
}
|
||||
|
||||
input[type=range]:focus {
|
||||
input[type="range"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-runnable-track {
|
||||
input[type="range"]::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: var(--track-size);
|
||||
cursor: pointer;
|
||||
|
@ -53,7 +50,7 @@ export class Slider extends BaseElement {
|
|||
border-radius: 100%;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
height: var(--knob-size);
|
||||
width: var(--knob-size);
|
||||
|
@ -67,7 +64,7 @@ export class Slider extends BaseElement {
|
|||
background-clip: content-box;
|
||||
}
|
||||
|
||||
input[type=range]:active::-webkit-slider-thumb {
|
||||
input[type="range"]:active::-webkit-slider-thumb {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
|
@ -82,21 +79,24 @@ export class Slider extends BaseElement {
|
|||
.value-display {
|
||||
margin-left: 10px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
</style>
|
||||
render() {
|
||||
return html`
|
||||
<label>${this.label}</label>
|
||||
|
||||
<label>${this.label}</label>
|
||||
<input
|
||||
type="range"
|
||||
.value=${this.value}
|
||||
.min=${this.min}
|
||||
.max=${this.max}
|
||||
.step=${this.step}
|
||||
@input=${() => this._inputChange()}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="range"
|
||||
.value=${this.value}
|
||||
.min=${this.min}
|
||||
.max=${this.max}
|
||||
.step=${this.step}
|
||||
@input=${() => this._inputChange()}>
|
||||
|
||||
<span class="value-display" ?hidden=${this.hideValue}>${this.value}${this.unit}</span>
|
||||
`;
|
||||
<span class="value-display" ?hidden=${this.hideValue}>${this.value}${this.unit}</span>
|
||||
`;
|
||||
}
|
||||
|
||||
private _inputChange() {
|
||||
|
|
|
@ -1,68 +1,75 @@
|
|||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, html, query } from "./base.js";
|
||||
import { mixins, shared } from "../styles";
|
||||
import { BaseElement, css, query } from "./base.js";
|
||||
import { animateElement, animateCascade } from "../animation.js";
|
||||
import { Logo } from "./logo.js";
|
||||
import "./icon.js";
|
||||
|
||||
export const sharedStyles = html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
@keyframes reveal {
|
||||
from { transform: translate(0, 30px); opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
const styles = css`
|
||||
@keyframes reveal {
|
||||
from {
|
||||
transform: translate(0, 30px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
to { transform: translate(0, -200px); opacity: 0; }
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
:host, .wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
${mixins.fullbleed()}
|
||||
${mixins.scroll()}
|
||||
@keyframes fade {
|
||||
to {
|
||||
transform: translate(0, -200px);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
:host,
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
${mixins.fullbleed()}
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
form > * {
|
||||
border-radius: 8px;
|
||||
margin: 10px;
|
||||
}
|
||||
form {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
pl-logo {
|
||||
margin: 20px auto;
|
||||
}
|
||||
form > * {
|
||||
border-radius: 8px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
pl-loading-button {
|
||||
overflow: hidden;
|
||||
font-weight: bold;
|
||||
}
|
||||
pl-logo {
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: var(--font-size-small);
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 30px;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
pl-loading-button {
|
||||
overflow: hidden;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hint.warning {
|
||||
color: #ffc107;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-shadow: none;
|
||||
}
|
||||
</style>
|
||||
.hint {
|
||||
font-size: var(--font-size-small);
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 30px;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.hint.warning {
|
||||
color: #ffc107;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-shadow: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export abstract class StartForm extends BaseElement {
|
||||
static styles = [shared, styles];
|
||||
|
||||
@query("pl-logo")
|
||||
_logo: Logo;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { app } from "../init.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, html, property, listen, query } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, listen, query } from "./base.js";
|
||||
import { Unlock } from "./unlock.js";
|
||||
import { Login } from "./login.js";
|
||||
import { Signup } from "./signup.js";
|
||||
|
@ -59,55 +59,55 @@ export class Start extends BaseElement {
|
|||
}
|
||||
}
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
--color-background: var(--color-primary);
|
||||
--color-foreground: var(--color-tertiary);
|
||||
--color-highlight: var(--color-secondary);
|
||||
color: var(--color-foreground);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 5;
|
||||
text-align: center;
|
||||
text-shadow: rgba(0, 0, 0, 0.15) 0 2px 0;
|
||||
background: linear-gradient(180deg, #59c6ff 0%, #077cb9 100%);
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: transform 0.4s cubic-bezier(1, 0, 0.2, 1);
|
||||
${mixins.fullbleed()}
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
main {
|
||||
${mixins.fullbleed()}
|
||||
background: transparent;
|
||||
min-height: 510px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.form:not(.showing) {
|
||||
opacity: 0;
|
||||
transition: opacity 1s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
transition-delay: 0.4s;
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
--color-background: var(--color-primary);
|
||||
--color-foreground: var(--color-tertiary);
|
||||
--color-highlight: var(--color-secondary);
|
||||
color: var(--color-foreground);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 5;
|
||||
text-align: center;
|
||||
text-shadow: rgba(0, 0, 0, 0.15) 0 2px 0;
|
||||
background: linear-gradient(180deg, #59c6ff 0%, #077cb9 100%);
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: transform 0.4s cubic-bezier(1, 0, 0.2, 1);
|
||||
${mixins.fullbleed()}
|
||||
${mixins.scroll()}
|
||||
}
|
||||
|
||||
main {
|
||||
${mixins.fullbleed()}
|
||||
background: transparent;
|
||||
min-height: 510px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.form:not(.showing) {
|
||||
opacity: 0;
|
||||
transition: opacity 1s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host([open]) {
|
||||
transition-delay: 0.4s;
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
</style>
|
||||
|
||||
<pl-unlock class="form"></pl-unlock>
|
||||
|
||||
<pl-login class="form"></pl-login>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Vault } from "@padloc/core/lib/vault.js";
|
|||
import { Tag } from "@padloc/core/lib/item.js";
|
||||
import { app } from "../init.js";
|
||||
import { shared } from "../styles";
|
||||
import { BaseElement, element, html, property, query } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, query } from "./base.js";
|
||||
import { Input } from "./input";
|
||||
import "./icon.js";
|
||||
|
||||
|
@ -23,6 +23,82 @@ export class TagsInput extends BaseElement {
|
|||
|
||||
private _focusTimeout: number = 0;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: visible;
|
||||
font-size: var(--font-size-small);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
flex-wrap: wrap;
|
||||
overflow: visible;
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
||||
.wrapper > * {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.tags.small .tag {
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
.results {
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
margin-top: 0;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.results .tag {
|
||||
padding: 6px 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
font-size: var(--font-size-micro);
|
||||
padding: 0 4px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
background: #eee;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
align-self: stretch;
|
||||
position: relative;
|
||||
min-width: 80px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.input-wrapper pl-input {
|
||||
font-size: inherit;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-left: 20px;
|
||||
top: 0;
|
||||
font-weight: bold;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.add-tag {
|
||||
height: 26px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.add-tag .input-wrapper pl-icon {
|
||||
height: 25px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { tags, editing, vault, _showResults } = this;
|
||||
const { value } = this._input || { value: "" };
|
||||
|
@ -34,81 +110,6 @@ export class TagsInput extends BaseElement {
|
|||
}
|
||||
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: visible;
|
||||
font-size: var(--font-size-small);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
flex-wrap: wrap;
|
||||
overflow: visible;
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
||||
.wrapper > * {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.tags.small .tag {
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
.results {
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
margin-top: 0;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.results .tag {
|
||||
padding: 6px 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
font-size: var(--font-size-micro);
|
||||
padding: 0 4px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
background: #eee;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
align-self: stretch;
|
||||
position: relative;
|
||||
min-width: 80px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.input-wrapper pl-input {
|
||||
font-size: inherit;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-left: 20px;
|
||||
top: 0;
|
||||
font-weight: bold;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.add-tag {
|
||||
height: 26px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.add-tag .input-wrapper pl-icon {
|
||||
height: 25px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="tags small wrapper">
|
||||
<div class="tag highlight tap" @click=${() => this._vaultClicked()}>
|
||||
<pl-icon icon="vault"></pl-icon>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, html, property, query } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, query } from "./base.js";
|
||||
import { Toggle } from "./toggle.js";
|
||||
|
||||
@element("pl-toggle-button")
|
||||
|
@ -14,13 +14,9 @@ export class ToggleButton extends BaseElement {
|
|||
@query("pl-toggle")
|
||||
_toggle: Toggle;
|
||||
|
||||
render() {
|
||||
const { active, label } = this;
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: inline-block;
|
||||
font-size: inherit;
|
||||
|
@ -59,8 +55,12 @@ export class ToggleButton extends BaseElement {
|
|||
display: inline-block;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const { active, label } = this;
|
||||
return html`
|
||||
<button @click=${() => this.toggle()}>
|
||||
|
||||
<pl-toggle .active=${active} @change=${() => (this.active = this._toggle.active)}"></pl-toggle>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BaseElement, element, html, property, listen } from "./base.js";
|
||||
import { BaseElement, element, html, css, property, listen } from "./base.js";
|
||||
import { shared } from "../styles";
|
||||
|
||||
@element("pl-toggle")
|
||||
|
@ -7,49 +7,51 @@ export class Toggle extends BaseElement {
|
|||
active: boolean = false;
|
||||
@property() notap: boolean = false;
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
--width: var(--toggle-width, 36px);
|
||||
--height: var(--toggle-height, 24px);
|
||||
--gutter-width: var(--toggle-gutter-width, 2px);
|
||||
--color-off: var(--toggle-color-off, var(--color-foreground));
|
||||
--color-on: var(--toggle-color-on, var(--color-highlight));
|
||||
--color-knob: var(--toggle-color-knob, var(--color-background));
|
||||
|
||||
display: inline-block;
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
background: var(--color-off);
|
||||
border-radius: var(--height);
|
||||
|
||||
transition: background 0.5s ease;
|
||||
}
|
||||
|
||||
.knob {
|
||||
--size: calc(var(--height) - 2 * var(--gutter-width));
|
||||
display: block;
|
||||
height: var(--size);
|
||||
width: var(--size);
|
||||
margin: var(--gutter-width);
|
||||
background: var(--color-knob);
|
||||
border-radius: var(--size);
|
||||
|
||||
transition: transform 0.5s cubic-bezier(1, -0.5, 0, 1.5) -0.2s, background 0.5s, opacity 0.5s;
|
||||
}
|
||||
|
||||
:host([active]) {
|
||||
background: var(--color-on);
|
||||
}
|
||||
|
||||
:host([active]) .knob {
|
||||
--dx: calc(var(--width) - var(--height));
|
||||
transform: translate(var(--dx), 0);
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
<style>
|
||||
:host {
|
||||
--width: var(--toggle-width, 36px);
|
||||
--height: var(--toggle-height, 24px);
|
||||
--gutter-width: var(--toggle-gutter-width, 2px);
|
||||
--color-off: var(--toggle-color-off, var(--color-foreground));
|
||||
--color-on: var(--toggle-color-on, var(--color-highlight));
|
||||
--color-knob: var(--toggle-color-knob, var(--color-background));
|
||||
|
||||
display: inline-block;
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
background: var(--color-off);
|
||||
border-radius: var(--height);
|
||||
|
||||
transition: background 0.5s ease;
|
||||
}
|
||||
|
||||
.knob {
|
||||
--size: calc(var(--height) - 2 * var(--gutter-width));
|
||||
display: block;
|
||||
height: var(--size);
|
||||
width: var(--size);
|
||||
margin: var(--gutter-width);
|
||||
background: var(--color-knob);
|
||||
border-radius: var(--size);
|
||||
|
||||
transition: transform 0.5s cubic-bezier(1, -0.5, 0, 1.5) -0.2s, background 0.5s, opacity 0.5s;
|
||||
}
|
||||
|
||||
:host([active]) {
|
||||
background: var(--color-on);
|
||||
}
|
||||
|
||||
:host([active]) .knob {
|
||||
--dx: calc(var(--width) - var(--height));
|
||||
transform: translate(var(--dx), 0);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="knob"></div>
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { ErrorCode } from "@padloc/core/lib/error.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { element, property, html, query } from "./base.js";
|
||||
import { StartForm, sharedStyles } from "./start-form";
|
||||
import { element, property, html, css, query } from "./base.js";
|
||||
import { StartForm } from "./start-form";
|
||||
import { PasswordInput } from "./password-input.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import { confirm } from "../dialog.js";
|
||||
|
@ -29,23 +29,24 @@ export class Unlock extends StartForm {
|
|||
setTimeout(() => this._passwordInput.focus(), 100);
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...StartForm.styles,
|
||||
css`
|
||||
.current-account {
|
||||
font-size: var(--font-size-tiny);
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
.logout {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
const email = app.account && app.account.email;
|
||||
return html`
|
||||
${sharedStyles}
|
||||
|
||||
<style>
|
||||
.current-account {
|
||||
font-size: var(--font-size-tiny);
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
.logout {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div flex></div>
|
||||
|
||||
<form>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { localize as $l } from "@padloc/core/lib/locale.js";
|
|||
import { mixins } from "../styles";
|
||||
import { app } from "../init.js";
|
||||
import { prompt } from "../dialog.js";
|
||||
import { element, html, property, query } from "./base.js";
|
||||
import { element, html, css, property, query } from "./base.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { LoadingButton } from "./loading-button.js";
|
||||
import { Input } from "./input.js";
|
||||
|
@ -232,6 +232,45 @@ export class VaultDialog extends Dialog<InputType, void> {
|
|||
return !!this.org;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...Dialog.styles,
|
||||
css`
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
color: var(--color-negative);
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin: 8px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 0 8px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.subheader .permission {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
font-size: var(--font-size-tiny);
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item pl-toggle {
|
||||
margin-right: 14px;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
renderContent() {
|
||||
const org = this.org!;
|
||||
const isAdmin = org.isAdmin(app.account!);
|
||||
|
@ -248,42 +287,6 @@ export class VaultDialog extends Dialog<InputType, void> {
|
|||
const groups = filter ? org.groups.filter(({ name }) => name.toLowerCase().includes(filter)) : org.groups;
|
||||
|
||||
return html`
|
||||
<style>
|
||||
.inner {
|
||||
background: var(--color-quaternary);
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
color: var(--color-negative);
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin: 8px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 0 8px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.subheader .permission {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
font-size: var(--font-size-tiny);
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item pl-toggle {
|
||||
margin-right: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<pl-icon icon="vault"></pl-icon>
|
||||
<pl-input
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { VaultID } from "@padloc/core/lib/vault.js";
|
||||
import { shared } from "../styles";
|
||||
import { BaseElement, element, html, property } from "./base.js";
|
||||
import { BaseElement, element, html, css, property } from "./base.js";
|
||||
import "./icon.js";
|
||||
|
||||
@element("pl-vault-item")
|
||||
|
@ -8,41 +8,42 @@ export class VaultItem extends BaseElement {
|
|||
@property()
|
||||
vault: { id: VaultID; name: string };
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 120%;
|
||||
margin: 8px;
|
||||
background: #eee;
|
||||
border: solid 1px #ddd;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.vault-name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.vault-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
`
|
||||
];
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 120%;
|
||||
margin: 8px;
|
||||
background: #eee;
|
||||
border: solid 1px #ddd;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.tags {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.vault-name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.vault-info {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<pl-icon class="icon" icon="vault"></pl-icon>
|
||||
|
||||
<div class="vault-info">
|
||||
|
|
|
@ -1,452 +0,0 @@
|
|||
import { Vault } from "@padloc/core/lib/vault.js";
|
||||
import { VaultItem, Field } from "@padloc/core/lib/item.js";
|
||||
import { localize as $l } from "@padloc/core/lib/locale.js";
|
||||
import { repeat } from "lit-html/directives/repeat.js";
|
||||
import { cache } from "lit-html/directives/cache.js";
|
||||
import { setClipboard } from "../clipboard.js";
|
||||
import { app, router } from "../init.js";
|
||||
import { shared, mixins } from "../styles";
|
||||
import { BaseElement, element, html, property, listen } from "./base.js";
|
||||
// import { CreateItemDialog } from "./create-item-dialog.js";
|
||||
// import { MoveItemsDialog } from "./move-items-dialog.js";
|
||||
import "./icon.js";
|
||||
import "./browse-filter.js";
|
||||
|
||||
@element("pl-vault")
|
||||
export class Vaults extends BaseElement {
|
||||
@property()
|
||||
vault: Vault;
|
||||
|
||||
@property()
|
||||
selected: string = "";
|
||||
@property()
|
||||
multiSelect: boolean = false;
|
||||
//
|
||||
// @dialog("pl-create-item-dialog")
|
||||
// private _createItemDialog: CreateItemDialog;
|
||||
//
|
||||
// @dialog("pl-move-items-dialog")
|
||||
// private _moveItemsDialog: MoveItemsDialog;
|
||||
|
||||
@property()
|
||||
private _items: VaultItem[] = [];
|
||||
|
||||
private _multiSelect = new Map<string, VaultItem>();
|
||||
|
||||
private _sections = new Map<number, string>();
|
||||
|
||||
@listen("items-added", app)
|
||||
@listen("items-deleted", app)
|
||||
@listen("item-changed", app)
|
||||
@listen("items-moved", app)
|
||||
@listen("settings-changed", app)
|
||||
@listen("vault-changed", app)
|
||||
@listen("filter-changed", app)
|
||||
@listen("unlock", app)
|
||||
@listen("lock", app)
|
||||
@listen("synchronize", app)
|
||||
_updateItems() {
|
||||
let items = [...this.vault.items];
|
||||
this._sections.clear();
|
||||
|
||||
const recentCount = 0;
|
||||
|
||||
const recent = items
|
||||
.sort((a, b) => {
|
||||
return (b.lastUsed || b.updated).getTime() - (a.lastUsed || a.updated).getTime();
|
||||
})
|
||||
.slice(0, recentCount);
|
||||
|
||||
items = items.slice(recentCount);
|
||||
|
||||
items = recent.concat(
|
||||
items.sort((a, b) => {
|
||||
const x = a.name.toLowerCase();
|
||||
const y = b.name.toLowerCase();
|
||||
return x > y ? 1 : x < y ? -1 : 0;
|
||||
})
|
||||
);
|
||||
|
||||
for (let i = 0, item, prevSection; i < items.length; i++) {
|
||||
item = items[i];
|
||||
|
||||
const section =
|
||||
i < recentCount
|
||||
? $l("Recently Used")
|
||||
: (item && item.name[0] && item.name[0].toUpperCase()) || $l("No Name");
|
||||
|
||||
const firstInSection = section !== prevSection;
|
||||
if (firstInSection) {
|
||||
this._sections.set(i, section);
|
||||
}
|
||||
|
||||
prevSection = section;
|
||||
}
|
||||
|
||||
this._items = items;
|
||||
}
|
||||
|
||||
selectItem(item: VaultItem) {
|
||||
if (this.multiSelect) {
|
||||
if (this._multiSelect.has(item.id)) {
|
||||
this._multiSelect.delete(item.id);
|
||||
} else {
|
||||
this._multiSelect.set(item.id, item);
|
||||
}
|
||||
this.requestUpdate();
|
||||
} else {
|
||||
router.go(`item/${item.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
selectAll() {
|
||||
this.multiSelect = true;
|
||||
for (const item of this.vault.items) {
|
||||
this._multiSelect.set(item.id, item);
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this._multiSelect.clear();
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
cancelMultiSelect() {
|
||||
this._multiSelect.clear();
|
||||
this.multiSelect = false;
|
||||
this.requestUpdate();
|
||||
}
|
||||
//
|
||||
// private async _newItem() {
|
||||
// await this._createItemDialog.show();
|
||||
// }
|
||||
//
|
||||
// private async _deleteItems() {
|
||||
// const confirmed = await confirm(
|
||||
// $l("Are you sure you want to delete these items? This action can not be undone!"),
|
||||
// $l("Delete {0} Items", this._multiSelect.size.toString()),
|
||||
// $l("Cancel"),
|
||||
// { type: "warning" }
|
||||
// );
|
||||
// if (confirmed) {
|
||||
// await app.deleteItems([...this._multiSelect.values()]);
|
||||
// this.cancelMultiSelect();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private async _moveItems() {
|
||||
// const movedItems = await this._moveItemsDialog.show([...this._multiSelect.values()]);
|
||||
// if (movedItems) {
|
||||
// this.cancelMultiSelect();
|
||||
// }
|
||||
// }
|
||||
|
||||
private _copyField(item: VaultItem, index: number, e: Event) {
|
||||
e.stopPropagation();
|
||||
setClipboard(item, item.fields[index]);
|
||||
const fieldEl = e.target as HTMLElement;
|
||||
fieldEl.classList.add("copied");
|
||||
setTimeout(() => fieldEl.classList.remove("copied"), 1000);
|
||||
}
|
||||
|
||||
private _renderItem(index: number) {
|
||||
const item = this._items[index];
|
||||
const section = this._sections.get(index);
|
||||
const tags = [];
|
||||
|
||||
// if (item.warning) {
|
||||
// tags.push({ icon: "error", class: "tag warning", name: "" });
|
||||
// }
|
||||
|
||||
const t = item.tags[0];
|
||||
if (t) {
|
||||
tags.push({
|
||||
name: item.tags.length > 1 ? `${t} (+${item.tags.length - 1})` : t,
|
||||
icon: "",
|
||||
class: ""
|
||||
});
|
||||
}
|
||||
|
||||
const attCount = (item.attachments && item.attachments.length) || 0;
|
||||
if (attCount) {
|
||||
tags.push({
|
||||
name: "",
|
||||
icon: "attachment",
|
||||
class: ""
|
||||
});
|
||||
}
|
||||
|
||||
return html`
|
||||
${cache(
|
||||
section
|
||||
? html`
|
||||
<div class="section-header">
|
||||
<div>${section}</div>
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
<div>${section}</div>
|
||||
</div>
|
||||
`
|
||||
: html``
|
||||
)}
|
||||
|
||||
<div
|
||||
class="item tap"
|
||||
?selected=${item.id === this.selected}
|
||||
@click=${() => this.selectItem(item)}
|
||||
index="${index}"
|
||||
>
|
||||
<div class="item-check" ?hidden=${!this.multiSelect} ?checked=${this._multiSelect.has(item.id)}></div>
|
||||
|
||||
<div class="item-body">
|
||||
<div class="item-header">
|
||||
<div class="item-name" ?disabled=${!item.name}>
|
||||
${item.name || $l("No Name")}
|
||||
</div>
|
||||
|
||||
<div class="tags small">
|
||||
${tags.map(tag =>
|
||||
tag.icon
|
||||
? html`
|
||||
<div class="tag ${tag.class}">
|
||||
<pl-icon icon="${tag.icon}"></pl-icon>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="ellipsis tag ${tag.class}">${tag.name}</div>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-fields">
|
||||
${item.fields.map(
|
||||
(f: Field, i: number) => html`
|
||||
<div class="item-field tap" @click=${(e: MouseEvent) => this._copyField(item, i, e)}>
|
||||
<div class="item-field-label">${f.name}</div>
|
||||
|
||||
<div class="copied-message">${$l("copied")}</div>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
|
||||
<div class="item-field" disabled ?hidden=${!!item.fields.length}>
|
||||
${$l("No Fields")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
shouldUpdate() {
|
||||
return !!this.vault;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${shared}
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--color-tertiary);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0 2px 0;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-bottom: 70px;
|
||||
background: var(--color-quaternary);
|
||||
border-radius: var(--border-radius);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
grid-gap: 6px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
background: inherit;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 15px;
|
||||
font-size: var(--font-size-tiny);
|
||||
font-weight: bold;
|
||||
box-sizing: border-box;
|
||||
border-radius: var(--border-radius);
|
||||
margin-bottom: -6px;
|
||||
margin-top: 8px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
/* background: var(--color-tertiary); */
|
||||
/* margin: 10px; */
|
||||
/* box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 3px; */
|
||||
/* border-radius: var(--border-radius); */
|
||||
}
|
||||
|
||||
.item-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item .tags {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
height: var(--row-height);
|
||||
line-height: var(--row-height);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
padding-left: 15px;
|
||||
${mixins.ellipsis()}
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-fields {
|
||||
position: relative;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.item-fields::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 6px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.item-field {
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-tiny);
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
margin: 0 0 8px 8px;
|
||||
border-radius: 8px;
|
||||
${mixins.shade2()}
|
||||
}
|
||||
|
||||
.item-field > * {
|
||||
transition: transform 0.2s cubic-bezier(1, -0.3, 0, 1.3), opacity 0.2s;
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
${mixins.fullbleed()}
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.item-field:not(.copied) .copied-message, .item-field.copied .item-field-label {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
font-weight: bold;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-background);
|
||||
}
|
||||
|
||||
.copied-message::before {
|
||||
font-family: "FontAwesome";
|
||||
content: "\\f00c\\ ";
|
||||
}
|
||||
|
||||
.item-field-label {
|
||||
padding: 0 15px;
|
||||
pointer-events: none;
|
||||
${mixins.ellipsis()}
|
||||
}
|
||||
|
||||
.item:focus:not([selected]) {
|
||||
border-color: var(--color-highlight);
|
||||
color: #4ca8d9;
|
||||
}
|
||||
|
||||
.item[selected] {
|
||||
background: #e6e6e6;
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
position: relative;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
box-sizing: border-box;
|
||||
border: solid 3px #eee;
|
||||
background: #eee;
|
||||
border-radius: 30px;
|
||||
margin: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.item-check::after {
|
||||
content: "";
|
||||
display: block;
|
||||
${mixins.fullbleed()}
|
||||
background: var(--color-primary);
|
||||
border-radius: inherit;
|
||||
transition: transform 0.2s, opacity 0.2s;
|
||||
transition-timing-function: cubic-bezier(1, -0.3, 0, 1.3);
|
||||
}
|
||||
|
||||
.item-check:not([checked])::after {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.selected-count {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-left: 15px;
|
||||
background: #ddd;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 5px;
|
||||
line-height: 1.2em;
|
||||
font-size: var(--font-size-tiny);
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>${this.vault.name}</h1>
|
||||
|
||||
<main id="main">
|
||||
${repeat(this._items, item => item.id, (_: any, index: number) => this._renderItem(index))}
|
||||
</main>
|
||||
|
||||
<div class="empty-placeholder" ?hidden=${!!this.vault.items.size || app.filter.text}>
|
||||
<pl-icon icon="list"></pl-icon>
|
||||
|
||||
<div>${$l("This vault doesn't have any items yet!")}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
|
@ -1,66 +1,67 @@
|
|||
import { html } from "@polymer/lit-element";
|
||||
import { css } from "lit-element";
|
||||
|
||||
export const narrowWidth = 700;
|
||||
export const wideWidth = 1200;
|
||||
|
||||
export const cssVars = html`
|
||||
<style>
|
||||
:host {
|
||||
--font-family: "Nunito";
|
||||
--font-family-fallback: sans-serif;
|
||||
--font-family-mono: "Inconsolata";
|
||||
export const cssVars = css`
|
||||
:host {
|
||||
--font-family: "Nunito";
|
||||
--font-family-fallback: sans-serif;
|
||||
--font-family-mono: "Inconsolata";
|
||||
|
||||
--font-size-micro: 12px;
|
||||
--font-size-tiny: 14px;
|
||||
--font-size-small: 16px;
|
||||
--font-size-default: 18px;
|
||||
--font-weight-thin: 100;
|
||||
--font-weight-light: 300;
|
||||
--font-weight-regular: 400;
|
||||
--font-weight-bold: 700;
|
||||
--font-size-micro: 12px;
|
||||
--font-size-tiny: 14px;
|
||||
--font-size-small: 16px;
|
||||
--font-size-default: 18px;
|
||||
--font-weight-thin: 100;
|
||||
--font-weight-light: 300;
|
||||
--font-weight-regular: 400;
|
||||
--font-weight-bold: 700;
|
||||
|
||||
--color-primary: #3bb7f9;
|
||||
--color-secondary: #444;
|
||||
--color-tertiary: #ffffff;
|
||||
--color-quaternary: #fafafa;
|
||||
/* --color-negative: #D7322D; */
|
||||
--color-negative: #ff6666;
|
||||
--color-primary: #3bb7f9;
|
||||
--color-secondary: #444;
|
||||
--color-tertiary: #ffffff;
|
||||
--color-quaternary: #fafafa;
|
||||
/* --color-negative: #D7322D; */
|
||||
--color-negative: #ff6666;
|
||||
|
||||
--color-background: var(--color-tertiary);
|
||||
--color-foreground: var(--color-secondary);
|
||||
--color-highlight: var(--color-primary);
|
||||
--color-error: var(--color-negative);
|
||||
--color-background: var(--color-tertiary);
|
||||
--color-foreground: var(--color-secondary);
|
||||
--color-highlight: var(--color-primary);
|
||||
--color-error: var(--color-negative);
|
||||
|
||||
--color-shade-1: rgba(0, 0, 0, 0.05);
|
||||
--color-shade-2: rgba(0, 0, 0, 0.1);
|
||||
--color-shade-3: rgba(0, 0, 0, 0.15);
|
||||
--color-shade-4: rgba(0, 0, 0, 0.2);
|
||||
--color-shade-1: rgba(0, 0, 0, 0.05);
|
||||
--color-shade-2: rgba(0, 0, 0, 0.1);
|
||||
--color-shade-3: rgba(0, 0, 0, 0.15);
|
||||
--color-shade-4: rgba(0, 0, 0, 0.2);
|
||||
|
||||
--color-gradient-highlight-from: rgb(7, 124, 185);
|
||||
--color-gradient-highlight-to: rgb(89, 198, 255);
|
||||
--color-gradient-warning-from: #f25b00;
|
||||
--color-gradient-warning-to: #f49300;
|
||||
--color-gradient-dark-from: #222;
|
||||
--color-gradient-dark-to: #555;
|
||||
--color-gradient-highlight-from: rgb(7, 124, 185);
|
||||
--color-gradient-highlight-to: rgb(89, 198, 255);
|
||||
--color-gradient-warning-from: #f25b00;
|
||||
--color-gradient-warning-to: #f49300;
|
||||
--color-gradient-dark-from: #222;
|
||||
--color-gradient-dark-to: #555;
|
||||
|
||||
--color-scrim: rgba(255, 255, 255, 0.9);
|
||||
--color-scrim: rgba(255, 255, 255, 0.9);
|
||||
|
||||
--color-btn-front: var(--color-foreground);
|
||||
--color-btn-back: var(--shade-3-color);
|
||||
--color-btn-front: var(--color-foreground);
|
||||
--color-btn-back: var(--shade-3-color);
|
||||
|
||||
--row-height: 50px;
|
||||
--row-height: 50px;
|
||||
|
||||
--gutter-size: 8px;
|
||||
--border-radius: 8px;
|
||||
--border-color: rgba(0, 0, 0, 0.1);
|
||||
--gutter-size: 8px;
|
||||
--border-radius: 8px;
|
||||
--border-color: rgba(0, 0, 0, 0.1);
|
||||
|
||||
--toaster-easing: cubic-bezier(1, -0.3, 0, 1.3);
|
||||
--toaster-easing: cubic-bezier(1, -0.3, 0, 1.3);
|
||||
|
||||
--shade-1-color: transparent;
|
||||
--shade-2-color: var(--color-shade-1);
|
||||
--shade-3-color: var(--color-shade-2);
|
||||
--shade-4-color: var(--color-shade-3);
|
||||
--shade-5-color: var(--color-shade-4);
|
||||
}
|
||||
</style>
|
||||
--shade-1-color: transparent;
|
||||
--shade-2-color: var(--color-shade-1);
|
||||
--shade-3-color: var(--color-shade-2);
|
||||
--shade-4-color: var(--color-shade-3);
|
||||
--shade-5-color: var(--color-shade-4);
|
||||
|
||||
--narrow-width: 700px;
|
||||
--wide-width: 1200px;
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import * as mixins from "./mixins";
|
||||
import * as config from "./config";
|
||||
|
||||
import { listLayout } from "./list-layout";
|
||||
import { shared } from "./shared";
|
||||
|
||||
export { mixins, config, listLayout, shared };
|
||||
export { mixins, config, shared };
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import { html } from "@polymer/lit-element";
|
||||
import * as mixins from "./mixins";
|
||||
import * as config from "./config";
|
||||
|
||||
export const listLayout = html`
|
||||
<style>
|
||||
|
||||
.list-layout {
|
||||
${mixins.fullbleed()}
|
||||
perspective: 1000px;
|
||||
}
|
||||
|
||||
.list-layout > * {
|
||||
border-radius: var(--border-radius);
|
||||
overflow: hidden;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
@media (min-width: ${config.narrowWidth}px) {
|
||||
.list-layout {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.list-layout > :first-child {
|
||||
width: 350px;
|
||||
margin-right: var(--gutter-size);
|
||||
}
|
||||
|
||||
.list-layout > :last-child {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.list-layout:not([show-detail]) > :last-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: ${config.narrowWidth}px) {
|
||||
.list-layout > :first-child {
|
||||
margin: 0;
|
||||
${mixins.fullbleed()}
|
||||
}
|
||||
|
||||
.list-layout > :last-child {
|
||||
${mixins.fullbleed()}
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.list-layout > :first-child,
|
||||
.list-layout > :last-child {
|
||||
transition: transform 0.3s cubic-bezier(0.6, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.list-layout[show-detail] > :first-child {
|
||||
transform: translate3d(0, 0, -50px);
|
||||
}
|
||||
|
||||
.list-layout:not([show-detail]) > :last-child {
|
||||
transform: translate(100%, 0);
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -1,9 +1,11 @@
|
|||
export const unselectable = () => `
|
||||
import { css } from "lit-element";
|
||||
|
||||
export const unselectable = () => css`
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
export const positionSticky = () => `
|
||||
export const positionSticky = () => css`
|
||||
position: -webkit-sticky;
|
||||
position: -moz-sticky;
|
||||
position: -o-sticky;
|
||||
|
@ -11,37 +13,7 @@ export const positionSticky = () => `
|
|||
position: sticky;
|
||||
`;
|
||||
|
||||
export const tapHighlight = () => `
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
export const tapHighlightAfter = () => `
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: currentColor;
|
||||
opacity: 0;
|
||||
transition: opacity 1s;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
`;
|
||||
|
||||
export const tapHighlightActiveAfter = () => `
|
||||
opacity: 0.3;
|
||||
transition: none;
|
||||
`;
|
||||
|
||||
export const tapHighlightHoverAfter = () => `
|
||||
opacity: 0.1;
|
||||
transition: none;
|
||||
`;
|
||||
|
||||
export const fullbleed = () => `
|
||||
export const fullbleed = () => css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -50,43 +22,43 @@ export const fullbleed = () => `
|
|||
overflow: hidden;
|
||||
`;
|
||||
|
||||
export const scroll = (direction?: "vertical" | "horizontal") => `
|
||||
${direction === "vertical" ? "overflow-y" : direction === "horizontal" ? "overflow-x" : "overflow"}: auto;
|
||||
export const scroll = (direction?: "vertical" | "horizontal") => css`
|
||||
${direction === "vertical" ? css`overflow-y` : direction === "horizontal" ? css`overflow-x` : css`overflow`}: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
`;
|
||||
|
||||
export const ellipsis = () => `
|
||||
export const ellipsis = () => css`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
export const absoluteCenter = () => `
|
||||
export const absoluteCenter = () => css`
|
||||
${fullbleed()};
|
||||
margin: auto;
|
||||
`;
|
||||
|
||||
export const shade1 = () => `
|
||||
export const shade1 = () => css`
|
||||
background: var(--shade-1-color);
|
||||
`;
|
||||
|
||||
export const shade2 = () => `
|
||||
export const shade2 = () => css`
|
||||
background: var(--shade-2-color);
|
||||
`;
|
||||
|
||||
export const shade3 = () => `
|
||||
export const shade3 = () => css`
|
||||
background: var(--shade-3-color);
|
||||
`;
|
||||
|
||||
export const shade4 = () => `
|
||||
export const shade4 = () => css`
|
||||
background: var(--shade-4-color);
|
||||
`;
|
||||
|
||||
export const shade5 = () => `
|
||||
export const shade5 = () => css`
|
||||
background: var(--shade-5-color);
|
||||
`;
|
||||
|
||||
export const card = () => `
|
||||
export const card = () => css`
|
||||
background: var(--color-background);
|
||||
/* box-shadow: rgba(0, 0, 0, 0.2) 0 0 1px; */
|
||||
border-radius: var(--border-radius);
|
||||
|
@ -95,24 +67,30 @@ export const card = () => `
|
|||
overflow: hidden;
|
||||
`;
|
||||
|
||||
export const gradientHighlight = (horizontal = false) => `
|
||||
background: linear-gradient(${
|
||||
horizontal ? "90deg" : "0"
|
||||
}, var(--color-gradient-highlight-from) 0%, var(--color-gradient-highlight-to) 100%);
|
||||
export const gradientHighlight = (horizontal = false) => css`
|
||||
background: linear-gradient(
|
||||
${horizontal ? css`90deg` : css`0`},
|
||||
var(--color-gradient-highlight-from) 0%,
|
||||
var(--color-gradient-highlight-to) 100%
|
||||
);
|
||||
`;
|
||||
|
||||
export const gradientWarning = (horizontal = false) => `
|
||||
background: linear-gradient(${
|
||||
horizontal ? "90deg" : "0"
|
||||
}, var(--color-gradient-warning-from) 0%, var(--color-gradient-warning-to) 100%);
|
||||
export const gradientWarning = (horizontal = false) => css`
|
||||
background: linear-gradient(
|
||||
${horizontal ? css`90deg` : css`0`},
|
||||
var(--color-gradient-warning-from) 0%,
|
||||
var(--color-gradient-warning-to) 100%
|
||||
);
|
||||
`;
|
||||
|
||||
export const gradientDark = (horizontal = false) => `
|
||||
background: linear-gradient(${
|
||||
horizontal ? "90deg" : "0"
|
||||
}, var(--color-gradient-dark-from) 0%, var(--color-gradient-dark-to) 100%);
|
||||
export const gradientDark = (horizontal = false) => css`
|
||||
background: linear-gradient(
|
||||
${horizontal ? css`90deg` : css`0`},
|
||||
var(--color-gradient-dark-from) 0%,
|
||||
var(--color-gradient-dark-to) 100%
|
||||
);
|
||||
`;
|
||||
|
||||
export const textShadow = () => `
|
||||
export const textShadow = () => css`
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0px 2px 0px;
|
||||
`;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { html } from "@polymer/lit-element";
|
||||
import { css } from "lit-element";
|
||||
import * as mixins from "./mixins";
|
||||
import * as config from "./config";
|
||||
|
||||
export const shared = html`
|
||||
<style>
|
||||
export const shared = css`
|
||||
:host {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
@ -280,19 +278,46 @@ export const shared = html`
|
|||
}
|
||||
|
||||
.tap {
|
||||
${mixins.tapHighlight()}
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tap::after {
|
||||
${mixins.tapHighlightAfter()}
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: currentColor;
|
||||
opacity: 0;
|
||||
transition: opacity 1s;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.tap:active::after {
|
||||
${mixins.tapHighlightActiveAfter()}
|
||||
opacity: 0.3;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.tap:not(:active):hover::after {
|
||||
${mixins.tapHighlightHoverAfter()}
|
||||
.tap::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: currentColor;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.tap:not(:active):hover::before {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.tiles > :nth-child(8n + 1), .tiles-1 {
|
||||
|
@ -550,29 +575,19 @@ export const shared = html`
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 15px;
|
||||
border-bottom: solid 3px var(--color-shade-1);
|
||||
}
|
||||
|
||||
.tabs > * > pl-icon {
|
||||
margin-left: -12px;
|
||||
margin-left: -10px;
|
||||
font-size: 90%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.tabs > *[active] {
|
||||
color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.tabs > *[active]::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: currentColor;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
header > .tabs {
|
||||
margin: -10px -10px -12px -10px;
|
||||
border-color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.search-wrapper {
|
||||
|
@ -622,7 +637,7 @@ export const shared = html`
|
|||
75% {transform: translate(5px, 2px);}
|
||||
}
|
||||
|
||||
@media (min-width: ${config.narrowWidth + 1}px) {
|
||||
@media (min-width: 701px) {
|
||||
.menu-button {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -632,10 +647,9 @@ export const shared = html`
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: ${config.narrowWidth}px) {
|
||||
@media (max-width: 700px) {
|
||||
.wide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
|
Loading…
Reference in New Issue