@veluai/velu 0.1.16 → 0.2.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.
@@ -0,0 +1,173 @@
1
+ /* ContextMenu — the per-page agent/IDE action bar (eyebrow + Copy Page
2
+ split-button + dropdown). Mirrors NavSelect's dropdown recipe; all values are
3
+ tokens, light/dark via [data-theme]. */
4
+
5
+ .velu-context-bar {
6
+ /* Tight to the page title below — the eyebrow reads as a kicker on the
7
+ title, not a detached row. Negative pull cancels the h1's line-height
8
+ leading so the cap-height of the title sits right under the eyebrow. */
9
+ margin-block-end: calc(-1 * var(--s-5));
10
+ }
11
+
12
+ /* Section/group label, top-left — small, uppercase, accent (matches the
13
+ crimson eyebrow in the reference). */
14
+ .velu-context-bar__eyebrow {
15
+ min-inline-size: 0;
16
+ overflow: hidden;
17
+ text-overflow: ellipsis;
18
+ white-space: nowrap;
19
+ font-size: var(--f-h6);
20
+ font-weight: 600;
21
+ letter-spacing: 0.06em;
22
+ text-transform: uppercase;
23
+ color: var(--accent-color);
24
+ }
25
+
26
+ .velu-context-menu {
27
+ position: relative;
28
+ flex: none;
29
+ }
30
+
31
+ /* The split button: "Copy Page" + a divider + a chevron toggle, joined as one
32
+ segmented control. */
33
+ .velu-context-menu__split {
34
+ display: inline-flex;
35
+ align-items: stretch;
36
+ border: var(--border-width) solid var(--border-color);
37
+ border-radius: var(--radius-sm);
38
+ background: var(--page-bg);
39
+ overflow: hidden;
40
+ transition: border-color 0.12s ease;
41
+ }
42
+ .velu-context-menu__split:hover {
43
+ border-color: var(--accent-color);
44
+ }
45
+
46
+ .velu-context-menu__copy,
47
+ .velu-context-menu__toggle {
48
+ display: inline-flex;
49
+ align-items: center;
50
+ gap: var(--s-3);
51
+ background: transparent;
52
+ border: 0;
53
+ font: inherit;
54
+ font-size: var(--f-h6);
55
+ color: var(--text-color);
56
+ cursor: pointer;
57
+ transition: background 0.12s ease, color 0.12s ease;
58
+ }
59
+ .velu-context-menu__copy {
60
+ padding-block: var(--s-3);
61
+ padding-inline: var(--s-1);
62
+ font-weight: 500;
63
+ }
64
+ .velu-context-menu__toggle {
65
+ padding-inline: var(--s-3);
66
+ border-inline-start: var(--border-width) solid var(--border-color);
67
+ }
68
+ .velu-context-menu__copy:hover,
69
+ .velu-context-menu__toggle:hover {
70
+ background: var(--surface-color);
71
+ color: var(--accent-color);
72
+ }
73
+ .velu-context-menu__copy-icon {
74
+ display: inline-flex;
75
+ flex: none;
76
+ }
77
+ .velu-context-menu__toggle svg {
78
+ transition: transform 0.18s ease;
79
+ }
80
+ .velu-context-menu[data-open='true'] .velu-context-menu__toggle svg {
81
+ transform: rotate(180deg);
82
+ }
83
+
84
+ /* Menu — anchored to the trailing edge below the button; fades + slides in.
85
+ Always in DOM so the transition runs both ways; visibility delayed so the
86
+ closed menu isn't focusable. */
87
+ .velu-context-menu__menu {
88
+ position: absolute;
89
+ inset-block-start: calc(100% + var(--s-3));
90
+ inset-inline-end: 0;
91
+ min-inline-size: 17rem;
92
+ margin: 0;
93
+ padding-block: var(--s-3);
94
+ padding-inline: 0.5rem; /* 8px */
95
+ list-style: none;
96
+ background: var(--page-bg);
97
+ border: var(--border-width) solid var(--border-color);
98
+ border-radius: 0.75rem; /* 12px */
99
+ box-shadow: 0 var(--s-1) var(--s2) color-mix(in srgb, #000 14%, transparent);
100
+ opacity: 0;
101
+ visibility: hidden;
102
+ transform: translateY(-0.25rem);
103
+ pointer-events: none;
104
+ transition:
105
+ opacity 0.15s ease,
106
+ transform 0.15s ease,
107
+ visibility 0s linear 0.15s;
108
+ z-index: 40;
109
+ }
110
+ .velu-context-menu[data-open='true'] .velu-context-menu__menu {
111
+ opacity: 1;
112
+ visibility: visible;
113
+ transform: translateY(0);
114
+ pointer-events: auto;
115
+ transition:
116
+ opacity 0.15s ease,
117
+ transform 0.15s ease,
118
+ visibility 0s;
119
+ }
120
+
121
+ .velu-context-menu__item {
122
+ display: flex;
123
+ align-items: flex-start;
124
+ gap: var(--s-2);
125
+ inline-size: 100%;
126
+ padding-block: var(--s-3);
127
+ padding-inline: var(--s-3);
128
+ border-radius: var(--radius-sm);
129
+ background: transparent;
130
+ border: 0;
131
+ font: inherit;
132
+ text-align: start;
133
+ color: var(--text-color);
134
+ cursor: pointer;
135
+ transition: background 0.12s ease;
136
+ }
137
+ .velu-context-menu__item:hover {
138
+ background: var(--surface-color);
139
+ }
140
+
141
+ .velu-context-menu__item-icon {
142
+ display: inline-flex;
143
+ flex: none;
144
+ margin-block-start: 0.1em;
145
+ color: var(--muted-color);
146
+ }
147
+ .velu-context-menu__item:hover .velu-context-menu__item-icon {
148
+ color: var(--accent-color);
149
+ }
150
+
151
+ .velu-context-menu__item-text {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.1em;
155
+ min-inline-size: 0;
156
+ }
157
+ .velu-context-menu__item-title {
158
+ display: inline-flex;
159
+ align-items: center;
160
+ gap: var(--s-4);
161
+ font-size: var(--f-h6);
162
+ font-weight: 500;
163
+ color: var(--text-color);
164
+ }
165
+ .velu-context-menu__item-ext {
166
+ flex: none;
167
+ color: var(--muted-color);
168
+ }
169
+ .velu-context-menu__item-desc {
170
+ font-size: var(--f-h6);
171
+ line-height: var(--lh-tight, 1.3);
172
+ color: var(--muted-color);
173
+ }
@@ -102,6 +102,16 @@
102
102
  /* Region wrapping the scroll area + the overlay arrows. Fills the
103
103
  remaining aside height; relative so the arrows position to its
104
104
  top/bottom edges. */
105
+ /* Hairline between the top anchor links and the nav sections (the sidebar
106
+ design's anchor↔sidebar separator). Tokenized; sits flush in the aside flow. */
107
+ .velu-docs-context-divider {
108
+ flex: none;
109
+ block-size: var(--border-width);
110
+ background: var(--border-color);
111
+ margin-block: var(--s-2);
112
+ margin-inline: var(--s-2);
113
+ }
114
+
105
115
  .velu-docs-nav-region {
106
116
  position: relative;
107
117
  flex: 1 1 auto;
@@ -200,10 +210,13 @@
200
210
  .velu-docs-layout__aside--right[data-fade-top='true'] {
201
211
  --vf-top: var(--s2);
202
212
  }
203
- /* The left nav's under-heading fade (the ::after below each sticky
204
- section heading) is shown only while the nav is scrolled up, so a
205
- section's first item isn't dimmed at rest. */
206
- .velu-docs-nav-scroll[data-fade-top='true'] .velu-sidebar__section::after {
213
+ /* The left nav's under-heading fade (the ::after below a sticky section
214
+ heading) is shown only while the nav is scrolled up AND only under the
215
+ currently-PINNED section ([data-stuck], set by the runtime). Other sections'
216
+ headings scroll normally, so their first item must not be dimmed — only the
217
+ item sliding under the top-pinned heading fades. */
218
+ .velu-docs-nav-scroll[data-fade-top='true']
219
+ .velu-sidebar__section[data-stuck='true']::after {
207
220
  opacity: 1;
208
221
  }
209
222
  .velu-docs-nav-scroll[data-fade-bottom='true'],
@@ -782,3 +795,21 @@
782
795
  display: block;
783
796
  }
784
797
  }
798
+
799
+ /* ── 404 takeover ─────────────────────────────────────────────────────── */
800
+ /* On a not-found route the docs chrome (both fixed asides) is hidden and the
801
+ centre column spans full width to center the <NotFound> content. The header
802
+ and (configured) footer stay. */
803
+ .velu-docs-layout[data-not-found='true'] .velu-docs-layout__aside {
804
+ display: none;
805
+ }
806
+ .velu-docs-layout[data-not-found='true'] .velu-docs-layout__center {
807
+ margin-inline: 0;
808
+ }
809
+ .velu-404-main {
810
+ display: flex;
811
+ align-items: center;
812
+ justify-content: center;
813
+ min-block-size: 70vh;
814
+ padding: var(--s4) var(--s2);
815
+ }
@@ -0,0 +1,94 @@
1
+ /* not-found.css — the 404 page (Direction 1 · Classic).
2
+ Mapped onto Velu tokens, so light/dark follow [data-theme]. */
3
+
4
+ .velu-404 {
5
+ inline-size: 34rem;
6
+ max-inline-size: 100%;
7
+ margin-inline: auto;
8
+ text-align: center;
9
+ display: flex;
10
+ flex-direction: column;
11
+ align-items: center;
12
+ }
13
+
14
+ .velu-404__eyebrow {
15
+ margin: 0 0 var(--s-1);
16
+ font-size: 0.75rem;
17
+ font-weight: var(--weight-medium);
18
+ letter-spacing: 0.06em;
19
+ text-transform: uppercase;
20
+ color: var(--accent-color);
21
+ }
22
+
23
+ /* Big crimson numeral — the brand font (Outfit), light weight. clamp keeps
24
+ it large on desktop but never overflows a narrow screen. */
25
+ .velu-404__num {
26
+ font-family: var(--font-brand);
27
+ font-weight: var(--weight-light);
28
+ font-size: clamp(7rem, 30vw, 9.375rem);
29
+ line-height: 0.9;
30
+ letter-spacing: -0.04em;
31
+ color: var(--accent-color);
32
+ margin-block-end: var(--s0);
33
+ }
34
+
35
+ .velu-404__title {
36
+ margin: 0 0 var(--s-1);
37
+ font-size: var(--f-h2);
38
+ font-weight: var(--weight-semibold);
39
+ letter-spacing: -0.02em;
40
+ line-height: 1.1;
41
+ color: var(--text-color);
42
+ }
43
+
44
+ .velu-404__body {
45
+ margin: 0 0 var(--s2);
46
+ max-inline-size: 27rem;
47
+ font-size: var(--f-body);
48
+ font-weight: var(--weight-light);
49
+ line-height: 1.55;
50
+ color: var(--muted-color);
51
+ }
52
+
53
+ .velu-404__actions {
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ flex-wrap: wrap;
58
+ gap: var(--s-1);
59
+ margin-block-start: var(--s-2);
60
+ }
61
+
62
+ .velu-404__btn {
63
+ display: inline-flex;
64
+ align-items: center;
65
+ gap: var(--s-2);
66
+ white-space: nowrap;
67
+ padding: var(--s-2) var(--s1);
68
+ border: var(--border-width) solid var(--border-color);
69
+ border-radius: var(--radius-md);
70
+ background: var(--page-bg);
71
+ color: var(--text-color);
72
+ font: inherit;
73
+ font-size: var(--f-h6);
74
+ font-weight: var(--weight-medium);
75
+ text-decoration: none;
76
+ cursor: pointer;
77
+ transition: border-color 0.12s ease, background 0.12s ease;
78
+ }
79
+ .velu-404__btn:hover {
80
+ border-color: var(--accent-color);
81
+ }
82
+ .velu-404__btn--primary {
83
+ background: var(--accent-color);
84
+ border-color: var(--accent-color);
85
+ color: #fff;
86
+ font-weight: var(--weight-bold);
87
+ }
88
+ .velu-404__btn--primary:hover {
89
+ background: color-mix(in srgb, var(--accent-color) 88%, #000);
90
+ }
91
+ .velu-404__btn-ic {
92
+ display: inline-flex;
93
+ align-items: center;
94
+ }
@@ -147,6 +147,7 @@
147
147
  color: var(--text-color);
148
148
  }
149
149
  .velu-header__action--outlined:hover {
150
+ background: var(--surface-color);
150
151
  border-color: var(--accent-color);
151
152
  color: var(--accent-color);
152
153
  }
@@ -16,6 +16,12 @@
16
16
  .velu-content-foot .velu-powered-by {
17
17
  margin: 0;
18
18
  padding: 0;
19
+ /* Fill the row so the badge's own `justify-content: flex-end` right-aligns
20
+ it — with or without the social icons as a sibling. (Avoids a
21
+ `margin-inline-start: auto` reset, which the production CSS minifier folds
22
+ away when it follows `margin: 0`, leaving the lone badge stuck at the
23
+ start in the build but not in dev.) */
24
+ flex: 1;
19
25
  }
20
26
  .velu-content-foot .velu-social {
21
27
  color: var(--muted-color);
@@ -7,10 +7,51 @@
7
7
  rotation, and centralized icon sizing/stroke. All values are tokens. */
8
8
 
9
9
  .velu-sidebar {
10
- border-left: var(--border-width) solid var(--surface-color);
10
+ position: relative; /* anchors the gliding active indicator */
11
11
  margin-left: var(--s1);
12
12
  }
13
13
 
14
+ /* The single active indicator — a crimson tint band with a flush-left 2px bar
15
+ that GLIDES between items (one element animating its position/height) instead
16
+ of each item painting its own active state. z-index 0 keeps it BEHIND the
17
+ items + sticky headings (both positioned, z-index 1), so the text reads over
18
+ the tint and a pinned heading's opaque background covers the indicator when an
19
+ item scrolls under it. Driven imperatively from JS (transform/height/opacity);
20
+ the easing curve makes the slide feel continuous. */
21
+ .velu-sidebar__indicator {
22
+ position: absolute;
23
+ inset-inline-start: 0;
24
+ inset-inline-end: var(--s-3);
25
+ inset-block-start: 0;
26
+ height: 0;
27
+ opacity: 0;
28
+ z-index: 0;
29
+ pointer-events: none;
30
+ background: color-mix(in srgb, var(--accent-color) 8%, transparent);
31
+ border-radius: var(--radius-sm);
32
+ transition:
33
+ transform 0.3s cubic-bezier(0.32, 0.72, 0, 1),
34
+ height 0.3s cubic-bezier(0.32, 0.72, 0, 1),
35
+ opacity 0.2s ease;
36
+ will-change: transform, height;
37
+ }
38
+ .velu-sidebar__indicator::before {
39
+ content: '';
40
+ position: absolute;
41
+ inset-inline-start: 0;
42
+ inset-block: 15%;
43
+ inline-size: 2px;
44
+ border-start-end-radius: 2px;
45
+ border-end-end-radius: 2px;
46
+ background: var(--accent-color);
47
+ }
48
+ /* Honour reduced-motion: snap instead of glide. */
49
+ @media (prefers-reduced-motion: reduce) {
50
+ .velu-sidebar__indicator {
51
+ transition: opacity 0.2s ease;
52
+ }
53
+ }
54
+
14
55
  .velu-sidebar__section {
15
56
  /* Sticky section header: each heading pins to the top of the scroll
16
57
  region until its own section scrolls past, then the next heading
@@ -21,7 +62,10 @@
21
62
  bar is invisible until it's actually covering scrolled content. */
22
63
  position: sticky;
23
64
  inset-block-start: 0;
24
- z-index: 1;
65
+ /* Above the items (z-index 1) so scrolled rows tuck UNDER the heading (its
66
+ opaque bg + the ::after fade hide them), not over it; above the gliding
67
+ indicator (z-index 0) too. */
68
+ z-index: 2;
25
69
  background: var(--page-bg);
26
70
  display: flex;
27
71
  align-items: center;
@@ -94,21 +138,38 @@
94
138
  so these stay CSS until/if a Cluster/Inline primitive exists. */
95
139
  .velu-sidebar__item,
96
140
  .velu-sidebar__subitem {
141
+ /* Positioned above the gliding indicator (z-index 0) so the label reads over
142
+ the tint band. */
143
+ position: relative;
144
+ z-index: 1;
97
145
  display: flex;
98
146
  align-items: center;
99
147
  gap: var(--s-3);
100
148
  padding-inline: var(--s0);
101
149
  color: var(--text-color);
102
150
  text-decoration: none;
151
+ transition: color 0.2s ease;
103
152
  }
104
153
 
105
154
  .velu-sidebar__subitem {
106
155
  padding-block: var(--s-5);
107
156
  }
108
157
 
158
+ /* Active = colour + weight only; the moving indicator paints the bar + tint. */
109
159
  .velu-sidebar__item--active {
110
160
  color: var(--accent-color);
111
- border-left: 2px solid var(--accent-color);
161
+ font-weight: 500;
162
+ }
163
+ .velu-sidebar__item--active .velu-sidebar__icon {
164
+ color: var(--accent-color);
165
+ }
166
+
167
+ /* The label fills the row so the group chevron (and any external-link icon)
168
+ sit flush at the row's RIGHT end, not crowded against the label — faithful
169
+ to the design's `flex: 1` label. */
170
+ .velu-sidebar__label {
171
+ flex: 1;
172
+ min-inline-size: 0;
112
173
  }
113
174
 
114
175
  .velu-sidebar__summary {
@@ -39,6 +39,7 @@
39
39
  transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
40
40
  }
41
41
  .velu-theme-toggle:hover {
42
+ background: var(--surface-color);
42
43
  border-color: var(--accent-color);
43
44
  }
44
45
  /* Tactile press feedback on click. */
@@ -4,6 +4,7 @@ export { default as Cluster } from './primitives/Cluster.jsx';
4
4
  export { default as ThemeToggle } from './components/ThemeToggle.jsx';
5
5
  export { default as Sidebar } from './components/Sidebar.jsx';
6
6
  export { default as NavSelect } from './components/NavSelect.jsx';
7
+ export { default as ContextMenu } from './components/ContextMenu.jsx';
7
8
  export { default as Toc } from './components/Toc.jsx';
8
9
  export { default as TocBar } from './components/TocBar.jsx';
9
10
  export { default as Callout } from './components/Callout.jsx';
@@ -28,6 +29,7 @@ export { default as ApiClient } from './components/ApiClient.jsx';
28
29
  export { default as ApiSidebar } from './components/ApiSidebar.jsx';
29
30
  export { default as ApiReferencePage } from './components/ApiReferencePage.jsx';
30
31
  export { default as ApiSamples } from './components/ApiSamples.jsx';
32
+ export { default as NotFound } from './components/NotFound.jsx';
31
33
  export { default as AskBar } from './components/AskBar.jsx';
32
34
  export { default as Chatbot } from './components/Chatbot.jsx';
33
35
  export { default as PageFeedback } from './components/PageFeedback.jsx';
@@ -40,6 +42,7 @@ export {
40
42
  VeluMark,
41
43
  } from './components/PageHeader.jsx';
42
44
  export { default as Search } from './components/Search.jsx';
45
+ export { default as pagefindSearch } from './lib/pagefind.js';
43
46
  export { default as Image } from './components/Image.jsx';
44
47
  export {
45
48
  default as CodeBlock,
@@ -0,0 +1,103 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Brand glyphs for the contextual menu's "Open in <tool>" / "Connect to <IDE>"
5
+ * actions. Sourced from svgl.app and inlined (the project inlines icons as JSX,
6
+ * like lucide — no SVG loader). Each takes a `size` prop, mirroring lucide's
7
+ * icon API so they're drop-in in the menu.
8
+ *
9
+ * ALL marks use `currentColor` so the icon column reads as one uniform set:
10
+ * muted/grey at rest, accent on hover (matching the lucide icons beside them).
11
+ * The brand glyphs keep their distinctive shapes; only the fill follows the
12
+ * menu's text/hover color across light + dark.
13
+ */
14
+
15
+ export function MarkdownIcon({ size = '1em', ...rest }) {
16
+ return (
17
+ <svg width={size} height={size} viewBox="0 0 208 128" fill="none" aria-hidden="true" {...rest}>
18
+ <path
19
+ fill="none"
20
+ stroke="currentColor"
21
+ strokeWidth="10"
22
+ d="M15 5h178a10 10 0 0 1 10 10v98a10 10 0 0 1-10 10H15a10 10 0 0 1-10-10V15A10 10 0 0 1 15 5z"
23
+ />
24
+ <path
25
+ fill="currentColor"
26
+ d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39H30zm125 0-30-33h20V30h20v35h20l-30 33z"
27
+ />
28
+ </svg>
29
+ );
30
+ }
31
+
32
+ export function OpenAIIcon({ size = '1em', ...rest }) {
33
+ return (
34
+ <svg width={size} height={size} viewBox="0 0 256 260" fill="currentColor" aria-hidden="true" {...rest}>
35
+ <path d="M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.246 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z" />
36
+ </svg>
37
+ );
38
+ }
39
+
40
+ export function ClaudeIcon({ size = '1em', ...rest }) {
41
+ return (
42
+ <svg width={size} height={size} viewBox="0 0 256 257" aria-hidden="true" {...rest}>
43
+ <path fill="currentColor" d="m50.228 170.321 50.357-28.257.843-2.463-.843-1.361h-2.462l-8.426-.518-28.775-.778-24.952-1.037-24.175-1.296-6.092-1.297L0 125.796l.583-3.759 5.12-3.434 7.324.648 16.202 1.101 24.304 1.685 17.629 1.037 26.118 2.722h4.148l.583-1.685-1.426-1.037-1.101-1.037-25.147-17.045-27.22-18.017-14.258-10.37-7.713-5.25-3.888-4.925-1.685-10.758 7-7.713 9.397.649 2.398.648 9.527 7.323 20.35 15.75L94.817 91.9l3.889 3.24 1.555-1.102.195-.777-1.75-2.917-14.453-26.118-15.425-26.572-6.87-11.018-1.814-6.61c-.648-2.723-1.102-4.991-1.102-7.778l7.972-10.823L71.42 0 82.05 1.426l4.472 3.888 6.61 15.101 10.694 23.786 16.591 32.34 4.861 9.592 2.592 8.879.973 2.722h1.685v-1.556l1.36-18.211 2.528-22.36 2.463-28.776.843-8.1 4.018-9.722 7.971-5.25 6.222 2.981 5.12 7.324-.713 4.73-3.046 19.768-5.962 30.98-3.889 20.739h2.268l2.593-2.593 10.499-13.934 17.628-22.036 7.778-8.749 9.073-9.657 5.833-4.601h11.018l8.1 12.055-3.628 12.443-11.342 14.388-9.398 12.184-13.48 18.147-8.426 14.518.778 1.166 2.01-.194 30.46-6.481 16.462-2.982 19.637-3.37 8.88 4.148.971 4.213-3.5 8.62-20.998 5.184-24.628 4.926-36.682 8.685-.454.324.519.648 16.526 1.555 7.065.389h17.304l32.21 2.398 8.426 5.574 5.055 6.805-.843 5.184-12.962 6.611-17.498-4.148-40.83-9.721-14-3.5h-1.944v1.167l11.666 11.406 21.387 19.314 26.767 24.887 1.36 6.157-3.434 4.86-3.63-.518-23.526-17.693-9.073-7.972-20.545-17.304h-1.36v1.814l4.73 6.935 25.017 37.59 1.296 11.536-1.814 3.76-6.481 2.268-7.13-1.297-14.647-20.544-15.1-23.138-12.185-20.739-1.49.843-7.194 77.448-3.37 3.953-7.778 2.981-6.48-4.925-3.436-7.972 3.435-15.749 4.148-20.544 3.37-16.333 3.046-20.285 1.815-6.74-.13-.454-1.49.194-15.295 20.999-23.267 31.433-18.406 19.702-4.407 1.75-7.648-3.954.713-7.064 4.277-6.286 25.47-32.405 15.36-20.092 9.917-11.6-.065-1.686h-.583L44.07 198.125l-12.055 1.555-5.185-4.86.648-7.972 2.463-2.593 20.35-13.999-.064.065Z" />
44
+ </svg>
45
+ );
46
+ }
47
+
48
+ export function PerplexityIcon({ size = '1em', ...rest }) {
49
+ return (
50
+ <svg width={size} height={size} viewBox="0 0 48 48" fill="none" aria-hidden="true" {...rest}>
51
+ <g stroke="currentColor" strokeLinecap="round" strokeLinejoin="round">
52
+ <path d="M24 4.5v39M13.73 16.573v-9.99L24 16.573m0 14.5L13.73 41.417V27.01L24 16.573m0 0l10.27-9.99v9.99" />
53
+ <path d="M13.73 31.396H9.44V16.573h29.12v14.823h-4.29" />
54
+ <path d="M24 16.573L34.27 27.01v14.407L24 31.073" />
55
+ </g>
56
+ </svg>
57
+ );
58
+ }
59
+
60
+ export function CursorIcon({ size = '1em', ...rest }) {
61
+ return (
62
+ <svg width={size} height={size} viewBox="0 0 466.73 532.09" fill="currentColor" aria-hidden="true" {...rest}>
63
+ <path d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z" />
64
+ </svg>
65
+ );
66
+ }
67
+
68
+ export function VscodeIcon({ size = '1em', ...rest }) {
69
+ return (
70
+ <svg width={size} height={size} viewBox="0 0 100 100" fill="none" aria-hidden="true" {...rest}>
71
+ <mask
72
+ id="velu-vsc-mask"
73
+ width="100"
74
+ height="100"
75
+ x="0"
76
+ y="0"
77
+ maskUnits="userSpaceOnUse"
78
+ style={{ maskType: 'alpha' }}
79
+ >
80
+ <path
81
+ fill="#fff"
82
+ fillRule="evenodd"
83
+ clipRule="evenodd"
84
+ d="M70.912 99.317a6.223 6.223 0 0 0 4.96-.19l20.589-9.907A6.25 6.25 0 0 0 100 83.587V16.413a6.25 6.25 0 0 0-3.54-5.632L75.874.874a6.226 6.226 0 0 0-7.104 1.21L29.355 38.04 12.187 25.01a4.162 4.162 0 0 0-5.318.236l-5.506 5.009a4.168 4.168 0 0 0-.004 6.162L16.247 50 1.36 63.583a4.168 4.168 0 0 0 .004 6.162l5.506 5.01a4.162 4.162 0 0 0 5.318.236l17.168-13.032L68.77 97.917a6.217 6.217 0 0 0 2.143 1.4ZM75.015 27.3 45.11 50l29.906 22.701V27.3Z"
85
+ />
86
+ </mask>
87
+ <g mask="url(#velu-vsc-mask)">
88
+ <path
89
+ fill="currentColor"
90
+ d="M96.461 10.796 75.857.876a6.23 6.23 0 0 0-7.107 1.207l-67.451 61.5a4.167 4.167 0 0 0 .004 6.162l5.51 5.009a4.167 4.167 0 0 0 5.32.236l81.228-61.62c2.725-2.067 6.639-.124 6.639 3.297v-.24a6.25 6.25 0 0 0-3.539-5.63Z"
91
+ />
92
+ <path
93
+ fill="currentColor"
94
+ d="m96.461 89.204-20.604 9.92a6.229 6.229 0 0 1-7.107-1.207l-67.451-61.5a4.167 4.167 0 0 1 .004-6.162l5.51-5.009a4.167 4.167 0 0 1 5.32-.236l81.228 61.62c2.725 2.067 6.639.124 6.639-3.297v.24a6.25 6.25 0 0 1-3.539 5.63Z"
95
+ />
96
+ <path
97
+ fill="currentColor"
98
+ d="M75.858 99.126a6.232 6.232 0 0 1-7.108-1.21c2.306 2.307 6.25.674 6.25-2.588V4.672c0-3.262-3.944-4.895-6.25-2.589a6.232 6.232 0 0 1 7.108-1.21l20.6 9.908A6.25 6.25 0 0 1 100 16.413v67.174a6.25 6.25 0 0 1-3.541 5.633l-20.601 9.906Z"
99
+ />
100
+ </g>
101
+ </svg>
102
+ );
103
+ }