vectra-client 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 510bd3a530df754db719892b7157846a72a29998659052fa7fda33b615ddab84
4
- data.tar.gz: 6e853240a0231e909fda25709b72610f5d294e630f3576a0a52c0949e500e47f
3
+ metadata.gz: b0d48b8a6205df9a0d6545e3772e26da09f826f03d56751a6fa997e1a73d89f1
4
+ data.tar.gz: 25dc65ad327e03e7912a0b938739b6acf1d6708efd8fa41773d9bbae1053e3dc
5
5
  SHA512:
6
- metadata.gz: a1658293c6bd4f62c777b106f40da783b56b68498b4cb73dda4af6df542277c8545105bafe47c6ba1fea106f68e934395df42f0d8453d35a2cdc3d89ef80500d
7
- data.tar.gz: 9a108eb9be1df21a216824f2e9f0bbe60bb721bf6145cb2b4f772ecb1d7abe7b2e618c2d70d67455ed484ad65c05b20b3ec65485196740a51809fa9dd49a70c3
6
+ metadata.gz: 68fc7d7a2c941733bb8f42007dffa52989daedeb362da62c094d05dec7d02f8ca6d7ca8763194e9b51b4ecfe3f7a6e8db4418c7589caab31943f055f75f4c48a
7
+ data.tar.gz: f40ab28eb011943d4961e22c5d31b5a816a81cea1a2bf6afa238004adaa1cdd8558f10b0ee8d56376d6fc737788b16fc1acb7088778d8461ecb3a8db2ff85580
data/.rubocop.yml CHANGED
@@ -11,6 +11,7 @@ AllCops:
11
11
  - 'bin/**/*'
12
12
  - 'node_modules/**/*'
13
13
  - 'lib/generators/**/templates/**/*'
14
+ - 'examples/**/*'
14
15
 
15
16
  # Layout
16
17
  Layout/LineLength:
@@ -30,6 +31,7 @@ Metrics/BlockLength:
30
31
  - 'vectra.gemspec'
31
32
  - 'Rakefile'
32
33
  - 'benchmarks/**/*'
34
+ - 'examples/**/*'
33
35
  AllowedMethods:
34
36
  - 'included'
35
37
  - 'class_methods'
@@ -38,26 +40,34 @@ Metrics/MethodLength:
38
40
  Max: 30
39
41
  Exclude:
40
42
  - 'spec/**/*'
43
+ - 'examples/**/*'
41
44
 
42
45
  Metrics/AbcSize:
43
46
  Max: 30
44
47
  Exclude:
45
48
  - 'spec/**/*'
49
+ - 'examples/**/*'
46
50
 
47
51
  Metrics/ClassLength:
48
52
  Max: 250
49
53
  Exclude:
50
54
  - 'spec/**/*'
55
+ - 'examples/**/*'
51
56
 
52
57
  Metrics/ModuleLength:
53
58
  Exclude:
54
59
  - 'spec/**/*'
60
+ - 'examples/**/*'
55
61
 
56
62
  Metrics/CyclomaticComplexity:
57
63
  Max: 10
64
+ Exclude:
65
+ - 'examples/**/*'
58
66
 
59
67
  Metrics/PerceivedComplexity:
60
68
  Max: 10
69
+ Exclude:
70
+ - 'examples/**/*'
61
71
 
62
72
  Metrics/ParameterLists:
