@oasisomniverse/angular 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +37 -0
- package/src/components/avatar/avatar-wallet.component.ts +49 -0
- package/src/components/avatar/edit-avatar.component.ts +28 -0
- package/src/components/avatar/search-avatar.component.ts +45 -0
- package/src/components/avatar/view-avatar.component.ts +49 -0
- package/src/components/avatar-connect/avatar-connect.component.ts +78 -0
- package/src/components/avatar-profile/avatar-profile.component.ts +146 -0
- package/src/components/coming-soon/coming-soon.component.ts +27 -0
- package/src/components/confirmation/confirmation.component.ts +38 -0
- package/src/components/contact/contact.component.ts +64 -0
- package/src/components/data-screen/add-data.component.ts +50 -0
- package/src/components/data-screen/cross-chain-management.component.ts +28 -0
- package/src/components/data-screen/load-data.component.ts +28 -0
- package/src/components/data-screen/manage-data.component.ts +50 -0
- package/src/components/data-screen/off-chain-management.component.ts +28 -0
- package/src/components/data-screen/search-data.component.ts +40 -0
- package/src/components/eggs/eggs.component.ts +76 -0
- package/src/components/eggs/manage-eggs.component.ts +50 -0
- package/src/components/eggs/search-eggs.component.ts +40 -0
- package/src/components/eggs/view-eggs.component.ts +49 -0
- package/src/components/forgot-password/forgot-password.component.ts +80 -0
- package/src/components/game/game.component.ts +58 -0
- package/src/components/game/search-profiles.component.ts +36 -0
- package/src/components/game/view-achievements.component.ts +48 -0
- package/src/components/game/view-leagues.component.ts +48 -0
- package/src/components/game/view-tournaments.component.ts +49 -0
- package/src/components/hyperdrive/hyperdrive.component.ts +81 -0
- package/src/components/karma/search-karma.component.ts +36 -0
- package/src/components/karma/view-avatar-karma.component.ts +51 -0
- package/src/components/karma/view-karma.component.ts +46 -0
- package/src/components/karma/vote-karma.component.ts +48 -0
- package/src/components/karma-panel/karma-panel.component.ts +87 -0
- package/src/components/karma-toast/karma-toast.component.ts +33 -0
- package/src/components/login/login.component.ts +95 -0
- package/src/components/map/add-2d-object-map.component.ts +42 -0
- package/src/components/map/add-3d-object-map.component.ts +43 -0
- package/src/components/map/add-quest-to-map.component.ts +42 -0
- package/src/components/map/download-our-world.component.ts +28 -0
- package/src/components/map/manage-map.component.ts +28 -0
- package/src/components/map/map.component.ts +70 -0
- package/src/components/map/plot-route-on-map.component.ts +42 -0
- package/src/components/map/search-map.component.ts +44 -0
- package/src/components/map/view-global-3d-map.component.ts +28 -0
- package/src/components/map/view-halons-on-map.component.ts +28 -0
- package/src/components/map/view-oapp-on-map.component.ts +28 -0
- package/src/components/map/view-quest-on-map.component.ts +28 -0
- package/src/components/menu-message/menu-message.component.ts +69 -0
- package/src/components/messages/message.component.ts +59 -0
- package/src/components/messaging/messaging.component.ts +89 -0
- package/src/components/mission/manage-mission.component.ts +43 -0
- package/src/components/mission/mission.component.ts +63 -0
- package/src/components/mission/search-mission.component.ts +36 -0
- package/src/components/mission/view-mission.component.ts +49 -0
- package/src/components/modal/modal.component.ts +28 -0
- package/src/components/navbar/navbar.component.ts +64 -0
- package/src/components/nft/contact-popup.component.ts +41 -0
- package/src/components/nft/manage-oasis-nft.component.ts +43 -0
- package/src/components/nft/nft.component.ts +70 -0
- package/src/components/nft/purchase-oasis-nft.component.ts +53 -0
- package/src/components/nft/purchase-oasis-virtual-land-nft.component.ts +28 -0
- package/src/components/nft/search-oasis-nft.component.ts +36 -0
- package/src/components/nft/solana.component.ts +28 -0
- package/src/components/nft/view-oasis-nft.component.ts +52 -0
- package/src/components/oapp/create-oapp.component.ts +43 -0
- package/src/components/oapp/deploy-oapp.component.ts +42 -0
- package/src/components/oapp/download-our-world.component.ts +28 -0
- package/src/components/oapp/edit-oapp.component.ts +41 -0
- package/src/components/oapp/install-oapp.component.ts +36 -0
- package/src/components/oapp/launch-oapp.component.ts +58 -0
- package/src/components/oapp/manage-oapp.component.ts +42 -0
- package/src/components/oapp/oapp.component.ts +70 -0
- package/src/components/oapp/search-oapp.component.ts +36 -0
- package/src/components/oasis-card/oasis-card.component.ts +30 -0
- package/src/components/onet/onet.component.ts +77 -0
- package/src/components/onode/onode.component.ts +73 -0
- package/src/components/provider/activity-pub.component.ts +44 -0
- package/src/components/provider/compare-provider-speeds.component.ts +48 -0
- package/src/components/provider/eosio.component.ts +44 -0
- package/src/components/provider/ethereum.component.ts +44 -0
- package/src/components/provider/holochain.component.ts +44 -0
- package/src/components/provider/ipfs.component.ts +44 -0
- package/src/components/provider/manage-auto-fail-over.component.ts +42 -0
- package/src/components/provider/manage-auto-replicaton.component.ts +42 -0
- package/src/components/provider/manage-load-balancing.component.ts +42 -0
- package/src/components/provider/manage-providers.component.ts +28 -0
- package/src/components/provider/mongo-db.component.ts +44 -0
- package/src/components/provider/neo4j.component.ts +44 -0
- package/src/components/provider/search-providers.component.ts +36 -0
- package/src/components/provider/seeds-provider.component.ts +42 -0
- package/src/components/provider/solid.component.ts +44 -0
- package/src/components/provider/sql-lite.component.ts +44 -0
- package/src/components/provider/three-fold.component.ts +44 -0
- package/src/components/provider/view-provider-stats.component.ts +61 -0
- package/src/components/provider/view-providers.component.ts +54 -0
- package/src/components/provider-dropdown/provider-dropdown.component.ts +64 -0
- package/src/components/providers/providers.component.ts +60 -0
- package/src/components/quest/manage-quest.component.ts +43 -0
- package/src/components/quest/quest.component.ts +65 -0
- package/src/components/quest/search-quest.component.ts +36 -0
- package/src/components/quest/view-quest.component.ts +49 -0
- package/src/components/reset-password/reset-password.component.ts +68 -0
- package/src/components/search-avatars/search-avatars.component.ts +80 -0
- package/src/components/seeds/accept-invite.component.ts +44 -0
- package/src/components/seeds/donate-seeds.component.ts +42 -0
- package/src/components/seeds/manage-seeds.component.ts +42 -0
- package/src/components/seeds/pay-with-seeds.component.ts +41 -0
- package/src/components/seeds/reward-seeds.component.ts +41 -0
- package/src/components/seeds/search-seeds.component.ts +36 -0
- package/src/components/seeds/seeds.component.ts +75 -0
- package/src/components/seeds/send-invite.component.ts +41 -0
- package/src/components/seeds/view-organizations.component.ts +55 -0
- package/src/components/seeds/view-seeds.component.ts +78 -0
- package/src/components/settings/settings.component.ts +96 -0
- package/src/components/signup/signup.component.ts +118 -0
- package/src/components/star-field/star-field.component.ts +44 -0
- package/src/components/verify-email/verify-email.component.ts +48 -0
- package/src/components/wallet/wallet.component.ts +83 -0
- package/src/index.ts +145 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'oasis-search-providers',
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [CommonModule, FormsModule],
|
|
9
|
+
template: `
|
|
10
|
+
<div class="sf-shell">
|
|
11
|
+
<div class="sf-header"><span>🔍</span><h2 class="sf-title">Search Providers</h2></div>
|
|
12
|
+
<div class="sf-row"><input class="sf-input" [(ngModel)]="query" placeholder="Search by provider name or type..." (keyup.enter)="search()" /><button class="sf-btn" (click)="search()">Search</button></div>
|
|
13
|
+
@for (r of results(); track r) { <div class="sf-result">{{ r }}</div> }
|
|
14
|
+
<div class="sf-footer"><button class="sf-cancel" (click)="close.emit()">Close</button></div>
|
|
15
|
+
</div>
|
|
16
|
+
`,
|
|
17
|
+
styles: [`
|
|
18
|
+
.sf-shell{display:flex;flex-direction:column;gap:14px;padding:20px}
|
|
19
|
+
.sf-header{display:flex;align-items:center;gap:10px}
|
|
20
|
+
.sf-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
21
|
+
.sf-row{display:flex;gap:10px}
|
|
22
|
+
.sf-input{flex:1;background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.25);border-radius:8px;color:#fff;font-size:13px;padding:10px 14px;outline:none}
|
|
23
|
+
.sf-input:focus{border-color:rgba(0,200,255,.6)}
|
|
24
|
+
.sf-btn{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;padding:10px 20px;cursor:pointer;white-space:nowrap}
|
|
25
|
+
.sf-result{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:8px;color:#c8dff0;font-size:13px;padding:10px 14px}
|
|
26
|
+
.sf-footer{display:flex;justify-content:flex-end}
|
|
27
|
+
.sf-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:8px 20px;cursor:pointer}
|
|
28
|
+
`]
|
|
29
|
+
})
|
|
30
|
+
export class SearchProvidersComponent {
|
|
31
|
+
@Input() show = false;
|
|
32
|
+
@Output() close = new EventEmitter<void>();
|
|
33
|
+
query = '';
|
|
34
|
+
results = signal<string[]>([]);
|
|
35
|
+
search() { if (this.query.trim()) this.results.set(['No results found for "' + this.query + '"']); }
|
|
36
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-seeds-provider',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="mf-shell">
|
|
10
|
+
<div class="mf-header"><span>🌱</span><h2 class="mf-title">SEEDS Provider</h2></div>
|
|
11
|
+
<div class="mf-body">
|
|
12
|
+
<div class="mf-field"><label class="mf-lbl">Account Number</label><input class="mf-inp" placeholder="Account Number..." /></div>
|
|
13
|
+
<div class="mf-field"><label class="mf-lbl">Network</label><input class="mf-inp" placeholder="Network..." /></div>
|
|
14
|
+
<div class="mf-field"><label class="mf-lbl">API Endpoint</label><input class="mf-inp" placeholder="API Endpoint..." /></div>
|
|
15
|
+
<div class="mf-field"><label class="mf-lbl">API Key</label><input class="mf-inp" placeholder="API Key..." /></div>
|
|
16
|
+
<div class="mf-field"><label class="mf-lbl">Region</label><input class="mf-inp" placeholder="Region..." /></div>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="mf-footer">
|
|
19
|
+
<button class="mf-save" (click)="save()">Save</button>
|
|
20
|
+
<button class="mf-cancel" (click)="close.emit()">Cancel</button>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
`,
|
|
24
|
+
styles: [`
|
|
25
|
+
.mf-shell{display:flex;flex-direction:column;gap:18px;padding:20px}
|
|
26
|
+
.mf-header{display:flex;align-items:center;gap:10px}
|
|
27
|
+
.mf-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
28
|
+
.mf-body{display:flex;flex-direction:column;gap:12px}
|
|
29
|
+
.mf-field{display:flex;flex-direction:column;gap:5px}
|
|
30
|
+
.mf-lbl{font-size:11px;font-weight:700;letter-spacing:.07em;color:#7a9bbf;text-transform:uppercase}
|
|
31
|
+
.mf-inp{background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.25);border-radius:8px;color:#fff;font-size:13px;padding:10px 14px;outline:none}
|
|
32
|
+
.mf-inp:focus{border-color:rgba(0,200,255,.6)}
|
|
33
|
+
.mf-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
34
|
+
.mf-save{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;padding:10px 22px;cursor:pointer}
|
|
35
|
+
.mf-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:10px 18px;cursor:pointer}
|
|
36
|
+
`]
|
|
37
|
+
})
|
|
38
|
+
export class SeedsProviderComponent {
|
|
39
|
+
@Input() show = false;
|
|
40
|
+
@Output() close = new EventEmitter<void>();
|
|
41
|
+
save() { this.close.emit(); }
|
|
42
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-solid',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="pi-shell">
|
|
10
|
+
<div class="pi-header"><div class="pi-icon">🔷</div><h2 class="pi-title">Solid</h2></div>
|
|
11
|
+
<div class="pi-body">
|
|
12
|
+
<div class="pi-row"><span class="pi-label">Provider</span><span class="pi-value">Solid</span></div>
|
|
13
|
+
<div class="pi-row"><span class="pi-label">Website</span><span class="pi-value">solidproject.org</span></div>
|
|
14
|
+
<div class="pi-row"><span class="pi-label">Status</span><span class="pi-badge pi-badge--active">Active</span></div>
|
|
15
|
+
<div class="pi-row"><span class="pi-label">Description</span><span class="pi-value" style="max-width:240px;text-align:right;font-size:12px;color:#a8bfd8">Decentralised data storage enabling user ownership of personal data.</span></div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="pi-footer">
|
|
18
|
+
<button class="pi-btn-primary" (click)="connect()">Connect</button>
|
|
19
|
+
<button class="pi-btn-cancel" (click)="close.emit()">Cancel</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
`,
|
|
23
|
+
styles: [`
|
|
24
|
+
.pi-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
25
|
+
.pi-header{display:flex;align-items:center;gap:12px}
|
|
26
|
+
.pi-icon{font-size:36px}
|
|
27
|
+
.pi-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
28
|
+
.pi-body{background:rgba(255,255,255,.03);border:1px solid rgba(0,200,255,.1);border-radius:10px;padding:16px;display:flex;flex-direction:column;gap:10px}
|
|
29
|
+
.pi-row{display:flex;justify-content:space-between;align-items:center;font-size:13px}
|
|
30
|
+
.pi-label{color:#7a9bbf}
|
|
31
|
+
.pi-value{color:#c8dff0;font-weight:500}
|
|
32
|
+
.pi-badge{font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;border-radius:999px;padding:2px 9px;border:1px solid currentColor}
|
|
33
|
+
.pi-badge--active{color:#00c864;border-color:rgba(0,200,100,.3)}
|
|
34
|
+
.pi-badge--inactive{color:#7a9bbf;border-color:rgba(122,155,191,.25)}
|
|
35
|
+
.pi-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
36
|
+
.pi-btn-primary{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 18px;cursor:pointer}
|
|
37
|
+
.pi-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 18px;cursor:pointer}
|
|
38
|
+
`]
|
|
39
|
+
})
|
|
40
|
+
export class SolidComponent {
|
|
41
|
+
@Input() show = false;
|
|
42
|
+
@Output() close = new EventEmitter<void>();
|
|
43
|
+
connect() { this.close.emit(); }
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-sql-lite',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="pi-shell">
|
|
10
|
+
<div class="pi-header"><div class="pi-icon">🗄️</div><h2 class="pi-title">SQLite</h2></div>
|
|
11
|
+
<div class="pi-body">
|
|
12
|
+
<div class="pi-row"><span class="pi-label">Provider</span><span class="pi-value">SQLite</span></div>
|
|
13
|
+
<div class="pi-row"><span class="pi-label">Website</span><span class="pi-value">sqlite.org</span></div>
|
|
14
|
+
<div class="pi-row"><span class="pi-label">Status</span><span class="pi-badge pi-badge--active">Active</span></div>
|
|
15
|
+
<div class="pi-row"><span class="pi-label">Description</span><span class="pi-value" style="max-width:240px;text-align:right;font-size:12px;color:#a8bfd8">Lightweight embedded relational database engine.</span></div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="pi-footer">
|
|
18
|
+
<button class="pi-btn-primary" (click)="connect()">Connect</button>
|
|
19
|
+
<button class="pi-btn-cancel" (click)="close.emit()">Cancel</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
`,
|
|
23
|
+
styles: [`
|
|
24
|
+
.pi-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
25
|
+
.pi-header{display:flex;align-items:center;gap:12px}
|
|
26
|
+
.pi-icon{font-size:36px}
|
|
27
|
+
.pi-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
28
|
+
.pi-body{background:rgba(255,255,255,.03);border:1px solid rgba(0,200,255,.1);border-radius:10px;padding:16px;display:flex;flex-direction:column;gap:10px}
|
|
29
|
+
.pi-row{display:flex;justify-content:space-between;align-items:center;font-size:13px}
|
|
30
|
+
.pi-label{color:#7a9bbf}
|
|
31
|
+
.pi-value{color:#c8dff0;font-weight:500}
|
|
32
|
+
.pi-badge{font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;border-radius:999px;padding:2px 9px;border:1px solid currentColor}
|
|
33
|
+
.pi-badge--active{color:#00c864;border-color:rgba(0,200,100,.3)}
|
|
34
|
+
.pi-badge--inactive{color:#7a9bbf;border-color:rgba(122,155,191,.25)}
|
|
35
|
+
.pi-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
36
|
+
.pi-btn-primary{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 18px;cursor:pointer}
|
|
37
|
+
.pi-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 18px;cursor:pointer}
|
|
38
|
+
`]
|
|
39
|
+
})
|
|
40
|
+
export class SqlLiteComponent {
|
|
41
|
+
@Input() show = false;
|
|
42
|
+
@Output() close = new EventEmitter<void>();
|
|
43
|
+
connect() { this.close.emit(); }
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-three-fold',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="pi-shell">
|
|
10
|
+
<div class="pi-header"><div class="pi-icon">🌱</div><h2 class="pi-title">ThreeFold</h2></div>
|
|
11
|
+
<div class="pi-body">
|
|
12
|
+
<div class="pi-row"><span class="pi-label">Provider</span><span class="pi-value">ThreeFold</span></div>
|
|
13
|
+
<div class="pi-row"><span class="pi-label">Website</span><span class="pi-value">threefold.io</span></div>
|
|
14
|
+
<div class="pi-row"><span class="pi-label">Status</span><span class="pi-badge pi-badge--active">Active</span></div>
|
|
15
|
+
<div class="pi-row"><span class="pi-label">Description</span><span class="pi-value" style="max-width:240px;text-align:right;font-size:12px;color:#a8bfd8">Decentralised cloud infrastructure powered by renewable energy.</span></div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="pi-footer">
|
|
18
|
+
<button class="pi-btn-primary" (click)="connect()">Connect</button>
|
|
19
|
+
<button class="pi-btn-cancel" (click)="close.emit()">Cancel</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
`,
|
|
23
|
+
styles: [`
|
|
24
|
+
.pi-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
25
|
+
.pi-header{display:flex;align-items:center;gap:12px}
|
|
26
|
+
.pi-icon{font-size:36px}
|
|
27
|
+
.pi-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
28
|
+
.pi-body{background:rgba(255,255,255,.03);border:1px solid rgba(0,200,255,.1);border-radius:10px;padding:16px;display:flex;flex-direction:column;gap:10px}
|
|
29
|
+
.pi-row{display:flex;justify-content:space-between;align-items:center;font-size:13px}
|
|
30
|
+
.pi-label{color:#7a9bbf}
|
|
31
|
+
.pi-value{color:#c8dff0;font-weight:500}
|
|
32
|
+
.pi-badge{font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;border-radius:999px;padding:2px 9px;border:1px solid currentColor}
|
|
33
|
+
.pi-badge--active{color:#00c864;border-color:rgba(0,200,100,.3)}
|
|
34
|
+
.pi-badge--inactive{color:#7a9bbf;border-color:rgba(122,155,191,.25)}
|
|
35
|
+
.pi-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
36
|
+
.pi-btn-primary{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 18px;cursor:pointer}
|
|
37
|
+
.pi-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 18px;cursor:pointer}
|
|
38
|
+
`]
|
|
39
|
+
})
|
|
40
|
+
export class ThreeFoldComponent {
|
|
41
|
+
@Input() show = false;
|
|
42
|
+
@Output() close = new EventEmitter<void>();
|
|
43
|
+
connect() { this.close.emit(); }
|
|
44
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-view-provider-stats',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="vps-shell">
|
|
10
|
+
<div class="vps-header"><span>📊</span><h2 class="vps-title">Provider Stats</h2></div>
|
|
11
|
+
<div class="vps-grid">
|
|
12
|
+
@for (stat of stats(); track stat.label) {
|
|
13
|
+
<div class="vps-card">
|
|
14
|
+
<div class="vps-card-icon">{{ stat.icon }}</div>
|
|
15
|
+
<div class="vps-card-val">{{ stat.value }}</div>
|
|
16
|
+
<div class="vps-card-lbl">{{ stat.label }}</div>
|
|
17
|
+
</div>
|
|
18
|
+
}
|
|
19
|
+
</div>
|
|
20
|
+
<div class="vps-list">
|
|
21
|
+
@for (p of providerStats(); track p.name) {
|
|
22
|
+
<div class="vps-row"><span class="vps-pname">{{ p.name }}</span><span class="vps-puptime">{{ p.uptime }}% uptime</span><span class="vps-pspeed">{{ p.speed }}ms</span></div>
|
|
23
|
+
}
|
|
24
|
+
</div>
|
|
25
|
+
<div class="vps-footer"><button class="vps-btn" (click)="close.emit()">Close</button></div>
|
|
26
|
+
</div>
|
|
27
|
+
`,
|
|
28
|
+
styles: [`
|
|
29
|
+
.vps-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
30
|
+
.vps-header{display:flex;align-items:center;gap:10px}
|
|
31
|
+
.vps-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
32
|
+
.vps-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px}
|
|
33
|
+
.vps-card{background:rgba(0,200,255,.06);border:1px solid rgba(0,200,255,.15);border-radius:10px;padding:14px;text-align:center;display:flex;flex-direction:column;gap:6px}
|
|
34
|
+
.vps-card-icon{font-size:24px}
|
|
35
|
+
.vps-card-val{font-family:'Orbitron',sans-serif;font-size:18px;font-weight:700;color:#00c8ff}
|
|
36
|
+
.vps-card-lbl{font-size:10px;color:#7a9bbf;text-transform:uppercase;letter-spacing:.06em}
|
|
37
|
+
.vps-list{display:flex;flex-direction:column;gap:6px}
|
|
38
|
+
.vps-row{display:flex;align-items:center;gap:12px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.05);border-radius:8px;padding:8px 12px;font-size:12px}
|
|
39
|
+
.vps-pname{flex:1;color:#c8dff0}
|
|
40
|
+
.vps-puptime{color:#00c864;font-weight:600}
|
|
41
|
+
.vps-pspeed{color:#7a9bbf;width:50px;text-align:right}
|
|
42
|
+
.vps-footer{display:flex;justify-content:flex-end}
|
|
43
|
+
.vps-btn{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 22px;cursor:pointer}
|
|
44
|
+
`]
|
|
45
|
+
})
|
|
46
|
+
export class ViewProviderStatsComponent {
|
|
47
|
+
@Input() show = false;
|
|
48
|
+
@Output() close = new EventEmitter<void>();
|
|
49
|
+
stats = signal([
|
|
50
|
+
{ icon:'🌐', label:'Active Providers', value:'4' },
|
|
51
|
+
{ icon:'⚡', label:'Avg Speed', value:'55ms' },
|
|
52
|
+
{ icon:'📈', label:'Uptime', value:'99.2%' },
|
|
53
|
+
{ icon:'🔄', label:'Sync Count', value:'1,248' },
|
|
54
|
+
]);
|
|
55
|
+
providerStats = signal([
|
|
56
|
+
{ name:'Holochain', uptime:99.9, speed:12 },
|
|
57
|
+
{ name:'Ethereum', uptime:99.5, speed:180 },
|
|
58
|
+
{ name:'MongoDB', uptime:99.8, speed:5 },
|
|
59
|
+
{ name:'SQLite', uptime:100, speed:1 },
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-view-providers',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="vp-shell">
|
|
10
|
+
<div class="vp-header"><span>🌐</span><h2 class="vp-title">View Providers</h2></div>
|
|
11
|
+
<div class="vp-table-wrap">
|
|
12
|
+
<table class="vp-table">
|
|
13
|
+
<thead><tr><th>Provider</th><th>Installed</th><th>Running</th><th>VP Time</th></tr></thead>
|
|
14
|
+
<tbody>
|
|
15
|
+
@for (p of providers(); track p.name) {
|
|
16
|
+
<tr>
|
|
17
|
+
<td>{{ p.name }}</td>
|
|
18
|
+
<td><span class="vp-dot">{{ p.installed ? '✅' : '❌' }}</span></td>
|
|
19
|
+
<td><span class="vp-dot">{{ p.running ? '🟢' : '⚪' }}</span></td>
|
|
20
|
+
<td>{{ p.vpTime }}</td>
|
|
21
|
+
</tr>
|
|
22
|
+
}
|
|
23
|
+
</tbody>
|
|
24
|
+
</table>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="vp-footer"><button class="vp-btn" (click)="close.emit()">Close</button></div>
|
|
27
|
+
</div>
|
|
28
|
+
`,
|
|
29
|
+
styles: [`
|
|
30
|
+
.vp-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
31
|
+
.vp-header{display:flex;align-items:center;gap:10px}
|
|
32
|
+
.vp-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
33
|
+
.vp-table-wrap{overflow-x:auto;border:1px solid rgba(0,200,255,.15);border-radius:10px}
|
|
34
|
+
.vp-table{width:100%;border-collapse:collapse;font-size:13px}
|
|
35
|
+
.vp-table th{background:rgba(0,200,255,.08);color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:10px;font-weight:700;letter-spacing:.06em;padding:10px 12px;text-align:left;border-bottom:1px solid rgba(0,200,255,.15)}
|
|
36
|
+
.vp-table td{color:#c8dff0;padding:9px 12px;border-bottom:1px solid rgba(255,255,255,.04)}
|
|
37
|
+
.vp-table tr:last-child td{border-bottom:none}
|
|
38
|
+
.vp-footer{display:flex;justify-content:flex-end}
|
|
39
|
+
.vp-btn{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:9px 22px;cursor:pointer}
|
|
40
|
+
`]
|
|
41
|
+
})
|
|
42
|
+
export class ViewProvidersComponent {
|
|
43
|
+
@Input() show = false;
|
|
44
|
+
@Output() close = new EventEmitter<void>();
|
|
45
|
+
providers = signal([
|
|
46
|
+
{ name: 'Holochain', installed: true, running: true, vpTime: '12ms' },
|
|
47
|
+
{ name: 'Ethereum', installed: true, running: true, vpTime: '180ms' },
|
|
48
|
+
{ name: 'IPFS', installed: true, running: false, vpTime: 'N/A' },
|
|
49
|
+
{ name: 'MongoDB', installed: true, running: true, vpTime: '5ms' },
|
|
50
|
+
{ name: 'Neo4j', installed: false, running: false, vpTime: 'N/A' },
|
|
51
|
+
{ name: 'SQLite', installed: true, running: true, vpTime: '1ms' },
|
|
52
|
+
{ name: 'ThreeFold', installed: false, running: false, vpTime: 'N/A' },
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Component, signal, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
interface Provider { id: string; name: string; icon: string; color: string }
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'oasis-provider-dropdown',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule],
|
|
10
|
+
template: `
|
|
11
|
+
<div class="pd-shell">
|
|
12
|
+
<div class="pd-trigger" [class.pd-trigger--open]="open()" (click)="open.set(!open())">
|
|
13
|
+
<div class="pd-icon" [style.color]="selected().color">{{ selected().icon }}</div>
|
|
14
|
+
<div class="pd-label">
|
|
15
|
+
<div class="pd-name">{{ selected().name }}</div>
|
|
16
|
+
<div class="pd-sub">Active Provider</div>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="pd-arrow" [class.pd-arrow--open]="open()">▼</div>
|
|
19
|
+
</div>
|
|
20
|
+
@if (open()) {
|
|
21
|
+
<div class="pd-menu">
|
|
22
|
+
@for (p of providers; track p.id) {
|
|
23
|
+
<div class="pd-option" [class.pd-option--selected]="p.id === selected().id" (click)="select(p)">
|
|
24
|
+
<div class="pd-opt-icon" [style.color]="p.color">{{ p.icon }}</div>
|
|
25
|
+
<div class="pd-opt-name">{{ p.name }}</div>
|
|
26
|
+
</div>
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
}
|
|
30
|
+
</div>
|
|
31
|
+
`,
|
|
32
|
+
styles: [`
|
|
33
|
+
:host{display:block;position:relative}
|
|
34
|
+
.pd-shell{position:relative}
|
|
35
|
+
.pd-trigger{display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.25);border-radius:10px;padding:10px 14px;cursor:pointer;transition:border-color .2s;color:#fff}
|
|
36
|
+
.pd-trigger:hover,.pd-trigger--open{border-color:rgba(0,200,255,.5)}
|
|
37
|
+
.pd-icon{font-size:20px;width:28px;text-align:center}
|
|
38
|
+
.pd-label{flex:1}
|
|
39
|
+
.pd-name{font-family:'Orbitron',sans-serif;font-size:13px;font-weight:700;color:#fff}
|
|
40
|
+
.pd-sub{font-size:11px;color:#7a9bbf;margin-top:2px}
|
|
41
|
+
.pd-arrow{font-size:10px;color:#7a9bbf;transition:transform .2s}
|
|
42
|
+
.pd-arrow--open{transform:rotate(180deg)}
|
|
43
|
+
.pd-menu{position:absolute;top:calc(100% + 6px);left:0;right:0;background:#0d1b2e;border:1px solid rgba(0,200,255,.2);border-radius:10px;overflow:hidden;z-index:100;box-shadow:0 8px 32px rgba(0,0,0,.5)}
|
|
44
|
+
.pd-option{display:flex;align-items:center;gap:10px;padding:10px 14px;cursor:pointer;transition:background .15s;color:#e0f0ff}
|
|
45
|
+
.pd-option:hover{background:rgba(0,200,255,.1)}
|
|
46
|
+
.pd-option--selected{background:rgba(0,200,255,.12);border-left:3px solid #00c8ff}
|
|
47
|
+
.pd-opt-icon{font-size:18px;width:24px;text-align:center}
|
|
48
|
+
.pd-opt-name{font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700}
|
|
49
|
+
`]
|
|
50
|
+
})
|
|
51
|
+
export class ProviderDropdownComponent {
|
|
52
|
+
@Output() providerChange = new EventEmitter<Provider>();
|
|
53
|
+
open = signal(false);
|
|
54
|
+
providers: Provider[] = [
|
|
55
|
+
{ id: 'ethereum', name: 'Ethereum', icon: '⟠', color: '#627eea' },
|
|
56
|
+
{ id: 'solana', name: 'Solana', icon: '◎', color: '#9945ff' },
|
|
57
|
+
{ id: 'polygon', name: 'Polygon', icon: '⬡', color: '#8247e5' },
|
|
58
|
+
{ id: 'arbitrum', name: 'Arbitrum', icon: '🔵', color: '#2d9cdb' },
|
|
59
|
+
{ id: 'eosio', name: 'EOSIO', icon: '🔮', color: '#443f54' },
|
|
60
|
+
{ id: 'holochain', name: 'Holochain', icon: '⬡', color: '#00e5be' },
|
|
61
|
+
];
|
|
62
|
+
selected = signal<Provider>(this.providers[0]);
|
|
63
|
+
select(p: Provider) { this.selected.set(p); this.open.set(false); this.providerChange.emit(p); }
|
|
64
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
interface Provider { id: string; name: string; icon: string; color: string; type: string; connected: boolean; description: string }
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'oasis-providers',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule],
|
|
10
|
+
template: `
|
|
11
|
+
<div class="prov-shell">
|
|
12
|
+
<div class="prov-header"><h2 class="prov-title">🔗 Providers</h2><p class="prov-sub">Connect blockchain providers to your OASIS avatar.</p></div>
|
|
13
|
+
<div class="prov-list">
|
|
14
|
+
@for (p of providers(); track p.id) {
|
|
15
|
+
<div class="prov-card" [class.prov-card--connected]="p.connected">
|
|
16
|
+
<div class="prov-icon" [style.color]="p.color">{{ p.icon }}</div>
|
|
17
|
+
<div class="prov-info">
|
|
18
|
+
<div class="prov-name">{{ p.name }}</div>
|
|
19
|
+
<div class="prov-type">{{ p.type }}</div>
|
|
20
|
+
<div class="prov-desc">{{ p.description }}</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="prov-actions">
|
|
23
|
+
<div class="prov-status-dot" [class.prov-status-dot--on]="p.connected"></div>
|
|
24
|
+
<button class="prov-btn" [class.prov-btn--disconnect]="p.connected" (click)="toggle(p)">{{ p.connected ? 'Disconnect' : 'Connect' }}</button>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
`,
|
|
31
|
+
styles: [`
|
|
32
|
+
.prov-shell{display:flex;flex-direction:column;gap:18px}
|
|
33
|
+
.prov-header{text-align:center}
|
|
34
|
+
.prov-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}
|
|
35
|
+
.prov-sub{font-size:13px;color:#7a9bbf;margin:0}
|
|
36
|
+
.prov-list{display:flex;flex-direction:column;gap:10px}
|
|
37
|
+
.prov-card{display:flex;align-items:center;gap:14px;background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:12px;padding:14px 16px;transition:border-color .2s}
|
|
38
|
+
.prov-card--connected{border-color:rgba(72,220,130,.3);background:rgba(72,220,130,.03)}
|
|
39
|
+
.prov-icon{font-size:26px;flex-shrink:0}
|
|
40
|
+
.prov-info{flex:1}
|
|
41
|
+
.prov-name{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff;margin-bottom:2px}
|
|
42
|
+
.prov-type{font-size:11px;color:#5ba8ff;text-transform:uppercase;letter-spacing:.06em;margin-bottom:4px}
|
|
43
|
+
.prov-desc{font-size:12px;color:#7a9bbf}
|
|
44
|
+
.prov-actions{display:flex;flex-direction:column;align-items:center;gap:8px;flex-shrink:0}
|
|
45
|
+
.prov-status-dot{width:8px;height:8px;border-radius:50%;background:#4a6a88}
|
|
46
|
+
.prov-status-dot--on{background:#48dc82;box-shadow:0 0 6px #48dc82}
|
|
47
|
+
.prov-btn{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:7px;color:#fff;font-family:'Orbitron',sans-serif;font-size:10px;font-weight:700;letter-spacing:.06em;padding:7px 14px;cursor:pointer;white-space:nowrap}
|
|
48
|
+
.prov-btn--disconnect{background:rgba(255,80,80,.15);border:1px solid rgba(255,80,80,.3);color:#ff6b6b}
|
|
49
|
+
`]
|
|
50
|
+
})
|
|
51
|
+
export class ProvidersComponent {
|
|
52
|
+
providers = signal<Provider[]>([
|
|
53
|
+
{ id: '1', name: 'Ethereum', icon: '⟠', color: '#627eea', type: 'Blockchain', description: 'Connect your Ethereum wallet (MetaMask, WalletConnect).', connected: false },
|
|
54
|
+
{ id: '2', name: 'Solana', icon: '◎', color: '#9945ff', type: 'Blockchain', description: 'Connect your Solana wallet (Phantom, Solflare).', connected: false },
|
|
55
|
+
{ id: '3', name: 'EOSIO', icon: '🔮', color: '#443f54', type: 'Blockchain', description: 'Connect via EOSIO for high-speed transactions.', connected: false },
|
|
56
|
+
{ id: '4', name: 'Holochain', icon: '⬡', color: '#00e5be', type: 'P2P Network', description: 'Peer-to-peer data storage on Holochain.', connected: false },
|
|
57
|
+
{ id: '5', name: 'The Graph', icon: '📊', color: '#6f4cff', type: 'Indexer', description: 'Query blockchain data with The Graph protocol.', connected: false },
|
|
58
|
+
]);
|
|
59
|
+
toggle(p: Provider) { this.providers.update(l => l.map(x => x.id === p.id ? { ...x, connected: !x.connected } : x)); }
|
|
60
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-manage-quest',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="mf-shell">
|
|
10
|
+
<div class="mf-header"><span>⚔️</span><h2 class="mf-title">Manage Quest</h2></div>
|
|
11
|
+
<div class="mf-body">
|
|
12
|
+
<div class="mf-field"><label class="mf-lbl">Quest Name</label><input class="mf-inp" placeholder="Quest Name..." /></div>
|
|
13
|
+
<div class="mf-field"><label class="mf-lbl">Description</label><input class="mf-inp" placeholder="Description..." /></div>
|
|
14
|
+
<div class="mf-field"><label class="mf-lbl">Reward</label><input class="mf-inp" placeholder="Reward..." /></div>
|
|
15
|
+
<div class="mf-field"><label class="mf-lbl">Difficulty</label><input class="mf-inp" placeholder="Difficulty..." /></div>
|
|
16
|
+
<div class="mf-field"><label class="mf-lbl">Required Level</label><input class="mf-inp" placeholder="Required Level..." /></div>
|
|
17
|
+
<div class="mf-field"><label class="mf-lbl">Location</label><input class="mf-inp" placeholder="Location..." /></div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="mf-footer">
|
|
20
|
+
<button class="mf-save" (click)="save()">Save</button>
|
|
21
|
+
<button class="mf-cancel" (click)="close.emit()">Cancel</button>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
`,
|
|
25
|
+
styles: [`
|
|
26
|
+
.mf-shell{display:flex;flex-direction:column;gap:18px;padding:20px}
|
|
27
|
+
.mf-header{display:flex;align-items:center;gap:10px}
|
|
28
|
+
.mf-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
29
|
+
.mf-body{display:flex;flex-direction:column;gap:12px}
|
|
30
|
+
.mf-field{display:flex;flex-direction:column;gap:5px}
|
|
31
|
+
.mf-lbl{font-size:11px;font-weight:700;letter-spacing:.07em;color:#7a9bbf;text-transform:uppercase}
|
|
32
|
+
.mf-inp{background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.25);border-radius:8px;color:#fff;font-size:13px;padding:10px 14px;outline:none}
|
|
33
|
+
.mf-inp:focus{border-color:rgba(0,200,255,.6)}
|
|
34
|
+
.mf-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
35
|
+
.mf-save{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;padding:10px 22px;cursor:pointer}
|
|
36
|
+
.mf-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:10px 18px;cursor:pointer}
|
|
37
|
+
`]
|
|
38
|
+
})
|
|
39
|
+
export class ManageQuestComponent {
|
|
40
|
+
@Input() show = false;
|
|
41
|
+
@Output() close = new EventEmitter<void>();
|
|
42
|
+
save() { this.close.emit(); }
|
|
43
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
interface Quest { id: string; title: string; description: string; reward: number; difficulty: 'Easy' | 'Medium' | 'Hard' | 'Legendary'; accepted: boolean; completed: boolean }
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'oasis-quest',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule],
|
|
10
|
+
template: `
|
|
11
|
+
<div class="qst-shell">
|
|
12
|
+
<div class="qst-header"><h2 class="qst-title">⚔️ Quests</h2><p class="qst-sub">Embark on quests to gain karma and rare rewards.</p></div>
|
|
13
|
+
<div class="qst-list">
|
|
14
|
+
@for (q of quests(); track q.id) {
|
|
15
|
+
<div class="qst-card" [class.qst-card--active]="q.accepted && !q.completed" [class.qst-card--done]="q.completed">
|
|
16
|
+
<div class="qst-diff qst-diff--{{ q.difficulty.toLowerCase() }}">{{ q.difficulty }}</div>
|
|
17
|
+
<div class="qst-body">
|
|
18
|
+
<div class="qst-title-text">{{ q.title }}</div>
|
|
19
|
+
<div class="qst-desc">{{ q.description }}</div>
|
|
20
|
+
<div class="qst-reward">+{{ q.reward }} karma</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="qst-actions">
|
|
23
|
+
@if (q.completed) { <div class="qst-done">✅ Done</div> }
|
|
24
|
+
@else if (!q.accepted) { <button class="qst-btn" (click)="accept(q)">Accept Quest</button> }
|
|
25
|
+
@else { <button class="qst-btn qst-btn--finish" (click)="complete(q)">Finish</button> }
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
`,
|
|
32
|
+
styles: [`
|
|
33
|
+
.qst-shell{display:flex;flex-direction:column;gap:18px}
|
|
34
|
+
.qst-header{text-align:center}
|
|
35
|
+
.qst-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}
|
|
36
|
+
.qst-sub{font-size:13px;color:#7a9bbf;margin:0}
|
|
37
|
+
.qst-list{display:flex;flex-direction:column;gap:12px}
|
|
38
|
+
.qst-card{display:flex;gap:14px;align-items:flex-start;background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:12px;padding:16px;transition:border-color .2s}
|
|
39
|
+
.qst-card--active{border-color:rgba(0,200,255,.4)}
|
|
40
|
+
.qst-card--done{opacity:.6;border-color:rgba(72,220,130,.2)}
|
|
41
|
+
.qst-diff{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;border-radius:999px;padding:4px 10px;border:1px solid currentColor;white-space:nowrap;flex-shrink:0}
|
|
42
|
+
.qst-diff--easy{color:#48dc82;border-color:rgba(72,220,130,.3)}
|
|
43
|
+
.qst-diff--medium{color:#ffb43c;border-color:rgba(255,180,60,.3)}
|
|
44
|
+
.qst-diff--hard{color:#ff6b6b;border-color:rgba(255,107,107,.3)}
|
|
45
|
+
.qst-diff--legendary{color:#b87fff;border-color:rgba(184,127,255,.3)}
|
|
46
|
+
.qst-body{flex:1}
|
|
47
|
+
.qst-title-text{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff;margin-bottom:4px}
|
|
48
|
+
.qst-desc{font-size:12px;color:#7a9bbf;line-height:1.5;margin-bottom:6px}
|
|
49
|
+
.qst-reward{font-size:12px;color:#48dc82;font-weight:600}
|
|
50
|
+
.qst-actions{flex-shrink:0}
|
|
51
|
+
.qst-btn{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:7px;color:#fff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;letter-spacing:.08em;padding:8px 16px;cursor:pointer;white-space:nowrap}
|
|
52
|
+
.qst-btn--finish{background:linear-gradient(135deg,#48dc82,#00aa55)}
|
|
53
|
+
.qst-done{font-size:13px;color:#48dc82;font-weight:600}
|
|
54
|
+
`]
|
|
55
|
+
})
|
|
56
|
+
export class QuestComponent {
|
|
57
|
+
quests = signal<Quest[]>([
|
|
58
|
+
{ id: '1', title: 'Avatar Awakening', description: 'Complete your avatar profile and connect your first provider.', reward: 200, difficulty: 'Easy', accepted: true, completed: true },
|
|
59
|
+
{ id: '2', title: 'Karma Seeker', description: 'Earn 1000 karma through good deeds and OASIS contributions.', reward: 500, difficulty: 'Medium', accepted: true, completed: false },
|
|
60
|
+
{ id: '3', title: 'The NFT Collector', description: 'Acquire 5 unique NFTs across different categories.', reward: 1000, difficulty: 'Hard', accepted: false, completed: false },
|
|
61
|
+
{ id: '4', title: 'Omniverse Explorer', description: 'Visit every major hub location on the OASIS map.', reward: 2500, difficulty: 'Legendary', accepted: false, completed: false },
|
|
62
|
+
]);
|
|
63
|
+
accept(q: Quest) { this.quests.update(l => l.map(x => x.id === q.id ? { ...x, accepted: true } : x)); }
|
|
64
|
+
complete(q: Quest) { this.quests.update(l => l.map(x => x.id === q.id ? { ...x, completed: true } : x)); }
|
|
65
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'oasis-search-quest',
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [CommonModule, FormsModule],
|
|
9
|
+
template: `
|
|
10
|
+
<div class="sf-shell">
|
|
11
|
+
<div class="sf-header"><span>🔍</span><h2 class="sf-title">Search Quests</h2></div>
|
|
12
|
+
<div class="sf-row"><input class="sf-input" [(ngModel)]="query" placeholder="Search quests by name, difficulty, or reward..." (keyup.enter)="search()" /><button class="sf-btn" (click)="search()">Search</button></div>
|
|
13
|
+
@for (r of results(); track r) { <div class="sf-result">{{ r }}</div> }
|
|
14
|
+
<div class="sf-footer"><button class="sf-cancel" (click)="close.emit()">Close</button></div>
|
|
15
|
+
</div>
|
|
16
|
+
`,
|
|
17
|
+
styles: [`
|
|
18
|
+
.sf-shell{display:flex;flex-direction:column;gap:14px;padding:20px}
|
|
19
|
+
.sf-header{display:flex;align-items:center;gap:10px}
|
|
20
|
+
.sf-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
21
|
+
.sf-row{display:flex;gap:10px}
|
|
22
|
+
.sf-input{flex:1;background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.25);border-radius:8px;color:#fff;font-size:13px;padding:10px 14px;outline:none}
|
|
23
|
+
.sf-input:focus{border-color:rgba(0,200,255,.6)}
|
|
24
|
+
.sf-btn{background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;padding:10px 20px;cursor:pointer;white-space:nowrap}
|
|
25
|
+
.sf-result{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:8px;color:#c8dff0;font-size:13px;padding:10px 14px}
|
|
26
|
+
.sf-footer{display:flex;justify-content:flex-end}
|
|
27
|
+
.sf-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;padding:8px 20px;cursor:pointer}
|
|
28
|
+
`]
|
|
29
|
+
})
|
|
30
|
+
export class SearchQuestComponent {
|
|
31
|
+
@Input() show = false;
|
|
32
|
+
@Output() close = new EventEmitter<void>();
|
|
33
|
+
query = '';
|
|
34
|
+
results = signal<string[]>([]);
|
|
35
|
+
search() { if (this.query.trim()) this.results.set(['No results found for "' + this.query + '"']); }
|
|
36
|
+
}
|