@reddb-io/ui 0.1.1

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 (169) hide show
  1. package/LICENSE +17 -0
  2. package/bin/red-ui.js +259 -0
  3. package/build/CNAME +1 -0
  4. package/build/_app/env.js +1 -0
  5. package/build/_app/immutable/assets/0.C63jY5jX.css +1 -0
  6. package/build/_app/immutable/assets/10.Dblyk0Kr.css +1 -0
  7. package/build/_app/immutable/assets/EmptyState.RXcH7ryE.css +1 -0
  8. package/build/_app/immutable/assets/Workspace.BCzG1DsH.css +1 -0
  9. package/build/_app/immutable/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2 +0 -0
  10. package/build/_app/immutable/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2 +0 -0
  11. package/build/_app/immutable/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2 +0 -0
  12. package/build/_app/immutable/assets/inter-greek-wght-normal.CkhJZR-_.woff2 +0 -0
  13. package/build/_app/immutable/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2 +0 -0
  14. package/build/_app/immutable/assets/inter-latin-wght-normal.Dx4kXJAl.woff2 +0 -0
  15. package/build/_app/immutable/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2 +0 -0
  16. package/build/_app/immutable/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2 +0 -0
  17. package/build/_app/immutable/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2 +0 -0
  18. package/build/_app/immutable/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2 +0 -0
  19. package/build/_app/immutable/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2 +0 -0
  20. package/build/_app/immutable/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2 +0 -0
  21. package/build/_app/immutable/chunks/3j4cZ58b.js +1 -0
  22. package/build/_app/immutable/chunks/69_IOA4Y.js +1 -0
  23. package/build/_app/immutable/chunks/ALqaDrNQ.js +2 -0
  24. package/build/_app/immutable/chunks/BGcIe2ep.js +2 -0
  25. package/build/_app/immutable/chunks/BMHKbvs8.js +1 -0
  26. package/build/_app/immutable/chunks/BQHbwf54.js +916 -0
  27. package/build/_app/immutable/chunks/Bgso8cDH.js +311 -0
  28. package/build/_app/immutable/chunks/Bmgx1mfv.js +310 -0
  29. package/build/_app/immutable/chunks/BrvvOVaJ.js +1 -0
  30. package/build/_app/immutable/chunks/Bzak7iHL.js +1 -0
  31. package/build/_app/immutable/chunks/D9CTkMjK.js +1 -0
  32. package/build/_app/immutable/chunks/DIeogL5L.js +1 -0
  33. package/build/_app/immutable/chunks/DXY_Rxa7.js +113 -0
  34. package/build/_app/immutable/chunks/DhEqZVGG.js +1 -0
  35. package/build/_app/immutable/chunks/Ov8N-vxt.js +1 -0
  36. package/build/_app/immutable/chunks/oiO4RLqp.js +1 -0
  37. package/build/_app/immutable/entry/app.D_IVtpdv.js +2 -0
  38. package/build/_app/immutable/entry/start.3oC0UQ_Q.js +1 -0
  39. package/build/_app/immutable/nodes/0.CHPiFxDo.js +1 -0
  40. package/build/_app/immutable/nodes/1.BC_4YZ0h.js +1 -0
  41. package/build/_app/immutable/nodes/10.B7DMKSNc.js +60 -0
  42. package/build/_app/immutable/nodes/2.CAG5_cGP.js +1 -0
  43. package/build/_app/immutable/nodes/3.CAG5_cGP.js +1 -0
  44. package/build/_app/immutable/nodes/4.CAG5_cGP.js +1 -0
  45. package/build/_app/immutable/nodes/5.CAG5_cGP.js +1 -0
  46. package/build/_app/immutable/nodes/6.CAG5_cGP.js +1 -0
  47. package/build/_app/immutable/nodes/7.BZX9Iird.js +134 -0
  48. package/build/_app/immutable/nodes/8.CAG5_cGP.js +1 -0
  49. package/build/_app/immutable/nodes/9.CAG5_cGP.js +1 -0
  50. package/build/_app/version.json +1 -0
  51. package/build/favicon.png +0 -0
  52. package/build/index.html +59 -0
  53. package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js +26562 -0
  54. package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js.map +1 -0
  55. package/dist/embed/bundle-mjs-UuVRz3O4.js +3047 -0
  56. package/dist/embed/bundle-mjs-UuVRz3O4.js.map +1 -0
  57. package/dist/embed/core-QuRYvMt8.js +118 -0
  58. package/dist/embed/core-QuRYvMt8.js.map +1 -0
  59. package/dist/embed/index-B6ZQhCsu.js +577 -0
  60. package/dist/embed/index-B6ZQhCsu.js.map +1 -0
  61. package/dist/embed/index-client-ItCEU64C.js +3087 -0
  62. package/dist/embed/index-client-ItCEU64C.js.map +1 -0
  63. package/dist/embed/index-fad77a13.esm-BqPj0saH.js +1318 -0
  64. package/dist/embed/index-fad77a13.esm-BqPj0saH.js.map +1 -0
  65. package/dist/embed/index.js +11 -0
  66. package/dist/embed/index.js.map +1 -0
  67. package/dist/embed/sigma-node-border.esm-CGtlgqmo.js +432 -0
  68. package/dist/embed/sigma-node-border.esm-CGtlgqmo.js.map +1 -0
  69. package/dist/embed/sigma.esm-y0qgY-OC.js +2355 -0
  70. package/dist/embed/sigma.esm-y0qgY-OC.js.map +1 -0
  71. package/dist/embed/ui.css +1 -0
  72. package/package.json +101 -0
  73. package/src/app.css +238 -0
  74. package/src/lib/ActivityIndicator.svelte +100 -0
  75. package/src/lib/ClusterNode.svelte +119 -0
  76. package/src/lib/ClusterView.svelte +541 -0
  77. package/src/lib/CollectionHistory.svelte +266 -0
  78. package/src/lib/CollectionsView.svelte +14 -0
  79. package/src/lib/CommandPalette.svelte +237 -0
  80. package/src/lib/ConnectDropdown.svelte +222 -0
  81. package/src/lib/EmptyState.svelte +27 -0
  82. package/src/lib/LiveChanges.svelte +195 -0
  83. package/src/lib/MasterPasswordDialog.svelte +168 -0
  84. package/src/lib/PageHeader.svelte +32 -0
  85. package/src/lib/PendingChangesPanel.svelte +153 -0
  86. package/src/lib/QueryEditor.svelte +122 -0
  87. package/src/lib/ResultsPane.svelte +747 -0
  88. package/src/lib/SchemaTree.svelte +193 -0
  89. package/src/lib/SecurityView.svelte +255 -0
  90. package/src/lib/ShortcutOverlay.svelte +104 -0
  91. package/src/lib/Splash.svelte +46 -0
  92. package/src/lib/StatusBar.svelte +163 -0
  93. package/src/lib/SubNav.svelte +62 -0
  94. package/src/lib/Topbar.svelte +119 -0
  95. package/src/lib/Workspace.svelte +247 -0
  96. package/src/lib/activity.svelte.ts +91 -0
  97. package/src/lib/build-info.ts +41 -0
  98. package/src/lib/capability.ts +221 -0
  99. package/src/lib/cn.ts +6 -0
  100. package/src/lib/collection-catalog.ts +116 -0
  101. package/src/lib/collection-pages.ts +33 -0
  102. package/src/lib/connection-history.ts +301 -0
  103. package/src/lib/connections.svelte.ts +493 -0
  104. package/src/lib/embed/RedUiEmbedRoot.svelte +31 -0
  105. package/src/lib/embed/index.ts +234 -0
  106. package/src/lib/graph-loader/contract.ts +336 -0
  107. package/src/lib/graph-loader/drilldown.ts +334 -0
  108. package/src/lib/graph-loader/index.ts +13 -0
  109. package/src/lib/index.ts +114 -0
  110. package/src/lib/pending-changes.svelte.ts +149 -0
  111. package/src/lib/query-tabs.svelte.ts +130 -0
  112. package/src/lib/reddb/boot-params.ts +254 -0
  113. package/src/lib/reddb/cdc-stream-client.ts +234 -0
  114. package/src/lib/reddb/client.ts +698 -0
  115. package/src/lib/reddb/connection-bootstrap.ts +260 -0
  116. package/src/lib/reddb/connection-provider.contract.ts +72 -0
  117. package/src/lib/reddb/connection-provider.ts +72 -0
  118. package/src/lib/reddb/index.ts +14 -0
  119. package/src/lib/reddb/injected-client-provider.ts +76 -0
  120. package/src/lib/reddb/local-url-provider.ts +245 -0
  121. package/src/lib/reddb/secure-store.ts +41 -0
  122. package/src/lib/reddb/server-capabilities.ts +71 -0
  123. package/src/lib/reddb/tauri-encrypted-store.ts +64 -0
  124. package/src/lib/reddb/transports.ts +89 -0
  125. package/src/lib/reddb/types.ts +32 -0
  126. package/src/lib/reddb/uri.ts +54 -0
  127. package/src/lib/reddb/web-encrypted-store.ts +201 -0
  128. package/src/lib/renderers/DiffRenderer.svelte +184 -0
  129. package/src/lib/renderers/DocumentRenderer.svelte +134 -0
  130. package/src/lib/renderers/GraphRenderer.svelte +1328 -0
  131. package/src/lib/renderers/HypertableRenderer.svelte +253 -0
  132. package/src/lib/renderers/JsonRenderer.svelte +30 -0
  133. package/src/lib/renderers/KvRenderer.svelte +150 -0
  134. package/src/lib/renderers/QueueRenderer.svelte +286 -0
  135. package/src/lib/renderers/StatsRenderer.svelte +123 -0
  136. package/src/lib/renderers/TableRenderer.svelte +440 -0
  137. package/src/lib/renderers/VectorRenderer.svelte +388 -0
  138. package/src/lib/renderers/diff-render.ts +122 -0
  139. package/src/lib/renderers/diff.ts +9 -0
  140. package/src/lib/renderers/document-render.ts +64 -0
  141. package/src/lib/renderers/document.ts +9 -0
  142. package/src/lib/renderers/graph-render.ts +631 -0
  143. package/src/lib/renderers/graph-sigma.ts +395 -0
  144. package/src/lib/renderers/graph.ts +9 -0
  145. package/src/lib/renderers/hypertable-render.ts +320 -0
  146. package/src/lib/renderers/hypertable.ts +9 -0
  147. package/src/lib/renderers/index.ts +42 -0
  148. package/src/lib/renderers/json-render.ts +89 -0
  149. package/src/lib/renderers/json.ts +10 -0
  150. package/src/lib/renderers/kv-render.ts +193 -0
  151. package/src/lib/renderers/kv.ts +9 -0
  152. package/src/lib/renderers/queue-render.ts +197 -0
  153. package/src/lib/renderers/queue.ts +9 -0
  154. package/src/lib/renderers/registry.ts +68 -0
  155. package/src/lib/renderers/stats-render.ts +73 -0
  156. package/src/lib/renderers/stats.ts +9 -0
  157. package/src/lib/renderers/table-render.ts +156 -0
  158. package/src/lib/renderers/table.ts +11 -0
  159. package/src/lib/renderers/types.ts +33 -0
  160. package/src/lib/renderers/vector-render.ts +154 -0
  161. package/src/lib/renderers/vector.ts +9 -0
  162. package/src/lib/router.svelte.ts +163 -0
  163. package/src/lib/secureStore.svelte.ts +148 -0
  164. package/src/lib/shadow-dom-spike/ShadowDomSpikeCore.svelte +198 -0
  165. package/src/lib/shadow-dom-spike/mount-shadow-dom-spike.ts +94 -0
  166. package/src/lib/shortcuts.ts +22 -0
  167. package/src/lib/surface.ts +80 -0
  168. package/src/lib/tabs.svelte.ts +115 -0
  169. package/src/lib/theme.svelte.ts +63 -0
