diff --git a/.eslintrc.json b/.eslintrc.json index 5aaf5ccd..8d683881 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -57,6 +57,7 @@ { "SwitchCase": 1 } - ] + ], + "no-console": 0 } } diff --git a/config/manifest.json b/config/manifest.json index c0257ff4..96128234 100644 --- a/config/manifest.json +++ b/config/manifest.json @@ -18,7 +18,7 @@ "96": "images/96.png", "128": "images/128.png" }, - "version": "1.14.0", + "version": "1.15.0", "background": { "scripts": [ "background.js" diff --git a/examples/examples.md b/examples/examples.md index a544bc75..6127fd46 100644 --- a/examples/examples.md +++ b/examples/examples.md @@ -100,6 +100,7 @@ tr.addOperation(window.echojslib.constants.OPERATIONS_IDS.ACCOUNT_CREATE, { num_committee: 0, votes: [], extensions: [], + delegate_share: 0 }, } ); diff --git a/examples/index.html b/examples/index.html index f156c0a9..1f8a8a7d 100644 --- a/examples/index.html +++ b/examples/index.html @@ -76,7 +76,7 @@

Transfer

id="transfer-fromAddress" name="transfer-fromAddress" placeholder="from" - value="1.2.1204" + value="1.2.18" /> Contract id="contract-registrar" name="contract-registrar" placeholder="registrar" - value="1.2.1204" + value="1.2.18" /> Create Contract id="contactCreate-fromAddress" name="transfer-fromAddress" placeholder="from" - value="1.2.1204" + value="1.2.18" /> Create account id="createAccount-registrar" name="createAccount-registrar" placeholder="registrar" - value="1.2.1204" + value="1.2.18" /> Update account id="updateAccount-registrar" name="createAccount-registrar" placeholder="registrar" - value="1.2.1204" + value="1.2.18" /> Sign message id="signMessage-account" name="signMessage-account" placeholder="account" - value="1.2.1204" + value="1.2.18" />
@@ -594,6 +594,7 @@

Sign message

num_committee: 0, votes: [], extensions: [], + delegate_share: 0 } }; diff --git a/extension/SignTransaction.js b/extension/SignTransaction.js index c4ccfb91..c546a708 100644 --- a/extension/SignTransaction.js +++ b/extension/SignTransaction.js @@ -1,3 +1,5 @@ +/* eslint-disable no-underscore-dangle */ + import { serializers, Signature } from 'echojs-lib'; import { EXPIRATION_INFELICITY, GLOBAL_ID_1 } from '../src/constants/GlobalConstants'; diff --git a/extension/background.js b/extension/background.js index 1f7de734..970647a8 100644 --- a/extension/background.js +++ b/extension/background.js @@ -1,6 +1,6 @@ /* eslint-disable no-nested-ternary */ import echo, { Transaction, PrivateKey, aes, ED25519, crypto as echojsCrypto } from 'echojs-lib'; -import { throttle } from 'lodash'; +import { throttle, uniqBy } from 'lodash'; import urlParse from 'url-parse'; import EventEmitter from '../libs/CustomAwaitEmitter'; @@ -32,6 +32,8 @@ import { DRAFT_STORAGE_KEY, GLOBAL_ID_1, EXPIRATION_INFELICITY, + REGISTRATION_OPTIONS, + MESSAGE_METHODS, } from '../src/constants/GlobalConstants'; import { operationKeys } from '../src/constants/OperationConstants'; @@ -57,22 +59,134 @@ const notificationManager = new NotificationManager(); const emitter = new EventEmitter(); const crypto = new Crypto(); -const requestAccountMethodCallbacks = []; +/** @type {[PortObject]} */ +const ports = []; -let lastRequestType = ''; -const accountsRequests = []; -let activeAccountRequests = []; -let requestQueue = []; -const networkSubscribers = []; -const activeAccountSubscribers = []; - -const processedOrigins = []; -let providerRequests = []; -let signMessageRequests = []; const providerNotification = new NotificationManager(); const signNotification = new NotificationManager(); +let requestQueue = []; + +const approvedOrigins = {}; + +/** + * @method isPortApproved + * @param {PortObject} portObj + * @return {Boolean} + */ +const isPortApproved = (portObj) => approvedOrigins[portObj.origin]; + +/** + * + * @param {Object} res + * @param {String} method + */ +const notifyAllApprovedPorts = (res, method) => { + ports.forEach((portObj) => { + if (isPortApproved(portObj)) { + portObj.port.postMessage({ res, method }); + } + }); +}; + +/** + * @method sendOnPorts + * @param {[PortObject]} portsToSend + * @param {Function} comparator + * @param {String} method + * @param {Object|Number|Boolean|String} res + * @param {Object|String} error + */ +const sendOnPorts = (portsToSend, comparator, method, res, error) => { + portsToSend.forEach((portObject) => { + const { port, origin } = portObject; + + if (!isPortApproved(portObject) + && method + && ![MESSAGE_METHODS.GET_ACCESS, MESSAGE_METHODS.CHECK_ACCESS].includes(method)) { + return; + } + + portObject.pendingTasks = portObject.pendingTasks.filter((task) => { + if (comparator({ ...task, origin })) { + + delete task.data; + const message = { ...task, origin, res }; + if (error) { + message.error = error; + } + port.postMessage(message); + return false; + } + return true; + }); + }); +}; + +/** + * @method sendOnPortsViaMethod + * @param {[PortObject]} portsToSend + * @param {String} requestedMethod + * @param {Object|Number|Boolean|String} res + * @param {Object|String} error + */ +const sendOnPortsViaMethod = (portsToSend, requestedMethod, res, error) => { + sendOnPorts( + portsToSend, + (({ method }) => method === requestedMethod), + requestedMethod, + res, + error, + ); +}; +/** + * @method sendOnPortsViaMethod + * @param {[PortObject]} portsToSend + * @param {String} requestedMethod + * @param {Object|Number|Boolean|String} res + * @param {Object|String} error + */ +const sendOnPortsViaId = (portsToSend, requestedId, res, error) => { + sendOnPorts( + portsToSend, + (({ id }) => id === requestedId), + null, + res, + error, + ); +}; + +/** + * @method getProviderApprovalTaskCount + */ +const getProviderApprovalTaskCount = () => { + // the looking out a count of ports that contains MESSAGE_METHODS.GET_ACCESS task + const filterPorts = ports.filter(({ pendingTasks }) => + pendingTasks.find(({ method }) => + method === MESSAGE_METHODS.GET_ACCESS)); + const providerApprovalTaskCount = uniqBy(filterPorts, ({ origin }) => origin).length; + return providerApprovalTaskCount; +}; + +/** + * @method getSignMessageTaskCount + */ +const getSignMessageTaskCount = () => { + // the looking out a count of total count of signing tasks + const count = 0; + ports.forEach(({ pendingTasks }) => { + pendingTasks.forEach(({ method }) => + method === MESSAGE_METHODS.PROOF_OF_AUTHORITY + || method === MESSAGE_METHODS.SIGN_DATA); + }); + return count; +}; + +/** + * @method connectSubscribe + * @param {String} status + */ const connectSubscribe = (status) => { try { switch (status) { @@ -113,7 +227,6 @@ const createSocket = async (url) => { const network = await storage.get('current_network') || NETWORKS[0]; ({ url } = network); - } url = url || NETWORKS[0].url; @@ -126,6 +239,7 @@ const createSocket = async (url) => { pingInterval: PING_INTERVAL, debug: false, apis: ['database', 'network_broadcast', 'history', 'registration', 'asset', 'login', 'network_node'], + registration: { batch: REGISTRATION_OPTIONS.BATCH, timeout: REGISTRATION_OPTIONS.TIMEOUT }, }); connectSubscribe(CONNECT_STATUS); echo.subscriber.setGlobalSubscribe(throttle(() => { @@ -180,7 +294,7 @@ const closePopup = (manager = notificationManager) => { * Set count of requests */ const setBadge = () => { - const length = requestQueue.length + providerRequests.length + signMessageRequests.length; + const length = requestQueue.length + getSignMessageTaskCount() + getProviderApprovalTaskCount(); const text = length === 0 ? 'BETA' : (length > 9 ? '9+' : length.toString()); extensionizer.browserAction.setBadgeText({ text }); }; @@ -233,32 +347,6 @@ const createAccount = async (name, path) => { }; -/** - - * Get user account if unlocked - * @returns {Promise.<*>} - */ -const resolveAccounts = async () => { - - const network = await getNetwork(); - - try { - let accounts = await crypto.getInByNetwork(network.name, 'accounts') || []; - accounts = accounts.filter((account) => account.active); - - accountsRequests.forEach((request) => { - try { - request.cb({ id: request.id, res: accounts }); - } catch (e) { - console.log(e.message); - } - }); - return accountsRequests.splice(0, accountsRequests.length); - } catch (e) { - return { error: e.message }; - } - -}; /** * Get active account by network @@ -282,285 +370,208 @@ const getActiveAccount = async (switchNetwork) => { }; /** - * Resolve request to get active account from inpage - * @param request - * @returns {Promise} + * @method resolveRequestAccount + * @param {[PortObject]} portsToSend */ -const resolveActiveAccount = async (request) => { - try { - const account = await getActiveAccount(); - request.cb({ id: request.id, res: account }); - request.cb = function cb() {}; - } catch (e) { - console.log(e.message); - } +const resolveRequestAccount = async (portsToSend) => { + const account = await getActiveAccount(); + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.REQUEST_ACCOUNT, account); }; - /** - * Update active account on all requested inpage - * @returns {Promise} + * @method resolveAccounts + * @param {[PortObject]} portsToSend */ -const updateActiveAccountInpage = async (network) => { - try { - const account = await getActiveAccount(network); - - activeAccountRequests.forEach((request) => { - try { - request.cb({ id: request.id, res: account }); - } catch (e) { - console.log(e.message); - } - }); - activeAccountRequests.splice(0, activeAccountRequests.length); - return null; - - } catch (e) { - return { error: e.message }; - } +const resolveAccounts = async (portsToSend) => { + const network = await getNetwork(); + let accounts = await crypto.getInByNetwork(network.name, 'accounts') || []; + accounts = accounts.filter((account) => account.active); + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.ACCOUNTS, accounts); }; +/** + * @method resolveActiveAccount + * @param {[PortObject]} portsToSend + */ +const resolveActiveAccount = async (portsToSend) => { + const activeAccount = await getActiveAccount(); + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.GET_ACTIVE_ACCOUNT, activeAccount); +}; -const execGetAccountCallbacks = async () => { - - try { - const account = await getActiveAccount(); - - requestAccountMethodCallbacks.forEach((request) => { - try { - request.cb({ id: request.id, res: account }); - } catch (e) { - console.log(e.message); - } - }); - - return requestAccountMethodCallbacks.splice(0, requestAccountMethodCallbacks.length); - +/** + * @method resolveNetwork + * @param {[PortObject]} portsToSend + */ +const resolveNetwork = async (portsToSend) => { + const result = await getNetwork(); + const stringifiedResult = JSON.parse(JSON.stringify(result)); + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.GET_NETWORK, stringifiedResult); +}; - } catch (e) { - return { error: e.message }; - } +/** + * @method resolveCheckAccess + * @param {[PortObject]} portsToSend + */ +const resolveCheckAccess = async (portsToSend) => { + const { origin } = portsToSend[0]; + const result = !!approvedOrigins[origin]; + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.CHECK_ACCESS, result); +}; +/** + * @method resolveProviderApprove + * @param {[PortObject]} portsToSend + */ +const resolveProviderApprove = (portsToSend, err) => { + const { origin } = portsToSend[0]; + const status = approvedOrigins[origin]; + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.GET_ACCESS, status, err); }; /** - * On content script request - * @param request - * @param sender - * @param sendResponse - * @returns {boolean} + * @method origin + * @param {[PortObject]} portsToSend */ -const onMessage = (request, sender, sendResponse) => { +const resolveGetAccess = (portsToSend) => { + const { origin } = portsToSend[0]; + const result = !!approvedOrigins[origin]; + sendOnPortsViaMethod(portsToSend, MESSAGE_METHODS.GET_ACCESS, result); +}; - const { hostname } = urlParse(sender.tab.url); - const { id: tabId } = sender.tab; - request = JSON.parse(JSON.stringify(request)); +/** + * + * @param {Object} request + * @param {PortObject} portObj + */ +const onMessageHandler = (request, portObj) => { + const { port: { sender } } = portObj; + const { origin } = urlParse(sender.tab.url); + const { id, method } = request; - if (!request.method || !request.appId || request.appId !== APP_ID) return false; + const sendResponse = + (reposneObject) => portObj.port.postMessage({ ...reposneObject, origin, method }); - if (request.method === 'closeTab') { - activeAccountRequests = activeAccountRequests - .filter((accountRequest) => accountRequest.tabId !== tabId); - const indexFindRequest = providerRequests.findIndex((rq) => rq.origin === hostname); - if (indexFindRequest === -1) return true; - const indexTabId = providerRequests[indexFindRequest].tabs - .findIndex((id) => id === tabId); - if (indexTabId === -1) return true; - providerRequests[indexFindRequest].cbs.splice(indexTabId, 1); - providerRequests[indexFindRequest].ids.splice(indexTabId, 1); - providerRequests[indexFindRequest].tabs.splice(indexTabId, 1); - return true; - } + if (!request.id || !request.method || !request.appId || request.appId !== APP_ID) return false; - if (request.method === 'checkAccess') { - sendResponse({ id: request.id, response: !!processedOrigins[hostname] }); + if (request.method === MESSAGE_METHODS.CHECK_ACCESS) { + portObj.addTask(id, method); + resolveCheckAccess([portObj]); return true; - } + } else if (!approvedOrigins[origin]) { - if (typeof processedOrigins[hostname] !== 'boolean') { - - if (request.method !== 'getAccess') { + if (request.method !== MESSAGE_METHODS.GET_ACCESS) { sendResponse({ id: request.id, error: 'No access' }); return true; } - const indexRequest = providerRequests.findIndex((p) => p.origin === hostname); - if (indexRequest !== -1) { - providerRequests[indexRequest].ids.push(request.id); - providerRequests[indexRequest].cbs.push(sendResponse); - providerRequests[indexRequest].tabs.push(tabId); - return true; - } - - providerRequests.push({ - origin: hostname, - tabs: [tabId], - ids: [request.id], - cbs: [sendResponse], - }); - - setBadge(); + portObj.addTask(id, method); try { - emitter.emit('addProviderRequest', request.id, hostname); + emitter.emit('addProviderRequest', request.id, origin); } catch (e) { return null; } + setBadge(); triggerPopup(INCOMING_CONNECTION_PATH, providerNotification); - return true; - } else if (request.method === 'getAccess') { - const isAccess = processedOrigins[hostname]; - if (isAccess) { - sendResponse({ id: request.id, status: isAccess }); - } else { - sendResponse({ id: request.id, status: isAccess, error: { isAccess: false } }); - } - return true; } - if (request.method === 'requestAccount') { - - requestAccountMethodCallbacks.push({ - id: request.id, cb: sendResponse, - }); - if (!crypto.isLocked()) { - execGetAccountCallbacks(); - } else { - triggerPopup(CLOSE_AFTER_UNLOCK_PATH); + switch (method) { + case MESSAGE_METHODS.GET_ACCESS: { + portObj.addTask(id, method); + resolveGetAccess(ports); + return true; } - return true; - } - - if (request.method === 'getNetwork') { - - getNetwork().then((result) => { - sendResponse(({ id: request.id, res: JSON.parse(JSON.stringify(result)) })); - }); - return true; - } - - if (['proofOfAuthority', 'signData'].includes(request.method)) { - - signMessageRequests.push({ - origin: hostname, - id: request.id, - message: request.data.message, - signer: request.data.accountId, - method: request.method, - cb: sendResponse, - }); - - setBadge(); - - try { - emitter.emit( - 'addSignMessageRequest', - request.id, - hostname, - request.data.accountId, - request.data.message, - ); - } catch (e) { - return null; + case MESSAGE_METHODS.REQUEST_ACCOUNT: { + portObj.addTask(id, method); + if (!crypto.isLocked()) { + resolveRequestAccount([portObj]); + } else { + triggerPopup(CLOSE_AFTER_UNLOCK_PATH); + } + return true; } + case MESSAGE_METHODS.GET_NETWORK: { + portObj.addTask(id, method); + resolveNetwork([portObj]); + return true; + } + case MESSAGE_METHODS.ACCOUNTS: { + portObj.addTask(id, method); - triggerPopup(SIGN_MESSAGE_PATH, signNotification); - return true; - } - - if (request.method === 'networkSubscribe') { - networkSubscribers.push({ id: request.id, cb: sendResponse }); - return true; - } - - if (request.method === 'accountSubscribe') { - activeAccountSubscribers.push({ id: request.id, cb: sendResponse }); - return true; - } - - if (!request.id) return false; - - const { id } = request; - - lastRequestType = request.method; - - - if (request.method === 'confirm' && request.data) { - - const operations = JSON.parse(request.data); - - requestQueue.push({ - data: operations, sender, id, cb: sendResponse, - }); + if (!crypto.isLocked()) { + resolveAccounts([portObj]); + } else { + triggerPopup(CLOSE_AFTER_UNLOCK_PATH); + } + return true; + } + case MESSAGE_METHODS.GET_ACTIVE_ACCOUNT: { + portObj.addTask(id, method); + resolveActiveAccount([portObj]); + return true; + } + case MESSAGE_METHODS.PROOF_OF_AUTHORITY: + case MESSAGE_METHODS.SIGN_DATA: { + portObj.addTask(id, method, { + message: request.data.message, + signer: request.data.accountId, + }); + setBadge(); - setBadge(); + try { + emitter.emit( + 'addSignMessageRequest', + id, + origin, + request.data.accountId, + request.data.message, + method, + ); + } catch (e) { + return null; + } - try { - emitter.emit('request', id, operations); - } catch (e) { - return null; + triggerPopup(SIGN_MESSAGE_PATH, signNotification); + return true; } + case MESSAGE_METHODS.CONFIRM: { + if (request.data) { + const operations = JSON.parse(request.data); + portObj.addTask(id, method); - notificationManager.getPopup() - .then((popup) => { - if (!popup) { - triggerPopup(); - } - }) - .catch(triggerPopup); - - } else if (request.method === 'accounts') { + requestQueue.push({ + data: operations, sender, id, cb: sendResponse, + }); - accountsRequests.push({ - id, cb: sendResponse, - }); + setBadge(); - if (!crypto.isLocked()) { - resolveAccounts(); + try { + emitter.emit('request', id, operations); + } catch (e) { + return null; + } - } else { - triggerPopup(); + notificationManager.getPopup() + .then((popup) => { + if (!popup) { + triggerPopup(); + } + }) + .catch(triggerPopup); + } + return true; } - - } else if (request.method === 'getActiveAccount') { - const { inPageId } = request; - const tabIndex = activeAccountRequests - .findIndex(({ inPageId: reqInPageId }) => inPageId === reqInPageId); - const req = { - id: request.id, cb: sendResponse, inPageId, - }; - if (tabIndex === -1) { - resolveActiveAccount(req); - activeAccountRequests.push(req); + default: { + // TODO send error about unknown method return true; } - - activeAccountRequests[tabIndex] = req; - - return true; - } - - return true; -}; - -const onPinUnlock = () => { - if (lastRequestType === 'accounts') { - resolveAccounts(); - closePopup(); } - execGetAccountCallbacks(); - updateActiveAccountInpage(); - return null; }; -const onLock = () => { - updateActiveAccountInpage(); - return null; -}; /** * @method removeTransaction @@ -585,6 +596,16 @@ const removeTransaction = (id, err = null) => { return null; }; +/** + * @method removeSigningTasks + * @param {String} id + */ +const removeSigningTasks = (id) => { + requestQueue = requestQueue.filter((r) => r.id !== id); + setBadge(); + return null; +}; + /** * On extension emitter response * @param err @@ -622,7 +643,7 @@ export const onResponse = (err, id, status) => { if ( (requestQueue.length === 0 && COMPLETE_STATUS === status) - || [DISCONNECT_STATUS, NOT_LOGGED_STATUS].includes(status) + || [DISCONNECT_STATUS, NOT_LOGGED_STATUS].includes(status) ) closePopup(); return null; @@ -642,7 +663,7 @@ export const trSignResponse = (signData) => { } const dataToSend = JSON.stringify(signData); - requestQueue[0].cb({ id: requestQueue[0].id, signData: dataToSend }); + requestQueue[0].cb({ id: requestQueue[0].id, res: dataToSend }); removeTransaction(requestQueue[0].id); return null; @@ -667,7 +688,6 @@ const onFirstInstall = (details) => { } }; - /** * @method sendTransaction * @@ -677,6 +697,7 @@ const onFirstInstall = (details) => { * @param {String} networkName */ const sendTransaction = async (transaction, networkName) => { + // TODO:: add validation of input variables const { type } = transaction; const account = transaction[operationKeys[type]]; const options = formatToSend(type, transaction); @@ -684,7 +705,7 @@ const sendTransaction = async (transaction, networkName) => { const publicKeys = account.active.key_auths; const keyPromises = - await Promise.all(publicKeys.map((key) => crypto.getInByNetwork(networkName, key[0]))); + await Promise.all(publicKeys.map((key) => crypto.getInByNetwork(networkName, key[0]))); const indexPublicKey = keyPromises.findIndex((key) => !!key); @@ -714,8 +735,8 @@ export const onSend = async (options, networkName) => { await Promise.race([ sendTransaction(options, networkName) - .then(() => {}, (err) => { - console.warn('Broadcast transaction error', err); + .then(() => { }, (err) => { + console.error('Broadcast transaction error', err); if (err) { path = ERROR_SEND_PATH; } }).finally(() => new Date().getTime() - start), new Promise((resolve, reject) => { @@ -726,7 +747,7 @@ export const onSend = async (options, networkName) => { }), ]); } catch (err) { - console.warn('Broadcast transaction error', err); + console.error('Broadcast transaction error', err); path = NETWORK_ERROR_SEND_PATH; try { @@ -745,6 +766,32 @@ export const onSend = async (options, networkName) => { return null; }; +/** + * Update active account on all requested inpage + * @returns {Promise} + */ +const updateActiveAccountInpage = async (network) => { + try { + const account = await getActiveAccount(network); + notifyAllApprovedPorts(account, MESSAGE_METHODS.ACTIVE_ACCOUNT_SUBSCRIBE); + return null; + } catch (e) { + return { error: e.message }; + } +}; + +const onPinUnlock = () => { + resolveRequestAccount(ports); + resolveAccounts(ports); + updateActiveAccountInpage(); + return null; +}; + +const onLock = () => { + updateActiveAccountInpage(); + return null; +}; + /** * @method onSwitchNetwork * @@ -754,34 +801,22 @@ export const onSend = async (options, networkName) => { export const onSwitchNetwork = async (network) => { try { await createSocket(network.url); - updateActiveAccountInpage(network); } catch (e) { - console.warn('Switch network error', e); + console.error('Switch network error', e); } finally { - networkSubscribers.forEach(({ id, cb }) => { - try { - cb({ id, res: network }); - } catch (error) { - console.warn('Switch network callback error', error); - } - }); - networkSubscribers.splice(0, networkSubscribers.length); + updateActiveAccountInpage(network); + notifyAllApprovedPorts(network, MESSAGE_METHODS.SWITCH_NETWORK_SUBSCRIBE); } - }; - +/** + * @method onSwitchActiveAccount + * @param {*} res + */ const onSwitchActiveAccount = (res) => { updateActiveAccountInpage(); if (!res) return; - activeAccountSubscribers.forEach(({ id, cb }) => { - try { - cb({ id, res }); - } catch (error) { - console.warn('Switch account callback error', error); - } - }); - activeAccountSubscribers.splice(0, activeAccountSubscribers.length); + notifyAllApprovedPorts(res, MESSAGE_METHODS.SWITCH_ACCOUNT_SUBSCRIBE); }; /** @@ -791,52 +826,35 @@ const onSwitchActiveAccount = (res) => { * @param {String} id * @param {Boolean} status */ -export const onProviderApproval = (err, id, status) => { - const request = providerRequests.find(({ ids }) => String(ids[0]) === id); - - if (!request) { - return; - } - +export const onProviderApproval = (err, id, status, approvedOrigin) => { + approvedOrigins[approvedOrigin] = status; - request.ids.forEach((rId, index) => request.cbs[index]({ error: err, id: rId, status })); - - providerRequests = providerRequests.filter(({ ids }) => ids[0] !== request.ids[0]); - processedOrigins[request.origin] = status; + const portsToSend = ports.filter((portObj) => portObj.origin === approvedOrigin); + resolveProviderApprove(portsToSend, err); + updateActiveAccountInpage(); - if (!providerRequests.length) { + if (getProviderApprovalTaskCount() === 0) { closePopup(providerNotification); } try { emitter.emit('removeProviderRequest', id); } catch (e) { - // + console.warn('emit removeProviderRequest: ', e); } setBadge(); }; -const removeSignMessageRequest = (err, id, signature) => { - const request = signMessageRequests.find((r) => String(r.id) === id); - request.cb({ error: err, id: request.id, signature }); - - signMessageRequests = signMessageRequests.filter((p) => p.id !== request.id); - if (!signMessageRequests.length) { - closePopup(signNotification); - } - - setBadge(); - - try { - emitter.emit('removeSignMessageRequest', id); - } catch (e) { - // - } -}; - +/** + * @method signMessage + * @param {String} method + * @param {String} message + * @param {String} account + * @param {String} networkName + */ const signMessage = async (method, message, account, networkName) => { - if (method === 'proofOfAuthority') { + if (method === MESSAGE_METHODS.PROOF_OF_AUTHORITY) { const publicKey = account.keys[0]; const wif = await crypto.getWIFByPublicKey(networkName, publicKey); const privateKeyBuffer = PrivateKey.fromWif(wif).toBuffer(); @@ -844,7 +862,7 @@ const signMessage = async (method, message, account, networkName) => { return ED25519.signMessage(Buffer.from(message, 'utf8'), publicKeyBuffer, privateKeyBuffer); } - if (method === 'signData') { + if (method === MESSAGE_METHODS.SIGN_DATA) { const keys = await account.keys.reduce(async (promise, publicKey) => { const arr = await promise; const wif = await crypto.getWIFByPublicKey(networkName, publicKey); @@ -857,10 +875,41 @@ const signMessage = async (method, message, account, networkName) => { throw new Error('Method is not allowed'); }; -export const onSignMessageApproval = async (err, id, status, message, signer) => { +/** + * @method resolveSignMessageRequest + * @param {*} err + * @param {String} id + * @param {String} signature + */ +const resolveSignMessageRequest = (err, id, signature) => { + sendOnPortsViaId(ports, id, signature, err); + + if (getSignMessageTaskCount() === 0) { + closePopup(signNotification); + } + + setBadge(); + + try { + emitter.emit('removeSignMessageRequest', id); + } catch (e) { + // + } +}; + +/** + * @method onSignMessageApproval + * @param {*} err + * @param {String} id + * @param {String} status + * @param {String} message + * @param {String} signer + * @param {String} method + */ +export const onSignMessageApproval = async (err, id, status, message, signer, method) => { if (!status) { - removeSignMessageRequest(err, id); + resolveSignMessageRequest(err, id); return; } @@ -869,20 +918,61 @@ export const onSignMessageApproval = async (err, id, status, message, signer) => try { const accounts = await crypto.getInByNetwork(network.name, 'accounts') || []; const accountIndex = accounts.findIndex((i) => i.id === signer); - const request = signMessageRequests.find((i) => i.id === id); if (accountIndex >= 0) { const account = accounts[accountIndex]; - const signature = await signMessage(request.method, request.message, account, network.name); + const signature = await signMessage(method, message, account, network.name); const signatureHex = signature.toString('hex'); - removeSignMessageRequest(err, id, signatureHex); + resolveSignMessageRequest(err, id, signatureHex); } } catch (error) { - console.warn(error); + console.error(error); } }; +/** + * @method onPortConnect + * @param {Object} port + */ +const onPortConnect = (port) => { + const { sender } = port; + const { tab: { id, url } } = sender; + const { origin } = urlParse(url); + + // push object with `accessPermission`, `id` and `portObject` info + const portObj = { + origin, + id, + port, + pendingTasks: [], + addTask: function addTask(requestId, method, data) { + this.pendingTasks.push({ id: requestId, method, data }); + }, + }; + + // sometimes contentscript creates several instances of port connection + if (!ports.find((portItem) => portItem.id === id)) { + ports.push(portObj); + } + + const onMessageCb = (message) => onMessageHandler(message, portObj); + + const onDisconnectCb = () => { + port.onMessage.removeListener(onMessageCb); + port.onDisconnect.removeListener(onDisconnectCb); + + const portIndex = ports.findIndex((portItem) => portItem.id === id); + portObj.pendingTasks.forEach((item) => { + removeSigningTasks(item.id); + }); + ports.splice(portIndex, 1); + }; + + port.onMessage.addListener(onMessageCb); + port.onDisconnect.addListener(onDisconnectCb); +}; + const listeners = new Listeners(emitter, crypto); listeners.initBackgroundListeners( @@ -905,27 +995,51 @@ window.getList = () => requestQueue.map(({ id, data }) => ({ id, options: data } window.getPrivateKey = () => PrivateKey; window.getAes = () => aes; window.Transaction = () => Transaction; -window.getProviderMap = () => providerRequests.reduce((map, { ids: [reqId], origin }) => { - map[reqId] = origin; - return map; -}, {}); - -window.getSignMessageMap = () => signMessageRequests.reduce((map, { - id, origin, message, signer, method, -}) => { - map[id] = { - origin, - signer, - message: method === 'proofOfAuthority' ? message : message.toString('hex'), - }; - return map; -}, {}); +window.getProviderMap = () => { + const providerMap = {}; + ports.forEach(({ pendingTasks, origin }) => { + pendingTasks.forEach(({ id, method }) => { + if (method === MESSAGE_METHODS.GET_ACCESS) { + providerMap[id] = origin; + } + }); + }); + return providerMap; +}; -extensionizer.runtime.onMessage.addListener(onMessage); +window.getSignMessageMap = () => { + const providerMap = {}; + ports.forEach(({ pendingTasks, origin }) => { + pendingTasks.forEach(({ id, method, data }) => { + if ([MESSAGE_METHODS.SIGN_DATA, MESSAGE_METHODS.PROOF_OF_AUTHORITY].includes(method)) { + providerMap[id] = { + origin, + signer: data.signer, + message: method === MESSAGE_METHODS.PROOF_OF_AUTHORITY ? data.message : data.message.toString('hex'), + method, + }; + } + }); + }); + return providerMap; +}; crypto.on('unlocked', onPinUnlock); crypto.on('locked', onLock); + extensionizer.runtime.onInstalled.addListener(onFirstInstall); extensionizer.browserAction.setBadgeText({ text: 'BETA' }); + +extensionizer.runtime.onConnect.addListener(onPortConnect); + +/** + * The complete Triforce, or one or more components of the Triforce. + * @typedef {Object} PortObject + * @property {object} port + * @property {string} origin + * @property {function} addTask + * @property {number} id + * @property {[object]} pendingTasks + */ diff --git a/extension/contentscript.js b/extension/contentscript.js index baac121f..e20dc65c 100644 --- a/extension/contentscript.js +++ b/extension/contentscript.js @@ -1,44 +1,50 @@ /* global EXTENSION */ +/* global INPAGE_PATH_PACK_FOLDER */ const extensionizer = require('./extensionizer'); const { APP_ID } = require('../src/constants/GlobalConstants'); +/* eslint-disable global-require */ +/* eslint-disable import/no-dynamic-require */ +const inpage = require(`../${INPAGE_PATH_PACK_FOLDER}/inpage`); -const getAccessRequest = {}; +const inpageContent = inpage.default; +let currentPort; /** * inpage script injection to web page */ -function setupInjection() { +function setupInjection(content) { try { const scriptTag = document.createElement('script'); - - scriptTag.src = extensionizer.extension.getURL('inpage.js'); - scriptTag.onload = function () { - this.parentNode.removeChild(this); - }; + scriptTag.textContent = content; + scriptTag.setAttribute('async', false); const container = document.head || document.documentElement; container.insertBefore(scriptTag, container.children[0]); + container.removeChild(scriptTag); + // see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port + // the object for long-live exchanging of messages between page script and background.js + currentPort = extensionizer.runtime.connect(); } catch (e) { console.error('Bridge injection failed.', e); } } -// eslint-disable-next-line no-unused-expressions -EXTENSION && setupInjection(); - /** - * On background response - * @param res - * @param origin + * + * @param {Object} res + * @return {Promise} */ -const onResponse = (res, origin = '*') => { +const onBackgroundMessage = async (res) => { if (!res) { return null; } + const { origin } = res; + + delete res.origin; res.target = 'inpage'; res.appId = APP_ID; @@ -51,28 +57,13 @@ const onResponse = (res, origin = '*') => { * On Inpage message * @param event */ -const onMessage = async (event) => { - const { data, origin } = event; +const onPageMessage = (event) => { + const { data } = event; if (data.target !== 'content' || !data.appId || data.appId !== APP_ID) return; try { - if (data.method !== 'getAccess') { - extensionizer.runtime.sendMessage(data, (res) => onResponse(res, event.origin)); - return; - } - if (!getAccessRequest[origin]) { - getAccessRequest[origin] = new Promise((resolve) => { - extensionizer.runtime.sendMessage(data, (res) => { - onResponse(res, event.origin); - resolve(res); - }); - }); - } else { - const result = await getAccessRequest[origin]; - result.id = event.data.id; - onResponse(result, event.origin); - } + currentPort.postMessage(data); } catch (err) { if (err.message.match(/Invocation of form runtime\.connect/) && err.message.match(/doesn't match definition runtime\.connect/)) { console.error('Connection to background error, please reload the page', err); @@ -82,12 +73,12 @@ const onMessage = async (event) => { } }; -window.addEventListener('beforeunload', () => { - extensionizer.runtime.sendMessage({ - method: 'closeTab', - appId: APP_ID, - }); -}); -window.addEventListener('message', onMessage, false); +// eslint-disable-next-line no-unused-expressions +EXTENSION && setupInjection(inpageContent); + +// listen messages from inpage.js script injected in web page. Implemented with One-off messages +window.addEventListener('message', onPageMessage, false); +// listen messages from background.js script by. Implemented with Connection-based messaging +currentPort.onMessage.addListener(onBackgroundMessage); diff --git a/extension/inpage.js b/extension/inpage.js index 99207b23..8eaad4d3 100644 --- a/extension/inpage.js +++ b/extension/inpage.js @@ -1,3 +1,4 @@ +/* eslint-disable no-underscore-dangle */ import * as echojslib from 'echojs-lib'; import lodash from 'lodash'; @@ -7,6 +8,7 @@ import { MAX_RETRIES, PING_INTERVAL, PING_TIMEOUT, + MESSAGE_METHODS, } from '../src/constants/GlobalConstants'; import IdHelper from './IdHelper'; @@ -19,211 +21,33 @@ const accountChangedSubscribers = []; let activeAccount = null; -const INPAGE_ID = IdHelper.getId(); - -/** - * network subscription - * - */ -const networkSubscription = () => { - const id = IdHelper.getId(); - - const callback = ({ data }) => { - /** - * call all subscribers and repost subscription - */ - networkSubscribers.forEach((cb) => cb(data.res)); - networkSubscription(); - }; - - requestQueue.push({ id, cb: callback }); - - window.postMessage({ - method: 'networkSubscribe', target: 'content', appId: APP_ID, id, - }, '*'); -}; - -const accountSubscription = () => { - const id = IdHelper.getId(); - - const callback = ({ data }) => { - /** - * call all subscribers and repost subscription - */ - accountSubscribers.forEach((cb) => cb(data.res)); - accountSubscription(); - }; - - requestQueue.push({ id, cb: callback }); - - window.postMessage({ - method: 'accountSubscribe', target: 'content', appId: APP_ID, id, - }, '*'); -}; - /** - * Get current network - * @returns {Promise} + * @member dispatchNotifyResponse + * @description dispatch notify response that is received from background like switchNetwork, + * switchAccount, activeAccount + * @param {Object} eventData */ -const getCurrentNetwork = () => { - const id = IdHelper.getId(); - - const result = new Promise((resolve, reject) => { - const callback = ({ data }) => { - if (data.error) { - reject(data.error); - return; - } - - resolve(data.res); - }; - - requestQueue.push({ id, cb: callback }); - - window.postMessage({ - method: 'getNetwork', target: 'content', appId: APP_ID, id, - }, '*'); - }); +const dispatchNotifyResponse = (eventData) => { + const { method, res } = eventData; - return result; -}; - -/** - * subscribeSwitchNetwork to switch network - * @param subscriberCb - * @returns {Promise} - */ -const subscribeSwitchNetwork = (subscriberCb) => { - const id = IdHelper.getId(); - - const result = new Promise((resolve, reject) => { - if (!lodash.isFunction(subscriberCb)) { - reject(new Error('Is not a function')); - return; + switch (method) { + case MESSAGE_METHODS.SWITCH_NETWORK_SUBSCRIBE: { + networkSubscribers.forEach((cb) => cb(res)); + break; } - - const callback = ({ data }) => { - if (data.error) { - reject(data.error); - return; - } - - resolve(data.res); - - if (!networkSubscribers.length) { - networkSubscription(); - } - - networkSubscribers.push(subscriberCb); - subscriberCb(data.res); - }; - - requestQueue.push({ id, cb: callback }); - - window.postMessage({ - method: 'getNetwork', target: 'content', appId: APP_ID, id, - }, '*'); - }); - - return result; -}; - -/** - * Notify about switch account - * @param {Function} subscriberCb - * @returns {Promise} - */ -const subscribeAccountChanged = (subscriberCb) => { - - if (!lodash.isFunction(subscriberCb)) { - throw new Error('The first argument is not a function'); - } - - const id = IdHelper.getId(); - - const result = new Promise((resolve, reject) => { - - const callback = ({ data }) => { - - if (data.error) { - reject(data.error); - return; - } - - if (data.response) { - - accountChangedSubscribers.push(subscriberCb); - - resolve(activeAccount); - subscriberCb(activeAccount); - return; - } - - reject(new Error('No access')); - }; - - requestQueue.push({ id, cb: callback }); - - window.postMessage({ - method: 'checkAccess', target: 'content', appId: APP_ID, id, - }, '*'); - - }); - - return result; - - -}; - -/** - * @method notifyAccountChanged - * @param {String|null} accountId - */ -const notifyAccountChanged = (accountId) => { - accountChangedSubscribers.forEach((cb) => { - cb(accountId); - }); - -}; - -/** - * Notify about switch account - * @param {Function} subscriberCb - * @returns {Promise} - */ -const subscribeSwitchAccount = (subscriberCb) => { - const id = IdHelper.getId(); - - const result = new Promise((resolve, reject) => { - if (!lodash.isFunction(subscriberCb)) { - reject(new Error('Is not a function')); - return; + case MESSAGE_METHODS.SWITCH_ACCOUNT_SUBSCRIBE: { + accountSubscribers.forEach((cb) => cb(res)); + break; } + case MESSAGE_METHODS.ACTIVE_ACCOUNT_SUBSCRIBE: { + const error = eventData.error || (res && res.error); + activeAccount = error ? null : res; - const callback = ({ data }) => { - if (data.error) { - reject(data.error); - return; - } - - resolve(); - - if (!accountSubscribers.length) { - accountSubscription(); - } - - accountSubscribers.push(subscriberCb); - subscriberCb(data.res.find((account) => account.active)); - }; - - requestQueue.push({ id, cb: callback }); - - window.postMessage({ - method: 'accounts', target: 'content', appId: APP_ID, id, - }, '*'); - }); - - return result; + accountChangedSubscribers.forEach((cb) => cb(res)); + break; + } + default: break; + } }; echojslib.echo = echojslib.default; @@ -262,7 +86,7 @@ echojslib.echo.connect = (url, params) => { requestQueue.push({ id, cb }); window.postMessage({ - method: 'getNetwork', id, target: 'content', appId: APP_ID, + method: MESSAGE_METHODS.GET_NETWORK, id, target: 'content', appId: APP_ID, }, '*'); }); @@ -272,87 +96,31 @@ echojslib.echo.connect = (url, params) => { /** * On content script message + * @method onMessage * @param event */ const onMessage = (event) => { const { id, target, appId } = event.data; - if (!id || target !== 'inpage' || !appId || appId !== APP_ID) return; - - const requestIndex = requestQueue.findIndex(({ id: requestId }) => requestId === id); - if (requestIndex === -1) return; - - const request = requestQueue.splice(requestIndex, 1); - request[0].cb(event); - -}; - - -/** - * Send custom transaction - * @param options - * @returns {Promise} - */ -const sendTransaction = (options) => { - const id = IdHelper.getId(); - - const result = new Promise((resolve, reject) => { - const cb = ({ data }) => { - - const { status, text, resultBroadcast } = data; - - if (status === 'approved') { - resolve({ status, resultBroadcast }); - } else { - reject(data.error || text || status); - } - }; - requestQueue.push({ id, cb }); - window.postMessage({ - method: 'confirm', data: options, id, target: 'content', appId: APP_ID, - }, '*'); - - }); + if (target !== 'inpage' || !appId || appId !== APP_ID) return; - return result; - -}; - - -/** - * Get user account if unlocked - * @returns {Promise} - */ -const getAccounts = () => { - const id = IdHelper.getId(); + if (!id) { + dispatchNotifyResponse(event.data); + } else { + const requestIndex = requestQueue.findIndex(({ id: requestId }) => requestId === id); + if (requestIndex === -1) return; - const result = new Promise((resolve, reject) => { - - const cb = ({ data }) => { - if (data.error || data.res.error) { - reject(data.error || data.res.error); - } else { - resolve(data.res); - } - }; - - requestQueue.push({ id, cb }); - window.postMessage({ - method: 'accounts', id, target: 'content', appId: APP_ID, - }, '*'); - - }); - - return result; + const request = requestQueue.splice(requestIndex, 1); + request[0].cb(event); + } }; - /** * @method backgroundRequest * @param {String} method */ -const backgroundRequest = (method) => { +const backgroundRequest = (method, requestData) => { const id = `${method}_${IdHelper.getId()}`; const result = new Promise((resolve, reject) => { @@ -368,7 +136,7 @@ const backgroundRequest = (method) => { requestQueue.push({ id, cb }); window.postMessage({ - method, id, target: 'content', appId: APP_ID, + method, id, target: 'content', appId: APP_ID, data: requestData, }, '*'); }); @@ -376,134 +144,124 @@ const backgroundRequest = (method) => { return result; }; -const requestAccount = () => backgroundRequest('requestAccount'); /** - * Load active bridge account - * @returns {undefined} + * @method requestAccount */ -const loadActiveAccount = () => { +const requestAccount = () => backgroundRequest(MESSAGE_METHODS.REQUEST_ACCOUNT); - const cb = ({ data }) => { - - const id = IdHelper.getId(); +/** + * @method getAccounts + */ +const getAccounts = () => backgroundRequest(MESSAGE_METHODS.ACCOUNTS); - window.postMessage({ - method: 'getActiveAccount', id, target: 'content', appId: APP_ID, inPageId: INPAGE_ID, - }, '*'); +/** + * @method getCurrentNetwork + */ +const getCurrentNetwork = () => backgroundRequest(MESSAGE_METHODS.GET_NETWORK); - const error = data.error || (data.res && data.res.error); +/** + * @method checkAccess + */ +const checkAccess = () => backgroundRequest(MESSAGE_METHODS.CHECK_ACCESS); - const prevAccount = activeAccount; +/** + * @method getActiveAccount + */ +const getActiveAccount = () => backgroundRequest(MESSAGE_METHODS.GET_ACTIVE_ACCOUNT); - if (error) { - activeAccount = null; - } else { - activeAccount = data.res; - requestQueue.push({ id, cb }); - } - if (prevAccount !== activeAccount) { - notifyAccountChanged(activeAccount); - } +/** + * @method getAccess + */ +const getAccess = () => backgroundRequest(MESSAGE_METHODS.GET_ACCESS); - }; +/** + * @method proofOfAuthority + * @param {string} message + * @param {string} accountId + */ +const proofOfAuthority = async (message, accountId) => { + if (typeof message !== 'string') throw new Error('message is not a string'); + return backgroundRequest(MESSAGE_METHODS.PROOF_OF_AUTHORITY, { message, accountId }); +}; - const id = IdHelper.getId(); +/** + * @method signData + * @param {string} message + * @param {string} accountId + */ +const signData = async (message, accountId) => { + if (!Buffer.isBuffer(message)) throw new Error('Message isn\'t a Buffer'); + return backgroundRequest(MESSAGE_METHODS.SIGN_DATA, { message: message.toString('hex'), accountId }); +}; - requestQueue.push({ id, cb }); - window.postMessage({ - method: 'getActiveAccount', id, target: 'content', appId: APP_ID, inPageId: INPAGE_ID, - }, '*'); +/** + * @method loadActiveAccount + */ +const loadActiveAccount = async () => { + const isAccess = await checkAccess(); + if (isAccess) { + const account = await getActiveAccount(); + activeAccount = account; + } }; -const proofOfAuthority = (message, accountId) => { - const id = IdHelper.getId(); - const result = new Promise((resolve, reject) => { - const cb = ({ data }) => { - if (data.error) { - reject(data.error); - } else { - resolve(data.signature); - } - }; +/** + * @method sendTransaction + * @param {string} message + * @param {string} accountId + */ +const sendTransaction = async (options) => { + const result = await backgroundRequest(MESSAGE_METHODS.CONFIRM, JSON.stringify(options)); + return JSON.parse(result); +}; - requestQueue.push({ id, cb }); - window.postMessage({ - method: 'proofOfAuthority', - id, - data: { message, accountId }, - target: 'content', - appId: APP_ID, - }, '*'); +/** + * @method subscribeSwitchAccount + * @param {function} subscriberCb + */ +const subscribeSwitchAccount = async (subscriberCb) => { + if (!lodash.isFunction(subscriberCb)) throw new Error('Is not a function'); - }); + const result = await getAccounts(); + accountSubscribers.push(subscriberCb); + subscriberCb(result); return result; }; -const signData = (message, accountId) => { - const id = IdHelper.getId(); - const result = new Promise((resolve, reject) => { - - if (!Buffer.isBuffer(message)) { - reject(new Error('Message isn\'t a Buffer')); - return; - } - - const cb = ({ data }) => { - if (data.error) { - reject(data.error); - } else { - resolve(data.signature); - } - }; - - requestQueue.push({ id, cb }); - window.postMessage({ - method: 'signData', - id, - data: { - message: message.toString('hex'), - accountId, - }, - target: 'content', - appId: APP_ID, - }, '*'); +/** + * @method subscribeSwitchNetwork + * @param {function} subscriberCb + */ +const subscribeSwitchNetwork = async (subscriberCb) => { + if (!lodash.isFunction(subscriberCb)) throw new Error('Is not a function'); - }); + const result = await getCurrentNetwork(); + networkSubscribers.push(subscriberCb); + subscriberCb(result); return result; }; /** - * Get provider approval - * @returns {Promise} + * @method subscribeAccountChanged + * @param {function} subscriberCb */ -const getAccess = () => { - const id = IdHelper.getId(); +const subscribeAccountChanged = async (subscriberCb) => { + if (!lodash.isFunction(subscriberCb)) throw new Error('Is not a function'); - const result = new Promise((resolve, reject) => { + const access = await checkAccess(); + subscriberCb(activeAccount); - const cb = ({ data }) => { - if (data.error) { - reject(data.error); - } else { - loadActiveAccount(); - resolve(data.status); - } - }; - - requestQueue.push({ id, cb }); - window.postMessage({ - method: 'getAccess', id, target: 'content', appId: APP_ID, - }, '*'); - - }); + if (access) { + accountChangedSubscribers.push(subscriberCb); + return activeAccount; + } - return result; + return null; }; - class Signat { /** @@ -538,18 +296,18 @@ echojslib.Transaction.prototype.signWithBridge = async function signWithBridge() return; } - const signData = JSON.parse(data.signData); + const signResult = JSON.parse(data.res); if (this._operations[0][1].from) { - this._operations[0][1].from = signData.accountId; + this._operations[0][1].from = signResult.accountId; } else if (this._operations[0][1].registrar) { - this._operations[0][1].registrar = signData.accountId; + this._operations[0][1].registrar = signResult.accountId; } - this._refBlockNum = signData.ref_block_num; - this._refBlockPrefix = signData.ref_block_prefix; - this._expiration = signData.expiration; - this._signatures = signData.serializedSignatures.map((hexString) => new Signat(hexString)); + this._refBlockNum = signResult.ref_block_num; + this._refBlockPrefix = signResult.ref_block_prefix; + this._expiration = signResult.expiration; + this._signatures = signResult.serializedSignatures.map((hexString) => new Signat(hexString)); this._finalized = true; @@ -561,7 +319,7 @@ echojslib.Transaction.prototype.signWithBridge = async function signWithBridge() const operations = JSON.stringify(this._operations); window.postMessage({ - method: 'confirm', + method: MESSAGE_METHODS.CONFIRM, data: operations, id, target: 'content', diff --git a/libs/CustomAwaitEmitter.js b/libs/CustomAwaitEmitter.js index 80df477e..3db8bbb4 100644 --- a/libs/CustomAwaitEmitter.js +++ b/libs/CustomAwaitEmitter.js @@ -35,86 +35,88 @@ function onceListener(fn) { } function AwaitEventEmitter() { - this._events = {}; + this.events = {}; } function on(type, fn) { assertType(type); assertFn(fn); - this._events[type] = this._events[type] || []; - this._events[type].push(alwaysListener(fn)); + this.events[type] = this.events[type] || []; + this.events[type].push(alwaysListener(fn)); return this; } function prepend(type, fn) { assertType(type); assertFn(fn); - this._events[type] = this._events[type] || []; - this._events[type].unshift(alwaysListener(fn)); + this.events[type] = this.events[type] || []; + this.events[type].unshift(alwaysListener(fn)); return this; } function prependOnce(type, fn) { assertType(type); assertFn(fn); - this._events[type] = this._events[type] || []; - this._events[type].unshift(onceListener(fn)); + this.events[type] = this.events[type] || []; + this.events[type].unshift(onceListener(fn)); return this; } function listeners(type) { - return (this._events[type] || []).map((x) => x.fn); + return (this.events[type] || []).map((x) => x.fn); } function once(type, fn) { assertType(type); assertFn(fn); - this._events[type] = this._events[type] || []; - this._events[type].push(onceListener(fn)); + this.events[type] = this.events[type] || []; + this.events[type].push(onceListener(fn)); return this; } function removeListener(type, nullOrFn) { assertType(type); - const listeners = this.listeners(type); + const listenersItems = this.listeners(type); if (typeof nullOrFn === 'function') { - let index, - found = false; - while ((index = listeners.indexOf(nullOrFn)) >= 0) { - listeners.splice(index, 1); - this._events[type].splice(index, 1); + let index; + let found = false; + /* eslint-disable no-cond-assign */ + while ((index = listenersItems.indexOf(nullOrFn)) >= 0) { + listenersItems.splice(index, 1); + this.events[type].splice(index, 1); found = true; } return found; } - return delete this._events[type]; + return delete this.events[type]; } function removeAllListeners() { - Object.keys(this._events).forEach((eventType) => delete this._events[eventType]); + Object.keys(this.events).forEach((eventType) => delete this.events[eventType]); return true; } async function emit(type, ...args) { assertType(type); - const listeners = this.listeners(type); + const listenersItems = this.listeners(type); const onceListeners = []; - if (listeners && listeners.length) { - for (let i = 0; i < listeners.length; i++) { - const event = listeners[i]; + if (listenersItems && listenersItems.length) { + for (let i = 0; i < listenersItems.length; i += 1) { + const event = listenersItems[i]; try { const rlt = event.apply(this, args); if (isPromise(rlt)) { + /* eslint-disable no-await-in-loop */ await rlt; } - if (this._events[type][i][TYPE_KEYNAME] === 'once') { + if (this.events[type][i][TYPE_KEYNAME] === 'once') { onceListeners.push(event); } } catch (e) { @@ -132,14 +134,14 @@ async function emit(type, ...args) { function emitSync(type, ...args) { assertType(type); - const listeners = this.listeners(type); + const listenersItems = this.listeners(type); const onceListeners = []; - if (listeners && listeners.length) { - for (let i = 0; i < listeners.length; i++) { - const event = listeners[i]; + if (listenersItems && listenersItems.length) { + for (let i = 0; i < listenersItems.length; i += 1) { + const event = listenersItems[i]; event.apply(this, args); - if (this._events[type][i][TYPE_KEYNAME] === 'once') { + if (this.events[type][i][TYPE_KEYNAME] === 'once') { onceListeners.push(event); } } @@ -151,11 +153,13 @@ function emitSync(type, ...args) { return false; } -AwaitEventEmitter.prototype.on = AwaitEventEmitter.prototype.addListener = on; +AwaitEventEmitter.prototype.on = on; +AwaitEventEmitter.prototype.addListener = on; AwaitEventEmitter.prototype.once = once; AwaitEventEmitter.prototype.prependListener = prepend; AwaitEventEmitter.prototype.prependOnceListener = prependOnce; -AwaitEventEmitter.prototype.off = AwaitEventEmitter.prototype.removeListener = removeListener; +AwaitEventEmitter.prototype.off = removeListener; +AwaitEventEmitter.prototype.removeListener = removeListener; AwaitEventEmitter.prototype.removeAllListeners = removeAllListeners; AwaitEventEmitter.prototype.emit = emit; AwaitEventEmitter.prototype.emitSync = emitSync; diff --git a/package.json b/package.json index 167b0541..e5c38b70 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,14 @@ { "name": "echo-bridge", "description": "The bridge between your web site and the Echo", - "version": "1.14.0", + "version": "1.15.0", "scripts": { - "start": "cross-env NODE_ENV=local webpack-dev-server --mode development --progress --colors --history-api-fallback --hot --inline --port 8081", "build": "cross-env NODE_ENV=production webpack --progress --display-error-details --colors --mode production", "build-ext": "cross-env EXTENSION=TRUE NODE_ENV=production webpack --display-error-details --colors --mode production", "build-ext-dev": "cross-env EXTENSION=TRUE NODE_ENV=development webpack --progress --display-error-details --colors --mode development", "build-dev": "cross-env NODE_ENV=development webpack --progress --display-error-details --colors --mode production", "build-stage": "cross-env NODE_ENV=stage webpack --progress --display-error-details --colors --mode production", - "lint": "$(npm bin)/eslint 'src/**/*.jsx' 'src/**/*.js'", + "lint": "$(npm bin)/eslint 'src/**/*.jsx' 'src/**/*.js' 'extension/**/*.js' 'libs/**/*.js'", "lint-win": "cross-env eslint 'src/**/*.jsx' 'src/**/*.js' --fix", "copy-manifest": "copyfiles -f config/manifest.json build/src", "test": "echo \"should run tests\"" @@ -24,7 +23,8 @@ "classnames": "^2.2.6", "config": "^1.30.0", "crypto-random-string": "^1.0.0", - "echojs-lib": "^1.9.3", + "echojs-lib": "^1.9.5", + "echojs-ping": "^0.1.7", "events": "^3.0.0", "file-loader": "^1.1.11", "focus-trap-react": "^4.0.1", @@ -87,6 +87,7 @@ "html-webpack-plugin": "^3.0.4", "img-loader": "^2.0.1", "node-sass": "^4.7.2", + "raw-loader": "^3.1.0", "sass-loader": "^6.0.7", "style-loader": "^0.20.2", "url-loader": "^1.0.1", diff --git a/src/actions/GlobalActions.js b/src/actions/GlobalActions.js index 84b46492..370c7dfe 100644 --- a/src/actions/GlobalActions.js +++ b/src/actions/GlobalActions.js @@ -9,6 +9,7 @@ import { setFormError, setValue, toggleLoading } from './FormActions'; import { disconnect, connect, checkActiveLoading } from './ChainStoreAction'; import { getTokenDetails, initAssetsBalances, removeBalances } from './BalanceActions'; import { globals, loadRequests } from './SignActions'; +import { initHistory } from './HistoryActions'; import ValidateNetworkHelper from '../helpers/ValidateNetworkHelper'; import FormatHelper from '../helpers/FormatHelper'; @@ -18,12 +19,7 @@ import GlobalReducer from '../reducers/GlobalReducer'; import echoService from '../services/echo'; import { - ACCOUNT_COLORS, - BASE_ICON, - BASE_ICON_COLOR, DRAFT_STORAGE_KEY, - ICON_COLORS_COUNT, - ICONS_COUNT, NETWORKS, POPUP_WINDOW_TYPE, CONTRACT_PREFIX, @@ -115,8 +111,12 @@ export const loadSignMessageRequests = () => (dispatch) => { * Add new sign message request * */ -export const addSignMessageRequest = (id, origin, signer, message) => (dispatch) => { - dispatch(setIn('signMessageRequests', { [id]: { origin, signer, message } })); +export const addSignMessageRequest = (id, origin, signer, message, method) => (dispatch) => { + dispatch(setIn('signMessageRequests', { + [id]: { + origin, signer, message, method, + }, + })); }; /** @@ -184,12 +184,12 @@ export const removeProviderRequest = (id) => (dispatch) => { * @param {String} id * @param {Boolean} status */ -export const chooseProviderAccess = (id, status) => (dispatch) => { +export const chooseProviderAccess = (id, status, origin) => (dispatch) => { const emitter = echoService.getEmitter(); try { const error = status ? null : { isAccess: false }; - emitter.emit('providerResponse', error, id, status); + emitter.emit('providerResponse', error, id, status, origin); } catch (err) { dispatch(set('error', FormatHelper.formatError(err))); } @@ -203,12 +203,12 @@ export const chooseProviderAccess = (id, status) => (dispatch) => { * @param {String} id * @param {Boolean} status */ -export const chooseSignMessageResponse = (id, status, message, signer) => (dispatch) => { +export const chooseSignMessageResponse = (id, status, message, signer, method) => (dispatch) => { const emitter = echoService.getEmitter(); try { const error = status ? null : SIGN_MEASSAGE_CANCELED; - emitter.emit('signMessageResponse', error, id, status, message, signer); + emitter.emit('signMessageResponse', error, id, status, message, signer, method); } catch (err) { dispatch(set('error', FormatHelper.formatError(err))); } @@ -234,6 +234,7 @@ export const initAccount = ({ name, icon, iconColor }) => async (dispatch) => { }))); await dispatch(initAssetsBalances()); + await dispatch(initHistory()); } catch (err) { dispatch(set('error', FormatHelper.formatError(err))); } finally { @@ -277,25 +278,17 @@ export const addAccount = (name, keys, networkName, path) => async (dispatch, ge accounts = accounts.set(networkName, accounts.get(networkName).map((i) => ({ ...i, active: false }))); - let icon = BASE_ICON; - let iconColor = BASE_ICON_COLOR; - - if (accounts.get(networkName).size) { - icon = Math.floor(Math.random() * ICONS_COUNT) + 1; - iconColor = ACCOUNT_COLORS[Math.floor(Math.random() * ICON_COLORS_COUNT)]; - } - accounts = accounts.set(networkName, accounts.get(networkName).push({ - id: account.id, active: true, icon, iconColor, name, keys, + id: account.id, active: true, name, keys, })); await dispatch(setCryptoInfo('accounts', accounts.get(networkName), networkName)); dispatch(set('accounts', accounts)); - await dispatch(initAccount({ name, icon, iconColor })); + await dispatch(initAccount({ name })); emitter.emit('activeAccountResponse', { - id: account.id, active: true, icon, iconColor, name, keys, + id: account.id, active: true, name, keys, }); if (path) { diff --git a/src/assets/fonts/futura/futuramedium.eot b/src/assets/fonts/futura/futuramedium.eot new file mode 100644 index 00000000..ad8b13e5 Binary files /dev/null and b/src/assets/fonts/futura/futuramedium.eot differ diff --git a/src/assets/fonts/futura/futuramedium.otf b/src/assets/fonts/futura/futuramedium.otf new file mode 100644 index 00000000..bd56f4ea Binary files /dev/null and b/src/assets/fonts/futura/futuramedium.otf differ diff --git a/src/assets/fonts/futura/futuramedium.svg b/src/assets/fonts/futura/futuramedium.svg new file mode 100644 index 00000000..024370d7 --- /dev/null +++ b/src/assets/fonts/futura/futuramedium.svg @@ -0,0 +1,1361 @@ + + + + +Created by FontForge 20170924 at Tue Nov 17 22:55:15 1992 + By www-data +Copyright 1990-1993 Bitstream Inc. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/fonts/futura/futuramedium.ttf b/src/assets/fonts/futura/futuramedium.ttf new file mode 100644 index 00000000..5b1c0239 Binary files /dev/null and b/src/assets/fonts/futura/futuramedium.ttf differ diff --git a/src/assets/fonts/futura/futuramedium.woff b/src/assets/fonts/futura/futuramedium.woff new file mode 100644 index 00000000..6f3864b0 Binary files /dev/null and b/src/assets/fonts/futura/futuramedium.woff differ diff --git a/src/assets/fonts/futura/futuramedium.woff2 b/src/assets/fonts/futura/futuramedium.woff2 new file mode 100644 index 00000000..dce7c6a3 Binary files /dev/null and b/src/assets/fonts/futura/futuramedium.woff2 differ diff --git a/src/assets/images/avatars/ava1.svg b/src/assets/images/avatars/ava1.svg deleted file mode 100644 index 1d882eff..00000000 --- a/src/assets/images/avatars/ava1.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava10.svg b/src/assets/images/avatars/ava10.svg deleted file mode 100644 index bcc601ab..00000000 --- a/src/assets/images/avatars/ava10.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - diff --git a/src/assets/images/avatars/ava11.svg b/src/assets/images/avatars/ava11.svg deleted file mode 100644 index af947f82..00000000 --- a/src/assets/images/avatars/ava11.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - diff --git a/src/assets/images/avatars/ava12.svg b/src/assets/images/avatars/ava12.svg deleted file mode 100644 index 6eefc1db..00000000 --- a/src/assets/images/avatars/ava12.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - diff --git a/src/assets/images/avatars/ava13.svg b/src/assets/images/avatars/ava13.svg deleted file mode 100644 index 54095267..00000000 --- a/src/assets/images/avatars/ava13.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava14.svg b/src/assets/images/avatars/ava14.svg deleted file mode 100644 index cded8f0c..00000000 --- a/src/assets/images/avatars/ava14.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/src/assets/images/avatars/ava15.svg b/src/assets/images/avatars/ava15.svg deleted file mode 100644 index 621f1fb8..00000000 --- a/src/assets/images/avatars/ava15.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava2.svg b/src/assets/images/avatars/ava2.svg deleted file mode 100644 index 11bff768..00000000 --- a/src/assets/images/avatars/ava2.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava3.svg b/src/assets/images/avatars/ava3.svg deleted file mode 100644 index aff7157d..00000000 --- a/src/assets/images/avatars/ava3.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - diff --git a/src/assets/images/avatars/ava4.svg b/src/assets/images/avatars/ava4.svg deleted file mode 100644 index 50c44bcb..00000000 --- a/src/assets/images/avatars/ava4.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava5.svg b/src/assets/images/avatars/ava5.svg deleted file mode 100644 index 25f5860c..00000000 --- a/src/assets/images/avatars/ava5.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - diff --git a/src/assets/images/avatars/ava6.svg b/src/assets/images/avatars/ava6.svg deleted file mode 100644 index 9f8b9395..00000000 --- a/src/assets/images/avatars/ava6.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava7.svg b/src/assets/images/avatars/ava7.svg deleted file mode 100644 index 113578f0..00000000 --- a/src/assets/images/avatars/ava7.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava8.svg b/src/assets/images/avatars/ava8.svg deleted file mode 100644 index feca521f..00000000 --- a/src/assets/images/avatars/ava8.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/src/assets/images/avatars/ava9.svg b/src/assets/images/avatars/ava9.svg deleted file mode 100644 index 3697f88d..00000000 --- a/src/assets/images/avatars/ava9.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/src/assets/images/default-avatar.svg b/src/assets/images/default-avatar.svg new file mode 100644 index 00000000..ceee4e82 --- /dev/null +++ b/src/assets/images/default-avatar.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/scss/_fonts.scss b/src/assets/scss/_fonts.scss index 43d61080..3fc7af97 100644 --- a/src/assets/scss/_fonts.scss +++ b/src/assets/scss/_fonts.scss @@ -22,3 +22,9 @@ font-family: FNMedium; src: url('../fonts/FuturaNew/FuturaNewMedium.ttf') format('opentype'); } + + +@font-face { + font-family: FMedium; + src: url('../fonts/futura/futuramedium.ttf') format('opentype'); +} diff --git a/src/assets/scss/components/_all.scss b/src/assets/scss/components/_all.scss index 1964caed..b46414d8 100644 --- a/src/assets/scss/components/_all.scss +++ b/src/assets/scss/components/_all.scss @@ -3,4 +3,5 @@ @import "transactionStatus"; @import "checkbox"; @import "sidebar"; -@import "modal"; \ No newline at end of file +@import "modal"; +@import "avatar"; diff --git a/src/assets/scss/components/_avatar.scss b/src/assets/scss/components/_avatar.scss new file mode 100644 index 00000000..d4ed092d --- /dev/null +++ b/src/assets/scss/components/_avatar.scss @@ -0,0 +1,9 @@ +.avatar-image { + svg { + border-radius: 50%; + } +} + +img.avatar-image { + border-radius: 50%; +} \ No newline at end of file diff --git a/src/assets/scss/elements/_all.scss b/src/assets/scss/elements/_all.scss index cf4acbb0..0a93d9bc 100644 --- a/src/assets/scss/elements/_all.scss +++ b/src/assets/scss/elements/_all.scss @@ -1,9 +1,7 @@ @import "btn"; @import "input"; @import "link"; -@import "list"; @import "wrap"; -@import "icons"; @import "dropdown"; @import "dropdownNetworks"; @import "dropdownUsers"; diff --git a/src/assets/scss/elements/_btn.scss b/src/assets/scss/elements/_btn.scss index 4cb1d56d..9e355286 100644 --- a/src/assets/scss/elements/_btn.scss +++ b/src/assets/scss/elements/_btn.scss @@ -579,92 +579,6 @@ .button { - &[class*="select-"] { - padding: 0; - border-radius: 50%; - width: 38px; - height: 38px; - position: relative; - border: 0; - background-color: transparent; - border: 1px solid transparent; - cursor: pointer; - transition: - background-color $speed, - border $speed; - - &:hover { - &:not(.active) { - border: 1px solid #b7bdbf; - } - } - &:focus { - &:not(:active) { - border: 1px solid #b7bdbf; - } - } - &.active { - background-color: #fff; - box-shadow: - 0 -3px 6px rgba(#3f4c4e,0.06), - 0 3px 6px rgba(#3f4c4e,0.06); - } - &:before { - width: 22px; - height: 22px; - position: absolute; - right: 0; - left: 0; - top: 0; - bottom: 0; - margin: auto; - content: ""; - border-radius: 50%; - } - } - &.select { - &-green { - &:before { - background-color:#64d3ad; - } - } - - &-sky { - &:before { - background-color: #76c5d3; - } - } - - &-blue { - &:before { - background-color: #7683d3; - } - } - - &-pink { - &:before { - background-color: #b989cf; - } - } - - &-red { - &:before { - background-color: #d36496; - } - } - - &-yellow { - &:before { - background-color: #d3c564; - } - } - - &-lemon { - &:before { - background-color: #cbd376; - } - } - } .btn-close { padding: 0; height: 40px; @@ -677,19 +591,17 @@ } .modal { - .btn { - &-transparent { - color: rgba(#fff, .7); - - &:not(.disabled) { - &:not(:active) { - @include onBtnFocus ( - $angularMax, - 2px, - 2px, - rgba(#fff, .15) - ); - } + .btn-transparent { + color: rgba(#fff, .7); + + &:not(.disabled) { + &:not(:active) { + @include onBtnFocus ( + $angularMax, + 2px, + 2px, + rgba(#fff, .15) + ); } } } diff --git a/src/assets/scss/elements/_dropdown.scss b/src/assets/scss/elements/_dropdown.scss index b0187c02..24e8fb20 100644 --- a/src/assets/scss/elements/_dropdown.scss +++ b/src/assets/scss/elements/_dropdown.scss @@ -13,7 +13,6 @@ @mixin onToggleFocus ($color) { position: relative; - @include hardwareAccel(); &:before { @@ -53,7 +52,7 @@ } } } - &-menu { + .dropdown-menu { .user-icon-wrap { transition: opacity .2s ease; opacity: 0.8; @@ -77,8 +76,7 @@ } } } - &-toggle { - + .dropdown-toggle { .ddDown { opacity: .4; transition: opacity $speed; diff --git a/src/assets/scss/elements/_dropdownNetworks.scss b/src/assets/scss/elements/_dropdownNetworks.scss index 3fb25e17..26b3da7e 100644 --- a/src/assets/scss/elements/_dropdownNetworks.scss +++ b/src/assets/scss/elements/_dropdownNetworks.scss @@ -1,5 +1,4 @@ .dropdown-network { - margin-left: auto; .dropdown { &-toggle { @@ -104,7 +103,6 @@ } } - a { display: flex; align-items: center; diff --git a/src/assets/scss/elements/_icons.scss b/src/assets/scss/elements/_icons.scss deleted file mode 100644 index b6a25af9..00000000 --- a/src/assets/scss/elements/_icons.scss +++ /dev/null @@ -1,271 +0,0 @@ -.user-icon-wrap { - - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - position: relative; - background-color: transparent; - padding: 0; - border: 0; - - .content { - display: flex; - align-items: center; - justify-content: center; - } - &.small { - .content { - height: 22px; - width: 22px; - img { - width: 16px; - } - } - } - - &.medium { - .content { - width: 42px; - height: 42px; - } - img { - width: 32px; - } - } - - &.big { - width: 86px; - height: 86px; - img { - width: 40px; - margin-bottom: 2px; - } - } - - - - &.select { - min-width: 60px; - height: 60px; - cursor: pointer; - transition: - background-color $speed, - box-shadow $speed, - border $speed; - border: 1px solid transparent; - - .content { - pointer-events: none; - img { - width: 36px; - opacity: .3; - transition: opacity $speed; - } - } - &:hover, - &:focus { - .content { - img { - opacity: .7; - } - } - - } - &.active { - box-shadow: - 0 -3px 6px rgba(#3f4c4e,0.06), - 0 3px 6px rgba(#3f4c4e,0.06); - background-color: #fff; - .content { - img { - opacity: 1; - } - } - } - &:hover, - &:focus { - &:not(.active) { - border: 1px solid #b7bdbf; - } - } - } - - &.transparent { - background-color: transparent; - } - - &.green { - background-color:#16d6aa; - } - - &.sky { - background-color: #76c5d3; - } - - &.blue { - background-color: #7683d3; - } - - &.pink { - background-color: #b989cf; - } - - &.red { - background-color: #d36496; - } - - &.yellow { - background-color: #d3c564; - } - - &.lemon { - background-color: #cbd376; - } - - - - &.change-animation { - - opacity: 1; - - .content { - transition: opacity $speed; - } - .animation-blobs { - cursor: pointer; - transition: box-shadow $speed; - &:active { - background-color: rgba(#3e4b4e, .2); - } - &:hover, - &:focus { - transition: box-shadow $speed; - box-shadow: - 0 -3px 8px rgba(#3f4c4e,0.2), - 0 3px 8px rgba(#3f4c4e,0.2); - } - - } - .blob { - width: 4px; - height: 4px; - border-radius: 50%; - position: absolute; - margin: auto; - top: auto; - bottom: 13px; - background-color: rgba(#405051, .4); - will-change: contents; - transition: - transform $speed ease, - border .1s ease, - width .1s ease, - background-color $speed ease; - - &:first-child { - left:0; - right: 0; - transform: translate(5px, 0); - } - &:last-child { - left: 0; - right: 0; - transform: translate(-5px, 0); - } - } - &:hover { - .blob { - border-radius: 0; - height: 2px; - width: 16px; - background-color: #405051; - bottom: 15px; - &:first-child { - transform: translate(0, 0); - } - &:last-child { - transform: translate(0, 0); - } - } - .animation-text { - display: flex; - } - .content { - opacity: .2; - } - } - } - - &.back-animation { - - .animation-blobs { - height: auto; - width: auto; - cursor: pointer; - top: 0; - bottom: 0; - transition: box-shadow $speed, background-color $speed; - &:active { - background-color: rgba(#3f4c4e,0.1); - } - &:hover, - &:focus { - box-shadow: - 0 -3px 8px rgba(#3f4c4e,0.2), - 0 3px 8px rgba(#3f4c4e,0.2); - } - } - .blob { - height: 2px; - width: 16px; - border-radius: 1px; - right: 0; - left: 0; - top: auto; - bottom: 23px; - background-color: #405051; - position: absolute; - margin: auto; - &:first-child { - transform: rotate(45deg); - } - &:last-child { - transform: rotate(-45deg); - } - } - } - - -} - -.animation-blobs { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - margin: auto; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; -} - -.animation-text { - animation: fadeInUp .4s; - position: absolute; - right: 0; - left: 4px; - top: -1px; - bottom: 0; - display: none; - align-items: center; - justify-content: center; - text-align: center; - color: #3E4851; - font-family: FNBook; - font-size: 14px; - letter-spacing: .3px; - user-select: none; -} \ No newline at end of file diff --git a/src/assets/scss/elements/_input.scss b/src/assets/scss/elements/_input.scss index 1e377966..f1280c93 100644 --- a/src/assets/scss/elements/_input.scss +++ b/src/assets/scss/elements/_input.scss @@ -6,10 +6,14 @@ z-index: 2; font-family: FNMedium; font-size: 18px; - transition: color $speed, padding $speed; - padding: 0; - letter-spacing: .13em; + padding: 0; + letter-spacing: 0.8px; + + &[type='password'] { + font-size: 16px; + font-family: FMedium; + } } .input { @@ -339,8 +343,8 @@ } input { - cursor: pointer; @extend %input; + cursor: pointer; height: 42px; &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ diff --git a/src/assets/scss/elements/_list.scss b/src/assets/scss/elements/_list.scss deleted file mode 100644 index 24c3c549..00000000 --- a/src/assets/scss/elements/_list.scss +++ /dev/null @@ -1,22 +0,0 @@ -.list-avatars { - display: flex; - flex-wrap: wrap; - margin: 0 auto; - padding: 26px 0 0; - max-width: 320px; - li { - width: 20%; - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 3px; - } -} - -.list-colors { - max-width: 320px; - padding: 44px 7px 0; - margin: auto; - display: flex; - justify-content: space-between; -} \ No newline at end of file diff --git a/src/assets/scss/elements/_wrap.scss b/src/assets/scss/elements/_wrap.scss index dbbb4792..8586fa9b 100644 --- a/src/assets/scss/elements/_wrap.scss +++ b/src/assets/scss/elements/_wrap.scss @@ -17,11 +17,7 @@ background-color: $colorBgLight; } &.dark { - // background-color: $colorBgDark; - - // background-color: #394247; - - background-color: #324045; // Цвет брал так: загружал картинку через pixelperfect и брал с неё цвет + background-color: #324045; input:-webkit-autofill, input:-webkit-autofill:hover, @@ -70,6 +66,7 @@ margin-top: 40px; } } + .page-action-wrap { height: 70px; display: flex; @@ -102,22 +99,12 @@ } } -.welcome-wrap, -.settings-wrap { - & > .user-icon-wrap { - margin: -43px auto 0; - position: absolute; - right: 0; - left: 0; - } -} -.settings-wrap { - .user-icon-wrap { - &.big { - img { - width: 32px; - margin-bottom: 20px; - } - } - } -} + +.welcome-wrap > .avatar-image { + margin: -43px auto 0; + z-index: 2; + position: absolute; + max-width: 86px; + right: 0; + left: 0; +} \ No newline at end of file diff --git a/src/assets/scss/libs/bootstrap/_bootstrap.scss b/src/assets/scss/libs/bootstrap/_bootstrap.scss index f270fc50..9b64d65c 100755 --- a/src/assets/scss/libs/bootstrap/_bootstrap.scss +++ b/src/assets/scss/libs/bootstrap/_bootstrap.scss @@ -1,5 +1,5 @@ -@import "bootstrap/variables"; -@import "bootstrap/mixins"; -@import "bootstrap/component-animations"; -@import "bootstrap/dropdowns"; -@import "bootstrap/button-groups"; +@import "./variables"; +@import "./mixins"; +@import "./component-animations"; +@import "./dropdowns"; +@import "./button-groups"; diff --git a/src/assets/scss/libs/bootstrap/bootstrap/_button-groups.scss b/src/assets/scss/libs/bootstrap/_button-groups.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/_button-groups.scss rename to src/assets/scss/libs/bootstrap/_button-groups.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/_component-animations.scss b/src/assets/scss/libs/bootstrap/_component-animations.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/_component-animations.scss rename to src/assets/scss/libs/bootstrap/_component-animations.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/_dropdowns.scss b/src/assets/scss/libs/bootstrap/_dropdowns.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/_dropdowns.scss rename to src/assets/scss/libs/bootstrap/_dropdowns.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/_mixins.scss b/src/assets/scss/libs/bootstrap/_mixins.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/_mixins.scss rename to src/assets/scss/libs/bootstrap/_mixins.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/_variables.scss b/src/assets/scss/libs/bootstrap/_variables.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/_variables.scss rename to src/assets/scss/libs/bootstrap/_variables.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_alerts.scss b/src/assets/scss/libs/bootstrap/mixins/_alerts.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_alerts.scss rename to src/assets/scss/libs/bootstrap/mixins/_alerts.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_background-variant.scss b/src/assets/scss/libs/bootstrap/mixins/_background-variant.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_background-variant.scss rename to src/assets/scss/libs/bootstrap/mixins/_background-variant.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_border-radius.scss b/src/assets/scss/libs/bootstrap/mixins/_border-radius.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_border-radius.scss rename to src/assets/scss/libs/bootstrap/mixins/_border-radius.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_buttons.scss b/src/assets/scss/libs/bootstrap/mixins/_buttons.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_buttons.scss rename to src/assets/scss/libs/bootstrap/mixins/_buttons.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_center-block.scss b/src/assets/scss/libs/bootstrap/mixins/_center-block.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_center-block.scss rename to src/assets/scss/libs/bootstrap/mixins/_center-block.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_clearfix.scss b/src/assets/scss/libs/bootstrap/mixins/_clearfix.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_clearfix.scss rename to src/assets/scss/libs/bootstrap/mixins/_clearfix.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_forms.scss b/src/assets/scss/libs/bootstrap/mixins/_forms.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_forms.scss rename to src/assets/scss/libs/bootstrap/mixins/_forms.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_gradients.scss b/src/assets/scss/libs/bootstrap/mixins/_gradients.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_gradients.scss rename to src/assets/scss/libs/bootstrap/mixins/_gradients.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_grid-framework.scss b/src/assets/scss/libs/bootstrap/mixins/_grid-framework.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_grid-framework.scss rename to src/assets/scss/libs/bootstrap/mixins/_grid-framework.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_grid.scss b/src/assets/scss/libs/bootstrap/mixins/_grid.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_grid.scss rename to src/assets/scss/libs/bootstrap/mixins/_grid.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_hide-text.scss b/src/assets/scss/libs/bootstrap/mixins/_hide-text.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_hide-text.scss rename to src/assets/scss/libs/bootstrap/mixins/_hide-text.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_image.scss b/src/assets/scss/libs/bootstrap/mixins/_image.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_image.scss rename to src/assets/scss/libs/bootstrap/mixins/_image.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_labels.scss b/src/assets/scss/libs/bootstrap/mixins/_labels.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_labels.scss rename to src/assets/scss/libs/bootstrap/mixins/_labels.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_list-group.scss b/src/assets/scss/libs/bootstrap/mixins/_list-group.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_list-group.scss rename to src/assets/scss/libs/bootstrap/mixins/_list-group.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_nav-divider.scss b/src/assets/scss/libs/bootstrap/mixins/_nav-divider.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_nav-divider.scss rename to src/assets/scss/libs/bootstrap/mixins/_nav-divider.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_nav-vertical-align.scss b/src/assets/scss/libs/bootstrap/mixins/_nav-vertical-align.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_nav-vertical-align.scss rename to src/assets/scss/libs/bootstrap/mixins/_nav-vertical-align.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_opacity.scss b/src/assets/scss/libs/bootstrap/mixins/_opacity.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_opacity.scss rename to src/assets/scss/libs/bootstrap/mixins/_opacity.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_pagination.scss b/src/assets/scss/libs/bootstrap/mixins/_pagination.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_pagination.scss rename to src/assets/scss/libs/bootstrap/mixins/_pagination.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_panels.scss b/src/assets/scss/libs/bootstrap/mixins/_panels.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_panels.scss rename to src/assets/scss/libs/bootstrap/mixins/_panels.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_progress-bar.scss b/src/assets/scss/libs/bootstrap/mixins/_progress-bar.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_progress-bar.scss rename to src/assets/scss/libs/bootstrap/mixins/_progress-bar.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_reset-filter.scss b/src/assets/scss/libs/bootstrap/mixins/_reset-filter.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_reset-filter.scss rename to src/assets/scss/libs/bootstrap/mixins/_reset-filter.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_reset-text.scss b/src/assets/scss/libs/bootstrap/mixins/_reset-text.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_reset-text.scss rename to src/assets/scss/libs/bootstrap/mixins/_reset-text.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_resize.scss b/src/assets/scss/libs/bootstrap/mixins/_resize.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_resize.scss rename to src/assets/scss/libs/bootstrap/mixins/_resize.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_responsive-visibility.scss b/src/assets/scss/libs/bootstrap/mixins/_responsive-visibility.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_responsive-visibility.scss rename to src/assets/scss/libs/bootstrap/mixins/_responsive-visibility.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_size.scss b/src/assets/scss/libs/bootstrap/mixins/_size.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_size.scss rename to src/assets/scss/libs/bootstrap/mixins/_size.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_tab-focus.scss b/src/assets/scss/libs/bootstrap/mixins/_tab-focus.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_tab-focus.scss rename to src/assets/scss/libs/bootstrap/mixins/_tab-focus.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_table-row.scss b/src/assets/scss/libs/bootstrap/mixins/_table-row.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_table-row.scss rename to src/assets/scss/libs/bootstrap/mixins/_table-row.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_text-emphasis.scss b/src/assets/scss/libs/bootstrap/mixins/_text-emphasis.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_text-emphasis.scss rename to src/assets/scss/libs/bootstrap/mixins/_text-emphasis.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_text-overflow.scss b/src/assets/scss/libs/bootstrap/mixins/_text-overflow.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_text-overflow.scss rename to src/assets/scss/libs/bootstrap/mixins/_text-overflow.scss diff --git a/src/assets/scss/libs/bootstrap/bootstrap/mixins/_vendor-prefixes.scss b/src/assets/scss/libs/bootstrap/mixins/_vendor-prefixes.scss similarity index 100% rename from src/assets/scss/libs/bootstrap/bootstrap/mixins/_vendor-prefixes.scss rename to src/assets/scss/libs/bootstrap/mixins/_vendor-prefixes.scss diff --git a/src/assets/scss/libs/semantic-ui/modules/_all.scss b/src/assets/scss/libs/semantic-ui/modules/_all.scss index 86f0af46..1e08f587 100755 --- a/src/assets/scss/libs/semantic-ui/modules/_all.scss +++ b/src/assets/scss/libs/semantic-ui/modules/_all.scss @@ -1,8 +1,6 @@ @import 'accordion'; @import 'checkbox'; @import 'dimmer'; -@import 'dropdown'; -@import 'rating'; @import 'search'; @import 'sidebar'; @import 'transition'; \ No newline at end of file diff --git a/src/assets/scss/libs/semantic-ui/modules/_dropdown.scss b/src/assets/scss/libs/semantic-ui/modules/_dropdown.scss deleted file mode 100755 index 4de7161e..00000000 --- a/src/assets/scss/libs/semantic-ui/modules/_dropdown.scss +++ /dev/null @@ -1,1304 +0,0 @@ -/*! - * # Semantic UI 2.4.0 - Dropdown - * http://github.com/semantic-org/semantic-ui/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - - -/******************************* - Dropdown -*******************************/ - -.ui.dropdown { - cursor: pointer; - position: relative; - display: flex; - align-items: center; - outline: none; - text-align: left; -} - - -/******************************* - Content -*******************************/ - - -/*-------------- - Menu ----------------*/ - -.ui.dropdown .menu { - cursor: auto; - position: absolute; - display: none; - outline: none; - top: 100%; - min-width: -webkit-max-content; - min-width: -moz-max-content; - min-width: max-content; - text-shadow: none; - text-align: left; - border: 1px solid rgba(34, 36, 38, 0.15); - border-radius: 0.28571429rem; - z-index: 11; - will-change: transform; -} -.ui.dropdown .menu > * { - white-space: nowrap; -} - -/*-------------- - Hidden Input ----------------*/ - -.ui.dropdown > input:not(.search):first-child, -.ui.dropdown > select { - display: none !important; -} - -/*-------------- - Dropdown Icon ----------------*/ - - - - -/*-------------- - Text ----------------*/ - -.ui.dropdown > .text { - display: inline-block; - -webkit-transition: none; - transition: none; -} - -/*-------------- - Menu Item ----------------*/ - -.ui.dropdown .menu > .item { - &:not(.disabled):not(.user-create):not(.user-import):not(.add-network) { - position: relative; - } - cursor: pointer; -} -.ui.dropdown .menu > .item:first-child { - border-top-width: 0px; -} - -/*-------------- - Floated Content ----------------*/ - -.ui.dropdown > .text > [class*="right floated"], -.ui.dropdown .menu .item > [class*="right floated"] { - float: right !important; - margin-right: 0em !important; - margin-left: 1em !important; -} -.ui.dropdown > .text > [class*="left floated"], -.ui.dropdown .menu .item > [class*="left floated"] { - float: left !important; - margin-left: 0em !important; - margin-right: 1em !important; -} - -.ui.dropdown .menu .item > .flag.floated, -.ui.dropdown .menu .item > .image.floated, -.ui.dropdown .menu .item > img.floated { - margin-top: 0em; -} - -/*-------------- - Menu Divider ----------------*/ - -.ui.dropdown .menu > .header { - margin: 1rem 0rem 0.75rem; - padding: 0em 1.14285714rem; - color: rgba(0, 0, 0, 0.85); - font-size: 0.78571429em; - font-weight: bold; - text-transform: uppercase; -} -.ui.dropdown .menu > .divider { - border-top: 1px solid rgba(34, 36, 38, 0.1); - height: 0em; - margin: 0.5em 0em; -} -.ui.dropdown.dropdown .menu > .input { - width: auto; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - margin: 1.14285714rem 0.78571429rem; - min-width: 10rem; -} -.ui.dropdown .menu > .header + .input { - margin-top: 0em; -} -.ui.dropdown .menu > .input:not(.transparent) input { - padding: 0.5em 1em; -} -.ui.dropdown .menu > .input:not(.transparent) .button, -.ui.dropdown .menu > .input:not(.transparent) .label { - padding-top: 0.5em; - padding-bottom: 0.5em; -} - -/*----------------- - Item Description --------------------*/ - -.ui.dropdown > .text > .description, -.ui.dropdown .menu > .item > .description { - float: right; - margin: 0em 0em 0em 1em; - color: rgba(0, 0, 0, 0.4); -} - -/*----------------- - Message --------------------*/ - -.ui.dropdown .menu > .message { - padding: 0.78571429rem 1.14285714rem; - font-weight: normal; -} -.ui.dropdown .menu > .message:not(.ui) { - color: rgba(0, 0, 0, 0.4); -} - -/*-------------- - Sub Menu ----------------*/ - -.ui.dropdown .menu .menu { - top: 0% !important; - left: 100%; - right: auto; - margin: 0em 0em 0em -0.5em !important; - border-radius: 0.28571429rem !important; - z-index: 21 !important; -} - -/* Hide Arrow */ -.ui.dropdown .menu .menu:after { - display: none; -} - -/*-------------- - Sub Elements ----------------*/ - - -/* Icons / Flags / Labels / Image */ -.ui.dropdown > .text > .label, -.ui.dropdown > .text > .flag, -.ui.dropdown > .text > img, -.ui.dropdown > .text > .image { - margin-top: 0em; -} - -.ui.dropdown .menu > .item > .label, -.ui.dropdown .menu > .item > .flag, -.ui.dropdown .menu > .item > .image, -.ui.dropdown .menu > .item > img { - margin-top: 0em; -} - -.ui.dropdown > .text > .label, -.ui.dropdown > .text > .flag, -.ui.dropdown > .text > img, -.ui.dropdown > .text > .image, -.ui.dropdown .menu > .item > .icon, -.ui.dropdown .menu > .item > .label, -.ui.dropdown .menu > .item > .flag, -.ui.dropdown .menu > .item > .image, -.ui.dropdown .menu > .item > img { - margin-left: 0em; - float: none; - margin-right: 0.78571429rem; -} - -/*-------------- - Image ----------------*/ - -.ui.dropdown > .text > img, -.ui.dropdown > .text > .image, -.ui.dropdown .menu > .item > .image, -.ui.dropdown .menu > .item > img { - display: inline-block; - vertical-align: top; - width: auto; - margin-top: -0.5em; - margin-bottom: -0.5em; - max-height: 2em; -} - - -/******************************* - Coupling -*******************************/ - - -/*-------------- - Menu ----------------*/ - - -/* Remove Menu Item Divider */ -.ui.dropdown .ui.menu > .item:before, -.ui.menu .ui.dropdown .menu > .item:before { - display: none; -} - -/* Prevent Menu Item Border */ -.ui.menu .ui.dropdown .menu .active.item { - border-left: none; -} - -/* Automatically float dropdown menu right on last menu item */ -.ui.menu .right.menu .dropdown:last-child .menu, -.ui.menu .right.dropdown.item .menu, -.ui.buttons > .ui.dropdown:last-child .menu { - left: auto; - right: 0em; -} - -/*-------------- - Label ----------------*/ - - -/* Dropdown Menu */ -.ui.label.dropdown .menu { - min-width: 100%; -} - -/*-------------- - Button ----------------*/ - - -.ui.button.dropdown .menu { - min-width: 100%; -} - - -/******************************* - Types -*******************************/ - - -/*-------------- - Selection ----------------*/ - - -/* Displays like a select box */ -.ui.selection.dropdown { - cursor: pointer; - word-wrap: break-word; - line-height: 1em; - white-space: normal; - outline: 0; - -webkit-transform: rotateZ(0deg); - transform: rotateZ(0deg); - min-width: 14em; - min-height: 2.71428571em; - background: #FFFFFF; - display: inline-block; - padding: 0.78571429em 2.1em 0.78571429em 1em; - color: rgba(0, 0, 0, 0.87); - -webkit-box-shadow: none; - box-shadow: none; - border: 1px solid rgba(34, 36, 38, 0.15); - border-radius: 0.28571429rem; - -webkit-transition: width 0.1s ease, -webkit-box-shadow 0.1s ease; - transition: width 0.1s ease, -webkit-box-shadow 0.1s ease; - transition: box-shadow 0.1s ease, width 0.1s ease; - transition: box-shadow 0.1s ease, width 0.1s ease, -webkit-box-shadow 0.1s ease; -} -.ui.selection.dropdown.visible, -.ui.selection.dropdown.active { - z-index: 10; -} -select.ui.dropdown { - height: 38px; - padding: 0.5em; - border: 1px solid rgba(34, 36, 38, 0.15); - visibility: visible; -} - -/* Compact */ -.ui.compact.selection.dropdown { - min-width: 0px; -} - -/* Selection Menu */ -.ui.selection.dropdown .menu { - overflow-x: hidden; - overflow-y: auto; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-overflow-scrolling: touch; - border-top-width: 0px !important; - width: auto; - outline: none; - margin: 0px -1px; - min-width: calc(100% + 2px ); - width: calc(100% + 2px ); - border-radius: 0em 0em 0.28571429rem 0.28571429rem; - -webkit-box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - -webkit-transition: opacity 0.1s ease; - transition: opacity 0.1s ease; -} -.ui.selection.dropdown .menu:after, -.ui.selection.dropdown .menu:before { - display: none; -} - -/*-------------- - Message ----------------*/ - -.ui.selection.dropdown .menu > .message { - padding: 0.78571429rem 1.14285714rem; -} -@media only screen and (max-width: 767px) { - .ui.selection.dropdown .menu { - max-height: 8.01428571rem; - } -} -@media only screen and (min-width: 768px) { - .ui.selection.dropdown .menu { - max-height: 10.68571429rem; - } -} -@media only screen and (min-width: 992px) { - .ui.selection.dropdown .menu { - max-height: 16.02857143rem; - } -} -@media only screen and (min-width: 1920px) { - .ui.selection.dropdown .menu { - max-height: 21.37142857rem; - } -} - -/* Menu Item */ -.ui.selection.dropdown .menu > .item { - border-top: 1px solid #FAFAFA; - padding: 0.78571429rem 1.14285714rem !important; - white-space: normal; - word-wrap: normal; -} - -/* User Item */ -.ui.selection.dropdown .menu > .hidden.addition.item { - display: none; -} - -/* Hover */ -.ui.selection.dropdown:hover { - border-color: rgba(34, 36, 38, 0.35); - -webkit-box-shadow: none; - box-shadow: none; -} - -/* Active */ -.ui.selection.active.dropdown { - border-color: #96C8DA; - -webkit-box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); -} -.ui.selection.active.dropdown .menu { - border-color: #96C8DA; - -webkit-box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); -} - -/* Focus */ -.ui.selection.dropdown:focus { - border-color: #96C8DA; - -webkit-box-shadow: none; - box-shadow: none; -} -.ui.selection.dropdown:focus .menu { - border-color: #96C8DA; - -webkit-box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); -} - -/* Visible */ -.ui.selection.visible.dropdown > .text:not(.default) { - font-weight: normal; - color: rgba(0, 0, 0, 0.8); -} - -/* Visible Hover */ -.ui.selection.active.dropdown:hover { - border-color: #96C8DA; - -webkit-box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); -} -.ui.selection.active.dropdown:hover .menu { - border-color: #96C8DA; - -webkit-box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); - box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); -} - -/* Connecting Border */ -.ui.active.selection.dropdown { - border-bottom-left-radius: 0em !important; - border-bottom-right-radius: 0em !important; -} - -/* Empty Connecting Border */ -.ui.active.empty.selection.dropdown { - border-radius: 0.28571429rem !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; -} -.ui.active.empty.selection.dropdown .menu { - border: none !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; -} - -/*-------------- - Searchable ----------------*/ - - -/* Search Selection */ -.ui.search.dropdown { - min-width: ''; -} - -/* Search Dropdown */ -.ui.search.dropdown > input.search { - background: none transparent !important; - border: none !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; - cursor: text; - top: 0em; - left: 1px; - width: 100%; - outline: none; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - padding: inherit; -} - -/* Text Layering */ -.ui.search.dropdown > input.search { - position: absolute; - z-index: 2; -} -.ui.search.dropdown > .text { - cursor: text; - position: relative; - left: 1px; - z-index: 3; -} - -/* Search Selection */ -.ui.search.selection.dropdown > input.search { - line-height: 1.21428571em; - padding: 0.67857143em 2.1em 0.67857143em 1em; -} - -/* Used to size multi select input to character width */ -.ui.search.selection.dropdown > span.sizer { - line-height: 1.21428571em; - padding: 0.67857143em 2.1em 0.67857143em 1em; - display: none; - white-space: pre; -} - -/* Active/Visible Search */ -.ui.search.dropdown.active > input.search, -.ui.search.dropdown.visible > input.search { - cursor: auto; -} -.ui.search.dropdown.active > .text, -.ui.search.dropdown.visible > .text { - pointer-events: none; -} - -/* Filtered Text */ -.ui.active.search.dropdown input.search:focus + .text .icon, -.ui.active.search.dropdown input.search:focus + .text .flag { - opacity: 0.45; -} -.ui.active.search.dropdown input.search:focus + .text { - color: rgba(115, 115, 115, 0.87) !important; -} - -/* Search Menu */ -.ui.search.dropdown .menu { - overflow-x: hidden; - overflow-y: auto; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-overflow-scrolling: touch; -} -@media only screen and (max-width: 767px) { - .ui.search.dropdown .menu { - max-height: 8.01428571rem; - } -} -@media only screen and (min-width: 768px) { - .ui.search.dropdown .menu { - max-height: 10.68571429rem; - } -} -@media only screen and (min-width: 992px) { - .ui.search.dropdown .menu { - max-height: 16.02857143rem; - } -} -@media only screen and (min-width: 1920px) { - .ui.search.dropdown .menu { - max-height: 21.37142857rem; - } -} - -/*-------------- - Multiple ----------------*/ - - -/* Multiple Selection */ -.ui.multiple.dropdown { - padding: 0.22619048em 2.1em 0.22619048em 0.35714286em; -} -.ui.multiple.dropdown .menu { - cursor: auto; -} - -/* Multiple Search Selection */ -.ui.multiple.search.dropdown, -.ui.multiple.search.dropdown > input.search { - cursor: text; -} - -/* Selection Label */ -.ui.multiple.dropdown > .label { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - display: inline-block; - vertical-align: top; - white-space: normal; - font-size: 1em; - padding: 0.35714286em 0.78571429em; - margin: 0.14285714rem 0.28571429rem 0.14285714rem 0em; - -webkit-box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset; - box-shadow: 0px 0px 0px 1px rgba(34, 36, 38, 0.15) inset; -} - -/* Text */ -.ui.multiple.dropdown > .text { - position: static; - padding: 0; - max-width: 100%; - margin: 0.45238095em 0em 0.45238095em 0.64285714em; - line-height: 1.21428571em; -} -.ui.multiple.dropdown > .label ~ input.search { - margin-left: 0.14285714em !important; -} -.ui.multiple.dropdown > .label ~ .text { - display: none; -} - -/*----------------- - Multiple Search ------------------*/ - - -/* Prompt Text */ -.ui.multiple.search.dropdown > .text { - display: inline-block; - position: absolute; - top: 0; - left: 0; - padding: inherit; - margin: 0.45238095em 0em 0.45238095em 0.64285714em; - line-height: 1.21428571em; -} -.ui.multiple.search.dropdown > .label ~ .text { - display: none; -} - -/* Search */ -.ui.multiple.search.dropdown > input.search { - position: static; - padding: 0; - max-width: 100%; - margin: 0.45238095em 0em 0.45238095em 0.64285714em; - width: 2.2em; - line-height: 1.21428571em; -} - -/*-------------- - Inline ----------------*/ - -.ui.inline.dropdown { - cursor: pointer; - display: inline-block; - color: inherit; -} - -.ui.inline.dropdown > .text { - font-weight: bold; -} -.ui.inline.dropdown .menu { - cursor: auto; - margin-top: 0.21428571em; - border-radius: 0.28571429rem; -} - - -/******************************* - States -*******************************/ - - -/*-------------------- - Active -----------------------*/ - - -/* Menu Item Active */ -.ui.dropdown .menu .active.item { - z-index: 12; -} - -/*-------------------- - Hover -----------------------*/ - - -/* Menu Item Hover */ -.ui.dropdown .menu > .item:hover { - z-index: 13; -} - - - -/* Coupling */ - -@-webkit-keyframes dropdown-spin { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - to { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@keyframes dropdown-spin { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - to { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} - -/*-------------------- - Default Text -----------------------*/ - -.ui.dropdown:not(.button) > .default.text, -.ui.default.dropdown:not(.button) > .text { - color: rgba(191, 191, 191, 0.87); -} -.ui.dropdown:not(.button) > input:focus ~ .default.text, -.ui.default.dropdown:not(.button) > input:focus ~ .text { - color: rgba(115, 115, 115, 0.87); -} - -/*-------------------- - Loading -----------------------*/ - -.ui.loading.dropdown > .text { - -webkit-transition: none; - transition: none; -} - -/* Used To Check Position */ -.ui.dropdown .loading.menu { - display: block; - visibility: hidden; - z-index: -1; -} -.ui.dropdown > .loading.menu { - left: 0px !important; - right: auto !important; -} -.ui.dropdown > .menu .loading.menu { - left: 100% !important; - right: auto !important; -} - -/*-------------------- - Search Filtered -----------------------*/ - - -/* Filtered Item */ -.ui.dropdown > .filtered.text { - visibility: hidden; -} -.ui.dropdown .filtered.item { - display: none !important; -} - -/*-------------------- - Error -----------------------*/ - -.ui.dropdown.error, -.ui.dropdown.error > .text, -.ui.dropdown.error > .default.text { - color: #9F3A38; -} -.ui.selection.dropdown.error { - background: #FFF6F6; - border-color: #E0B4B4; -} -.ui.selection.dropdown.error:hover { - border-color: #E0B4B4; -} -.ui.dropdown.error > .menu, -.ui.dropdown.error > .menu .menu { - border-color: #E0B4B4; -} -.ui.dropdown.error > .menu > .item { - color: #9F3A38; -} -.ui.multiple.selection.error.dropdown > .label { - border-color: #E0B4B4; -} - -/* Item Hover */ -.ui.dropdown.error > .menu > .item:hover { - background-color: #FFF2F2; -} - -/* Item Active */ -.ui.dropdown.error > .menu .active.item { - background-color: #FDCFCF; -} - - -/*-------------------- - Disabled -----------------------*/ - - -/* Disabled */ -.ui.disabled.dropdown, -.ui.dropdown .menu > .disabled.item { - cursor: default; - pointer-events: none; - z-index: -1; -} - - -/*-------------- - Direction ----------------*/ - - -/* Flyout Direction */ -.ui.dropdown .menu { - left: 0px; -} - -/* Default Side (Right) */ -.ui.dropdown .right.menu > .menu, -.ui.dropdown .menu .right.menu { - left: 100% !important; - right: auto !important; - border-radius: 0.28571429rem !important; -} - -/* Leftward Opening Menu */ -.ui.dropdown > .left.menu { - left: auto !important; - right: 0px !important; -} -.ui.dropdown > .left.menu .menu, -.ui.dropdown .menu .left.menu { - left: auto; - right: 100%; - margin: 0em -0.5em 0em 0em !important; - border-radius: 0.28571429rem !important; -} - -/*-------------- - Upward ----------------*/ - - -/* Upward Main Menu */ -.ui.upward.dropdown > .menu { - top: auto; - bottom: 100%; - -webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.08); - box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.08); - border-radius: 0.28571429rem 0.28571429rem 0em 0em; -} - -/* Upward Sub Menu */ -.ui.dropdown .upward.menu { - top: auto !important; - bottom: 0 !important; -} - -/* Active Upward */ -.ui.simple.upward.active.dropdown, -.ui.simple.upward.dropdown:hover { - border-radius: 0.28571429rem 0.28571429rem 0em 0em !important; -} -.ui.upward.dropdown.button:not(.pointing):not(.floating).active { - border-radius: 0.28571429rem 0.28571429rem 0em 0em; -} - -/* Selection */ -.ui.upward.selection.dropdown .menu { - border-top-width: 1px !important; - border-bottom-width: 0px !important; - -webkit-box-shadow: 0px -2px 3px 0px rgba(0, 0, 0, 0.08); - box-shadow: 0px -2px 3px 0px rgba(0, 0, 0, 0.08); -} -.ui.upward.selection.dropdown:hover { - -webkit-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.05); - box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.05); -} - -/* Active Upward */ -.ui.active.upward.selection.dropdown { - border-radius: 0em 0em 0.28571429rem 0.28571429rem !important; -} - -/* Visible Upward */ -.ui.upward.selection.dropdown.visible { - -webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.08); - box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.08); - border-radius: 0em 0em 0.28571429rem 0.28571429rem !important; -} - -/* Visible Hover Upward */ -.ui.upward.active.selection.dropdown:hover { - -webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.05); - box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.05); -} -.ui.upward.active.selection.dropdown:hover .menu { - -webkit-box-shadow: 0px -2px 3px 0px rgba(0, 0, 0, 0.08); - box-shadow: 0px -2px 3px 0px rgba(0, 0, 0, 0.08); -} - -/*-------------- - Simple ----------------*/ - - -/* Selection Menu */ -.ui.scrolling.dropdown .menu, -.ui.dropdown .scrolling.menu { - overflow-x: hidden; - overflow-y: auto; -} -.ui.scrolling.dropdown .menu { - overflow-x: hidden; - overflow-y: auto; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-overflow-scrolling: touch; - min-width: 100% !important; - width: auto !important; -} -.ui.dropdown .scrolling.menu { - position: static; - overflow-y: auto; - border: none; - -webkit-box-shadow: none !important; - box-shadow: none !important; - border-radius: 0 !important; - margin: 0 !important; - min-width: 100% !important; - width: auto !important; - border-top: 1px solid rgba(34, 36, 38, 0.15); -} -.ui.scrolling.dropdown .menu .item.item.item, -.ui.dropdown .scrolling.menu > .item.item.item { - border-top: none; -} -.ui.scrolling.dropdown .menu .item:first-child, -.ui.dropdown .scrolling.menu .item:first-child { - border-top: none; -} -.ui.dropdown > .animating.menu .scrolling.menu, -.ui.dropdown > .visible.menu .scrolling.menu { - display: block; -} - -/* Scrollbar in IE */ -@media all and (-ms-high-contrast: none) { - .ui.scrolling.dropdown .menu, - .ui.dropdown .scrolling.menu { - min-width: calc(100% - 17px ); - } -} -@media only screen and (max-width: 767px) { - .ui.scrolling.dropdown .menu, - .ui.dropdown .scrolling.menu { - max-height: 10.28571429rem; - } -} -@media only screen and (min-width: 768px) { - .ui.scrolling.dropdown .menu, - .ui.dropdown .scrolling.menu { - max-height: 15.42857143rem; - } -} -@media only screen and (min-width: 992px) { - .ui.scrolling.dropdown .menu, - .ui.dropdown .scrolling.menu { - max-height: 20.57142857rem; - } -} -@media only screen and (min-width: 1920px) { - .ui.scrolling.dropdown .menu, - .ui.dropdown .scrolling.menu { - max-height: 20.57142857rem; - } -} - -/*-------------- - Simple ----------------*/ - - -/* Displays without javascript */ -.ui.simple.dropdown .menu:before, -.ui.simple.dropdown .menu:after { - display: none; -} -.ui.simple.dropdown .menu { - position: absolute; - display: block; - overflow: hidden; - top: -9999px !important; - opacity: 0; - width: 0; - height: 0; - -webkit-transition: opacity 0.1s ease; - transition: opacity 0.1s ease; -} -.ui.simple.active.dropdown, -.ui.simple.dropdown:hover { - border-bottom-left-radius: 0em !important; - border-bottom-right-radius: 0em !important; -} -.ui.simple.active.dropdown > .menu, -.ui.simple.dropdown:hover > .menu { - overflow: visible; - width: auto; - height: auto; - top: 100% !important; - opacity: 1; -} -.ui.simple.dropdown > .menu > .item:active > .menu, -.ui.simple.dropdown:hover > .menu > .item:hover > .menu { - overflow: visible; - width: auto; - height: auto; - top: 0% !important; - left: 100% !important; - opacity: 1; -} -.ui.simple.disabled.dropdown:hover .menu { - display: none; - height: 0px; - width: 0px; - overflow: hidden; -} - -/* Visible */ -.ui.simple.visible.dropdown > .menu { - display: block; -} - -/*-------------- - Fluid ----------------*/ - -.ui.fluid.dropdown { - display: block; - width: 100%; - min-width: 0em; -} - - -/*-------------- - Floating ----------------*/ - -.ui.floating.dropdown .menu { - left: 0; - right: auto; - -webkit-box-shadow: 0px 2px 4px 0px rgba(34, 36, 38, 0.12), 0px 2px 10px 0px rgba(34, 36, 38, 0.15) !important; - box-shadow: 0px 2px 4px 0px rgba(34, 36, 38, 0.12), 0px 2px 10px 0px rgba(34, 36, 38, 0.15) !important; - border-radius: 0.28571429rem !important; -} -.ui.floating.dropdown > .menu { - margin-top: 0.5em !important; - border-radius: 0.28571429rem !important; -} - -/*-------------- - Pointing ----------------*/ - -.ui.pointing.dropdown > .menu { - top: 100%; - margin-top: 0.78571429rem; - border-radius: 0.28571429rem; -} -.ui.pointing.dropdown > .menu:after { - display: block; - position: absolute; - pointer-events: none; - content: ''; - visibility: visible; - -webkit-transform: rotate(45deg); - transform: rotate(45deg); - width: 0.5em; - height: 0.5em; - -webkit-box-shadow: -1px -1px 0px 0px rgba(34, 36, 38, 0.15); - box-shadow: -1px -1px 0px 0px rgba(34, 36, 38, 0.15); - background: #FFFFFF; - z-index: 2; -} -.ui.pointing.dropdown > .menu:after { - top: -0.25em; - left: 50%; - margin: 0em 0em 0em -0.25em; -} - -/* Top Left Pointing */ -.ui.top.left.pointing.dropdown > .menu { - top: 100%; - bottom: auto; - left: 0%; - right: auto; - margin: 1em 0em 0em; -} -.ui.top.left.pointing.dropdown > .menu { - top: 100%; - bottom: auto; - left: 0%; - right: auto; - margin: 1em 0em 0em; -} -.ui.top.left.pointing.dropdown > .menu:after { - top: -0.25em; - left: 1em; - right: auto; - margin: 0em; - -webkit-transform: rotate(45deg); - transform: rotate(45deg); -} - -/* Top Right Pointing */ -.ui.top.right.pointing.dropdown > .menu { - top: 100%; - bottom: auto; - right: 0%; - left: auto; - margin: 1em 0em 0em; -} -.ui.top.pointing.dropdown > .left.menu:after, -.ui.top.right.pointing.dropdown > .menu:after { - top: -0.25em; - left: auto !important; - right: 1em !important; - margin: 0em; - -webkit-transform: rotate(45deg); - transform: rotate(45deg); -} - -/* Left Pointing */ -.ui.left.pointing.dropdown > .menu { - top: 0%; - left: 100%; - right: auto; - margin: 0em 0em 0em 1em; -} -.ui.left.pointing.dropdown > .menu:after { - top: 1em; - left: -0.25em; - margin: 0em 0em 0em 0em; - -webkit-transform: rotate(-45deg); - transform: rotate(-45deg); -} -.ui.left:not(.top):not(.bottom).pointing.dropdown > .left.menu { - left: auto !important; - right: 100% !important; - margin: 0em 1em 0em 0em; -} -.ui.left:not(.top):not(.bottom).pointing.dropdown > .left.menu:after { - top: 1em; - left: auto; - right: -0.25em; - margin: 0em 0em 0em 0em; - -webkit-transform: rotate(135deg); - transform: rotate(135deg); -} - -/* Right Pointing */ -.ui.right.pointing.dropdown > .menu { - top: 0%; - left: auto; - right: 100%; - margin: 0em 1em 0em 0em; -} -.ui.right.pointing.dropdown > .menu:after { - top: 1em; - left: auto; - right: -0.25em; - margin: 0em 0em 0em 0em; - -webkit-transform: rotate(135deg); - transform: rotate(135deg); -} - -/* Bottom Pointing */ -.ui.bottom.pointing.dropdown > .menu { - top: auto; - bottom: 100%; - left: 0%; - right: auto; - margin: 0em 0em 1em; -} -.ui.bottom.pointing.dropdown > .menu:after { - top: auto; - bottom: -0.25em; - right: auto; - margin: 0em; - -webkit-transform: rotate(-135deg); - transform: rotate(-135deg); -} - -/* Reverse Sub-Menu Direction */ -.ui.bottom.pointing.dropdown > .menu .menu { - top: auto !important; - bottom: 0px !important; -} - -/* Bottom Left */ -.ui.bottom.left.pointing.dropdown > .menu { - left: 0%; - right: auto; -} -.ui.bottom.left.pointing.dropdown > .menu:after { - left: 1em; - right: auto; -} - -/* Bottom Right */ -.ui.bottom.right.pointing.dropdown > .menu { - right: 0%; - left: auto; -} -.ui.bottom.right.pointing.dropdown > .menu:after { - left: auto; - right: 1em; -} - -/* Upward pointing */ -.ui.pointing.upward.dropdown .menu, -.ui.top.pointing.upward.dropdown .menu { - top: auto !important; - bottom: 100% !important; - margin: 0em 0em 0.78571429rem; - border-radius: 0.28571429rem; -} -.ui.pointing.upward.dropdown .menu:after, -.ui.top.pointing.upward.dropdown .menu:after { - top: 100% !important; - bottom: auto !important; - -webkit-box-shadow: 1px 1px 0px 0px rgba(34, 36, 38, 0.15); - box-shadow: 1px 1px 0px 0px rgba(34, 36, 38, 0.15); - margin: -0.25em 0em 0em; -} - -/* Right Pointing Upward */ -.ui.right.pointing.upward.dropdown:not(.top):not(.bottom) .menu { - top: auto !important; - bottom: 0 !important; - margin: 0em 1em 0em 0em; -} -.ui.right.pointing.upward.dropdown:not(.top):not(.bottom) .menu:after { - top: auto !important; - bottom: 0 !important; - margin: 0em 0em 1em 0em; - -webkit-box-shadow: -1px -1px 0px 0px rgba(34, 36, 38, 0.15); - box-shadow: -1px -1px 0px 0px rgba(34, 36, 38, 0.15); -} - -/* Left Pointing Upward */ -.ui.left.pointing.upward.dropdown:not(.top):not(.bottom) .menu { - top: auto !important; - bottom: 0 !important; - margin: 0em 0em 0em 1em; -} -.ui.left.pointing.upward.dropdown:not(.top):not(.bottom) .menu:after { - top: auto !important; - bottom: 0 !important; - margin: 0em 0em 1em 0em; - -webkit-box-shadow: -1px -1px 0px 0px rgba(34, 36, 38, 0.15); - box-shadow: -1px -1px 0px 0px rgba(34, 36, 38, 0.15); -} - - -/******************************* - Theme Overrides -*******************************/ - - -/* Dropdown Carets */ -@font-face { - font-family: 'Dropdown'; - src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAVgAA8AAAAACFAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABWAAAABwAAAAchGgaq0dERUYAAAF0AAAAHAAAAB4AJwAPT1MvMgAAAZAAAABDAAAAVnW4TJdjbWFwAAAB1AAAAEsAAAFS8CcaqmN2dCAAAAIgAAAABAAAAAQAEQFEZ2FzcAAAAiQAAAAIAAAACP//AANnbHlmAAACLAAAAQoAAAGkrRHP9WhlYWQAAAM4AAAAMAAAADYPK8YyaGhlYQAAA2gAAAAdAAAAJANCAb1obXR4AAADiAAAACIAAAAiCBkAOGxvY2EAAAOsAAAAFAAAABQBnAIybWF4cAAAA8AAAAAfAAAAIAEVAF5uYW1lAAAD4AAAATAAAAKMFGlj5HBvc3QAAAUQAAAARgAAAHJoedjqd2ViZgAABVgAAAAGAAAABrO7W5UAAAABAAAAANXulPUAAAAA1r4hgAAAAADXu2Q1eNpjYGRgYOABYjEgZmJgBEIOIGYB8xgAA/YAN3jaY2BktGOcwMDKwMI4jTGNgYHBHUp/ZZBkaGFgYGJgZWbACgLSXFMYHFT/fLjFeOD/AQY9xjMMbkBhRpAcAN48DQYAeNpjYGBgZoBgGQZGBhDwAfIYwXwWBgMgzQGETAwMqn8+8H649f8/lHX9//9b7Pzf+fWgusCAkY0BzmUE6gHpQwGMDMMeAACbxg7SAAARAUQAAAAB//8AAnjadZBPSsNAGMXfS+yMqYgOhpSuSlKadmUhiVEhEMQzFF22m17BbbvzCh5BXCUn6EG8gjeQ4DepwYo4i+/ffL95j4EDA+CFC7jQuKyIeVHrI3wkleq9F7XrSInKteOeHdda8bOoaeepSc00NWPz/LRec9G8GabyGtEdF7h19z033GAMTK7zbM42xNEZpzYof0RtQ5CUHAQJ73OtVyutc+3b7Ou//b8XNlsPx3jgjUifABdhEohKJJL5iM5p39uqc7X1+sRQSqmGrUVhlsJ4lpmEUVwyT8SUYtg0P9DyNzPADDs+tjrGV6KRCRfsui3eHcL4/p8ZXvfMlcnEU+CLv7hDykOP+AKTPTxbAAB42mNgZGBgAGKuf5KP4vltvjLIMzGAwLV9ig0g+vruFFMQzdjACOJzMIClARh0CTJ42mNgZGBgPPD/AJD8wgAEjA0MjAyogAMAbOQEAQAAAAC7ABEAAAAAAKoAAAH0AAABgAAAAUAACAFAAAgAwAAXAAAAAAAAACoAKgAqADIAbACGAKAAugDSeNpjYGRgYOBkUGFgYgABEMkFhAwM/xn0QAIADdUBdAB42qWQvUoDQRSFv3GjaISUQaymSmGxJoGAsRC0iPYLsU50Y6IxrvlRtPCJJKUPIBb+PIHv4EN4djKuKAqCDHfmu+feOdwZoMCUAJNbAlYUMzaUlM14jjxbngOq7HnOia89z1Pk1vMCa9x7ztPkzfMyJbPj+ZGi6Xp+omxuPD+zaD7meaFg7mb8GrBqHmhwxoAxlm0uiRkpP9X5m26pKRoMxTGR1D49Dv/Yb/91o6l8qL6eu5n2hZQzn68utR9m3FU2cB4t9cdSLG2utI+44Eh/P9bqKO+oJ/WxmXssj77YkrjasZQD6SFddythk3Wtzrf+UF2p076Udla1VNzsERP3kkjVRKel7mp1udXYcHtZSlV7RfmJe1GiFWveluaeKD5/MuJcSk8Tpm/vvwPIbmJleNpjYGKAAFYG7ICTgYGRiZGZkYWRlZGNkZ2Rg5GTLT2nsiDDEEIZsZfmZRqZujmDaDcDAxcI7WIOpS2gtCWUdgQAZkcSmQAAAAFblbO6AAA=) format('woff'); - font-weight: normal; - font-style: normal; -} -.ui.dropdown > .dropdown.icon { - font-family: 'Dropdown'; -} - -.ui.dropdown > .dropdown.icon:before { - content: '\f0d7'; -} \ No newline at end of file diff --git a/src/assets/scss/libs/semantic-ui/modules/_rating.scss b/src/assets/scss/libs/semantic-ui/modules/_rating.scss deleted file mode 100755 index 5de6a2a2..00000000 --- a/src/assets/scss/libs/semantic-ui/modules/_rating.scss +++ /dev/null @@ -1,263 +0,0 @@ -/*! - * # Semantic UI 2.4.0 - Rating - * http://github.com/semantic-org/semantic-ui/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - - -/******************************* - Rating -*******************************/ - -.ui.rating { - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - white-space: nowrap; - vertical-align: baseline; -} -.ui.rating:last-child { - margin-right: 0em; -} - -/* Icon */ -.ui.rating .icon { - padding: 0em; - margin: 0em; - text-align: center; - font-weight: normal; - font-style: normal; - -webkit-box-flex: 1; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - cursor: pointer; - width: 1.25em; - height: auto; - -webkit-transition: opacity 0.1s ease, background 0.1s ease, text-shadow 0.1s ease, color 0.1s ease; - transition: opacity 0.1s ease, background 0.1s ease, text-shadow 0.1s ease, color 0.1s ease; -} - - -/******************************* - Types -*******************************/ - - -/*------------------- - Standard ---------------------*/ - - -/* Inactive Icon */ -.ui.rating .icon { - background: transparent; - color: rgba(0, 0, 0, 0.15); -} - -/* Active Icon */ -.ui.rating .active.icon { - background: transparent; - color: rgba(0, 0, 0, 0.85); -} - -/* Selected Icon */ -.ui.rating .icon.selected, -.ui.rating .icon.selected.active { - background: transparent; - color: rgba(0, 0, 0, 0.87); -} - -/*------------------- - Star ---------------------*/ - - -/* Inactive */ -.ui.star.rating .icon { - width: 1.25em; - height: auto; - background: transparent; - color: rgba(0, 0, 0, 0.15); - text-shadow: none; -} - -/* Active Star */ -.ui.star.rating .active.icon { - background: transparent !important; - color: #FFE623 !important; - text-shadow: 0px -1px 0px #DDC507, -1px 0px 0px #DDC507, 0px 1px 0px #DDC507, 1px 0px 0px #DDC507 !important; -} - -/* Selected Star */ -.ui.star.rating .icon.selected, -.ui.star.rating .icon.selected.active { - background: transparent !important; - color: #FFCC00 !important; - text-shadow: 0px -1px 0px #E6A200, -1px 0px 0px #E6A200, 0px 1px 0px #E6A200, 1px 0px 0px #E6A200 !important; -} - -/*------------------- - Heart ---------------------*/ - -.ui.heart.rating .icon { - width: 1.4em; - height: auto; - background: transparent; - color: rgba(0, 0, 0, 0.15); - text-shadow: none !important; -} - -/* Active Heart */ -.ui.heart.rating .active.icon { - background: transparent !important; - color: #FF6D75 !important; - text-shadow: 0px -1px 0px #CD0707, -1px 0px 0px #CD0707, 0px 1px 0px #CD0707, 1px 0px 0px #CD0707 !important; -} - -/* Selected Heart */ -.ui.heart.rating .icon.selected, -.ui.heart.rating .icon.selected.active { - background: transparent !important; - color: #FF3000 !important; - text-shadow: 0px -1px 0px #AA0101, -1px 0px 0px #AA0101, 0px 1px 0px #AA0101, 1px 0px 0px #AA0101 !important; -} - - -/******************************* - States -*******************************/ - - -/*------------------- - Disabled ---------------------*/ - - -/* disabled rating */ -.ui.disabled.rating .icon { - cursor: default; -} - -/*------------------- - User Interactive ---------------------*/ - - -/* Selected Rating */ -.ui.rating.selected .active.icon { - opacity: 1; -} -.ui.rating.selected .icon.selected, -.ui.rating .icon.selected { - opacity: 1; -} - - -/******************************* - Variations -*******************************/ - -.ui.mini.rating { - font-size: 0.78571429rem; -} -.ui.tiny.rating { - font-size: 0.85714286rem; -} -.ui.small.rating { - font-size: 0.92857143rem; -} -.ui.rating { - font-size: 1rem; -} -.ui.large.rating { - font-size: 1.14285714rem; -} -.ui.huge.rating { - font-size: 1.42857143rem; -} -.ui.massive.rating { - font-size: 2rem; -} - - -/******************************* - Theme Overrides -*******************************/ - -@font-face { - font-family: 'Rating'; - src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMggjCBsAAAC8AAAAYGNtYXCj2pm8AAABHAAAAKRnYXNwAAAAEAAAAcAAAAAIZ2x5ZlJbXMYAAAHIAAARnGhlYWQBGAe5AAATZAAAADZoaGVhA+IB/QAAE5wAAAAkaG10eCzgAEMAABPAAAAAcGxvY2EwXCxOAAAUMAAAADptYXhwACIAnAAAFGwAAAAgbmFtZfC1n04AABSMAAABPHBvc3QAAwAAAAAVyAAAACAAAwIAAZAABQAAAUwBZgAAAEcBTAFmAAAA9QAZAIQAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADxZQHg/+D/4AHgACAAAAABAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEAJAAAAAgACAABAAAAAEAIOYF8AbwDfAj8C7wbvBw8Irwl/Cc8SPxZf/9//8AAAAAACDmAPAE8AzwI/Au8G7wcPCH8JfwnPEj8WT//f//AAH/4xoEEAYQAQ/sD+IPow+iD4wPgA98DvYOtgADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAPAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAIAAP/tAgAB0wAKABUAAAEvAQ8BFwc3Fyc3BQc3Jz8BHwEHFycCALFPT7GAHp6eHoD/AHAWW304OH1bFnABGRqgoBp8sFNTsHyyOnxYEnFxElh8OgAAAAACAAD/7QIAAdMACgASAAABLwEPARcHNxcnNwUxER8BBxcnAgCxT0+xgB6enh6A/wA4fVsWcAEZGqCgGnywU1OwfLIBHXESWHw6AAAAAQAA/+0CAAHTAAoAAAEvAQ8BFwc3Fyc3AgCxT0+xgB6enh6AARkaoKAafLBTU7B8AAAAAAEAAAAAAgABwAArAAABFA4CBzEHDgMjIi4CLwEuAzU0PgIzMh4CFz4DMzIeAhUCAAcMEgugBgwMDAYGDAwMBqALEgwHFyg2HhAfGxkKChkbHxAeNigXAS0QHxsZCqAGCwkGBQkLBqAKGRsfEB42KBcHDBILCxIMBxcoNh4AAAAAAgAAAAACAAHAACsAWAAAATQuAiMiDgIHLgMjIg4CFRQeAhcxFx4DMzI+Aj8BPgM1DwEiFCIGMTAmIjQjJy4DNTQ+AjMyHgIfATc+AzMyHgIVFA4CBwIAFyg2HhAfGxkKChkbHxAeNigXBwwSC6AGDAwMBgYMDAwGoAsSDAdbogEBAQEBAaIGCgcEDRceEQkREA4GLy8GDhARCREeFw0EBwoGAS0eNigXBwwSCwsSDAcXKDYeEB8bGQqgBgsJBgUJCwagChkbHxA+ogEBAQGiBg4QEQkRHhcNBAcKBjQ0BgoHBA0XHhEJERAOBgABAAAAAAIAAcAAMQAAARQOAgcxBw4DIyIuAi8BLgM1ND4CMzIeAhcHFwc3Jzc+AzMyHgIVAgAHDBILoAYMDAwGBgwMDAagCxIMBxcoNh4KFRMSCC9wQLBwJwUJCgkFHjYoFwEtEB8bGQqgBgsJBgUJCwagChkbHxAeNigXAwUIBUtAoMBAOwECAQEXKDYeAAABAAAAAAIAAbcAKgAAEzQ3NjMyFxYXFhcWFzY3Njc2NzYzMhcWFRQPAQYjIi8BJicmJyYnJicmNQAkJUARExIQEAsMCgoMCxAQEhMRQCUkQbIGBwcGsgMFBQsKCQkGBwExPyMkBgYLCgkKCgoKCQoLBgYkIz8/QawFBawCBgUNDg4OFRQTAAAAAQAAAA0B2wHSACYAABM0PwI2FzYfAhYVFA8BFxQVFAcGByYvAQcGByYnJjU0PwEnJjUAEI9BBQkIBkCPEAdoGQMDBgUGgIEGBQYDAwEYaAcBIwsCFoEMAQEMgRYCCwYIZJABBQUFAwEBAkVFAgEBAwUFAwOQZAkFAAAAAAIAAAANAdsB0gAkAC4AABM0PwI2FzYfAhYVFA8BFxQVFAcmLwEHBgcmJyY1ND8BJyY1HwEHNxcnNy8BBwAQj0EFCQgGQI8QB2gZDAUGgIEGBQYDAwEYaAc/WBVsaxRXeDY2ASMLAhaBDAEBDIEWAgsGCGSQAQUNAQECRUUCAQEDBQUDA5BkCQURVXg4OHhVEW5uAAABACMAKQHdAXwAGgAANzQ/ATYXNh8BNzYXNh8BFhUUDwEGByYvASY1IwgmCAwLCFS8CAsMCCYICPUIDAsIjgjSCwkmCQEBCVS7CQEBCSYJCg0H9gcBAQePBwwAAAEAHwAfAXMBcwAsAAA3ND8BJyY1ND8BNjMyHwE3NjMyHwEWFRQPARcWFRQPAQYjIi8BBwYjIi8BJjUfCFRUCAgnCAwLCFRUCAwLCCcICFRUCAgnCAsMCFRUCAsMCCcIYgsIVFQIDAsIJwgIVFQICCcICwwIVFQICwwIJwgIVFQICCcIDAAAAAACAAAAJQFJAbcAHwArAAA3NTQ3NjsBNTQ3NjMyFxYdATMyFxYdARQHBiMhIicmNTczNTQnJiMiBwYdAQAICAsKJSY1NCYmCQsICAgIC/7tCwgIW5MWFR4fFRZApQsICDc0JiYmJjQ3CAgLpQsICAgIC8A3HhYVFRYeNwAAAQAAAAcBbgG3ACEAADcRNDc2NzYzITIXFhcWFREUBwYHBiMiLwEHBiMiJyYnJjUABgUKBgYBLAYGCgUGBgUKBQcOCn5+Cg4GBgoFBicBcAoICAMDAwMICAr+kAoICAQCCXl5CQIECAgKAAAAAwAAACUCAAFuABgAMQBKAAA3NDc2NzYzMhcWFxYVFAcGBwYjIicmJyY1MxYXFjMyNzY3JicWFRQHBiMiJyY1NDcGBzcUFxYzMjc2NTQ3NjMyNzY1NCcmIyIHBhUABihDREtLREMoBgYoQ0RLS0RDKAYlJjk5Q0M5OSYrQREmJTU1JSYRQSuEBAQGBgQEEREZBgQEBAQGJBkayQoKQSgoKChBCgoKCkEoJycoQQoKOiMjIyM6RCEeIjUmJSUmNSIeIUQlBgQEBAQGGBIRBAQGBgQEGhojAAAABQAAAAkCAAGJACwAOABRAGgAcAAANzQ3Njc2MzIXNzYzMhcWFxYXFhcWFxYVFDEGBwYPAQYjIicmNTQ3JicmJyY1MxYXNyYnJjU0NwYHNxQXFjMyNzY1NDc2MzI3NjU0JyYjIgcGFRc3Njc2NyYnNxYXFhcWFRQHBgcGBwYjPwEWFRQHBgcABitBQU0ZGhADBQEEBAUFBAUEBQEEHjw8Hg4DBQQiBQ0pIyIZBiUvSxYZDg4RQSuEBAQGBgQEEREZBgQEBAQGJBkaVxU9MzQiIDASGxkZEAYGCxQrODk/LlACFxYlyQsJQycnBRwEAgEDAwIDAwIBAwUCNmxsNhkFFAMFBBUTHh8nCQtKISgSHBsfIh4hRCUGBAQEBAYYEhEEBAYGBAQaGiPJJQUiIjYzISASGhkbCgoKChIXMRsbUZANCyghIA8AAAMAAAAAAbcB2wA5AEoAlAAANzU0NzY7ATY3Njc2NzY3Njc2MzIXFhcWFRQHMzIXFhUUBxYVFAcUFRQHFgcGKwEiJyYnJisBIicmNTcUFxYzMjc2NTQnJiMiBwYVFzMyFxYXFhcWFxYXFhcWOwEyNTQnNjc2NTQnNjU0JyYnNjc2NTQnJisBNDc2NTQnJiMGBwYHBgcGBwYHBgcGBwYHBgcGBwYrARUACwoQTgodEQ4GBAMFBgwLDxgTEwoKDjMdFhYOAgoRARkZKCUbGxsjIQZSEAoLJQUFCAcGBQUGBwgFBUkJBAUFBAQHBwMDBwcCPCUjNwIJBQUFDwMDBAkGBgsLDmUODgoJGwgDAwYFDAYQAQUGAwQGBgYFBgUGBgQJSbcPCwsGJhUPCBERExMMCgkJFBQhGxwWFR4ZFQoKFhMGBh0WKBcXBgcMDAoLDxIHBQYGBQcIBQYGBQgSAQEBAQICAQEDAgEULwgIBQoLCgsJDhQHCQkEAQ0NCg8LCxAdHREcDQ4IEBETEw0GFAEHBwUECAgFBQUFAgO3AAADAAD/2wG3AbcAPABNAJkAADc1NDc2OwEyNzY3NjsBMhcWBxUWFRQVFhUUBxYVFAcGKwEWFRQHBgcGIyInJicmJyYnJicmJyYnIyInJjU3FBcWMzI3NjU0JyYjIgcGFRczMhcWFxYXFhcWFxYXFhcWFxYXFhcWFzI3NjU0JyY1MzI3NjU0JyYjNjc2NTQnNjU0JyYnNjU0JyYrASIHIgcGBwYHBgcGIwYrARUACwoQUgYhJRsbHiAoGRkBEQoCDhYWHTMOCgoTExgPCwoFBgIBBAMFDhEdCk4QCgslBQUIBwYFBQYHCAUFSQkEBgYFBgUGBgYEAwYFARAGDAUGAwMIGwkKDg5lDgsLBgYJBAMDDwUFBQkCDg4ZJSU8AgcHAwMHBwQEBQUECbe3DwsKDAwHBhcWJwIWHQYGExYKChUZHhYVHRoiExQJCgsJDg4MDAwNBg4WJQcLCw+kBwUGBgUHCAUGBgUIpAMCBQYFBQcIBAUHBwITBwwTExERBw0OHBEdHRALCw8KDQ0FCQkHFA4JCwoLCgUICBgMCxUDAgEBAgMBAQG3AAAAAQAAAA0A7gHSABQAABM0PwI2FxEHBgcmJyY1ND8BJyY1ABCPQQUJgQYFBgMDARhoBwEjCwIWgQwB/oNFAgEBAwUFAwOQZAkFAAAAAAIAAAAAAgABtwAqAFkAABM0NzYzMhcWFxYXFhc2NzY3Njc2MzIXFhUUDwEGIyIvASYnJicmJyYnJjUzFB8BNzY1NCcmJyYnJicmIyIHBgcGBwYHBiMiJyYnJicmJyYjIgcGBwYHBgcGFQAkJUARExIQEAsMCgoMCxAQEhMRQCUkQbIGBwcGsgMFBQsKCQkGByU1pqY1BgYJCg4NDg0PDhIRDg8KCgcFCQkFBwoKDw4REg4PDQ4NDgoJBgYBMT8jJAYGCwoJCgoKCgkKCwYGJCM/P0GsBQWsAgYFDQ4ODhUUEzA1oJ82MBcSEgoLBgcCAgcHCwsKCQgHBwgJCgsLBwcCAgcGCwoSEhcAAAACAAAABwFuAbcAIQAoAAA3ETQ3Njc2MyEyFxYXFhURFAcGBwYjIi8BBwYjIicmJyY1PwEfAREhEQAGBQoGBgEsBgYKBQYGBQoFBw4Kfn4KDgYGCgUGJZIZef7cJwFwCggIAwMDAwgICv6QCggIBAIJeXkJAgQICAoIjRl0AWP+nQAAAAABAAAAJQHbAbcAMgAANzU0NzY7ATU0NzYzMhcWHQEUBwYrASInJj0BNCcmIyIHBh0BMzIXFh0BFAcGIyEiJyY1AAgIC8AmJjQ1JiUFBQgSCAUFFhUfHhUWHAsICAgIC/7tCwgIQKULCAg3NSUmJiU1SQgFBgYFCEkeFhUVFh43CAgLpQsICAgICwAAAAIAAQANAdsB0gAiAC0AABM2PwI2MzIfAhYXFg8BFxYHBiMiLwEHBiMiJyY/AScmNx8CLwE/AS8CEwEDDJBABggJBUGODgIDCmcYAgQCCAMIf4IFBgYEAgEZaQgC7hBbEgINSnkILgEBJggCFYILC4IVAggICWWPCgUFA0REAwUFCo9lCQipCTBmEw1HEhFc/u0AAAADAAAAAAHJAbcAFAAlAHkAADc1NDc2OwEyFxYdARQHBisBIicmNTcUFxYzMjc2NTQnJiMiBwYVFzU0NzYzNjc2NzY3Njc2NzY3Njc2NzY3NjMyFxYXFhcWFxYXFhUUFRQHBgcGBxQHBgcGBzMyFxYVFAcWFRYHFgcGBxYHBgcjIicmJyYnJiciJyY1AAUGB1MHBQYGBQdTBwYFJQUFCAcGBQUGBwgFBWQFBQgGDw8OFAkFBAQBAQMCAQIEBAYFBw4KCgcHBQQCAwEBAgMDAgYCAgIBAU8XEBAQBQEOBQUECwMREiYlExYXDAwWJAoHBQY3twcGBQUGB7cIBQUFBQgkBwYFBQYHCAUGBgUIJLcHBQYBEBATGQkFCQgGBQwLBgcICQUGAwMFBAcHBgYICQQEBwsLCwYGCgIDBAMCBBEQFhkSDAoVEhAREAsgFBUBBAUEBAcMAQUFCAAAAAADAAD/2wHJAZIAFAAlAHkAADcUFxYXNxY3Nj0BNCcmBycGBwYdATc0NzY3FhcWFRQHBicGJyY1FzU0NzY3Fjc2NzY3NjcXNhcWBxYXFgcWBxQHFhUUBwYHJxYXFhcWFRYXFhcWFRQVFAcGBwYHBgcGBwYnBicmJyYnJicmJyYnJicmJyYnJiciJyY1AAUGB1MHBQYGBQdTBwYFJQUFCAcGBQUGBwgFBWQGBQcKJBYMDBcWEyUmEhEDCwQFBQ4BBRAQEBdPAQECAgIGAgMDAgEBAwIEBQcHCgoOBwUGBAQCAQIDAQEEBAUJFA4PDwYIBQWlBwYFAQEBBwQJtQkEBwEBAQUGB7eTBwYEAQEEBgcJBAYBAQYECZS4BwYEAgENBwUCBgMBAQEXEyEJEhAREBcIDhAaFhEPAQEFAgQCBQELBQcKDAkIBAUHCgUGBwgDBgIEAQEHBQkIBwUMCwcECgcGCRoREQ8CBgQIAAAAAQAAAAEAAJth57dfDzz1AAsCAAAAAADP/GODAAAAAM/8Y4MAAP/bAgAB2wAAAAgAAgAAAAAAAAABAAAB4P/gAAACAAAAAAACAAABAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAEAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAdwAAAHcAAACAAAjAZMAHwFJAAABbgAAAgAAAAIAAAACAAAAAgAAAAEAAAACAAAAAW4AAAHcAAAB3AABAdwAAAHcAAAAAAAAAAoAFAAeAEoAcACKAMoBQAGIAcwCCgJUAoICxgMEAzoDpgRKBRgF7AYSBpgG2gcgB2oIGAjOAAAAAQAAABwAmgAFAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAwAAAABAAAAAAACAA4AQAABAAAAAAADAAwAIgABAAAAAAAEAAwATgABAAAAAAAFABYADAABAAAAAAAGAAYALgABAAAAAAAKADQAWgADAAEECQABAAwAAAADAAEECQACAA4AQAADAAEECQADAAwAIgADAAEECQAEAAwATgADAAEECQAFABYADAADAAEECQAGAAwANAADAAEECQAKADQAWgByAGEAdABpAG4AZwBWAGUAcgBzAGkAbwBuACAAMQAuADAAcgBhAHQAaQBuAGdyYXRpbmcAcgBhAHQAaQBuAGcAUgBlAGcAdQBsAGEAcgByAGEAdABpAG4AZwBGAG8AbgB0ACAAZwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABJAGMAbwBNAG8AbwBuAC4AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format('truetype'), url(data:application/font-woff;charset=utf-8;base64,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kIiRi5MI5vdUFfcni4vCBYufhJx8mn2ZepJ3i3aLeoR9fX18g3qLdwiLVAUO+yaLshWL+AQFi5GNkY+RjpCQj5KNj42PjI+LCPfAiwWPi4+Kj4mRiZCHj4aPhY2Fi4UIi/wEBYuEiYWHhoeGhoeFiIiKhoqHi4GLhI6EkQj7EvcN+xL7DQWEhYOIgouHi4eLh42EjoaPiJCHkImRi5IIDov3XRWLko2Rj5Kltq+vuKW4pbuZvYu9i7t9uHG4ca9npWCPhI2Fi4SLhYmEh4RxYGdoXnAIXnFbflmLWYtbmF6lXqZnrnG2h5KJkouRCLCLFaRkq2yxdLF0tH+4i7iLtJexorGiq6qksm64Z61goZZ3kXaLdItnfm1ycnJybX9oiwhoi22XcqRypH6pi6+LopGglp9gdWdpbl4I9xiwFYuHjIiOiI6IjoqPi4+LjoyOjo2OjY6Lj4ubkJmXl5eWmZGbi4+LjoyOjo2OjY6LjwiLj4mOiY6IjYiNh4tzi3eCenp6eoJ3i3MIDov3XRWLko2Sj5GouK+utqW3pbqYvouci5yJnIgIm6cFjY6NjI+LjIuNi42JjYqOio+JjomOiY6KjomOiY6JjoqNioyKjomMiYuHi4qLiouLCHdnbVVjQ2NDbVV3Zwh9cgWJiIiJiIuJi36SdJiIjYmOi46LjY+UlJlvl3KcdJ90oHeie6WHkYmSi5IIsIsVqlq0Z711CKGzBXqXfpqCnoKdhp6LoIuikaCWn2B1Z2luXgj3GLAVi4eMiI6IjoiOio+Lj4uOjI6OjY6NjouPi5uQmZeXl5aZkZuLj4uOjI6OjY6NjouPCIuPiY6JjoiNiI2Hi3OLd4J6enp6gneLcwji+10VoLAFtI+wmK2hrqKnqKKvdq1wp2uhCJ2rBZ1/nHycepx6mHqWeY+EjYWLhIuEiYWHhIR/gH1+fG9qaXJmeWV5Y4Jhiwi53BXb9yQFjIKMg4uEi3CDc3x1fHV3fHOBCA6L1BWL90sFi5WPlJKSkpKTj5aLCNmLBZKPmJqepJaZlZeVlY+Qj5ONl42WjpeOmI+YkZWTk5OSk46Vi5uLmYiYhZiFlIGSfgiSfo55i3WLeYd5gXgIvosFn4uchJl8mn2Seot3i3qGfIJ9jYSLhYuEi3yIfoR+i4eLh4uHi3eGen99i3CDdnt8CHt8dYNwiwhmiwV5i3mNeY95kHeRc5N1k36Ph4sIOYsFgIuDjoSShJKHlIuVCLCdFYuGjIePiI+Hj4mQi5CLj42Pj46OjY+LkIuQiZCIjoePh42Gi4aLh4mHh4eIioaLhgjUeRWUiwWNi46Lj4qOi4+KjYqOi4+Kj4mQio6KjYqNio+Kj4mQio6KjIqzfquEpIsIrosFr4uemouri5CKkYqQkY6QkI6SjpKNkouSi5KJkoiRlZWQlouYi5CKkImRiZGJj4iOCJGMkI+PlI+UjZKLkouViJODk4SSgo+CiwgmiwWLlpCalJ6UnpCbi5aLnoiYhJSFlH+QeYuGhoeDiYCJf4h/h3+IfoWBg4KHh4SCgH4Ii4qIiYiGh4aIh4mIiIiIh4eGh4aHh4eHiIiHiIeHiIiHiIeKh4mIioiLCIKLi/tLBQ6L90sVi/dLBYuVj5OSk5KSk46WiwjdiwWPi5iPoZOkk6CRnZCdj56Nn4sIq4sFpougg5x8m3yTd4txCIuJBZd8kHuLd4uHi4eLh5J+jn6LfIuEi4SJhZR9kHyLeot3hHp8fH19eoR3iwhYiwWVeI95i3mLdIh6hH6EfoKBfoV+hX2He4uBi4OPg5KFkYaTh5SHlYiTipOKk4qTiJMIiZSIkYiPgZSBl4CaeKR+moSPCD2LBYCLg4+EkoSSh5SLlQiw9zgVi4aMh4+Ij4ePiZCLkIuPjY+Pjo6Nj4uQi5CJkIiOh4+HjYaLhouHiYeHh4iKhouGCNT7OBWUiwWOi46Kj4mPio+IjoiPh4+IjoePiI+Hj4aPho6HjoiNiI6Hj4aOho6Ii4qWfpKDj4YIk4ORgY5+j36OgI1/jYCPg5CGnYuXj5GUkpSOmYuei5aGmoKfgp6GmouWCPCLBZSLlI+SkpOTjpOLlYuSiZKHlIeUho+Fi46PjY+NkY2RjJCLkIuYhpaBlY6RjZKLkgiLkomSiJKIkoaQhY6MkIyRi5CLm4aXgpOBkn6Pe4sIZosFcotrhGN9iouIioaJh4qHiomKiYqIioaKh4mHioiKiYuHioiLh4qIi4mLCIKLi/tLBQ77lIv3txWLkpCPlo0I9yOgzPcWBY6SkI+RiwiL/BL7FUcFh4mHioiLh4uIjImOiY6KjouPi4yLjYyOCKP3IyPwBYaQiZCLjwgOi/fFFYu1l6yjoqOjrZe2i5aLl4mYh5eHloWWhJaElIWShZOE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) format('woff'); - font-weight: normal; - font-style: normal; -} -.ui.rating .icon { - font-family: 'Rating'; - line-height: 1; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - font-weight: normal; - font-style: normal; - text-align: center; -} - -/* Empty Star */ -.ui.rating .icon:before { - content: '\f005'; -} - -/* Active Star */ -.ui.rating .active.icon:before { - content: '\f005'; -} - -/*------------------- - Star ---------------------*/ - - -/* Unfilled Star */ -.ui.star.rating .icon:before { - content: '\f005'; -} - -/* Active Star */ -.ui.star.rating .active.icon:before { - content: '\f005'; -} - -/* Partial */ -.ui.star.rating .partial.icon:before { - content: '\f006'; -} -.ui.star.rating .partial.icon { - content: '\f005'; -} - -/*------------------- - Heart ---------------------*/ - - -/* Empty Heart -.ui.heart.rating .icon:before { - content: '\f08a'; -} -*/ -.ui.heart.rating .icon:before { - content: '\f004'; -} -/* Active */ -.ui.heart.rating .active.icon:before { - content: '\f004'; -} - - -/******************************* - Site Overrides -*******************************/ - diff --git a/src/assets/scss/libs/semantic-ui/modules/_search.scss b/src/assets/scss/libs/semantic-ui/modules/_search.scss index 1bd3cc8c..f69397ff 100755 --- a/src/assets/scss/libs/semantic-ui/modules/_search.scss +++ b/src/assets/scss/libs/semantic-ui/modules/_search.scss @@ -388,43 +388,11 @@ left: auto; } -/*-------------- - Fluid ----------------*/ .ui.fluid.search .results { width: 100%; } -/*-------------- - Sizes ----------------*/ - -.ui.mini.search { - font-size: 0.78571429em; -} -.ui.small.search { - font-size: 0.92857143em; -} -.ui.search { - font-size: 1em; -} -.ui.large.search { - font-size: 1.14285714em; -} -.ui.big.search { - font-size: 1.28571429em; -} -.ui.huge.search { - font-size: 1.42857143em; -} -.ui.massive.search { - font-size: 1.71428571em; -} - -/*-------------- - Mobile ----------------*/ @media only screen and (max-width: 767px) { .ui.search .results { diff --git a/src/assets/scss/libs/semantic-ui/modules/_sidebar.scss b/src/assets/scss/libs/semantic-ui/modules/_sidebar.scss index 15043b9f..234c52e1 100755 --- a/src/assets/scss/libs/semantic-ui/modules/_sidebar.scss +++ b/src/assets/scss/libs/semantic-ui/modules/_sidebar.scss @@ -48,8 +48,8 @@ ---------------*/ .pushable { - height: 100%; - padding: 0em !important; + height: 100%; + padding: 0em !important; } /* Whole Page */ diff --git a/src/assets/scss/pages/_accounts.scss b/src/assets/scss/pages/_accounts.scss index aba1d330..f693cbfb 100644 --- a/src/assets/scss/pages/_accounts.scss +++ b/src/assets/scss/pages/_accounts.scss @@ -58,10 +58,3 @@ align-items: center; } } - -.settings-wrap { - - .page { - padding: 0 16px 35px; - } -} \ No newline at end of file diff --git a/src/components/Avatar/index.jsx b/src/components/Avatar/index.jsx new file mode 100644 index 00000000..fc9fe102 --- /dev/null +++ b/src/components/Avatar/index.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { svgAvatar } from 'echojs-ping'; + +import avatar from '../../assets/images/default-avatar.svg'; + +class Avatar extends React.Component { + + + render() { + const { name, size } = this.props; + return name ? +
: + avatar; + } + +} + +Avatar.propTypes = { + name: PropTypes.string, + size: PropTypes.number, +}; + +Avatar.defaultProps = { + name: '', + size: 20, +}; + +export default Avatar; diff --git a/src/components/BridgeInput/index.jsx b/src/components/BridgeInput/index.jsx index 07b87c96..19bdc1a6 100644 --- a/src/components/BridgeInput/index.jsx +++ b/src/components/BridgeInput/index.jsx @@ -2,7 +2,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Input, Button } from 'semantic-ui-react'; import classnames from 'classnames'; -import UserIcon from '../UserIcon'; +import Avatar from '../Avatar'; + import CurrencySelect from '../CurrencySelect/index'; class BridgeInput extends React.Component { @@ -74,10 +75,10 @@ class BridgeInput extends React.Component { ); } - renderImage(color, id) { + renderImage(avatar) { return (
- +
); } @@ -102,7 +103,7 @@ class BridgeInput extends React.Component { const { name, labelText, type, error, disabled, theme, value, autoFocus, privacyEye, position, descriptionText, leftLabel, placeholder, - defaultUp, readOnly, userIcon, innerDropdown, hintText, onKeyPress, onKeyDown, + defaultUp, readOnly, avatar, innerDropdown, hintText, onKeyPress, onKeyDown, } = this.props; const { @@ -135,7 +136,7 @@ class BridgeInput extends React.Component { { 'left-label': leftLabel }, { filled: defaultUp }, { readOnly }, - { 'with-image': userIcon }, + { 'with-image': avatar }, position, { 'visible-pas': (privacyEye && showPas) }, )} @@ -156,7 +157,7 @@ class BridgeInput extends React.Component { onKeyDown={(e) => (onKeyDown ? onKeyDown(e) : null)} onKeyPress={(e) => onKeyPress && onKeyPress(e)} /> - { userIcon ? this.renderImage(userIcon.color, userIcon.icon) : null} + { avatar ? this.renderImage(avatar) : null} { error ? this.renderError() : null } { hintText ? this.renderHint() : null } { descriptionText ?
{ descriptionText }
: null } @@ -189,7 +190,7 @@ BridgeInput.propTypes = { onChange: PropTypes.func, privacyEye: PropTypes.bool, innerDropdown: PropTypes.object, - userIcon: PropTypes.object, + avatar: PropTypes.string, onHintClick: PropTypes.func, onKeyDown: PropTypes.func, onKeyPress: PropTypes.func, @@ -218,7 +219,7 @@ BridgeInput.defaultProps = { onChange: null, privacyEye: false, innerDropdown: null, - userIcon: null, + avatar: '', onHintClick: null, onKeyDown: null, onKeyPress: null, diff --git a/src/components/BridgeSidebar/index.jsx b/src/components/BridgeSidebar/index.jsx index 7499bc8d..e5aeff94 100644 --- a/src/components/BridgeSidebar/index.jsx +++ b/src/components/BridgeSidebar/index.jsx @@ -15,7 +15,7 @@ import { WALLET_PATH, UNLOCK_PATH, } from '../../constants/RouterConstants'; -import UserIcon from '../UserIcon'; +import Avatar from '../Avatar'; import LockIcon from '../../assets/images/icons/lock.svg'; import IconClose from '../../assets/images/icons/cross_big.svg'; @@ -56,10 +56,9 @@ class BridgeSidebar extends React.PureComponent { { account && account.size ?
-
{account.get('name')}
: null diff --git a/src/components/CurrencySelect/index.jsx b/src/components/CurrencySelect/index.jsx index 7be18ff7..201c6ae9 100644 --- a/src/components/CurrencySelect/index.jsx +++ b/src/components/CurrencySelect/index.jsx @@ -82,6 +82,9 @@ class CurrencySelect extends React.Component { this.refList = []; } + static getDerivedStateFromProps(nextProps, prevState) { + return { search: prevState.search }; + } componentDidUpdate(prevProps, prevState) { const { opened } = this.state; diff --git a/src/components/NetworkDropdown/index.jsx b/src/components/NetworkDropdown/index.jsx index 0f24c655..b867264c 100644 --- a/src/components/NetworkDropdown/index.jsx +++ b/src/components/NetworkDropdown/index.jsx @@ -6,6 +6,7 @@ import PropTypes from 'prop-types'; import CustomScroll from 'react-custom-scroll'; import { withRouter } from 'react-router'; import classnames from 'classnames'; +import query from 'query-string'; import { changeNetwork, @@ -13,8 +14,12 @@ import { setNetworkInfo, } from '../../actions/GlobalActions'; -import { NETWORKS } from '../../constants/GlobalConstants'; -import { ADD_NETWORK_PATH, NETWORK_PATH } from '../../constants/RouterConstants'; +import { NETWORKS, POPUP_WINDOW_TYPE } from '../../constants/GlobalConstants'; +import { + ADD_NETWORK_PATH, + INCOMING_CONNECTION_PATH, + NETWORK_PATH, +} from '../../constants/RouterConstants'; import GlobalReducer from '../../reducers/GlobalReducer'; @@ -158,6 +163,10 @@ class NetworkDropdown extends React.PureComponent { } toggleDropdown() { + const { windowType, windowPath } = query.parse(window.location.search); + if (windowType === POPUP_WINDOW_TYPE && windowPath === INCOMING_CONNECTION_PATH) { + return; + } this.setState({ opened: !this.state.opened }); } diff --git a/src/components/NewKeyComponent/index.jsx b/src/components/NewKeyComponent/index.jsx index 42b76e5a..3ea872e6 100644 --- a/src/components/NewKeyComponent/index.jsx +++ b/src/components/NewKeyComponent/index.jsx @@ -2,27 +2,26 @@ import React from 'react'; import { Button } from 'semantic-ui-react'; import PropTypes from 'prop-types'; -import UserIcon from '../UserIcon'; +import Avatar from '../Avatar'; import ArrowDown from '../../assets/images/icons/arrow_dark_bot.svg'; class NewKeyComponent extends React.Component { render() { const { - name, icon, iconColor, + name, } = this.props; return (
- - this.props.onChangeIcon()} - /> +
+ {{ name }} + +
@@ -51,17 +50,9 @@ class NewKeyComponent extends React.Component { } - -NewKeyComponent.defaultProps = { - onChangeIcon: null, -}; - NewKeyComponent.propTypes = { name: PropTypes.string.isRequired, - icon: PropTypes.number.isRequired, - iconColor: PropTypes.string.isRequired, proceed: PropTypes.func.isRequired, - onChangeIcon: PropTypes.func, }; export default NewKeyComponent; diff --git a/src/components/SignDropdown/index.jsx b/src/components/SignDropdown/index.jsx index 264ffd97..931b29ce 100644 --- a/src/components/SignDropdown/index.jsx +++ b/src/components/SignDropdown/index.jsx @@ -7,12 +7,12 @@ import classnames from 'classnames'; import { withRouter } from 'react-router'; import { Map } from 'immutable'; -import { BASE_ICON, BASE_ICON_COLOR, CORE_ID, CORE_SYMBOL } from '../../constants/GlobalConstants'; +import { CORE_ID, CORE_SYMBOL } from '../../constants/GlobalConstants'; import FormatHelper from '../../helpers/FormatHelper'; -import UserIcon from '../UserIcon'; import GlobalReducer from '../../reducers/GlobalReducer'; +import Avatar from '../Avatar'; class SignDropdown extends React.PureComponent { @@ -98,11 +98,7 @@ class SignDropdown extends React.PureComponent { onSelect={() => this.onSelect(account.name)} > - +
{account.name}
{ @@ -142,20 +138,12 @@ class SignDropdown extends React.PureComponent { { account.size ? ( - - +