mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
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:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user