@nockchain/rose 0.1.4-nightly.5

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 (205) hide show
  1. package/.github/workflows/artifacts.yml +33 -0
  2. package/.github/workflows/ci.yml +68 -0
  3. package/.github/workflows/publish-sdk.yml +35 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +5 -0
  6. package/.prettierrc +8 -0
  7. package/LICENSE +22 -0
  8. package/README.md +117 -0
  9. package/extension/background/index.ts +1500 -0
  10. package/extension/content/index.ts +59 -0
  11. package/extension/icons/rose.svg +27 -0
  12. package/extension/icons/rose128.png +0 -0
  13. package/extension/icons/rose16.png +0 -0
  14. package/extension/icons/rose256.png +0 -0
  15. package/extension/icons/rose32.png +0 -0
  16. package/extension/icons/rose48.png +0 -0
  17. package/extension/icons/rose512.png +0 -0
  18. package/extension/inpage/index.ts +86 -0
  19. package/extension/manifest.json +48 -0
  20. package/extension/popup/Popup.tsx +94 -0
  21. package/extension/popup/Router.tsx +121 -0
  22. package/extension/popup/assets/arrow-down-icon.svg +3 -0
  23. package/extension/popup/assets/arrow-left-icon.svg +3 -0
  24. package/extension/popup/assets/arrow-right-icon.svg +3 -0
  25. package/extension/popup/assets/arrow-up-icon.svg +3 -0
  26. package/extension/popup/assets/arrow-up-right-icon.svg +3 -0
  27. package/extension/popup/assets/checkmark-icon.svg +3 -0
  28. package/extension/popup/assets/checkmark-pencil-icon.svg +3 -0
  29. package/extension/popup/assets/checkmark-success-icon.svg +3 -0
  30. package/extension/popup/assets/clock-icon.svg +3 -0
  31. package/extension/popup/assets/close-x-icon.svg +3 -0
  32. package/extension/popup/assets/copy-icon.svg +6 -0
  33. package/extension/popup/assets/explorer-icon.svg +3 -0
  34. package/extension/popup/assets/eye-off-icon.svg +3 -0
  35. package/extension/popup/assets/eye-open-icon.svg +4 -0
  36. package/extension/popup/assets/feedback-icon.svg +3 -0
  37. package/extension/popup/assets/green-status-dot.svg +3 -0
  38. package/extension/popup/assets/info-icon.svg +3 -0
  39. package/extension/popup/assets/iris-logo-40.svg +27 -0
  40. package/extension/popup/assets/iris-logo-96.svg +27 -0
  41. package/extension/popup/assets/iris-logo-blue.svg +27 -0
  42. package/extension/popup/assets/iris-logo-no-eye.svg +27 -0
  43. package/extension/popup/assets/iris-logo-orange.svg +27 -0
  44. package/extension/popup/assets/iris-logo.svg +27 -0
  45. package/extension/popup/assets/key-icon.svg +3 -0
  46. package/extension/popup/assets/lock-icon-yellow.svg +3 -0
  47. package/extension/popup/assets/lock-icon.svg +3 -0
  48. package/extension/popup/assets/pencil-edit-icon.svg +3 -0
  49. package/extension/popup/assets/permissions-icon.svg +3 -0
  50. package/extension/popup/assets/receipt-icon.svg +5 -0
  51. package/extension/popup/assets/refresh-icon.svg +3 -0
  52. package/extension/popup/assets/settings-gear-icon.svg +8 -0
  53. package/extension/popup/assets/settings-icon.svg +3 -0
  54. package/extension/popup/assets/theme-icon.svg +3 -0
  55. package/extension/popup/assets/trash-bin-icon.svg +3 -0
  56. package/extension/popup/assets/trend-down-arrow.svg +5 -0
  57. package/extension/popup/assets/trend-up-arrow.svg +5 -0
  58. package/extension/popup/assets/user-account-icon.svg +3 -0
  59. package/extension/popup/assets/vector-bottom-left.svg +9 -0
  60. package/extension/popup/assets/vector-left.svg +9 -0
  61. package/extension/popup/assets/vector-right.svg +9 -0
  62. package/extension/popup/assets/vector-top-right-rotated.svg +8 -0
  63. package/extension/popup/assets/vector-top-right.svg +9 -0
  64. package/extension/popup/assets/wallet-dropdown-arrow.svg +5 -0
  65. package/extension/popup/assets/wallet-icon-style-1.svg +6 -0
  66. package/extension/popup/assets/wallet-icon-style-10.svg +8 -0
  67. package/extension/popup/assets/wallet-icon-style-11.svg +8 -0
  68. package/extension/popup/assets/wallet-icon-style-12.svg +8 -0
  69. package/extension/popup/assets/wallet-icon-style-13.svg +8 -0
  70. package/extension/popup/assets/wallet-icon-style-14.svg +8 -0
  71. package/extension/popup/assets/wallet-icon-style-15.svg +8 -0
  72. package/extension/popup/assets/wallet-icon-style-2.svg +8 -0
  73. package/extension/popup/assets/wallet-icon-style-3.svg +8 -0
  74. package/extension/popup/assets/wallet-icon-style-4.svg +8 -0
  75. package/extension/popup/assets/wallet-icon-style-5.svg +8 -0
  76. package/extension/popup/assets/wallet-icon-style-6.svg +8 -0
  77. package/extension/popup/assets/wallet-icon-style-7.svg +8 -0
  78. package/extension/popup/assets/wallet-icon-style-8.svg +8 -0
  79. package/extension/popup/assets/wallet-icon-style-9.svg +8 -0
  80. package/extension/popup/components/AccountIcon.tsx +78 -0
  81. package/extension/popup/components/AccountSelector.tsx +246 -0
  82. package/extension/popup/components/Alert.tsx +48 -0
  83. package/extension/popup/components/ConfirmModal.tsx +81 -0
  84. package/extension/popup/components/PasswordInput.tsx +49 -0
  85. package/extension/popup/components/ScreenContainer.tsx +17 -0
  86. package/extension/popup/components/SiteIcon.tsx +60 -0
  87. package/extension/popup/components/ThemeToggle.tsx +44 -0
  88. package/extension/popup/components/icons/ArrowDownLeftIcon.tsx +20 -0
  89. package/extension/popup/components/icons/ArrowUpRightIcon.tsx +20 -0
  90. package/extension/popup/components/icons/CheckIcon.tsx +20 -0
  91. package/extension/popup/components/icons/ChevronDownIcon.tsx +15 -0
  92. package/extension/popup/components/icons/ChevronLeftIcon.tsx +15 -0
  93. package/extension/popup/components/icons/ChevronRightIcon.tsx +15 -0
  94. package/extension/popup/components/icons/ChevronUpIcon.tsx +15 -0
  95. package/extension/popup/components/icons/CloseIcon.tsx +26 -0
  96. package/extension/popup/components/icons/CopyIcon.tsx +20 -0
  97. package/extension/popup/components/icons/EditIcon.tsx +20 -0
  98. package/extension/popup/components/icons/EyeIcon.tsx +13 -0
  99. package/extension/popup/components/icons/EyeOffIcon.tsx +13 -0
  100. package/extension/popup/components/icons/InfoIcon.tsx +20 -0
  101. package/extension/popup/components/icons/LockIcon.tsx +20 -0
  102. package/extension/popup/components/icons/PlusIcon.tsx +15 -0
  103. package/extension/popup/components/icons/ReceiveArrowIcon.tsx +14 -0
  104. package/extension/popup/components/icons/ReceiveCircleIcon.tsx +20 -0
  105. package/extension/popup/components/icons/SendPaperPlaneIcon.tsx +18 -0
  106. package/extension/popup/components/icons/SentArrowIcon.tsx +21 -0
  107. package/extension/popup/components/icons/SettingsIcon.tsx +26 -0
  108. package/extension/popup/components/icons/ShieldIcon.tsx +20 -0
  109. package/extension/popup/components/icons/UploadIcon.tsx +20 -0
  110. package/extension/popup/components/icons/WalletIcon.tsx +20 -0
  111. package/extension/popup/contexts/ThemeContext.tsx +105 -0
  112. package/extension/popup/hooks/useApprovalDetection.ts +128 -0
  113. package/extension/popup/hooks/useAutoFocus.ts +36 -0
  114. package/extension/popup/hooks/useAutoRejectOnClose.ts +25 -0
  115. package/extension/popup/hooks/useClickOutside.ts +33 -0
  116. package/extension/popup/hooks/useCopyToClipboard.ts +33 -0
  117. package/extension/popup/hooks/useFavicon.ts +64 -0
  118. package/extension/popup/hooks/useNumericInput.ts +93 -0
  119. package/extension/popup/index.html +13 -0
  120. package/extension/popup/index.tsx +24 -0
  121. package/extension/popup/screens/AboutScreen.tsx +118 -0
  122. package/extension/popup/screens/HomeScreen.tailwind.css +85 -0
  123. package/extension/popup/screens/HomeScreen.tsx +902 -0
  124. package/extension/popup/screens/KeySettingsPasswordScreen.tsx +164 -0
  125. package/extension/popup/screens/LockTimeScreen.tsx +155 -0
  126. package/extension/popup/screens/ReceiveScreen.tsx +149 -0
  127. package/extension/popup/screens/RecoveryPhraseScreen.tsx +183 -0
  128. package/extension/popup/screens/SendReviewScreen.tsx +308 -0
  129. package/extension/popup/screens/SendScreen.tsx +825 -0
  130. package/extension/popup/screens/SendSubmittedScreen.tsx +193 -0
  131. package/extension/popup/screens/SettingsScreen.tsx +116 -0
  132. package/extension/popup/screens/ThemeSettingsScreen.tsx +107 -0
  133. package/extension/popup/screens/TransactionDetailsScreen.tsx +346 -0
  134. package/extension/popup/screens/ViewSecretPhraseScreen.tsx +212 -0
  135. package/extension/popup/screens/WalletPermissionsScreen.tsx +123 -0
  136. package/extension/popup/screens/WalletSettingsScreen.tsx +381 -0
  137. package/extension/popup/screens/WalletStylingScreen.tsx +306 -0
  138. package/extension/popup/screens/approvals/ConnectApprovalScreen.tsx +136 -0
  139. package/extension/popup/screens/approvals/SignMessageScreen.tsx +140 -0
  140. package/extension/popup/screens/approvals/SignRawTxScreen.tsx +320 -0
  141. package/extension/popup/screens/approvals/TransactionApprovalScreen.tsx +167 -0
  142. package/extension/popup/screens/onboarding/BackupScreen.tsx +254 -0
  143. package/extension/popup/screens/onboarding/CreateScreen.tsx +273 -0
  144. package/extension/popup/screens/onboarding/ImportScreen.tsx +676 -0
  145. package/extension/popup/screens/onboarding/ImportScreenV0.tsx +678 -0
  146. package/extension/popup/screens/onboarding/ImportSuccessScreen.tsx +236 -0
  147. package/extension/popup/screens/onboarding/ResumeBackupScreen.tsx +166 -0
  148. package/extension/popup/screens/onboarding/StartScreen.tsx +142 -0
  149. package/extension/popup/screens/onboarding/SuccessScreen.tsx +193 -0
  150. package/extension/popup/screens/onboarding/VerifyScreen.tsx +220 -0
  151. package/extension/popup/screens/system/LockedScreen.tsx +288 -0
  152. package/extension/popup/screens/transactions/ReceiveScreen.tsx +84 -0
  153. package/extension/popup/screens/transactions/SentScreen.tsx +138 -0
  154. package/extension/popup/store.ts +482 -0
  155. package/extension/popup/styles.css +246 -0
  156. package/extension/popup/utils/format.ts +58 -0
  157. package/extension/popup/utils/formatWalletError.ts +36 -0
  158. package/extension/popup/utils/memo.ts +299 -0
  159. package/extension/popup/utils/messaging.ts +16 -0
  160. package/extension/shared/address-encoding.ts +69 -0
  161. package/extension/shared/balance-query.ts +123 -0
  162. package/extension/shared/constants.ts +386 -0
  163. package/extension/shared/currency.ts +128 -0
  164. package/extension/shared/first-name-derivation.ts +128 -0
  165. package/extension/shared/keyfile.ts +58 -0
  166. package/extension/shared/onboarding.ts +78 -0
  167. package/extension/shared/price-api.ts +79 -0
  168. package/extension/shared/rpc-client-browser.ts +315 -0
  169. package/extension/shared/transaction-builder.ts +443 -0
  170. package/extension/shared/types.ts +450 -0
  171. package/extension/shared/utxo-diff.ts +212 -0
  172. package/extension/shared/utxo-store.ts +548 -0
  173. package/extension/shared/utxo-sync.ts +343 -0
  174. package/extension/shared/validators.ts +26 -0
  175. package/extension/shared/vault.ts +1580 -0
  176. package/extension/shared/wallet-crypto.ts +77 -0
  177. package/extension/shared/wasm-utils.ts +76 -0
  178. package/extension/shared/webcrypto.ts +67 -0
  179. package/extension/types/wasm.d.ts +13 -0
  180. package/package.json +39 -0
  181. package/postcss.config.js +6 -0
  182. package/rose-extension-dist.zip +0 -0
  183. package/sdk/README.md +88 -0
  184. package/sdk/examples/app.ts +166 -0
  185. package/sdk/examples/index.html +51 -0
  186. package/sdk/examples/tsconfig.json +15 -0
  187. package/sdk/examples/tx-builder.html +532 -0
  188. package/sdk/examples/tx-builder.ts +1766 -0
  189. package/sdk/package-lock.json +424 -0
  190. package/sdk/package.json +68 -0
  191. package/sdk/src/constants.ts +28 -0
  192. package/sdk/src/errors.ts +74 -0
  193. package/sdk/src/hooks/index.ts +1 -0
  194. package/sdk/src/hooks/use-rose.ts +94 -0
  195. package/sdk/src/index.ts +12 -0
  196. package/sdk/src/provider.ts +396 -0
  197. package/sdk/src/transaction.ts +163 -0
  198. package/sdk/src/types/rose-wasm.d.ts +14 -0
  199. package/sdk/src/types.ts +97 -0
  200. package/sdk/src/wasm.ts +13 -0
  201. package/sdk/tsconfig.json +20 -0
  202. package/sdk/vite.config.examples.ts +32 -0
  203. package/tailwind.config.ts +38 -0
  204. package/tsconfig.json +20 -0
  205. package/vite.config.ts +60 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * SiteIcon - Display site favicon with fallback to letter avatar
