Update setup wizard styling (#1954)

* base srevampof home page

* update sembassy page

* update all  ephemeral pages

* matrix animation working

* wip success

* refactor styling  of success page

* modal and mobile adjustments

* cleanup

* make chnages to styles and copy (#1955)

* make chnages to styles and copy

* fix responsiveness of downloadable page

Co-authored-by: Lucy Cifferello <12953208+elvece@users.noreply.github.com>

* refactor success page

* cleanup headers

* revert isKiosk testing

* udpate patch DB

Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com>
Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
Lucy C
2022-11-20 20:37:19 -07:00
committed by Aiden McClelland
parent a3d1b2d671
commit 4042b8f026
23 changed files with 812 additions and 425 deletions

View File

@@ -1,269 +1,232 @@
<ion-content [scrollEvents]="true" (ionScrollEnd)="checkBottom()">
<ion-grid>
<ion-row>
<ion-col>
<!-- kiosk mode -->
<ng-container *ngIf="isKiosk; else notKiosk">
<ion-card color="dark">
<ion-card-header class="ion-text-center" color="success">
<ion-icon
style="font-size: 80px"
name="checkmark-circle-outline"
></ion-icon>
<ion-card-title>Setup Complete</ion-card-title>
<ion-card-subtitle
><b>You will be redirected momentarily</b></ion-card-subtitle
<canvas #canvas> Your browser does not support the canvas element. </canvas>
<ion-content>
<div class="grid-center-wrapper">
<ion-grid [fixed]="true">
<!-- kiosk mode -->
<ng-container *ngIf="isKiosk; else notKiosk">
<ion-card>
<ion-row>
<ion-col size-xs="12" class="ion-text-center">
<div class="inline">
<ion-icon
name="checkmark-circle-outline"
color="success"
></ion-icon>
<h1>Setup Complete!</h1>
</div>
<h3 class="ion-padding-top">
You will be redirected momentarily.
</h3>
</ion-col>
</ion-row>
</ion-card>
</ng-container>
<!-- not kiosk -->
<ng-template #notKiosk>
<ion-card>
<ion-row>
<ion-col size-xs="12" class="ion-text-center">
<div style="margin-bottom: 4rem">
<div class="inline">
<ion-icon
name="checkmark-circle-outline"
color="success"
></ion-icon>
<h1>Setup Complete!</h1>
</div>
<h3 *ngIf="recoverySource && recoverySource.type === 'backup'">
You can now safely unplug your backup drive
</h3>
<h3 *ngIf="recoverySource && recoverySource.type === 'migrate'">
You can now safely unplug your old drive
</h3>
</div>
<div class="card-container">
<ion-card id="information" (click)="download()">
<ion-card-content>
<ion-card-title
>Download your Embassy's address information for permanent
access</ion-card-title
>
<p>
<code>embassy.local</code> was for setup only. It will no
longer work.
</p>
</ion-card-content>
<ion-footer>
<div class="container">
<div class="inline">
<p>Download</p>
<ion-icon name="download-outline"></ion-icon>
</div>
</div>
</ion-footer>
</ion-card>
<ion-card id="launch" href="{{ lanAddress }}" target="_blank">
<ion-card-content>
<ion-card-title
>Launch to login to your Embassy</ion-card-title
>
<p class="ion-padding-bottom">
<span class="emphasis-warn">Important!</span><br />
Your browser will warn you that the page is untrusted. You
can safely bypass this warning. It will go away after you
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
target="_blank"
rel="noreferrer"
>
setup a secure connection </a
>.
</p>
</ion-card-content>
<ion-footer>
<div class="container">
<div class="inline">
<p>Launch</p>
<ion-icon name="rocket-outline"></ion-icon>
</div>
</div>
</ion-footer>
</ion-card>
</div>
</ion-col>
</ion-row>
<!-- cert elem -->
<a hidden id="install-cert" download="embassy.crt"></a>
<!-- download elem -->
<div hidden id="downloadable">
<div
style="
font-family: Montserrat;
color: #333333;
display: flex;
flex-direction: column;
margin: auto;
width: clamp(900px, 35vw, 600px);
"
>
<h1
style="
font-variant-caps: all-small-caps;
text-align: center;
padding: 1rem;
"
>
<br />
</ion-card-header>
</ion-card>
</ng-container>
Embassy Address Info
</h1>
<!-- not kiosk -->
<ng-template #notKiosk>
<ion-card color="dark">
<ion-card-header class="ion-text-center" color="success">
<ion-icon
style="font-size: 80px"
name="checkmark-circle-outline"
></ion-icon>
<ion-card-title>Setup Complete</ion-card-title>
<ion-card-subtitle
><b>See below for next steps</b></ion-card-subtitle
<section
style="
padding: 1rem 3rem 2rem 3rem;
border: solid #c4c4c5 3px;
margin-bottom: 24px;
"
>
<br />
</ion-card-header>
<ion-card-content>
<br />
<br />
<h2 *ngIf="recoverySource" class="ion-padding-bottom">
<span *ngIf="recoverySource.type === 'backup'"
>You can now safely unplug your backup drive.</span
>
<span *ngIf="recoverySource.type === 'migrate'"
>You can now safely unplug your old drive.</span
>
</h2>
<h2 style="font-weight: bold">
Access your Embassy using the methods below. You should
<a (click)="download()" class="inline">
download this page
<ion-icon name="download-outline"></ion-icon>
</a>
for your records.
</h2>
<div class="line"></div>
<!-- LAN Instructions -->
<h1><b>From Home (LAN)</b></h1>
<div class="ion-padding ion-text-start">
<h2 style="font-variant-caps: all-small-caps">
Access from home (LAN)
</h2>
<p>
Visit the address below when you are connected to the same
WiFi or Local Area Network (LAN) as your Embassy:
</p>
<br />
<p>
<b>Note:</b> embassy.local was for setup purposes only, it
will no longer work.
</p>
<ion-item
lines="none"
color="dark"
class="ion-padding-top ion-padding-bottom"
<p
style="
padding: 16px;
font-weight: bold;
font-size: 1.1rem;
overflow: auto;
"
>
<ion-label class="ion-text-wrap">
<code
><ion-text color="light"
><b>{{ lanAddress }}</b></ion-text
></code
<code id="lan-addr"></code>
</p>
<div>
<h3 style="color: #f8546a; font-weight: bold">Important!</h3>
<p>
Your browser will warn you that the page is untrusted. You
can safely bypass this warning. It will go away after you
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
target="_blank"
rel="noreferrer"
style="
color: #6866cc;
font-weight: bold;
text-decoration: none;
"
>
</ion-label>
<ion-button
color="light"
fill="clear"
[href]="lanAddress"
target="_blank"
>
<ion-icon slot="icon-only" name="open-outline"></ion-icon>
</ion-button>
<ion-button
color="light"
fill="clear"
(click)="copy(lanAddress)"
>
<ion-icon slot="icon-only" name="copy-outline"></ion-icon>
</ion-button>
</ion-item>
follow the instructions
</a>
to download and trust your Embassy's Root Certificate
Authority.
</p>
</div>
<p>
<b>Important!</b>
Your browser will warn you that the website is untrusted. You
can bypass this warning on most browsers. The warning will go
away after you
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
target="_blank"
rel="noreferrer"
class="inline"
>
follow the instructions
<ion-icon name="open-outline"></ion-icon>
</a>
to download and trust your Embassy's Root Certificate
Authority.
</p>
<ion-button style="margin-top: 24px" (click)="installCert()">
Download Root CA
<ion-icon slot="end" name="download-outline"></ion-icon>
</ion-button>
</div>
<div class="line"></div>
<!-- Tor Instructions -->
<h1><b>On The Go (Tor)</b></h1>
<div class="ion-padding ion-text-start">
<p>Visit the address below when you are away from home:</p>
<ion-item
lines="none"
color="dark"
class="ion-padding-top ion-padding-bottom"
>
<ion-label class="ion-text-wrap">
<code
><ion-text color="light"
><b>{{ torAddress }}</b></ion-text
></code
>
</ion-label>
<ion-button
color="light"
fill="clear"
(click)="copy(torAddress)"
>
<ion-icon slot="icon-only" name="copy-outline"></ion-icon>
</ion-button>
</ion-item>
<p>
<b>Important!</b>
This address will only work from a
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-tor"
target="_blank"
rel="noreferrer"
class="inline"
>
Tor-enabled browser
<ion-icon name="open-outline"></ion-icon> </a
>.
</p>
</div>
</ion-card-content>
<div id="bottom-div"></div>
</ion-card>
<!-- scroll down -->
<div
[ngStyle]="{
position: 'fixed',
bottom: isOnBottom ? '-42px' : '24px',
transition: 'bottom 0.15s ease-out 0s',
right: '50%',
width: '120px',
'margin-right': '-60px',
'z-index': '1000'
}"
>
<ion-button color="warning" (click)="scrollToBottom()">
More
<ion-icon slot="end" name="chevron-down"></ion-icon>
</ion-button>
</div>
<!-- cert elem -->
<a hidden id="install-cert" download="embassy.crt"></a>
<!-- download elem -->
<div hidden id="downloadable">
<div style="padding: 0 24px; font-family: Courier">
<h1>Embassy Info</h1>
<section style="padding: 16px; border: solid 1px">
<h2>Tor Info</h2>
<p>
To use your Embassy over Tor, visit its unique Tor address
from any Tor-enabled browser.
</p>
<p>
For more detailed instructions, click
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-tor"
target="_blank"
rel="noreferrer"
><b>here</b></a
>.
</p>
<p><b>Tor Address: </b><code id="tor-addr"></code></p>
</section>
<section
style="padding: 16px; border: solid 1px; border-top: none"
>
<h2>LAN Info</h2>
<p>To use your Embassy locally, you must:</p>
<ol>
<li>
Currently be connected to the same Local Area Network (LAN)
as your Embassy.
</li>
<li>Download your Embassy's Root Certificate Authority.</li>
<li>
Trust your Embassy's Root CA on <i>both</i> your
computer/phone and in your browser settings.
</li>
</ol>
<p>
For step-by-step instructions, click
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
target="_blank"
rel="noreferrer"
><b>here</b></a
>.
</p>
<div style="margin: 42px 0">
<div style="padding: 2rem; text-align: center">
<a
id="cert"
download="embassy.crt"
style="
background: #25272b;
padding: 10px;
display: inline-block;
padding: 1em 1.2em;
box-sizing: border-box;
font-size: 1rem;
text-decoration: none;
text-align: center;
border-radius: 4px;
color: white;
border-radius: clamp(2rem, 3rem, 4rem);
cursor: pointer;
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
background: #6866cc;
color: #f4f4f5;
"
>
Download Root CA
</a>
</div>
</section>
<p><b>LAN Address: </b><code id="lan-addr"></code></p>
<section
style="padding: 1rem 3rem 2rem 3rem; border: solid #c4c4c5 3px"
>
<h2 style="font-variant-caps: all-small-caps">
Access on the go (Tor)
</h2>
<p>Visit the address below when you are away from home:</p>
<p
style="
padding: 16px;
font-weight: bold;
font-size: 1.1rem;
overflow: auto;
"
>
<code id="tor-addr"></code>
</p>
<div>
<h3 style="color: #f8546a; font-weight: bold">Important!</h3>
<p>
This address will only work from a Tor-enabled browser.
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-tor"
target="_blank"
rel="noreferrer"
style="
color: #6866cc;
font-weight: bold;
text-decoration: none;
"
>
Follow the instructions
</a>
to get setup.
</p>
</div>
</section>
</div>
</div>
</ng-template>
</ion-col>
</ion-row>
</ion-grid>
</ion-card>
</ng-template>
</ion-grid>
</div>
</ion-content>

View File

@@ -1,15 +1,149 @@
p {
color: var(--ion-color-light);
canvas {
position: fixed;
left: 0;
top: 0;
z-index: -1;
}
a {
text-decoration: none;
font-weight: bold;
cursor: pointer;
h1 {
font-variant: all-small-caps;
margin: unset;
}
.line {
margin-bottom: 48px;
padding-bottom: 48px;
border-bottom: solid 1px;
ion-content {
position: absolute;
z-index: 0;
--background: transparent;
}
ion-grid {
padding-top: 2rem;
max-width: 760px;
margin: auto;
}
.grid-center-wrapper {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
ion-card {
padding: 3rem;
h1 {
color: var(--ion-color-success);
padding-left: 0.5rem;
}
ion-icon {
font-size: 40px;
}
li {
margin-bottom: 2rem;
}
ion-card {
max-width: 91%;
background: #615F5F;
color: var(--ion-text-color);
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 44px;
margin: auto;
text-align: left;
cursor: pointer;
position: relative;
padding: 1rem 2rem;
transition: all 350ms ease;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
transition-property: transform;
transform: scale(1.05);
transition-delay: 40ms;
}
ion-card-title {
color: var(--ion-text-color);
font-size: 1.3rem;
}
ion-card-content {
padding-bottom: 4rem;
p {
padding: 1rem 0;
}
}
p {
a {
text-decoration: none;
font-weight: bold;
color: var(--ion-text-color);
}
}
ion-footer {
position: absolute;
bottom: 10px;
left: 0;
color: var(--ion-text-color);
p {
font-size: 1.1rem;
font-weight: bold;
margin: unset;
}
ion-icon {
font-size: 1.6rem;
}
.container {
display: flex;
justify-content: center;
align-items: center;
}
}
.footer-md::before {
background-image: none;
}
}
#launch:after {
content: '';
position: absolute;
left: 0;
top: 80%;
width: 100%;
height: 100%;
background: var(--alt-blue);
}
#information:after {
content: '';
position: absolute;
left: 0;
top: 77%;
width: 100%;
height: 100%;
background: var(--color-accent);
}
}
.card-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 2rem;
}
.emphasis-warn {
font-weight: 600;
color: var(--ion-color-warning);
}

View File

@@ -1,8 +1,10 @@
import { DOCUMENT } from '@angular/common'
import {
Component,
ElementRef,
EventEmitter,
Inject,
NgZone,
Output,
ViewChild,
} from '@angular/core'
@@ -24,15 +26,23 @@ import { StateService } from 'src/app/services/state.service'
export class SuccessPage {
@ViewChild(IonContent)
private content?: IonContent
@ViewChild('canvas', { static: true })
private canvas: ElementRef<HTMLCanvasElement> = {} as ElementRef<HTMLCanvasElement>
private ctx: CanvasRenderingContext2D = {} as CanvasRenderingContext2D
@Output() onDownload = new EventEmitter()
torAddress = ''
lanAddress = ''
cert = ''
isOnBottom = true
tileSize = 16
// a higher fade factor will make the characters fade quicker
fadeFactor = 0.07
columns: any[] = []
maxStackHeight: any
constructor(
@Inject(DOCUMENT) private readonly document: Document,
private readonly toastCtrl: ToastController,
@@ -40,6 +50,7 @@ export class SuccessPage {
private readonly stateService: StateService,
private api: ApiService,
private readonly downloadHtml: DownloadHTMLService,
private ngZone: NgZone,
) {}
get recoverySource() {
@@ -51,6 +62,7 @@ export class SuccessPage {
}
async ngAfterViewInit() {
this.ngZone.runOutsideAngular(() => this.initMatrix())
try {
const ret = await this.api.complete()
if (!this.isKiosk) {
@@ -67,7 +79,6 @@ export class SuccessPage {
'data:application/x-x509-ca-cert;base64,' +
encodeURIComponent(this.cert),
)
this.download()
}
await this.api.exit()
} catch (e: any) {
@@ -118,7 +129,57 @@ export class SuccessPage {
bottomDiv.getBoundingClientRect().top - 192 < window.innerHeight
}
scrollToBottom() {
this.content?.scrollToBottom(250)
initMatrix() {
this.ctx = this.canvas.nativeElement.getContext('2d')!
this.canvas.nativeElement.width = window.innerWidth
this.canvas.nativeElement.height = window.innerHeight
this.setupMatrixGrid()
this.tick()
}
setupMatrixGrid() {
this.maxStackHeight = Math.ceil(this.ctx.canvas.height / this.tileSize)
// divide the canvas into columns
for (let i = 0; i < this.ctx.canvas.width / this.tileSize; ++i) {
const column = {} as any
// save the x position of the column
column.x = i * this.tileSize
// create a random stack height for the column
column.stackHeight = 10 + Math.random() * this.maxStackHeight
// add a counter to count the stack height
column.stackCounter = 0
// add the column to the list
this.columns.push(column)
}
}
draw() {
// draw a semi transparent black rectangle on top of the scene to slowly fade older characters
this.ctx.fillStyle = 'rgba( 0 , 0 , 0 , ' + this.fadeFactor + ' )'
this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
// pick a font slightly smaller than the tile size
this.ctx.font = this.tileSize - 2 + 'px monospace'
this.ctx.fillStyle = '#ff4961'
for (let i = 0; i < this.columns.length; ++i) {
// pick a random ascii character (change the 94 to a higher number to include more characters)
const randomCharacter = String.fromCharCode(
33 + Math.floor(Math.random() * 94),
)
this.ctx.fillText(
randomCharacter,
this.columns[i].x,
this.columns[i].stackCounter * this.tileSize + this.tileSize,
)
// if the stack is at its height limit, pick a new random height and reset the counter
if (++this.columns[i].stackCounter >= this.columns[i].stackHeight) {
this.columns[i].stackHeight = 10 + Math.random() * this.maxStackHeight
this.columns[i].stackCounter = 0
}
}
}
tick() {
this.draw()
setTimeout(this.tick.bind(this), 50)
}
}