this.gui 1.3.41 → 1.3.42

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 (310) hide show
  1. package/package.json +3 -2
  2. package/src/GUI.tsx +46 -0
  3. package/src/QRouter/QRegistry.tsx +53 -0
  4. package/src/QRouter/QRouter.stories.tsx +31 -0
  5. package/src/QRouter/QRouter.tsx +57 -0
  6. package/src/gui/Theme/GuiProvider.tsx +111 -0
  7. package/src/gui/Theme/Icon/Icon.resolver.tsx +29 -0
  8. package/src/gui/Theme/Icon/Icon.tsx +43 -0
  9. package/src/gui/Theme/Layout/Content/Content.resolver.tsx +0 -0
  10. package/src/gui/Theme/Layout/Content/Content.stories.tsx +88 -0
  11. package/src/gui/Theme/Layout/Content/Content.tsx +53 -0
  12. package/src/gui/Theme/Layout/Content/Content.types.tsx +40 -0
  13. package/src/gui/Theme/Layout/Footer/Footer.resolver.tsx +45 -0
  14. package/src/gui/Theme/Layout/Footer/Footer.stories.tsx +205 -0
  15. package/src/gui/Theme/Layout/Footer/Footer.tsx +337 -0
  16. package/src/gui/Theme/Layout/Footer/Footer.types.ts +40 -0
  17. package/src/gui/Theme/Layout/Layout/Layout.resolver.tsx +37 -0
  18. package/src/gui/Theme/Layout/Layout/Layout.stories.tsx +289 -0
  19. package/src/gui/Theme/Layout/Layout/Layout.tsx +117 -0
  20. package/src/gui/Theme/Layout/Layout/Layout.types.ts +57 -0
  21. package/src/gui/Theme/Layout/Layout/useLayoutBreakpoints.ts +9 -0
  22. package/src/gui/Theme/Layout/Namespace/Namespace.stories.tsx +105 -0
  23. package/src/gui/Theme/Layout/Namespace/Namespace.tsx +26 -0
  24. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.resolver.tsx +87 -0
  25. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.stories.tsx +199 -0
  26. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.tsx +311 -0
  27. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.types.ts +41 -0
  28. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/SidebarToggleButton.tsx +53 -0
  29. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarAction/LeftSidebarAction.resolver.tsx +19 -0
  30. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarAction/LeftSidebarAction.tsx +107 -0
  31. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarLink/LeftSidebarLink.resolver.tsx +0 -0
  32. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarLink/LeftSidebarLink.tsx +134 -0
  33. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarLink/LeftSidebarLink.types.ts +15 -0
  34. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarMenu/LeftSidebarMenu.tsx +142 -0
  35. package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarToggleButton/LeftSidebarToggleButton.tsx +23 -0
  36. package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.resolver.tsx +35 -0
  37. package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.stories.tsx +239 -0
  38. package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.tsx +319 -0
  39. package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.types.ts +17 -0
  40. package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarAction/RightSidebarAction.tsx +102 -0
  41. package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarLink/RightSidebarLink.tsx +132 -0
  42. package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarMenu/RightSidebarMenu.tsx +140 -0
  43. package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarToggleButton/RightSidebarToggleButton.tsx +22 -0
  44. package/src/gui/Theme/Layout/StickyOptions/StickyOptionsTop.stories.tsx +469 -0
  45. package/src/gui/Theme/Layout/StickyOptions/StickyOptionsTop.tsx +489 -0
  46. package/src/gui/Theme/Layout/TopBar/TopBar.resolver.tsx +86 -0
  47. package/src/gui/Theme/Layout/TopBar/TopBar.stories.tsx +350 -0
  48. package/src/gui/Theme/Layout/TopBar/TopBar.tsx +292 -0
  49. package/src/gui/Theme/Layout/TopBar/TopBar.types.ts +39 -0
  50. package/src/gui/Theme/Layout/TopBar/components/TopBarAction/TopBarAction.stories.tsx +83 -0
  51. package/src/gui/Theme/Layout/TopBar/components/TopBarAction/TopBarAction.tsx +18 -0
  52. package/src/gui/Theme/Layout/TopBar/components/TopBarAction/TopBarAction.types.ts +4 -0
  53. package/src/gui/Theme/Layout/TopBar/components/TopBarLink/TopBarLink.stories.tsx +189 -0
  54. package/src/gui/Theme/Layout/TopBar/components/TopBarLink/TopBarLink.tsx +30 -0
  55. package/src/gui/Theme/Layout/TopBar/components/TopBarLink/TopBarLink.types.ts +9 -0
  56. package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.resolver.tsx +14 -0
  57. package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.stories.tsx +56 -0
  58. package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.tsx +123 -0
  59. package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.types.ts +44 -0
  60. package/src/gui/Theme/catalog/CherryByte/CherryByte.png +0 -0
  61. package/src/gui/Theme/catalog/CherryByte/dark.tokens.ts +47 -0
  62. package/src/gui/Theme/catalog/CherryByte/light.tokens.ts +47 -0
  63. package/src/gui/Theme/catalog/CherryByte/manifest.ts +24 -0
  64. package/src/gui/Theme/catalog/GhostShell/dark.tokens.ts +43 -0
  65. package/src/gui/Theme/catalog/GhostShell/ghost.png +0 -0
  66. package/src/gui/Theme/catalog/GhostShell/light.tokens.ts +39 -0
  67. package/src/gui/Theme/catalog/GhostShell/manifest.ts +24 -0
  68. package/src/gui/Theme/catalog/LunaHex/LunaHex.png +0 -0
  69. package/src/gui/Theme/catalog/LunaHex/dark.tokens.ts +34 -0
  70. package/src/gui/Theme/catalog/LunaHex/light.tokens.ts +74 -0
  71. package/src/gui/Theme/catalog/LunaHex/manifest.ts +24 -0
  72. package/src/gui/Theme/catalog/MUI/MUI.png +0 -0
  73. package/src/gui/Theme/catalog/MUI/dark.tokens.ts +58 -0
  74. package/src/gui/Theme/catalog/MUI/light.tokens.ts +74 -0
  75. package/src/gui/Theme/catalog/MUI/manifest.ts +24 -0
  76. package/src/gui/Theme/catalog/PrinceOfDarkness/dark.tokens.ts +48 -0
  77. package/src/gui/Theme/catalog/PrinceOfDarkness/light.tokens.ts +47 -0
  78. package/src/gui/Theme/catalog/PrinceOfDarkness/manifest.ts +24 -0
  79. package/src/gui/Theme/catalog/PrinceOfDarkness/prince.png +0 -0
  80. package/src/gui/Theme/catalog/PrinceOfDarkness/princeOfDarkness.png +0 -0
  81. package/src/gui/Theme/catalog/Seafoam/dark.tokens.ts +49 -0
  82. package/src/gui/Theme/catalog/Seafoam/light.tokens.ts +47 -0
  83. package/src/gui/Theme/catalog/Seafoam/manifest.ts +24 -0
  84. package/src/gui/Theme/catalog/Seafoam/seaFoam.png +0 -0
  85. package/src/gui/Theme/catalog/neurons/dark.tokens.ts +58 -0
  86. package/src/gui/Theme/catalog/neurons/light.tokens.ts +74 -0
  87. package/src/gui/Theme/catalog/neurons/manifest.ts +24 -0
  88. package/src/gui/Theme/catalog/neurons/neurons.me.png +0 -0
  89. package/src/gui/Theme/fromTokens.ts +272 -0
  90. package/src/gui/Theme/gui.css +31 -0
  91. package/src/gui/Theme/index.ts +17 -0
  92. package/src/gui/Theme/styles/buildShadows.ts +83 -0
  93. package/src/gui/Theme/styles/theme.tokens.ts +108 -0
  94. package/src/gui/Theme/utils/catalog.ts +61 -0
  95. package/src/gui/Theme/utils/persistence.ts +66 -0
  96. package/src/gui/Theme/utils/themeUtils.ts +34 -0
  97. package/src/gui/components/atoms/AppBar/AppBar.resolver.tsx +46 -0
  98. package/src/gui/components/atoms/AppBar/AppBar.stories.tsx +251 -0
  99. package/src/gui/components/atoms/AppBar/AppBar.tsx +107 -0
  100. package/src/gui/components/atoms/AppBar/AppBar.types.ts +28 -0
  101. package/src/gui/components/atoms/Avatar/Avatar.resolver.tsx +61 -0
  102. package/src/gui/components/atoms/Avatar/Avatar.stories.tsx +36 -0
  103. package/src/gui/components/atoms/Avatar/Avatar.tsx +14 -0
  104. package/src/gui/components/atoms/Box/Box.resolver.tsx +171 -0
  105. package/src/gui/components/atoms/Box/Box.stories.tsx +263 -0
  106. package/src/gui/components/atoms/Box/Box.tsx +15 -0
  107. package/src/gui/components/atoms/Button/Button.resolver.tsx +103 -0
  108. package/src/gui/components/atoms/Button/Button.stories.tsx +219 -0
  109. package/src/gui/components/atoms/Button/Button.tsx +40 -0
  110. package/src/gui/components/atoms/Card/Card.resolver.tsx +63 -0
  111. package/src/gui/components/atoms/Card/Card.stories.tsx +54 -0
  112. package/src/gui/components/atoms/Card/Card.tsx +13 -0
  113. package/src/gui/components/atoms/CardActions/CardActions.resolver.tsx +59 -0
  114. package/src/gui/components/atoms/CardActions/CardActions.stories.tsx +32 -0
  115. package/src/gui/components/atoms/CardActions/CardActions.tsx +14 -0
  116. package/src/gui/components/atoms/CardContent/CardContent.resolver.tsx +60 -0
  117. package/src/gui/components/atoms/CardContent/CardContent.stories.tsx +34 -0
  118. package/src/gui/components/atoms/CardContent/CardContent.tsx +13 -0
  119. package/src/gui/components/atoms/CardHeader/CardHeader.resolver.tsx +68 -0
  120. package/src/gui/components/atoms/CardHeader/CardHeader.stories.tsx +40 -0
  121. package/src/gui/components/atoms/CardHeader/CardHeader.tsx +12 -0
  122. package/src/gui/components/atoms/Collapse/Collapse.resolver.tsx +85 -0
  123. package/src/gui/components/atoms/Collapse/Collapse.stories.tsx +130 -0
  124. package/src/gui/components/atoms/Collapse/Collapse.tsx +17 -0
  125. package/src/gui/components/atoms/Divider/Divider.resolver.tsx +95 -0
  126. package/src/gui/components/atoms/Divider/Divider.stories.tsx +108 -0
  127. package/src/gui/components/atoms/Divider/Divider.tsx +14 -0
  128. package/src/gui/components/atoms/Drawer/Drawer.resolver.tsx +116 -0
  129. package/src/gui/components/atoms/Drawer/Drawer.stories.tsx +223 -0
  130. package/src/gui/components/atoms/Drawer/Drawer.tsx +25 -0
  131. package/src/gui/components/atoms/Grid/Grid.resolver.tsx +33 -0
  132. package/src/gui/components/atoms/Grid/Grid.stories.tsx +136 -0
  133. package/src/gui/components/atoms/Grid/Grid.tsx +15 -0
  134. package/src/gui/components/atoms/Grid/Grid.types.ts +9 -0
  135. package/src/gui/components/atoms/IconButton/IconButton.resolver.tsx +137 -0
  136. package/src/gui/components/atoms/IconButton/IconButton.stories.tsx +134 -0
  137. package/src/gui/components/atoms/IconButton/IconButton.tsx +22 -0
  138. package/src/gui/components/atoms/Link/Link.resolver.tsx +74 -0
  139. package/src/gui/components/atoms/Link/Link.stories.tsx +157 -0
  140. package/src/gui/components/atoms/Link/Link.tsx +36 -0
  141. package/src/gui/components/atoms/List/List.resolver.tsx +94 -0
  142. package/src/gui/components/atoms/List/List.stories.tsx +137 -0
  143. package/src/gui/components/atoms/List/List.tsx +20 -0
  144. package/src/gui/components/atoms/ListItem/ListItem.resolver.tsx +88 -0
  145. package/src/gui/components/atoms/ListItem/ListItem.stories.tsx +151 -0
  146. package/src/gui/components/atoms/ListItem/ListItem.tsx +19 -0
  147. package/src/gui/components/atoms/ListItemButton/ListItemButton.resolver.tsx +214 -0
  148. package/src/gui/components/atoms/ListItemButton/ListItemButton.stories.tsx +155 -0
  149. package/src/gui/components/atoms/ListItemButton/ListItemButton.tsx +15 -0
  150. package/src/gui/components/atoms/ListItemIcon/ListItemIcon.resolver.tsx +102 -0
  151. package/src/gui/components/atoms/ListItemIcon/ListItemIcon.stories.tsx +132 -0
  152. package/src/gui/components/atoms/ListItemIcon/ListItemIcon.tsx +11 -0
  153. package/src/gui/components/atoms/ListItemText/ListItemText.resolver.tsx +112 -0
  154. package/src/gui/components/atoms/ListItemText/ListItemText.stories.tsx +156 -0
  155. package/src/gui/components/atoms/ListItemText/ListItemText.tsx +15 -0
  156. package/src/gui/components/atoms/Menu/Menu.resolver.tsx +112 -0
  157. package/src/gui/components/atoms/Menu/Menu.stories.tsx +162 -0
  158. package/src/gui/components/atoms/Menu/Menu.tsx +17 -0
  159. package/src/gui/components/atoms/MenuItem/MenuItem.resolver.tsx +183 -0
  160. package/src/gui/components/atoms/MenuItem/MenuItem.stories.tsx +134 -0
  161. package/src/gui/components/atoms/MenuItem/MenuItem.tsx +14 -0
  162. package/src/gui/components/atoms/Paper/Paper.resolver.tsx +98 -0
  163. package/src/gui/components/atoms/Paper/Paper.stories.tsx +184 -0
  164. package/src/gui/components/atoms/Paper/Paper.tsx +15 -0
  165. package/src/gui/components/atoms/Section/Section.resolver.tsx +10 -0
  166. package/src/gui/components/atoms/Section/Section.stories.tsx +189 -0
  167. package/src/gui/components/atoms/Section/Section.tsx +76 -0
  168. package/src/gui/components/atoms/Section/Section.types.tsx +24 -0
  169. package/src/gui/components/atoms/Stack/Stack.resolver.tsx +94 -0
  170. package/src/gui/components/atoms/Stack/Stack.stories.tsx +160 -0
  171. package/src/gui/components/atoms/Stack/Stack.tsx +15 -0
  172. package/src/gui/components/atoms/Surface/Surface.resolver.tsx +37 -0
  173. package/src/gui/components/atoms/Surface/Surface.tsx +49 -0
  174. package/src/gui/components/atoms/Surface/Surface.types.ts +20 -0
  175. package/src/gui/components/atoms/Switch/Switch.resolver.tsx +53 -0
  176. package/src/gui/components/atoms/Switch/Switch.stories.tsx +236 -0
  177. package/src/gui/components/atoms/Switch/Switch.tsx +22 -0
  178. package/src/gui/components/atoms/Table/Body/TableBody.tsx +7 -0
  179. package/src/gui/components/atoms/Table/Cell/TableCell.tsx +18 -0
  180. package/src/gui/components/atoms/Table/Head/TableHead.tsx +9 -0
  181. package/src/gui/components/atoms/Table/Row/TableRow.tsx +20 -0
  182. package/src/gui/components/atoms/Table/Table.resolver.tsx +77 -0
  183. package/src/gui/components/atoms/Table/Table.stories.tsx +173 -0
  184. package/src/gui/components/atoms/Table/Table.tsx +20 -0
  185. package/src/gui/components/atoms/TextField/TextField.stories.tsx +25 -0
  186. package/src/gui/components/atoms/TextField/TextField.tsx +15 -0
  187. package/src/gui/components/atoms/Toolbar/Toolbar.resolver.tsx +60 -0
  188. package/src/gui/components/atoms/Toolbar/Toolbar.stories.tsx +155 -0
  189. package/src/gui/components/atoms/Toolbar/Toolbar.tsx +16 -0
  190. package/src/gui/components/atoms/Tooltip/Tooltip.resolver.tsx +142 -0
  191. package/src/gui/components/atoms/Tooltip/Tooltip.stories.tsx +117 -0
  192. package/src/gui/components/atoms/Tooltip/Tooltip.tsx +70 -0
  193. package/src/gui/components/atoms/Typography/Typography.resolver.tsx +158 -0
  194. package/src/gui/components/atoms/Typography/Typography.stories.tsx +222 -0
  195. package/src/gui/components/atoms/Typography/Typography.tsx +27 -0
  196. package/src/gui/components/atoms/Window/Nodes/node.ts +0 -0
  197. package/src/gui/components/atoms/Window/code/block/node.tsx +0 -0
  198. package/src/gui/components/atoms/Window/code/hugging.face.api.ts +11 -0
  199. package/src/gui/components/atoms/Window/connectors/index.ts +19 -0
  200. package/src/gui/components/atoms/Window/window.stories.tsx +20 -0
  201. package/src/gui/components/atoms/Window/window.tsx +636 -0
  202. package/src/gui/components/atoms/atoms.tsx +151 -0
  203. package/src/gui/components/atoms/index.ts +2 -0
  204. package/src/gui/components/generics/Cards/Gridme.jsx +52 -0
  205. package/src/gui/components/generics/Cards/LilBox.jsx +65 -0
  206. package/src/gui/components/generics/Cards/ModuleCard.jsx +106 -0
  207. package/src/gui/components/generics/Chats/FullChatBot.jsx +223 -0
  208. package/src/gui/components/generics/Code/CodeBlock.jsx +33 -0
  209. package/src/gui/components/generics/EmojiCursor/EmojiCursor.stories.tsx +153 -0
  210. package/src/gui/components/generics/EmojiCursor/EmojiCursor.tsx +23 -0
  211. package/src/gui/components/generics/Feedback/Callout.jsx +92 -0
  212. package/src/gui/components/generics/Layout/GridX.jsx +29 -0
  213. package/src/gui/components/generics/Layout/Hero2.jsx +132 -0
  214. package/src/gui/components/generics/Layout/PageContainer.jsx +29 -0
  215. package/src/gui/components/generics/Layout/PageDivider.jsx +20 -0
  216. package/src/gui/components/generics/Layout/Section.jsx +43 -0
  217. package/src/gui/components/generics/Layout/SectionHeader.jsx +21 -0
  218. package/src/gui/components/generics/Media/Img.jsx +58 -0
  219. package/src/gui/components/generics/Media/VideoEmbed.jsx +51 -0
  220. package/src/gui/components/generics/Organization/TableOfContents.jsx +51 -0
  221. package/src/gui/components/generics/Organization/Tabs.jsx +45 -0
  222. package/src/gui/components/generics/Text/TextList.jsx +41 -0
  223. package/src/gui/components/generics/Text/TextParagraph.jsx +28 -0
  224. package/src/gui/components/generics/Text/TextQuote.jsx +23 -0
  225. package/src/gui/components/generics/Text/TextTitle.jsx +44 -0
  226. package/src/gui/components/molecules/Dialog/Dialog.stories.tsx +18 -0
  227. package/src/gui/components/molecules/Dialog/Dialog.tsx +5 -0
  228. package/src/gui/components/molecules/Hero/Hero.stories.tsx +140 -0
  229. package/src/gui/components/molecules/Hero/Hero.tsx +152 -0
  230. package/src/gui/components/molecules/Hero/Hero.types.tsx +18 -0
  231. package/src/gui/components/molecules/Modal/Modal.resolver.tsx +38 -0
  232. package/src/gui/components/molecules/Modal/Modal.stories.tsx +82 -0
  233. package/src/gui/components/molecules/Modal/Modal.tsx +110 -0
  234. package/src/gui/components/molecules/Modal/Modal.types.ts +29 -0
  235. package/src/gui/components/molecules/Page/Page.stories.tsx +135 -0
  236. package/src/gui/components/molecules/Page/Page.tsx +94 -0
  237. package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.resolver.tsx +58 -0
  238. package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.stories.tsx +133 -0
  239. package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.tsx +101 -0
  240. package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.types.ts +29 -0
  241. package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.resolver.tsx +15 -0
  242. package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.stories.tsx +88 -0
  243. package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.tsx +167 -0
  244. package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.types.ts +34 -0
  245. package/src/gui/components/molecules/molecules.ts +49 -0
  246. package/src/gui/components/organisms/Blockchain/Blocks/BlocksTable.tsx +119 -0
  247. package/src/gui/components/organisms/Blockchain/Usernames/Identities.stories.tsx +20 -0
  248. package/src/gui/components/organisms/Blockchain/Usernames/QR.tsx +566 -0
  249. package/src/gui/components/organisms/Blockchain/Usernames/Usernames.tsx +448 -0
  250. package/src/gui/components/organisms/Blockchain/Usernames/identities.tsx +710 -0
  251. package/src/gui/components/organisms/Blockchain/blockchain.stories.tsx +17 -0
  252. package/src/gui/components/organisms/Blockchain/blockchain.tsx +368 -0
  253. package/src/gui/components/organisms/Blockchain/scripts/connection.ts +82 -0
  254. package/src/gui/components/organisms/Blockchain/scripts/match_face.ts +143 -0
  255. package/src/gui/components/organisms/HighLighter/HighLighter.stories.tsx +168 -0
  256. package/src/gui/components/organisms/HighLighter/HighLighter.tsx +420 -0
  257. package/src/gui/components/organisms/HighLighter/HighLightsDrawer.tsx +197 -0
  258. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/FaceRecognition.stories.tsx +312 -0
  259. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/FaceRecognition.tsx +765 -0
  260. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceCameraPermission.ts +70 -0
  261. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceLandmarker.ts +106 -0
  262. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceOverlay.ts +489 -0
  263. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceTemplate.ts +32 -0
  264. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceTemplateBurst.ts +178 -0
  265. package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/verifyTemplate.ts +136 -0
  266. package/src/gui/components/organisms/IdentityNoise/IdentityNoise.tsx +403 -0
  267. package/src/gui/components/organisms/IdentityNoise/IndentityNoise.stories.tsx +15 -0
  268. package/src/gui/components/organisms/IdentityNoise/Noise/Noise.stories.tsx +206 -0
  269. package/src/gui/components/organisms/IdentityNoise/Noise/Noise.tsx +394 -0
  270. package/src/gui/components/organisms/IdentityNoise/Triad/QR.tsx +566 -0
  271. package/src/gui/components/organisms/IdentityNoise/Triad/Tiad.stories.tsx +6 -0
  272. package/src/gui/components/organisms/IdentityNoise/Triad/Triad.tsx +917 -0
  273. package/src/gui/components/organisms/IdentityNoise/Triad/handleCleak.ts +0 -0
  274. package/src/gui/components/organisms/IdentityNoise/Triad/identity.ts +31 -0
  275. package/src/gui/components/organisms/IdentityNoise/Triad/me/fundamentals/vectors/vectors.tsx +252 -0
  276. package/src/gui/components/organisms/IdentityNoise/Triad/me/me.stories.tsx +314 -0
  277. package/src/gui/components/organisms/IdentityNoise/Triad/me/me.tsx +0 -0
  278. package/src/gui/components/organisms/organisms.ts +15 -0
  279. package/src/gui/contexts/InsetsContext.tsx +40 -0
  280. package/src/gui/contexts/LeftSidebarContext.tsx +20 -0
  281. package/src/gui/contexts/RightSidebarContext.tsx +25 -0
  282. package/src/gui/contexts/ThemeContext.ts +34 -0
  283. package/src/gui/contexts/index.ts +4 -0
  284. package/src/gui/hooks/index.ts +11 -0
  285. package/src/gui/hooks/resolveColorToken.ts +39 -0
  286. package/src/gui/hooks/useCodeGen.ts +12 -0
  287. package/src/gui/hooks/useGuiMediaQuery.ts +18 -0
  288. package/src/gui/hooks/useGuiTheme.ts +18 -0
  289. package/src/gui/hooks/useInsets.ts +26 -0
  290. package/src/gui/hooks/useIsMobile.ts +13 -0
  291. package/src/gui/hooks/useIsTouchDevice.ts +25 -0
  292. package/src/gui/hooks/useLeftSidebar.ts +10 -0
  293. package/src/gui/hooks/useRightSidebar.ts +12 -0
  294. package/src/gui/hooks/useViewportKey.ts +19 -0
  295. package/src/gui/hooks/useViewportProp.ts +17 -0
  296. package/src/gui/registry/GuiRegistry.ts +19 -0
  297. package/src/gui/registry/factory.ts +12 -0
  298. package/src/gui/registry/index.ts +3 -0
  299. package/src/gui/registry/types.ts +6 -0
  300. package/src/gui/utils/nodeID.ts +11 -0
  301. package/src/registry/GuiRegistry.ts +19 -0
  302. package/src/stories/01.Home.mdx +22 -0
  303. package/src/stories/02.Understanding.This.GUI.mdx +149 -0
  304. package/src/stories/Theme/Palette.stories.tsx +86 -0
  305. package/src/stories/Theme/ThemeViewer.stories.tsx +91 -0
  306. package/src/stories/Theme/Typography.stories.jsx +211 -0
  307. package/src/stories/assets/this.GUI.png +0 -0
  308. package/src/types/gui.d.ts +67 -0
  309. package/src/types/theme.d.ts +191 -0
  310. package/src/types/viewport.ts +132 -0
