Release v1.0.7 - Move lock button to page headers

- Move lock button from bottom navigation bar to each page header
- Add lock button styling to common SCSS with hover effect
- Remove logs and info tabs from bottom navigation
- Standardize header height to 48px across all pages
- Simplify home component by removing lock logic

Files modified:
- package.json, manifest.json (both browsers)
- home.component.html/ts (both browsers)
- identities, identity, bookmarks, logs, info, settings components
- projects/common/src/lib/styles/_common.scss

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
woikos
2025-12-21 05:15:21 +01:00
parent 7ff8e257dd
commit 2c1f3265b7
46 changed files with 360 additions and 177 deletions

View File

@@ -1,12 +1,12 @@
{ {
"name": "plebeian-signer", "name": "plebeian-signer",
"version": "v1.0.6", "version": "v1.0.7",
"custom": { "custom": {
"chrome": { "chrome": {
"version": "v1.0.6" "version": "v1.0.7"
}, },
"firefox": { "firefox": {
"version": "v1.0.6" "version": "v1.0.7"
} }
}, },
"scripts": { "scripts": {

View File

@@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "Plebeian Signer - Nostr Identity Manager & Signer", "name": "Plebeian Signer - Nostr Identity Manager & Signer",
"description": "Manage and switch between multiple identities while interacting with Nostr apps", "description": "Manage and switch between multiple identities while interacting with Nostr apps",
"version": "1.0.6", "version": "1.0.7",
"homepage_url": "https://git.mleku.dev/mleku/plebeian-signer", "homepage_url": "https://git.mleku.dev/mleku/plebeian-signer",
"options_page": "options.html", "options_page": "options.html",
"permissions": [ "permissions": [

View File

@@ -1,8 +1,11 @@
<!-- eslint-disable @angular-eslint/template/interactive-supports-focus --> <!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->
<!-- eslint-disable @angular-eslint/template/click-events-have-key-events --> <!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->
<div class="bookmarks-header"> <div class="sam-text-header">
<span class="bookmarks-title">Bookmarks</span> <button class="lock-btn" title="Lock" (click)="onClickLock()">
<button class="btn btn-primary btn-sm" (click)="onBookmarkThisPage()"> <span class="emoji">🔒</span>
</button>
<span>Bookmarks</span>
<button class="action-btn btn btn-primary btn-sm" (click)="onBookmarkThisPage()">
<span class="emoji">🔖</span> Bookmark This Page <span class="emoji">🔖</span> Bookmark This Page
</button> </button>
</div> </div>

View File

@@ -2,21 +2,24 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: var(--size); padding-top: var(--size);
padding-bottom: var(--size);
overflow: hidden; overflow: hidden;
}
.bookmarks-header { > *:not(.sam-text-header) {
display: flex; margin-left: var(--size);
justify-content: space-between; margin-right: var(--size);
align-items: center; }
.sam-text-header {
margin-bottom: var(--size); margin-bottom: var(--size);
flex-shrink: 0; flex-shrink: 0;
}
.bookmarks-title { .action-btn {
font-weight: 600; position: absolute;
font-size: 1.1rem; right: 0;
}
}
} }
.bookmarks-container { .bookmarks-container {

View File

@@ -1,5 +1,6 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { Bookmark, LoggerService, SignerMetaData } from '@common'; import { Router } from '@angular/router';
import { Bookmark, LoggerService, SignerMetaData, StorageService } from '@common';
import { ChromeMetaHandler } from '../../../common/data/chrome-meta-handler'; import { ChromeMetaHandler } from '../../../common/data/chrome-meta-handler';
@Component({ @Component({
@@ -11,6 +12,8 @@ import { ChromeMetaHandler } from '../../../common/data/chrome-meta-handler';
export class BookmarksComponent implements OnInit { export class BookmarksComponent implements OnInit {
readonly #logger = inject(LoggerService); readonly #logger = inject(LoggerService);
readonly #metaHandler = new ChromeMetaHandler(); readonly #metaHandler = new ChromeMetaHandler();
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
bookmarks: Bookmark[] = []; bookmarks: Bookmark[] = [];
isLoading = true; isLoading = true;
@@ -87,4 +90,10 @@ export class BookmarksComponent implements OnInit {
return url; return url;
} }
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -33,16 +33,4 @@
<a class="tab" routerLink="/home/bookmarks" routerLinkActive="active" title="Bookmarks"> <a class="tab" routerLink="/home/bookmarks" routerLinkActive="active" title="Bookmarks">
<span class="emoji">🔖</span> <span class="emoji">🔖</span>
</a> </a>
<a class="tab" routerLink="/home/logs" routerLinkActive="active" title="Logs">
<span class="emoji">🪵</span>
</a>
<a class="tab" routerLink="/home/info" routerLinkActive="active" title="Info">
<span class="emoji">💡</span>
</a>
<button class="tab" (click)="onClickLock()" title="Lock">
<span class="emoji">🔒</span>
</button>
</div> </div>

View File

@@ -1,6 +1,5 @@
import { Component, inject } from '@angular/core'; import { Component } from '@angular/core';
import { Router, RouterModule, RouterOutlet } from '@angular/router'; import { RouterModule, RouterOutlet } from '@angular/router';
import { LoggerService, StorageService } from '@common';
@Component({ @Component({
selector: 'app-home', selector: 'app-home',
@@ -8,14 +7,4 @@ import { LoggerService, StorageService } from '@common';
styleUrl: './home.component.scss', styleUrl: './home.component.scss',
imports: [RouterOutlet, RouterModule], imports: [RouterOutlet, RouterModule],
}) })
export class HomeComponent { export class HomeComponent {}
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
readonly #logger = inject(LoggerService);
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
}

View File

@@ -1,6 +1,9 @@
<!-- eslint-disable @angular-eslint/template/interactive-supports-focus --> <!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->
<!-- eslint-disable @angular-eslint/template/click-events-have-key-events --> <!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->
<div class="custom-header" style="position: sticky; top: 0"> <div class="custom-header" style="position: sticky; top: 0">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span class="text">Identities</span> <span class="text">Identities</span>
<button class="button btn btn-primary btn-sm" (click)="onClickNewIdentity()"> <button class="button btn btn-primary btn-sm" (click)="onClickNewIdentity()">

View File

@@ -3,37 +3,55 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow-y: auto;
padding-left: var(--size);
padding-right: var(--size); > *:not(.custom-header) {
margin-left: var(--size);
margin-right: var(--size);
}
.custom-header { .custom-header {
padding-top: var(--size); height: 48px;
padding-bottom: var(--size); min-height: 48px;
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-rows: auto; grid-template-rows: auto;
align-items: center; align-items: center;
background: var(--background); background: var(--background);
position: relative;
.lock-btn {
position: absolute;
left: 0;
background: transparent;
border: none;
padding: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: background-color 0.2s;
&:hover {
background-color: var(--background-light);
}
.emoji {
font-size: 20px;
}
}
.button { .button {
grid-column-start: 1; position: absolute;
grid-column-end: 2; right: 0;
grid-row-start: 1;
grid-row-end: 2;
justify-self: end;
} }
.text { .text {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
font-family: var(--font-heading); font-family: var(--font-heading);
font-size: 24px; font-size: 24px;
font-weight: 700; font-weight: 700;
letter-spacing: 0.1rem; letter-spacing: 0.1rem;
justify-self: center; justify-self: center;
height: 32px;
} }
} }

View File

@@ -3,6 +3,7 @@ import { Router } from '@angular/router';
import { import {
IconButtonComponent, IconButtonComponent,
Identity_DECRYPTED, Identity_DECRYPTED,
LoggerService,
NostrHelper, NostrHelper,
ProfileMetadata, ProfileMetadata,
ProfileMetadataService, ProfileMetadataService,
@@ -20,6 +21,7 @@ export class IdentitiesComponent implements OnInit {
readonly storage = inject(StorageService); readonly storage = inject(StorageService);
readonly #router = inject(Router); readonly #router = inject(Router);
readonly #profileMetadata = inject(ProfileMetadataService); readonly #profileMetadata = inject(ProfileMetadataService);
readonly #logger = inject(LoggerService);
// Cache of pubkey -> profile for quick lookup // Cache of pubkey -> profile for quick lookup
#profileCache = new Map<string, ProfileMetadata | null>(); #profileCache = new Map<string, ProfileMetadata | null>();
@@ -73,4 +75,10 @@ export class IdentitiesComponent implements OnInit {
onClickWhitelistedApps() { onClickWhitelistedApps() {
this.#router.navigateByUrl('/whitelisted-apps'); this.#router.navigateByUrl('/whitelisted-apps');
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,6 +1,9 @@
<!-- eslint-disable @angular-eslint/template/interactive-supports-focus --> <!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->
<!-- eslint-disable @angular-eslint/template/click-events-have-key-events --> <!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->
<div class="sam-text-header"> <div class="sam-text-header">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span>You</span> <span>You</span>
<button class="edit-btn" title="Edit profile" (click)="onClickEditProfile()"> <button class="edit-btn" title="Edit profile" (click)="onClickEditProfile()">
<img src="edit.svg" alt="Edit" class="edit-icon" /> <img src="edit.svg" alt="Edit" class="edit-icon" />

View File

@@ -4,14 +4,12 @@
flex-direction: column; flex-direction: column;
.sam-text-header { .sam-text-header {
position: relative;
.edit-btn { .edit-btn {
position: absolute; position: absolute;
right: var(--size); right: 0;
background: transparent; background: transparent;
border: none; border: none;
padding: 4px; padding: 8px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -76,6 +76,12 @@ export class IdentityComponent implements OnInit {
this.#router.navigateByUrl('/profile-edit'); this.#router.navigateByUrl('/profile-edit');
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
async #loadData() { async #loadData() {
try { try {
const selectedIdentityId = const selectedIdentityId =

View File

@@ -1,4 +1,7 @@
<div class="sam-text-header"> <div class="sam-text-header">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span> Plebeian Signer </span> <span> Plebeian Signer </span>
</div> </div>

View File

@@ -4,6 +4,13 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
overflow-y: auto; overflow-y: auto;
padding-left: var(--size);
padding-right: var(--size); > *:not(.sam-text-header) {
margin-left: var(--size);
margin-right: var(--size);
}
.sam-text-header {
width: 100%;
}
} }

View File

@@ -1,4 +1,6 @@
import { Component } from '@angular/core'; import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { LoggerService, StorageService } from '@common';
import packageJson from '../../../../../../../package.json'; import packageJson from '../../../../../../../package.json';
@Component({ @Component({
@@ -7,5 +9,15 @@ import packageJson from '../../../../../../../package.json';
styleUrl: './info.component.scss', styleUrl: './info.component.scss',
}) })
export class InfoComponent { export class InfoComponent {
readonly #logger = inject(LoggerService);
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
version = packageJson.custom.chrome.version; version = packageJson.custom.chrome.version;
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,5 +1,8 @@
<div class="logs-header"> <div class="sam-text-header">
<span class="logs-title">Logs</span> <button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span>Logs</span>
<div class="logs-actions"> <div class="logs-actions">
<button class="btn btn-sm btn-secondary" (click)="onRefresh()">Refresh</button> <button class="btn btn-sm btn-secondary" (click)="onRefresh()">Refresh</button>
<button class="btn btn-sm btn-secondary" (click)="onClear()">Clear</button> <button class="btn btn-sm btn-secondary" (click)="onClear()">Clear</button>

View File

@@ -2,26 +2,26 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: var(--size); padding-top: var(--size);
padding-bottom: var(--size);
overflow: hidden; overflow: hidden;
}
.logs-header { > *:not(.sam-text-header) {
display: flex; margin-left: var(--size);
justify-content: space-between; margin-right: var(--size);
align-items: center; }
.sam-text-header {
margin-bottom: var(--size); margin-bottom: var(--size);
flex-shrink: 0; flex-shrink: 0;
}
.logs-actions { .logs-actions {
position: absolute;
right: 0;
display: flex; display: flex;
gap: 8px; gap: 8px;
} }
}
.logs-title {
font-weight: 600;
font-size: 1.1rem;
} }
.logs-container { .logs-container {

View File

@@ -1,5 +1,6 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { LoggerService, LogEntry } from '@common'; import { Router } from '@angular/router';
import { LoggerService, LogEntry, StorageService } from '@common';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
@Component({ @Component({
@@ -10,6 +11,8 @@ import { DatePipe } from '@angular/common';
}) })
export class LogsComponent implements OnInit { export class LogsComponent implements OnInit {
readonly #logger = inject(LoggerService); readonly #logger = inject(LoggerService);
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
get logs(): LogEntry[] { get logs(): LogEntry[] {
return this.#logger.logs; return this.#logger.logs;
@@ -40,4 +43,10 @@ export class LogsComponent implements OnInit {
return 'log-info'; return 'log-info';
} }
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,4 +1,7 @@
<div class="sam-text-header"> <div class="sam-text-header">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span> Settings </span> <span> Settings </span>
</div> </div>
@@ -12,6 +15,9 @@
Import Vault Import Vault
</button> </button>
<lib-nav-item text="🪵 Logs" (click)="navigate('/home/logs')"></lib-nav-item>
<lib-nav-item text="💡 Info" (click)="navigate('/home/info')"></lib-nav-item>
<div class="sam-flex-grow"></div> <div class="sam-flex-grow"></div>
<button <button

View File

@@ -4,8 +4,11 @@
flex-direction: column; flex-direction: column;
row-gap: var(--size); row-gap: var(--size);
overflow-y: auto; overflow-y: auto;
padding-left: var(--size);
padding-right: var(--size); > *:not(.sam-text-header) {
margin-left: var(--size);
margin-right: var(--size);
}
.file-input { .file-input {
position: absolute; position: absolute;

View File

@@ -1,4 +1,5 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { import {
BrowserSyncData, BrowserSyncData,
BrowserSyncFlow, BrowserSyncFlow,
@@ -6,6 +7,7 @@ import {
DateHelper, DateHelper,
LoggerService, LoggerService,
NavComponent, NavComponent,
NavItemComponent,
StartupService, StartupService,
StorageService, StorageService,
} from '@common'; } from '@common';
@@ -13,11 +15,12 @@ import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage
@Component({ @Component({
selector: 'app-settings', selector: 'app-settings',
imports: [ConfirmComponent], imports: [ConfirmComponent, NavItemComponent],
templateUrl: './settings.component.html', templateUrl: './settings.component.html',
styleUrl: './settings.component.scss', styleUrl: './settings.component.scss',
}) })
export class SettingsComponent extends NavComponent implements OnInit { export class SettingsComponent extends NavComponent implements OnInit {
readonly #router = inject(Router);
syncFlow: string | undefined; syncFlow: string | undefined;
readonly #storage = inject(StorageService); readonly #storage = inject(StorageService);
@@ -101,4 +104,10 @@ export class SettingsComponent extends NavComponent implements OnInit {
downloadAnchorNode.click(); downloadAnchorNode.click();
downloadAnchorNode.remove(); downloadAnchorNode.remove();
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,12 +1,13 @@
.sam-text-header { .sam-text-header {
background: var(--background); background: var(--background);
z-index: 20; z-index: 20;
padding-top: var(--size); height: 48px;
padding-bottom: var(--size); min-height: 48px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative;
span { span {
font-family: var(--font-heading); font-family: var(--font-heading);
@@ -14,6 +15,28 @@
font-weight: 700; font-weight: 700;
letter-spacing: 0.1rem; letter-spacing: 0.1rem;
} }
.lock-btn {
position: absolute;
left: 0;
background: transparent;
border: none;
padding: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: background-color 0.2s;
&:hover {
background-color: var(--background-light);
}
.emoji {
font-size: 20px;
}
}
} }
.sam-footer-grid-2 { .sam-footer-grid-2 {

View File

@@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "Plebeian Signer", "name": "Plebeian Signer",
"description": "Nostr Identity Manager & Signer", "description": "Nostr Identity Manager & Signer",
"version": "1.0.6", "version": "1.0.7",
"homepage_url": "https://git.mleku.dev/mleku/plebeian-signer", "homepage_url": "https://git.mleku.dev/mleku/plebeian-signer",
"options_page": "options.html", "options_page": "options.html",
"permissions": [ "permissions": [

View File

@@ -1,8 +1,11 @@
<!-- eslint-disable @angular-eslint/template/interactive-supports-focus --> <!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->
<!-- eslint-disable @angular-eslint/template/click-events-have-key-events --> <!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->
<div class="bookmarks-header"> <div class="sam-text-header">
<span class="bookmarks-title">Bookmarks</span> <button class="lock-btn" title="Lock" (click)="onClickLock()">
<button class="btn btn-primary btn-sm" (click)="onBookmarkThisPage()"> <span class="emoji">🔒</span>
</button>
<span>Bookmarks</span>
<button class="action-btn btn btn-primary btn-sm" (click)="onBookmarkThisPage()">
<span class="emoji">🔖</span> Bookmark This Page <span class="emoji">🔖</span> Bookmark This Page
</button> </button>
</div> </div>

View File

@@ -2,21 +2,24 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: var(--size); padding-top: var(--size);
padding-bottom: var(--size);
overflow: hidden; overflow: hidden;
}
.bookmarks-header { > *:not(.sam-text-header) {
display: flex; margin-left: var(--size);
justify-content: space-between; margin-right: var(--size);
align-items: center; }
.sam-text-header {
margin-bottom: var(--size); margin-bottom: var(--size);
flex-shrink: 0; flex-shrink: 0;
}
.bookmarks-title { .action-btn {
font-weight: 600; position: absolute;
font-size: 1.1rem; right: 0;
}
}
} }
.bookmarks-container { .bookmarks-container {

View File

@@ -1,5 +1,6 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { Bookmark, LoggerService, SignerMetaData } from '@common'; import { Router } from '@angular/router';
import { Bookmark, LoggerService, SignerMetaData, StorageService } from '@common';
import { FirefoxMetaHandler } from '../../../common/data/firefox-meta-handler'; import { FirefoxMetaHandler } from '../../../common/data/firefox-meta-handler';
import browser from 'webextension-polyfill'; import browser from 'webextension-polyfill';
@@ -12,6 +13,8 @@ import browser from 'webextension-polyfill';
export class BookmarksComponent implements OnInit { export class BookmarksComponent implements OnInit {
readonly #logger = inject(LoggerService); readonly #logger = inject(LoggerService);
readonly #metaHandler = new FirefoxMetaHandler(); readonly #metaHandler = new FirefoxMetaHandler();
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
bookmarks: Bookmark[] = []; bookmarks: Bookmark[] = [];
isLoading = true; isLoading = true;
@@ -88,4 +91,10 @@ export class BookmarksComponent implements OnInit {
return url; return url;
} }
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -33,16 +33,4 @@
<a class="tab" routerLink="/home/bookmarks" routerLinkActive="active" title="Bookmarks"> <a class="tab" routerLink="/home/bookmarks" routerLinkActive="active" title="Bookmarks">
<span class="emoji">🔖</span> <span class="emoji">🔖</span>
</a> </a>
<a class="tab" routerLink="/home/logs" routerLinkActive="active" title="Logs">
<span class="emoji">🪵</span>
</a>
<a class="tab" routerLink="/home/info" routerLinkActive="active" title="Info">
<span class="emoji">💡</span>
</a>
<button class="tab" (click)="onClickLock()" title="Lock">
<span class="emoji">🔒</span>
</button>
</div> </div>

View File

@@ -1,6 +1,5 @@
import { Component, inject } from '@angular/core'; import { Component } from '@angular/core';
import { Router, RouterModule, RouterOutlet } from '@angular/router'; import { RouterModule, RouterOutlet } from '@angular/router';
import { LoggerService, StorageService } from '@common';
@Component({ @Component({
selector: 'app-home', selector: 'app-home',
@@ -8,14 +7,4 @@ import { LoggerService, StorageService } from '@common';
templateUrl: './home.component.html', templateUrl: './home.component.html',
styleUrl: './home.component.scss', styleUrl: './home.component.scss',
}) })
export class HomeComponent { export class HomeComponent {}
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
readonly #logger = inject(LoggerService);
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
}

View File

@@ -1,6 +1,9 @@
<!-- eslint-disable @angular-eslint/template/interactive-supports-focus --> <!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->
<!-- eslint-disable @angular-eslint/template/click-events-have-key-events --> <!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->
<div class="custom-header" style="position: sticky; top: 0"> <div class="custom-header" style="position: sticky; top: 0">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span class="text">Identities</span> <span class="text">Identities</span>
<button class="button btn btn-primary btn-sm" (click)="onClickNewIdentity()"> <button class="button btn btn-primary btn-sm" (click)="onClickNewIdentity()">

View File

@@ -3,37 +3,55 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow-y: auto;
padding-left: var(--size);
padding-right: var(--size); > *:not(.custom-header) {
margin-left: var(--size);
margin-right: var(--size);
}
.custom-header { .custom-header {
padding-top: var(--size); height: 48px;
padding-bottom: var(--size); min-height: 48px;
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-rows: auto; grid-template-rows: auto;
align-items: center; align-items: center;
background: var(--background); background: var(--background);
position: relative;
.lock-btn {
position: absolute;
left: 0;
background: transparent;
border: none;
padding: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: background-color 0.2s;
&:hover {
background-color: var(--background-light);
}
.emoji {
font-size: 20px;
}
}
.button { .button {
grid-column-start: 1; position: absolute;
grid-column-end: 2; right: 0;
grid-row-start: 1;
grid-row-end: 2;
justify-self: end;
} }
.text { .text {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 1;
grid-row-end: 2;
font-family: var(--font-heading); font-family: var(--font-heading);
font-size: 24px; font-size: 24px;
font-weight: 700; font-weight: 700;
letter-spacing: 0.1rem; letter-spacing: 0.1rem;
justify-self: center; justify-self: center;
height: 32px;
} }
} }

View File

@@ -3,6 +3,7 @@ import { Router } from '@angular/router';
import { import {
IconButtonComponent, IconButtonComponent,
Identity_DECRYPTED, Identity_DECRYPTED,
LoggerService,
NostrHelper, NostrHelper,
ProfileMetadata, ProfileMetadata,
ProfileMetadataService, ProfileMetadataService,
@@ -20,6 +21,7 @@ export class IdentitiesComponent implements OnInit {
readonly storage = inject(StorageService); readonly storage = inject(StorageService);
readonly #router = inject(Router); readonly #router = inject(Router);
readonly #profileMetadata = inject(ProfileMetadataService); readonly #profileMetadata = inject(ProfileMetadataService);
readonly #logger = inject(LoggerService);
// Cache of pubkey -> profile for quick lookup // Cache of pubkey -> profile for quick lookup
#profileCache = new Map<string, ProfileMetadata | null>(); #profileCache = new Map<string, ProfileMetadata | null>();
@@ -73,4 +75,10 @@ export class IdentitiesComponent implements OnInit {
onClickWhitelistedApps() { onClickWhitelistedApps() {
this.#router.navigateByUrl('/whitelisted-apps'); this.#router.navigateByUrl('/whitelisted-apps');
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,6 +1,9 @@
<!-- eslint-disable @angular-eslint/template/interactive-supports-focus --> <!-- eslint-disable @angular-eslint/template/interactive-supports-focus -->
<!-- eslint-disable @angular-eslint/template/click-events-have-key-events --> <!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->
<div class="sam-text-header"> <div class="sam-text-header">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span>You</span> <span>You</span>
<button class="edit-btn" title="Edit profile" (click)="onClickEditProfile()"> <button class="edit-btn" title="Edit profile" (click)="onClickEditProfile()">
<img src="edit.svg" alt="Edit" class="edit-icon" /> <img src="edit.svg" alt="Edit" class="edit-icon" />

View File

@@ -4,14 +4,12 @@
flex-direction: column; flex-direction: column;
.sam-text-header { .sam-text-header {
position: relative;
.edit-btn { .edit-btn {
position: absolute; position: absolute;
right: var(--size); right: 0;
background: transparent; background: transparent;
border: none; border: none;
padding: 4px; padding: 8px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -76,6 +76,12 @@ export class IdentityComponent implements OnInit {
this.#router.navigateByUrl('/profile-edit'); this.#router.navigateByUrl('/profile-edit');
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
async #loadData() { async #loadData() {
try { try {
const selectedIdentityId = const selectedIdentityId =

View File

@@ -1,4 +1,7 @@
<div class="sam-text-header"> <div class="sam-text-header">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span> Plebeian Signer </span> <span> Plebeian Signer </span>
</div> </div>

View File

@@ -4,6 +4,13 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
overflow-y: auto; overflow-y: auto;
padding-left: var(--size);
padding-right: var(--size); > *:not(.sam-text-header) {
margin-left: var(--size);
margin-right: var(--size);
}
.sam-text-header {
width: 100%;
}
} }

View File

@@ -1,4 +1,6 @@
import { Component } from '@angular/core'; import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { LoggerService, StorageService } from '@common';
import packageJson from '../../../../../../../package.json'; import packageJson from '../../../../../../../package.json';
@Component({ @Component({
@@ -7,5 +9,15 @@ import packageJson from '../../../../../../../package.json';
styleUrl: './info.component.scss', styleUrl: './info.component.scss',
}) })
export class InfoComponent { export class InfoComponent {
readonly #logger = inject(LoggerService);
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
version = packageJson.custom.firefox.version; version = packageJson.custom.firefox.version;
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,5 +1,8 @@
<div class="logs-header"> <div class="sam-text-header">
<span class="logs-title">Logs</span> <button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span>Logs</span>
<div class="logs-actions"> <div class="logs-actions">
<button class="btn btn-sm btn-secondary" (click)="onRefresh()">Refresh</button> <button class="btn btn-sm btn-secondary" (click)="onRefresh()">Refresh</button>
<button class="btn btn-sm btn-secondary" (click)="onClear()">Clear</button> <button class="btn btn-sm btn-secondary" (click)="onClear()">Clear</button>

View File

@@ -2,26 +2,26 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: var(--size); padding-top: var(--size);
padding-bottom: var(--size);
overflow: hidden; overflow: hidden;
}
.logs-header { > *:not(.sam-text-header) {
display: flex; margin-left: var(--size);
justify-content: space-between; margin-right: var(--size);
align-items: center; }
.sam-text-header {
margin-bottom: var(--size); margin-bottom: var(--size);
flex-shrink: 0; flex-shrink: 0;
}
.logs-actions { .logs-actions {
position: absolute;
right: 0;
display: flex; display: flex;
gap: 8px; gap: 8px;
} }
}
.logs-title {
font-weight: 600;
font-size: 1.1rem;
} }
.logs-container { .logs-container {

View File

@@ -1,5 +1,6 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { LoggerService, LogEntry } from '@common'; import { Router } from '@angular/router';
import { LoggerService, LogEntry, StorageService } from '@common';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
@Component({ @Component({
@@ -10,6 +11,8 @@ import { DatePipe } from '@angular/common';
}) })
export class LogsComponent implements OnInit { export class LogsComponent implements OnInit {
readonly #logger = inject(LoggerService); readonly #logger = inject(LoggerService);
readonly #storage = inject(StorageService);
readonly #router = inject(Router);
get logs(): LogEntry[] { get logs(): LogEntry[] {
return this.#logger.logs; return this.#logger.logs;
@@ -40,4 +43,10 @@ export class LogsComponent implements OnInit {
return 'log-info'; return 'log-info';
} }
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }

View File

@@ -1,4 +1,7 @@
<div class="sam-text-header"> <div class="sam-text-header">
<button class="lock-btn" title="Lock" (click)="onClickLock()">
<span class="emoji">🔒</span>
</button>
<span> Settings </span> <span> Settings </span>
</div> </div>
@@ -12,6 +15,9 @@
Import Vault Import Vault
</button> </button>
<lib-nav-item text="🪵 Logs" (click)="navigate('/home/logs')"></lib-nav-item>
<lib-nav-item text="💡 Info" (click)="navigate('/home/info')"></lib-nav-item>
<div class="sam-flex-grow"></div> <div class="sam-flex-grow"></div>
<button <button

View File

@@ -4,8 +4,11 @@
flex-direction: column; flex-direction: column;
row-gap: var(--size); row-gap: var(--size);
overflow-y: auto; overflow-y: auto;
padding-left: var(--size);
padding-right: var(--size); > *:not(.sam-text-header) {
margin-left: var(--size);
margin-right: var(--size);
}
.file-input { .file-input {
position: absolute; position: absolute;

View File

@@ -1,10 +1,12 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { import {
BrowserSyncFlow, BrowserSyncFlow,
ConfirmComponent, ConfirmComponent,
DateHelper, DateHelper,
LoggerService, LoggerService,
NavComponent, NavComponent,
NavItemComponent,
StartupService, StartupService,
StorageService, StorageService,
} from '@common'; } from '@common';
@@ -12,11 +14,12 @@ import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage
@Component({ @Component({
selector: 'app-settings', selector: 'app-settings',
imports: [ConfirmComponent], imports: [ConfirmComponent, NavItemComponent],
templateUrl: './settings.component.html', templateUrl: './settings.component.html',
styleUrl: './settings.component.scss', styleUrl: './settings.component.scss',
}) })
export class SettingsComponent extends NavComponent implements OnInit { export class SettingsComponent extends NavComponent implements OnInit {
readonly #router = inject(Router);
syncFlow: string | undefined; syncFlow: string | undefined;
readonly #storage = inject(StorageService); readonly #storage = inject(StorageService);
@@ -74,4 +77,10 @@ export class SettingsComponent extends NavComponent implements OnInit {
downloadAnchorNode.click(); downloadAnchorNode.click();
downloadAnchorNode.remove(); downloadAnchorNode.remove();
} }
async onClickLock() {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
} }