first chrome implementation

This commit is contained in:
DEV Sam Hayes
2025-01-10 19:37:10 +01:00
parent dc7a980dc5
commit a652718bc7
175 changed files with 18526 additions and 610 deletions

View File

@@ -0,0 +1,42 @@
<div class="sam-text-header">
<span>Gooti</span>
</div>
<div class="vertically-centered">
<div class="sam-flex-column center">
<div class="sam-flex-column gap" style="align-items: center">
<div class="logo-frame">
<img src="gooti.svg" height="120" width="120" alt=""/>
</div>
<button
type="button"
class="sam-mt-2 btn btn-primary"
(click)="router.navigateByUrl('/vault-create/new')"
>
<div class="sam-flex-row gap-h">
<i class="bi bi-plus-circle" style="height: 22px"></i>
<span>Create a new vault</span>
</div>
</button>
<span class="sam-text-muted">or</span>
<button
type="button"
class="btn btn-secondary"
(click)="fileInput.click()"
>
<span>Import a vault</span>
</button>
</div>
</div>
</div>
<input
#fileInput
class="file-input"
type="file"
(change)="onImportFileChange($event)"
accept=".json"
/>

View File

@@ -0,0 +1,17 @@
:host {
height: 100%;
display: flex;
flex-direction: column;
.vertically-centered {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.file-input {
position: absolute;
visibility: hidden;
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HomeComponent } from './home.component';
describe('HomeComponent', () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HomeComponent]
})
.compileComponents();
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,36 @@
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { BrowserSyncData, StorageService } from '@common';
import { StartupService } from '../../../services/startup/startup.service';
@Component({
selector: 'app-home',
imports: [],
templateUrl: './home.component.html',
styleUrl: './home.component.scss',
})
export class HomeComponent {
readonly router = inject(Router);
readonly #storage = inject(StorageService);
readonly #startup = inject(StartupService);
async onImportFileChange(event: Event) {
try {
const element = event.currentTarget as HTMLInputElement;
const file = element.files !== null ? element.files[0] : undefined;
if (!file) {
return;
}
const text = await file.text();
const vault = JSON.parse(text) as BrowserSyncData;
console.log(vault);
await this.#storage.importVault(vault);
this.#startup.startOver();
} catch (error) {
console.log(error);
// TODO
}
}
}

View File

@@ -0,0 +1,48 @@
<div class="sam-text-header">
<span>Gooti</span>
</div>
<div class="content">
<div class="sam-flex-column gap" style="align-items: center">
<div class="logo-frame">
<img src="gooti.svg" height="120" width="120" alt=""/>
</div>
<span class="sam-mt-2"> Please define a password for your vault. </span>
<small class="sam-text-muted">
Sensitive data is encypted before it is stored.
</small>
<div class="sam-mt input-group">
<input
#passwordInputElement
type="password"
class="form-control form-control-lg"
style="font-size: 1rem"
placeholder="vault password"
[(ngModel)]="password"
/>
<button
class="btn btn-outline-secondary"
type="button"
(click)="toggleType(passwordInputElement)"
>
<i
class="bi bi-eye"
[class.bi-eye]="passwordInputElement.type === 'password'"
[class.bi-eye-slash]="passwordInputElement.type === 'text'"
></i>
</button>
</div>
<button
[disabled]="!password || password.length < 4"
type="button"
class="sam-mt btn btn-primary"
(click)="createVault()"
>
Create vault
</button>
</div>
</div>

View File

@@ -0,0 +1,48 @@
:host {
height: 100%;
display: flex;
flex-direction: column;
color-scheme: dark;
.custom-header {
padding-top: var(--size);
padding-bottom: var(--size);
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto;
align-items: center;
.back {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
justify-self: start;
padding-left: var(--size);
}
.text {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
font-size: 20px;
font-weight: 500;
justify-self: center;
}
}
.content {
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
padding: 0 var(--size) var(--size) var(--size);
}
.logo-frame {
border: 2px solid #0d6efd;
border-radius: 100%;
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NewComponent } from './new.component';
describe('NewComponent', () => {
let component: NewComponent;
let fixture: ComponentFixture<NewComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [NewComponent]
})
.compileComponents();
fixture = TestBed.createComponent(NewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,34 @@
import { Component, inject } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import { NavComponent, StorageService } from '@common';
@Component({
selector: 'app-new',
imports: [FormsModule],
templateUrl: './new.component.html',
styleUrl: './new.component.scss',
})
export class NewComponent extends NavComponent {
password = '';
readonly #router = inject(Router);
readonly #storage = inject(StorageService);
toggleType(element: HTMLInputElement) {
if (element.type === 'password') {
element.type = 'text';
} else {
element.type = 'password';
}
}
async createVault() {
if (!this.password) {
return;
}
await this.#storage.createNewVault(this.password);
this.#router.navigateByUrl('/home/identities');
}
}

View File

@@ -0,0 +1 @@
<router-outlet></router-outlet>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { VaultCreateComponent } from './vault-create.component';
describe('VaultCreateComponent', () => {
let component: VaultCreateComponent;
let fixture: ComponentFixture<VaultCreateComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [VaultCreateComponent]
})
.compileComponents();
fixture = TestBed.createComponent(VaultCreateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-vault-create',
imports: [RouterOutlet],
templateUrl: './vault-create.component.html',
styleUrl: './vault-create.component.scss'
})
export class VaultCreateComponent {
}