@@ -0,0 +1 @@
1
+ .svelte-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.svelte-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.svelte-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.svelte-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.svelte-flow__pane{z-index:1}.svelte-flow__pane.draggable{cursor:grab}.svelte-flow__pane.dragging{cursor:grabbing}.svelte-flow__pane.selection{cursor:pointer}.svelte-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.svelte-flow__renderer{z-index:4}.svelte-flow__selection{z-index:6}.svelte-flow__nodesselection-rect:focus,.svelte-flow__nodesselection-rect:focus-visible{outline:none}.svelte-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.svelte-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.svelte-flow .svelte-flow__edges{position:absolute}.svelte-flow .svelte-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.svelte-flow__edge{pointer-events:visibleStroke}.svelte-flow__edge.selectable{cursor:pointer}.svelte-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.svelte-flow__edge.animated path.svelte-flow__edge-interaction{stroke-dasharray:none;animation:none}.svelte-flow__edge.inactive{pointer-events:none}.svelte-flow__edge.selected,.svelte-flow__edge:focus,.svelte-flow__edge:focus-visible{outline:none}.svelte-flow__edge.selected .svelte-flow__edge-path,.svelte-flow__edge.selectable:focus .svelte-flow__edge-path,.svelte-flow__edge.selectable:focus-visible .svelte-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.svelte-flow__edge-textwrapper{pointer-events:all}.svelte-flow__edge .svelte-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.svelte-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.svelte-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.svelte-flow__connection{pointer-events:none}.svelte-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.svelte-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.svelte-flow__nodes{pointer-events:none;transform-origin:0 0}.svelte-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.svelte-flow__node.selectable{cursor:pointer}.svelte-flow__node.draggable{cursor:grab;pointer-events:all}.svelte-flow__node.draggable.dragging{cursor:grabbing}.svelte-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.svelte-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.svelte-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.svelte-flow__handle.connectingfrom{pointer-events:all}.svelte-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.svelte-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.svelte-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.svelte-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.svelte-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.svelte-flow__edgeupdater{cursor:move;pointer-events:all}.svelte-flow__pane.selection .svelte-flow__panel{pointer-events:none}.svelte-flow__panel{position:absolute;z-index:5;margin:15px}.svelte-flow__panel.top{top:0}.svelte-flow__panel.bottom{bottom:0}.svelte-flow__panel.top.center,.svelte-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.svelte-flow__panel.left{left:0}.svelte-flow__panel.right{right:0}.svelte-flow__panel.left.center,.svelte-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.svelte-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.svelte-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.svelte-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.svelte-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.svelte-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.svelte-flow__minimap-svg{display:block}.svelte-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.svelte-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.svelte-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.svelte-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.svelte-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.svelte-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.svelte-flow__controls.horizontal{flex-direction:row}.svelte-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.svelte-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.svelte-flow__edge.updating .svelte-flow__edge-path{stroke:#777}.svelte-flow__edge-text{font-size:10px}.svelte-flow__node.selectable:focus,.svelte-flow__node.selectable:focus-visible{outline:none}.svelte-flow__node-input,.svelte-flow__node-default,.svelte-flow__node-output,.svelte-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.svelte-flow__node-input.selectable:hover,.svelte-flow__node-default.selectable:hover,.svelte-flow__node-output.selectable:hover,.svelte-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.svelte-flow__node-input.selectable.selected,.svelte-flow__node-input.selectable:focus,.svelte-flow__node-input.selectable:focus-visible,.svelte-flow__node-default.selectable.selected,.svelte-flow__node-default.selectable:focus,.svelte-flow__node-default.selectable:focus-visible,.svelte-flow__node-output.selectable.selected,.svelte-flow__node-output.selectable:focus,.svelte-flow__node-output.selectable:focus-visible,.svelte-flow__node-group.selectable.selected,.svelte-flow__node-group.selectable:focus,.svelte-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.svelte-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.svelte-flow__nodesselection-rect,.svelte-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.svelte-flow__nodesselection-rect:focus,.svelte-flow__nodesselection-rect:focus-visible,.svelte-flow__selection:focus,.svelte-flow__selection:focus-visible{outline:none}.svelte-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.svelte-flow__controls-button:disabled{pointer-events:none}.svelte-flow__controls-button:disabled svg{fill-opacity:.4}.svelte-flow__controls-button:last-child{border-bottom:none}.svelte-flow__controls.horizontal .svelte-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.svelte-flow__controls.horizontal .svelte-flow__controls-button:last-child{border-right:none}.svelte-flow__resize-control{position:absolute}.svelte-flow__resize-control.left,.svelte-flow__resize-control.right{cursor:ew-resize}.svelte-flow__resize-control.top,.svelte-flow__resize-control.bottom{cursor:ns-resize}.svelte-flow__resize-control.top.left,.svelte-flow__resize-control.bottom.right{cursor:nwse-resize}.svelte-flow__resize-control.bottom.left,.svelte-flow__resize-control.top.right{cursor:nesw-resize}.svelte-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.svelte-flow__resize-control.handle.left{left:0;top:50%}.svelte-flow__resize-control.handle.right{left:100%;top:50%}.svelte-flow__resize-control.handle.top{left:50%;top:0}.svelte-flow__resize-control.handle.bottom{left:50%;top:100%}.svelte-flow__resize-control.handle.top.left,.svelte-flow__resize-control.handle.bottom.left{left:0}.svelte-flow__resize-control.handle.top.right,.svelte-flow__resize-control.handle.bottom.right{left:100%}.svelte-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.svelte-flow__resize-control.line.left,.svelte-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.svelte-flow__resize-control.line.left{left:0;border-left-width:1px}.svelte-flow__resize-control.line.right{left:100%;border-right-width:1px}.svelte-flow__resize-control.line.top,.svelte-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.svelte-flow__resize-control.line.top{top:0;border-top-width:1px}.svelte-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.svelte-flow__edge-label{text-align:center;position:absolute;padding:2px;font-size:10px;color:var(--xy-edge-label-color, var(--xy-edge-label-color-default));background:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.svelte-flow__container{-webkit-user-select:none;-moz-user-select:none;user-select:none}
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "@reddb-io/ui",
3
+ "version": "0.1.1",
4
+ "private": false,
5
+ "description": "RedDB UI components and standalone web application.",
6
+ "type": "module",
7
+ "bin": {
8
+ "red-ui": "./bin/red-ui.js"
9
+ },
10
+ "svelte": "./src/lib/index.ts",
11
+ "imports": {
12
+ "#reddb": {
13
+ "types": "./src/lib/reddb/index.ts",
14
+ "default": "./src/lib/reddb/index.ts"
15
+ }
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "svelte": "./src/lib/index.ts",
20
+ "types": "./src/lib/index.ts"
21
+ },
22
+ "./app.css": "./src/app.css",
23
+ "./embed": {
24
+ "types": "./src/lib/embed/index.ts",
25
+ "import": "./dist/embed/index.js",
26
+ "default": "./dist/embed/index.js"
27
+ },
28
+ "./renderers": {
29
+ "svelte": "./src/lib/renderers/index.ts",
30
+ "types": "./src/lib/renderers/index.ts"
31
+ },
32
+ "./build/*": "./build/*"
33
+ },
34
+ "files": [
35
+ "bin",
36
+ "build",
37
+ "dist",
38
+ "src/app.css",
39
+ "src/lib/**/*.svelte",
40
+ "src/lib/**/*.ts",
41
+ "!src/lib/**/*.test.ts",
42
+ "README.md"
43
+ ],
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "dependencies": {
48
+ "@fontsource-variable/inter": "^5.2.8",
49
+ "@fontsource-variable/jetbrains-mono": "^5.2.8",
50
+ "@sigma/node-border": "^3.0.0",
51
+ "@tauri-apps/api": "^2.5.0",
52
+ "@xyflow/svelte": "^1.2.0",
53
+ "bits-ui": "^2.18.1",
54
+ "clsx": "^2.1.1",
55
+ "graphology": "^0.26.0",
56
+ "graphology-communities-louvain": "^2.0.2",
57
+ "graphology-layout-forceatlas2": "^0.10.1",
58
+ "lucide-svelte": "^0.475.0",
59
+ "sigma": "^3.0.3",
60
+ "tailwind-merge": "^3.6.0",
61
+ "tailwind-variants": "^2.1.0",
62
+ "@reddb-io/ui-mcp": "0.1.1",
63
+ "@reddb-io/ui-kit": "0.1.1"
64
+ },
65
+ "devDependencies": {
66
+ "@sveltejs/adapter-static": "^3.0.8",
67
+ "@sveltejs/kit": "^2.17.0",
68
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
69
+ "@tailwindcss/vite": "^4.3.0",
70
+ "@types/node": "^25.9.1",
71
+ "svelte": "^5.20.0",
72
+ "svelte-check": "^4.1.4",
73
+ "tailwindcss": "^4.3.0",
74
+ "typescript": "^5.7.2",
75
+ "vite": "^6.0.7",
76
+ "vitest": "^2.1.8"
77
+ },
78
+ "peerDependencies": {
79
+ "svelte": "^5.0.0"
80
+ },
81
+ "engines": {
82
+ "node": ">=20"
83
+ },
84
+ "license": "Apache-2.0",
85
+ "homepage": "https://github.com/reddb-io/red-ui",
86
+ "repository": {
87
+ "type": "git",
88
+ "url": "git+https://github.com/reddb-io/red-ui.git",
89
+ "directory": "packages/ui"
90
+ },
91
+ "bugs": {
92
+ "url": "https://github.com/reddb-io/red-ui/issues"
93
+ },
94
+ "scripts": {
95
+ "dev": "vite dev --host 127.0.0.1 --port 1420 --strictPort",
96
+ "build": "vite build && vite build --config vite.embed.config.ts",
97
+ "preview": "vite preview",
98
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
99
+ "test": "svelte-kit sync && vitest run"
100
+ }
101
+ }
package/src/app.css ADDED
@@ -0,0 +1,238 @@
1
+ @import 'tailwindcss';
2
+ @import '@fontsource-variable/inter';
3
+ @import '@fontsource-variable/jetbrains-mono';
4
+
5
+ /* ============================================================================
6
+ Design tokens. Linear/Vercel vibe — surgical accent, contemporary type.
7
+
8
+ Two themes live here:
9
+ - default (`:root`, no data-theme or `data-theme="light"`): light, white-leaning.
10
+ - opt-in (`:root[data-theme="dark"]`): dark, near-black with green tint.
11
+
12
+ Light is default for both OSS and cloud first-load. Dark is opt-in via the
13
+ topbar toggle / Cmd-K command. Selection is persisted in localStorage and
14
+ applied before paint by an inline script in app.html.
15
+
16
+ Hierarchy of layers (lowest to highest in z):
17
+ bg-0 — page background (the deepest base)
18
+ bg-1 — primary surfaces (cards, panels, topbar)
19
+ bg-2 — interactive surfaces (buttons, inputs, hover)
20
+ bg-3 — elevated / active surfaces
21
+
22
+ Text ramp (most readable to least):
23
+ fg-0 — primary text, h1/h2, important values
24
+ fg-1 — body text, secondary headings
25
+ fg-2 — labels, meta, captions, muted UI text
26
+ fg-3 — disabled, "tertiary noise" (e.g. helper hints)
27
+ ============================================================================ */
28
+
29
+ @theme {
30
+ /* Surfaces — light, white-leaning ramp.
31
+ bg-0 white, surfaces step up in grey via the zinc family. */
32
+ --color-bg-0: #ffffff;
33
+ --color-bg-1: #fafafa;
34
+ --color-bg-2: #f4f4f5;
35
+ --color-bg-3: #e7e7ea;
36
+
37
+ /* Foreground ramp — every level is WCAG AA on bg-0/bg-1.
38
+ fg-3 floor is ~4.8:1 on white; below that is decorative only. */
39
+ --color-fg-0: #0a0a0b;
40
+ --color-fg-1: #3f3f46;
41
+ --color-fg-2: #52525b;
42
+ --color-fg-3: #71717a;
43
+
44
+ /* Lines */
45
+ --color-line-1: #ececef;
46
+ --color-line-2: #d4d4d8;
47
+ --color-line-3: #a1a1aa;
48
+
49
+ /* Surgical accent — rose 600. #ff2056 vibrates on white and fails AA when
50
+ paired with white text on accent fills; the slightly darker chroma
51
+ (#e11d48) keeps the same reddb identity while clearing 4.5:1 against
52
+ white surfaces and against white button labels. */
53
+ --color-accent: #e11d48;
54
+ --color-accent-soft: rgba(225, 29, 72, 0.10);
55
+ --color-accent-glow: rgba(225, 29, 72, 0.30);
56
+
57
+ /* Semantic — darker variants so they stay AA on white surfaces */
58
+ --color-ok: #16a34a;
59
+ --color-warn: #b45309;
60
+ --color-danger: #dc2626;
61
+ --color-info: #2563eb;
62
+
63
+ /* Node roles */
64
+ --color-role-primary: #e11d48;
65
+ --color-role-replica: #2563eb;
66
+ --color-role-embedded: #16a34a;
67
+
68
+ /* Ambient glow — soft red wash at top of viewport, scaled per theme */
69
+ --color-ambient-glow: rgba(225, 29, 72, 0.04);
70
+
71
+ /* Geometry */
72
+ --radius-sm: 3px;
73
+ --radius-md: 5px;
74
+ --radius-lg: 8px;
75
+ --radius-xl: 12px;
76
+
77
+ /* Typography — base text is 13px (Linear scale) */
78
+ --text-xs: 11px;
79
+ --text-xs--line-height: 1.45;
80
+ --text-sm: 12px;
81
+ --text-sm--line-height: 1.5;
82
+ --text-base: 13px;
83
+ --text-base--line-height: 1.5;
84
+ --text-md: 14px;
85
+ --text-md--line-height: 1.5;
86
+ --text-lg: 18px;
87
+ --text-lg--line-height: 1.3;
88
+ --text-xl: 22px;
89
+ --text-xl--line-height: 1.2;
90
+ --text-2xl: 28px;
91
+ --text-2xl--line-height: 1.15;
92
+
93
+ --font-sans: 'Inter Variable', 'Inter', system-ui, -apple-system, sans-serif;
94
+ --font-mono: 'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, 'SF Mono', 'Menlo', monospace;
95
+
96
+ /* ease-out-expo for ambient transitions, ease-out-quart for snappier UI */
97
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
98
+ --ease-snap: cubic-bezier(0.25, 1, 0.5, 1);
99
+
100
+ /* Shadows — light variant: smaller alpha, slate tint */
101
+ --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08), 0 0 0 1px var(--color-line-2);
102
+ --shadow-lg: 0 16px 48px rgba(15, 23, 42, 0.14), 0 0 0 1px var(--color-line-2);
103
+ }
104
+
105
+ /* Dark theme — opt-in via `data-theme="dark"` on the document root. */
106
+ :root[data-theme='dark'] {
107
+ --color-bg-0: #050607;
108
+ --color-bg-1: #0d0f13;
109
+ --color-bg-2: #181b21;
110
+ --color-bg-3: #232730;
111
+
112
+ --color-fg-0: #f7f8fa;
113
+ --color-fg-1: #c8ccd4;
114
+ --color-fg-2: #9ca1a9;
115
+ --color-fg-3: #7a7f87;
116
+
117
+ --color-line-1: #181b21;
118
+ --color-line-2: #2a2e36;
119
+ --color-line-3: #3d424b;
120
+
121
+ --color-accent: #ff2056;
122
+ --color-accent-soft: rgba(255, 32, 86, 0.12);
123
+ --color-accent-glow: rgba(255, 32, 86, 0.45);
124
+
125
+ --color-ok: #4ade80;
126
+ --color-warn: #fbbf24;
127
+ --color-danger: #ff5470;
128
+ --color-info: #60a5fa;
129
+
130
+ --color-role-primary: #ff2056;
131
+ --color-role-replica: #60a5fa;
132
+ --color-role-embedded: #4ade80;
133
+
134
+ --color-ambient-glow: rgba(255, 32, 86, 0.06);
135
+
136
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px var(--color-line-2);
137
+ --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.6), 0 0 0 1px var(--color-line-2);
138
+ }
139
+
140
+ /* shadcn-svelte semantic aliases — driven by the active theme's tokens */
141
+ @layer base {
142
+ :root {
143
+ --background: var(--color-bg-0);
144
+ --foreground: var(--color-fg-0);
145
+ --card: var(--color-bg-1);
146
+ --card-foreground: var(--color-fg-0);
147
+ --popover: var(--color-bg-1);
148
+ --popover-foreground: var(--color-fg-0);
149
+ --primary: var(--color-accent);
150
+ --primary-foreground: #ffffff;
151
+ --secondary: var(--color-bg-2);
152
+ --secondary-foreground: var(--color-fg-1);
153
+ --muted: var(--color-bg-2);
154
+ --muted-foreground: var(--color-fg-2);
155
+ --accent: var(--color-bg-3);
156
+ --accent-foreground: var(--color-fg-0);
157
+ --destructive: var(--color-danger);
158
+ --destructive-foreground: #ffffff;
159
+ --border: var(--color-line-2);
160
+ --input: var(--color-line-2);
161
+ --ring: var(--color-accent);
162
+ --radius: var(--radius-md);
163
+ }
164
+
165
+ * { box-sizing: border-box; }
166
+
167
+ html, body {
168
+ background: var(--color-bg-0);
169
+ color: var(--color-fg-0);
170
+ font-family: var(--font-sans);
171
+ font-size: 13px;
172
+ line-height: 1.5;
173
+ font-feature-settings: 'cv11', 'ss01', 'ss03';
174
+ letter-spacing: -0.005em;
175
+ margin: 0;
176
+ -webkit-font-smoothing: antialiased;
177
+ text-rendering: optimizeLegibility;
178
+ }
179
+
180
+ /* Explicit type system — every page should use these classes for hierarchy */
181
+ .type-h1 {
182
+ font-size: 22px;
183
+ font-weight: 600;
184
+ letter-spacing: -0.02em;
185
+ line-height: 1.2;
186
+ color: var(--color-fg-0);
187
+ }
188
+ .type-h2 {
189
+ font-size: 16px;
190
+ font-weight: 600;
191
+ letter-spacing: -0.015em;
192
+ line-height: 1.3;
193
+ color: var(--color-fg-0);
194
+ }
195
+ .type-label {
196
+ font-family: var(--font-mono);
197
+ font-size: 10px;
198
+ font-weight: 500;
199
+ text-transform: uppercase;
200
+ letter-spacing: 0.1em;
201
+ color: var(--color-fg-2);
202
+ }
203
+ .type-caption {
204
+ font-size: 11px;
205
+ color: var(--color-fg-2);
206
+ line-height: 1.45;
207
+ }
208
+ .type-code {
209
+ font-family: var(--font-mono);
210
+ font-size: 12px;
211
+ color: var(--color-fg-1);
212
+ }
213
+
214
+ /* Ambient grid — 96px squares; lines use line-1 so the texture
215
+ reads as "barely there" in both themes. */
216
+ body::before {
217
+ content: '';
218
+ position: fixed;
219
+ inset: 0;
220
+ background-image:
221
+ radial-gradient(ellipse 80% 50% at 50% -10%, var(--color-ambient-glow), transparent),
222
+ linear-gradient(var(--color-line-1) 1px, transparent 1px),
223
+ linear-gradient(90deg, var(--color-line-1) 1px, transparent 1px);
224
+ background-size: 100% 100%, 96px 96px, 96px 96px;
225
+ opacity: 0.35;
226
+ pointer-events: none;
227
+ z-index: 0;
228
+ }
229
+
230
+ ::selection { background: var(--color-accent-soft); color: var(--color-fg-0); }
231
+
232
+ /* Default scrollbar styling — border matches page bg so the thumb
233
+ "floats" off the surface in both themes. */
234
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
235
+ ::-webkit-scrollbar-track { background: transparent; }
236
+ ::-webkit-scrollbar-thumb { background: var(--color-line-2); border-radius: 8px; border: 2px solid var(--color-bg-0); }
237
+ ::-webkit-scrollbar-thumb:hover { background: var(--color-line-3); }
238
+ }
@@ -0,0 +1,100 @@
1
+ <script lang="ts">
2
+ import { activity } from './activity.svelte'
3
+ import { Activity, CheckCircle2, AlertCircle, Loader2 } from 'lucide-svelte'
4
+
5
+ let open = $state(false)
6
+
7
+ function fmtDuration(ms: number | null): string {
8
+ if (ms === null) return '…'
9
+ if (ms < 1000) return `${ms}ms`
10
+ return `${(ms / 1000).toFixed(1)}s`
11
+ }
12
+
13
+ function fmtRel(at: number): string {
14
+ const d = Date.now() - at
15
+ if (d < 1000) return 'just now'
16
+ if (d < 60_000) return `${Math.round(d / 1000)}s ago`
17
+ return `${Math.round(d / 60_000)}m ago`
18
+ }
19
+ </script>
20
+
21
+ <div class="relative">
22
+ <button
23
+ type="button"
24
+ onclick={() => (open = !open)}
25
+ aria-pressed={open}
26
+ title="reddb activity"
27
+ class={[
28
+ 'inline-flex items-center gap-1.5 h-7 px-2 rounded-md border text-xs font-mono transition-colors cursor-pointer',
29
+ activity.inflight > 0
30
+ ? 'border-accent/40 bg-accent/10 text-accent'
31
+ : 'border-line-2 bg-bg-2 text-fg-3 hover:text-fg-1',
32
+ ].join(' ')}
33
+ >
34
+ {#if activity.inflight > 0}
35
+ <Loader2 class="size-3.5 animate-spin" />
36
+ <span>{activity.inflight}</span>
37
+ {:else}
38
+ <Activity class="size-3.5" />
39
+ <span class="text-fg-3">idle</span>
40
+ {/if}
41
+ </button>
42
+
43
+ {#if open}
44
+ <div class="fixed inset-0 z-40" role="presentation" onclick={() => (open = false)}></div>
45
+ <div
46
+ role="dialog"
47
+ aria-label="Activity log"
48
+ class="absolute top-[calc(100%+6px)] right-0 z-50 w-[360px] bg-bg-1 border border-line-2 rounded-lg shadow-2xl text-[11px] font-mono"
49
+ >
50
+ <header class="flex items-center justify-between px-3 py-2 border-b border-line-1">
51
+ <span class="type-label">Recent reddb requests</span>
52
+ <div class="flex items-center gap-2">
53
+ <span class="text-fg-3">{activity.inflight} active</span>
54
+ {#if activity.inflight > 0}
55
+ <button
56
+ type="button"
57
+ onclick={() => activity.reset()}
58
+ title="Force-clear the in-flight counter (use when a request hangs)"
59
+ class="px-1.5 py-0.5 rounded border border-line-1 text-fg-3 hover:text-fg-1 hover:border-line-2 cursor-pointer text-[10px]"
60
+ >
61
+ reset
62
+ </button>
63
+ {/if}
64
+ </div>
65
+ </header>
66
+ <div class="max-h-[320px] overflow-y-auto py-1">
67
+ {#if activity.log.length === 0}
68
+ <div class="px-3 py-3 text-fg-3">No activity yet.</div>
69
+ {:else}
70
+ {#each activity.log as e (e.id)}
71
+ <div class="px-3 py-1.5 border-b border-line-1/50 last:border-0 grid grid-cols-[16px_1fr_auto] items-center gap-2">
72
+ <span aria-hidden="true">
73
+ {#if e.status === 'pending'}
74
+ <Loader2 class="size-3 animate-spin text-accent" />
75
+ {:else if e.status === 'ok'}
76
+ <CheckCircle2 class="size-3 text-ok" />
77
+ {:else}
78
+ <AlertCircle class="size-3 text-danger" />
79
+ {/if}
80
+ </span>
81
+ <div class="min-w-0">
82
+ <div class="text-fg-1 truncate">{e.label}</div>
83
+ {#if e.status === 'error' && e.error}
84
+ <div class="text-danger text-[10px] truncate">{e.error}</div>
85
+ {/if}
86
+ </div>
87
+ <div class="text-fg-3 text-[10px] tabular-nums whitespace-nowrap">
88
+ {#if e.status === 'pending'}
89
+ {fmtRel(e.startedAt)}
90
+ {:else}
91
+ {fmtDuration(e.durationMs)}
92
+ {/if}
93
+ </div>
94
+ </div>
95
+ {/each}
96
+ {/if}
97
+ </div>
98
+ </div>
99
+ {/if}
100
+ </div>
@@ -0,0 +1,119 @@
1
+ <script lang="ts">
2
+ import { Handle, Position } from '@xyflow/svelte'
3
+
4
+ interface Props {
5
+ data: {
6
+ label: string
7
+ role: string
8
+ collections: number
9
+ entities: number
10
+ url: string
11
+ }
12
+ selected?: boolean
13
+ }
14
+ let { data, selected }: Props = $props()
15
+
16
+ const roleClass = $derived(
17
+ data.role === 'primary' ? 'role-primary' :
18
+ data.role === 'replica' ? 'role-replica' :
19
+ 'role-embedded'
20
+ )
21
+ </script>
22
+
23
+ <Handle type="target" position={Position.Left} style="opacity:0;pointer-events:none" />
24
+ <Handle type="source" position={Position.Right} style="opacity:0;pointer-events:none" />
25
+
26
+ <div class="card {roleClass}" class:selected>
27
+ <div class="stripe"></div>
28
+ <div class="body">
29
+ <div class="head">
30
+ <span class="role">{data.role}</span>
31
+ <span class="dot"></span>
32
+ </div>
33
+ <div class="label">{data.label}</div>
34
+ <div class="meta">
35
+ <span class="metric"><span class="n">{data.collections}</span><span class="u">colls</span></span>
36
+ <span class="sep">·</span>
37
+ <span class="metric"><span class="n">{data.entities.toLocaleString()}</span><span class="u">entities</span></span>
38
+ </div>
39
+ </div>
40
+ </div>
41
+
42
+ <style>
43
+ .card {
44
+ --c: #7a8088;
45
+ position: relative;
46
+ width: 240px;
47
+ background: var(--color-bg-1);
48
+ border: 1px solid var(--color-line-2);
49
+ border-radius: 8px;
50
+ overflow: hidden;
51
+ transition: border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out), transform 200ms var(--ease-snap);
52
+ cursor: pointer;
53
+ }
54
+ .card:hover {
55
+ border-color: color-mix(in srgb, var(--c) 50%, var(--color-line-3));
56
+ }
57
+ .card.selected {
58
+ border-color: var(--c);
59
+ box-shadow: 0 0 0 1px var(--c), 0 8px 28px -8px color-mix(in srgb, var(--c) 60%, transparent);
60
+ }
61
+
62
+ .role-primary { --c: var(--color-role-primary); }
63
+ .role-replica { --c: var(--color-role-replica); }
64
+ .role-embedded { --c: var(--color-role-embedded); }
65
+
66
+ .stripe {
67
+ position: absolute; left: 0; top: 0; bottom: 0;
68
+ width: 2px;
69
+ background: var(--c);
70
+ box-shadow: 0 0 8px var(--c);
71
+ }
72
+
73
+ .body { padding: 12px 14px 12px 16px; }
74
+
75
+ .head { display: flex; align-items: center; justify-content: space-between; }
76
+ .role {
77
+ font-family: var(--font-mono);
78
+ font-size: 9px;
79
+ font-weight: 500;
80
+ text-transform: uppercase;
81
+ letter-spacing: 0.14em;
82
+ color: var(--c);
83
+ }
84
+ .dot {
85
+ width: 6px; height: 6px;
86
+ border-radius: 9999px;
87
+ background: var(--c);
88
+ box-shadow: 0 0 6px var(--c);
89
+ animation: pulse 2.4s ease-in-out infinite;
90
+ }
91
+ @keyframes pulse {
92
+ 0%, 100% { opacity: 1; transform: scale(1); }
93
+ 50% { opacity: 0.5; transform: scale(0.9); }
94
+ }
95
+
96
+ .label {
97
+ font-family: var(--font-mono);
98
+ font-size: 13px;
99
+ font-weight: 500;
100
+ color: var(--color-fg-0);
101
+ margin-top: 4px;
102
+ letter-spacing: -0.01em;
103
+ }
104
+
105
+ .meta {
106
+ margin-top: 10px;
107
+ padding-top: 10px;
108
+ border-top: 1px solid var(--color-line-1);
109
+ display: flex;
110
+ align-items: baseline;
111
+ gap: 6px;
112
+ font-family: var(--font-mono);
113
+ font-size: 11px;
114
+ }
115
+ .metric { display: inline-flex; align-items: baseline; gap: 4px; }
116
+ .metric .n { color: var(--color-fg-0); font-weight: 500; }
117
+ .metric .u { color: var(--color-fg-3); font-size: 10px; }
118
+ .sep { color: var(--color-fg-3); }
119
+ </style>