@oasisomniverse/react 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.
Files changed (139) hide show
  1. package/README.md +69 -0
  2. package/package.json +72 -0
  3. package/src/components/App.js +504 -0
  4. package/src/components/ForgetPassword.js +126 -0
  5. package/src/components/Login.js +222 -0
  6. package/src/components/ResetPassword.js +176 -0
  7. package/src/components/Signup.js +285 -0
  8. package/src/components/VerifyEmail.js +68 -0
  9. package/src/components/common/AvatarConnect.jsx +89 -0
  10. package/src/components/common/Contact.jsx +60 -0
  11. package/src/components/common/Eggs.jsx +50 -0
  12. package/src/components/common/Game.jsx +36 -0
  13. package/src/components/common/HyperDrive.jsx +50 -0
  14. package/src/components/common/KarmaToast.jsx +38 -0
  15. package/src/components/common/Map.jsx +42 -0
  16. package/src/components/common/MenuMessage.jsx +70 -0
  17. package/src/components/common/Messaging.jsx +74 -0
  18. package/src/components/common/Mission.jsx +40 -0
  19. package/src/components/common/NFT.jsx +42 -0
  20. package/src/components/common/NavBar.jsx +52 -0
  21. package/src/components/common/Navbar.js +137 -0
  22. package/src/components/common/OApp.jsx +41 -0
  23. package/src/components/common/ONET.jsx +50 -0
  24. package/src/components/common/ONODE.jsx +49 -0
  25. package/src/components/common/OasisModal.css +9 -0
  26. package/src/components/common/OasisModal.jsx +29 -0
  27. package/src/components/common/ProviderDropdown.js +25 -0
  28. package/src/components/common/ProviderDropdown.jsx +61 -0
  29. package/src/components/common/Providers.jsx +38 -0
  30. package/src/components/common/Quest.jsx +40 -0
  31. package/src/components/common/SearchAvatars.jsx +49 -0
  32. package/src/components/common/Seeds.jsx +39 -0
  33. package/src/components/common/Settings.jsx +70 -0
  34. package/src/components/common/StarField.jsx +56 -0
  35. package/src/components/common/Wallet.jsx +45 -0
  36. package/src/components/common/message/MessageContacts.jsx +66 -0
  37. package/src/components/common/message/Messages.jsx +75 -0
  38. package/src/components/common/sidebar/Sidebar.jsx +27 -0
  39. package/src/components/common/sidebar/SidebarData.js +615 -0
  40. package/src/components/common/sidebar/SidebarMenuItem.jsx +79 -0
  41. package/src/components/index.js +26 -0
  42. package/src/components/pages/forgotPassword.js +47 -0
  43. package/src/components/popups/avatar/components/AvatarWallet.jsx +169 -0
  44. package/src/components/popups/avatar/components/EditAvatar.jsx +34 -0
  45. package/src/components/popups/avatar/components/SearchAvatar.jsx +34 -0
  46. package/src/components/popups/avatar/components/ViewAvatar.jsx +148 -0
  47. package/src/components/popups/avatar/index.jsx +39 -0
  48. package/src/components/popups/comingsoon/ComingSoon.jsx +28 -0
  49. package/src/components/popups/confirmation/Confirmation.js +30 -0
  50. package/src/components/popups/contact/index.js +100 -0
  51. package/src/components/popups/data-screen/components/AddData.jsx +89 -0
  52. package/src/components/popups/data-screen/components/CrossChainManagement.jsx +87 -0
  53. package/src/components/popups/data-screen/components/LoadData.jsx +157 -0
  54. package/src/components/popups/data-screen/components/ManageData.jsx +34 -0
  55. package/src/components/popups/data-screen/components/OffChainManagement.jsx +177 -0
  56. package/src/components/popups/data-screen/components/SearchData.jsx +34 -0
  57. package/src/components/popups/data-screen/index.jsx +52 -0
  58. package/src/components/popups/eggs/components/ManageEggs.jsx +34 -0
  59. package/src/components/popups/eggs/components/SearchEggs.jsx +34 -0
  60. package/src/components/popups/eggs/components/ViewEggs.jsx +34 -0
  61. package/src/components/popups/eggs/index.jsx +31 -0
  62. package/src/components/popups/game/components/SearchProfiles.jsx +34 -0
  63. package/src/components/popups/game/components/ViewAchievements.jsx +34 -0
  64. package/src/components/popups/game/components/ViewLeagues.jsx +34 -0
  65. package/src/components/popups/game/components/ViewTournaments.jsx +34 -0
  66. package/src/components/popups/game/index.jsx +38 -0
  67. package/src/components/popups/karma/components/SearchKarma.jsx +34 -0
  68. package/src/components/popups/karma/components/ViewAvatarKarma.jsx +139 -0
  69. package/src/components/popups/karma/components/ViewKarma.jsx +103 -0
  70. package/src/components/popups/karma/components/VoteKarma.jsx +34 -0
  71. package/src/components/popups/karma/index.jsx +34 -0
  72. package/src/components/popups/map/components/Add2dObjectMap.jsx +34 -0
  73. package/src/components/popups/map/components/Add3dObjectMap.jsx +34 -0
  74. package/src/components/popups/map/components/AddQuestToMap.jsx +34 -0
  75. package/src/components/popups/map/components/DownloadOurWorld.jsx +34 -0
  76. package/src/components/popups/map/components/ManageMap.jsx +34 -0
  77. package/src/components/popups/map/components/PlotRouteOnMap.jsx +34 -0
  78. package/src/components/popups/map/components/SearchMap.jsx +34 -0
  79. package/src/components/popups/map/components/ViewGlobal3dMap.jsx +34 -0
  80. package/src/components/popups/map/components/ViewHalonsOnMap.jsx +34 -0
  81. package/src/components/popups/map/components/ViewOappOnMap.jsx +34 -0
  82. package/src/components/popups/map/components/ViewQuestOnMap.jsx +34 -0
  83. package/src/components/popups/map/index.jsx +79 -0
  84. package/src/components/popups/messages/Message.jsx +86 -0
  85. package/src/components/popups/mission/components/ManageMission.jsx +34 -0
  86. package/src/components/popups/mission/components/SearchMission.jsx +34 -0
  87. package/src/components/popups/mission/components/ViewMission.jsx +34 -0
  88. package/src/components/popups/mission/index.jsx +32 -0
  89. package/src/components/popups/nft/ContactPopup.jsx +146 -0
  90. package/src/components/popups/nft/Solana.jsx +70 -0
  91. package/src/components/popups/nft/components/ManageOasisNft.jsx +34 -0
  92. package/src/components/popups/nft/components/PurchaseOasisNft.jsx +34 -0
  93. package/src/components/popups/nft/components/PurchaseOasisVirtualLandNft.jsx +34 -0
  94. package/src/components/popups/nft/components/SearchOasisNft.jsx +34 -0
  95. package/src/components/popups/nft/components/ViewOasisNft.jsx +34 -0
  96. package/src/components/popups/nft/index.jsx +45 -0
  97. package/src/components/popups/oapp/components/CreateOAPP.jsx +34 -0
  98. package/src/components/popups/oapp/components/DeployOAPP.jsx +34 -0
  99. package/src/components/popups/oapp/components/DownloadOurWorld.jsx +34 -0
  100. package/src/components/popups/oapp/components/EditOAPP.jsx +34 -0
  101. package/src/components/popups/oapp/components/InstallOAPP.jsx +34 -0
  102. package/src/components/popups/oapp/components/LaunchOAPP.jsx +34 -0
  103. package/src/components/popups/oapp/components/ManageOAPP.jsx +68 -0
  104. package/src/components/popups/oapp/components/SearchOAPP.jsx +34 -0
  105. package/src/components/popups/oapp/index.jsx +62 -0
  106. package/src/components/popups/provider/components/ActivityPub.jsx +34 -0
  107. package/src/components/popups/provider/components/CompareProviderSpeeds.jsx +123 -0
  108. package/src/components/popups/provider/components/Eosio.jsx +34 -0
  109. package/src/components/popups/provider/components/Ethereum.jsx +34 -0
  110. package/src/components/popups/provider/components/Holochain.jsx +34 -0
  111. package/src/components/popups/provider/components/Ipfs.jsx +35 -0
  112. package/src/components/popups/provider/components/ManageAutoFailOver.jsx +34 -0
  113. package/src/components/popups/provider/components/ManageAutoReplicaton.jsx +34 -0
  114. package/src/components/popups/provider/components/ManageLoadBalancing.jsx +34 -0
  115. package/src/components/popups/provider/components/ManageProviders.jsx +34 -0
  116. package/src/components/popups/provider/components/MongoDb.jsx +34 -0
  117. package/src/components/popups/provider/components/Neo4j.jsx +34 -0
  118. package/src/components/popups/provider/components/SearchProviders.jsx +122 -0
  119. package/src/components/popups/provider/components/Seeds.jsx +34 -0
  120. package/src/components/popups/provider/components/Solid.jsx +34 -0
  121. package/src/components/popups/provider/components/SqlLite.jsx +34 -0
  122. package/src/components/popups/provider/components/ThreeFold.jsx +34 -0
  123. package/src/components/popups/provider/components/ViewProviderStats.jsx +123 -0
  124. package/src/components/popups/provider/components/ViewProviders.jsx +121 -0
  125. package/src/components/popups/provider/index.jsx +113 -0
  126. package/src/components/popups/quest/components/ManageQuest.jsx +34 -0
  127. package/src/components/popups/quest/components/SearchQuest.jsx +34 -0
  128. package/src/components/popups/quest/components/ViewQuest.jsx +34 -0
  129. package/src/components/popups/quest/index.jsx +32 -0
  130. package/src/components/popups/seeds/components/AcceptInvite.jsx +61 -0
  131. package/src/components/popups/seeds/components/DonateSeeds.jsx +178 -0
  132. package/src/components/popups/seeds/components/ManageSeeds.jsx +34 -0
  133. package/src/components/popups/seeds/components/PayWithSeeds.jsx +233 -0
  134. package/src/components/popups/seeds/components/RewardSeeds.jsx +178 -0
  135. package/src/components/popups/seeds/components/SearchSeeds.jsx +91 -0
  136. package/src/components/popups/seeds/components/SendInvite.jsx +178 -0
  137. package/src/components/popups/seeds/components/ViewOrganizations.jsx +178 -0
  138. package/src/components/popups/seeds/components/ViewSeeds.jsx +221 -0
  139. package/src/components/popups/seeds/index.jsx +70 -0
