@oasisomniverse/svelte 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 +36 -0
- package/src/components/AvatarConnect.svelte +61 -0
- package/src/components/AvatarProfile.svelte +124 -0
- package/src/components/ComingSoon.svelte +13 -0
- package/src/components/Confirmation.svelte +21 -0
- package/src/components/Contact.svelte +38 -0
- package/src/components/Eggs.svelte +40 -0
- package/src/components/ForgotPassword.svelte +67 -0
- package/src/components/Game.svelte +28 -0
- package/src/components/HyperDrive.svelte +42 -0
- package/src/components/KarmaPanel.svelte +74 -0
- package/src/components/KarmaToast.svelte +23 -0
- package/src/components/Login.svelte +88 -0
- package/src/components/Map.svelte +41 -0
- package/src/components/MenuMessage.svelte +59 -0
- package/src/components/Messaging.svelte +41 -0
- package/src/components/Mission.svelte +31 -0
- package/src/components/NFT.svelte +37 -0
- package/src/components/NavBar.svelte +63 -0
- package/src/components/OApp.svelte +36 -0
- package/src/components/ONET.svelte +35 -0
- package/src/components/ONODE.svelte +36 -0
- package/src/components/OasisModal.svelte +35 -0
- package/src/components/ProviderDropdown.svelte +35 -0
- package/src/components/Providers.svelte +29 -0
- package/src/components/Quest.svelte +34 -0
- package/src/components/ResetPassword.svelte +28 -0
- package/src/components/SearchAvatars.svelte +44 -0
- package/src/components/Seeds.svelte +39 -0
- package/src/components/Settings.svelte +59 -0
- package/src/components/Signup.svelte +115 -0
- package/src/components/StarField.svelte +47 -0
- package/src/components/VerifyEmail.svelte +18 -0
- package/src/components/Wallet.svelte +42 -0
- package/src/components/avatar/AvatarWallet.svelte +17 -0
- package/src/components/avatar/EditAvatar.svelte +17 -0
- package/src/components/avatar/SearchAvatar.svelte +17 -0
- package/src/components/avatar/ViewAvatar.svelte +17 -0
- package/src/components/comingsoon/ComingSoon.svelte +17 -0
- package/src/components/confirmation/Confirmation.svelte +17 -0
- package/src/components/contact/Contact.svelte +17 -0
- package/src/components/data-screen/AddData.svelte +17 -0
- package/src/components/data-screen/CrossChainManagement.svelte +17 -0
- package/src/components/data-screen/LoadData.svelte +17 -0
- package/src/components/data-screen/ManageData.svelte +17 -0
- package/src/components/data-screen/OffChainManagement.svelte +17 -0
- package/src/components/data-screen/SearchData.svelte +17 -0
- package/src/components/eggs/ManageEggs.svelte +17 -0
- package/src/components/eggs/SearchEggs.svelte +17 -0
- package/src/components/eggs/ViewEggs.svelte +17 -0
- package/src/components/game/SearchProfiles.svelte +17 -0
- package/src/components/game/ViewAchievements.svelte +17 -0
- package/src/components/game/ViewLeagues.svelte +17 -0
- package/src/components/game/ViewTournaments.svelte +17 -0
- package/src/components/karma/SearchKarma.svelte +17 -0
- package/src/components/karma/ViewAvatarKarma.svelte +17 -0
- package/src/components/karma/ViewKarma.svelte +17 -0
- package/src/components/karma/VoteKarma.svelte +17 -0
- package/src/components/map/Add2dObjectMap.svelte +17 -0
- package/src/components/map/Add3dObjectMap.svelte +17 -0
- package/src/components/map/AddQuestToMap.svelte +17 -0
- package/src/components/map/DownloadOurWorld.svelte +17 -0
- package/src/components/map/ManageMap.svelte +17 -0
- package/src/components/map/PlotRouteOnMap.svelte +17 -0
- package/src/components/map/SearchMap.svelte +17 -0
- package/src/components/map/ViewGlobal3dMap.svelte +17 -0
- package/src/components/map/ViewHalonsOnMap.svelte +17 -0
- package/src/components/map/ViewOappOnMap.svelte +17 -0
- package/src/components/map/ViewQuestOnMap.svelte +17 -0
- package/src/components/messages/Message.svelte +17 -0
- package/src/components/mission/ManageMission.svelte +17 -0
- package/src/components/mission/SearchMission.svelte +17 -0
- package/src/components/mission/ViewMission.svelte +17 -0
- package/src/components/nft/ContactPopup.svelte +17 -0
- package/src/components/nft/ManageOasisNft.svelte +17 -0
- package/src/components/nft/PurchaseOasisNft.svelte +17 -0
- package/src/components/nft/PurchaseOasisVirtualLandNft.svelte +17 -0
- package/src/components/nft/SearchOasisNft.svelte +17 -0
- package/src/components/nft/Solana.svelte +17 -0
- package/src/components/nft/ViewOasisNft.svelte +17 -0
- package/src/components/oapp/CreateOAPP.svelte +17 -0
- package/src/components/oapp/DeployOAPP.svelte +17 -0
- package/src/components/oapp/DownloadOurWorld.svelte +17 -0
- package/src/components/oapp/EditOAPP.svelte +17 -0
- package/src/components/oapp/InstallOAPP.svelte +17 -0
- package/src/components/oapp/LaunchOAPP.svelte +17 -0
- package/src/components/oapp/ManageOAPP.svelte +17 -0
- package/src/components/oapp/SearchOAPP.svelte +17 -0
- package/src/components/provider/ActivityPub.svelte +17 -0
- package/src/components/provider/CompareProviderSpeeds.svelte +17 -0
- package/src/components/provider/Eosio.svelte +17 -0
- package/src/components/provider/Ethereum.svelte +17 -0
- package/src/components/provider/Holochain.svelte +17 -0
- package/src/components/provider/Ipfs.svelte +17 -0
- package/src/components/provider/ManageAutoFailOver.svelte +17 -0
- package/src/components/provider/ManageAutoReplicaton.svelte +17 -0
- package/src/components/provider/ManageLoadBalancing.svelte +17 -0
- package/src/components/provider/ManageProviders.svelte +17 -0
- package/src/components/provider/MongoDb.svelte +17 -0
- package/src/components/provider/Neo4j.svelte +17 -0
- package/src/components/provider/SearchProviders.svelte +17 -0
- package/src/components/provider/Seeds.svelte +17 -0
- package/src/components/provider/Solid.svelte +17 -0
- package/src/components/provider/SqlLite.svelte +17 -0
- package/src/components/provider/ThreeFold.svelte +17 -0
- package/src/components/provider/ViewProviderStats.svelte +17 -0
- package/src/components/provider/ViewProviders.svelte +17 -0
- package/src/components/quest/ManageQuest.svelte +17 -0
- package/src/components/quest/SearchQuest.svelte +17 -0
- package/src/components/quest/ViewQuest.svelte +17 -0
- package/src/components/seeds/AcceptInvite.svelte +17 -0
- package/src/components/seeds/DonateSeeds.svelte +17 -0
- package/src/components/seeds/ManageSeeds.svelte +17 -0
- package/src/components/seeds/PayWithSeeds.svelte +17 -0
- package/src/components/seeds/RewardSeeds.svelte +17 -0
- package/src/components/seeds/SearchSeeds.svelte +17 -0
- package/src/components/seeds/SendInvite.svelte +17 -0
- package/src/components/seeds/ViewOrganizations.svelte +17 -0
- package/src/components/seeds/ViewSeeds.svelte +17 -0
- package/src/index.ts +139 -0
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oasisomniverse/svelte",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OASIS Omniverse Svelte 4 UI components",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"oasis",
|
|
7
|
+
"omniverse",
|
|
8
|
+
"svelte",
|
|
9
|
+
"components"
|
|
10
|
+
],
|
|
11
|
+
"author": "NextGenSoftware",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/NextGenSoftwareUK/OASIS-Svelte-UI-Component-Library.git"
|
|
16
|
+
},
|
|
17
|
+
"main": "src/index.ts",
|
|
18
|
+
"svelte": "src/index.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": "./src/index.ts",
|
|
21
|
+
"./components/*": "./src/components/*.svelte"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"src"
|
|
25
|
+
],
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"svelte": "\u003e=4.0.0",
|
|
28
|
+
"@oasisomniverse/web4-api": "\u003e=2.0.0"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { session, login, logout } from './oasisStore'
|
|
3
|
+
import OasisModal from './OasisModal.svelte'
|
|
4
|
+
|
|
5
|
+
let open = false
|
|
6
|
+
let loading = false
|
|
7
|
+
let error = ''
|
|
8
|
+
let username = ''
|
|
9
|
+
let password = ''
|
|
10
|
+
|
|
11
|
+
async function doLogin() {
|
|
12
|
+
if (!username || !password) { error = 'Please fill in both fields.'; return }
|
|
13
|
+
loading = true; error = ''
|
|
14
|
+
try {
|
|
15
|
+
await login(username, password)
|
|
16
|
+
open = false; username = ''; password = ''
|
|
17
|
+
} catch {
|
|
18
|
+
error = 'Login failed. Please check your credentials.'
|
|
19
|
+
} finally { loading = false }
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
{#if $session}
|
|
24
|
+
<div class="avatar-badge">
|
|
25
|
+
<span class="avatar-icon">⬡</span>
|
|
26
|
+
<span class="avatar-name">{$session.username}</span>
|
|
27
|
+
<span class="karma-pill">{$session.karma.toLocaleString()} ✦</span>
|
|
28
|
+
<button class="logout-btn" on:click={logout}>✕</button>
|
|
29
|
+
</div>
|
|
30
|
+
{:else}
|
|
31
|
+
<button class="connect-btn" on:click={() => open = true}>⬡ CONNECT AVATAR</button>
|
|
32
|
+
{/if}
|
|
33
|
+
|
|
34
|
+
<OasisModal {open} accentColor="rgba(59,130,246,.3)" on:close={() => open = false}>
|
|
35
|
+
<div class="modal-icon">⬡</div>
|
|
36
|
+
<h2 class="modal-title">Connect Your Avatar</h2>
|
|
37
|
+
<p class="modal-sub">Sign in to your OASIS avatar to earn karma across Justice League Academy.</p>
|
|
38
|
+
<input bind:value={username} class="oasis-input" placeholder="Avatar username" />
|
|
39
|
+
<input bind:value={password} class="oasis-input" type="password" placeholder="Password" />
|
|
40
|
+
{#if error}<p class="error-msg">{error}</p>{/if}
|
|
41
|
+
<button class="btn-primary" disabled={loading} on:click={doLogin}>
|
|
42
|
+
{loading ? 'Connecting…' : 'Connect Avatar'}
|
|
43
|
+
</button>
|
|
44
|
+
</OasisModal>
|
|
45
|
+
|
|
46
|
+
<style>
|
|
47
|
+
.connect-btn { background: none; border: 1px solid rgba(59,130,246,.4); border-radius: 999px; padding: 8px 18px; color: #3b82f6; font-family: 'Share Tech Mono', monospace; font-size: 11px; letter-spacing: .1em; cursor: pointer; transition: background .2s; }
|
|
48
|
+
.connect-btn:hover { background: rgba(59,130,246,.08); }
|
|
49
|
+
.avatar-badge { display: flex; align-items: center; gap: 8px; }
|
|
50
|
+
.avatar-icon { color: #3b82f6; font-size: 16px; }
|
|
51
|
+
.avatar-name { font-family: 'Share Tech Mono', monospace; font-size: 12px; color: #fff; letter-spacing: .06em; }
|
|
52
|
+
.karma-pill { background: rgba(59,130,246,.12); border: 1px solid rgba(59,130,246,.3); border-radius: 999px; padding: 2px 10px; font-family: 'Share Tech Mono', monospace; font-size: 11px; color: #3b82f6; }
|
|
53
|
+
.logout-btn { background: none; border: none; color: #a8bfd8; cursor: pointer; font-size: 14px; }
|
|
54
|
+
.modal-icon { font-size: 40px; text-align: center; color: #3b82f6; margin-bottom: 16px; }
|
|
55
|
+
.modal-title { font-family: 'Orbitron', sans-serif; font-size: 20px; font-weight: 700; color: #fff; text-align: center; margin: 0 0 8px; }
|
|
56
|
+
.modal-sub { font-size: 14px; color: #a8bfd8; text-align: center; line-height: 1.6; margin: 0 0 24px; }
|
|
57
|
+
.oasis-input { width: 100%; background: rgba(255,255,255,.05); border: 1px solid rgba(59,130,246,.2); border-radius: 8px; padding: 11px 14px; color: #fff; font-size: 14px; outline: none; box-sizing: border-box; margin-bottom: 12px; display: block; font-family: inherit; }
|
|
58
|
+
.btn-primary { width: 100%; padding: 14px; background: linear-gradient(135deg,#3b82f6,#a855f7); border: none; border-radius: 10px; color: #fff; font-family: 'Orbitron', sans-serif; font-size: 13px; font-weight: 700; letter-spacing: .08em; cursor: pointer; margin-top: 4px; }
|
|
59
|
+
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }
|
|
60
|
+
.error-msg { color: #f87171; font-size: 13px; text-align: center; margin-bottom: 8px; }
|
|
61
|
+
</style>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { session } from './oasisStore'
|
|
3
|
+
|
|
4
|
+
let fields = { title: '', firstName: '', lastName: '', username: $session?.username ?? '', email: '', address: '' }
|
|
5
|
+
let dirty = false
|
|
6
|
+
let saving = false
|
|
7
|
+
let status = ''
|
|
8
|
+
let statusError = false
|
|
9
|
+
|
|
10
|
+
function markDirty() { dirty = true }
|
|
11
|
+
|
|
12
|
+
async function save() {
|
|
13
|
+
saving = true
|
|
14
|
+
status = ''
|
|
15
|
+
try {
|
|
16
|
+
await new Promise(r => setTimeout(r, 600))
|
|
17
|
+
dirty = false
|
|
18
|
+
statusError = false
|
|
19
|
+
status = 'Changes saved.'
|
|
20
|
+
setTimeout(() => { status = '' }, 3000)
|
|
21
|
+
} catch (e: any) {
|
|
22
|
+
statusError = true
|
|
23
|
+
status = e?.message ?? 'Save failed.'
|
|
24
|
+
} finally {
|
|
25
|
+
saving = false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function discard() {
|
|
30
|
+
fields = { title: '', firstName: '', lastName: '', username: $session?.username ?? '', email: '', address: '' }
|
|
31
|
+
dirty = false
|
|
32
|
+
status = ''
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div class="avp-shell">
|
|
37
|
+
{#if !$session}
|
|
38
|
+
<div class="avp-empty">Please <strong>Beam In</strong> to view your avatar.</div>
|
|
39
|
+
{:else}
|
|
40
|
+
<div class="avp-layout">
|
|
41
|
+
<aside class="avp-summary">
|
|
42
|
+
<div class="avp-avatar-img"><span class="avp-avatar-icon">👤</span></div>
|
|
43
|
+
<div class="avp-name">{$session.username}</div>
|
|
44
|
+
<div class="avp-stats">
|
|
45
|
+
<div class="avp-stat">
|
|
46
|
+
<span class="avp-stat-icon">⚡</span>
|
|
47
|
+
<div>
|
|
48
|
+
<div class="avp-stat-value">{$session.karma}</div>
|
|
49
|
+
<div class="avp-stat-label">Karma</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</aside>
|
|
54
|
+
|
|
55
|
+
<div class="avp-fields">
|
|
56
|
+
<div class="avp-section-label">PROFILE</div>
|
|
57
|
+
<div class="avp-field-row">
|
|
58
|
+
<label class="avp-label" for="avp-title">Title</label>
|
|
59
|
+
<input class="avp-input" id="avp-title" type="text" bind:value={fields.title} placeholder="Dr, Mr, Ms…" on:input={markDirty} />
|
|
60
|
+
</div>
|
|
61
|
+
<div class="avp-field-row">
|
|
62
|
+
<label class="avp-label" for="avp-first">First Name</label>
|
|
63
|
+
<input class="avp-input" id="avp-first" type="text" bind:value={fields.firstName} placeholder="First name" on:input={markDirty} />
|
|
64
|
+
</div>
|
|
65
|
+
<div class="avp-field-row">
|
|
66
|
+
<label class="avp-label" for="avp-last">Last Name</label>
|
|
67
|
+
<input class="avp-input" id="avp-last" type="text" bind:value={fields.lastName} placeholder="Last name" on:input={markDirty} />
|
|
68
|
+
</div>
|
|
69
|
+
<div class="avp-field-row">
|
|
70
|
+
<label class="avp-label" for="avp-username">Username</label>
|
|
71
|
+
<input class="avp-input" id="avp-username" type="text" bind:value={fields.username} placeholder="Username" on:input={markDirty} />
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div class="avp-section-label" style="margin-top:18px">CONTACT</div>
|
|
75
|
+
<div class="avp-field-row">
|
|
76
|
+
<label class="avp-label" for="avp-email">Email</label>
|
|
77
|
+
<input class="avp-input" id="avp-email" type="email" bind:value={fields.email} placeholder="name@example.com" on:input={markDirty} />
|
|
78
|
+
</div>
|
|
79
|
+
<div class="avp-field-row">
|
|
80
|
+
<label class="avp-label" for="avp-address">Address</label>
|
|
81
|
+
<input class="avp-input" id="avp-address" type="text" bind:value={fields.address} placeholder="Optional" on:input={markDirty} />
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{#if status}
|
|
85
|
+
<div class="avp-status" class:avp-status--error={statusError}>{status}</div>
|
|
86
|
+
{/if}
|
|
87
|
+
|
|
88
|
+
{#if dirty}
|
|
89
|
+
<div class="avp-actions">
|
|
90
|
+
<button class="avp-btn" on:click={save} disabled={saving}>{saving ? 'Saving…' : 'Save Changes'}</button>
|
|
91
|
+
<button class="avp-btn avp-btn--ghost" on:click={discard}>Discard</button>
|
|
92
|
+
</div>
|
|
93
|
+
{/if}
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
{/if}
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<style>
|
|
100
|
+
.avp-shell { color:#fff; }
|
|
101
|
+
.avp-empty { text-align:center; padding:40px; color:#7a9bbf; font-size:14px; }
|
|
102
|
+
.avp-layout { display:grid; grid-template-columns:180px 1fr; gap:28px; }
|
|
103
|
+
.avp-summary { display:flex; flex-direction:column; align-items:center; gap:14px; }
|
|
104
|
+
.avp-avatar-img { width:88px; height:88px; border-radius:50%; background:rgba(0,200,255,.1); border:2px solid rgba(0,200,255,.3); display:flex; align-items:center; justify-content:center; }
|
|
105
|
+
.avp-avatar-icon { font-size:40px; }
|
|
106
|
+
.avp-name { font-family:'Orbitron',sans-serif; font-size:13px; color:#fff; text-align:center; word-break:break-all; }
|
|
107
|
+
.avp-stats { display:flex; flex-direction:column; gap:8px; width:100%; }
|
|
108
|
+
.avp-stat { display:flex; align-items:center; gap:8px; background:rgba(0,200,255,.06); border-radius:8px; padding:8px 10px; }
|
|
109
|
+
.avp-stat-icon { font-size:16px; }
|
|
110
|
+
.avp-stat-value { font-family:'Orbitron',sans-serif; font-size:14px; color:#00c8ff; }
|
|
111
|
+
.avp-stat-label { font-size:11px; color:#7a9bbf; text-transform:uppercase; letter-spacing:.06em; }
|
|
112
|
+
.avp-fields { display:flex; flex-direction:column; gap:12px; }
|
|
113
|
+
.avp-section-label { font-size:10px; font-weight:700; letter-spacing:.12em; color:#7a9bbf; text-transform:uppercase; margin-bottom:4px; }
|
|
114
|
+
.avp-field-row { display:grid; grid-template-columns:90px 1fr; align-items:center; gap:12px; }
|
|
115
|
+
.avp-label { font-size:12px; color:#7a9bbf; text-align:right; }
|
|
116
|
+
.avp-input { width:100%; background:rgba(255,255,255,.05); border:1px solid rgba(0,200,255,.2); border-radius:6px; padding:8px 12px; color:#fff; font-size:13px; outline:none; box-sizing:border-box; transition:border-color .2s; }
|
|
117
|
+
.avp-input:focus { border-color:rgba(0,200,255,.5); }
|
|
118
|
+
.avp-status { margin-top:4px; font-size:13px; color:#48dc82; }
|
|
119
|
+
.avp-status--error { color:#ff6b6b; }
|
|
120
|
+
.avp-actions { display:flex; gap:10px; margin-top:4px; }
|
|
121
|
+
.avp-btn { background:linear-gradient(135deg,#00c8ff,#0080ff); border:none; border-radius:6px; color:#fff; font-family:'Orbitron',sans-serif; font-size:11px; font-weight:700; letter-spacing:.08em; padding:9px 16px; cursor:pointer; transition:opacity .2s; }
|
|
122
|
+
.avp-btn:disabled { opacity:.5; cursor:not-allowed; }
|
|
123
|
+
.avp-btn--ghost { background:transparent; border:1px solid rgba(0,200,255,.3); color:#00c8ff; }
|
|
124
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export let title = 'Feature Coming Soon'
|
|
3
|
+
export let message = 'This feature is currently under development and will be available soon.'
|
|
4
|
+
</script>
|
|
5
|
+
<div class="cs-shell">
|
|
6
|
+
<div class="cs-icon">🚀</div>
|
|
7
|
+
<h2 class="cs-title">{title}</h2>
|
|
8
|
+
<p class="cs-body">{message}</p>
|
|
9
|
+
<div class="cs-badge">Coming Soon</div>
|
|
10
|
+
</div>
|
|
11
|
+
<style>
|
|
12
|
+
.cs-shell{display:flex;flex-direction:column;align-items:center;gap:16px;padding:40px 20px;text-align:center}.cs-icon{font-size:48px}.cs-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0}.cs-body{font-size:14px;color:#7a9bbf;line-height:1.6;margin:0;max-width:360px}.cs-badge{background:rgba(255,180,60,.12);border:1px solid rgba(255,180,60,.28);color:#ffb43c;border-radius:999px;font-size:11px;font-weight:700;letter-spacing:.1em;padding:5px 14px;text-transform:uppercase}
|
|
13
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
export let title = 'Are you sure?'
|
|
4
|
+
export let message = 'This action cannot be undone.'
|
|
5
|
+
export let icon = '⚠️'
|
|
6
|
+
export let confirmLabel = 'Confirm'
|
|
7
|
+
export let cancelLabel = 'Cancel'
|
|
8
|
+
const dispatch = createEventDispatcher<{ confirm: void; cancel: void }>()
|
|
9
|
+
</script>
|
|
10
|
+
<div class="conf-shell">
|
|
11
|
+
<div class="conf-icon">{icon}</div>
|
|
12
|
+
<h2 class="conf-title">{title}</h2>
|
|
13
|
+
<p class="conf-body">{message}</p>
|
|
14
|
+
<div class="conf-actions">
|
|
15
|
+
<button class="conf-btn conf-btn--confirm" on:click={() => dispatch('confirm')}>{ confirmLabel}</button>
|
|
16
|
+
<button class="conf-btn conf-btn--cancel" on:click={() => dispatch('cancel')}>{cancelLabel}</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<style>
|
|
20
|
+
.conf-shell{display:flex;flex-direction:column;align-items:center;gap:18px;padding:20px;text-align:center}.conf-icon{font-size:44px}.conf-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.conf-body{font-size:14px;color:#a8bfd8;line-height:1.6;margin:0;max-width:360px}.conf-actions{display:flex;gap:12px;margin-top:4px}.conf-btn{border:none;border-radius:8px;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;letter-spacing:.08em;padding:11px 24px;cursor:pointer;transition:opacity .2s}.conf-btn--confirm{background:linear-gradient(135deg,#ff4444,#cc0000);color:#fff}.conf-btn--cancel{background:transparent;border:1px solid rgba(0,200,255,.3);color:#00c8ff}
|
|
21
|
+
</style>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let firstName = '', lastName = '', email = '', subject = '', message = ''
|
|
3
|
+
let loading = false, error = '', sent = false
|
|
4
|
+
async function submit() {
|
|
5
|
+
if (!email || !message) { error = 'Please fill in your email and message.'; return }
|
|
6
|
+
loading = true; error = ''
|
|
7
|
+
try {
|
|
8
|
+
await fetch('https://formsubmit.co/ajax/davidellams@hotmail.com', {
|
|
9
|
+
method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
10
|
+
body: JSON.stringify({ firstName, lastName, email, subject, message })
|
|
11
|
+
})
|
|
12
|
+
sent = true
|
|
13
|
+
} catch (e: any) { error = e?.message ?? 'Send failed. Please try again.' }
|
|
14
|
+
finally { loading = false }
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
<div class="ct-shell">
|
|
18
|
+
<div class="ct-header">
|
|
19
|
+
<h2 class="ct-title">Contact Us</h2>
|
|
20
|
+
<p class="ct-sub">Get in touch with the OASIS team.</p>
|
|
21
|
+
</div>
|
|
22
|
+
{#if sent}
|
|
23
|
+
<div class="oasis-auth-success">✅ Message sent! We'll be in touch soon.</div>
|
|
24
|
+
{:else}
|
|
25
|
+
{#if error}<div class="oasis-auth-error">{error}</div>{/if}
|
|
26
|
+
<div class="oasis-grid-2">
|
|
27
|
+
<div class="oasis-field"><label class="oasis-label">First Name</label><input class="oasis-input" type="text" bind:value={firstName} placeholder="John" /></div>
|
|
28
|
+
<div class="oasis-field"><label class="oasis-label">Last Name</label><input class="oasis-input" type="text" bind:value={lastName} placeholder="Doe" /></div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="oasis-field"><label class="oasis-label">Email</label><input class="oasis-input" type="email" bind:value={email} placeholder="name@example.com" /></div>
|
|
31
|
+
<div class="oasis-field"><label class="oasis-label">Subject</label><input class="oasis-input" type="text" bind:value={subject} placeholder="How can we help?" /></div>
|
|
32
|
+
<div class="oasis-field"><label class="oasis-label">Message</label><textarea class="oasis-input oasis-textarea" bind:value={message} placeholder="Your message…" rows="4"></textarea></div>
|
|
33
|
+
<button class="oasis-btn" disabled={loading} on:click={submit}>{loading ? 'Sending…' : 'Send Message'}</button>
|
|
34
|
+
{/if}
|
|
35
|
+
</div>
|
|
36
|
+
<style>
|
|
37
|
+
.ct-shell{display:flex;flex-direction:column;gap:18px}.ct-header{text-align:center}.ct-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}.ct-sub{font-size:13px;color:#7a9bbf;margin:0}.oasis-auth-error{background:rgba(255,80,80,.12);border:1px solid rgba(255,80,80,.3);color:#ff6b6b;border-radius:8px;padding:10px 14px;font-size:13px}.oasis-auth-success{background:rgba(72,220,130,.12);border:1px solid rgba(72,220,130,.3);color:#48dc82;border-radius:8px;padding:10px 14px;font-size:13px}.oasis-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:14px}.oasis-field{display:flex;flex-direction:column;gap:6px}.oasis-label{font-size:12px;font-weight:600;letter-spacing:.06em;color:#7a9bbf;text-transform:uppercase}.oasis-input{width:100%;background:rgba(255,255,255,.05);border:1px solid rgba(0,200,255,.2);border-radius:8px;padding:10px 14px;color:#fff;font-size:14px;outline:none;box-sizing:border-box;transition:border-color .2s;font-family:inherit}.oasis-input:focus{border-color:rgba(0,200,255,.5)}.oasis-textarea{resize:vertical;min-height:100px}.oasis-btn{width:100%;background:linear-gradient(135deg,#00c8ff,#0080ff);border:none;border-radius:8px;color:#fff;font-family:'Orbitron',sans-serif;font-size:13px;font-weight:700;letter-spacing:.08em;padding:12px;cursor:pointer;transition:opacity .2s}.oasis-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Egg { id: string; name: string; rarity: string; hatchProgress: number; hatched: boolean; reward: string }
|
|
3
|
+
let eggs: Egg[] = [
|
|
4
|
+
{ id: '1', name: 'Cosmic Egg', rarity: 'Legendary', hatchProgress: 75, hatched: false, reward: '+500 Karma Companion' },
|
|
5
|
+
{ id: '2', name: 'Forest Egg', rarity: 'Common', hatchProgress: 100, hatched: true, reward: 'Woodland Sprite' },
|
|
6
|
+
{ id: '3', name: 'Astral Egg', rarity: 'Epic', hatchProgress: 30, hatched: false, reward: '+200 Karma Companion' },
|
|
7
|
+
{ id: '4', name: 'Ocean Egg', rarity: 'Rare', hatchProgress: 55, hatched: false, reward: 'Sea Guardian' },
|
|
8
|
+
]
|
|
9
|
+
function incubate(e: Egg) {
|
|
10
|
+
const next = Math.min(100, e.hatchProgress + 25)
|
|
11
|
+
e.hatchProgress = next; e.hatched = next >= 100; eggs = [...eggs]
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
<div class="eggs-shell">
|
|
15
|
+
<div class="eggs-header">
|
|
16
|
+
<h2 class="eggs-title">🥚 Eggs</h2>
|
|
17
|
+
<p class="eggs-sub">Hatch eggs to discover rare OASIS companions and rewards.</p>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="eggs-grid">
|
|
20
|
+
{#each eggs as e (e.id)}
|
|
21
|
+
<div class="egg-card" class:egg-card--hatched={e.hatched}>
|
|
22
|
+
<div class="egg-rarity egg-rarity--{e.rarity.toLowerCase()}">{e.rarity}</div>
|
|
23
|
+
<div class="egg-icon">{e.hatched ? '🐣' : '🥚'}</div>
|
|
24
|
+
<div class="egg-name">{e.name}</div>
|
|
25
|
+
{#if !e.hatched}
|
|
26
|
+
<div class="egg-progress-wrap">
|
|
27
|
+
<div class="egg-progress-bar"><div class="egg-progress-fill" style="width:{e.hatchProgress}%"></div></div>
|
|
28
|
+
<div class="egg-pct">{e.hatchProgress}%</div>
|
|
29
|
+
</div>
|
|
30
|
+
<button class="egg-btn" on:click={() => incubate(e)}>Incubate</button>
|
|
31
|
+
{:else}
|
|
32
|
+
<div class="egg-reward">✨ {e.reward}</div>
|
|
33
|
+
{/if}
|
|
34
|
+
</div>
|
|
35
|
+
{/each}
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<style>
|
|
39
|
+
.eggs-shell{display:flex;flex-direction:column;gap:20px}.eggs-header{text-align:center}.eggs-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}.eggs-sub{font-size:13px;color:#7a9bbf;margin:0}.eggs-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:16px}.egg-card{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.15);border-radius:12px;padding:18px 14px;display:flex;flex-direction:column;align-items:center;gap:10px;transition:border-color .2s}.egg-card:hover{border-color:rgba(0,200,255,.35)}.egg-card--hatched{border-color:rgba(255,180,60,.3);background:rgba(255,180,60,.04)}.egg-rarity{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;border-radius:999px;padding:3px 10px;border:1px solid currentColor}.egg-rarity--common{color:#7a9bbf;border-color:rgba(122,155,191,.3)}.egg-rarity--rare{color:#5ba8ff;border-color:rgba(91,168,255,.3)}.egg-rarity--epic{color:#b87fff;border-color:rgba(184,127,255,.3)}.egg-rarity--legendary{color:#ffb43c;border-color:rgba(255,180,60,.3)}.egg-icon{font-size:40px}.egg-name{font-family:'Orbitron',sans-serif;font-size:12px;color:#fff;text-align:center}.egg-progress-wrap{width:100%;display:flex;flex-direction:column;gap:4px;align-items:center}.egg-progress-bar{width:100%;height:6px;background:rgba(255,255,255,.1);border-radius:999px;overflow:hidden}.egg-progress-fill{height:100%;background:linear-gradient(90deg,#00c8ff,#0080ff);border-radius:999px;transition:width .4s}.egg-pct{font-size:11px;color:#7a9bbf}.egg-btn{width:100%;background:linear-gradient(135deg,#ffb43c,#ff8c00);border:none;border-radius:7px;color:#fff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;letter-spacing:.08em;padding:8px;cursor:pointer;transition:opacity .2s}.egg-btn:hover{opacity:.85}.egg-reward{font-size:12px;color:#ffb43c;font-weight:600;text-align:center}
|
|
40
|
+
</style>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
import { forgotPassword } from './oasisStore'
|
|
4
|
+
|
|
5
|
+
const dispatch = createEventDispatcher<{ switchTo: 'login' }>()
|
|
6
|
+
|
|
7
|
+
let email = ''
|
|
8
|
+
let loading = false
|
|
9
|
+
let error = ''
|
|
10
|
+
let sent = false
|
|
11
|
+
|
|
12
|
+
async function submit() {
|
|
13
|
+
if (!email) { error = 'Please enter your email address.'; return }
|
|
14
|
+
loading = true
|
|
15
|
+
error = ''
|
|
16
|
+
try {
|
|
17
|
+
await forgotPassword(email)
|
|
18
|
+
sent = true
|
|
19
|
+
} catch (e: any) {
|
|
20
|
+
error = e?.message ?? 'Request failed. Please try again.'
|
|
21
|
+
} finally {
|
|
22
|
+
loading = false
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<div class="oasis-auth-form">
|
|
28
|
+
<div class="oasis-auth-header">
|
|
29
|
+
<h2 class="oasis-auth-title">Forgot Password?</h2>
|
|
30
|
+
<p class="oasis-auth-sub">Enter your email and we'll send a reset link if the account exists.</p>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
{#if error}
|
|
34
|
+
<div class="oasis-auth-error">{error}</div>
|
|
35
|
+
{/if}
|
|
36
|
+
|
|
37
|
+
{#if !sent}
|
|
38
|
+
<div class="oasis-field">
|
|
39
|
+
<label class="oasis-label" for="fp-email">Email</label>
|
|
40
|
+
<input class="oasis-input" id="fp-email" type="email" bind:value={email} placeholder="name@example.com" autocomplete="email" />
|
|
41
|
+
</div>
|
|
42
|
+
<button class="oasis-btn" type="button" disabled={loading} on:click={submit}>
|
|
43
|
+
{loading ? 'Sending…' : 'Send Reset Link'}
|
|
44
|
+
</button>
|
|
45
|
+
{:else}
|
|
46
|
+
<div class="oasis-auth-success">✅ Reset link sent! Check your inbox.</div>
|
|
47
|
+
{/if}
|
|
48
|
+
|
|
49
|
+
<a class="oasis-link oasis-link--center" href="#" on:click|preventDefault={() => dispatch('switchTo', 'login')}>← Back to Login</a>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<style>
|
|
53
|
+
.oasis-auth-form { display:flex; flex-direction:column; gap:20px; }
|
|
54
|
+
.oasis-auth-header { text-align:center; }
|
|
55
|
+
.oasis-auth-title { font-family:'Orbitron',sans-serif; font-size:20px; color:#fff; margin:0 0 6px; }
|
|
56
|
+
.oasis-auth-sub { font-size:13px; color:#7a9bbf; margin:0; line-height:1.5; }
|
|
57
|
+
.oasis-auth-error { background:rgba(255,80,80,.12); border:1px solid rgba(255,80,80,.3); color:#ff6b6b; border-radius:8px; padding:10px 14px; font-size:13px; }
|
|
58
|
+
.oasis-auth-success { background:rgba(72,220,130,.12); border:1px solid rgba(72,220,130,.3); color:#48dc82; border-radius:8px; padding:14px; font-size:13px; }
|
|
59
|
+
.oasis-field { display:flex; flex-direction:column; gap:6px; }
|
|
60
|
+
.oasis-label { font-size:12px; font-weight:600; letter-spacing:.06em; color:#7a9bbf; text-transform:uppercase; }
|
|
61
|
+
.oasis-input { width:100%; background:rgba(255,255,255,.05); border:1px solid rgba(0,200,255,.2); border-radius:8px; padding:10px 14px; color:#fff; font-size:14px; outline:none; box-sizing:border-box; transition:border-color .2s; }
|
|
62
|
+
.oasis-input:focus { border-color:rgba(0,200,255,.5); }
|
|
63
|
+
.oasis-link { color:#00c8ff; text-decoration:none; cursor:pointer; font-size:13px; }
|
|
64
|
+
.oasis-link--center { text-align:center; }
|
|
65
|
+
.oasis-btn { background:linear-gradient(135deg,#00c8ff,#0080ff); border:none; border-radius:8px; color:#fff; font-family:'Orbitron',sans-serif; font-size:13px; font-weight:700; letter-spacing:.08em; padding:12px; cursor:pointer; transition:opacity .2s; }
|
|
66
|
+
.oasis-btn:disabled { opacity:.5; cursor:not-allowed; }
|
|
67
|
+
</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Game { id: string; name: string; genre: string; description: string; players: number; karma: number; icon: string; playing: boolean }
|
|
3
|
+
let games: Game[] = [
|
|
4
|
+
{ id: '1', name: 'Karma Wars', genre: 'Strategy', description: 'Battle other avatars for karma dominance in real-time.', players: 12450, karma: 50, icon: '⚔️', playing: false },
|
|
5
|
+
{ id: '2', name: 'Seed Garden', genre: 'Simulation', description: 'Grow and cultivate a virtual garden to earn seeds and karma.', players: 8900, karma: 30, icon: '🌱', playing: false },
|
|
6
|
+
{ id: '3', name: 'OASIS Racer', genre: 'Racing', description: 'Race across virtual worlds and earn speed karma.', players: 5600, karma: 40, icon: '🏎️', playing: false },
|
|
7
|
+
{ id: '4', name: 'NFT Quest', genre: 'RPG', description: 'An epic RPG adventure to discover legendary NFTs.', players: 22000, karma: 80, icon: '🗡️', playing: false },
|
|
8
|
+
]
|
|
9
|
+
function toggle(g: Game) { g.playing = !g.playing; games = [...games] }
|
|
10
|
+
</script>
|
|
11
|
+
<div class="game-shell">
|
|
12
|
+
<div class="game-header"><h2 class="game-title">🎮 Games</h2><p class="game-sub">Play games in the OASIS to earn karma and rewards.</p></div>
|
|
13
|
+
<div class="game-grid">
|
|
14
|
+
{#each games as g (g.id)}
|
|
15
|
+
<div class="game-card" class:game-card--playing={g.playing}>
|
|
16
|
+
<div class="game-icon">{g.icon}</div>
|
|
17
|
+
<div class="game-genre">{g.genre}</div>
|
|
18
|
+
<div class="game-name">{g.name}</div>
|
|
19
|
+
<div class="game-desc">{g.description}</div>
|
|
20
|
+
<div class="game-meta"><div class="game-players">👥 {g.players.toLocaleString()}</div><div class="game-karma">+{g.karma} karma/hr</div></div>
|
|
21
|
+
<button class="game-btn" class:game-btn--stop={g.playing} on:click={() => toggle(g)}>{g.playing ? '⏹ Stop' : '▶ Play'}</button>
|
|
22
|
+
</div>
|
|
23
|
+
{/each}
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<style>
|
|
27
|
+
.game-shell{display:flex;flex-direction:column;gap:18px}.game-header{text-align:center}.game-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}.game-sub{font-size:13px;color:#7a9bbf;margin:0}.game-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px}.game-card{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.12);border-radius:12px;padding:18px 14px;display:flex;flex-direction:column;gap:8px;transition:border-color .2s}.game-card:hover{border-color:rgba(0,200,255,.3)}.game-card--playing{border-color:rgba(0,200,255,.5);background:rgba(0,200,255,.05)}.game-icon{font-size:40px}.game-genre{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#5ba8ff}.game-name{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff}.game-desc{font-size:12px;color:#7a9bbf;line-height:1.5;flex:1}.game-meta{display:flex;justify-content:space-between}.game-players{font-size:11px;color:#7a9bbf}.game-karma{font-size:11px;color:#48dc82;font-weight:600}.game-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:9px;cursor:pointer;transition:opacity .2s;margin-top:4px}.game-btn--stop{background:rgba(255,80,80,.2);border:1px solid rgba(255,80,80,.35);color:#ff6b6b}
|
|
28
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let active = false
|
|
3
|
+
const metrics = [
|
|
4
|
+
{ label: 'Throughput', value: '4.2 TB/s' },
|
|
5
|
+
{ label: 'Latency', value: '0.3ms' },
|
|
6
|
+
{ label: 'Uptime', value: '99.98%' },
|
|
7
|
+
]
|
|
8
|
+
const nodes = [
|
|
9
|
+
{ id: '1', name: 'ONODE Alpha — US East', status: 'active', latency: 12 },
|
|
10
|
+
{ id: '2', name: 'ONODE Beta — EU West', status: 'active', latency: 28 },
|
|
11
|
+
{ id: '3', name: 'ONODE Gamma — Asia Pacific', status: 'idle', latency: 55 },
|
|
12
|
+
]
|
|
13
|
+
</script>
|
|
14
|
+
<div class="hd-shell">
|
|
15
|
+
<div class="hd-header"><h2 class="hd-title">🚀 HyperDrive</h2><p class="hd-sub">Quantum-speed data layer for the OASIS Omniverse.</p></div>
|
|
16
|
+
<div class="hd-status-card" class:hd-status-card--active={active}>
|
|
17
|
+
<div class="hd-status-icon">{active ? '⚡' : '💤'}</div>
|
|
18
|
+
<div class="hd-status-info">
|
|
19
|
+
<div class="hd-status-label">HyperDrive Status</div>
|
|
20
|
+
<div class="hd-status-val" class:hd-status-val--on={active}>{active ? 'ACTIVE' : 'OFFLINE'}</div>
|
|
21
|
+
</div>
|
|
22
|
+
<button class="hd-toggle-btn" class:hd-toggle-btn--on={active} on:click={() => active = !active}>{active ? 'Disengage' : 'Engage'}</button>
|
|
23
|
+
</div>
|
|
24
|
+
{#if active}
|
|
25
|
+
<div class="hd-metrics">
|
|
26
|
+
{#each metrics as m}<div class="hd-metric-card"><div class="hd-metric-val">{m.value}</div><div class="hd-metric-label">{m.label}</div></div>{/each}
|
|
27
|
+
</div>
|
|
28
|
+
<div class="hd-nodes-header">Connected Nodes</div>
|
|
29
|
+
<div class="hd-nodes">
|
|
30
|
+
{#each nodes as n (n.id)}
|
|
31
|
+
<div class="hd-node">
|
|
32
|
+
<div class="hd-node-dot hd-node-dot--{n.status}"></div>
|
|
33
|
+
<div class="hd-node-name">{n.name}</div>
|
|
34
|
+
<div class="hd-node-latency">{n.latency}ms</div>
|
|
35
|
+
</div>
|
|
36
|
+
{/each}
|
|
37
|
+
</div>
|
|
38
|
+
{/if}
|
|
39
|
+
</div>
|
|
40
|
+
<style>
|
|
41
|
+
.hd-shell{display:flex;flex-direction:column;gap:18px}.hd-header{text-align:center}.hd-title{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;margin:0 0 6px}.hd-sub{font-size:13px;color:#7a9bbf;margin:0}.hd-status-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:16px;transition:border-color .2s}.hd-status-card--active{border-color:rgba(0,200,255,.4);background:rgba(0,200,255,.05)}.hd-status-icon{font-size:28px}.hd-status-info{flex:1}.hd-status-label{font-size:12px;color:#7a9bbf;text-transform:uppercase;letter-spacing:.06em}.hd-status-val{font-family:'Orbitron',sans-serif;font-size:16px;color:#7a9bbf;margin-top:2px}.hd-status-val--on{color:#00c8ff}.hd-toggle-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 20px;cursor:pointer}.hd-toggle-btn--on{background:rgba(255,80,80,.2);border:1px solid rgba(255,80,80,.35);color:#ff6b6b}.hd-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.hd-metric-card{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.1);border-radius:10px;padding:14px;text-align:center}.hd-metric-val{font-family:'Share Tech Mono',monospace;font-size:20px;color:#00c8ff;font-weight:600}.hd-metric-label{font-size:11px;color:#7a9bbf;margin-top:4px;text-transform:uppercase;letter-spacing:.06em}.hd-nodes{display:flex;flex-direction:column;gap:8px}.hd-nodes-header{font-family:'Orbitron',sans-serif;font-size:12px;color:#7a9bbf;letter-spacing:.06em;text-transform:uppercase}.hd-node{display:flex;align-items:center;gap:10px;padding:10px 14px;background:rgba(255,255,255,.03);border:1px solid rgba(0,200,255,.07);border-radius:8px}.hd-node-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.hd-node-dot--active{background:#48dc82;box-shadow:0 0 6px #48dc82}.hd-node-dot--idle{background:#7a9bbf}.hd-node-name{flex:1;font-size:13px;color:#e0f0ff}.hd-node-latency{font-family:'Share Tech Mono',monospace;font-size:12px;color:#7a9bbf}
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { derived } from 'svelte/store'
|
|
3
|
+
import { session } from './oasisStore'
|
|
4
|
+
|
|
5
|
+
type Tab = 'records' | 'stats' | 'weightings'
|
|
6
|
+
let activeTab: Tab = 'records'
|
|
7
|
+
|
|
8
|
+
const level = derived(session, $s => Math.floor(Math.sqrt(($s?.karma ?? 0) / 100)) + 1)
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<div class="kp-shell">
|
|
12
|
+
<div class="kp-banner">
|
|
13
|
+
<div class="kp-stat">
|
|
14
|
+
<div class="kp-stat-label">KARMA</div>
|
|
15
|
+
<div class="kp-stat-value">{$session?.karma ?? '—'}</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="kp-stat">
|
|
18
|
+
<div class="kp-stat-label">LEVEL</div>
|
|
19
|
+
<div class="kp-stat-value kp-stat-value--level">{$level}</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="kp-stat">
|
|
22
|
+
<div class="kp-stat-label">AVATAR TYPE</div>
|
|
23
|
+
<div class="kp-stat-value kp-stat-value--type">User</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="kp-tabs">
|
|
28
|
+
<button class="kp-tab" class:kp-tab--active={activeTab === 'records'} on:click={() => activeTab = 'records'}>Akashic Records</button>
|
|
29
|
+
<button class="kp-tab" class:kp-tab--active={activeTab === 'stats'} on:click={() => activeTab = 'stats'}>Stats</button>
|
|
30
|
+
<button class="kp-tab" class:kp-tab--active={activeTab === 'weightings'} on:click={() => activeTab = 'weightings'}>Weightings</button>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
{#if activeTab === 'records'}
|
|
34
|
+
<div class="kp-panel kp-empty">
|
|
35
|
+
<div class="kp-empty-icon">📜</div>
|
|
36
|
+
<p>No karma records found.<br>Complete actions in the OASIS ecosystem to build your Akashic Record.</p>
|
|
37
|
+
</div>
|
|
38
|
+
{:else if activeTab === 'stats'}
|
|
39
|
+
<div class="kp-panel kp-empty">
|
|
40
|
+
<div class="kp-empty-icon">📊</div>
|
|
41
|
+
<p>No stats available yet.</p>
|
|
42
|
+
</div>
|
|
43
|
+
{:else}
|
|
44
|
+
<div class="kp-panel">
|
|
45
|
+
<div class="kp-vote-banner">
|
|
46
|
+
<div>
|
|
47
|
+
<strong>Karma Voting</strong>
|
|
48
|
+
<p>Community voting to adjust karma weightings is coming soon.</p>
|
|
49
|
+
</div>
|
|
50
|
+
<button class="kp-btn-ghost">Vote on Weightings <span class="kp-soon">Coming Soon</span></button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
{/if}
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<style>
|
|
57
|
+
.kp-shell { color:#fff; display:flex; flex-direction:column; gap:20px; }
|
|
58
|
+
.kp-banner { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
|
|
59
|
+
.kp-stat { background:rgba(0,200,255,.06); border:1px solid rgba(0,200,255,.12); border-radius:10px; padding:14px; text-align:center; }
|
|
60
|
+
.kp-stat-label { font-size:10px; font-weight:700; letter-spacing:.1em; color:#7a9bbf; text-transform:uppercase; margin-bottom:6px; }
|
|
61
|
+
.kp-stat-value { font-family:'Orbitron',sans-serif; font-size:22px; color:#00c8ff; }
|
|
62
|
+
.kp-stat-value--level { color:#a78bfa; }
|
|
63
|
+
.kp-stat-value--type { color:#48dc82; font-size:16px; }
|
|
64
|
+
.kp-tabs { display:flex; gap:4px; border-bottom:1px solid rgba(0,200,255,.12); }
|
|
65
|
+
.kp-tab { background:none; border:none; color:#7a9bbf; font-size:13px; padding:10px 16px; cursor:pointer; border-bottom:2px solid transparent; transition:all .2s; }
|
|
66
|
+
.kp-tab--active { color:#00c8ff; border-bottom-color:#00c8ff; }
|
|
67
|
+
.kp-panel { padding:16px 0; }
|
|
68
|
+
.kp-empty { display:flex; flex-direction:column; align-items:center; gap:10px; padding:40px 16px; text-align:center; color:#7a9bbf; font-size:13px; line-height:1.6; }
|
|
69
|
+
.kp-empty-icon { font-size:32px; }
|
|
70
|
+
.kp-vote-banner { display:flex; align-items:center; justify-content:space-between; gap:16px; background:rgba(255,255,255,.03); border:1px solid rgba(0,200,255,.1); border-radius:10px; padding:16px; font-size:13px; color:#a8bfd8; line-height:1.5; }
|
|
71
|
+
.kp-vote-banner strong { display:block; color:#fff; margin-bottom:4px; }
|
|
72
|
+
.kp-btn-ghost { flex-shrink:0; background:transparent; border:1px solid rgba(0,200,255,.3); color:#00c8ff; border-radius:6px; padding:8px 14px; font-size:12px; cursor:pointer; white-space:nowrap; }
|
|
73
|
+
.kp-soon { display:inline-block; background:rgba(255,180,60,.15); color:#ffb43c; border-radius:999px; font-size:9px; padding:2px 6px; margin-left:6px; letter-spacing:.06em; vertical-align:middle; }
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { fly } from 'svelte/transition'
|
|
3
|
+
import { karmaToast } from './oasisStore'
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
{#if $karmaToast}
|
|
7
|
+
<div class="karma-toast" transition:fly={{ y: 20, duration: 350 }}>
|
|
8
|
+
<span class="kt-amount">+{$karmaToast.amount} ✦</span>
|
|
9
|
+
<span class="kt-msg">{$karmaToast.message}</span>
|
|
10
|
+
</div>
|
|
11
|
+
{/if}
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
.karma-toast {
|
|
15
|
+
position: fixed; bottom: 32px; right: 32px; z-index: 9999;
|
|
16
|
+
background: linear-gradient(135deg, rgba(59,130,246,.15), rgba(168,85,247,.1));
|
|
17
|
+
border: 1px solid rgba(59,130,246,.45); border-radius: 14px;
|
|
18
|
+
padding: 16px 24px; display: flex; flex-direction: column; gap: 4px;
|
|
19
|
+
backdrop-filter: blur(12px);
|
|
20
|
+
}
|
|
21
|
+
.kt-amount { font-family: 'Orbitron', sans-serif; font-size: 22px; font-weight: 900; color: #3b82f6; }
|
|
22
|
+
.kt-msg { font-family: 'Share Tech Mono', monospace; font-size: 11px; letter-spacing: .1em; color: #a8bfd8; }
|
|
23
|
+
</style>
|