Update/misc UI fixes (#1961)

* fix login error message spacing and ensure not longer than 64 chars

* spinner color to tertiary

* totally responsive homepage cards

* copy changes, back button for marketplace, minor styling

* center setup wizard tiles; adjust external link style

* remove cert note from setup success

* convert launch card to go to login button

* change system settings to system; update icons

* refactor card widget input as full card details; more card resizing for home page

* cleanup

* clean up widget params

* delete contructor

Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
Lucy C
2022-11-23 06:05:36 -07:00
committed by Aiden McClelland
parent 6eea2526f6
commit f7c5e64fbc
36 changed files with 451 additions and 322 deletions

View File

@@ -49,7 +49,6 @@
[ngModelOptions]="{'standalone': true}"
[type]="!unmasked2 ? 'password' : 'text'"
(ionChange)="checkVer()"
maxlength="64"
placeholder="Retype Password"
></ion-input>
<ion-button

View File

@@ -63,6 +63,8 @@ export class PasswordPage {
if (this.password.length < 12) {
this.pwError = 'Must be 12 characters or greater'
} else if (this.password.length > 64) {
this.pwError = 'Must be less than 65 characters'
} else {
this.pwError = ''
}

View File

@@ -1,6 +1,6 @@
<ion-content>
<ion-grid>
<ion-row>
<ion-row class="ion-align-items-center">
<ion-col>
<ion-card color="dark">
<ion-card-header class="ion-text-center">

View File

@@ -1,6 +1,6 @@
<ion-content>
<ion-grid>
<ion-row>
<ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">
<ion-card color="dark">
<ion-card-header

View File

@@ -1,6 +1,6 @@
<ion-content>
<ion-grid>
<ion-row>
<ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">
<div style="padding-bottom: 32px">
<img
@@ -9,7 +9,6 @@
style="max-width: 220px"
/>
</div>
<ion-card *ngIf="!loading" color="dark">
<ion-card-header>
<ion-button

View File

@@ -1,6 +1,6 @@
<ion-content>
<ion-grid>
<ion-row>
<ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">
<ion-card color="dark">
<ion-card-header>

View File

@@ -1,6 +1,6 @@
<ion-content>
<ion-grid>
<ion-row>
<ion-row class="ion-align-items-center">
<ion-col>
<ion-card color="dark">
<ion-card-header class="ion-text-center">

View File

@@ -1,32 +1,13 @@
<canvas #canvas> Your browser does not support the canvas element. </canvas>
<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">
<ion-grid>
<ion-row class="ion-align-items-center">
<ion-col>
<!-- kiosk mode -->
<ng-container *ngIf="isKiosk; else notKiosk">
<ion-card>
<ion-row class="ion-align-items-center">
<ion-col size-xs="12" class="ion-text-center">
<div class="inline">
<ion-icon
name="checkmark-circle-outline"
@@ -34,199 +15,215 @@
></ion-icon>
<h1>Setup Complete!</h1>
</div>
<h3 *ngIf="recoverySource && recoverySource.type === 'backup'">
You can now safely unplug your backup drive
<h3 class="ion-padding-top">
You will be redirected momentarily.
</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>
</ion-col>
</ion-row>
</ion-card>
</ng-container>
<!-- not kiosk -->
<ng-template #notKiosk>
<ion-card>
<ion-row class="ion-align-items-center">
<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 permanent address info</ion-card-title
>
<p>
embassy.local was for setup purposes 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
[disabled]="disableLogin"
id="launch"
href="{{ lanAddress }}"
target="_blank"
>
<div class="container">
<div class="inline">
<p>Download</p>
<ion-icon name="download-outline"></ion-icon>
<p>Go to Embassy login</p>
<ion-icon name="open-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
</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;
"
>
Embassy Address Info
</h1>
<section
style="
padding: 1rem 3rem 2rem 3rem;
border: solid #c4c4c5 3px;
margin-bottom: 24px;
"
>
<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>
<p
style="
padding: 16px;
font-weight: bold;
font-size: 1.1rem;
overflow: auto;
"
>
<code id="lan-addr"></code>
</p>
<div>
<h3 style="color: #f8546a; font-weight: bold">
Important!
</h3>
<p>
Be sure to
<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;
"
>
setup a secure connection </a
>.
follow the instructions
</a>
to establish a secure connection by installing your
Embassy's certificate.
</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;
"
>
Embassy Address Info
</h1>
</div>
<section
style="
padding: 1rem 3rem 2rem 3rem;
border: solid #c4c4c5 3px;
margin-bottom: 24px;
"
>
<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>
<p
style="
padding: 16px;
font-weight: bold;
font-size: 1.1rem;
overflow: auto;
"
>
<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
<div style="padding: 2rem; text-align: center">
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
target="_blank"
rel="noreferrer"
id="cert"
download="embassy.crt"
style="
color: #6866cc;
font-weight: bold;
display: inline-block;
padding: 1em 1.2em;
box-sizing: border-box;
font-size: 1rem;
text-decoration: none;
text-align: center;
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;
"
>
follow the instructions
Download certificate
</a>
to download and trust your Embassy's Root Certificate
Authority.
</p>
</div>
</div>
</section>
<div style="padding: 2rem; text-align: center">
<a
id="cert"
download="embassy.crt"
<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="
display: inline-block;
padding: 1em 1.2em;
box-sizing: border-box;
font-size: 1rem;
text-decoration: none;
text-align: center;
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;
padding: 16px;
font-weight: bold;
font-size: 1.1rem;
overflow: auto;
"
>
Download Root CA
</a>
</div>
</section>
<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.
<code id="tor-addr"></code>
</p>
</div>
</section>
<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>
</div>
</ion-card>
</ng-template>
</ion-grid>
</div>
</ion-card>
</ng-template>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>

View File

@@ -17,9 +17,8 @@ ion-content {
}
ion-grid {
padding-top: 2rem;
max-width: 760px;
margin: auto;
height: 100%;
}
.grid-center-wrapper {
@@ -47,6 +46,7 @@ ion-card {
ion-card {
max-width: 91%;
min-width: 91%;
background: #615F5F;
color: var(--ion-text-color);
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
@@ -78,14 +78,6 @@ ion-card {
}
}
p {
a {
text-decoration: none;
font-weight: bold;
color: var(--ion-text-color);
}
}
ion-footer {
position: absolute;
bottom: 10px;
@@ -101,12 +93,6 @@ ion-card {
ion-icon {
font-size: 1.6rem;
}
.container {
display: flex;
justify-content: center;
align-items: center;
}
}
.footer-md::before {
@@ -114,21 +100,31 @@ ion-card {
}
}
#launch:after {
content: '';
position: absolute;
left: 0;
top: 80%;
width: 100%;
height: 100%;
.container {
display: flex;
justify-content: center;
align-items: center;
}
#launch {
background: var(--alt-blue);
height: 100%;
.container p {
font-size: 1.4rem !important;
font-weight: bold;
}
ion-icon {
font-size: 1.7rem;
}
}
#information:after {
content: '';
position: absolute;
left: 0;
top: 77%;
top: 80%;
width: 100%;
height: 100%;
background: var(--color-accent);

View File

@@ -42,6 +42,7 @@ export class SuccessPage {
fadeFactor = 0.07
columns: any[] = []
maxStackHeight: any
disableLogin = true
constructor(
@Inject(DOCUMENT) private readonly document: Document,
@@ -119,7 +120,9 @@ export class SuccessPage {
encodeURIComponent(this.cert),
)
let html = this.document.getElementById('downloadable')?.innerHTML || ''
this.downloadHtml.download('embassy-info.html', html)
this.downloadHtml.download('embassy-info.html', html).then(_ => {
this.disableLogin = false
})
}
checkBottom() {

View File

@@ -1,6 +1,6 @@
<ion-content>
<ion-grid>
<ion-row>
<ion-row class="ion-align-items-center">
<ion-col>
<ion-card color="dark">
<ion-card-header class="ion-text-center">

View File

@@ -116,12 +116,12 @@
--color-accent: #6866cc;
--color-dark-black: #121212;
--alt-red: #FF4961;
--alt-orange: #F89248;
--alt-yellow: #E5D53E;
--alt-green: #3DCF6F;
--alt-blue: #00A8A8;
--alt-purple: #9747FF;
--alt-red: #FF4961;
--alt-orange: #F89248;
--alt-yellow: #E5D53E;
--alt-green: #3DCF6F;
--alt-blue: #00A8A8;
--alt-purple: #9747FF;
}
h1,
@@ -177,7 +177,7 @@ ion-grid {
}
ion-row {
height: 100%;
height: 90%;
}
ion-card {
@@ -334,4 +334,11 @@ ion-footer {
ion-item {
margin: 0 0.5rem 2rem 0.5rem;
}
}
p a {
color: var(--ion-text-color);
// text-decoration: none;
font-weight: 600;
text-underline-offset: 0.4rem;
}

View File

@@ -1,7 +1,7 @@
<ion-grid class="full-height">
<ion-row class="ion-align-items-center ion-text-center full-height">
<ion-col>
<ion-spinner color="warning"></ion-spinner>
<ion-spinner color="tertiary"></ion-spinner>
<p>{{ text }}</p>
</ion-col>
</ion-row>

View File

@@ -22,7 +22,7 @@ const routes: Routes = [
import('./pages/home/home.module').then(m => m.HomePageModule),
},
{
path: 'settings',
path: 'system',
canActivate: [AuthGuard],
canActivateChild: [AuthGuard],
loadChildren: () =>

View File

@@ -22,7 +22,7 @@
{{ page.title }}
</ion-label>
<ion-icon
*ngIf="page.url === '/settings' && (showEOSUpdate$ | async)"
*ngIf="page.url === '/system' && (showEOSUpdate$ | async)"
color="success"
size="small"
name="rocket-outline"

View File

@@ -38,9 +38,9 @@ export class MenuComponent {
icon: 'notifications-outline',
},
{
title: 'System Settings',
url: '/settings',
icon: 'settings-outline',
title: 'System',
url: '/system',
icon: 'construct-outline',
},
]

View File

@@ -54,6 +54,7 @@ const ICONS = [
'newspaper-outline',
'notifications-outline',
'open-outline',
'options-outline',
'pencil',
'phone-portrait-outline',
'play-circle-outline',

View File

@@ -11,7 +11,7 @@
<ng-container *ngTemplateOutlet="content"></ng-container>
</a>
<ng-template #internal>
<a [routerLink]="link">
<a [routerLink]="link" [queryParams]="qp">
<ng-container *ngTemplateOutlet="content"></ng-container>
</a>
</ng-template>

View File

@@ -13,7 +13,8 @@ import {
})
export class AnyLinkComponent implements OnInit {
@Input() link!: string
externalLink: boolean = false
@Input() qp?: Record<string, string>
externalLink = false
ngOnInit() {
try {

View File

@@ -1,15 +1,28 @@
<ion-card>
<any-link link="{{ link }}">
<div class="p1">
<ion-card-header>
<ion-card-title>{{ title }}</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-icon name="{{ icon }}" style="color: {{ color }}"></ion-icon>
</ion-card-content>
<ion-footer>
{{ description }}
</ion-footer>
</div>
</any-link>
</ion-card>
<div
class="outer-wrapper"
#outerWrapper
[ngStyle]="{ height: outerHeight, width: outerWidth }"
>
<div
class="inner-wrapper"
#innerWrapper
[ngStyle]="{ transform: innerTransform }"
>
<ion-card>
<any-link [link]="cardDetails.link" [qp]="cardDetails.qp">
<ion-card-header>
<ion-card-title>{{ cardDetails.title }}</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-icon
[name]="cardDetails.icon"
[style.color]="cardDetails.color"
></ion-icon>
</ion-card-content>
<ion-footer>
<p>{{ cardDetails.description }}</p>
</ion-footer>
</any-link>
</ion-card>
</div>
</div>

View File

@@ -3,7 +3,8 @@ ion-card {
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 44px;
margin: auto;
max-width: 22rem;
max-height: 100%;
max-width: 100%;
text-align: center;
transition: all 350ms ease;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -18,7 +19,8 @@ ion-card {
font-family: 'Open Sans';
padding: 0.6rem;
font-weight: 600;
font-size: 1.3rem;
font-size: calc(12px + 0.5vw);
height: 3rem;
}
ion-card-content {
@@ -29,7 +31,7 @@ ion-card {
align-items: center;
ion-icon {
font-size: 8rem;
font-size: calc(90px + 0.5vw);
--ionicon-stroke-width: 1rem;
}
}
@@ -37,7 +39,13 @@ ion-card {
ion-footer {
padding: 1rem;
font-family: 'Open Sans';
font-size: 1.2rem;
font-size: clamp(1rem, calc(12px + 0.5vw), 1.3rem);
height: 9rem;
width: clamp(13rem, 80%, 18rem);
margin: 0 auto;
* {
max-width: 100%;
}
}
.footer-md::before {
@@ -45,6 +53,17 @@ ion-card {
}
}
.p1 {
padding: 1.2rem;
@media (max-width: 900px) {
ion-card-title, ion-footer {
height: auto !important;
}
ion-footer {
width: 10rem;
}
}
@media (max-width: 1200px) {
ion-footer {
width: 14rem;
}
}

View File

@@ -1,4 +1,11 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import {
ChangeDetectionStrategy,
Component,
ElementRef,
HostListener,
Input,
ViewChild,
} from '@angular/core'
@Component({
selector: 'widget-card',
@@ -7,11 +14,53 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WidgetCardComponent {
@Input() title: string = ''
@Input() icon: string = ''
@Input() color: string = ''
@Input() description: string = ''
@Input() link: string = ''
@Input() cardDetails!: Card
@Input() containerDimensions!: Dimension
@ViewChild('outerWrapper') outerWrapper: ElementRef<HTMLElement> =
{} as ElementRef<HTMLElement>
@ViewChild('innerWrapper') innerWrapper: ElementRef<HTMLElement> =
{} as ElementRef<HTMLElement>
@HostListener('window:resize', ['$event'])
onResize() {
this.resize()
}
maxHeight = 0
maxWidth = 0
innerTransform = ''
outerWidth: any
outerHeight: any
constructor() {}
ngAfterViewInit() {
this.maxHeight = (<HTMLElement> (
this.innerWrapper.nativeElement
)).getBoundingClientRect().height
this.maxWidth = (<HTMLElement> (
this.innerWrapper.nativeElement
)).getBoundingClientRect().width
this.resize()
}
resize() {
const height = this.containerDimensions.height
const width = this.containerDimensions.width
const isMax = width >= this.maxWidth && height >= this.maxHeight
const scale = Math.min(width / this.maxWidth, height / this.maxHeight)
this.innerTransform = isMax ? '' : 'scale(' + scale + ')'
this.outerWidth = isMax ? '' : this.maxWidth * scale
this.outerHeight = isMax ? '' : this.maxHeight * scale
}
}
export interface Dimension {
height: number
width: number
}
export interface Card {
title: string
icon: string
color: string
description: string
link: string
qp?: Record<string, string>
}

View File

@@ -1,17 +1,18 @@
<ion-grid>
<ion-row class="ion-justify-content-center ion-align-items-center">
<ion-col
*ngFor="let card of cards"
size="auto"
class="ion-align-self-center"
>
<widget-card
title="{{ card.title }}"
icon="{{ card.icon }}"
color="{{ card.color }}"
description="{{ card.description }}"
link="{{ card.link }}"
></widget-card>
</ion-col>
</ion-row>
</ion-grid>
<div #gridContent>
<ion-grid>
<ion-row class="ion-justify-content-center ion-align-items-center">
<ion-col
*ngFor="let card of cards"
sizeLg="4"
sizeSm="6"
sizeXs="12"
class="ion-align-self-center"
>
<widget-card
[cardDetails]="card"
[containerDimensions]="containerDimensions"
></widget-card>
</ion-col>
</ion-row>
</ion-grid>
</div>

View File

@@ -1,7 +1,13 @@
ion-row {
grid-row-gap: 1rem;
ion-col {
max-width: 22rem !important;
--ion-grid-column-padding: 1rem;
}
ion-col {
padding: 0 0.5rem 0.5rem 1rem;
@media (min-width: 1800px) {
div {
padding: 0 20%;
}
ion-col {
max-width: 24rem !important;
}
}

View File

@@ -1,4 +1,11 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import {
ChangeDetectionStrategy,
Component,
ElementRef,
HostListener,
ViewChild,
} from '@angular/core'
import { Card, Dimension } from '../widget-card/widget-card.component'
@Component({
selector: 'widget-list',
@@ -7,7 +14,27 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WidgetListComponent {
constructor() {}
@ViewChild('gridContent') gridContent: ElementRef<HTMLElement> =
{} as ElementRef<HTMLElement>
@HostListener('window:resize', ['$event'])
onResize() {
this.setContainerDimensions()
}
containerDimensions: Dimension = {} as Dimension
ngAfterViewInit() {
this.setContainerDimensions()
}
setContainerDimensions() {
this.containerDimensions.height = (<HTMLElement> (
this.gridContent.nativeElement
)).getBoundingClientRect().height
this.containerDimensions.width = (<HTMLElement> (
this.gridContent.nativeElement
)).getBoundingClientRect().width
}
cards: Card[] = [
{
@@ -15,7 +42,8 @@ export class WidgetListComponent {
icon: 'storefront-outline',
color: 'var(--alt-blue)',
description: 'Shop for your favorite open source services',
link: '/marketplace/browse',
link: '/marketplace',
qp: { back: 'true' },
},
{
title: 'LAN Setup',
@@ -23,21 +51,21 @@ export class WidgetListComponent {
color: 'var(--alt-orange)',
description:
'Install your Embassy certificate for a secure local connection',
link: '/settings/lan',
link: '/system/lan',
},
{
title: 'Create Backup',
icon: 'duplicate-outline',
color: 'var(--alt-purple)',
description: 'Back up your Embassy and service data',
link: '/settings/backup',
link: '/system/backup',
},
{
title: 'Embassy Info',
icon: 'information-circle-outline',
color: 'var(--alt-green)',
description: 'View basic information about your Embassy',
link: '/settings/specs',
link: '/system/specs',
},
{
title: 'User Manual',
@@ -55,11 +83,3 @@ export class WidgetListComponent {
},
]
}
interface Card {
title: string
icon: string
color: string
description: string
link: string
}

View File

@@ -56,7 +56,7 @@ export class ToButtonsPipe implements PipeTransform {
this.modalService.presentModalConfig({ pkgId: pkg.manifest.id }),
title: 'Config',
description: `Customize ${pkgTitle}`,
icon: 'construct-outline',
icon: 'options-outline',
},
// properties
{

View File

@@ -7,7 +7,7 @@
</ion-toolbar>
</ion-header>
<ion-content>
<div style="padding: 36px 0">
<div class="padding-top">
<widget-list></widget-list>
</div>
</ion-content>

View File

@@ -0,0 +1,9 @@
.padding-top {
padding-top: 2rem;
}
@media (min-width: 2000px) {
.padding-top {
padding-top: 10rem;
}
}

View File

@@ -39,9 +39,6 @@
></ion-icon>
</ion-button>
</ion-item>
<p style="text-align: left; padding-top: 4px">
<ion-text color="danger">{{ error }}</ion-text>
</p>
</ion-item-group>
<ion-button
class="login-button"
@@ -51,6 +48,9 @@
>
<span style="font-size: larger; font-weight: bold">Login</span>
</ion-button>
<p style="text-align: left; padding-top: 4px">
<ion-text color="danger">{{ error }}</ion-text>
</p>
</form>
</ion-card-content>
</ion-card>

View File

@@ -28,6 +28,7 @@ ion-card {
background: var(--ion-color-step-200);
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 44px;
min-height: 16rem;
}
.input-label {

View File

@@ -40,6 +40,10 @@ export class LoginPage {
try {
document.cookie = ''
if (this.password.length > 64) {
this.error = 'Password must be less than 65 characters'
return
}
await this.api.login({
password: this.password,
metadata: { platforms: getPlatforms() },

View File

@@ -1,5 +1,8 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start" *ngIf="back">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Marketplace</ion-title>
<ion-buttons slot="end">
<badge-menu-button></badge-menu-button>

View File

@@ -1,4 +1,5 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ModalController } from '@ionic/angular'
import { AbstractMarketplaceService } from '@start9labs/marketplace'
import { PatchDB } from 'patch-db-client'
@@ -15,6 +16,8 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MarketplaceListPage {
readonly back = !!this.route.snapshot.queryParamMap.get('back')
readonly store$ = this.marketplaceService.getSelectedStore$().pipe(
filter(Boolean),
map(({ info, packages }) => {
@@ -73,6 +76,7 @@ export class MarketplaceListPage {
private readonly marketplaceService: MarketplaceService,
private readonly modalCtrl: ModalController,
private readonly config: ConfigService,
private readonly route: ActivatedRoute,
) {}
category = 'featured'

View File

@@ -4,11 +4,7 @@ import { Routes, RouterModule } from '@angular/router'
const routes: Routes = [
{
path: '',
redirectTo: 'browse',
pathMatch: 'full',
},
{
path: 'browse',
loadChildren: () =>
import('./marketplace-list/marketplace-list.module').then(
m => m.MarketplaceListPageModule,

View File

@@ -26,7 +26,7 @@ export class NotificationsPage {
notifications: ServerNotifications = []
beforeCursor?: number
needInfinite = false
fromToast = false
fromToast = !!this.route.snapshot.queryParamMap.get('toast')
readonly perPage = 40
readonly packageData$ = this.patch.watch$('package-data')
@@ -41,7 +41,6 @@ export class NotificationsPage {
) {}
async ngOnInit() {
this.fromToast = !!this.route.snapshot.queryParamMap.get('toast')
this.notifications = await this.getNotifications()
this.loading = false
}

View File

@@ -1,6 +1,6 @@
<ion-header>
<ion-toolbar>
<ion-title> System Settings </ion-title>
<ion-title> System </ion-title>
<ion-buttons slot="end">
<badge-menu-button></badge-menu-button>
</ion-buttons>