Skip to content

Commit

Permalink
Provide dark mode theme for link dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
petejkim committed Feb 25, 2020
1 parent a0b3217 commit 34c6229
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 33 deletions.
5 changes: 4 additions & 1 deletion js/src/WalletLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface WalletLinkOptions {
appName: string
/** @optional Application logo image URL; favicon is used if unspecified */
appLogoUrl?: string | null
/** @optional Use dark theme */
darkMode?: boolean
/** @optional WalletLink server URL; for most, leave it unspecified */
walletLinkUrl?: string
}
Expand All @@ -41,7 +43,8 @@ export class WalletLink {
constructor(options: Readonly<WalletLinkOptions>) {
this._relay = new WalletLinkRelay({
walletLinkUrl: options.walletLinkUrl || WALLETLINK_URL,
version: WALLETLINK_VERSION
version: WALLETLINK_VERSION,
darkMode: !!options.darkMode
})
this.setAppInfo(options.appName, options.appLogoUrl)
this._relay.attach(document.documentElement)
Expand Down
2 changes: 1 addition & 1 deletion js/src/components/LinkDialog-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
// Copyright (c) 2018-2020 Coinbase, Inc. <https://www.coinbase.com/>
// Licensed under the Apache License, version 2.0

export default `.-walletlink-css-reset .-walletlink-link-dialog{z-index:2147483647;position:fixed;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center}.-walletlink-css-reset .-walletlink-link-dialog-backdrop{z-index:2147483647;position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,.33);transition:opacity .25s}.-walletlink-css-reset .-walletlink-link-dialog-backdrop-hidden{opacity:0}.-walletlink-css-reset .-walletlink-link-dialog-box{display:flex;position:relative;flex-direction:column;background-color:#f6f6f6;border-radius:16px;box-shadow:0px 16px 24px rgba(0,0,0,.1),0px 0px 8px rgba(0,0,0,.05);transform:scale(1);transition:opacity .25s,transform .25s;overflow:hidden}.-walletlink-css-reset .-walletlink-link-dialog-box-hidden{opacity:0;transform:scale(0.85)}.-walletlink-css-reset .-walletlink-link-dialog-box-content{padding:24px;text-align:center}.-walletlink-css-reset .-walletlink-link-dialog-box-content h3{display:block;margin-bottom:24px;text-align:left;text-transform:uppercase;font-size:22px;font-weight:bold;line-height:1.2}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode{position:relative;display:block;margin-bottom:24px;background-color:#f6f6f6;padding:16px;border-radius:16px;box-shadow:4px 4px 8px rgba(0,0,0,.15),-8px -8px 8px #fff;overflow:hidden}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-wrapper{display:block;width:224px;height:224px;margin-bottom:16px}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-wrapper img{display:block;width:224px;height:224px}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode>p{display:block;color:gray;font-weight:bold;font-size:12px;text-align:center}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-connecting{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(255,255,255,.98)}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-connecting p{margin-top:16px;color:#333;font-size:12px;font-weight:bold}.-walletlink-css-reset .-walletlink-link-dialog-box-content a{text-align:center;cursor:pointer;transition:color .1s}.-walletlink-css-reset .-walletlink-link-dialog-box-content a,.-walletlink-css-reset .-walletlink-link-dialog-box-content a:link,.-walletlink-css-reset .-walletlink-link-dialog-box-content a:visited{color:#999}.-walletlink-css-reset .-walletlink-link-dialog-box-content a:hover,.-walletlink-css-reset .-walletlink-link-dialog-box-content a:active{color:#666;text-decoration:underline}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel{position:absolute;-webkit-appearance:none;display:flex;align-items:center;justify-content:center;top:24px;right:24px;width:24px;height:24px;border-radius:12px;background-color:#e7e7e7;cursor:pointer}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel img{transition:opacity .1s;opacity:.33}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel:hover img{opacity:1}.-walletlink-css-reset .-walletlink-link-dialog-container{display:block}.-walletlink-css-reset .-walletlink-link-dialog-container-hidden{display:none}`
export default `.-walletlink-css-reset .-walletlink-link-dialog{z-index:2147483647;position:fixed;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center}.-walletlink-css-reset .-walletlink-link-dialog-backdrop{z-index:2147483647;position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,.33);transition:opacity .25s}.-walletlink-css-reset .-walletlink-link-dialog-backdrop-hidden{opacity:0}.-walletlink-css-reset .-walletlink-link-dialog-box{display:flex;position:relative;flex-direction:column;background-color:#f6f6f6;border-radius:16px;box-shadow:0px 16px 24px rgba(0,0,0,.1),0px 0px 8px rgba(0,0,0,.05);transform:scale(1);transition:opacity .25s,transform .25s;overflow:hidden}.-walletlink-css-reset .-walletlink-link-dialog-box-hidden{opacity:0;transform:scale(0.85)}.-walletlink-css-reset .-walletlink-link-dialog-box-content{padding:24px;text-align:center}.-walletlink-css-reset .-walletlink-link-dialog-box-content h3{display:block;margin-bottom:24px;text-align:left;text-transform:uppercase;font-size:22px;font-weight:bold;line-height:1.2;color:#000}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode{position:relative;display:block;margin-bottom:24px;background-color:#f6f6f6;padding:16px;border-radius:16px;box-shadow:4px 4px 8px rgba(0,0,0,.15),-8px -8px 8px #fff;overflow:hidden}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-wrapper{display:block;width:224px;height:224px;margin-bottom:16px}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-wrapper img{display:block;width:224px;height:224px}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode>p{display:block;color:gray;font-weight:bold;font-size:12px;text-align:center}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-connecting{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(246,246,246,.98)}.-walletlink-css-reset .-walletlink-link-dialog-box-content-qrcode-connecting p{margin-top:16px;color:#333;font-size:12px;font-weight:bold}.-walletlink-css-reset .-walletlink-link-dialog-box-content a{text-align:center;cursor:pointer;transition:color .1s}.-walletlink-css-reset .-walletlink-link-dialog-box-content a,.-walletlink-css-reset .-walletlink-link-dialog-box-content a:link,.-walletlink-css-reset .-walletlink-link-dialog-box-content a:visited{color:#999}.-walletlink-css-reset .-walletlink-link-dialog-box-content a:hover,.-walletlink-css-reset .-walletlink-link-dialog-box-content a:active{color:#666;text-decoration:underline}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel{position:absolute;-webkit-appearance:none;display:flex;align-items:center;justify-content:center;top:24px;right:24px;width:24px;height:24px;border-radius:12px;background-color:#e7e7e7;cursor:pointer}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel-x{position:relative;display:block}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel-x-a,.-walletlink-css-reset .-walletlink-link-dialog-box-cancel-x-b{position:absolute;display:block;top:-1px;left:-7px;width:14px;height:2px;background-color:#999;transition:background-color .2s}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel-x-a{transform:rotate(45deg)}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel-x-b{transform:rotate(135deg)}.-walletlink-css-reset .-walletlink-link-dialog-box-cancel:hover .-walletlink-link-dialog-box-cancel-x-a,.-walletlink-css-reset .-walletlink-link-dialog-box-cancel:hover .-walletlink-link-dialog-box-cancel-x-b{background-color:#000}.-walletlink-css-reset .-walletlink-link-dialog-container{display:block}.-walletlink-css-reset .-walletlink-link-dialog-container-hidden{display:none}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box{background-color:#2a2a2a}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content h3{color:#ccc}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content-qrcode{background-color:#2a2a2a;box-shadow:4px 4px 8px rgba(0,0,0,.5),-8px -8px 8px #333}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content-qrcode>p{color:#999}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content-qrcode-connecting{background:rgba(42,42,42,.98)}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content-qrcode-connecting p{color:#ddd}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content a,.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content a:link,.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content a:visited{color:#888}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content a:hover,.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-content a:active{color:#aaa}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-cancel{background-color:#333}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-cancel-x-a,.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-cancel-x-b{background-color:#aaa}.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-cancel:hover .-walletlink-link-dialog-box-cancel-x-a,.-walletlink-css-reset .-walletlink-link-dialog-container-dark .-walletlink-link-dialog-box-cancel:hover .-walletlink-link-dialog-box-cancel-x-b{background-color:#eee}`
102 changes: 96 additions & 6 deletions js/src/components/LinkDialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
font-size: 22px;
font-weight: bold;
line-height: 1.2;
color: #000;
}

&-qrcode {
Expand Down Expand Up @@ -100,7 +101,7 @@
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(#fff, 0.98);
background: rgba(#f6f6f6, 0.98);

p {
margin-top: 16px;
Expand Down Expand Up @@ -144,13 +145,38 @@
background-color: #e7e7e7;
cursor: pointer;

img {
transition: opacity 0.1s;
opacity: 0.33;
&-x {
position: relative;
display: block;

&-a,
&-b {
position: absolute;
display: block;
top: -1px;
left: -7px;
width: 14px;
height: 2px;
background-color: #999;
transition: background-color 0.2s;
}

&-a {
transform: rotate(45deg);
}

&-b {
transform: rotate(135deg);
}
}

&:hover img {
opacity: 1;
&:hover {
.-walletlink-link-dialog-box-cancel-x {
&-a,
&-b {
background-color: #000;
}
}
}
}
}
Expand All @@ -163,4 +189,68 @@
}
}
}

.-walletlink-link-dialog-container-dark {
.-walletlink-link-dialog {
&-box {
background-color: #2a2a2a;

&-content {
h3 {
color: #ccc;
}

&-qrcode {
background-color: #2a2a2a;
box-shadow: 4px 4px 8px rgba(#000, 0.5), -8px -8px 8px #333;

> p {
color: #999;
}

&-connecting {
background: rgba(#2a2a2a, 0.98);

p {
color: #ddd;
}
}
}

a {
&,
&:link,
&:visited {
color: #888;
}

&:hover,
&:active {
color: #aaa;
}
}
}

&-cancel {
background-color: #333;

&-x {
&-a,
&-b {
background-color: #aaa;
}
}

&:hover {
.-walletlink-link-dialog-box-cancel-x {
&-a,
&-b {
background-color: #eee;
}
}
}
}
}
}
}
}
26 changes: 16 additions & 10 deletions js/src/components/LinkDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import clsx from "clsx"
import { FunctionComponent, h } from "preact"
import { useEffect, useState } from "preact/hooks"
import closeSvg from "../images/close-svg"
import css from "./LinkDialog-css"
import { QRCode } from "./QRCode"
import { Spinner } from "./Spinner"

export const LinkDialog: FunctionComponent<{
darkMode: boolean
version: string
sessionId: string
sessionSecret: string
Expand Down Expand Up @@ -49,6 +49,7 @@ export const LinkDialog: FunctionComponent<{
<div
class={clsx(
"-walletlink-link-dialog-container",
props.darkMode && "-walletlink-link-dialog-container-dark",
isContainerHidden && "-walletlink-link-dialog-container-hidden"
)}
>
Expand All @@ -67,28 +68,23 @@ export const LinkDialog: FunctionComponent<{
)}
>
<ScanQRCode
darkMode={props.darkMode}
version={props.version}
sessionId={props.sessionId}
sessionSecret={props.sessionSecret}
walletLinkUrl={props.walletLinkUrl}
isConnected={props.isConnected}
/>

{props.onCancel && (
<button
class="-walletlink-link-dialog-box-cancel"
onClick={props.onCancel}
>
<img src={closeSvg} alt="Cancel" />
</button>
)}
{props.onCancel && <CancelButton onClick={props.onCancel} />}
</div>
</div>
</div>
)
}

const ScanQRCode: FunctionComponent<{
darkMode: boolean
version: string
sessionId: string
sessionSecret: string
Expand All @@ -111,13 +107,14 @@ const ScanQRCode: FunctionComponent<{
content={qrUrl}
width={224}
height={224}
fgColor={props.darkMode ? "#fff" : "#000"}
bgColor="transparent"
/>
</div>
<input type="hidden" value={qrUrl} />
{!props.isConnected && (
<div class="-walletlink-link-dialog-box-content-qrcode-connecting">
<Spinner size={128} color="#000" />
<Spinner size={128} color={props.darkMode ? "#fff" : "#000"} />
<p>Connecting...</p>
</div>
)}
Expand All @@ -134,3 +131,12 @@ const ScanQRCode: FunctionComponent<{
</div>
)
}

const CancelButton: FunctionComponent<{ onClick: () => void }> = props => (
<button class="-walletlink-link-dialog-box-cancel" onClick={props.onClick}>
<div class="-walletlink-link-dialog-box-cancel-x">
<div class="-walletlink-link-dialog-box-cancel-x-a" />
<div class="-walletlink-link-dialog-box-cancel-x-b" />
</div>
</button>
)
4 changes: 4 additions & 0 deletions js/src/components/LinkFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Observable, Subscription } from "rxjs"
import { LinkDialog } from "./LinkDialog"

export interface LinkFlowOptions {
darkMode: boolean
version: string
sessionId: string
sessionSecret: string
Expand All @@ -15,6 +16,7 @@ export interface LinkFlowOptions {
}

export class LinkFlow {
private readonly darkMode: boolean
private readonly version: string
private readonly sessionId: string
private readonly sessionSecret: string
Expand All @@ -30,6 +32,7 @@ export class LinkFlow {
private root: Element | null = null

constructor(options: Readonly<LinkFlowOptions>) {
this.darkMode = options.darkMode
this.version = options.version
this.sessionId = options.sessionId
this.sessionSecret = options.sessionSecret
Expand Down Expand Up @@ -81,6 +84,7 @@ export class LinkFlow {

render(
<LinkDialog
darkMode={this.darkMode}
version={this.version}
sessionId={this.sessionId}
sessionSecret={this.sessionSecret}
Expand Down
25 changes: 20 additions & 5 deletions js/src/components/Snackbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { useEffect, useState } from "preact/hooks"
import chevronSvg from "../images/chevron-svg"
import css from "./Snackbar-css"

export interface SnackbarOptions {
darkMode: boolean
}

export interface SnackbarItemProps {
message?: string
showProgressBar?: boolean
Expand All @@ -21,10 +25,16 @@ export interface SnackbarItemAction {
}

export class Snackbar {
private items = new Map<number, SnackbarItemProps>()
private readonly darkMode: boolean
private readonly items = new Map<number, SnackbarItemProps>()

private nextItemKey = 0
private root: Element | null = null

constructor(options: Readonly<SnackbarOptions>) {
this.darkMode = options.darkMode
}

public attach(el: Element): void {
this.root = document.createElement("div")
this.root.className = "-walletlink-snackbar-root"
Expand Down Expand Up @@ -54,7 +64,7 @@ export class Snackbar {
return
}
render(
<SnackbarContainer>
<SnackbarContainer darkMode={this.darkMode}>
{Array.from(this.items.entries()).map(([key, itemProps]) => (
<SnackbarItem {...itemProps} key={key} />
))}
Expand All @@ -64,10 +74,15 @@ export class Snackbar {
}
}

const SnackbarContainer: FunctionComponent = ({ children }) => (
<div class="-walletlink-snackbar-container">
const SnackbarContainer: FunctionComponent<{ darkMode: boolean }> = props => (
<div
class={clsx(
"-walletlink-snackbar-container",
props.darkMode && "-walletlink-snackbar-container-dark"
)}
>
<style>{css}</style>
<div class="-walletlink-snackbar">{children}</div>
<div class="-walletlink-snackbar">{props.children}</div>
</div>
)

Expand Down
5 changes: 0 additions & 5 deletions js/src/images/close-svg.ts

This file was deleted.

4 changes: 0 additions & 4 deletions js/src/images/close.svg

This file was deleted.

8 changes: 7 additions & 1 deletion js/src/relay/WalletLinkRelay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type ResponseCallback = (response: Web3Response) => void
export interface WalletLinkRelayOptions {
walletLinkUrl: string
version: string
darkMode: boolean
}

export class WalletLinkRelay {
Expand All @@ -77,7 +78,7 @@ export class WalletLinkRelay {
private readonly connection: WalletLinkConnection

private readonly linkFlow: LinkFlow
private readonly snackbar = new Snackbar()
private readonly snackbar: Snackbar

private appName = ""
private appLogoUrl: string | null = null
Expand Down Expand Up @@ -109,7 +110,12 @@ export class WalletLinkRelay {
.pipe(filter(c => !!c.metadata && c.metadata.__destroyed === "1"))
.subscribe({ next: this.resetAndReload })

this.snackbar = new Snackbar({
darkMode: options.darkMode
})

this.linkFlow = new LinkFlow({
darkMode: options.darkMode,
version: options.version,
sessionId: this.session.id,
sessionSecret: this.session.secret,
Expand Down

0 comments on commit 34c6229

Please sign in to comment.