@@ -0,0 +1,49 @@
1
+ import { useState } from 'react';
2
+
3
+ const METRICS = [{ label: 'CPU', value: '18%' }, { label: 'RAM', value: '2.1 GB' }, { label: 'Storage', value: '47 GB' }, { label: 'Blocks', value: '12,450' }];
4
+ const LOGS = [
5
+ { time: '09:42:01', level: 'info', message: 'ONODE started. Connecting to ONET…' },
6
+ { time: '09:42:02', level: 'info', message: 'Connected to 12 peers.' },
7
+ { time: '09:42:05', level: 'info', message: 'Block #12450 validated.' },
8
+ { time: '09:42:08', level: 'warn', message: 'Peer ONODE-77 latency high: 340ms.' },
9
+ { time: '09:42:12', level: 'info', message: 'Data sync complete. 100% coverage.' },
10
+ ];
11
+ const LOG_COLORS = { info: '#00c8ff', warn: '#ffb43c', error: '#ff6b6b' };
12
+
13
+ export function ONODE() {
14
+ const [running, setRunning] = useState(false);
15
+ return (
16
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
17
+ <div style={{ textAlign: 'center' }}>
18
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>🖥️ ONODE</h2>
19
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Your personal OASIS node. Store, validate, and relay data.</p>
20
+ </div>
21
+ <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
22
+ <div style={{ flex: 1, background: 'rgba(255,255,255,.04)', border: `1px solid ${running ? 'rgba(72,220,130,.3)' : 'rgba(255,80,80,.2)'}`, borderRadius: 8, padding: '10px 14px', fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: running ? '#48dc82' : '#ff6b6b' }}>{running ? '● Running' : '○ Stopped'}</div>
23
+ <button onClick={() => setRunning(r => !r)} style={{ background: running ? 'rgba(255,80,80,.2)' : 'linear-gradient(135deg,#00c8ff,#0080ff)', border: running ? '1px solid rgba(255,80,80,.35)' : 'none', borderRadius: 8, color: running ? '#ff6b6b' : '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 12, fontWeight: 700, letterSpacing: '.08em', padding: '10px 20px', cursor: 'pointer' }}>{running ? 'Stop Node' : 'Start Node'}</button>
24
+ </div>
25
+ {running && (
26
+ <>
27
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 10 }}>
28
+ {METRICS.map(m => (
29
+ <div key={m.label} style={{ background: 'rgba(255,255,255,.04)', border: '1px solid rgba(0,200,255,.1)', borderRadius: 10, padding: 12, textAlign: 'center' }}>
30
+ <div style={{ fontFamily: "'Share Tech Mono',monospace", fontSize: 16, color: '#00c8ff', fontWeight: 600 }}>{m.value}</div>
31
+ <div style={{ fontSize: 10, color: '#7a9bbf', marginTop: 4, textTransform: 'uppercase', letterSpacing: '.06em' }}>{m.label}</div>
32
+ </div>
33
+ ))}
34
+ </div>
35
+ <div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 12, color: '#7a9bbf', letterSpacing: '.06em', textTransform: 'uppercase' }}>Node Logs</div>
36
+ <div style={{ background: '#020a14', border: '1px solid rgba(0,200,255,.1)', borderRadius: 8, padding: 12, display: 'flex', flexDirection: 'column', gap: 5, maxHeight: 160, overflowY: 'auto', fontFamily: "'Share Tech Mono',monospace" }}>
37
+ {LOGS.map(l => (
38
+ <div key={l.time} style={{ display: 'flex', gap: 10, fontSize: 11 }}>
39
+ <span style={{ color: '#4a6a88', flexShrink: 0 }}>{l.time}</span>
40
+ <span style={{ color: LOG_COLORS[l.level] }}>[{l.level.toUpperCase()}]</span>
41
+ <span style={{ color: '#7a9bbf' }}>{l.message}</span>
42
+ </div>
43
+ ))}
44
+ </div>
45
+ </>
46
+ )}
47
+ </div>
48
+ );
49
+ }
@@ -0,0 +1,9 @@
1
+ .oasis-modal-backdrop{position:fixed;inset:0;background:rgba(3,7,20,.75);backdrop-filter:blur(6px);display:flex;align-items:center;justify-content:center;z-index:9999;animation:oasisFadeIn .25s ease}
2
+ .oasis-modal-box{background:#0d1829;border:1px solid rgba(0,200,255,.18);border-radius:16px;padding:28px;width:min(520px,92vw);max-height:88vh;overflow-y:auto;animation:oasisSlideUp .25s ease}
3
+ .oasis-modal-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px;border-bottom:1px solid;margin-bottom:20px}
4
+ .oasis-modal-title{font-family:'Orbitron',sans-serif;font-size:15px;font-weight:700;letter-spacing:.06em}
5
+ .oasis-modal-close{background:none;border:none;color:#7a9bbf;font-size:18px;cursor:pointer;padding:0;line-height:1}
6
+ .oasis-modal-close:hover{color:#fff}
7
+ .oasis-modal-body{color:#a8bfd8;font-size:14px;line-height:1.6}
8
+ @keyframes oasisFadeIn{from{opacity:0}to{opacity:1}}
9
+ @keyframes oasisSlideUp{from{transform:translateY(16px);opacity:0}to{transform:none;opacity:1}}
@@ -0,0 +1,29 @@
1
+ import React, { useEffect } from 'react';
2
+ import './OasisModal.css';
3
+
4
+ export default function OasisModal({ open, onClose, title, accentColor = '#00c8ff', children }) {
5
+ useEffect(() => {
6
+ if (!open) return;
7
+ const onKey = e => { if (e.key === 'Escape') onClose?.(); };
8
+ document.addEventListener('keydown', onKey);
9
+ document.body.style.overflow = 'hidden';
10
+ return () => {
11
+ document.removeEventListener('keydown', onKey);
12
+ document.body.style.overflow = '';
13
+ };
14
+ }, [open, onClose]);
15
+
16
+ if (!open) return null;
17
+
18
+ return (
19
+ <div className="oasis-modal-backdrop" onClick={e => { if (e.target === e.currentTarget) onClose?.(); }}>
20
+ <div className="oasis-modal-box" role="dialog" aria-modal="true">
21
+ <div className="oasis-modal-header" style={{ borderBottomColor: accentColor + '33' }}>
22
+ <span className="oasis-modal-title" style={{ color: accentColor }}>{title}</span>
23
+ <button className="oasis-modal-close" onClick={onClose} aria-label="Close">&#x2715;</button>
24
+ </div>
25
+ <div className="oasis-modal-body">{children}</div>
26
+ </div>
27
+ </div>
28
+ );
29
+ }
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ class ProviderDropdown extends React.Component {
3
+ state = { }
4
+ render() {
5
+ return (
6
+ <>
7
+ <p className="single-form-row">
8
+ <label>Provider: </label>
9
+ <span className="have-selectbox">
10
+ <select className="custom-selectbox">
11
+ <option>EOSIO</option>
12
+ <option>EOSIO - 1</option>
13
+ <option>EOSIO - 2</option>
14
+ </select>
15
+ <i className="fa fa-angle-down"></i>
16
+ </span>
17
+
18
+ <span className="have-icon"></span>
19
+ </p>
20
+ </>
21
+ );
22
+ }
23
+ }
24
+
25
+ export default ProviderDropdown;
@@ -0,0 +1,61 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+
3
+ const PROVIDERS = [
4
+ { id: 'ethereum', name: 'Ethereum', icon: '⟠', color: '#627eea' },
5
+ { id: 'solana', name: 'Solana', icon: '◎', color: '#9945ff' },
6
+ { id: 'polygon', name: 'Polygon', icon: '⬡', color: '#8247e5' },
7
+ { id: 'arbitrum', name: 'Arbitrum', icon: '🔵', color: '#2d9cdb' },
8
+ { id: 'eosio', name: 'EOSIO', icon: '🔮', color: '#443f54' },
9
+ { id: 'holochain', name: 'Holochain', icon: '⬡', color: '#00e5be' },
10
+ { id: 'thegraph', name: 'The Graph', icon: '📊', color: '#6f4cff' },
11
+ ];
12
+
13
+ /**
14
+ * ProviderDropdown — blockchain provider selector.
15
+ * Props:
16
+ * defaultProvider string — id of default provider
17
+ * onChange fn — called with selected provider object
18
+ */
19
+ export function ProviderDropdown({ defaultProvider = 'ethereum', onChange }) {
20
+ const [selected, setSelected] = useState(() => PROVIDERS.find(p => p.id === defaultProvider) || PROVIDERS[0]);
21
+ const [open, setOpen] = useState(false);
22
+ const ref = useRef(null);
23
+
24
+ useEffect(() => {
25
+ function onDoc(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
26
+ document.addEventListener('mousedown', onDoc);
27
+ return () => document.removeEventListener('mousedown', onDoc);
28
+ }, []);
29
+
30
+ function select(p) { setSelected(p); setOpen(false); onChange?.(p); }
31
+
32
+ return (
33
+ <div ref={ref} style={{ position: 'relative', fontFamily: "'Rajdhani',sans-serif" }}>
34
+ <div
35
+ onClick={() => setOpen(o => !o)}
36
+ style={{ display: 'flex', alignItems: 'center', gap: 10, background: 'rgba(255,255,255,.05)', border: `1px solid ${open ? 'rgba(0,200,255,.5)' : 'rgba(0,200,255,.25)'}`, borderRadius: 10, padding: '10px 14px', cursor: 'pointer', color: '#fff', transition: 'border-color .2s' }}
37
+ >
38
+ <span style={{ fontSize: 20, width: 28, textAlign: 'center', color: selected.color }}>{selected.icon}</span>
39
+ <div style={{ flex: 1 }}>
40
+ <div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, fontWeight: 700 }}>{selected.name}</div>
41
+ <div style={{ fontSize: 11, color: '#7a9bbf', marginTop: 2 }}>Active Provider</div>
42
+ </div>
43
+ <span style={{ fontSize: 10, color: '#7a9bbf', transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .2s', display: 'inline-block' }}>▼</span>
44
+ </div>
45
+ {open && (
46
+ <div style={{ position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0, background: '#0d1b2e', border: '1px solid rgba(0,200,255,.2)', borderRadius: 10, overflow: 'hidden', zIndex: 999, boxShadow: '0 8px 32px rgba(0,0,0,.5)' }}>
47
+ {PROVIDERS.map(p => (
48
+ <div
49
+ key={p.id}
50
+ onClick={() => select(p)}
51
+ style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', cursor: 'pointer', color: '#e0f0ff', background: p.id === selected.id ? 'rgba(0,200,255,.12)' : 'transparent', borderLeft: p.id === selected.id ? '3px solid #00c8ff' : '3px solid transparent', transition: 'background .15s' }}
52
+ >
53
+ <span style={{ fontSize: 18, width: 24, textAlign: 'center', color: p.color }}>{p.icon}</span>
54
+ <span style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 12, fontWeight: 700 }}>{p.name}</span>
55
+ </div>
56
+ ))}
57
+ </div>
58
+ )}
59
+ </div>
60
+ );
61
+ }
@@ -0,0 +1,38 @@
1
+ import { useState } from 'react';
2
+
3
+ const INITIAL = [
4
+ { id: '1', name: 'Ethereum', icon: '⟠', color: '#627eea', type: 'Blockchain', description: 'Connect your Ethereum wallet (MetaMask, WalletConnect).', connected: false },
5
+ { id: '2', name: 'Solana', icon: '◎', color: '#9945ff', type: 'Blockchain', description: 'Connect your Solana wallet (Phantom, Solflare).', connected: false },
6
+ { id: '3', name: 'EOSIO', icon: '🔮', color: '#443f54', type: 'Blockchain', description: 'Connect via EOSIO for high-speed transactions.', connected: false },
7
+ { id: '4', name: 'Holochain', icon: '⬡', color: '#00e5be', type: 'P2P Network', description: 'Peer-to-peer data storage on Holochain.', connected: false },
8
+ { id: '5', name: 'The Graph', icon: '📊', color: '#6f4cff', type: 'Indexer', description: 'Query blockchain data with The Graph protocol.', connected: false },
9
+ ];
10
+
11
+ export function Providers() {
12
+ const [providers, setProviders] = useState(INITIAL);
13
+ function toggle(id) { setProviders(l => l.map(x => x.id === id ? { ...x, connected: !x.connected } : x)); }
14
+ return (
15
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
16
+ <div style={{ textAlign: 'center' }}>
17
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>🔗 Providers</h2>
18
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Connect blockchain providers to your OASIS avatar.</p>
19
+ </div>
20
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
21
+ {providers.map(p => (
22
+ <div key={p.id} style={{ display: 'flex', alignItems: 'center', gap: 14, background: p.connected ? 'rgba(72,220,130,.03)' : 'rgba(255,255,255,.04)', border: `1px solid ${p.connected ? 'rgba(72,220,130,.3)' : 'rgba(0,200,255,.12)'}`, borderRadius: 12, padding: '14px 16px' }}>
23
+ <div style={{ fontSize: 26, flexShrink: 0, color: p.color }}>{p.icon}</div>
24
+ <div style={{ flex: 1 }}>
25
+ <div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: '#fff', marginBottom: 2 }}>{p.name}</div>
26
+ <div style={{ fontSize: 11, color: '#5ba8ff', textTransform: 'uppercase', letterSpacing: '.06em', marginBottom: 4 }}>{p.type}</div>
27
+ <div style={{ fontSize: 12, color: '#7a9bbf' }}>{p.description}</div>
28
+ </div>
29
+ <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, flexShrink: 0 }}>
30
+ <div style={{ width: 8, height: 8, borderRadius: '50%', background: p.connected ? '#48dc82' : '#4a6a88', boxShadow: p.connected ? '0 0 6px #48dc82' : undefined }} />
31
+ <button onClick={() => toggle(p.id)} style={{ background: p.connected ? 'rgba(255,80,80,.15)' : 'linear-gradient(135deg,#00c8ff,#0080ff)', border: p.connected ? '1px solid rgba(255,80,80,.3)' : 'none', borderRadius: 7, color: p.connected ? '#ff6b6b' : '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 10, fontWeight: 700, letterSpacing: '.06em', padding: '7px 14px', cursor: 'pointer', whiteSpace: 'nowrap' }}>{p.connected ? 'Disconnect' : 'Connect'}</button>
32
+ </div>
33
+ </div>
34
+ ))}
35
+ </div>
36
+ </div>
37
+ );
38
+ }
@@ -0,0 +1,40 @@
1
+ import { useState } from 'react';
2
+
3
+ const DIFF_COLORS = { Easy: '#48dc82', Medium: '#ffb43c', Hard: '#ff6b6b', Legendary: '#b87fff' };
4
+ const INITIAL = [
5
+ { id: '1', title: 'Avatar Awakening', description: 'Complete your avatar profile and connect your first provider.', reward: 200, difficulty: 'Easy', accepted: true, completed: true },
6
+ { id: '2', title: 'Karma Seeker', description: 'Earn 1000 karma through good deeds and OASIS contributions.', reward: 500, difficulty: 'Medium', accepted: true, completed: false },
7
+ { id: '3', title: 'The NFT Collector', description: 'Acquire 5 unique NFTs across different categories.', reward: 1000, difficulty: 'Hard', accepted: false, completed: false },
8
+ { id: '4', title: 'Omniverse Explorer', description: 'Visit every major hub location on the OASIS map.', reward: 2500, difficulty: 'Legendary', accepted: false, completed: false },
9
+ ];
10
+
11
+ export function Quest() {
12
+ const [quests, setQuests] = useState(INITIAL);
13
+ function accept(id) { setQuests(l => l.map(x => x.id === id ? { ...x, accepted: true } : x)); }
14
+ function complete(id) { setQuests(l => l.map(x => x.id === id ? { ...x, completed: true } : x)); }
15
+ return (
16
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
17
+ <div style={{ textAlign: 'center' }}>
18
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>⚔️ Quests</h2>
19
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Embark on quests to gain karma and rare rewards.</p>
20
+ </div>
21
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
22
+ {quests.map(q => (
23
+ <div key={q.id} style={{ display: 'flex', gap: 14, alignItems: 'flex-start', background: 'rgba(255,255,255,.04)', border: `1px solid ${q.completed ? 'rgba(72,220,130,.2)' : q.accepted ? 'rgba(0,200,255,.4)' : 'rgba(0,200,255,.12)'}`, borderRadius: 12, padding: 16, opacity: q.completed ? .6 : 1 }}>
24
+ <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '.1em', textTransform: 'uppercase', borderRadius: 999, padding: '4px 10px', border: `1px solid ${DIFF_COLORS[q.difficulty]}44`, color: DIFF_COLORS[q.difficulty], whiteSpace: 'nowrap', flexShrink: 0 }}>{q.difficulty}</div>
25
+ <div style={{ flex: 1 }}>
26
+ <div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: '#fff', marginBottom: 4 }}>{q.title}</div>
27
+ <div style={{ fontSize: 12, color: '#7a9bbf', lineHeight: 1.5, marginBottom: 6 }}>{q.description}</div>
28
+ <div style={{ fontSize: 12, color: '#48dc82', fontWeight: 600 }}>+{q.reward} karma</div>
29
+ </div>
30
+ <div style={{ flexShrink: 0 }}>
31
+ {q.completed ? <div style={{ fontSize: 13, color: '#48dc82', fontWeight: 600 }}>✅ Done</div>
32
+ : !q.accepted ? <button onClick={() => accept(q.id)} style={{ background: 'linear-gradient(135deg,#00c8ff,#0080ff)', border: 'none', borderRadius: 7, color: '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 11, fontWeight: 700, padding: '8px 16px', cursor: 'pointer' }}>Accept Quest</button>
33
+ : <button onClick={() => complete(q.id)} style={{ background: 'linear-gradient(135deg,#48dc82,#00aa55)', border: 'none', borderRadius: 7, color: '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 11, fontWeight: 700, padding: '8px 16px', cursor: 'pointer' }}>Finish</button>}
34
+ </div>
35
+ </div>
36
+ ))}
37
+ </div>
38
+ </div>
39
+ );
40
+ }
@@ -0,0 +1,49 @@
1
+ import { useState } from 'react';
2
+ import { OASISClient } from '@oasisomniverse/web4-api';
3
+
4
+ export function SearchAvatars() {
5
+ const [query, setQuery] = useState('');
6
+ const [loading, setLoading] = useState(false);
7
+ const [error, setError] = useState('');
8
+ const [results, setResults] = useState([]);
9
+ const [searched, setSearched] = useState(false);
10
+
11
+ async function search() {
12
+ if (!query.trim()) return;
13
+ setLoading(true); setError(''); setResults([]); setSearched(false);
14
+ try {
15
+ const oasis = new OASISClient({ baseUrl: 'https://api.web4.oasisomniverse.one' });
16
+ const res = await oasis.avatar?.searchAvatars?.({ searchQuery: query });
17
+ setResults(Array.isArray(res?.result) ? res.result : []);
18
+ setSearched(true);
19
+ } catch (e) { setError(e?.message ?? 'Search failed.'); }
20
+ finally { setLoading(false); }
21
+ }
22
+
23
+ return (
24
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
25
+ <div style={{ textAlign: 'center' }}>
26
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>🔍 Search Avatars</h2>
27
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Find other OASIS avatars by username or name.</p>
28
+ </div>
29
+ <div style={{ display: 'flex', gap: 10 }}>
30
+ <input style={{ flex: 1, background: 'rgba(255,255,255,.05)', border: '1px solid rgba(0,200,255,.2)', borderRadius: 8, padding: '10px 14px', color: '#fff', fontSize: 14, outline: 'none' }} value={query} onChange={e => setQuery(e.target.value)} onKeyDown={e => e.key === 'Enter' && search()} placeholder="Search by username…" />
31
+ <button onClick={search} disabled={loading || !query.trim()} style={{ background: 'linear-gradient(135deg,#00c8ff,#0080ff)', border: 'none', borderRadius: 8, color: '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 12, fontWeight: 700, letterSpacing: '.08em', padding: '10px 20px', cursor: 'pointer', opacity: loading || !query.trim() ? .4 : 1 }}>{loading ? '…' : 'Search'}</button>
32
+ </div>
33
+ {error && <div style={{ background: 'rgba(255,80,80,.12)', border: '1px solid rgba(255,80,80,.3)', color: '#ff6b6b', borderRadius: 8, padding: '10px 14px', fontSize: 13 }}>{error}</div>}
34
+ {results.length > 0 ? (
35
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
36
+ {results.map(a => (
37
+ <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 16px', background: 'rgba(255,255,255,.04)', border: '1px solid rgba(0,200,255,.12)', borderRadius: 10 }}>
38
+ <div style={{ fontSize: 28 }}>👤</div>
39
+ <div style={{ flex: 1 }}><div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: '#fff' }}>{a.username}</div><div style={{ fontSize: 12, color: '#7a9bbf', marginTop: 2 }}>{a.firstName} {a.lastName}</div></div>
40
+ <div style={{ fontSize: 12, color: '#48dc82', fontWeight: 600, whiteSpace: 'nowrap' }}>{a.karma} karma</div>
41
+ </div>
42
+ ))}
43
+ </div>
44
+ ) : searched && !loading ? (
45
+ <div style={{ textAlign: 'center', color: '#4a6a88', fontSize: 14, padding: 24 }}>No avatars found for "{query}".</div>
46
+ ) : null}
47
+ </div>
48
+ );
49
+ }
@@ -0,0 +1,39 @@
1
+ import { useState } from 'react';
2
+
3
+ const RARITY_COLORS = { Common: '#7a9bbf', Rare: '#5ba8ff', Epic: '#b87fff', Legendary: '#ffb43c' };
4
+ const ICONS = { Spiritual: '✨', Health: '💚', Community: '🤝', Knowledge: '📖' };
5
+ const INITIAL = [
6
+ { id: '1', name: 'Wisdom Seed', type: 'Spiritual', rarity: 'Rare', karma: 50, planted: false },
7
+ { id: '2', name: 'Healing Seed', type: 'Health', rarity: 'Common', karma: 20, planted: false },
8
+ { id: '3', name: 'Unity Seed', type: 'Community', rarity: 'Epic', karma: 150, planted: false },
9
+ { id: '4', name: 'Truth Seed', type: 'Knowledge', rarity: 'Legendary', karma: 500, planted: false },
10
+ { id: '5', name: 'Love Seed', type: 'Spiritual', rarity: 'Common', karma: 30, planted: false },
11
+ { id: '6', name: 'Peace Seed', type: 'Community', rarity: 'Rare', karma: 75, planted: false },
12
+ ];
13
+
14
+ export function Seeds() {
15
+ const [seeds, setSeeds] = useState(INITIAL);
16
+ function plant(id) { setSeeds(s => s.map(x => x.id === id ? { ...x, planted: true } : x)); }
17
+ return (
18
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
19
+ <div style={{ textAlign: 'center' }}>
20
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>🌱 Seeds</h2>
21
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Plant seeds to grow your OASIS avatar and earn karma.</p>
22
+ </div>
23
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(160px,1fr))', gap: 16 }}>
24
+ {seeds.map(s => (
25
+ <div key={s.id} style={{ background: s.planted ? 'rgba(72,220,130,.04)' : 'rgba(255,255,255,.04)', border: `1px solid ${s.planted ? 'rgba(72,220,130,.3)' : 'rgba(0,200,255,.15)'}`, borderRadius: 12, padding: '18px 14px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10 }}>
26
+ <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '.1em', textTransform: 'uppercase', borderRadius: 999, padding: '3px 10px', border: `1px solid ${RARITY_COLORS[s.rarity]}44`, color: RARITY_COLORS[s.rarity] }}>{s.rarity}</div>
27
+ <div style={{ fontSize: 36 }}>{ICONS[s.type] ?? '🌱'}</div>
28
+ <div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: '#fff', textAlign: 'center' }}>{s.name}</div>
29
+ <div style={{ fontSize: 11, color: '#7a9bbf' }}>{s.type}</div>
30
+ <div style={{ fontSize: 12, color: '#48dc82', fontWeight: 600 }}>+{s.karma} Karma</div>
31
+ {s.planted
32
+ ? <div style={{ fontSize: 12, color: '#48dc82', fontWeight: 600 }}>🌿 Growing…</div>
33
+ : <button style={{ width: '100%', background: 'linear-gradient(135deg,#00c8ff,#0080ff)', border: 'none', borderRadius: 7, color: '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 11, fontWeight: 700, letterSpacing: '.08em', padding: 8, cursor: 'pointer' }} onClick={() => plant(s.id)}>Plant Seed</button>}
34
+ </div>
35
+ ))}
36
+ </div>
37
+ </div>
38
+ );
39
+ }
@@ -0,0 +1,70 @@
1
+ import { useState } from 'react';
2
+
3
+ const SECTIONS = [
4
+ { icon: '🔔', label: 'Notifications', options: [
5
+ { key: 'notifications', name: 'Enable Notifications', desc: 'Receive alerts for karma, messages and quests.', type: 'toggle' },
6
+ { key: 'sound', name: 'Sound Effects', desc: 'Play sounds for OASIS events.', type: 'toggle' },
7
+ ]},
8
+ { icon: '🎨', label: 'Appearance', options: [
9
+ { key: 'darkMode', name: 'Dark Mode', desc: 'Use the dark space theme.', type: 'toggle' },
10
+ { key: 'theme', name: 'Theme', desc: 'Select your OASIS visual theme.', type: 'select', choices: ['Dark Space', 'Neon City', 'Forest Realm'] },
11
+ ]},
12
+ { icon: '🌐', label: 'Language & Region', options: [
13
+ { key: 'language', name: 'Language', desc: 'Select your preferred language.', type: 'select', choices: ['English', 'Spanish', 'French', 'German', 'Japanese'] },
14
+ { key: 'currency', name: 'Display Currency', desc: 'Currency for prices.', type: 'select', choices: ['ETH', 'SOL', 'USD', 'GBP', 'EUR'] },
15
+ ]},
16
+ { icon: '💾', label: 'Data', options: [
17
+ { key: 'autoSave', name: 'Auto-save Progress', desc: 'Automatically save your OASIS progress.', type: 'toggle' },
18
+ ]},
19
+ ];
20
+
21
+ export function Settings() {
22
+ const [open, setOpen] = useState('');
23
+ const [prefs, setPrefs] = useState({ notifications: true, darkMode: true, sound: false, autoSave: true, language: 'English', theme: 'Dark Space', currency: 'ETH' });
24
+ const [saved, setSaved] = useState(false);
25
+ function togglePref(k) { setPrefs(p => ({ ...p, [k]: !p[k] })); }
26
+ function setPref(k, v) { setPrefs(p => ({ ...p, [k]: v })); }
27
+ function save() { setSaved(true); setTimeout(() => setSaved(false), 2000); }
28
+ return (
29
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
30
+ <div style={{ textAlign: 'center' }}>
31
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>⚙️ Settings</h2>
32
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Manage your OASIS account and preferences.</p>
33
+ </div>
34
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
35
+ {SECTIONS.map(sec => (
36
+ <div key={sec.label} style={{ background: 'rgba(255,255,255,.04)', border: `1px solid ${open === sec.label ? 'rgba(0,200,255,.3)' : 'rgba(0,200,255,.12)'}`, borderRadius: 10, overflow: 'hidden' }}>
37
+ <div onClick={() => setOpen(o => o === sec.label ? '' : sec.label)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '14px 16px', cursor: 'pointer', userSelect: 'none' }}>
38
+ <span style={{ fontSize: 18 }}>{sec.icon}</span>
39
+ <span style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: '#fff', flex: 1 }}>{sec.label}</span>
40
+ <span style={{ fontSize: 10, color: '#7a9bbf' }}>{open === sec.label ? '▲' : '▼'}</span>
41
+ </div>
42
+ {open === sec.label && (
43
+ <div style={{ padding: '0 16px 16px', display: 'flex', flexDirection: 'column', gap: 14 }}>
44
+ {sec.options.map(opt => (
45
+ <div key={opt.key} style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
46
+ <div style={{ flex: 1 }}>
47
+ <div style={{ fontSize: 13, color: '#e0f0ff' }}>{opt.name}</div>
48
+ <div style={{ fontSize: 11, color: '#4a6a88', marginTop: 2 }}>{opt.desc}</div>
49
+ </div>
50
+ {opt.type === 'toggle' && (
51
+ <div onClick={() => togglePref(opt.key)} style={{ width: 44, height: 24, borderRadius: 999, background: prefs[opt.key] ? 'linear-gradient(135deg,#00c8ff,#0080ff)' : 'rgba(255,255,255,.1)', cursor: 'pointer', position: 'relative', flexShrink: 0 }}>
52
+ <div style={{ position: 'absolute', top: 3, left: prefs[opt.key] ? 23 : 3, width: 18, height: 18, borderRadius: '50%', background: '#fff', transition: 'left .2s' }} />
53
+ </div>
54
+ )}
55
+ {opt.type === 'select' && (
56
+ <select value={prefs[opt.key]} onChange={e => setPref(opt.key, e.target.value)} style={{ background: 'rgba(255,255,255,.05)', border: '1px solid rgba(0,200,255,.2)', borderRadius: 7, color: '#fff', fontSize: 12, padding: '6px 10px', outline: 'none' }}>
57
+ {opt.choices.map(c => <option key={c} value={c}>{c}</option>)}
58
+ </select>
59
+ )}
60
+ </div>
61
+ ))}
62
+ </div>
63
+ )}
64
+ </div>
65
+ ))}
66
+ </div>
67
+ <button onClick={save} style={{ background: 'linear-gradient(135deg,#00c8ff,#0080ff)', border: 'none', borderRadius: 8, color: '#fff', fontFamily: "'Orbitron',sans-serif", fontSize: 13, fontWeight: 700, letterSpacing: '.08em', padding: 12, cursor: 'pointer' }}>{saved ? '✅ Saved!' : 'Save Settings'}</button>
68
+ </div>
69
+ );
70
+ }
@@ -0,0 +1,56 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+
3
+ export default function StarField({ starCount = 160, speed = 0.3, style = {} }) {
4
+ const canvasRef = useRef(null);
5
+
6
+ useEffect(() => {
7
+ const canvas = canvasRef.current;
8
+ const ctx = canvas.getContext('2d');
9
+ let raf;
10
+ let stars = [];
11
+
12
+ function resize() {
13
+ canvas.width = window.innerWidth;
14
+ canvas.height = window.innerHeight;
15
+ }
16
+
17
+ function init() {
18
+ stars = Array.from({ length: starCount }, () => ({
19
+ x: Math.random() * canvas.width,
20
+ y: Math.random() * canvas.height,
21
+ r: Math.random() * 1.4 + 0.3,
22
+ o: Math.random() * 0.6 + 0.2,
23
+ dy: (Math.random() * 0.3 + 0.1) * speed,
24
+ }));
25
+ }
26
+
27
+ function tick() {
28
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
29
+ for (const s of stars) {
30
+ ctx.beginPath();
31
+ ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
32
+ ctx.fillStyle = `rgba(200,230,255,${s.o})`;
33
+ ctx.fill();
34
+ s.y -= s.dy;
35
+ if (s.y < -2) { s.y = canvas.height + 2; s.x = Math.random() * canvas.width; }
36
+ }
37
+ raf = requestAnimationFrame(tick);
38
+ }
39
+
40
+ window.addEventListener('resize', resize);
41
+ resize();
42
+ init();
43
+ raf = requestAnimationFrame(tick);
44
+ return () => {
45
+ cancelAnimationFrame(raf);
46
+ window.removeEventListener('resize', resize);
47
+ };
48
+ }, [starCount, speed]);
49
+
50
+ return (
51
+ <canvas
52
+ ref={canvasRef}
53
+ style={{ position: 'fixed', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 0, ...style }}
54
+ />
55
+ );
56
+ }
@@ -0,0 +1,45 @@
1
+ const BALANCES = [
2
+ { icon: '⟠', currency: 'Ethereum', network: 'Mainnet', amount: '0.4821', symbol: 'ETH' },
3
+ { icon: '◎', currency: 'Solana', network: 'Mainnet', amount: '12.305', symbol: 'SOL' },
4
+ { icon: '⬡', currency: 'Polygon', network: 'Mainnet', amount: '245.00', symbol: 'MATIC' },
5
+ ];
6
+ const TXS = [
7
+ { id: '1', type: 'in', amount: 0.05, currency: 'ETH', description: 'NFT Sale — Cosmic Warrior', date: '2 hours ago' },
8
+ { id: '2', type: 'out', amount: 12, currency: 'SOL', description: 'Quest Reward Conversion', date: '1 day ago' },
9
+ { id: '3', type: 'in', amount: 100, currency: 'MATIC', description: 'Karma Reward Payout', date: '3 days ago' },
10
+ ];
11
+
12
+ export function Wallet() {
13
+ return (
14
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
15
+ <div style={{ textAlign: 'center' }}>
16
+ <h2 style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 20, color: '#fff', margin: '0 0 6px' }}>💰 Wallet</h2>
17
+ <p style={{ fontSize: 13, color: '#7a9bbf', margin: 0 }}>Your OASIS multi-chain wallet.</p>
18
+ </div>
19
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
20
+ {BALANCES.map(b => (
21
+ <div key={b.currency} style={{ display: 'flex', alignItems: 'center', gap: 14, background: 'rgba(255,255,255,.04)', border: '1px solid rgba(0,200,255,.12)', borderRadius: 10, padding: '14px 16px' }}>
22
+ <div style={{ fontSize: 24 }}>{b.icon}</div>
23
+ <div style={{ flex: 1 }}><div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 13, color: '#fff' }}>{b.currency}</div><div style={{ fontSize: 11, color: '#7a9bbf', marginTop: 2 }}>{b.network}</div></div>
24
+ <div style={{ fontFamily: "'Share Tech Mono',monospace", fontSize: 16, color: '#00c8ff', fontWeight: 600 }}>{b.amount} <span style={{ fontSize: 12, color: '#7a9bbf' }}>{b.symbol}</span></div>
25
+ </div>
26
+ ))}
27
+ </div>
28
+ <div style={{ display: 'flex', gap: 10 }}>
29
+ {['📤 Send', '📥 Receive', '🔄 Swap'].map(a => (
30
+ <button key={a} style={{ flex: 1, background: 'rgba(0,200,255,.08)', border: '1px solid rgba(0,200,255,.2)', borderRadius: 8, color: '#00c8ff', fontFamily: "'Orbitron',sans-serif", fontSize: 11, fontWeight: 700, letterSpacing: '.06em', padding: 10, cursor: 'pointer' }}>{a}</button>
31
+ ))}
32
+ </div>
33
+ <div style={{ fontFamily: "'Orbitron',sans-serif", fontSize: 12, color: '#7a9bbf', letterSpacing: '.06em', textTransform: 'uppercase' }}>Recent Transactions</div>
34
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
35
+ {TXS.map(t => (
36
+ <div key={t.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px', background: 'rgba(255,255,255,.03)', border: '1px solid rgba(0,200,255,.08)', borderRadius: 8 }}>
37
+ <div style={{ width: 28, height: 28, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, fontWeight: 700, flexShrink: 0, background: t.type === 'in' ? 'rgba(72,220,130,.15)' : 'rgba(255,107,107,.15)', color: t.type === 'in' ? '#48dc82' : '#ff6b6b' }}>{t.type === 'in' ? '↓' : '↑'}</div>
38
+ <div style={{ flex: 1 }}><div style={{ fontSize: 13, color: '#e0f0ff' }}>{t.description}</div><div style={{ fontSize: 11, color: '#4a6a88', marginTop: 2 }}>{t.date}</div></div>
39
+ <div style={{ fontFamily: "'Share Tech Mono',monospace", fontSize: 13, fontWeight: 600, color: t.type === 'in' ? '#48dc82' : '#ff6b6b' }}>{t.type === 'in' ? '+' : '-'}{t.amount} {t.currency}</div>
40
+ </div>
41
+ ))}
42
+ </div>
43
+ </div>
44
+ );
45
+ }
@@ -0,0 +1,66 @@
1
+ import React from "react"
2
+
3
+ class MessageContacts extends React.Component {
4
+ constructor(props) {
5
+ super(props)
6
+
7
+ }
8
+
9
+ render() {
10
+ return (
11
+ <div class="inbox_people">
12
+ <div class="headind_srch">
13
+ <div class="recent_heading">
14
+ <h4>Recent</h4>
15
+ </div>
16
+ <div class="srch_bar">
17
+ <div class="stylish-input-group">
18
+ <input
19
+ type="text"
20
+ class="search-bar"
21
+ placeholder="Search"
22
+ />
23
+ <span class="input-group-addon">
24
+ <button type="button">
25
+ {" "}
26
+ <i
27
+ class="fa fa-search"
28
+ aria-hidden="true"
29
+ ></i>{" "}
30
+ </button>
31
+ </span>{" "}
32
+ </div>
33
+ </div>
34
+ </div>
35
+ <div class="inbox_chat">
36
+ {this.props.contactList.map((contact)=>(
37
+ <div class={contact.active ? "chat_list active_chat" : "chat_list"}>
38
+ <div class="chat_people">
39
+ <div class="chat_img">
40
+ {" "}
41
+ <img
42
+ src={contact.img}
43
+ alt={contact.name}
44
+ />
45
+ </div>
46
+ <div class="chat_ib">
47
+ <h5>
48
+ {contact.name}{" "}
49
+ <span class="chat_date">
50
+ {contact.date}
51
+ </span>
52
+ </h5>
53
+ <p>
54
+ {contact.lastMessage}
55
+ </p>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ ))}
60
+ </div>
61
+ </div>
62
+ )
63
+ }
64
+ }
65
+
66
+ export default MessageContacts