@@ -0,0 +1,917 @@
1
+ import React, { useState, useEffect, useMemo, useCallback } from "react";
2
+ import { useGuiTheme } from '@/gui/hooks';
3
+ import Box from '@/gui/atoms/Box/Box';
4
+ import TextField from "@/gui/components/atoms/TextField/TextField";
5
+ import Icon from "@/gui/Theme/Icon/Icon";
6
+ import Button from '@/gui/components/atoms/Button/Button';
7
+ import Tooltip from '@/gui/components/atoms/Tooltip/Tooltip';
8
+ import { useBlockchainConnection } from "@/gui/components/organisms/Blockchain/scripts/connection";
9
+ import { deriveIdentity } from "./identity";
10
+ import QR from "./QR";
11
+ import ME from "this.me";
12
+ import FaceRecognition from '../FaceRecognition/FaceRecognition';
13
+
14
+ export default function Triad() {
15
+ const theme = useGuiTheme();
16
+
17
+ // Username typed in the UI (raw text).
18
+ const [username, setUsername] = useState("");
19
+
20
+ // If the user types an invalid username, we keep the raw text in `username`
21
+ // but avoid feeding it into ME / network logic until it validates.
22
+ const [usernameError, setUsernameError] = useState<string | null>(null);
23
+
24
+ // Light, local validation to avoid exceptions from ME runtime.
25
+ // (We keep this intentionally permissive; ME is the source of truth.)
26
+ const validateUsername = useCallback((raw: string) => {
27
+ const v = String(raw || '').trim().toLowerCase();
28
+ if (!v) return { value: '', error: null as string | null };
29
+ // Basic DNS-ish username: a-z 0-9 underscore dash dot, 3-32 chars.
30
+ // This is just a UX guardrail; ME still validates on action.
31
+ if (v.length < 5) return { value: v, error: 'Username too short' };
32
+ if (v.length > 32) return { value: v, error: 'Username too long' };
33
+ if (!/^[a-z0-9._-]+$/.test(v)) return { value: v, error: 'Only a-z 0-9 . _ -' };
34
+ if (v.startsWith('.') || v.endsWith('.') || v.includes('..')) return { value: v, error: 'Invalid dots' };
35
+ return { value: v, error: null as string | null };
36
+ }, []);
37
+ const [secret, setSecret] = useState("");
38
+ const [showSecret, setShowSecret] = useState(false);
39
+ const [blockchain, setBlockchain] = useState("localhost:8161");
40
+ const [showIdentity, setShowIdentity] = useState(false);
41
+ const [showLedgerBox, setShowLedgerBox] = useState(false);
42
+ const [showFaceScan, setShowFaceScan] = useState(false);
43
+ const [faceCapture, setFaceCapture] = useState<string | null>(null);
44
+ const [showBlockchainInput, setShowBlockchainInput] = useState(false);
45
+ const [lastFacePayload, setLastFacePayload] = useState<any | null>(null);
46
+ const secretInputType = useMemo(() => (showSecret ? 'text' : 'password'), [showSecret]);
47
+ // this.me runtime (local semantic + crypto)
48
+ const me = useMemo(() => new ME(), []);
49
+ // Helper: normalized username only when valid.
50
+
51
+ // Mirror only blockchain host into ME (safe to do during typing).
52
+ // Identity claim '@' and secret '_' are applied explicitly on action (Cleak it).
53
+ // The hook provides blockchainHost and blockchainBaseUrl.
54
+ const normalizedUsername = useMemo(() => {
55
+ const { value, error } = validateUsername(username);
56
+ return error ? '' : value;
57
+ }, [username, validateUsername]);
58
+
59
+ // Only hit the server once the username is valid AND long enough, and no local error.
60
+ // (Also avoids calling while the user is still typing a short/invalid handle.)
61
+ const shouldQueryServer = useMemo(() => {
62
+ return Boolean(normalizedUsername) && normalizedUsername.length >= 5 && !usernameError;
63
+ }, [normalizedUsername, usernameError]);
64
+
65
+ // Gate the username we pass into the network hook.
66
+ // When empty, the hook should not call the server.
67
+ const networkUsername = shouldQueryServer ? normalizedUsername : '';
68
+
69
+ const { blockchainHost, blockchainBaseUrl, connectionStatus, usernameStatus } = useBlockchainConnection({
70
+ blockchain,
71
+ username: networkUsername,
72
+ me,
73
+ });
74
+
75
+ // server-derived identityHash for an existing username on this ledger
76
+ const userIdentityHash = shouldQueryServer
77
+ ? (me as any)(`ledger.user.${normalizedUsername}.identityHash`)
78
+ : undefined;
79
+ useEffect(() => {
80
+ try {
81
+ if (blockchainHost) (me as any).ledger.host(blockchainHost);
82
+ } catch {
83
+ // ignore
84
+ }
85
+ }, [me, blockchainHost]);
86
+ const namespace = connectionStatus === 'online' && normalizedUsername
87
+ ? `${normalizedUsername}@${blockchainHost}`
88
+ : `${blockchainHost || 'blockchain:none'}`;
89
+ const identity = useMemo(() => deriveIdentity({ secret, namespace }), [secret, namespace]);
90
+ const cleak = identity.identityRoot;
91
+
92
+ const [authStatus, setAuthStatus] = useState<'idle' | 'checking' | 'ok' | 'error'>('idle');
93
+ const [authError, setAuthError] = useState<string | null>(null);
94
+
95
+ const apiBaseUrl = useMemo(() => {
96
+ const s = String(blockchainBaseUrl || blockchain || '').trim();
97
+ if (!s) return '';
98
+ return s.startsWith('http') ? s.replace(/\/$/, '') : `http://${s.replace(/\/$/, '')}`;
99
+ }, [blockchainBaseUrl, blockchain]);
100
+
101
+ // Face matching (server-backed). Used to drive an on-face label (e.g. 404 NOT ENROLLED).
102
+ const [faceVerifyHttpStatus, setFaceVerifyHttpStatus] = useState<number | null>(null);
103
+ const [faceVerifyMessage, setFaceVerifyMessage] = useState<string | null>(null);
104
+ const [faceVerifyBusy, setFaceVerifyBusy] = useState(false);
105
+ const [faceHasStableTemplate, setFaceHasStableTemplate] = useState(false);
106
+
107
+ const facesMatchUrl = useMemo(() => {
108
+ const base = String(apiBaseUrl || '').trim();
109
+ return base ? `${base}/faces/match` : '';
110
+ }, [apiBaseUrl]);
111
+
112
+ const resetFaceVerify = useCallback(() => {
113
+ setFaceVerifyHttpStatus(null);
114
+ setFaceVerifyMessage(null);
115
+ setFaceVerifyBusy(false);
116
+ setLastFacePayload(null);
117
+ setFaceHasStableTemplate(false);
118
+ }, []);
119
+
120
+ const runFaceMatch = useCallback(async (probeTemplate: any) => {
121
+ if (!facesMatchUrl) {
122
+ setFaceVerifyHttpStatus(500);
123
+ setFaceVerifyMessage('NO MATCH URL');
124
+ return;
125
+ }
126
+ if (!normalizedUsername) {
127
+ setFaceVerifyHttpStatus(400);
128
+ setFaceVerifyMessage('USERNAME REQUIRED');
129
+ return;
130
+ }
131
+ // Accept either raw vector (number[]) or object containing { template: number[] }
132
+ const tpl = probeTemplate;
133
+ const probeVector = Array.isArray(tpl)
134
+ ? tpl
135
+ : Array.isArray((tpl as any)?.template)
136
+ ? (tpl as any).template
137
+ : null;
138
+
139
+ if (!probeVector || probeVector.length < 8) {
140
+ setFaceVerifyHttpStatus(400);
141
+ setFaceVerifyMessage('INVALID TEMPLATE');
142
+ return;
143
+ }
144
+
145
+ setFaceVerifyBusy(true);
146
+ setFaceVerifyHttpStatus(102);
147
+ setFaceVerifyMessage('VERIFYING…');
148
+
149
+ try {
150
+ const resp = await fetch(facesMatchUrl, {
151
+ method: 'POST',
152
+ headers: { 'Content-Type': 'application/json' },
153
+ body: JSON.stringify({ username: normalizedUsername, template: tpl }),
154
+ });
155
+
156
+ const json = await resp.json().catch(() => null);
157
+ if (!resp.ok) {
158
+ if (resp.status === 404) {
159
+ setFaceVerifyHttpStatus(404);
160
+ // 404 from /faces/match means there is no enrolled face for this username yet.
161
+ // For Cleaker UX, treat this as "available to claim".
162
+ const cleanHost = String(blockchainHost || blockchain || 'localhost')
163
+ .split(',')[0]
164
+ .trim()
165
+ .replace(/^https?:\/\//i, '')
166
+ .split(':')[0]
167
+ .trim();
168
+
169
+ const claimLabel = normalizedUsername
170
+ ? `AVAILABLE • CLAIM ${normalizedUsername}.${cleanHost}!`
171
+ : 'AVAILABLE • CLAIM USERNAME!';
172
+ setFaceVerifyMessage(claimLabel);
173
+ return;
174
+ }
175
+ setFaceVerifyHttpStatus(resp.status);
176
+ setFaceVerifyMessage(String(json?.error || json?.message || `HTTP ${resp.status}`));
177
+ return;
178
+ }
179
+
180
+ const match = Boolean((json as any)?.match);
181
+ const score = Number((json as any)?.score ?? (json as any)?.best?.score ?? 0);
182
+
183
+ setFaceVerifyHttpStatus(match ? 200 : 401);
184
+ setFaceVerifyMessage(match ? `MATCH ${score ? score.toFixed(3) : ''}`.trim() : `NO MATCH ${score ? score.toFixed(3) : ''}`.trim());
185
+ } catch (e: any) {
186
+ setFaceVerifyHttpStatus(500);
187
+ setFaceVerifyMessage(String(e?.message || 'VERIFY ERROR'));
188
+ } finally {
189
+ setFaceVerifyBusy(false);
190
+ }
191
+ }, [facesMatchUrl, normalizedUsername, blockchainHost, blockchain]);
192
+
193
+
194
+ const checkSecretMatches = useCallback(() => {
195
+ // If the username exists on this ledger, the server returns the claimed identityHash.
196
+ // We validate by recomputing identityHash from (secret, namespace) and comparing.
197
+ if (usernameStatus !== 'exists') return true;
198
+ if (!userIdentityHash) return false;
199
+ return String(userIdentityHash).trim() === String(identity.identityRoot).trim();
200
+ }, [usernameStatus, userIdentityHash, identity.identityRoot]);
201
+
202
+ const handleCleak = useCallback(async () => {
203
+ const { value: u, error: uErr } = validateUsername(username);
204
+ if (!u || uErr) {
205
+ setAuthStatus('error');
206
+ setAuthError(uErr || 'Invalid username');
207
+ return;
208
+ }
209
+
210
+ // Must be online to read/write to this ledger
211
+ if (connectionStatus !== 'online') {
212
+ setAuthStatus('error');
213
+ setAuthError('Ledger is offline');
214
+ return;
215
+ }
216
+
217
+ // Must have secret for both claim and verify.
218
+ if (!secret) {
219
+ setAuthStatus('error');
220
+ setAuthError('Secret is required');
221
+ return;
222
+ }
223
+
224
+ setAuthStatus('checking');
225
+ setAuthError(null);
226
+
227
+ // 1) If username exists -> verify secret matches
228
+ if (usernameStatus === 'exists') {
229
+ const ok = checkSecretMatches();
230
+ if (!ok) {
231
+ setAuthStatus('error');
232
+ setAuthError('Secret does not match this username on this ledger');
233
+ return;
234
+ }
235
+
236
+ // Apply ME algebra only when verified
237
+ try { (me as any)['@'](u); } catch {}
238
+ try { (me as any)['_'](secret); } catch {}
239
+
240
+ setAuthStatus('ok');
241
+ window.setTimeout(() => setAuthStatus('idle'), 900);
242
+ return;
243
+ }
244
+
245
+ // 2) If username is available -> claim it (POST /users)
246
+ if (usernameStatus !== 'available') {
247
+ setAuthStatus('error');
248
+ setAuthError('Username must be available to claim, or exist to verify');
249
+ return;
250
+ }
251
+
252
+ // Apply ME algebra explicitly at action time.
253
+ try { (me as any)['@'](u); } catch (e: any) {
254
+ setAuthStatus('error');
255
+ setAuthError(e?.message ?? 'Invalid username');
256
+ return;
257
+ }
258
+ try { (me as any)['_'](secret); } catch (e: any) {
259
+ setAuthStatus('error');
260
+ setAuthError(e?.message ?? 'Invalid secret');
261
+ return;
262
+ }
263
+
264
+ const identityHash = String(identity.identityRoot || '').trim();
265
+ const publicKey = '0x';
266
+
267
+ try {
268
+ const resp = await fetch(`${apiBaseUrl}/users`, {
269
+ method: 'POST',
270
+ headers: { 'Content-Type': 'application/json' },
271
+ body: JSON.stringify({ username: u, identityHash, publicKey }),
272
+ });
273
+
274
+ const payload = await resp.json().catch(() => null);
275
+ if (!resp.ok) {
276
+ const msg = payload?.error || payload?.message || `HTTP ${resp.status}`;
277
+ throw new Error(msg);
278
+ }
279
+
280
+ setAuthStatus('ok');
281
+ window.setTimeout(() => setAuthStatus('idle'), 900);
282
+ } catch (e: any) {
283
+ setAuthStatus('error');
284
+ setAuthError(e?.message ?? 'Failed to claim username');
285
+ }
286
+ }, [apiBaseUrl, checkSecretMatches, connectionStatus, identity.identityRoot, me, secret, username, usernameStatus]);
287
+ return (
288
+ <>
289
+ <Box
290
+ sx={{
291
+ border: `1px solid ${theme.palette.section.subtle}`,
292
+ borderRadius: "12px",
293
+ p: 1.5,
294
+ width: "300px",
295
+ mx: "auto",
296
+ background:
297
+ theme.palette.mode === "dark"
298
+ ? theme.palette.section.default
299
+ : theme.palette.section.subtle,
300
+ position: "relative",
301
+ }}
302
+ >
303
+ <Button
304
+ variant="text"
305
+ size="small"
306
+ onClick={() => setShowBlockchainInput((v) => !v)}
307
+ sx={{
308
+ position: 'absolute',
309
+ top: 6,
310
+ right: 6,
311
+ minWidth: '28px',
312
+ width: '28px',
313
+ height: '28px',
314
+ p: 0,
315
+ borderRadius: '8px',
316
+ color:
317
+ !blockchainHost || connectionStatus === 'idle'
318
+ ? theme.palette.divider
319
+ : connectionStatus === 'connecting'
320
+ ? 'yellow'
321
+ : connectionStatus === 'online'
322
+ ? 'green'
323
+ : 'red',
324
+ '&:hover': {
325
+ background: theme.palette.action.hover,
326
+ },
327
+ }}
328
+ aria-label={showBlockchainInput ? 'Hide blockchain input' : 'Show blockchain input'}
329
+ >
330
+ <Icon name="dns" fontSize={18} />
331
+ </Button>
332
+
333
+ <Box sx={{ display: "flex", justifyContent: "center" }}>
334
+ <pre style={{ margin: 0, padding: 0, lineHeight: "12px", fontSize: "12px", color: theme.palette.text.primary }}>
335
+ {`
336
+ ┓ ┏┓
337
+ ┓┏┏┣┓┏┓┏┛
338
+ •┗┻┛┛┗┗┛•
339
+ `}
340
+ </pre>
341
+ </Box>
342
+
343
+ <Box
344
+ sx={{
345
+ display: "flex",
346
+ flexDirection: "column",
347
+ gap: 1.25,
348
+ mt: 1.75,
349
+ width: "100%",
350
+ px: 0.5,
351
+ }}
352
+ >
353
+ {connectionStatus === 'online' && (
354
+ <Box sx={{ display: "flex", gap: 1, mb: 0.25 }}>
355
+ <TextField
356
+ label="Username"
357
+ variant="outlined"
358
+ autoComplete="off"
359
+ value={username}
360
+ onChange={(e) => {
361
+ const next = e.target.value;
362
+ setUsername(next);
363
+ const { error } = validateUsername(next);
364
+ setUsernameError(error);
365
+ }}
366
+ error={Boolean(usernameError)}
367
+ helperText={usernameError || undefined}
368
+ fullWidth
369
+ slotProps={{
370
+ htmlInput: {
371
+ autoCapitalize: 'none',
372
+ autoCorrect: 'off',
373
+ spellCheck: false,
374
+ inputMode: 'text',
375
+ },
376
+ input: {
377
+ endAdornment: (
378
+ <Box sx={{ display: 'flex', alignItems: 'center', pr: 0.25 }}>
379
+ <Tooltip
380
+ title="Create a new username by typing it, then check availability on this blockchain."
381
+ placement="top"
382
+ arrow
383
+ >
384
+ <Box
385
+ component="span"
386
+ sx={{
387
+ fontSize: '11px',
388
+ color: 'text.secondary',
389
+ opacity: 0.85,
390
+ cursor: 'help',
391
+ userSelect: 'none',
392
+ lineHeight: 1,
393
+ }}
394
+ >
395
+ new?
396
+ </Box>
397
+ </Tooltip>
398
+ </Box>
399
+ ),
400
+ },
401
+ }}
402
+ sx={{
403
+ '& input:-webkit-autofill, & input:-webkit-autofill:hover, & input:-webkit-autofill:focus, & input:-webkit-autofill:active': {
404
+ WebkitBoxShadow: `0 0 0 1000px ${theme.palette.background.paper} inset`,
405
+ WebkitTextFillColor: theme.palette.text.primary,
406
+ caretColor: theme.palette.text.primary,
407
+ transition: 'background-color 9999s ease-out 0s',
408
+ },
409
+ '& .MuiOutlinedInput-root': {
410
+ borderRadius: '10px',
411
+ position: 'relative',
412
+ '&:after': {
413
+ content: '""',
414
+ position: 'absolute',
415
+ top: 0,
416
+ bottom: 0,
417
+ right: 0,
418
+ width: '6px',
419
+ borderRadius: '0 10px 10px 0',
420
+ backgroundColor:
421
+ !username || usernameStatus === 'idle'
422
+ ? theme.palette.divider
423
+ : usernameStatus === 'checking'
424
+ ? 'yellow'
425
+ : usernameStatus === 'exists'
426
+ ? 'green'
427
+ : usernameStatus === 'available'
428
+ ? 'blue'
429
+ : 'red',
430
+ pointerEvents: 'none',
431
+ zIndex: 2,
432
+ }
433
+ }
434
+ }}
435
+ />
436
+ </Box>
437
+ )}
438
+
439
+ {connectionStatus === 'online' && shouldQueryServer && usernameStatus === 'available' && (
440
+ <Box sx={{ mt: -0.25, mb: 0.75, px: 1 }}>
441
+ <span style={{ fontSize: '11px', color: theme.palette.text.secondary }}>
442
+ Username is available. Follow steps to claim.
443
+ </span>
444
+ </Box>
445
+ )}
446
+
447
+ {(usernameStatus === 'exists' || usernameStatus === 'available') && (
448
+ <TextField
449
+ label="Secret"
450
+ type={secretInputType}
451
+ variant="outlined"
452
+ autoComplete="new-password"
453
+ value={secret}
454
+ onChange={(e) => { setSecret(e.target.value); setAuthStatus('idle'); setAuthError(null); }}
455
+ fullWidth
456
+ slotProps={{
457
+ htmlInput: {
458
+ autoCapitalize: 'none',
459
+ autoCorrect: 'off',
460
+ spellCheck: false,
461
+ },
462
+ input: {
463
+ endAdornment: (
464
+ <Button
465
+ variant="text"
466
+ size="small"
467
+ onClick={() => setShowSecret((v) => !v)}
468
+ sx={{
469
+ minWidth: '32px',
470
+ p: 0,
471
+ mr: '-6px',
472
+ color: secret ? theme.palette.text.secondary : theme.palette.divider,
473
+ }}
474
+ aria-label={showSecret ? 'Hide secret' : 'Show secret'}
475
+ >
476
+ <Icon name={showSecret ? "visibility_off" : "visibility"} fontSize={18} fill={showSecret ? 1 : 0} />
477
+ </Button>
478
+ ),
479
+ },
480
+ }}
481
+ sx={{
482
+ '& input:-webkit-autofill, & input:-webkit-autofill:hover, & input:-webkit-autofill:focus, & input:-webkit-autofill:active': {
483
+ WebkitBoxShadow: `0 0 0 1000px ${theme.palette.background.paper} inset`,
484
+ WebkitTextFillColor: theme.palette.text.primary,
485
+ caretColor: theme.palette.text.primary,
486
+ transition: 'background-color 9999s ease-out 0s',
487
+ },
488
+ }}
489
+ />
490
+ )}
491
+
492
+ {showBlockchainInput && (
493
+ <TextField
494
+ label="Blockchain"
495
+ variant="outlined"
496
+ autoComplete="off"
497
+ slotProps={{
498
+ htmlInput: {
499
+ autoCapitalize: 'none',
500
+ autoCorrect: 'off',
501
+ spellCheck: false,
502
+ inputMode: 'url',
503
+ },
504
+ }}
505
+ value={blockchain}
506
+ onChange={(e) => setBlockchain(e.target.value)}
507
+ fullWidth
508
+ sx={{
509
+ '& input:-webkit-autofill, & input:-webkit-autofill:hover, & input:-webkit-autofill:focus, & input:-webkit-autofill:active': {
510
+ WebkitBoxShadow: `0 0 0 1000px ${theme.palette.background.paper} inset`,
511
+ WebkitTextFillColor: theme.palette.text.primary,
512
+ caretColor: theme.palette.text.primary,
513
+ transition: 'background-color 9999s ease-out 0s',
514
+ },
515
+ '& .MuiOutlinedInput-root': {
516
+ borderRadius: '10px',
517
+ position: 'relative',
518
+ '&:after': {
519
+ content: '""',
520
+ position: 'absolute',
521
+ top: 0,
522
+ bottom: 0,
523
+ right: 0,
524
+ width: '6px',
525
+ borderRadius: '0 10px 10px 0',
526
+ backgroundColor:
527
+ !blockchainHost || connectionStatus === 'idle'
528
+ ? theme.palette.divider
529
+ : connectionStatus === 'connecting'
530
+ ? 'yellow'
531
+ : connectionStatus === 'online'
532
+ ? 'green'
533
+ : 'red',
534
+ pointerEvents: 'none',
535
+ zIndex: 2,
536
+ }
537
+ }
538
+ }}
539
+ />
540
+ )}
541
+ </Box>
542
+ </Box>
543
+
544
+ {secret && blockchain && (
545
+ <>
546
+ <Box
547
+ sx={{
548
+ mt: 2,
549
+ p: 1.25,
550
+ border: "1px solid rgba(0,255,255,0.3)",
551
+ borderRadius: "12px",
552
+ color: theme.palette.mode === "light" ? "#006677" : "#99faff",
553
+ fontFamily: "monospace",
554
+ wordBreak: "break-all",
555
+ width: "300px",
556
+ mx: "auto",
557
+ }}
558
+ >
559
+ <Box
560
+ sx={{
561
+ mb: 1.25,
562
+ overflow: 'hidden',
563
+ borderRadius: '14px',
564
+ background:
565
+ theme.palette.mode === 'dark'
566
+ ? theme.palette.section.subtle
567
+ : theme.palette.section.default,
568
+ border: `1px solid ${theme.palette.divider}`,
569
+ width: '100%',
570
+ position: 'relative',
571
+ }}
572
+ >
573
+ <Button
574
+ variant="text"
575
+ size="small"
576
+ onClick={() => setShowLedgerBox((prev) => !prev)}
577
+ sx={{
578
+ position: 'absolute',
579
+ top: 6,
580
+ right: 6,
581
+ minWidth: '24px',
582
+ width: '24px',
583
+ height: '24px',
584
+ p: 0,
585
+ borderRadius: '8px',
586
+ color: theme.palette.text.secondary,
587
+ background: theme.palette.mode === 'dark'
588
+ ? 'rgba(0,0,0,0.25)'
589
+ : 'rgba(255,255,255,0.35)',
590
+ backdropFilter: 'blur(6px)',
591
+ '&:hover': {
592
+ background: theme.palette.action.hover,
593
+ },
594
+ }}
595
+ aria-label={showLedgerBox ? 'Hide ledger box' : 'Show ledger box'}
596
+ >
597
+ <Icon name="info" fontSize={16} fill={showLedgerBox ? 1 : 0} />
598
+ </Button>
599
+ <Box
600
+ sx={{
601
+ pt: 0.35,
602
+ pb: 0.75,
603
+ px: 0.75,
604
+ display: 'flex',
605
+ flexDirection: 'column',
606
+ alignItems: 'center',
607
+ justifyContent: 'center',
608
+ gap: 0.15,
609
+ // cursor removed to make QR non-interactive
610
+ }}
611
+ >
612
+ {showFaceScan ? (
613
+ <>
614
+ <FaceRecognition
615
+ open={showFaceScan}
616
+ onClose={() => {
617
+ setShowFaceScan(false);
618
+ resetFaceVerify();
619
+ }}
620
+ onCapture={(img) => {
621
+ setFaceCapture(img);
622
+ setShowFaceScan(false);
623
+ }}
624
+ title="Face Scan"
625
+ variant="inline"
626
+ showLandmarks
627
+ verifyHttpStatus={faceVerifyHttpStatus}
628
+ verifyMessage={faceVerifyMessage}
629
+ onTemplate={(template: any) => {
630
+ // A template only exists when a face was detected and stabilized.
631
+ // If FaceRecognition ever emits a null/empty template, treat it as "no face".
632
+ if (!template || (Array.isArray(template) && template.length === 0)) {
633
+ setFaceHasStableTemplate(false);
634
+ setLastFacePayload(null);
635
+ resetFaceVerify();
636
+ return;
637
+ }
638
+
639
+ setFaceHasStableTemplate(true);
640
+ setLastFacePayload(template);
641
+
642
+ // Only run match when a stable template exists.
643
+ const now = Date.now();
644
+ const lastAt = (me as any)?.__lastFaceMatchAt || 0;
645
+ if (now - lastAt < 2000) return;
646
+ try { (me as any).__lastFaceMatchAt = now; } catch {}
647
+
648
+ runFaceMatch(template);
649
+ }}
650
+ />
651
+ <Box
652
+ sx={{
653
+ mt: 0.75,
654
+ px: 1,
655
+ py: 0.65,
656
+ borderRadius: '10px',
657
+ border: `1px solid ${theme.palette.divider}`,
658
+ color: theme.palette.text.secondary,
659
+ fontSize: '11px',
660
+ textAlign: 'center',
661
+ whiteSpace: 'pre-line',
662
+ userSelect: 'none',
663
+ }}
664
+ >
665
+ {faceVerifyBusy
666
+ ? 'Verifying…'
667
+ : !faceHasStableTemplate
668
+ ? 'Center your face'
669
+ : faceVerifyHttpStatus === 404
670
+ ? `Available\n${normalizedUsername || 'username'}.${String(blockchainHost || 'localhost').split(':')[0]}`
671
+ : faceVerifyHttpStatus
672
+ ? `${faceVerifyHttpStatus}${faceVerifyMessage ? ` • ${faceVerifyMessage}` : ''}`
673
+ : 'Center your face'}
674
+
675
+ <Box
676
+ sx={{
677
+ mt: 0.6,
678
+ display: 'flex',
679
+ gap: 0.75,
680
+ justifyContent: 'center',
681
+ }}
682
+ >
683
+ <Button
684
+ variant="contained"
685
+ size="small"
686
+ onClick={() => {
687
+ handleCleak();
688
+ setShowFaceScan(false);
689
+ resetFaceVerify();
690
+ }}
691
+ sx={{
692
+ borderRadius: '10px',
693
+ textTransform: 'none',
694
+ fontWeight: 800,
695
+ minWidth: '96px',
696
+ }}
697
+ disabled={faceVerifyBusy || !faceHasStableTemplate || faceVerifyHttpStatus !== 404}
698
+ >
699
+ Claim
700
+ </Button>
701
+ <Button
702
+ variant="text"
703
+ size="small"
704
+ onClick={() => {
705
+ setShowFaceScan(false);
706
+ resetFaceVerify();
707
+ }}
708
+ sx={{
709
+ borderRadius: '10px',
710
+ textTransform: 'none',
711
+ fontWeight: 700,
712
+ }}
713
+ >
714
+ Close
715
+ </Button>
716
+ </Box>
717
+ </Box>
718
+ </>
719
+ ) : (
720
+ <QR
721
+ value={identity.identityRoot}
722
+ size={144}
723
+ fg={theme.palette.primary.main}
724
+ ecc="H"
725
+ embedMode="positive-overlay"
726
+ embedScale={0.36}
727
+ embedBitmap={[
728
+ "000000000000000000000000000111111000",
729
+ "000000000000000000000000000111111000",
730
+ "111000111111111110000000111111111111",
731
+ "111000111111111110000000111000000111",
732
+ "111000111111111110000000111000000111",
733
+ "000000111001111001110000111111111111",
734
+ "000000111001111001110000111111111111",
735
+ "000000111001111001110000111111111111",
736
+ "000000111001111001110000111000000000",
737
+ "000000111001111001110000111000000000",
738
+ "000000000000000000000000000000000000",
739
+ "000000111000000001110000111000000000",
740
+ "000000111000000001110000111000000000",
741
+ "000000111000000001110000111111111111",
742
+ "000000111000000001110000000111111111",
743
+ "000000111000000001110000000111111111",
744
+ ]}
745
+ />
746
+ )}
747
+ </Box>
748
+ {showLedgerBox && (
749
+ <Box
750
+ sx={{
751
+ display: 'flex',
752
+ alignItems: 'center',
753
+ justifyContent: 'space-between',
754
+ gap: 1,
755
+ px: 1,
756
+ py: 0.35,
757
+ borderTop: `1px solid ${theme.palette.divider}`,
758
+ background:
759
+ theme.palette.mode === 'dark'
760
+ ? theme.palette.section.default
761
+ : theme.palette.section.subtle,
762
+ }}
763
+ >
764
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: '2px', minWidth: 0, flex: 1 }}>
765
+ <span
766
+ style={{
767
+ fontSize: '9px',
768
+ lineHeight: '11px',
769
+ color: theme.palette.primary.main,
770
+ fontFamily: 'monospace',
771
+ letterSpacing: 0.2,
772
+ userSelect: 'text',
773
+ overflow: 'hidden',
774
+ textOverflow: 'ellipsis',
775
+ whiteSpace: 'nowrap',
776
+ opacity: 0.9,
777
+ }}
778
+ title={blockchainHost || 'blockchain:none'}
779
+ >
780
+ {blockchainHost || 'blockchain:none'}
781
+ </span>
782
+
783
+ <span
784
+ style={{
785
+ fontSize: '9px',
786
+ lineHeight: '11px',
787
+ color: theme.palette.text.secondary,
788
+ fontFamily: 'monospace',
789
+ letterSpacing: 0.2,
790
+ userSelect: 'text',
791
+ overflow: 'hidden',
792
+ textOverflow: 'ellipsis',
793
+ whiteSpace: 'nowrap',
794
+ }}
795
+ title={identity.identityRoot}
796
+ >
797
+ {showIdentity
798
+ ? (identity.identityRoot || '')
799
+ : identity.identityRoot
800
+ ? `••••••••••••••••••••••••••${identity.identityRoot.slice(-4)}`
801
+ : '••••'}
802
+ </span>
803
+ </Box>
804
+
805
+ <Button
806
+ variant="text"
807
+ size="small"
808
+ onClick={() => setShowIdentity((prev) => !prev)}
809
+ sx={{
810
+ minWidth: '28px',
811
+ width: '28px',
812
+ height: '22px',
813
+ p: 0,
814
+ borderRadius: '8px',
815
+ color: theme.palette.text.secondary,
816
+ '&:hover': { background: theme.palette.action.hover },
817
+ }}
818
+ aria-label={showIdentity ? 'Hide identity' : 'Show identity'}
819
+ >
820
+ <Icon
821
+ name={showIdentity ? 'visibility_off' : 'visibility'}
822
+ fontSize={16}
823
+ fill={showIdentity ? 1 : 0}
824
+ />
825
+ </Button>
826
+ </Box>
827
+ )}
828
+ </Box>
829
+
830
+ {/* CTA */}
831
+ {!showFaceScan ? (
832
+ <>
833
+ <Box
834
+ sx={{
835
+ mt: 0.75,
836
+ px: 1,
837
+ py: 0.75,
838
+ borderRadius: '12px',
839
+ border: `1px solid ${theme.palette.divider}`,
840
+ background:
841
+ theme.palette.mode === 'dark'
842
+ ? theme.palette.section.default
843
+ : theme.palette.section.subtle,
844
+ display: 'flex',
845
+ alignItems: 'center',
846
+ justifyContent: 'space-between',
847
+ gap: 1,
848
+ }}
849
+ >
850
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: '2px', minWidth: 0, flex: 1 }}>
851
+ <span style={{ fontSize: '11px', color: theme.palette.text.primary, fontWeight: 700 }}>
852
+ Validate Identity.
853
+ </span>
854
+ <span
855
+ style={{
856
+ fontSize: '11px',
857
+ color: theme.palette.text.secondary,
858
+ overflow: 'hidden',
859
+ textOverflow: 'ellipsis',
860
+ whiteSpace: 'nowrap',
861
+ }}
862
+ title={blockchainHost || 'blockchain:none'}
863
+ >
864
+ to claim a username on {blockchainHost || 'this blockchain'}
865
+ </span>
866
+ </Box>
867
+
868
+ <Button
869
+ variant="contained"
870
+ size="small"
871
+ onClick={() => {
872
+ setAuthStatus('idle');
873
+ setAuthError(null);
874
+ resetFaceVerify();
875
+ setShowFaceScan(true);
876
+ }}
877
+ aria-label="Validate with face recognition"
878
+ sx={{
879
+ borderRadius: '10px',
880
+ textTransform: 'none',
881
+ fontWeight: 700,
882
+ minWidth: '128px',
883
+ display: 'flex',
884
+ alignItems: 'center',
885
+ justifyContent: 'center',
886
+ }}
887
+ disabled={!secret || !normalizedUsername || !facesMatchUrl || faceVerifyBusy}
888
+ >
889
+ <Icon name="face_unlock" fontSize={20} fill={1} />
890
+ </Button>
891
+ </Box>
892
+
893
+ {authStatus === 'checking' ? (
894
+ <span style={{ fontSize: '11px', color: theme.palette.text.secondary, paddingLeft: 2 }}>
895
+ {usernameStatus === 'exists' ? 'Verifying secret…' : 'Claiming username…'}
896
+ </span>
897
+ ) : null}
898
+
899
+ {authStatus === 'error' && authError ? (
900
+ <span style={{ fontSize: '11px', color: theme.palette.error.main, paddingLeft: 2 }}>
901
+ {authError}
902
+ </span>
903
+ ) : null}
904
+
905
+ {authStatus === 'ok' ? (
906
+ <span style={{ fontSize: '11px', color: theme.palette.success.main, paddingLeft: 2 }}>
907
+ {usernameStatus === 'exists' ? 'Secret verified.' : 'Username claimed.'}
908
+ </span>
909
+ ) : null}
910
+ </>
911
+ ) : null}
912
+ </Box>
913
+ </>
914
+ )}
915
+ </>
916
+ );
917
+ }