@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,43 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-manage-mission',
|
|
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 Mission</h2></div>
|
|
11
|
+
<div class="mf-body">
|
|
12
|
+
<div class="mf-field"><label class="mf-lbl">Mission Name</label><input class="mf-inp" placeholder="Mission 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">Start Date</label><input class="mf-inp" placeholder="Start Date..." /></div>
|
|
17
|
+
<div class="mf-field"><label class="mf-lbl">End Date</label><input class="mf-inp" placeholder="End Date..." /></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 ManageMissionComponent {
|
|
40
|
+
@Input() show = false;
|
|
41
|
+
@Output() close = new EventEmitter<void>();
|
|
42
|
+
save() { this.close.emit(); }
|
|
43
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
interface Mission { id: string; title: string; description: string; reward: number; status: 'available' | 'active' | 'complete' }
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'oasis-mission',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule],
|
|
10
|
+
template: `
|
|
11
|
+
<div class="mis-shell">
|
|
12
|
+
<div class="mis-header"><h2 class="mis-title">🎯 Missions</h2><p class="mis-sub">Complete missions to earn karma and unlock rewards.</p></div>
|
|
13
|
+
<div class="mis-list">
|
|
14
|
+
@for (m of missions(); track m.id) {
|
|
15
|
+
<div class="mis-card mis-card--{{ m.status }}">
|
|
16
|
+
<div class="mis-left">
|
|
17
|
+
<div class="mis-title-text">{{ m.title }}</div>
|
|
18
|
+
<div class="mis-desc">{{ m.description }}</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="mis-right">
|
|
21
|
+
<div class="mis-reward">+{{ m.reward }} karma</div>
|
|
22
|
+
<div class="mis-status-badge mis-status-badge--{{ m.status }}">{{ statusLabel(m.status) }}</div>
|
|
23
|
+
@if (m.status === 'available') { <button class="mis-btn" (click)="accept(m)">Accept</button> }
|
|
24
|
+
@if (m.status === 'active') { <button class="mis-btn mis-btn--complete" (click)="complete(m)">Complete</button> }
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
`,
|
|
31
|
+
styles: [`
|
|
32
|
+
.mis-shell{display:flex;flex-direction:column;gap:18px}
|
|
33
|
+
.mis-header{text-align:center}
|
|
34
|
+
.mis-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}
|
|
35
|
+
.mis-sub{font-size:13px;color:#7a9bbf;margin:0}
|
|
36
|
+
.mis-list{display:flex;flex-direction:column;gap:12px}
|
|
37
|
+
.mis-card{display:flex;align-items:center;gap:16px;background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:12px;padding:16px}
|
|
38
|
+
.mis-card--active{border-color:rgba(0,200,255,.35);background:rgba(0,200,255,.05)}
|
|
39
|
+
.mis-card--complete{border-color:rgba(72,220,130,.25);background:rgba(72,220,130,.04);opacity:.7}
|
|
40
|
+
.mis-left{flex:1}
|
|
41
|
+
.mis-title-text{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff;margin-bottom:4px}
|
|
42
|
+
.mis-desc{font-size:12px;color:#7a9bbf;line-height:1.5}
|
|
43
|
+
.mis-right{display:flex;flex-direction:column;align-items:flex-end;gap:8px;flex-shrink:0}
|
|
44
|
+
.mis-reward{font-size:12px;color:#48dc82;font-weight:600;white-space:nowrap}
|
|
45
|
+
.mis-status-badge{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;border-radius:999px;padding:3px 10px;border:1px solid currentColor}
|
|
46
|
+
.mis-status-badge--available{color:#7a9bbf;border-color:rgba(122,155,191,.3)}
|
|
47
|
+
.mis-status-badge--active{color:#00c8ff;border-color:rgba(0,200,255,.35)}
|
|
48
|
+
.mis-status-badge--complete{color:#48dc82;border-color:rgba(72,220,130,.3)}
|
|
49
|
+
.mis-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:7px 16px;cursor:pointer;transition:opacity .2s;white-space:nowrap}
|
|
50
|
+
.mis-btn--complete{background:linear-gradient(135deg,#48dc82,#00aa55)}
|
|
51
|
+
`]
|
|
52
|
+
})
|
|
53
|
+
export class MissionComponent {
|
|
54
|
+
missions = signal<Mission[]>([
|
|
55
|
+
{ id: '1', title: 'First Contact', description: 'Log into OASIS for the first time and explore the hub.', reward: 100, status: 'complete' },
|
|
56
|
+
{ id: '2', title: 'Karma Cultivator', description: 'Earn 500 karma through positive actions in the OASIS.', reward: 250, status: 'active' },
|
|
57
|
+
{ id: '3', title: 'NFT Hunter', description: 'Acquire your first rare NFT from the marketplace.', reward: 400, status: 'available' },
|
|
58
|
+
{ id: '4', title: 'Seed Planter', description: 'Plant 3 seeds and nurture them to full growth.', reward: 150, status: 'available' },
|
|
59
|
+
]);
|
|
60
|
+
statusLabel(s: string) { return s === 'available' ? 'Available' : s === 'active' ? 'In Progress' : 'Complete'; }
|
|
61
|
+
accept(m: Mission) { this.missions.update(l => l.map(x => x.id === m.id ? { ...x, status: 'active' } : x)); }
|
|
62
|
+
complete(m: Mission) { this.missions.update(l => l.map(x => x.id === m.id ? { ...x, status: 'complete' } : x)); }
|
|
63
|
+
}
|
|
@@ -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-mission',
|
|
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 Missions</h2></div>
|
|
12
|
+
<div class="sf-row"><input class="sf-input" [(ngModel)]="query" placeholder="Search missions by 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 SearchMissionComponent {
|
|
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,49 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-view-mission',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="vm-shell">
|
|
10
|
+
<div class="vm-header"><span>🎯</span><h2 class="vm-title">View Missions</h2></div>
|
|
11
|
+
<div class="vm-list">
|
|
12
|
+
@for (m of missions(); track m.id) {
|
|
13
|
+
<div class="vm-card">
|
|
14
|
+
<div class="vm-status vm-status--{{ m.status.toLowerCase() }}">{{ m.status }}</div>
|
|
15
|
+
<div class="vm-name">{{ m.name }}</div>
|
|
16
|
+
<div class="vm-desc">{{ m.description }}</div>
|
|
17
|
+
<div class="vm-meta"><span>Difficulty: {{ m.difficulty }}</span><span>Reward: {{ m.reward }}</span></div>
|
|
18
|
+
</div>
|
|
19
|
+
}
|
|
20
|
+
</div>
|
|
21
|
+
<div class="vm-footer"><button class="vm-btn" (click)="close.emit()">Close</button></div>
|
|
22
|
+
</div>
|
|
23
|
+
`,
|
|
24
|
+
styles: [`
|
|
25
|
+
.vm-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
26
|
+
.vm-header{display:flex;align-items:center;gap:10px}
|
|
27
|
+
.vm-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
28
|
+
.vm-list{display:flex;flex-direction:column;gap:10px}
|
|
29
|
+
.vm-card{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:10px;padding:14px 16px;display:flex;flex-direction:column;gap:8px}
|
|
30
|
+
.vm-status{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;border-radius:999px;padding:2px 10px;align-self:flex-start;border:1px solid currentColor}
|
|
31
|
+
.vm-status--active{color:#00c864;border-color:rgba(0,200,100,.3)}
|
|
32
|
+
.vm-status--completed{color:#5ba8ff;border-color:rgba(91,168,255,.3)}
|
|
33
|
+
.vm-status--upcoming{color:#ffb43c;border-color:rgba(255,180,60,.3)}
|
|
34
|
+
.vm-name{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff}
|
|
35
|
+
.vm-desc{font-size:12px;color:#a8bfd8;line-height:1.5}
|
|
36
|
+
.vm-meta{display:flex;gap:16px;font-size:11px;color:#7a9bbf}
|
|
37
|
+
.vm-footer{display:flex;justify-content:flex-end}
|
|
38
|
+
.vm-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}
|
|
39
|
+
`]
|
|
40
|
+
})
|
|
41
|
+
export class ViewMissionComponent {
|
|
42
|
+
@Input() show = false;
|
|
43
|
+
@Output() close = new EventEmitter<void>();
|
|
44
|
+
missions = signal([
|
|
45
|
+
{ id:1, name:'The Great Convergence', description:'Unite the three factions of the OASIS under one banner.', difficulty:'Hard', reward:'500 SEEDS', status:'Active' },
|
|
46
|
+
{ id:2, name:'Data Recovery', description:'Recover lost data fragments scattered across the OASIS.', difficulty:'Medium', reward:'200 SEEDS', status:'Upcoming' },
|
|
47
|
+
{ id:3, name:'First Contact', description:'Complete the introductory mission sequence.', difficulty:'Easy', reward:'50 SEEDS', status:'Completed' },
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-modal',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
@if (open) {
|
|
10
|
+
<div class="modal-backdrop" (click)="close.emit()">
|
|
11
|
+
<div class="modal-box" [style.border-color]="accentColor" (click)="$event.stopPropagation()">
|
|
12
|
+
<button class="modal-close" (click)="close.emit()">✕</button>
|
|
13
|
+
<ng-content />
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
}
|
|
17
|
+
`,
|
|
18
|
+
styles: [`
|
|
19
|
+
.modal-backdrop { position: fixed; inset: 0; z-index: 9000; background: rgba(3,7,20,.85); backdrop-filter: blur(8px); display: flex; align-items: center; justify-content: center; padding: 20px; }
|
|
20
|
+
.modal-box { background: #0a1535; border: 1px solid rgba(232,121,249,.25); border-radius: 20px; padding: 40px 36px; max-width: 520px; width: 100%; position: relative; max-height: 90vh; overflow-y: auto; }
|
|
21
|
+
.modal-close { position: absolute; top: 16px; right: 18px; background: none; border: none; color: #a8bfd8; font-size: 20px; cursor: pointer; line-height: 1; }
|
|
22
|
+
`]
|
|
23
|
+
})
|
|
24
|
+
export class ModalComponent {
|
|
25
|
+
@Input() open = false;
|
|
26
|
+
@Input() accentColor = 'rgba(232,121,249,.25)';
|
|
27
|
+
@Output() close = new EventEmitter<void>();
|
|
28
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { AvatarConnectComponent } from '../avatar-connect/avatar-connect.component';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'oasis-navbar',
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [CommonModule, AvatarConnectComponent],
|
|
9
|
+
template: `
|
|
10
|
+
<nav class="nav" [class.scrolled]="scrolled()">
|
|
11
|
+
<a class="nav-brand" href="#">
|
|
12
|
+
<span class="brand-icon">✦</span>
|
|
13
|
+
<span>GLOBAL <em>HEALING</em> NETWORK</span>
|
|
14
|
+
</a>
|
|
15
|
+
<button class="nav-toggle" [class.open]="menuOpen()" (click)="toggleMenu()" aria-label="Menu">
|
|
16
|
+
<span></span><span></span><span></span>
|
|
17
|
+
</button>
|
|
18
|
+
<ul class="nav-links" [class.open]="menuOpen()">
|
|
19
|
+
<li><a href="#mission" (click)="menuOpen.set(false)">Mission</a></li>
|
|
20
|
+
<li><a href="#pillars" (click)="menuOpen.set(false)">Pillars</a></li>
|
|
21
|
+
<li><a href="#live-beams" (click)="menuOpen.set(false)">Live Beams</a></li>
|
|
22
|
+
<li><a href="#submit-beam" (click)="menuOpen.set(false)">Submit Beam</a></li>
|
|
23
|
+
<li><a href="#groups" (click)="menuOpen.set(false)">Groups</a></li>
|
|
24
|
+
<li><a href="#archive" (click)="menuOpen.set(false)">Archive</a></li>
|
|
25
|
+
<li><a href="#forum" (click)="menuOpen.set(false)">Forum</a></li>
|
|
26
|
+
<li><a href="#healers" (click)="menuOpen.set(false)">Healers</a></li>
|
|
27
|
+
<li><a href="#map" (click)="menuOpen.set(false)">Map</a></li>
|
|
28
|
+
<li><a href="#ecosystem" (click)="menuOpen.set(false)">Ecosystem</a></li>
|
|
29
|
+
</ul>
|
|
30
|
+
<div class="nav-right">
|
|
31
|
+
<oasis-avatar-connect />
|
|
32
|
+
</div>
|
|
33
|
+
</nav>
|
|
34
|
+
`,
|
|
35
|
+
styles: [`
|
|
36
|
+
.nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; padding: 18px 40px; display: flex; align-items: center; justify-content: space-between; background: rgba(3,7,20,.88); backdrop-filter: blur(12px); border-bottom: 1px solid rgba(232,121,249,.1); transition: padding .3s; }
|
|
37
|
+
.nav.scrolled { padding: 12px 40px; }
|
|
38
|
+
.nav-brand { font-family: 'Orbitron', sans-serif; font-size: 11px; font-weight: 700; letter-spacing: .18em; color: #fff; text-decoration: none; display: flex; align-items: center; gap: 10px; white-space: nowrap; }
|
|
39
|
+
.nav-brand .brand-icon { color: #e879f9; font-size: 16px; }
|
|
40
|
+
.nav-brand em { color: #e879f9; font-style: normal; }
|
|
41
|
+
.nav-links { display: flex; gap: 16px; list-style: none; margin: 0; padding: 0; }
|
|
42
|
+
.nav-links a { font-family: 'Share Tech Mono', monospace; font-size: 11px; letter-spacing: .08em; color: #a8bfd8; text-decoration: none; transition: color .2s; text-transform: uppercase; }
|
|
43
|
+
.nav-links a:hover { color: #e879f9; }
|
|
44
|
+
.nav-right { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
|
|
45
|
+
.nav-toggle { display: none; flex-direction: column; justify-content: center; gap: 5px; width: 32px; height: 32px; background: none; border: none; cursor: pointer; }
|
|
46
|
+
.nav-toggle span { display: block; width: 100%; height: 2px; background: #a8bfd8; transition: transform .25s, opacity .25s; }
|
|
47
|
+
.nav-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
|
|
48
|
+
.nav-toggle.open span:nth-child(2) { opacity: 0; }
|
|
49
|
+
.nav-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
|
|
50
|
+
@media (max-width: 1100px) {
|
|
51
|
+
.nav-toggle { display: flex; }
|
|
52
|
+
.nav-links { position: fixed; top: 0; right: 0; height: 100vh; width: min(78vw,320px); flex-direction: column; justify-content: flex-start; align-items: flex-start; gap: 14px; padding: 76px 32px 24px; overflow-y: auto; background: rgba(3,7,20,.97); backdrop-filter: blur(12px); border-left: 1px solid rgba(232,121,249,.12); transform: translateX(100%); transition: transform .3s ease; }
|
|
53
|
+
.nav-links.open { transform: translateX(0); }
|
|
54
|
+
.nav { padding: 14px 20px; }
|
|
55
|
+
}
|
|
56
|
+
`],
|
|
57
|
+
host: { '(window:scroll)': 'onScroll()' }
|
|
58
|
+
})
|
|
59
|
+
export class NavbarComponent {
|
|
60
|
+
menuOpen = signal(false);
|
|
61
|
+
scrolled = signal(false);
|
|
62
|
+
toggleMenu() { this.menuOpen.set(!this.menuOpen()); }
|
|
63
|
+
onScroll() { this.scrolled.set(window.scrollY > 40); }
|
|
64
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-nft-contact-popup',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="mf-shell">
|
|
10
|
+
<div class="mf-header"><span>📧</span><h2 class="mf-title">Contact NFT Creator</h2></div>
|
|
11
|
+
<div class="mf-body">
|
|
12
|
+
<div class="mf-field"><label class="mf-lbl">Your Name</label><input class="mf-inp" placeholder="Your Name..." /></div>
|
|
13
|
+
<div class="mf-field"><label class="mf-lbl">Email Address</label><input class="mf-inp" placeholder="Email Address..." /></div>
|
|
14
|
+
<div class="mf-field"><label class="mf-lbl">Message</label><input class="mf-inp" placeholder="Message..." /></div>
|
|
15
|
+
<div class="mf-field"><label class="mf-lbl">NFT Reference</label><input class="mf-inp" placeholder="NFT Reference..." /></div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="mf-footer">
|
|
18
|
+
<button class="mf-save" (click)="save()">Save</button>
|
|
19
|
+
<button class="mf-cancel" (click)="close.emit()">Cancel</button>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
`,
|
|
23
|
+
styles: [`
|
|
24
|
+
.mf-shell{display:flex;flex-direction:column;gap:18px;padding:20px}
|
|
25
|
+
.mf-header{display:flex;align-items:center;gap:10px}
|
|
26
|
+
.mf-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
27
|
+
.mf-body{display:flex;flex-direction:column;gap:12px}
|
|
28
|
+
.mf-field{display:flex;flex-direction:column;gap:5px}
|
|
29
|
+
.mf-lbl{font-size:11px;font-weight:700;letter-spacing:.07em;color:#7a9bbf;text-transform:uppercase}
|
|
30
|
+
.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}
|
|
31
|
+
.mf-inp:focus{border-color:rgba(0,200,255,.6)}
|
|
32
|
+
.mf-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
33
|
+
.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}
|
|
34
|
+
.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}
|
|
35
|
+
`]
|
|
36
|
+
})
|
|
37
|
+
export class NftContactPopupComponent {
|
|
38
|
+
@Input() show = false;
|
|
39
|
+
@Output() close = new EventEmitter<void>();
|
|
40
|
+
save() { this.close.emit(); }
|
|
41
|
+
}
|
|
@@ -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-oasis-nft',
|
|
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 OASIS NFT</h2></div>
|
|
11
|
+
<div class="mf-body">
|
|
12
|
+
<div class="mf-field"><label class="mf-lbl">NFT Name</label><input class="mf-inp" placeholder="NFT 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">Price</label><input class="mf-inp" placeholder="Price..." /></div>
|
|
15
|
+
<div class="mf-field"><label class="mf-lbl">Royalty %</label><input class="mf-inp" placeholder="Royalty %..." /></div>
|
|
16
|
+
<div class="mf-field"><label class="mf-lbl">Collection</label><input class="mf-inp" placeholder="Collection..." /></div>
|
|
17
|
+
<div class="mf-field"><label class="mf-lbl">Blockchain</label><input class="mf-inp" placeholder="Blockchain..." /></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 ManageOasisNftComponent {
|
|
40
|
+
@Input() show = false;
|
|
41
|
+
@Output() close = new EventEmitter<void>();
|
|
42
|
+
save() { this.close.emit(); }
|
|
43
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
interface NFT { id: string; name: string; rarity: string; type: string; karma: number; image: string }
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'oasis-nft',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule],
|
|
10
|
+
template: `
|
|
11
|
+
<div class="nft-shell">
|
|
12
|
+
<div class="nft-header"><h2 class="nft-title">🖼️ NFTs</h2><p class="nft-sub">Your OASIS non-fungible token collection.</p></div>
|
|
13
|
+
<div class="nft-tabs">
|
|
14
|
+
@for (t of tabs; track t) {
|
|
15
|
+
<button class="nft-tab" [class.nft-tab--active]="activeTab() === t" (click)="activeTab.set(t)">{{ t }}</button>
|
|
16
|
+
}
|
|
17
|
+
</div>
|
|
18
|
+
<div class="nft-grid">
|
|
19
|
+
@for (n of filtered(); track n.id) {
|
|
20
|
+
<div class="nft-card">
|
|
21
|
+
<div class="nft-img">{{ n.image }}</div>
|
|
22
|
+
<div class="nft-rarity nft-rarity--{{ n.rarity.toLowerCase() }}">{{ n.rarity }}</div>
|
|
23
|
+
<div class="nft-name">{{ n.name }}</div>
|
|
24
|
+
<div class="nft-type">{{ n.type }}</div>
|
|
25
|
+
<div class="nft-karma">+{{ n.karma }} karma</div>
|
|
26
|
+
</div>
|
|
27
|
+
}
|
|
28
|
+
@if (filtered().length === 0) { <div class="nft-empty">No NFTs in this category.</div> }
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
`,
|
|
32
|
+
styles: [`
|
|
33
|
+
.nft-shell{display:flex;flex-direction:column;gap:18px}
|
|
34
|
+
.nft-header{text-align:center}
|
|
35
|
+
.nft-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}
|
|
36
|
+
.nft-sub{font-size:13px;color:#7a9bbf;margin:0}
|
|
37
|
+
.nft-tabs{display:flex;gap:8px;flex-wrap:wrap}
|
|
38
|
+
.nft-tab{background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.2);border-radius:8px;color:#7a9bbf;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;letter-spacing:.06em;padding:7px 16px;cursor:pointer;transition:all .2s}
|
|
39
|
+
.nft-tab--active{background:rgba(0,200,255,.15);border-color:#00c8ff;color:#00c8ff}
|
|
40
|
+
.nft-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:14px}
|
|
41
|
+
.nft-card{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:12px;padding:14px;display:flex;flex-direction:column;align-items:center;gap:8px;transition:border-color .2s}
|
|
42
|
+
.nft-card:hover{border-color:rgba(0,200,255,.35)}
|
|
43
|
+
.nft-img{font-size:44px}
|
|
44
|
+
.nft-rarity{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;border-radius:999px;padding:3px 10px;border:1px solid currentColor}
|
|
45
|
+
.nft-rarity--common{color:#7a9bbf;border-color:rgba(122,155,191,.3)}
|
|
46
|
+
.nft-rarity--rare{color:#5ba8ff;border-color:rgba(91,168,255,.3)}
|
|
47
|
+
.nft-rarity--epic{color:#b87fff;border-color:rgba(184,127,255,.3)}
|
|
48
|
+
.nft-rarity--legendary{color:#ffb43c;border-color:rgba(255,180,60,.3)}
|
|
49
|
+
.nft-name{font-family:'Orbitron',sans-serif;font-size:12px;color:#fff;text-align:center}
|
|
50
|
+
.nft-type{font-size:11px;color:#7a9bbf}
|
|
51
|
+
.nft-karma{font-size:12px;color:#48dc82;font-weight:600}
|
|
52
|
+
.nft-empty{grid-column:1/-1;text-align:center;color:#4a6a88;padding:32px;font-size:14px}
|
|
53
|
+
`]
|
|
54
|
+
})
|
|
55
|
+
export class NftComponent {
|
|
56
|
+
tabs = ['All', 'Avatar', 'Land', 'Item', 'Art'];
|
|
57
|
+
activeTab = signal('All');
|
|
58
|
+
nfts = signal<NFT[]>([
|
|
59
|
+
{ id: '1', name: 'Cosmic Warrior', rarity: 'Legendary', type: 'Avatar', karma: 500, image: '⚔️' },
|
|
60
|
+
{ id: '2', name: 'Forest Realm', rarity: 'Epic', type: 'Land', karma: 250, image: '🌲' },
|
|
61
|
+
{ id: '3', name: 'Quantum Blade', rarity: 'Rare', type: 'Item', karma: 100, image: '🗡️' },
|
|
62
|
+
{ id: '4', name: 'Nebula Portrait', rarity: 'Common', type: 'Art', karma: 30, image: '🎨' },
|
|
63
|
+
{ id: '5', name: 'Light Keeper', rarity: 'Epic', type: 'Avatar', karma: 200, image: '🌟' },
|
|
64
|
+
{ id: '6', name: 'Sky Citadel', rarity: 'Rare', type: 'Land', karma: 120, image: '🏰' },
|
|
65
|
+
]);
|
|
66
|
+
filtered() {
|
|
67
|
+
const t = this.activeTab();
|
|
68
|
+
return t === 'All' ? this.nfts() : this.nfts().filter(n => n.type === t);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, signal } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-purchase-oasis-nft',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="pn-shell">
|
|
10
|
+
<div class="pn-header"><span>🛒</span><h2 class="pn-title">Purchase OASIS NFT</h2></div>
|
|
11
|
+
<div class="pn-list">
|
|
12
|
+
@for (nft of nfts(); track nft.id) {
|
|
13
|
+
<div class="pn-card" (click)="selected.set(nft.id)" [class.pn-card--sel]="selected()===nft.id">
|
|
14
|
+
<div class="pn-emoji">{{ nft.emoji }}</div>
|
|
15
|
+
<div class="pn-info"><div class="pn-name">{{ nft.name }}</div><div class="pn-price">{{ nft.price }}</div></div>
|
|
16
|
+
</div>
|
|
17
|
+
}
|
|
18
|
+
</div>
|
|
19
|
+
<div class="pn-footer">
|
|
20
|
+
<button class="pn-buy" [disabled]="!selected()" (click)="buy()">Purchase</button>
|
|
21
|
+
<button class="pn-cancel" (click)="close.emit()">Cancel</button>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
`,
|
|
25
|
+
styles: [`
|
|
26
|
+
.pn-shell{display:flex;flex-direction:column;gap:16px;padding:20px}
|
|
27
|
+
.pn-header{display:flex;align-items:center;gap:10px}
|
|
28
|
+
.pn-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
29
|
+
.pn-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px}
|
|
30
|
+
.pn-card{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:10px;padding:14px;display:flex;align-items:center;gap:10px;cursor:pointer;transition:border-color .2s}
|
|
31
|
+
.pn-card:hover{border-color:rgba(0,200,255,.3)}
|
|
32
|
+
.pn-card--sel{border-color:#00c8ff;background:rgba(0,200,255,.08)}
|
|
33
|
+
.pn-emoji{font-size:28px}
|
|
34
|
+
.pn-name{font-family:'Orbitron',sans-serif;font-size:12px;color:#fff}
|
|
35
|
+
.pn-price{font-size:12px;color:#ffb43c;font-weight:700;margin-top:2px}
|
|
36
|
+
.pn-footer{display:flex;gap:10px;justify-content:flex-end}
|
|
37
|
+
.pn-buy{background:linear-gradient(135deg,#ffb43c,#ff8c00);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;padding:10px 22px;cursor:pointer}
|
|
38
|
+
.pn-buy:disabled{opacity:.4;cursor:not-allowed}
|
|
39
|
+
.pn-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}
|
|
40
|
+
`]
|
|
41
|
+
})
|
|
42
|
+
export class PurchaseOasisNftComponent {
|
|
43
|
+
@Input() show = false;
|
|
44
|
+
@Output() close = new EventEmitter<void>();
|
|
45
|
+
selected = signal<number|null>(null);
|
|
46
|
+
nfts = signal([
|
|
47
|
+
{ id:1, emoji:'🏛️', name:'OASIS Hub Alpha', price:'0.05 ETH' },
|
|
48
|
+
{ id:2, emoji:'🌌', name:'Cosmic Artifact', price:'0.12 ETH' },
|
|
49
|
+
{ id:3, emoji:'🐉', name:'Dragon Companion', price:'0.25 ETH' },
|
|
50
|
+
{ id:4, emoji:'💎', name:'Crystal Gem', price:'0.08 ETH' },
|
|
51
|
+
]);
|
|
52
|
+
buy() { this.selected.set(null); this.close.emit(); }
|
|
53
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-purchase-oasis-virtual-land-nft',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="popup-shell">
|
|
10
|
+
<div class="popup-icon">🏞️</div>
|
|
11
|
+
<h2 class="popup-title">Purchase Virtual Land NFT</h2>
|
|
12
|
+
<p class="popup-body">UI Coming Soon — access this feature via the OASIS API from the Developer menu.</p>
|
|
13
|
+
<button class="popup-btn" (click)="close.emit()">OK</button>
|
|
14
|
+
</div>
|
|
15
|
+
`,
|
|
16
|
+
styles: [`
|
|
17
|
+
.popup-shell{display:flex;flex-direction:column;align-items:center;gap:16px;padding:24px;text-align:center}
|
|
18
|
+
.popup-icon{font-size:48px}
|
|
19
|
+
.popup-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
20
|
+
.popup-body{font-size:13px;color:#a8bfd8;line-height:1.6;margin:0;max-width:380px}
|
|
21
|
+
.popup-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;letter-spacing:.08em;padding:10px 28px;cursor:pointer;transition:opacity .2s}
|
|
22
|
+
.popup-btn:hover{opacity:.85}
|
|
23
|
+
`]
|
|
24
|
+
})
|
|
25
|
+
export class PurchaseOasisVirtualLandNftComponent {
|
|
26
|
+
@Input() show = false;
|
|
27
|
+
@Output() close = new EventEmitter<void>();
|
|
28
|
+
}
|
|
@@ -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-oasis-nft',
|
|
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 OASIS NFTs</h2></div>
|
|
12
|
+
<div class="sf-row"><input class="sf-input" [(ngModel)]="query" placeholder="Search NFTs by name, collection, or creator..." (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 SearchOasisNftComponent {
|
|
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,28 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'oasis-solana',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="popup-shell">
|
|
10
|
+
<div class="popup-icon">◎</div>
|
|
11
|
+
<h2 class="popup-title">Solana Integration</h2>
|
|
12
|
+
<p class="popup-body">UI Coming Soon — access this feature via the OASIS API from the Developer menu.</p>
|
|
13
|
+
<button class="popup-btn" (click)="close.emit()">OK</button>
|
|
14
|
+
</div>
|
|
15
|
+
`,
|
|
16
|
+
styles: [`
|
|
17
|
+
.popup-shell{display:flex;flex-direction:column;align-items:center;gap:16px;padding:24px;text-align:center}
|
|
18
|
+
.popup-icon{font-size:48px}
|
|
19
|
+
.popup-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}
|
|
20
|
+
.popup-body{font-size:13px;color:#a8bfd8;line-height:1.6;margin:0;max-width:380px}
|
|
21
|
+
.popup-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;letter-spacing:.08em;padding:10px 28px;cursor:pointer;transition:opacity .2s}
|
|
22
|
+
.popup-btn:hover{opacity:.85}
|
|
23
|
+
`]
|
|
24
|
+
})
|
|
25
|
+
export class SolanaComponent {
|
|
26
|
+
@Input() show = false;
|
|
27
|
+
@Output() close = new EventEmitter<void>();
|
|
28
|
+
}
|