63
73
  Max: 7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.4.0](https://github.com/stokry/vectra/tree/v0.4.0) (2026-01-12)
4
+
5
+ ### Added
6
+ - Memory provider for in-memory vector storage
7
+ - QueryBuilder for chainable query API
8
+ - Batch operations with concurrent processing
9
+ - Vector normalization methods (L2, L1)
10
+ - Enhanced error message extraction
11
+
12
+ ### Fixed
13
+ - Weaviate DELETE request query parameters
14
+ - Qdrant error message extraction from nested status
15
+ - Client ping error info capture
16
+ - Credential rotation timeout parameter handling
17
+
18
+ [Full Changelog](https://github.com/stokry/vectra/compare/v0.3.4...v0.4.0)
19
+
20
+ ## [v0.3.4](https://github.com/stokry/vectra/tree/v0.3.4) (2026-01-12)
21
+
22
+ [Full Changelog](https://github.com/stokry/vectra/compare/v0.3.3...v0.3.4)
23
+
24
+ ## [v0.3.3](https://github.com/stokry/vectra/tree/v0.3.3) (2026-01-09)
25
+
26
+ [Full Changelog](https://github.com/stokry/vectra/compare/v0.3.2...v0.3.3)
27
+
3
28
  ## [v0.3.2](https://github.com/stokry/vectra/tree/v0.3.2) (2026-01-08)
4
29
 
5
30
  [Full Changelog](https://github.com/stokry/vectra/compare/v0.3.1...v0.3.2)
@@ -16,6 +41,7 @@
16
41
 
17
42
  [Full Changelog](https://github.com/stokry/vectra/compare/v0.2.1...v0.2.2)
18
43
 
44
+ ## [v0.2.1](https://github.com/stokry/vectra/tree/v0.2.1) (2026-01-08)
19
45
 
20
46
  [Full Changelog](https://github.com/stokry/vectra/compare/v0.2.0...v0.2.1)
21
47
 
@@ -23,14 +49,6 @@
23
49
 
24
50
  [Full Changelog](https://github.com/stokry/vectra/compare/v0.1.3...v0.2.0)
25
51
 
26
- ## [v0.3.3](https://github.com/stokry/vectra/tree/v0.3.3) (2026-01-09)
27
-
28
- [Full Changelog](https://github.com/stokry/vectra/compare/v0.3.2...v0.3.3)
29
-
30
- ### Changed
31
-
32
- - Version bump and minor maintenance release.
33
-
34
52
  ## [v0.1.3](https://github.com/stokry/vectra/tree/v0.1.3) (2026-01-07)
35
53
 
36
54
  [Full Changelog](https://github.com/stokry/vectra/compare/v0.1.1...v0.1.3)
data/README.md CHANGED
@@ -17,6 +17,7 @@
17
17
  | **Qdrant** | Open Source | ✅ Supported |
18
18
  | **Weaviate** | Open Source | ✅ Supported |
19
19
  | **pgvector** | PostgreSQL | ✅ Supported |
20
+ | **Memory** | In-Memory | ✅ Testing only |
20
21
 
21
22
  ## Installation
22
23
 
@@ -48,12 +49,38 @@ client.upsert(
48
49
  ]
49
50
  )
50
51
 
51
- # Search
52
+ # Search (classic API)
52
53
  results = client.query(vector: [0.1, 0.2, 0.3], top_k: 5)
53
54
  results.each { |match| puts "#{match.id}: #{match.score}" }
54
55
 
56
+ # Search (chainable Query Builder)
57
+ results = client
58
+ .query('docs')
59
+ .vector([0.1, 0.2, 0.3])
60
+ .top_k(5)
61
+ .with_metadata
62
+ .execute
63
+
64
+ results.each do |match|
65
+ puts "#{match.id}: #{match.score}"
66
+ end
67
+
68
+ # Normalize embeddings (for better cosine similarity)
69
+ embedding = openai_response['data'][0]['embedding']
70
+ normalized = Vectra::Vector.normalize(embedding)
71
+ client.upsert(vectors: [{ id: 'doc-1', values: normalized }])
72
+
55
73
  # Delete
56
74
  client.delete(ids: ['doc-1', 'doc-2'])
75
+
76
+ # Health check
77
+ if client.healthy?
78
+ puts "Connection is healthy"
79
+ end
80
+
81
+ # Ping with latency
82
+ status = client.ping
83
+ puts "Provider: #{status[:provider]}, Latency: #{status[:latency_ms]}ms"
57
84
  ```
58
85
 
59
86
  ## Provider Examples
@@ -69,10 +96,16 @@ client = Vectra.qdrant(host: 'http://localhost:6333')
69
96
  client = Vectra.qdrant(host: 'https://your-cluster.qdrant.io', api_key: ENV['QDRANT_API_KEY'])
70
97
 
71
98
  # Weaviate
72
- client = Vectra.weaviate(host: 'http://localhost:8080', api_key: ENV['WEAVIATE_API_KEY'])
99
+ client = Vectra.weaviate(
100
+ api_key: ENV['WEAVIATE_API_KEY'],
101
+ host: 'https://your-weaviate-instance'
102
+ )
73
103
 
74
104
  # pgvector (PostgreSQL)
75
105
  client = Vectra.pgvector(connection_url: 'postgres://user:pass@localhost/mydb')
106
+
107
+ # Memory (in-memory, testing only)
108
+ client = Vectra.memory
76
109
  ```
77
110
 
78
111
  ## Features
@@ -7,6 +7,7 @@
7
7
  <title>{{ page.title }} - {{ site.title }}</title>
8
8
  <link rel="stylesheet" href="{{ site.baseurl }}/assets/style.css">
9
9
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>◆</text></svg>">
10
+ <script defer src="https://umami-production-dfb8.up.railway.app/script.js" data-website-id="07e5420c-12d1-4e3c-9dbd-5cecb15a878f"></script>
10
11
  </head>
11
12
  <body>
12
13
  {{ content }}
@@ -7,13 +7,19 @@
7
7
  <title>{{ page.title }} - {{ site.title }}</title>
8
8
  <link rel="stylesheet" href="{{ site.baseurl }}/assets/style.css">
9
9
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>◆</text></svg>">
10
+ <script defer src="https://umami-production-dfb8.up.railway.app/script.js" data-website-id="07e5420c-12d1-4e3c-9dbd-5cecb15a878f"></script>
10
11
  </head>
11
12
  <body>
12
13
  <!-- Header -->
13
14
  <header class="tma-header">
14
15
  <nav class="tma-nav">
15
16
  <a href="{{ site.baseurl }}/" class="tma-nav__brand">Vectra</a>
16
- <ul class="tma-nav__menu">
17
+ <button class="tma-nav__toggle" aria-label="Toggle menu" aria-expanded="false">
18
+ <span class="tma-nav__toggle-line"></span>
19
+ <span class="tma-nav__toggle-line"></span>
20
+ <span class="tma-nav__toggle-line"></span>
21
+ </button>
22
+ <ul class="tma-nav__menu" id="nav-menu">
17
23
  <li><a href="{{ site.baseurl }}/guides/getting-started" class="tma-nav__link">Getting Started</a></li>
18
24
  <li><a href="{{ site.baseurl }}/providers" class="tma-nav__link">Providers</a></li>
19
25
  <li><a href="{{ site.baseurl }}/api/overview" class="tma-nav__link">API</a></li>
@@ -29,7 +35,7 @@
29
35
  <!-- Hero Section -->
30
36
  <section class="tma-hero">
31
37
  <div class="tma-hero__container">
32
- <span class="tma-hero__badge">v0.2.2Qdrant & Weaviate Support</span>
38
+ <span class="tma-hero__badge">v0.3.3Grafana Dashboard & Monitoring</span>
33
39
  <h1 class="tma-hero__title">
34
40
  Vector Databases,<br>
35
41
  <span class="tma-hero__title-gradient">Unified for Ruby.</span>
@@ -77,7 +83,7 @@
77
83
  <span class="tma-feature-card__icon">📈</span>
78
84
  <h3 class="tma-feature-card__title">Observable</h3>
79
85
  <p class="tma-feature-card__description">
80
- Native instrumentation for Datadog and New Relic. Track latency, throughput, and errors.
86
+ Grafana dashboard, Prometheus metrics, and native instrumentation for Datadog and New Relic. Track latency, throughput, and errors.
81
87
  </p>
82
88
  </div>
83
89
  <div class="tma-feature-card">
@@ -183,5 +189,40 @@
183
189
  </ul>
184
190
  </div>
185
191
  </footer>
192
+ <script>
193
+ document.addEventListener('DOMContentLoaded', function() {
194
+ const navToggle = document.querySelector('.tma-nav__toggle');
195
+ const navMenu = document.querySelector('.tma-nav__menu');
196
+
197
+ if (navToggle && navMenu) {
198
+ navToggle.addEventListener('click', function(e) {
199
+ e.preventDefault();
200
+ e.stopPropagation();
201
+ const isExpanded = navToggle.getAttribute('aria-expanded') === 'true';
202
+ navToggle.setAttribute('aria-expanded', !isExpanded);
203
+ navMenu.classList.toggle('tma-nav__menu--open');
204
+ });
205
+
206
+ // Close menu when clicking on a link
207
+ const navLinks = navMenu.querySelectorAll('.tma-nav__link');
208
+ navLinks.forEach(function(link) {
209
+ link.addEventListener('click', function() {
210
+ navToggle.setAttribute('aria-expanded', 'false');
211
+ navMenu.classList.remove('tma-nav__menu--open');
212
+ });
213
+ });
214
+
215
+ // Close menu when clicking outside
216
+ document.addEventListener('click', function(e) {
217
+ if (navMenu.classList.contains('tma-nav__menu--open') &&
218
+ !navMenu.contains(e.target) &&
219
+ !navToggle.contains(e.target)) {
220
+ navToggle.setAttribute('aria-expanded', 'false');
221
+ navMenu.classList.remove('tma-nav__menu--open');
222
+ }
223
+ });
224
+ }
225
+ });
226
+ </script>
186
227
  </body>
187
228
  </html>
@@ -7,13 +7,19 @@
7
7
  <title>{{ page.title }} - {{ site.title }}</title>
8
8
  <link rel="stylesheet" href="{{ site.baseurl }}/assets/style.css">
9
9
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>◆</text></svg>">
10
+ <script defer src="https://umami-production-dfb8.up.railway.app/script.js" data-website-id="07e5420c-12d1-4e3c-9dbd-5cecb15a878f"></script>
10
11
  </head>
11
12
  <body>
12
13
  <!-- Header -->
13
14
  <header class="tma-header">
14
15
  <nav class="tma-nav">
15
16
  <a href="{{ site.baseurl }}/" class="tma-nav__brand">Vectra</a>
16
- <ul class="tma-nav__menu">
17
+ <button class="tma-nav__toggle" aria-label="Toggle menu" aria-expanded="false">
18
+ <span class="tma-nav__toggle-line"></span>
19
+ <span class="tma-nav__toggle-line"></span>
20
+ <span class="tma-nav__toggle-line"></span>
21
+ </button>
22
+ <ul class="tma-nav__menu" id="nav-menu">
17
23
  <li><a href="{{ site.baseurl }}/guides/getting-started" class="tma-nav__link">Getting Started</a></li>
18
24
  <li><a href="{{ site.baseurl }}/providers" class="tma-nav__link">Providers</a></li>
19
25
  <li><a href="{{ site.baseurl }}/api/overview" class="tma-nav__link">API</a></li>
@@ -58,14 +64,6 @@
58
64
  </ul>
59
65
  </div>
60
66
 
61
- <div class="tma-sidebar__section">
62
- <h3 class="tma-sidebar__title">Examples</h3>
63
- <ul class="tma-sidebar__list">
64
- <li><a href="{{ site.baseurl }}/examples" class="tma-sidebar__link {% if page.url == '/examples/' %}tma-sidebar__link--active{% endif %}">Overview</a></li>
65
- <li><a href="{{ site.baseurl }}/examples/basic-usage" class="tma-sidebar__link {% if page.url == '/examples/basic-usage/' %}tma-sidebar__link--active{% endif %}">Basic Usage</a></li>
66
- </ul>
67
- </div>
68
-
69
67
  <div class="tma-sidebar__section">
70
68
  <h3 class="tma-sidebar__title">Community</h3>
71
69
  <ul class="tma-sidebar__list">
@@ -80,5 +78,40 @@
80
78
  {{ content }}
81
79
  </main>
82
80
  </div>
81
+ <script>
82
+ document.addEventListener('DOMContentLoaded', function() {
83
+ const navToggle = document.querySelector('.tma-nav__toggle');
84
+ const navMenu = document.querySelector('.tma-nav__menu');
85
+
86
+ if (navToggle && navMenu) {
87
+ navToggle.addEventListener('click', function(e) {
88
+ e.preventDefault();
89
+ e.stopPropagation();
90
+ const isExpanded = navToggle.getAttribute('aria-expanded') === 'true';
91
+ navToggle.setAttribute('aria-expanded', !isExpanded);
92
+ navMenu.classList.toggle('tma-nav__menu--open');
93
+ });
94
+
95
+ // Close menu when clicking on a link
96
+ const navLinks = navMenu.querySelectorAll('.tma-nav__link');
97
+ navLinks.forEach(function(link) {
98
+ link.addEventListener('click', function() {
99
+ navToggle.setAttribute('aria-expanded', 'false');
100
+ navMenu.classList.remove('tma-nav__menu--open');
101
+ });
102
+ });
103
+
104
+ // Close menu when clicking outside
105
+ document.addEventListener('click', function(e) {
106
+ if (navMenu.classList.contains('tma-nav__menu--open') &&
107
+ !navMenu.contains(e.target) &&
108
+ !navToggle.contains(e.target)) {
109
+ navToggle.setAttribute('aria-expanded', 'false');
110
+ navMenu.classList.remove('tma-nav__menu--open');
111
+ }
112
+ });
113
+ }
114
+ });
115
+ </script>
83
116
  </body>
84
117
  </html>
@@ -164,6 +164,40 @@ body {
164
164
  border-color: var(--tma-color-border-hover);
165
165
  }
166
166
 
167
+ .tma-nav__toggle {
168
+ display: none;
169
+ flex-direction: column;
170
+ justify-content: space-around;
171
+ width: 24px;
172
+ height: 24px;
173
+ background: transparent;
174
+ border: none;
175
+ cursor: pointer;
176
+ padding: 0;
177
+ z-index: 10;
178
+ }
179
+
180
+ .tma-nav__toggle-line {
181
+ width: 100%;
182
+ height: 2px;
183
+ background: var(--tma-color-text-primary);
184
+ border-radius: 2px;
185
+ transition: all var(--tma-transition-normal);
186
+ transform-origin: center;
187
+ }
188
+
189
+ .tma-nav__toggle[aria-expanded="true"] .tma-nav__toggle-line:nth-child(1) {
190
+ transform: rotate(45deg) translate(6px, 6px);
191
+ }
192
+
193
+ .tma-nav__toggle[aria-expanded="true"] .tma-nav__toggle-line:nth-child(2) {
194
+ opacity: 0;
195
+ }
196
+
197
+ .tma-nav__toggle[aria-expanded="true"] .tma-nav__toggle-line:nth-child(3) {
198
+ transform: rotate(-45deg) translate(6px, -6px);
199
+ }
200
+
167
201
  /* ============================================
168
202
  Hero Section
169
203
  ============================================ */
@@ -751,8 +785,49 @@ code {
751
785
  padding: 0 var(--tma-spacing-md);
752
786
  }
753
787
 
788
+ .tma-nav__toggle {
789
+ display: flex;
790
+ }
791
+
754
792
  .tma-nav__menu {
755
- display: none;
793
+ display: flex;
794
+ position: fixed;
795
+ top: var(--tma-header-height);
796
+ left: 0;
797
+ right: 0;
798
+ height: 0;
799
+ max-height: 400px;
800
+ background: rgba(10, 10, 15, 0.98);
801
+ backdrop-filter: blur(12px);
802
+ flex-direction: column;
803
+ align-items: stretch;
804
+ padding: 0;
805
+ gap: var(--tma-spacing-xs);
806
+ transform: translateX(100%);
807
+ transition: transform var(--tma-transition-normal), opacity var(--tma-transition-normal), height var(--tma-transition-normal), padding var(--tma-transition-normal);
808
+ z-index: 999;
809
+ overflow-y: auto;
810
+ opacity: 0;
811
+ pointer-events: none;
812
+ border-top: 1px solid var(--tma-color-border);
813
+ }
814
+
815
+ .tma-nav__menu.tma-nav__menu--open {
816
+ transform: translateX(0);
817
+ opacity: 1;
818
+ pointer-events: auto;
819
+ height: 400px;
820
+ padding: var(--tma-spacing-lg);
821
+ }
822
+
823
+ .tma-nav__menu li {
824
+ width: 100%;
825
+ }
826
+
827
+ .tma-nav__link {
828
+ width: 100%;
829
+ padding: var(--tma-spacing-md);
830
+ justify-content: flex-start;
756
831
  }
757
832
 
758
833
  .tma-hero {
@@ -925,3 +1000,153 @@ code {
925
1000
  color: #ef4444;
926
1001
  font-weight: bold;
927
1002
  }
1003
+
1004
+ /* ============================================
1005
+ Dashboard Showcase
1006
+ ============================================ */
1007
+ .tma-dashboard-showcase {
1008
+ display: grid;
1009
+ grid-template-columns: 1fr 1fr;
1010
+ gap: var(--tma-spacing-2xl);
1011
+ margin: var(--tma-spacing-2xl) 0;
1012
+ padding: var(--tma-spacing-xl);
1013
+ background: var(--tma-color-bg-secondary);
1014
+ border-radius: var(--tma-radius-lg);
1015
+ border: 1px solid var(--tma-color-border);
1016
+ }
1017
+
1018
+ .tma-dashboard-showcase__image {
1019
+ position: relative;
1020
+ border-radius: var(--tma-radius-md);
1021
+ overflow: hidden;
1022
+ box-shadow: var(--tma-shadow-lg);
1023
+ background: var(--tma-color-bg-primary);
1024
+ border: 1px solid var(--tma-color-border);
1025
+ }
1026
+
1027
+ .tma-dashboard-screenshot {
1028
+ width: 100%;
1029
+ height: auto;
1030
+ display: block;
1031
+ border-radius: var(--tma-radius-md);
1032
+ transition: transform var(--tma-transition-normal);
1033
+ }
1034
+
1035
+ .tma-dashboard-showcase__image:hover .tma-dashboard-screenshot {
1036
+ transform: scale(1.02);
1037
+ }
1038
+
1039
+ .tma-dashboard-showcase__features {
1040
+ display: flex;
1041
+ flex-direction: column;
1042
+ justify-content: center;
1043
+ }
1044
+
1045
+ .tma-dashboard-showcase__features h4 {
1046
+ font-size: 1.3rem;
1047
+ font-weight: 700;
1048
+ margin-bottom: var(--tma-spacing-lg);
1049
+ color: var(--tma-color-text-primary);
1050
+ }
1051
+
1052
+ .tma-dashboard-showcase__features ul {
1053
+ list-style: none;
1054
+ padding-left: 0;
1055
+ margin: 0 0 var(--tma-spacing-xl) 0;
1056
+ }
1057
+
1058
+ .tma-dashboard-showcase__features li {
1059
+ margin-bottom: var(--tma-spacing-md);
1060
+ padding-left: var(--tma-spacing-lg);
1061
+ position: relative;
1062
+ color: var(--tma-color-text-secondary);
1063
+ line-height: 1.6;
1064
+ }
1065
+
1066
+ .tma-dashboard-showcase__features li::before {
1067
+ content: '▸';
1068
+ position: absolute;
1069
+ left: 0;
1070
+ color: var(--tma-color-accent-primary);
1071
+ font-weight: bold;
1072
+ }
1073
+
1074
+ .tma-dashboard-showcase__features strong {
1075
+ color: var(--tma-color-text-primary);
1076
+ font-weight: 600;
1077
+ }
1078
+
1079
+ .tma-dashboard-showcase__actions {
1080
+ display: flex;
1081
+ gap: var(--tma-spacing-md);
1082
+ flex-wrap: wrap;
1083
+ margin-top: var(--tma-spacing-lg);
1084
+ }
1085
+
1086
+ .tma-button {
1087
+ display: inline-flex;
1088
+ align-items: center;
1089
+ gap: var(--tma-spacing-sm);
1090
+ padding: var(--tma-spacing-md) var(--tma-spacing-lg);
1091
+ border-radius: var(--tma-radius-md);
1092
+ font-weight: 600;
1093
+ font-size: 0.95rem;
1094
+ text-decoration: none;
1095
+ transition: all var(--tma-transition-fast);
1096
+ border: 1px solid transparent;
1097
+ }
1098
+
1099
+ .tma-button--primary {
1100
+ background: var(--tma-color-accent-primary);
1101
+ color: #0a0a0f!important;
1102
+ border-color: var(--tma-color-accent-primary);
1103
+ }
1104
+
1105
+ .tma-button--primary:hover {
1106
+ background: var(--tma-color-accent-light);
1107
+ border-color: var(--tma-color-accent-light);
1108
+ color: #0a0a0f!important;
1109
+ transform: translateY(-1px);
1110
+ box-shadow: var(--tma-shadow-md);
1111
+ }
1112
+
1113
+ .tma-button--secondary {
1114
+ background: transparent;
1115
+ color: var(--tma-color-accent-primary);
1116
+ border-color: var(--tma-color-accent-primary);
1117
+ }
1118
+
1119
+ .tma-button--secondary:hover {
1120
+ background: var(--tma-color-accent-muted);
1121
+ border-color: var(--tma-color-accent-light);
1122
+ color: var(--tma-color-accent-light);
1123
+ transform: translateY(-1px);
1124
+ }
1125
+
1126
+ /* Responsive Dashboard Showcase */
1127
+ @media (max-width: 1024px) {
1128
+ .tma-dashboard-showcase {
1129
+ grid-template-columns: 1fr;
1130
+ gap: var(--tma-spacing-xl);
1131
+ }
1132
+
1133
+ .tma-dashboard-showcase__features {
1134
+ order: -1;
1135
+ }
1136
+ }
1137
+
1138
+ @media (max-width: 768px) {
1139
+ .tma-dashboard-showcase {
1140
+ padding: var(--tma-spacing-md);
1141
+ margin: var(--tma-spacing-lg) 0;
1142
+ }
1143
+
1144
+ .tma-dashboard-showcase__actions {
1145
+ flex-direction: column;
1146
+ }
1147
+
1148
+ .tma-button {
1149
+ width: 100%;
1150
+ justify-content: center;
1151
+ }
1152
+ }
@@ -48,7 +48,16 @@ Practical examples to get started with Vectra.
48
48
  </div>
49
49
  </div>
50
50
 
51
+ ## Real-World Examples
52
+
53
+ <div class="tma-comparison-card">
54
+ <h4>Production Use Cases</h4>
55
+ <p>E-commerce search, RAG chatbots, multi-tenant SaaS, and batch processing</p>
56
+ <a href="{{ site.baseurl }}/examples/real-world/">View Examples →</a>
57
+ </div>
58
+
51
59
  ## More Resources
52
60
 
53
61
  - [GitHub Examples](https://github.com/stokry/vectra/tree/main/examples) - Full example files
62
+ - [Comprehensive Demo](https://github.com/stokry/vectra/tree/main/examples/comprehensive_demo.rb) - Complete feature demonstration
54
63
  - [Integration Tests](https://github.com/stokry/vectra/tree/main/spec/integration) - Real-world test cases