Release v1.2.1 - Add quick-add mint list to Cashu wallet
- Add suggested mints list (Minibits, Coinos, 21Mint, Macadamia, Stablenut) - Show quick-add menu on empty Cashu page with + icon and descriptions - Add collapsible "Quick Add" disclosure when mints exist - Hide already-added mints from the list - Closes #6 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "plebeian-signer",
|
"name": "plebeian-signer",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "plebeian-signer",
|
"name": "plebeian-signer",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^19.0.0",
|
"@angular/animations": "^19.0.0",
|
||||||
"@angular/common": "^19.0.0",
|
"@angular/common": "^19.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "plebeian-signer",
|
"name": "plebeian-signer",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"custom": {
|
"custom": {
|
||||||
"chrome": {
|
"chrome": {
|
||||||
"version": "v1.1.6"
|
"version": "v1.1.6"
|
||||||
|
|||||||
@@ -122,6 +122,31 @@
|
|||||||
<button class="show-info-btn" (click)="showCashuInfo = true">
|
<button class="show-info-btn" (click)="showCashuInfo = true">
|
||||||
Show storage info
|
Show storage info
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Suggested mints for quick-add -->
|
||||||
|
<div class="quick-add-section">
|
||||||
|
<div class="quick-add-label">Quick Add a Mint</div>
|
||||||
|
<div class="quick-add-menu">
|
||||||
|
@for (mint of suggestedMints; track mint.url) {
|
||||||
|
@if (!isMintAlreadyAdded(mint.url)) {
|
||||||
|
<button
|
||||||
|
class="quick-add-item"
|
||||||
|
[disabled]="addingMint"
|
||||||
|
(click)="quickAddMint(mint)"
|
||||||
|
>
|
||||||
|
<span class="mint-row">
|
||||||
|
<span class="add-icon">+</span>
|
||||||
|
<span class="mint-name">{{ mint.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="mint-desc">{{ mint.description }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (mintError) {
|
||||||
|
<div class="error-message small">{{ mintError }}</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -134,6 +159,33 @@
|
|||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick add disclosure when mints exist -->
|
||||||
|
@if (hasUnavailableMints()) {
|
||||||
|
<details class="quick-add-disclosure">
|
||||||
|
<summary>Quick Add</summary>
|
||||||
|
<div class="quick-add-menu">
|
||||||
|
@for (mint of suggestedMints; track mint.url) {
|
||||||
|
@if (!isMintAlreadyAdded(mint.url)) {
|
||||||
|
<button
|
||||||
|
class="quick-add-item"
|
||||||
|
[disabled]="addingMint"
|
||||||
|
(click)="quickAddMint(mint)"
|
||||||
|
>
|
||||||
|
<span class="mint-row">
|
||||||
|
<span class="add-icon">+</span>
|
||||||
|
<span class="mint-name">{{ mint.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="mint-desc">{{ mint.description }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (mintError) {
|
||||||
|
<div class="error-message small">{{ mintError }}</div>
|
||||||
|
}
|
||||||
|
</details>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
<button class="add-wallet-btn" (click)="showAddMint()">
|
<button class="add-wallet-btn" (click)="showAddMint()">
|
||||||
<span class="emoji">+</span>
|
<span class="emoji">+</span>
|
||||||
@@ -210,6 +262,31 @@
|
|||||||
<!-- Cashu add mint form -->
|
<!-- Cashu add mint form -->
|
||||||
@else if (activeSection === 'cashu-add') {
|
@else if (activeSection === 'cashu-add') {
|
||||||
<div class="add-wallet-form">
|
<div class="add-wallet-form">
|
||||||
|
<!-- Suggested mints -->
|
||||||
|
<div class="suggested-mints">
|
||||||
|
<div class="suggested-label">Quick Add</div>
|
||||||
|
<div class="suggested-list">
|
||||||
|
@for (mint of suggestedMints; track mint.url) {
|
||||||
|
<button
|
||||||
|
class="suggested-mint-btn"
|
||||||
|
[class.already-added]="isMintAlreadyAdded(mint.url)"
|
||||||
|
[disabled]="isMintAlreadyAdded(mint.url) || addingMint"
|
||||||
|
(click)="selectSuggestedMint(mint)"
|
||||||
|
[title]="mint.description"
|
||||||
|
>
|
||||||
|
<span class="mint-name">{{ mint.name }}</span>
|
||||||
|
@if (isMintAlreadyAdded(mint.url)) {
|
||||||
|
<span class="added-badge">✓</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-divider">
|
||||||
|
<span>or enter manually</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="mintName">Mint Name</label>
|
<label for="mintName">Mint Name</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -1134,3 +1134,182 @@
|
|||||||
padding: var(--size);
|
padding: var(--size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Suggested mints quick-add
|
||||||
|
.suggested-mints {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--size-h);
|
||||||
|
|
||||||
|
&.centered {
|
||||||
|
align-items: center;
|
||||||
|
margin-top: var(--size);
|
||||||
|
|
||||||
|
.suggested-list {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggested-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggested-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--size-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggested-mint-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: var(--background-light);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--foreground);
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background: var(--background-light-hover);
|
||||||
|
border-color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.already-added {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
.added-badge {
|
||||||
|
color: var(--success, #22c55e);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-name {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-divider {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--size);
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick add section (empty state)
|
||||||
|
.quick-add-section {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: var(--size);
|
||||||
|
|
||||||
|
.quick-add-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: var(--size-h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick add disclosure (when mints exist)
|
||||||
|
.quick-add-disclosure {
|
||||||
|
margin-top: var(--size-h);
|
||||||
|
|
||||||
|
summary {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: var(--size-h);
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::marker {
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[open] summary {
|
||||||
|
margin-bottom: var(--size-h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick add menu (shared by both)
|
||||||
|
.quick-add-menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
background: var(--background-light);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-add-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 2px;
|
||||||
|
padding: var(--size-h) var(--size);
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background: var(--background-light-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--size-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--success, #22c55e);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-name {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-desc {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
padding-left: calc(1rem + var(--size-h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -123,6 +123,15 @@ export class WalletComponent extends NavComponent implements OnInit, OnDestroy {
|
|||||||
refreshingMint = false;
|
refreshingMint = false;
|
||||||
refreshError = '';
|
refreshError = '';
|
||||||
|
|
||||||
|
// Suggested mints for quick-add
|
||||||
|
readonly suggestedMints = [
|
||||||
|
{ name: 'Minibits', url: 'https://mint.minibits.cash', description: 'Well-established mobile wallet mint' },
|
||||||
|
{ name: 'Coinos', url: 'https://mint.coinos.io', description: 'Lightning wallet with Cashu integration' },
|
||||||
|
{ name: '21Mint', url: 'https://21mint.me', description: 'Community mint' },
|
||||||
|
{ name: 'Macadamia', url: 'https://mint.macadamia.cash', description: 'Reliable community mint' },
|
||||||
|
{ name: 'Stablenut (USD)', url: 'https://stablenut.umint.cash', unit: 'usd', description: 'USD-denominated mint' },
|
||||||
|
];
|
||||||
|
|
||||||
get title(): string {
|
get title(): string {
|
||||||
switch (this.activeSection) {
|
switch (this.activeSection) {
|
||||||
case 'cashu':
|
case 'cashu':
|
||||||
@@ -499,6 +508,35 @@ export class WalletComponent extends NavComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectSuggestedMint(mint: { name: string; url: string }) {
|
||||||
|
this.newMintName = mint.name;
|
||||||
|
this.newMintUrl = mint.url;
|
||||||
|
this.mintError = '';
|
||||||
|
this.mintTestResult = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
isMintAlreadyAdded(mintUrl: string): boolean {
|
||||||
|
return this.mints.some(m => m.mintUrl === mintUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasUnavailableMints(): boolean {
|
||||||
|
return this.suggestedMints.some(m => !this.isMintAlreadyAdded(m.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
async quickAddMint(mint: { name: string; url: string }) {
|
||||||
|
this.addingMint = true;
|
||||||
|
this.mintError = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.cashuService.addMint(mint.name, mint.url);
|
||||||
|
} catch (error) {
|
||||||
|
this.mintError =
|
||||||
|
error instanceof Error ? error.message : 'Failed to add mint';
|
||||||
|
} finally {
|
||||||
|
this.addingMint = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async deleteMint() {
|
async deleteMint() {
|
||||||
if (!this.selectedMintId) return;
|
if (!this.selectedMintId) return;
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,31 @@
|
|||||||
<button class="show-info-btn" (click)="showCashuInfo = true">
|
<button class="show-info-btn" (click)="showCashuInfo = true">
|
||||||
Show storage info
|
Show storage info
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Suggested mints for quick-add -->
|
||||||
|
<div class="quick-add-section">
|
||||||
|
<div class="quick-add-label">Quick Add a Mint</div>
|
||||||
|
<div class="quick-add-menu">
|
||||||
|
@for (mint of suggestedMints; track mint.url) {
|
||||||
|
@if (!isMintAlreadyAdded(mint.url)) {
|
||||||
|
<button
|
||||||
|
class="quick-add-item"
|
||||||
|
[disabled]="addingMint"
|
||||||
|
(click)="quickAddMint(mint)"
|
||||||
|
>
|
||||||
|
<span class="mint-row">
|
||||||
|
<span class="add-icon">+</span>
|
||||||
|
<span class="mint-name">{{ mint.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="mint-desc">{{ mint.description }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (mintError) {
|
||||||
|
<div class="error-message small">{{ mintError }}</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -134,6 +159,33 @@
|
|||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick add disclosure when mints exist -->
|
||||||
|
@if (hasUnavailableMints()) {
|
||||||
|
<details class="quick-add-disclosure">
|
||||||
|
<summary>Quick Add</summary>
|
||||||
|
<div class="quick-add-menu">
|
||||||
|
@for (mint of suggestedMints; track mint.url) {
|
||||||
|
@if (!isMintAlreadyAdded(mint.url)) {
|
||||||
|
<button
|
||||||
|
class="quick-add-item"
|
||||||
|
[disabled]="addingMint"
|
||||||
|
(click)="quickAddMint(mint)"
|
||||||
|
>
|
||||||
|
<span class="mint-row">
|
||||||
|
<span class="add-icon">+</span>
|
||||||
|
<span class="mint-name">{{ mint.name }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="mint-desc">{{ mint.description }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (mintError) {
|
||||||
|
<div class="error-message small">{{ mintError }}</div>
|
||||||
|
}
|
||||||
|
</details>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
<button class="add-wallet-btn" (click)="showAddMint()">
|
<button class="add-wallet-btn" (click)="showAddMint()">
|
||||||
<span class="emoji">+</span>
|
<span class="emoji">+</span>
|
||||||
@@ -210,6 +262,31 @@
|
|||||||
<!-- Cashu add mint form -->
|
<!-- Cashu add mint form -->
|
||||||
@else if (activeSection === 'cashu-add') {
|
@else if (activeSection === 'cashu-add') {
|
||||||
<div class="add-wallet-form">
|
<div class="add-wallet-form">
|
||||||
|
<!-- Suggested mints -->
|
||||||
|
<div class="suggested-mints">
|
||||||
|
<div class="suggested-label">Quick Add</div>
|
||||||
|
<div class="suggested-list">
|
||||||
|
@for (mint of suggestedMints; track mint.url) {
|
||||||
|
<button
|
||||||
|
class="suggested-mint-btn"
|
||||||
|
[class.already-added]="isMintAlreadyAdded(mint.url)"
|
||||||
|
[disabled]="isMintAlreadyAdded(mint.url) || addingMint"
|
||||||
|
(click)="selectSuggestedMint(mint)"
|
||||||
|
[title]="mint.description"
|
||||||
|
>
|
||||||
|
<span class="mint-name">{{ mint.name }}</span>
|
||||||
|
@if (isMintAlreadyAdded(mint.url)) {
|
||||||
|
<span class="added-badge">✓</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-divider">
|
||||||
|
<span>or enter manually</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="mintName">Mint Name</label>
|
<label for="mintName">Mint Name</label>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -1134,3 +1134,173 @@
|
|||||||
padding: var(--size);
|
padding: var(--size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Suggested mints quick-add
|
||||||
|
.suggested-mints {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--size-h);
|
||||||
|
|
||||||
|
.suggested-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggested-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--size-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
.suggested-mint-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: var(--background-light);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--foreground);
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background: var(--background-light-hover);
|
||||||
|
border-color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.already-added {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
.added-badge {
|
||||||
|
color: var(--success, #22c55e);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-name {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-divider {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--size);
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick add section (empty state)
|
||||||
|
.quick-add-section {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: var(--size);
|
||||||
|
|
||||||
|
.quick-add-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: var(--size-h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick add disclosure (when mints exist)
|
||||||
|
.quick-add-disclosure {
|
||||||
|
margin-top: var(--size-h);
|
||||||
|
|
||||||
|
summary {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: var(--size-h);
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::marker {
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[open] summary {
|
||||||
|
margin-bottom: var(--size-h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick add menu (shared by both)
|
||||||
|
.quick-add-menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
background: var(--background-light);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-add-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 2px;
|
||||||
|
padding: var(--size-h) var(--size);
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background: var(--background-light-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--size-h);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--success, #22c55e);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-name {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mint-desc {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
padding-left: calc(1rem + var(--size-h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -123,6 +123,15 @@ export class WalletComponent extends NavComponent implements OnInit, OnDestroy {
|
|||||||
refreshingMint = false;
|
refreshingMint = false;
|
||||||
refreshError = '';
|
refreshError = '';
|
||||||
|
|
||||||
|
// Suggested mints for quick-add
|
||||||
|
readonly suggestedMints = [
|
||||||
|
{ name: 'Minibits', url: 'https://mint.minibits.cash', description: 'Well-established mobile wallet mint' },
|
||||||
|
{ name: 'Coinos', url: 'https://mint.coinos.io', description: 'Lightning wallet with Cashu integration' },
|
||||||
|
{ name: '21Mint', url: 'https://21mint.me', description: 'Community mint' },
|
||||||
|
{ name: 'Macadamia', url: 'https://mint.macadamia.cash', description: 'Reliable community mint' },
|
||||||
|
{ name: 'Stablenut (USD)', url: 'https://stablenut.umint.cash', unit: 'usd', description: 'USD-denominated mint' },
|
||||||
|
];
|
||||||
|
|
||||||
get title(): string {
|
get title(): string {
|
||||||
switch (this.activeSection) {
|
switch (this.activeSection) {
|
||||||
case 'cashu':
|
case 'cashu':
|
||||||
@@ -499,6 +508,35 @@ export class WalletComponent extends NavComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectSuggestedMint(mint: { name: string; url: string }) {
|
||||||
|
this.newMintName = mint.name;
|
||||||
|
this.newMintUrl = mint.url;
|
||||||
|
this.mintError = '';
|
||||||
|
this.mintTestResult = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
isMintAlreadyAdded(mintUrl: string): boolean {
|
||||||
|
return this.mints.some(m => m.mintUrl === mintUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasUnavailableMints(): boolean {
|
||||||
|
return this.suggestedMints.some(m => !this.isMintAlreadyAdded(m.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
async quickAddMint(mint: { name: string; url: string }) {
|
||||||
|
this.addingMint = true;
|
||||||
|
this.mintError = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.cashuService.addMint(mint.name, mint.url);
|
||||||
|
} catch (error) {
|
||||||
|
this.mintError =
|
||||||
|
error instanceof Error ? error.message : 'Failed to add mint';
|
||||||
|
} finally {
|
||||||
|
this.addingMint = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async deleteMint() {
|
async deleteMint() {
|
||||||
if (!this.selectedMintId) return;
|
if (!this.selectedMintId) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user