3
+ */
4
+
5
+ import { useFavicon } from '../hooks/useFavicon';
6
+
7
+ interface SiteIconProps {
8
+ origin: string;
9
+ domain: string;
10
+ size?: 'sm' | 'md' | 'lg';
11
+ }
12
+
13
+ export function SiteIcon({ origin, domain, size = 'lg' }: SiteIconProps) {
14
+ const faviconUrl = useFavicon(origin);
15
+
16
+ // Size mappings
17
+ const sizeClasses = {
18
+ sm: 'w-8 h-8',
19
+ md: 'w-12 h-12',
20
+ lg: 'w-16 h-16',
21
+ };
22
+
23
+ const textSizes = {
24
+ sm: 'text-lg',
25
+ md: 'text-xl',
26
+ lg: 'text-2xl',
27
+ };
28
+
29
+ const surface = 'var(--color-surface-800)';
30
+ const textPrimary = 'var(--color-text-primary)';
31
+
32
+ return (
33
+ <div className="relative inline-block">
34
+ <div
35
+ className={`inline-flex items-center justify-center rounded-full ${sizeClasses[size]} overflow-hidden`}
36
+ style={{ backgroundColor: surface }}
37
+ >
38
+ {faviconUrl ? (
39
+ <img
40
+ src={faviconUrl}
41
+ alt={`${domain} favicon`}
42
+ className="w-full h-full object-cover"
43
+ onError={e => {
44
+ // Hide broken image, show letter fallback
45
+ e.currentTarget.style.display = 'none';
46
+ const parent = e.currentTarget.parentElement;
47
+ if (parent) {
48
+ parent.innerHTML = `<span class="${textSizes[size]} font-bold" style="color: ${textPrimary}">${domain.charAt(0).toUpperCase()}</span>`;
49
+ }
50
+ }}
51
+ />
52
+ ) : (
53
+ <span className={`${textSizes[size]} font-bold`} style={{ color: textPrimary }}>
54
+ {domain.charAt(0).toUpperCase()}
55
+ </span>
56
+ )}
57
+ </div>
58
+ </div>
59
+ );
60
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Theme Toggle Component
3
+ * Allows users to switch between dark and light modes
4
+ */
5
+
6
+ import { useTheme } from '../contexts/ThemeContext';
7
+
8
+ export function ThemeToggle() {
9
+ const { theme, toggleTheme } = useTheme();
10
+
11
+ return (
12
+ <button
13
+ onClick={toggleTheme}
14
+ className="flex items-center gap-2 px-4 py-2 rounded-lg bg-gray-800 hover:bg-gray-700 transition-colors"
15
+ aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
16
+ >
17
+ {theme === 'dark' ? (
18
+ <>
19
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20
+ <path
21
+ strokeLinecap="round"
22
+ strokeLinejoin="round"
23
+ strokeWidth={2}
24
+ d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
25
+ />
26
+ </svg>
27
+ <span className="text-sm">Light Mode</span>
28
+ </>
29
+ ) : (
30
+ <>
31
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
32
+ <path
33
+ strokeLinecap="round"
34
+ strokeLinejoin="round"
35
+ strokeWidth={2}
36
+ d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
37
+ />
38
+ </svg>
39
+ <span className="text-sm">Dark Mode</span>
40
+ </>
41
+ )}
42
+ </button>
43
+ );
44
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ArrowDownLeftIcon - Incoming/received transaction icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ArrowDownLeftIcon({ className = 'w-6 h-6' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M17 7L7 17M7 17H17M7 17V7"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ArrowUpRightIcon - Simple diagonal arrow pointing up-right
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ArrowUpRightIcon({ className = 'w-6 h-6' }: IconProps) {
10
+ return (
11
+ <svg
12
+ className={className}
13
+ viewBox="0 0 11 11"
14
+ fill="currentColor"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ >
17
+ <path d="M1.16667 10.8333L9.16667 2.83333L9.16667 10L10.8333 10V0H0.833333L0.833334 1.66667H8L0 9.66667L1.16667 10.8333Z" />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CheckIcon - Success/checkmark icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ style?: React.CSSProperties;
8
+ }
9
+
10
+ export function CheckIcon({ className = 'w-5 h-5', style }: IconProps) {
11
+ return (
12
+ <svg className={className} style={style} viewBox="0 0 20 20" fill="currentColor">
13
+ <path
14
+ fillRule="evenodd"
15
+ d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
16
+ clipRule="evenodd"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ChevronDownIcon - Dropdown arrow icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ChevronDownIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
13
+ </svg>
14
+ );
15
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ChevronLeftIcon - Back/left arrow icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ChevronLeftIcon({ className = 'w-6 h-6' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
13
+ </svg>
14
+ );
15
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ChevronRightIcon - Right arrow icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ChevronRightIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
13
+ </svg>
14
+ );
15
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ChevronUpIcon - Up arrow icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ChevronUpIcon({ className = 'w-6 h-6' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 15l7-7 7 7" />
13
+ </svg>
14
+ );
15
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * CloseIcon - Close/X icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function CloseIcon({ className = '' }: IconProps) {
10
+ return (
11
+ <svg
12
+ className={className}
13
+ viewBox="0 0 16 16"
14
+ fill="none"
15
+ width="16"
16
+ height="16"
17
+ xmlns="http://www.w3.org/2000/svg"
18
+ stroke="currentColor"
19
+ >
20
+ <path
21
+ d="M14.4141 3L9.41406 8L14.4141 13L13 14.4141L8 9.41406L3 14.4141L1.58594 13L6.58594 8L1.58594 3L3 1.58594L8 6.58594L13 1.58594L14.4141 3Z"
22
+ fill="currentColor"
23
+ />
24
+ </svg>
25
+ );
26
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CopyIcon - Copy to clipboard icon (overlapping documents)
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function CopyIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * EditIcon - Edit/pencil icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function EditIcon({ className = 'w-4 h-4' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,13 @@
1
+ import EyeOpenIconSvg from '../../assets/eye-open-icon.svg';
2
+
3
+ /**
4
+ * EyeIcon - View/show icon
5
+ */
6
+
7
+ interface IconProps {
8
+ className?: string;
9
+ }
10
+
11
+ export function EyeIcon({ className = 'w-4 h-4' }: IconProps) {
12
+ return <img src={EyeOpenIconSvg} alt="" className={className} />;
13
+ }
@@ -0,0 +1,13 @@
1
+ import EyeOffIconSvg from '../../assets/eye-off-icon.svg';
2
+
3
+ /**
4
+ * EyeOffIcon - Hide/conceal icon
5
+ */
6
+
7
+ interface IconProps {
8
+ className?: string;
9
+ }
10
+
11
+ export function EyeOffIcon({ className = 'w-4 h-4' }: IconProps) {
12
+ return <img src={EyeOffIconSvg} alt="" className={className} />;
13
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * InfoIcon - Information icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function InfoIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * LockIcon - Lock/security icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function LockIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * PlusIcon - Add/create new icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function PlusIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
13
+ </svg>
14
+ );
15
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ReceiveArrowIcon
3
+ */
4
+
5
+ import ArrowDownIcon from '../../assets/arrow-down-icon.svg';
6
+
7
+ interface IconProps {
8
+ className?: string;
9
+ style?: React.CSSProperties;
10
+ }
11
+
12
+ export function ReceiveArrowIcon({ className = 'w-4 h-4', style }: IconProps) {
13
+ return <img src={ArrowDownIcon} alt="" className={className} style={style} />;
14
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ReceiveCircleIcon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ReceiveCircleIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
12
+ <path
13
+ fillRule="evenodd"
14
+ clipRule="evenodd"
15
+ d="M10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10C0 4.47715 4.47715 0 10 0ZM10 5.8252C9.53884 5.8252 9.16504 6.199 9.16504 6.66016V11.3232L7.25098 9.40918C6.92489 9.08309 6.39542 9.08309 6.06934 9.40918C5.74325 9.73527 5.74325 10.2647 6.06934 10.5908L9.40918 13.9307C9.73527 14.2568 10.2647 14.2568 10.5908 13.9307L13.9307 10.5908C14.2568 10.2647 14.2568 9.73527 13.9307 9.40918C13.6046 9.08309 13.0751 9.08309 12.749 9.40918L10.835 11.3232V6.66016C10.835 6.199 10.4612 5.8252 10 5.8252Z"
16
+ fill="currentColor"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * SendPaperPlaneIcon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function SendPaperPlaneIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
12
+ <path
13
+ d="M0.682286 6.74231C-0.228035 6.43728 -0.227221 5.14941 0.683484 4.84554L15.0466 0.0529811C15.8097 -0.201652 16.5459 0.503244 16.3245 1.27669L12.1665 15.8069C11.9098 16.7041 10.673 16.7918 10.2922 15.9399L8.02397 10.8654C7.87575 10.5338 7.91899 10.1479 8.13692 9.85734L9.0263 8.6715C9.72014 7.74639 8.55142 6.57766 7.6263 7.2715L6.38962 8.19901C6.12666 8.39623 5.78358 8.45163 5.47191 8.3472L0.682286 6.74231Z"
14
+ fill="currentColor"
15
+ />
16
+ </svg>
17
+ );
18
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * SentArrowIcon
3
+ */
4
+
5
+ import ArrowUpIcon from '../../assets/arrow-up-icon.svg';
6
+
7
+ interface IconProps {
8
+ className?: string;
9
+ style?: React.CSSProperties;
10
+ }
11
+
12
+ export function SentArrowIcon({ className = 'w-4 h-4', style }: IconProps) {
13
+ return (
14
+ <div
15
+ className={className}
16
+ style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', ...style }}
17
+ >
18
+ <img src={ArrowUpIcon} alt="" style={{ width: '68%', height: '68%' }} />
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * SettingsIcon - Gear/settings icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function SettingsIcon({ className = 'w-6 h-6' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
17
+ />
18
+ <path
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ strokeWidth={2}
22
+ d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
23
+ />
24
+ </svg>
25
+ );
26
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ShieldIcon - Security/protection icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function ShieldIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * UploadIcon - Import/upload icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function UploadIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * WalletIcon - Wallet/card icon
3
+ */
4
+
5
+ interface IconProps {
6
+ className?: string;
7
+ }
8
+
9
+ export function WalletIcon({ className = 'w-5 h-5' }: IconProps) {
10
+ return (
11
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ strokeWidth={2}
16
+ d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Theme Context - Manages dark/light mode switching with system theme support
3
+ */
4
+
5
+ import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
6
+
7
+ type Theme = 'dark' | 'light' | 'system';
8
+
9
+ interface ThemeContextType {
10
+ theme: Theme;
11
+ toggleTheme: () => void;
12
+ setTheme: (theme: Theme) => void;
13
+ }
14
+
15
+ const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
16
+
17
+ const STORAGE_KEY = 'rose-theme';
18
+
19
+ // Detect system theme preference
20
+ function getSystemTheme(): 'dark' | 'light' {
21
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
22
+ }
23
+
24
+ export function ThemeProvider({ children }: { children: ReactNode }) {
25
+ const [theme, setThemeState] = useState<Theme>('light');
26
+ const [mounted, setMounted] = useState(false);
27
+
28
+ // Load theme from storage on mount
29
+ useEffect(() => {
30
+ chrome.storage.local.get([STORAGE_KEY], result => {
31
+ const savedTheme = result[STORAGE_KEY] as Theme | undefined;
32
+ if (savedTheme) {
33
+ setThemeState(savedTheme);
34
+ applyTheme(savedTheme);
35
+ } else {
36
+ // No saved theme, default to light theme
37
+ setThemeState('light');
38
+ applyTheme('light');
39
+ chrome.storage.local.set({ [STORAGE_KEY]: 'light' });
40
+ }
41
+ setMounted(true);
42
+ });
43
+ }, []);
44
+
45
+ // Listen for system theme changes when using system theme
46
+ useEffect(() => {
47
+ if (theme !== 'system') return;
48
+
49
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
50
+ const handleChange = () => {
51
+ applyTheme('system');
52
+ };
53
+
54
+ // Modern browsers
55
+ mediaQuery.addEventListener('change', handleChange);
56
+
57
+ return () => {
58
+ mediaQuery.removeEventListener('change', handleChange);
59
+ };
60
+ }, [theme]);
61
+
62
+ // Apply theme to document
63
+ const applyTheme = (newTheme: Theme) => {
64
+ const root = document.documentElement;
65
+ const effectiveTheme = newTheme === 'system' ? getSystemTheme() : newTheme;
66
+
67
+ if (effectiveTheme === 'light') {
68
+ root.classList.add('light');
69
+ } else {
70
+ root.classList.remove('light');
71
+ }
72
+ };
73
+
74
+ // Set theme and persist
75
+ const setTheme = (newTheme: Theme) => {
76
+ setThemeState(newTheme);
77
+ applyTheme(newTheme);
78
+ chrome.storage.local.set({ [STORAGE_KEY]: newTheme });
79
+ };
80
+
81
+ // Toggle between dark and light (skip system)
82
+ const toggleTheme = () => {
83
+ const newTheme = theme === 'dark' ? 'light' : 'dark';
84
+ setTheme(newTheme);
85
+ };
86
+
87
+ // Prevent flash of wrong theme
88
+ if (!mounted) {
89
+ return null;
90
+ }
91
+
92
+ return (
93
+ <ThemeContext.Provider value={{ theme, toggleTheme, setTheme }}>
94
+ {children}
95
+ </ThemeContext.Provider>
96
+ );
97
+ }
98
+
99
+ export function useTheme() {
100
+ const context = useContext(ThemeContext);
101
+ if (!context) {
102
+ throw new Error('useTheme must be used within ThemeProvider');
103
+ }
104
+ return context;
105
+ }