@oasisomniverse/vue 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/AvatarWallet.vue +29 -0
- package/src/components/Avatar/EditAvatar.vue +21 -0
- package/src/components/Avatar/SearchAvatar.vue +24 -0
- package/src/components/Avatar/ViewAvatar.vue +19 -0
- package/src/components/AvatarConnect/AvatarConnect.vue +64 -0
- package/src/components/AvatarProfile/AvatarProfile.vue +123 -0
- package/src/components/ComingSoon/ComingSoon.vue +14 -0
- package/src/components/Confirmation/Confirmation.vue +18 -0
- package/src/components/Contact/Contact.vue +40 -0
- package/src/components/DataScreen/AddData.vue +26 -0
- package/src/components/DataScreen/CrossChainManagement.vue +14 -0
- package/src/components/DataScreen/LoadData.vue +24 -0
- package/src/components/DataScreen/ManageData.vue +14 -0
- package/src/components/DataScreen/OffChainManagement.vue +14 -0
- package/src/components/DataScreen/SearchData.vue +24 -0
- package/src/components/Eggs/Eggs.vue +40 -0
- package/src/components/Eggs/ManageEggs.vue +14 -0
- package/src/components/Eggs/SearchEggs.vue +24 -0
- package/src/components/Eggs/ViewEggs.vue +20 -0
- package/src/components/ForgotPassword/ForgotPassword.vue +71 -0
- package/src/components/Game/Game.vue +29 -0
- package/src/components/Game/SearchProfiles.vue +24 -0
- package/src/components/Game/ViewAchievements.vue +25 -0
- package/src/components/Game/ViewLeagues.vue +25 -0
- package/src/components/Game/ViewTournaments.vue +27 -0
- package/src/components/HyperDrive/HyperDrive.vue +46 -0
- package/src/components/Karma/SearchKarma.vue +24 -0
- package/src/components/Karma/ViewAvatarKarma.vue +20 -0
- package/src/components/Karma/ViewKarma.vue +30 -0
- package/src/components/Karma/VoteKarma.vue +26 -0
- package/src/components/KarmaPanel/KarmaPanel.vue +71 -0
- package/src/components/KarmaToast/KarmaToast.vue +29 -0
- package/src/components/Login/Login.vue +90 -0
- package/src/components/Map/Add2dObjectMap.vue +23 -0
- package/src/components/Map/Add3dObjectMap.vue +24 -0
- package/src/components/Map/AddQuestToMap.vue +22 -0
- package/src/components/Map/DownloadOurWorld.vue +18 -0
- package/src/components/Map/ManageMap.vue +14 -0
- package/src/components/Map/Map.vue +38 -0
- package/src/components/Map/PlotRouteOnMap.vue +25 -0
- package/src/components/Map/SearchMap.vue +24 -0
- package/src/components/Map/ViewGlobal3dMap.vue +14 -0
- package/src/components/Map/ViewHalonsOnMap.vue +27 -0
- package/src/components/Map/ViewOappOnMap.vue +14 -0
- package/src/components/Map/ViewQuestOnMap.vue +20 -0
- package/src/components/MenuMessage/MenuMessage.vue +72 -0
- package/src/components/Message/Message.vue +50 -0
- package/src/components/Messaging/Messaging.vue +44 -0
- package/src/components/Mission/ManageMission.vue +14 -0
- package/src/components/Mission/Mission.vue +32 -0
- package/src/components/Mission/SearchMission.vue +24 -0
- package/src/components/Mission/ViewMission.vue +21 -0
- package/src/components/NFT/ContactPopup.vue +36 -0
- package/src/components/NFT/ManageOasisNft.vue +14 -0
- package/src/components/NFT/NFT.vue +36 -0
- package/src/components/NFT/PurchaseOasisNft.vue +21 -0
- package/src/components/NFT/PurchaseOasisVirtualLandNft.vue +23 -0
- package/src/components/NFT/SearchOasisNft.vue +30 -0
- package/src/components/NFT/Solana.vue +27 -0
- package/src/components/NFT/ViewOasisNft.vue +20 -0
- package/src/components/NavBar/NavBar.vue +71 -0
- package/src/components/OApp/CreateOAPP.vue +31 -0
- package/src/components/OApp/DeployOAPP.vue +23 -0
- package/src/components/OApp/DownloadOurWorld.vue +18 -0
- package/src/components/OApp/EditOAPP.vue +21 -0
- package/src/components/OApp/InstallOAPP.vue +23 -0
- package/src/components/OApp/LaunchOAPP.vue +19 -0
- package/src/components/OApp/ManageOAPP.vue +14 -0
- package/src/components/OApp/OApp.vue +40 -0
- package/src/components/OApp/SearchOAPP.vue +30 -0
- package/src/components/ONET/ONET.vue +40 -0
- package/src/components/ONODE/ONODE.vue +42 -0
- package/src/components/OasisModal/OasisModal.vue +36 -0
- package/src/components/Provider/ActivityPub.vue +14 -0
- package/src/components/Provider/CompareProviderSpeeds.vue +32 -0
- package/src/components/Provider/Eosio.vue +14 -0
- package/src/components/Provider/Ethereum.vue +14 -0
- package/src/components/Provider/Holochain.vue +14 -0
- package/src/components/Provider/Ipfs.vue +14 -0
- package/src/components/Provider/ManageAutoFailOver.vue +14 -0
- package/src/components/Provider/ManageAutoReplicaton.vue +14 -0
- package/src/components/Provider/ManageLoadBalancing.vue +14 -0
- package/src/components/Provider/ManageProviders.vue +27 -0
- package/src/components/Provider/MongoDb.vue +14 -0
- package/src/components/Provider/Neo4j.vue +14 -0
- package/src/components/Provider/SearchProviders.vue +24 -0
- package/src/components/Provider/Seeds.vue +14 -0
- package/src/components/Provider/Solid.vue +14 -0
- package/src/components/Provider/SqlLite.vue +14 -0
- package/src/components/Provider/ThreeFold.vue +14 -0
- package/src/components/Provider/ViewProviderStats.vue +27 -0
- package/src/components/Provider/ViewProviders.vue +30 -0
- package/src/components/ProviderDropdown/ProviderDropdown.vue +34 -0
- package/src/components/Providers/Providers.vue +30 -0
- package/src/components/Quest/ManageQuest.vue +14 -0
- package/src/components/Quest/Quest.vue +35 -0
- package/src/components/Quest/SearchQuest.vue +30 -0
- package/src/components/Quest/ViewQuest.vue +23 -0
- package/src/components/ResetPassword/ResetPassword.vue +39 -0
- package/src/components/SearchAvatars/SearchAvatars.vue +42 -0
- package/src/components/Seeds/AcceptInvite.vue +26 -0
- package/src/components/Seeds/DonateSeeds.vue +34 -0
- package/src/components/Seeds/ManageSeeds.vue +14 -0
- package/src/components/Seeds/PayWithSeeds.vue +34 -0
- package/src/components/Seeds/RewardSeeds.vue +20 -0
- package/src/components/Seeds/SearchSeeds.vue +18 -0
- package/src/components/Seeds/Seeds.vue +37 -0
- package/src/components/Seeds/SendInvite.vue +34 -0
- package/src/components/Seeds/ViewOrganizations.vue +27 -0
- package/src/components/Seeds/ViewSeeds.vue +34 -0
- package/src/components/Settings/Settings.vue +52 -0
- package/src/components/Signup/Signup.vue +121 -0
- package/src/components/StarField/StarField.vue +55 -0
- package/src/components/VerifyEmail/VerifyEmail.vue +21 -0
- package/src/components/Wallet/Wallet.vue +41 -0
- package/src/index.ts +143 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
const emit = defineEmits<{ close: []; submit: [{ query: string; rarity: string }] }>()
|
|
4
|
+
const form = ref({ query: '', rarity: 'All' })
|
|
5
|
+
function handleSubmit() { emit('submit', { ...form.value }) }
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<div class="p-shell">
|
|
9
|
+
<h2 class="p-title">🔍 Search Eggs</h2>
|
|
10
|
+
<form class="p-form" @submit.prevent="handleSubmit">
|
|
11
|
+
<div class="p-row"><label class="p-label">Egg Name</label><input class="p-input" v-model="form.query" placeholder="Search eggs..." /></div>
|
|
12
|
+
<div class="p-row">
|
|
13
|
+
<label class="p-label">Rarity</label>
|
|
14
|
+
<select class="p-input" v-model="form.rarity">
|
|
15
|
+
<option>All</option><option>Common</option><option>Rare</option><option>Epic</option><option>Legendary</option>
|
|
16
|
+
</select>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="p-actions"><button class="p-btn-cancel" type="button" @click="emit('close')">Cancel</button><button class="p-btn" type="submit">Search</button></div>
|
|
19
|
+
</form>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
<style scoped>
|
|
23
|
+
.p-shell{display:flex;flex-direction:column;gap:20px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-form{display:flex;flex-direction:column;gap:14px}.p-row{display:flex;flex-direction:column;gap:6px}.p-label{font-size:12px;color:#7a9bbf;font-weight:600;letter-spacing:.05em}.p-input{background:rgba(255,255,255,.06);border:1px solid rgba(0,200,255,.2);border-radius:8px;color:#fff;font-size:14px;padding:10px 12px;width:100%;box-sizing:border-box;outline:none;transition:border-color .2s}.p-input:focus{border-color:rgba(0,200,255,.5)}.p-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:4px}.p-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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}.p-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;letter-spacing:.08em;padding:10px 24px;cursor:pointer}
|
|
24
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{ name?: string; rarity?: string; hatchProgress?: number; reward?: string }>()
|
|
3
|
+
const emit = defineEmits<{ close: [] }>()
|
|
4
|
+
</script>
|
|
5
|
+
<template>
|
|
6
|
+
<div class="p-shell">
|
|
7
|
+
<div class="p-icon">{{ (hatchProgress ?? 0) >= 100 ? '🐣' : '🥚' }}</div>
|
|
8
|
+
<h2 class="p-title">{{ name ?? 'Cosmic Egg' }}</h2>
|
|
9
|
+
<div class="p-badge" :class="`p-badge--${(rarity ?? 'common').toLowerCase()}`">{{ rarity ?? 'Common' }}</div>
|
|
10
|
+
<div class="p-progress-wrap" v-if="(hatchProgress ?? 0) < 100">
|
|
11
|
+
<div class="p-progress-bar"><div class="p-progress-fill" :style="{ width: (hatchProgress ?? 0) + '%' }"></div></div>
|
|
12
|
+
<span class="p-pct">{{ hatchProgress ?? 0 }}% incubated</span>
|
|
13
|
+
</div>
|
|
14
|
+
<p class="p-reward" v-if="(hatchProgress ?? 0) >= 100">✨ {{ reward ?? 'Mystery Companion' }}</p>
|
|
15
|
+
<button class="p-btn" @click="emit('close')">Close</button>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
<style scoped>
|
|
19
|
+
.p-shell{display:flex;flex-direction:column;align-items:center;gap:16px;padding:32px 20px;text-align:center}.p-icon{font-size:64px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-badge{font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;border-radius:999px;padding:4px 12px;border:1px solid currentColor}.p-badge--common{color:#7a9bbf}.p-badge--rare{color:#5ba8ff}.p-badge--epic{color:#b87fff}.p-badge--legendary{color:#ffb43c}.p-progress-wrap{width:200px;display:flex;flex-direction:column;gap:6px;align-items:center}.p-progress-bar{width:100%;height:8px;background:rgba(255,255,255,.1);border-radius:999px;overflow:hidden}.p-progress-fill{height:100%;background:linear-gradient(90deg,#00c8ff,#0080ff);border-radius:999px}.p-pct{font-size:12px;color:#7a9bbf}.p-reward{font-size:14px;color:#ffb43c;font-weight:600}.p-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:11px 28px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}
|
|
20
|
+
</style>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { useOasis } from '../../../composables/useOasis'
|
|
4
|
+
|
|
5
|
+
const emit = defineEmits<{ switchTo: [view: 'login'] }>()
|
|
6
|
+
|
|
7
|
+
const { forgotPassword } = useOasis()
|
|
8
|
+
|
|
9
|
+
const email = ref('')
|
|
10
|
+
const loading = ref(false)
|
|
11
|
+
const error = ref('')
|
|
12
|
+
const sent = ref(false)
|
|
13
|
+
|
|
14
|
+
async function submit() {
|
|
15
|
+
if (!email.value) { error.value = 'Please enter your email address.'; return }
|
|
16
|
+
loading.value = true
|
|
17
|
+
error.value = ''
|
|
18
|
+
try {
|
|
19
|
+
await forgotPassword(email.value)
|
|
20
|
+
sent.value = true
|
|
21
|
+
} catch (e: any) {
|
|
22
|
+
error.value = e?.message ?? 'Request failed. Please try again.'
|
|
23
|
+
} finally {
|
|
24
|
+
loading.value = false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<div class="oasis-auth-form">
|
|
31
|
+
<div class="oasis-auth-header">
|
|
32
|
+
<h2 class="oasis-auth-title">Forgot Password?</h2>
|
|
33
|
+
<p class="oasis-auth-sub">Enter your email and we'll send a reset link if the account exists.</p>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div v-if="error" class="oasis-auth-error">{{ error }}</div>
|
|
37
|
+
|
|
38
|
+
<template v-if="!sent">
|
|
39
|
+
<div class="oasis-field">
|
|
40
|
+
<label class="oasis-label" for="fp-email">Email</label>
|
|
41
|
+
<input class="oasis-input" id="fp-email" type="email" v-model="email" placeholder="name@example.com" autocomplete="email" />
|
|
42
|
+
</div>
|
|
43
|
+
<button class="oasis-btn" type="button" :disabled="loading" @click="submit">
|
|
44
|
+
{{ loading ? 'Sending…' : 'Send Reset Link' }}
|
|
45
|
+
</button>
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<div v-else class="oasis-auth-success">
|
|
49
|
+
✅ Reset link sent! Check your inbox.
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<a class="oasis-link oasis-link--center" href="#" @click.prevent="emit('switchTo', 'login')">← Back to Login</a>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.oasis-auth-form { display:flex; flex-direction:column; gap:20px; }
|
|
58
|
+
.oasis-auth-header { text-align:center; }
|
|
59
|
+
.oasis-auth-title { font-family:'Orbitron',sans-serif; font-size:20px; color:#fff; margin:0 0 6px; }
|
|
60
|
+
.oasis-auth-sub { font-size:13px; color:#7a9bbf; margin:0; line-height:1.5; }
|
|
61
|
+
.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; }
|
|
62
|
+
.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; }
|
|
63
|
+
.oasis-field { display:flex; flex-direction:column; gap:6px; }
|
|
64
|
+
.oasis-label { font-size:12px; font-weight:600; letter-spacing:.06em; color:#7a9bbf; text-transform:uppercase; }
|
|
65
|
+
.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; }
|
|
66
|
+
.oasis-input:focus { border-color:rgba(0,200,255,.5); }
|
|
67
|
+
.oasis-link { color:#00c8ff; text-decoration:none; cursor:pointer; font-size:13px; }
|
|
68
|
+
.oasis-link--center { text-align:center; }
|
|
69
|
+
.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; }
|
|
70
|
+
.oasis-btn:disabled { opacity:.5; cursor:not-allowed; }
|
|
71
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
interface Game { id: string; name: string; genre: string; description: string; players: number; karma: number; icon: string; playing: boolean }
|
|
4
|
+
const games = ref<Game[]>([
|
|
5
|
+
{ id: '1', name: 'Karma Wars', genre: 'Strategy', description: 'Battle other avatars for karma dominance in real-time.', players: 12450, karma: 50, icon: '⚔️', playing: false },
|
|
6
|
+
{ 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 },
|
|
7
|
+
{ id: '3', name: 'OASIS Racer', genre: 'Racing', description: 'Race across virtual worlds and earn speed karma.', players: 5600, karma: 40, icon: '🏎️', playing: false },
|
|
8
|
+
{ id: '4', name: 'NFT Quest', genre: 'RPG', description: 'An epic RPG adventure to discover legendary NFTs.', players: 22000, karma: 80, icon: '🗡️', playing: false },
|
|
9
|
+
])
|
|
10
|
+
function toggle(g: Game) { g.playing = !g.playing }
|
|
11
|
+
</script>
|
|
12
|
+
<template>
|
|
13
|
+
<div class="game-shell">
|
|
14
|
+
<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>
|
|
15
|
+
<div class="game-grid">
|
|
16
|
+
<div v-for="g in games" :key="g.id" class="game-card" :class="{ 'game-card--playing': g.playing }">
|
|
17
|
+
<div class="game-icon">{{ g.icon }}</div>
|
|
18
|
+
<div class="game-genre">{{ g.genre }}</div>
|
|
19
|
+
<div class="game-name">{{ g.name }}</div>
|
|
20
|
+
<div class="game-desc">{{ g.description }}</div>
|
|
21
|
+
<div class="game-meta"><div class="game-players">👥 {{ g.players.toLocaleString() }}</div><div class="game-karma">+{{ g.karma }} karma/hr</div></div>
|
|
22
|
+
<button class="game-btn" :class="{ 'game-btn--stop': g.playing }" @click="toggle(g)">{{ g.playing ? '⏹ Stop' : '▶ Play' }}</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
<style scoped>
|
|
28
|
+
.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}
|
|
29
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
const emit = defineEmits<{ close: []; submit: [{ query: string; game: string }] }>()
|
|
4
|
+
const form = ref({ query: '', game: 'All' })
|
|
5
|
+
function handleSubmit() { emit('submit', { ...form.value }) }
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<div class="p-shell">
|
|
9
|
+
<h2 class="p-title">🎮 Search Game Profiles</h2>
|
|
10
|
+
<form class="p-form" @submit.prevent="handleSubmit">
|
|
11
|
+
<div class="p-row"><label class="p-label">Avatar / Player Name</label><input class="p-input" v-model="form.query" placeholder="Search players..." /></div>
|
|
12
|
+
<div class="p-row">
|
|
13
|
+
<label class="p-label">Game</label>
|
|
14
|
+
<select class="p-input" v-model="form.game">
|
|
15
|
+
<option>All</option><option>Our World</option><option>OASIS Arena</option><option>StarQuest</option>
|
|
16
|
+
</select>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="p-actions"><button class="p-btn-cancel" type="button" @click="emit('close')">Cancel</button><button class="p-btn" type="submit">Search</button></div>
|
|
19
|
+
</form>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
<style scoped>
|
|
23
|
+
.p-shell{display:flex;flex-direction:column;gap:20px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-form{display:flex;flex-direction:column;gap:14px}.p-row{display:flex;flex-direction:column;gap:6px}.p-label{font-size:12px;color:#7a9bbf;font-weight:600;letter-spacing:.05em}.p-input{background:rgba(255,255,255,.06);border:1px solid rgba(0,200,255,.2);border-radius:8px;color:#fff;font-size:14px;padding:10px 12px;width:100%;box-sizing:border-box;outline:none;transition:border-color .2s}.p-input:focus{border-color:rgba(0,200,255,.5)}.p-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:4px}.p-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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}.p-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;letter-spacing:.08em;padding:10px 24px;cursor:pointer}
|
|
24
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const emit = defineEmits<{ close: [] }>()
|
|
3
|
+
const achievements = [
|
|
4
|
+
{ icon: '⭐', name: 'First Steps', desc: 'Complete your first quest', earned: true },
|
|
5
|
+
{ icon: '🏆', name: 'Champion', desc: 'Win 10 tournaments', earned: true },
|
|
6
|
+
{ icon: '🌍', name: 'World Explorer', desc: 'Visit 50 locations in Our World', earned: false },
|
|
7
|
+
{ icon: '💎', name: 'Legendary', desc: 'Reach Karma level 1000', earned: false },
|
|
8
|
+
]
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<div class="p-shell">
|
|
12
|
+
<h2 class="p-title">🏆 Achievements</h2>
|
|
13
|
+
<div class="p-list">
|
|
14
|
+
<div v-for="a in achievements" :key="a.name" class="p-item" :class="{ 'p-item--locked': !a.earned }">
|
|
15
|
+
<span class="p-item-icon">{{ a.icon }}</span>
|
|
16
|
+
<div class="p-item-info"><span class="p-item-name">{{ a.name }}</span><span class="p-item-desc">{{ a.desc }}</span></div>
|
|
17
|
+
<span class="p-item-status">{{ a.earned ? '✅' : '🔒' }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<button class="p-btn" @click="emit('close')">Close</button>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
<style scoped>
|
|
24
|
+
.p-shell{display:flex;flex-direction:column;gap:18px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-list{display:flex;flex-direction:column;gap:10px}.p-item{display:flex;align-items:center;gap:14px;background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.15);border-radius:10px;padding:14px}.p-item--locked{opacity:.5}.p-item-icon{font-size:28px;flex-shrink:0}.p-item-info{display:flex;flex-direction:column;gap:3px;flex:1}.p-item-name{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff;font-weight:700}.p-item-desc{font-size:12px;color:#7a9bbf}.p-item-status{font-size:20px}.p-btn{align-self:flex-end;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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const emit = defineEmits<{ close: [] }>()
|
|
3
|
+
const leagues = [
|
|
4
|
+
{ name: 'Bronze League', members: 1240, minKarma: 0, icon: '🥉' },
|
|
5
|
+
{ name: 'Silver League', members: 560, minKarma: 500, icon: '🥈' },
|
|
6
|
+
{ name: 'Gold League', members: 210, minKarma: 2000, icon: '🥇' },
|
|
7
|
+
{ name: 'Diamond League', members: 42, minKarma: 10000, icon: '💎' },
|
|
8
|
+
]
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<div class="p-shell">
|
|
12
|
+
<h2 class="p-title">🏅 Leagues</h2>
|
|
13
|
+
<div class="p-list">
|
|
14
|
+
<div v-for="l in leagues" :key="l.name" class="p-item">
|
|
15
|
+
<span class="p-item-icon">{{ l.icon }}</span>
|
|
16
|
+
<div class="p-item-info"><span class="p-item-name">{{ l.name }}</span><span class="p-item-desc">{{ l.members }} members · Min Karma {{ l.minKarma }}</span></div>
|
|
17
|
+
<button class="p-join-btn">Join</button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<button class="p-btn" @click="emit('close')">Close</button>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
<style scoped>
|
|
24
|
+
.p-shell{display:flex;flex-direction:column;gap:18px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-list{display:flex;flex-direction:column;gap:10px}.p-item{display:flex;align-items:center;gap:14px;background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.15);border-radius:10px;padding:14px}.p-item-icon{font-size:28px;flex-shrink:0}.p-item-info{display:flex;flex-direction:column;gap:3px;flex:1}.p-item-name{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff;font-weight:700}.p-item-desc{font-size:12px;color:#7a9bbf}.p-join-btn{background:rgba(0,200,255,.12);border:1px solid rgba(0,200,255,.3);border-radius:6px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:10px;font-weight:700;letter-spacing:.06em;padding:6px 14px;cursor:pointer;transition:background .2s}.p-join-btn:hover{background:rgba(0,200,255,.2)}.p-btn{align-self:flex-end;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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const emit = defineEmits<{ close: [] }>()
|
|
3
|
+
const tournaments = [
|
|
4
|
+
{ name: 'OASIS Grand Prix', date: '2025-03-01', prize: '5000 KARMA', status: 'Open', icon: '🏁' },
|
|
5
|
+
{ name: 'Quantum Arena Cup', date: '2025-04-15', prize: '2000 SEEDS', status: 'Upcoming', icon: '⚡' },
|
|
6
|
+
{ name: 'Starlight Championship', date: '2025-02-10', prize: '1000 KARMA', status: 'Ended', icon: '⭐' },
|
|
7
|
+
]
|
|
8
|
+
</script>
|
|
9
|
+
<template>
|
|
10
|
+
<div class="p-shell">
|
|
11
|
+
<h2 class="p-title">🏁 Tournaments</h2>
|
|
12
|
+
<div class="p-list">
|
|
13
|
+
<div v-for="t in tournaments" :key="t.name" class="p-item">
|
|
14
|
+
<span class="p-item-icon">{{ t.icon }}</span>
|
|
15
|
+
<div class="p-item-info">
|
|
16
|
+
<span class="p-item-name">{{ t.name }}</span>
|
|
17
|
+
<span class="p-item-desc">{{ t.date }} · Prize: {{ t.prize }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
<span class="p-status" :class="`p-status--${t.status.toLowerCase()}`">{{ t.status }}</span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<button class="p-btn" @click="emit('close')">Close</button>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
<style scoped>
|
|
26
|
+
.p-shell{display:flex;flex-direction:column;gap:18px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-list{display:flex;flex-direction:column;gap:10px}.p-item{display:flex;align-items:center;gap:14px;background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.15);border-radius:10px;padding:14px}.p-item-icon{font-size:28px;flex-shrink:0}.p-item-info{display:flex;flex-direction:column;gap:3px;flex:1}.p-item-name{font-family:'Orbitron',sans-serif;font-size:13px;color:#fff;font-weight:700}.p-item-desc{font-size:12px;color:#7a9bbf}.p-status{font-size:11px;font-weight:700;letter-spacing:.06em;border-radius:999px;padding:4px 10px;border:1px solid currentColor}.p-status--open{color:#00c8ff}.p-status--upcoming{color:#ffb43c}.p-status--ended{color:#5a7a9a}.p-btn{align-self:flex-end;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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}
|
|
27
|
+
</style>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
const active = ref(false)
|
|
4
|
+
const metrics = [
|
|
5
|
+
{ label: 'Throughput', value: '4.2 TB/s' },
|
|
6
|
+
{ label: 'Latency', value: '0.3ms' },
|
|
7
|
+
{ label: 'Uptime', value: '99.98%' },
|
|
8
|
+
]
|
|
9
|
+
const nodes = [
|
|
10
|
+
{ id: '1', name: 'ONODE Alpha — US East', status: 'active', latency: 12 },
|
|
11
|
+
{ id: '2', name: 'ONODE Beta — EU West', status: 'active', latency: 28 },
|
|
12
|
+
{ id: '3', name: 'ONODE Gamma — Asia Pacific', status: 'idle', latency: 55 },
|
|
13
|
+
]
|
|
14
|
+
</script>
|
|
15
|
+
<template>
|
|
16
|
+
<div class="hd-shell">
|
|
17
|
+
<div class="hd-header"><h2 class="hd-title">🚀 HyperDrive</h2><p class="hd-sub">Quantum-speed data layer for the OASIS Omniverse.</p></div>
|
|
18
|
+
<div class="hd-status-card" :class="{ 'hd-status-card--active': active }">
|
|
19
|
+
<div class="hd-status-icon">{{ active ? '⚡' : '💤' }}</div>
|
|
20
|
+
<div class="hd-status-info">
|
|
21
|
+
<div class="hd-status-label">HyperDrive Status</div>
|
|
22
|
+
<div class="hd-status-val" :class="{ 'hd-status-val--on': active }">{{ active ? 'ACTIVE' : 'OFFLINE' }}</div>
|
|
23
|
+
</div>
|
|
24
|
+
<button class="hd-toggle-btn" :class="{ 'hd-toggle-btn--on': active }" @click="active = !active">{{ active ? 'Disengage' : 'Engage' }}</button>
|
|
25
|
+
</div>
|
|
26
|
+
<template v-if="active">
|
|
27
|
+
<div class="hd-metrics">
|
|
28
|
+
<div v-for="m in metrics" :key="m.label" class="hd-metric-card">
|
|
29
|
+
<div class="hd-metric-val">{{ m.value }}</div>
|
|
30
|
+
<div class="hd-metric-label">{{ m.label }}</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="hd-nodes-header">Connected Nodes</div>
|
|
34
|
+
<div class="hd-nodes">
|
|
35
|
+
<div v-for="n in nodes" :key="n.id" class="hd-node">
|
|
36
|
+
<div class="hd-node-dot" :class="`hd-node-dot--${n.status}`"></div>
|
|
37
|
+
<div class="hd-node-name">{{ n.name }}</div>
|
|
38
|
+
<div class="hd-node-latency">{{ n.latency }}ms</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
<style scoped>
|
|
45
|
+
.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}
|
|
46
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
const emit = defineEmits<{ close: []; submit: [{ username: string; provider: string }] }>()
|
|
4
|
+
const form = ref({ username: '', provider: 'All' })
|
|
5
|
+
function handleSubmit() { emit('submit', { ...form.value }) }
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<div class="p-shell">
|
|
9
|
+
<h2 class="p-title">⭐ Search Karma</h2>
|
|
10
|
+
<form class="p-form" @submit.prevent="handleSubmit">
|
|
11
|
+
<div class="p-row"><label class="p-label">Avatar Username</label><input class="p-input" v-model="form.username" placeholder="Search by username" /></div>
|
|
12
|
+
<div class="p-row">
|
|
13
|
+
<label class="p-label">Provider</label>
|
|
14
|
+
<select class="p-input" v-model="form.provider">
|
|
15
|
+
<option>All</option><option>Holochain</option><option>Ethereum</option><option>IPFS</option>
|
|
16
|
+
</select>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="p-actions"><button class="p-btn-cancel" type="button" @click="emit('close')">Cancel</button><button class="p-btn" type="submit">Search</button></div>
|
|
19
|
+
</form>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
<style scoped>
|
|
23
|
+
.p-shell{display:flex;flex-direction:column;gap:20px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-form{display:flex;flex-direction:column;gap:14px}.p-row{display:flex;flex-direction:column;gap:6px}.p-label{font-size:12px;color:#7a9bbf;font-weight:600;letter-spacing:.05em}.p-input{background:rgba(255,255,255,.06);border:1px solid rgba(0,200,255,.2);border-radius:8px;color:#fff;font-size:14px;padding:10px 12px;width:100%;box-sizing:border-box;outline:none;transition:border-color .2s}.p-input:focus{border-color:rgba(0,200,255,.5)}.p-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:4px}.p-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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}.p-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;letter-spacing:.08em;padding:10px 24px;cursor:pointer}
|
|
24
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{ username?: string; karma?: number; level?: string; positive?: number; negative?: number }>()
|
|
3
|
+
const emit = defineEmits<{ close: [] }>()
|
|
4
|
+
</script>
|
|
5
|
+
<template>
|
|
6
|
+
<div class="p-shell">
|
|
7
|
+
<div class="p-icon">⭐</div>
|
|
8
|
+
<h2 class="p-title">{{ username ?? 'Avatar' }} Karma</h2>
|
|
9
|
+
<div class="p-stats">
|
|
10
|
+
<div class="p-stat p-stat--main"><span class="p-stat-label">Total Karma</span><span class="p-stat-value p-stat-value--gold">{{ karma ?? 0 }}</span></div>
|
|
11
|
+
<div class="p-stat"><span class="p-stat-label">Level</span><span class="p-stat-value">{{ level ?? 'Initiate' }}</span></div>
|
|
12
|
+
<div class="p-stat"><span class="p-stat-label">Positive</span><span class="p-stat-value p-stat-value--pos">+{{ positive ?? 0 }}</span></div>
|
|
13
|
+
<div class="p-stat"><span class="p-stat-label">Negative</span><span class="p-stat-value p-stat-value--neg">-{{ negative ?? 0 }}</span></div>
|
|
14
|
+
</div>
|
|
15
|
+
<button class="p-btn" @click="emit('close')">Close</button>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
<style scoped>
|
|
19
|
+
.p-shell{display:flex;flex-direction:column;align-items:center;gap:18px;padding:32px 20px;text-align:center}.p-icon{font-size:50px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%;max-width:340px}.p-stat{background:rgba(255,255,255,.04);border:1px solid rgba(0,200,255,.15);border-radius:10px;padding:12px 16px;display:flex;flex-direction:column;gap:4px}.p-stat--main{grid-column:span 2}.p-stat-label{font-size:11px;color:#7a9bbf;font-weight:600;letter-spacing:.08em;text-transform:uppercase}.p-stat-value{font-family:'Orbitron',sans-serif;font-size:20px;color:#fff;font-weight:700}.p-stat-value--gold{color:#ffb43c}.p-stat-value--pos{color:#00e676;font-size:16px}.p-stat-value--neg{color:#ff4444;font-size:16px}.p-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:11px 28px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}
|
|
20
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const emit = defineEmits<{ close: [] }>()
|
|
3
|
+
const entries = [
|
|
4
|
+
{ date: '2024-01-10', action: 'Completed Quest', amount: '+50', total: '550' },
|
|
5
|
+
{ date: '2024-01-08', action: 'Helped Avatar', amount: '+20', total: '500' },
|
|
6
|
+
{ date: '2024-01-05', action: 'Joined League', amount: '+30', total: '480' },
|
|
7
|
+
{ date: '2024-01-01', action: 'Welcome bonus', amount: '+100', total: '100' },
|
|
8
|
+
]
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<div class="p-shell">
|
|
12
|
+
<h2 class="p-title">⭐ Karma Log</h2>
|
|
13
|
+
<div class="p-table-wrap">
|
|
14
|
+
<table class="p-table">
|
|
15
|
+
<thead><tr><th>Date</th><th>Action</th><th>Amount</th><th>Total</th></tr></thead>
|
|
16
|
+
<tbody>
|
|
17
|
+
<tr v-for="(e, i) in entries" :key="i">
|
|
18
|
+
<td>{{ e.date }}</td><td>{{ e.action }}</td>
|
|
19
|
+
<td :class="e.amount.startsWith('+') ? 'pos' : 'neg'">{{ e.amount }}</td>
|
|
20
|
+
<td>{{ e.total }}</td>
|
|
21
|
+
</tr>
|
|
22
|
+
</tbody>
|
|
23
|
+
</table>
|
|
24
|
+
</div>
|
|
25
|
+
<button class="p-btn" @click="emit('close')">Close</button>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
<style scoped>
|
|
29
|
+
.p-shell{display:flex;flex-direction:column;gap:18px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-table-wrap{overflow-x:auto;border-radius:10px;border:1px solid rgba(0,200,255,.15)}.p-table{width:100%;border-collapse:collapse;font-size:13px}.p-table th{background:rgba(0,200,255,.08);color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;letter-spacing:.06em;padding:10px 12px;text-align:left}.p-table td{color:#c8dff0;padding:9px 12px;border-top:1px solid rgba(255,255,255,.05)}.p-table tr:hover td{background:rgba(0,200,255,.04)}.pos{color:#00e676;font-weight:700}.neg{color:#ff4444;font-weight:700}.p-btn{align-self:flex-end;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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}
|
|
30
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
const emit = defineEmits<{ close: []; submit: [{ username: string; vote: 'positive' | 'negative'; reason: string }] }>()
|
|
4
|
+
const form = ref({ username: '', vote: 'positive' as 'positive' | 'negative', reason: '' })
|
|
5
|
+
function handleSubmit() { emit('submit', { ...form.value }) }
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<div class="p-shell">
|
|
9
|
+
<h2 class="p-title">🗳️ Vote Karma</h2>
|
|
10
|
+
<form class="p-form" @submit.prevent="handleSubmit">
|
|
11
|
+
<div class="p-row"><label class="p-label">Avatar Username</label><input class="p-input" v-model="form.username" placeholder="Who are you voting for?" /></div>
|
|
12
|
+
<div class="p-row">
|
|
13
|
+
<label class="p-label">Vote</label>
|
|
14
|
+
<div class="p-vote-btns">
|
|
15
|
+
<button type="button" class="p-vote" :class="{ 'p-vote--active-pos': form.vote === 'positive' }" @click="form.vote = 'positive'">👍 Positive</button>
|
|
16
|
+
<button type="button" class="p-vote" :class="{ 'p-vote--active-neg': form.vote === 'negative' }" @click="form.vote = 'negative'">👎 Negative</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="p-row"><label class="p-label">Reason</label><textarea class="p-textarea" v-model="form.reason" placeholder="Why are you voting this way?"></textarea></div>
|
|
20
|
+
<div class="p-actions"><button class="p-btn-cancel" type="button" @click="emit('close')">Cancel</button><button class="p-btn" type="submit">Submit Vote</button></div>
|
|
21
|
+
</form>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
<style scoped>
|
|
25
|
+
.p-shell{display:flex;flex-direction:column;gap:20px;padding:24px 20px}.p-title{font-family:'Orbitron',sans-serif;font-size:18px;color:#fff;margin:0}.p-form{display:flex;flex-direction:column;gap:14px}.p-row{display:flex;flex-direction:column;gap:6px}.p-label{font-size:12px;color:#7a9bbf;font-weight:600;letter-spacing:.05em}.p-input,.p-textarea{background:rgba(255,255,255,.06);border:1px solid rgba(0,200,255,.2);border-radius:8px;color:#fff;font-size:14px;padding:10px 12px;width:100%;box-sizing:border-box;outline:none;transition:border-color .2s}.p-input:focus,.p-textarea:focus{border-color:rgba(0,200,255,.5)}.p-textarea{min-height:80px;resize:vertical}.p-vote-btns{display:flex;gap:10px}.p-vote{flex:1;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.15);border-radius:8px;color:#a8bfd8;font-size:13px;font-weight:600;padding:10px;cursor:pointer;transition:all .2s}.p-vote--active-pos{background:rgba(0,230,118,.12);border-color:rgba(0,230,118,.4);color:#00e676}.p-vote--active-neg{background:rgba(255,68,68,.12);border-color:rgba(255,68,68,.4);color:#ff4444}.p-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:4px}.p-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 24px;cursor:pointer;transition:opacity .2s}.p-btn:hover{opacity:.85}.p-btn-cancel{background:transparent;border:1px solid rgba(0,200,255,.3);border-radius:8px;color:#00c8ff;font-family:'Orbitron',sans-serif;font-size:12px;font-weight:700;letter-spacing:.08em;padding:10px 24px;cursor:pointer}
|
|
26
|
+
</style>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import { useOasis } from '../../../composables/useOasis'
|
|
4
|
+
|
|
5
|
+
const { session } = useOasis()
|
|
6
|
+
const activeTab = ref<'records' | 'stats' | 'weightings'>('records')
|
|
7
|
+
const level = computed(() => Math.floor(Math.sqrt((session.value?.karma ?? 0) / 100)) + 1)
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
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' }" @click="activeTab = 'records'">Akashic Records</button>
|
|
29
|
+
<button class="kp-tab" :class="{ 'kp-tab--active': activeTab === 'stats' }" @click="activeTab = 'stats'">Stats</button>
|
|
30
|
+
<button class="kp-tab" :class="{ 'kp-tab--active': activeTab === 'weightings' }" @click="activeTab = 'weightings'">Weightings</button>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div v-if="activeTab === 'records'" class="kp-panel kp-empty">
|
|
34
|
+
<div class="kp-empty-icon">📜</div>
|
|
35
|
+
<p>No karma records found.<br>Complete actions in the OASIS ecosystem to build your Akashic Record.</p>
|
|
36
|
+
</div>
|
|
37
|
+
<div v-else-if="activeTab === 'stats'" class="kp-panel kp-empty">
|
|
38
|
+
<div class="kp-empty-icon">📊</div>
|
|
39
|
+
<p>No stats available yet.</p>
|
|
40
|
+
</div>
|
|
41
|
+
<div v-else class="kp-panel">
|
|
42
|
+
<div class="kp-vote-banner">
|
|
43
|
+
<div>
|
|
44
|
+
<strong>Karma Voting</strong>
|
|
45
|
+
<p>Community voting to adjust karma weightings is coming soon.</p>
|
|
46
|
+
</div>
|
|
47
|
+
<button class="kp-btn-ghost">Vote on Weightings <span class="kp-soon">Coming Soon</span></button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<style scoped>
|
|
54
|
+
.kp-shell { color:#fff; display:flex; flex-direction:column; gap:20px; }
|
|
55
|
+
.kp-banner { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; }
|
|
56
|
+
.kp-stat { background:rgba(0,200,255,.06); border:1px solid rgba(0,200,255,.12); border-radius:10px; padding:14px; text-align:center; }
|
|
57
|
+
.kp-stat-label { font-size:10px; font-weight:700; letter-spacing:.1em; color:#7a9bbf; text-transform:uppercase; margin-bottom:6px; }
|
|
58
|
+
.kp-stat-value { font-family:'Orbitron',sans-serif; font-size:22px; color:#00c8ff; }
|
|
59
|
+
.kp-stat-value--level { color:#a78bfa; }
|
|
60
|
+
.kp-stat-value--type { color:#48dc82; font-size:16px; }
|
|
61
|
+
.kp-tabs { display:flex; gap:4px; border-bottom:1px solid rgba(0,200,255,.12); }
|
|
62
|
+
.kp-tab { background:none; border:none; color:#7a9bbf; font-size:13px; padding:10px 16px; cursor:pointer; border-bottom:2px solid transparent; transition:all .2s; }
|
|
63
|
+
.kp-tab--active { color:#00c8ff; border-bottom-color:#00c8ff; }
|
|
64
|
+
.kp-panel { padding:16px 0; }
|
|
65
|
+
.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; }
|
|
66
|
+
.kp-empty-icon { font-size:32px; }
|
|
67
|
+
.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; }
|
|
68
|
+
.kp-vote-banner strong { display:block; color:#fff; margin-bottom:4px; }
|
|
69
|
+
.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; }
|
|
70
|
+
.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; }
|
|
71
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Transition name="toast">
|
|
3
|
+
<div v-if="karmaToast" class="karma-toast">
|
|
4
|
+
<span class="kt-amount">+{{ karmaToast.amount }} ✦</span>
|
|
5
|
+
<span class="kt-msg">{{ karmaToast.message }}</span>
|
|
6
|
+
</div>
|
|
7
|
+
</Transition>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import { useOasis } from '../../../composables/useOasis'
|
|
12
|
+
const { karmaToast } = useOasis()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<style scoped>
|
|
16
|
+
.karma-toast {
|
|
17
|
+
position: fixed; bottom: 32px; right: 32px; z-index: 9999;
|
|
18
|
+
background: linear-gradient(135deg, rgba(0,232,124,.15), rgba(0,100,60,.1));
|
|
19
|
+
border: 1px solid rgba(0,232,124,.4); border-radius: 14px;
|
|
20
|
+
padding: 16px 24px; display: flex; flex-direction: column; gap: 4px;
|
|
21
|
+
backdrop-filter: blur(12px);
|
|
22
|
+
}
|
|
23
|
+
.kt-amount { font-family: 'Orbitron', sans-serif; font-size: 22px; font-weight: 900; color: #00e87c; }
|
|
24
|
+
.kt-msg { font-family: 'Share Tech Mono', monospace; font-size: 11px; letter-spacing: .1em; color: #a8bfd8; }
|
|
25
|
+
.toast-enter-active { transition: all .35s ease; }
|
|
26
|
+
.toast-leave-active { transition: all .3s ease; }
|
|
27
|
+
.toast-enter-from { transform: translateY(20px); opacity: 0; }
|
|
28
|
+
.toast-leave-to { transform: translateY(20px); opacity: 0; }
|
|
29
|
+
</style>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { useOasis } from '../../../composables/useOasis'
|
|
4
|
+
|
|
5
|
+
const emit = defineEmits<{ switchTo: [view: 'signup' | 'forgot']; loggedIn: [] }>()
|
|
6
|
+
|
|
7
|
+
const { login } = useOasis()
|
|
8
|
+
|
|
9
|
+
const username = ref('')
|
|
10
|
+
const password = ref('')
|
|
11
|
+
const rememberMe = ref(false)
|
|
12
|
+
const showPwd = ref(false)
|
|
13
|
+
const loading = ref(false)
|
|
14
|
+
const error = ref('')
|
|
15
|
+
|
|
16
|
+
async function submit() {
|
|
17
|
+
if (!username.value || !password.value) { error.value = 'Please fill in all fields.'; return }
|
|
18
|
+
loading.value = true
|
|
19
|
+
error.value = ''
|
|
20
|
+
try {
|
|
21
|
+
await login(username.value, password.value)
|
|
22
|
+
emit('loggedIn')
|
|
23
|
+
} catch (e: any) {
|
|
24
|
+
error.value = e?.message ?? 'Login failed. Please check your credentials.'
|
|
25
|
+
} finally {
|
|
26
|
+
loading.value = false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div class="oasis-auth-form">
|
|
33
|
+
<div class="oasis-auth-header">
|
|
34
|
+
<h2 class="oasis-auth-title">Beam In</h2>
|
|
35
|
+
<p class="oasis-auth-sub">
|
|
36
|
+
Don't have an account?
|
|
37
|
+
<a class="oasis-link" href="#" @click.prevent="emit('switchTo', 'signup')">Sign Up</a>
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div v-if="error" class="oasis-auth-error">{{ error }}</div>
|
|
42
|
+
|
|
43
|
+
<div class="oasis-field">
|
|
44
|
+
<label class="oasis-label" for="oasis-login-username">Username</label>
|
|
45
|
+
<input class="oasis-input" id="oasis-login-username" type="text" v-model="username" placeholder="yourusername" autocomplete="username" />
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="oasis-field">
|
|
49
|
+
<label class="oasis-label" for="oasis-login-password">Password</label>
|
|
50
|
+
<div class="oasis-input-wrap">
|
|
51
|
+
<input class="oasis-input" id="oasis-login-password" :type="showPwd ? 'text' : 'password'" v-model="password" placeholder="••••••••" autocomplete="current-password" />
|
|
52
|
+
<button class="oasis-pwd-toggle" type="button" @click="showPwd = !showPwd" :aria-label="showPwd ? 'Hide password' : 'Show password'">
|
|
53
|
+
{{ showPwd ? '🙈' : '👁️' }}
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
<a class="oasis-link oasis-link--small" href="#" @click.prevent="emit('switchTo', 'forgot')">Forgot Password?</a>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="oasis-field oasis-field--row">
|
|
60
|
+
<input class="oasis-checkbox" id="oasis-remember" type="checkbox" v-model="rememberMe" />
|
|
61
|
+
<label class="oasis-label oasis-label--inline" for="oasis-remember">Remember Me</label>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<button class="oasis-btn" type="button" :disabled="loading" @click="submit">
|
|
65
|
+
{{ loading ? 'Connecting…' : 'Beam In' }}
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<style scoped>
|
|
71
|
+
.oasis-auth-form { display:flex; flex-direction:column; gap:20px; }
|
|
72
|
+
.oasis-auth-header { text-align:center; }
|
|
73
|
+
.oasis-auth-title { font-family:'Orbitron',sans-serif; font-size:22px; color:#fff; margin:0 0 6px; }
|
|
74
|
+
.oasis-auth-sub { font-size:13px; color:#7a9bbf; margin:0; }
|
|
75
|
+
.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; }
|
|
76
|
+
.oasis-field { display:flex; flex-direction:column; gap:6px; }
|
|
77
|
+
.oasis-field--row { flex-direction:row; align-items:center; gap:10px; }
|
|
78
|
+
.oasis-label { font-size:12px; font-weight:600; letter-spacing:.06em; color:#7a9bbf; text-transform:uppercase; }
|
|
79
|
+
.oasis-label--inline { text-transform:none; font-size:13px; color:#a8bfd8; }
|
|
80
|
+
.oasis-input-wrap { position:relative; }
|
|
81
|
+
.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; }
|
|
82
|
+
.oasis-input:focus { border-color:rgba(0,200,255,.5); }
|
|
83
|
+
.oasis-input-wrap .oasis-input { padding-right:44px; }
|
|
84
|
+
.oasis-pwd-toggle { position:absolute; right:10px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; font-size:16px; padding:0; line-height:1; }
|
|
85
|
+
.oasis-checkbox { width:16px; height:16px; accent-color:#00c8ff; cursor:pointer; flex-shrink:0; }
|
|
86
|
+
.oasis-link { color:#00c8ff; text-decoration:none; cursor:pointer; }
|
|
87
|
+
.oasis-link--small { font-size:12px; margin-top:2px; }
|
|
88
|
+
.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; }
|
|
89
|
+
.oasis-btn:disabled { opacity:.5; cursor:not-allowed; }
|
|
90
|
+
</style>
|