mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Night theme (#2137)
* feat: add themes * fix: remove obvious issues with light theme * chore: improve light theme a bit * comment out theme swticher * chore: make login dark * add theme and widgets to seeds * add theme and widgets to migration --------- Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
committed by
Aiden McClelland
parent
e867f31c31
commit
3c0a82293c
@@ -2,6 +2,7 @@
|
||||
button
|
||||
*ngIf="pkg.entry.manifest as manifest"
|
||||
detail="false"
|
||||
class="service-card"
|
||||
[routerLink]="['/services', manifest.id]"
|
||||
>
|
||||
<app-list-icon slot="start" [pkg]="pkg"></app-list-icon>
|
||||
@@ -9,7 +10,7 @@
|
||||
<img alt="" [src]="pkg.entry['static-files'].icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label>
|
||||
<h2>{{ manifest.title }}</h2>
|
||||
<h2 ticker>{{ manifest.title }}</h2>
|
||||
<p>{{ manifest.version | displayEmver }}</p>
|
||||
<status
|
||||
[rendering]="pkg.primaryRendering"
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
EmverPipesModule,
|
||||
ResponsiveColModule,
|
||||
TextSpinnerComponentModule,
|
||||
TickerModule,
|
||||
} from '@start9labs/shared'
|
||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||
import { StatusComponentModule } from 'src/app/components/status/status.component.module'
|
||||
@@ -37,6 +38,7 @@ const routes: Routes = [
|
||||
BadgeMenuComponentModule,
|
||||
WidgetListComponentModule,
|
||||
ResponsiveColModule,
|
||||
TickerModule,
|
||||
],
|
||||
declarations: [
|
||||
AppListPage,
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="services"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-item lines="none" color="light">
|
||||
<ion-thumbnail slot="start">
|
||||
<img [src]="pkg['static-files'].icon" alt="" />
|
||||
</ion-thumbnail>
|
||||
<div class="header">
|
||||
<img class="logo" [src]="pkg['static-files'].icon" alt="" />
|
||||
<ion-label>
|
||||
<h1
|
||||
class="montserrat"
|
||||
@@ -16,6 +14,6 @@
|
||||
</h1>
|
||||
<h2>{{ pkg.manifest.version | displayEmver }}</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</div>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
.less-large {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 54px;
|
||||
width: 54px;
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ const routes: Routes = [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
SharedPipesModule,
|
||||
RouterModule.forChild(routes),
|
||||
],
|
||||
declarations: [LoginPage],
|
||||
})
|
||||
|
||||
@@ -1,41 +1,35 @@
|
||||
<ion-content>
|
||||
<ion-grid style="height: 100%; max-width: 540px">
|
||||
<ion-row class="ion-align-items-center" style="height: 90%">
|
||||
<ion-col class="ion-text-center">
|
||||
<div style="padding-bottom: 16px">
|
||||
<img src="assets/img/logo.png" style="max-width: 240px" />
|
||||
</div>
|
||||
<ion-content class="content">
|
||||
<ion-grid class="grid">
|
||||
<ion-row class="row">
|
||||
<ion-col>
|
||||
<img src="assets/img/logo.png" alt="Start9" class="logo" />
|
||||
|
||||
<ion-card>
|
||||
<ion-card-header class="ion-text-center" style="padding-bottom: 8px">
|
||||
<ion-card-title>Embassy Login</ion-card-title>
|
||||
<ion-card class="card">
|
||||
<ion-card-header>
|
||||
<ion-card-title class="title">Embassy Login</ion-card-title>
|
||||
</ion-card-header>
|
||||
|
||||
<ion-card-content class="ion-margin ion-text-center">
|
||||
<form
|
||||
class="inline"
|
||||
(submit)="submit()"
|
||||
style="margin-bottom: 12px"
|
||||
>
|
||||
<ion-card-content class="ion-margin">
|
||||
<form class="form" (submit)="submit()">
|
||||
<ion-item-group>
|
||||
<ion-item color="dark">
|
||||
<ion-item color="light">
|
||||
<ion-icon
|
||||
slot="start"
|
||||
name="key-outline"
|
||||
style="margin-right: 16px"
|
||||
></ion-icon>
|
||||
<ion-input
|
||||
[type]="unmasked ? 'text' : 'password'"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
[type]="unmasked ? 'text' : 'password'"
|
||||
[(ngModel)]="password"
|
||||
(ionChange)="error = ''"
|
||||
placeholder="Password"
|
||||
></ion-input>
|
||||
<ion-button fill="clear" color="light" (click)="toggleMask()">
|
||||
<ion-button fill="clear" color="dark" (click)="toggleMask()">
|
||||
<ion-icon
|
||||
slot="icon-only"
|
||||
[name]="unmasked ? 'eye-off-outline' : 'eye-outline'"
|
||||
size="small"
|
||||
[name]="unmasked ? 'eye-off-outline' : 'eye-outline'"
|
||||
></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
@@ -46,12 +40,12 @@
|
||||
expand="block"
|
||||
color="tertiary"
|
||||
>
|
||||
<span style="font-size: larger; font-weight: bold">Login</span>
|
||||
Login
|
||||
</ion-button>
|
||||
<p style="text-align: left; padding-top: 4px">
|
||||
<ion-text color="danger">{{ error }}</ion-text>
|
||||
</p>
|
||||
</form>
|
||||
<p class="error">
|
||||
<ion-text color="danger">{{ error }}</ion-text>
|
||||
</p>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
|
||||
@@ -1,10 +1,37 @@
|
||||
ion-card-title {
|
||||
margin: 24px 0;
|
||||
font-family: 'Montserrat';
|
||||
font-weight: 500;
|
||||
font-size: x-large;
|
||||
font-variant: all-small-caps;
|
||||
--color: var(--ion-color-dark);
|
||||
.content {
|
||||
--background: #222428;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #414141;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 24px 0 16px;
|
||||
color: #e0e0e0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.grid {
|
||||
height: 100%;
|
||||
max-width: 540px;
|
||||
}
|
||||
|
||||
.row {
|
||||
height: 90%;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
max-width: 240px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: block;
|
||||
text-align: left;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
ion-button {
|
||||
@@ -15,8 +42,7 @@ ion-item {
|
||||
--border-style: solid;
|
||||
--border-color: var(--ion-color-light);
|
||||
--border-radius: 4px 0 0 4px;
|
||||
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
|
||||
ion-button {
|
||||
@@ -26,26 +52,22 @@ ion-item {
|
||||
|
||||
ion-card {
|
||||
background: var(--ion-color-step-200);
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 44px;
|
||||
min-height: 16rem;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
padding-bottom: 2px;
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
color: var(--ion-color-dark);
|
||||
}
|
||||
|
||||
.login-button {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
height: 49px;
|
||||
font-size: larger;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.inline {
|
||||
.form {
|
||||
margin-bottom: 12px;
|
||||
|
||||
* {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
@@ -53,5 +75,5 @@ ion-card {
|
||||
}
|
||||
|
||||
.item-interactive {
|
||||
--highlight-background: var(--ion-color-tertiary) !important;
|
||||
}
|
||||
--highlight-background: #5260ff !important;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { TextSpinnerComponentModule } from '@start9labs/shared'
|
||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||
import { OSUpdatePageModule } from 'src/app/modals/os-update/os-update.page.module'
|
||||
import { BackupColorPipeModule } from 'src/app/pipes/backup-color/backup-color.module'
|
||||
import { ThemeSwitcherModule } from '../theme-switcher/theme-switcher.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -26,6 +27,7 @@ const routes: Routes = [
|
||||
BadgeMenuComponentModule,
|
||||
OSUpdatePageModule,
|
||||
BackupColorPipeModule,
|
||||
ThemeSwitcherModule,
|
||||
],
|
||||
declarations: [ServerShowPage],
|
||||
})
|
||||
|
||||
@@ -38,65 +38,65 @@
|
||||
{{ cat.key }}
|
||||
</ion-text>
|
||||
</ion-item-divider>
|
||||
<ng-container *ngFor="let button of cat.value">
|
||||
<ion-item
|
||||
button
|
||||
[style.display]="(button.title === 'Repair Disk' && !(showDiskRepair$ | async)) ? 'none' : 'block'"
|
||||
[detail]="button.detail"
|
||||
[disabled]="button.disabled$ | async"
|
||||
(click)="button.action()"
|
||||
>
|
||||
<ion-icon slot="start" [name]="button.icon"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ button.title }}</h2>
|
||||
<p *ngIf="button.description">{{ button.description }}</p>
|
||||
<!-- <theme-switcher *ngIf="cat.key === 'Manage'"></theme-switcher> -->
|
||||
<ion-item
|
||||
*ngFor="let button of cat.value"
|
||||
button
|
||||
[style.display]="(button.title === 'Repair Disk' && !(showDiskRepair$ | async)) ? 'none' : 'block'"
|
||||
[detail]="button.detail"
|
||||
[disabled]="button.disabled$ | async"
|
||||
(click)="button.action()"
|
||||
>
|
||||
<ion-icon slot="start" [name]="button.icon"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ button.title }}</h2>
|
||||
<p *ngIf="button.description">{{ button.description }}</p>
|
||||
|
||||
<!-- "Create Backup" button only -->
|
||||
<p *ngIf="button.title === 'Create Backup'">
|
||||
<ng-container *ngIf="server['status-info'] as statusInfo">
|
||||
<ion-text
|
||||
[color]="server['last-backup'] | backupColor"
|
||||
*ngIf="!statusInfo['backup-progress'] && !statusInfo['update-progress']"
|
||||
>
|
||||
Last Backup: {{ server['last-backup'] ? (server['last-backup']
|
||||
| date: 'medium') : 'never' }}
|
||||
</ion-text>
|
||||
<span *ngIf="!!statusInfo['backup-progress']" class="inline">
|
||||
<ion-spinner
|
||||
color="success"
|
||||
style="height: 12px; width: 12px; margin-right: 6px"
|
||||
></ion-spinner>
|
||||
<ion-text color="success">Backing up</ion-text>
|
||||
</span>
|
||||
</ng-container>
|
||||
</p>
|
||||
<!-- "Software Update" button only -->
|
||||
<p *ngIf="button.title === 'Software Update'">
|
||||
<!-- "Create Backup" button only -->
|
||||
<p *ngIf="button.title === 'Create Backup'">
|
||||
<ng-container *ngIf="server['status-info'] as statusInfo">
|
||||
<ion-text
|
||||
*ngIf="server['status-info'].updated; else notUpdated"
|
||||
class="inline"
|
||||
color="warning"
|
||||
[color]="server['last-backup'] | backupColor"
|
||||
*ngIf="!statusInfo['backup-progress'] && !statusInfo['update-progress']"
|
||||
>
|
||||
Update Complete. Restart to apply changes
|
||||
Last Backup: {{ server['last-backup'] ? (server['last-backup'] |
|
||||
date: 'medium') : 'never' }}
|
||||
</ion-text>
|
||||
<ng-template #notUpdated>
|
||||
<ng-container *ngIf="showUpdate$ | async; else check">
|
||||
<ion-text class="inline" color="success">
|
||||
<ion-icon name="rocket-outline"></ion-icon>
|
||||
Update Available
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
<ng-template #check>
|
||||
<ion-text class="inline" color="dark">
|
||||
<ion-icon name="refresh"></ion-icon>
|
||||
Check for updates
|
||||
</ion-text>
|
||||
</ng-template>
|
||||
<span *ngIf="!!statusInfo['backup-progress']" class="inline">
|
||||
<ion-spinner
|
||||
color="success"
|
||||
style="height: 12px; width: 12px; margin-right: 6px"
|
||||
></ion-spinner>
|
||||
<ion-text color="success">Backing up</ion-text>
|
||||
</span>
|
||||
</ng-container>
|
||||
</p>
|
||||
<!-- "Software Update" button only -->
|
||||
<p *ngIf="button.title === 'Software Update'">
|
||||
<ion-text
|
||||
*ngIf="server['status-info'].updated; else notUpdated"
|
||||
class="inline"
|
||||
color="warning"
|
||||
>
|
||||
Update Complete. Restart to apply changes
|
||||
</ion-text>
|
||||
<ng-template #notUpdated>
|
||||
<ng-container *ngIf="showUpdate$ | async; else check">
|
||||
<ion-text class="inline" color="success">
|
||||
<ion-icon name="rocket-outline"></ion-icon>
|
||||
Update Available
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
<ng-template #check>
|
||||
<ion-text class="inline" color="dark">
|
||||
<ion-icon name="refresh"></ion-icon>
|
||||
Check for updates
|
||||
</ion-text>
|
||||
</ng-template>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</div>
|
||||
</ion-item-group>
|
||||
</ion-content>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
{{ uploadState?.message }}
|
||||
</h4>
|
||||
<div class="box" *ngIf="toUpload.icon && toUpload.manifest">
|
||||
<div class="service-card">
|
||||
<div class="card">
|
||||
<div class="row row_end">
|
||||
<ion-button
|
||||
style="
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
justify-content: space-evenly
|
||||
}
|
||||
|
||||
.service-card {
|
||||
.card {
|
||||
background: radial-gradient(var(--ion-color-step-100), transparent);
|
||||
min-width: 200px;
|
||||
max-width: 200px;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<ion-item button [detail]="true" (click)="open = true">
|
||||
<ion-icon slot="start" name="brush-outline"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>Theme</h2>
|
||||
<p>{{ value }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ng-template
|
||||
[(tuiDialog)]="open"
|
||||
[tuiDialogOptions]="{
|
||||
label: 'Select theme',
|
||||
size: 's'
|
||||
}"
|
||||
>
|
||||
<tui-radio-list
|
||||
style="margin-top: 16px"
|
||||
size="l"
|
||||
[ngModel]="value"
|
||||
[items]="themes"
|
||||
(ngModelChange)="onChange($event)"
|
||||
></tui-radio-list>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core'
|
||||
|
||||
import { ThemeSwitcherService } from '../../../services/theme-switcher.service'
|
||||
|
||||
@Component({
|
||||
selector: 'theme-switcher',
|
||||
templateUrl: './theme-switcher.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ThemeSwitcherComponent {
|
||||
value = this.switcher.value
|
||||
|
||||
open = false
|
||||
|
||||
readonly themes = ['Dark', 'Light']
|
||||
|
||||
constructor(private readonly switcher: ThemeSwitcherService) {}
|
||||
|
||||
onChange(value: string): void {
|
||||
this.value = value
|
||||
this.switcher.next(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { TuiDialogModule } from '@taiga-ui/core'
|
||||
import { TuiRadioListModule } from '@taiga-ui/kit'
|
||||
|
||||
import { ThemeSwitcherComponent } from './theme-switcher.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [IonicModule, FormsModule, TuiDialogModule, TuiRadioListModule],
|
||||
declarations: [ThemeSwitcherComponent],
|
||||
exports: [ThemeSwitcherComponent],
|
||||
})
|
||||
export class ThemeSwitcherModule {}
|
||||
@@ -57,7 +57,7 @@
|
||||
.content {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
background: #333;
|
||||
background: var(--tui-base-02);
|
||||
border-radius: 24px;
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
|
||||
Reference in New Issue
Block a user