This is an automated email from the ASF dual-hosted git repository.
piotr pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iggy-website.git
The following commit(s) were added to refs/heads/main by this push:
new bccea431 Update examples and home page
bccea431 is described below
commit bccea43170a31a5bc7aef753debb5e1e39f4e6b4
Author: spetz <[email protected]>
AuthorDate: Sat Mar 28 11:28:39 2026 +0100
Update examples and home page
---
content/docs/sdk/csharp/intro.mdx | 6 +-
content/docs/sdk/go/intro.mdx | 2 +-
content/docs/sdk/java/examples.mdx | 97 +++++++++++++++++++++++++++++++
content/docs/sdk/java/intro.mdx | 2 +-
content/docs/sdk/node/examples.mdx | 86 ++++++++++++++++++++++++++++
content/docs/sdk/node/intro.mdx | 5 +-
content/docs/sdk/python/examples.mdx | 78 +++++++++++++++++++++++++
content/docs/sdk/python/intro.mdx | 2 +-
content/docs/sdk/rust/examples.mdx | 8 ++-
src/components/benchmark-chart.tsx | 17 +++---
src/components/code-tabs.tsx | 108 ++++++++++++++++++++++++-----------
11 files changed, 361 insertions(+), 50 deletions(-)
diff --git a/content/docs/sdk/csharp/intro.mdx
b/content/docs/sdk/csharp/intro.mdx
index 3f598d06..441d8d53 100644
--- a/content/docs/sdk/csharp/intro.mdx
+++ b/content/docs/sdk/csharp/intro.mdx
@@ -2,7 +2,7 @@
title: C# SDK
---
-The Iggy SDK for C# is a library that allows you to interact with the Iggy API
from your .NET applications. It communicates with the Iggy server over TCP
using the binary protocol. The repository can be found
[here](https://github.com/apache/iggy/tree/master/foreign/csharp).
+The Iggy SDK for C# is a library that allows you to interact with the Iggy API
from your .NET applications. It supports TCP and HTTP transports. The package
is available on [NuGet](https://www.nuget.org/packages/Apache.Iggy/) and the
source code can be found on
[GitHub](https://github.com/apache/iggy/tree/master/foreign/csharp).
## Installation
@@ -109,10 +109,10 @@ while (true)
Working examples are available in the
[examples/csharp](https://github.com/apache/iggy/tree/master/examples/csharp)
directory. The following example sets are included:
- **GettingStarted** - basic producer and consumer
+- **Basic** - producer and consumer with settings
+- **NewSdk** - new high-level SDK API patterns
- **MessageEnvelope** - working with message envelopes
- **MessageHeaders** - custom message headers
-- **MultiTenant** - multi-tenant streaming setup
- **TcpTls** - TLS-encrypted TCP connections
-- **StreamBuilder** - stream builder API usage
The solution can be opened with Visual Studio or built with `dotnet build`.
diff --git a/content/docs/sdk/go/intro.mdx b/content/docs/sdk/go/intro.mdx
index f4d90154..cac50b1e 100644
--- a/content/docs/sdk/go/intro.mdx
+++ b/content/docs/sdk/go/intro.mdx
@@ -2,7 +2,7 @@
title: Go SDK
---
-The Iggy Go SDK is a client library that allows you to interact with the Iggy
API from your Go application. It communicates with the Iggy server over TCP
using the binary protocol. The repository can be found
[here](https://github.com/apache/iggy/tree/master/foreign/go).
+The Iggy Go SDK is a client library that allows you to interact with the Iggy
API from your Go application. It communicates with the Iggy server over TCP
using the binary protocol. The package is available on
[pkg.go.dev](https://pkg.go.dev/github.com/apache/iggy/foreign/go) and the
source code can be found on
[GitHub](https://github.com/apache/iggy/tree/master/foreign/go).
## Installation
diff --git a/content/docs/sdk/java/examples.mdx
b/content/docs/sdk/java/examples.mdx
index 42f7ed41..26469164 100644
--- a/content/docs/sdk/java/examples.mdx
+++ b/content/docs/sdk/java/examples.mdx
@@ -1,3 +1,100 @@
---
title: Examples
---
+
+Working examples are available in the
[examples/java](https://github.com/apache/iggy/tree/master/examples/java)
directory as a Gradle project. The following example sets are included:
+
+- **gettingstarted** - basic blocking TCP producer and consumer
+- **async** - asynchronous producer and consumer
+- **messageenvelope** - JSON message envelope pattern
+- **messageheaders** - custom message headers
+- **multitenant** - multi-tenant isolation with per-tenant streams
+- **tcptls** - TLS-encrypted TCP connections
+- **sinkdataproducer** - bulk random data generation
+- **streambuilder** - combined producer and consumer in one class
+
+## Producer
+
+```java
+import org.apache.iggy.client.blocking.tcp.IggyTcpClient;
+import org.apache.iggy.identifier.StreamId;
+import org.apache.iggy.identifier.TopicId;
+import org.apache.iggy.message.Message;
+import org.apache.iggy.message.Partitioning;
+import org.apache.iggy.topic.CompressionAlgorithm;
+import java.math.BigInteger;
+import java.util.List;
+import static java.util.Optional.empty;
+
+public class Producer {
+ public static void main(String[] args) {
+ try (var client = IggyTcpClient.builder()
+ .host("localhost")
+ .port(8090)
+ .credentials("iggy", "iggy")
+ .buildAndLogin()) {
+
+ var streamId = StreamId.of("sample-stream");
+ var topicId = TopicId.of("sample-topic");
+
+ client.streams().createStream("sample-stream");
+ client.topics().createTopic(
+ streamId, 1L,
+ CompressionAlgorithm.None,
+ BigInteger.ZERO, BigInteger.ZERO,
+ empty(), "sample-topic");
+
+ var partitioning = Partitioning.partitionId(0L);
+ var messages = List.of(Message.of("hello world"));
+ client.messages().sendMessages(
+ streamId, topicId,
+ partitioning, messages);
+ }
+ }
+}
+```
+
+## Consumer
+
+```java
+import org.apache.iggy.client.blocking.tcp.IggyTcpClient;
+import org.apache.iggy.consumergroup.Consumer;
+import org.apache.iggy.identifier.StreamId;
+import org.apache.iggy.identifier.TopicId;
+import org.apache.iggy.message.Message;
+import org.apache.iggy.message.PolledMessages;
+import org.apache.iggy.message.PollingStrategy;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
+public class ConsumerExample {
+ public static void main(String[] args) {
+ try (var client = IggyTcpClient.builder()
+ .host("localhost")
+ .port(8090)
+ .credentials("iggy", "iggy")
+ .buildAndLogin()) {
+
+ var streamId = StreamId.of("sample-stream");
+ var topicId = TopicId.of("sample-topic");
+ var consumer = Consumer.of(0L);
+
+ PolledMessages polled = client.messages()
+ .pollMessages(
+ streamId, topicId,
+ Optional.of(0L), consumer,
+ PollingStrategy.offset(BigInteger.ZERO),
+ 10L, false);
+
+ for (Message message : polled.messages()) {
+ String payload = new String(
+ message.payload(), StandardCharsets.UTF_8);
+ System.out.println("Payload: " + payload);
+ }
+ }
+ }
+}
+```
+
+For the full source code, see the
[examples/java](https://github.com/apache/iggy/tree/master/examples/java)
directory.
diff --git a/content/docs/sdk/java/intro.mdx b/content/docs/sdk/java/intro.mdx
index 579c9fc4..163dcfdf 100644
--- a/content/docs/sdk/java/intro.mdx
+++ b/content/docs/sdk/java/intro.mdx
@@ -2,7 +2,7 @@
title: Java SDK
---
-The Iggy Java SDK is a library that allows you to interact with the Iggy API
from your Java application. It communicates with the Iggy server over TCP using
the binary protocol. The repository can be found
[here](https://github.com/apache/iggy/tree/master/foreign/java).
+The Iggy Java SDK is a library that allows you to interact with the Iggy API
from your Java application. It supports TCP and HTTP transports. The package is
available on [Maven
Central](https://mvnrepository.com/artifact/org.apache.iggy/iggy) and the
source code can be found on
[GitHub](https://github.com/apache/iggy/tree/master/foreign/java).
## Installation
diff --git a/content/docs/sdk/node/examples.mdx
b/content/docs/sdk/node/examples.mdx
index 42f7ed41..a4fce2cb 100644
--- a/content/docs/sdk/node/examples.mdx
+++ b/content/docs/sdk/node/examples.mdx
@@ -1,3 +1,89 @@
---
title: Examples
---
+
+Working examples are available in the
[examples/node](https://github.com/apache/iggy/tree/master/examples/node)
directory, written in TypeScript. The following example sets are included:
+
+- **getting-started** - basic producer and consumer
+- **basic** - producer and consumer with utilities
+- **message-envelope** - JSON message envelope pattern
+- **message-headers** - custom message headers
+- **multi-tenant** - multi-tenant streaming setup
+- **tcp-tls** - TLS-encrypted TCP connections
+- **stream-builder** - stream builder API usage
+- **sink-data-producer** - bulk data generation for sink connectors
+
+## Producer
+
+```typescript
+import { Client, Partitioning } from 'apache-iggy';
+
+const client = new Client({
+ transport: 'TCP',
+ options: { port: 8090, host: '127.0.0.1', keepAlive: true },
+ credentials: { username: 'iggy', password: 'iggy' },
+});
+
+const stream = await client.stream.create({ name: 'sample-stream' });
+const topic = await client.topic.create({
+ streamId: stream.id,
+ name: 'sample-topic',
+ partitionCount: 1,
+ compressionAlgorithm: 1,
+ replicationFactor: 1,
+});
+
+const messages = Array.from({ length: 10 }, (_, i) => ({
+ id: i + 1,
+ headers: [],
+ payload: `message-${i + 1}`,
+}));
+
+await client.message.send({
+ streamId: stream.id,
+ topicId: topic.id,
+ messages,
+ partition: Partitioning.PartitionId(
+ topic.partitions[0].id
+ ),
+});
+
+await client.destroy();
+```
+
+## Consumer
+
+```typescript
+import { Client, PollingStrategy, Consumer } from 'apache-iggy';
+
+const STREAM_ID = 1;
+const TOPIC_ID = 1;
+const PARTITION_ID = 0;
+
+const client = new Client({
+ transport: 'TCP',
+ options: { port: 8090, host: '127.0.0.1' },
+ credentials: { username: 'iggy', password: 'iggy' },
+});
+
+const polledMessages = await client.message.poll({
+ streamId: STREAM_ID,
+ topicId: TOPIC_ID,
+ consumer: Consumer.Single,
+ partitionId: PARTITION_ID,
+ pollingStrategy: PollingStrategy.Offset(BigInt(0)),
+ count: 10,
+ autocommit: false,
+});
+
+for (const message of polledMessages.messages) {
+ const payload = message.payload.toString('utf8');
+ console.log(
+ `Offset: ${message.headers.offset}, Payload: ${payload}`
+ );
+}
+
+await client.destroy();
+```
+
+For the full source code, see the
[examples/node](https://github.com/apache/iggy/tree/master/examples/node)
directory.
diff --git a/content/docs/sdk/node/intro.mdx b/content/docs/sdk/node/intro.mdx
index 6105685b..687771c9 100644
--- a/content/docs/sdk/node/intro.mdx
+++ b/content/docs/sdk/node/intro.mdx
@@ -2,7 +2,7 @@
title: Node.js SDK
---
-The Iggy Node.js SDK is a client library that allows you to interact with the
Iggy API from your Node.js and TypeScript applications. It communicates with
the Iggy server over TCP using the binary protocol. The repository can be found
[here](https://github.com/apache/iggy/tree/master/foreign/node).
+The Iggy Node.js SDK is a client library that allows you to interact with the
Iggy API from your Node.js and TypeScript applications. It communicates with
the Iggy server over TCP using the binary protocol. The package is available on
[npm](https://www.npmjs.com/package/apache-iggy) and the source code can be
found on [GitHub](https://github.com/apache/iggy/tree/master/foreign/node).
## Installation
@@ -87,9 +87,10 @@ if (polledMessages && polledMessages.messages.length > 0) {
Working examples are available in the
[examples/node](https://github.com/apache/iggy/tree/master/examples/node)
directory, written in TypeScript. The following example sets are included:
- **getting-started** - basic producer and consumer
-- **async** - asynchronous message processing
+- **basic** - producer and consumer with utilities
- **message-envelope** - working with message envelopes
- **message-headers** - custom message headers
- **multi-tenant** - multi-tenant streaming setup
- **tcp-tls** - TLS-encrypted TCP connections
- **stream-builder** - stream builder API usage
+- **sink-data-producer** - bulk data generation for sink connectors
diff --git a/content/docs/sdk/python/examples.mdx
b/content/docs/sdk/python/examples.mdx
index 42f7ed41..44cb4a1d 100644
--- a/content/docs/sdk/python/examples.mdx
+++ b/content/docs/sdk/python/examples.mdx
@@ -1,3 +1,81 @@
---
title: Examples
---
+
+Working examples are available in the
[examples/python](https://github.com/apache/iggy/tree/master/examples/python)
directory.
+
+- **basic** - producer and consumer using connection strings
+- **getting-started** - producer and consumer with TLS support
+
+## Producer
+
+```python
+import asyncio
+from apache_iggy import IggyClient
+from apache_iggy import SendMessage as Message
+
+STREAM_NAME = "sample-stream"
+TOPIC_NAME = "sample-topic"
+PARTITION_ID = 0
+
+async def main():
+ client = IggyClient.from_connection_string(
+ "iggy+tcp://iggy:[email protected]:8090"
+ )
+ await client.connect()
+
+ await client.create_stream(name=STREAM_NAME)
+ await client.create_topic(
+ stream=STREAM_NAME,
+ partitions_count=1,
+ name=TOPIC_NAME,
+ replication_factor=1,
+ )
+
+ messages = []
+ for i in range(10):
+ messages.append(Message(f"message-{i}"))
+
+ await client.send_messages(
+ stream=STREAM_NAME,
+ topic=TOPIC_NAME,
+ partitioning=PARTITION_ID,
+ messages=messages,
+ )
+
+asyncio.run(main())
+```
+
+## Consumer
+
+```python
+import asyncio
+from apache_iggy import IggyClient, PollingStrategy, ReceiveMessage
+
+STREAM_NAME = "sample-stream"
+TOPIC_NAME = "sample-topic"
+PARTITION_ID = 0
+
+async def main():
+ client = IggyClient.from_connection_string(
+ "iggy+tcp://iggy:[email protected]:8090"
+ )
+ await client.connect()
+
+ polled_messages = await client.poll_messages(
+ stream=STREAM_NAME,
+ topic=TOPIC_NAME,
+ partition_id=PARTITION_ID,
+ polling_strategy=PollingStrategy.Next(),
+ count=10,
+ auto_commit=True,
+ )
+
+ for message in polled_messages:
+ payload = message.payload().decode("utf-8")
+ print(f"Offset: {message.offset()}, Payload: {payload}")
+
+asyncio.run(main())
+```
+
+For the full source code, see the
[examples/python](https://github.com/apache/iggy/tree/master/examples/python)
directory.
diff --git a/content/docs/sdk/python/intro.mdx
b/content/docs/sdk/python/intro.mdx
index 7e1a64c0..ecf12c40 100644
--- a/content/docs/sdk/python/intro.mdx
+++ b/content/docs/sdk/python/intro.mdx
@@ -2,7 +2,7 @@
title: Python SDK
---
-The Iggy Python SDK is a client library that allows you to interact with the
Iggy API from your Python application. It is built as a PyO3 wrapper around the
Rust SDK, which means it supports TCP, QUIC, and HTTP transports. The
repository can be found
[here](https://github.com/apache/iggy/tree/master/foreign/python).
+The Iggy Python SDK is a client library that allows you to interact with the
Iggy API from your Python application. It is built as a PyO3 wrapper around the
Rust SDK, which means it supports TCP, QUIC, HTTP, and WebSocket transports via
connection strings. The package is available on
[PyPI](https://pypi.org/project/apache-iggy/) and the source code can be found
on [GitHub](https://github.com/apache/iggy/tree/master/foreign/python).
## Installation
diff --git a/content/docs/sdk/rust/examples.mdx
b/content/docs/sdk/rust/examples.mdx
index f137fbb9..263e472d 100644
--- a/content/docs/sdk/rust/examples.mdx
+++ b/content/docs/sdk/rust/examples.mdx
@@ -5,7 +5,11 @@ title: Examples
In the core repository, you can find the following
[examples](https://github.com/apache/iggy/tree/master/examples/rust/src) using
the Rust SDK:
- **Getting started** - the basic example which is discussed in the [getting
started](/docs/introduction/getting-started) guide.
+- **Basic** - producer and consumer using the low-level `Client` trait with
CLI args for transport selection (TCP/QUIC/HTTP).
+- **New SDK** - an introduction to the high-level SDK as discussed in the
[dedicated guide](/docs/sdk/rust/high-level-sdk).
+- **Stream builder** - examples using the `IggyStream`, `IggyStreamProducer`,
and `IggyStreamConsumer` builder APIs as discussed in the [stream builder
guide](/docs/sdk/rust/stream-builder).
- **Message envelope** - the example of how to send a message with a custom
envelope e.g. to differentiate between different types of messages.
-- **Message headers** - the example of how to send a message with custom
headers e.g. to differentiate between different types of messages.
+- **Message headers** - the example of how to send a message with custom
headers (typed headers, message type discrimination, client-side compression).
- **Multi-tenant** - the comprehensive example of how to structure your
application to support multiple tenants (separated by the unique streams) with
the different users, permissions, topics etc.
-- **New SDK** - an introduction to the high-level SDK as discussed in the
[dedicated guide](/docs/sdk/rust/high-level-sdk).
+- **TCP TLS** - TLS-encrypted TCP connections with custom CA certificates.
+- **Sink data producer** - generating random JSON records in bulk batches for
sink connector testing.
diff --git a/src/components/benchmark-chart.tsx
b/src/components/benchmark-chart.tsx
index b55edcfe..813ec808 100644
--- a/src/components/benchmark-chart.tsx
+++ b/src/components/benchmark-chart.tsx
@@ -33,6 +33,7 @@ export function BenchmarkSection() {
const wrAvg = CY(1.01);
const wrP99 = CY(2.05);
+ const rdAvg = CY(1.19);
return (
<div ref={ref}>
@@ -120,13 +121,15 @@ export function BenchmarkSection() {
<path d={READ_PATH} fill="none" stroke="#38bdf8"
strokeWidth="1.5" strokeLinejoin="round" className="iggy-line iggy-line-rd" />
<g className="iggy-label">
- <line x1="0" y1={wrAvg} x2="600" y2={wrAvg} stroke="#ff9103"
strokeOpacity="0.25" strokeDasharray="4 3" />
- <rect x="540" y={wrAvg - 11} width="56" height="18" rx="4"
fill="#ff9103" fillOpacity="0.12" />
- <text x="568" y={wrAvg + 2} textAnchor="middle" fill="#ff9103"
fontSize="10" fontFamily="monospace" fontWeight="600">AVG</text>
-
- <line x1="0" y1={wrP99} x2="600" y2={wrP99} stroke="#ff9103"
strokeOpacity="0.15" strokeDasharray="4 3" />
- <rect x="540" y={wrP99 - 11} width="56" height="18" rx="4"
fill="#ff9103" fillOpacity="0.08" />
- <text x="568" y={wrP99 + 2} textAnchor="middle" fill="#ff9103"
fontSize="10" fontFamily="monospace" fillOpacity="0.7">P99</text>
+ <line x1="0" y1={wrAvg} x2="600" y2={wrAvg} stroke="#ff9103"
strokeOpacity="0.3" strokeDasharray="6 6" strokeWidth="1" />
+ <rect x="539" y={wrAvg - 11} width="58" height="22" rx="4"
fill="#060a12" />
+ <rect x="539" y={wrAvg - 11} width="58" height="22" rx="4"
fill="#ff9103" fillOpacity="0.15" stroke="#ff9103" strokeOpacity="0.4"
strokeWidth="0.5" />
+ <text x="568" y={wrAvg + 4} textAnchor="middle" fill="#ff9103"
fontSize="11" fontFamily="monospace" fontWeight="bold">AVG</text>
+
+ <line x1="0" y1={wrP99} x2="600" y2={wrP99} stroke="#ff9103"
strokeOpacity="0.2" strokeDasharray="6 6" strokeWidth="1" />
+ <rect x="539" y={wrP99 - 11} width="58" height="22" rx="4"
fill="#060a12" />
+ <rect x="539" y={wrP99 - 11} width="58" height="22" rx="4"
fill="#ff9103" fillOpacity="0.1" stroke="#ff9103" strokeOpacity="0.3"
strokeWidth="0.5" />
+ <text x="568" y={wrP99 + 4} textAnchor="middle" fill="#ff9103"
fontSize="11" fontFamily="monospace" fontWeight="bold">P99</text>
</g>
</svg>
</div>
diff --git a/src/components/code-tabs.tsx b/src/components/code-tabs.tsx
index 858dc37c..185df57d 100644
--- a/src/components/code-tabs.tsx
+++ b/src/components/code-tabs.tsx
@@ -22,6 +22,16 @@
import { useState } from "react";
import { highlight } from "sugar-high";
+const pkgInfo: Record<string, { install: string; url: string; label: string }>
= {
+ "Rust": { install: "cargo add iggy", url: "https://crates.io/crates/iggy",
label: "crates.io" },
+ "Python": { install: "pip install apache-iggy", url:
"https://pypi.org/project/apache-iggy/", label: "PyPI" },
+ "Java": { install: "org.apache.iggy:iggy", url:
"https://mvnrepository.com/artifact/org.apache.iggy/iggy", label: "Maven
Central" },
+ "Go": { install: "go get github.com/apache/iggy/foreign/go", url:
"https://pkg.go.dev/github.com/apache/iggy/foreign/go", label: "pkg.go.dev" },
+ "Node.js": { install: "npm install apache-iggy", url:
"https://www.npmjs.com/package/apache-iggy", label: "npm" },
+ "C#": { install: "dotnet add package Apache.Iggy", url:
"https://www.nuget.org/packages/Apache.Iggy/", label: "NuGet" },
+ "C++ (WIP)": { install: "git clone https://github.com/apache/iggy", url:
"https://github.com/apache/iggy/tree/master/foreign/cpp", label: "GitHub" },
+};
+
const snippets = [
{
lang: "Rust",
@@ -39,7 +49,7 @@ let producer = client
.direct(
DirectConfig::builder()
.batch_length(100)
- .build(),
+ .build()
)
.partitioning(Partitioning::balanced())
.build();
@@ -232,43 +242,75 @@ iggy::ffi::delete_connection(client);`,
export function LandingCodeTabs() {
const [active, setActive] = useState(0);
+ const [copied, setCopied] = useState(false);
const s = snippets[active];
+ const pkg = pkgInfo[s.lang];
return (
- <div className="rounded-2xl border border-white/[0.08] bg-[#0c1220]
overflow-hidden">
- <div className="flex items-center border-b border-white/[0.06]
overflow-x-auto">
- {snippets.map((sn, i) => (
- <button
- key={sn.lang}
- onClick={() => setActive(i)}
- className={`px-4 py-2.5 text-xs font-medium whitespace-nowrap
transition-colors ${
- i === active
- ? "text-[#ff9103] border-b-2 border-[#ff9103] bg-white/[0.03]"
- : "text-[#636b75] hover:text-[#aaafb6]"
- }`}
- >
- {sn.lang}
- </button>
- ))}
- </div>
- <div className="p-5">
- <div className="flex items-center justify-between mb-3">
- <div className="flex items-center gap-2">
- <div className="w-3 h-3 rounded-full bg-[#ff5f57]" />
- <div className="w-3 h-3 rounded-full bg-[#febc2e]" />
- <div className="w-3 h-3 rounded-full bg-[#28c840]" />
- <span className="ml-2 text-xs text-[#636b75]
font-mono">{s.file}</span>
+ <div>
+ <div className="rounded-2xl border border-white/[0.08] bg-[#0c1220]
overflow-hidden">
+ <div className="flex items-center border-b border-white/[0.06]
overflow-x-auto">
+ {snippets.map((sn, i) => (
+ <button
+ key={sn.lang}
+ onClick={() => setActive(i)}
+ className={`px-4 py-2.5 text-xs font-medium whitespace-nowrap
transition-colors ${
+ i === active
+ ? "text-[#ff9103] border-b-2 border-[#ff9103]
bg-white/[0.03]"
+ : "text-[#636b75] hover:text-[#aaafb6]"
+ }`}
+ >
+ {sn.lang}
+ </button>
+ ))}
+ </div>
+ <div className="p-5">
+ <div className="flex items-center justify-between mb-3">
+ <div className="flex items-center gap-2">
+ <div className="w-3 h-3 rounded-full bg-[#ff5f57]" />
+ <div className="w-3 h-3 rounded-full bg-[#febc2e]" />
+ <div className="w-3 h-3 rounded-full bg-[#28c840]" />
+ <span className="ml-2 text-xs text-[#636b75]
font-mono">{s.file}</span>
+ </div>
+ <a
+ href={s.href}
+ className="text-[10px] text-[#ff9103] no-underline
hover:underline"
+ >
+ SDK docs →
+ </a>
</div>
- <a
- href={s.href}
- className="text-[10px] text-[#ff9103] no-underline hover:underline"
- >
- SDK docs →
- </a>
+ <pre className="text-[13px] leading-relaxed font-mono
overflow-x-auto m-0 whitespace-pre min-h-[360px]">
+ <code dangerouslySetInnerHTML={{ __html: highlight(s.code) }} />
+ </pre>
</div>
- <pre className="text-[13px] leading-relaxed font-mono overflow-x-auto
m-0 whitespace-pre">
- <code dangerouslySetInnerHTML={{ __html: highlight(s.code) }} />
- </pre>
+ </div>
+
+ <div className="mt-3 flex items-center gap-3">
+ <button
+ onClick={() => {
+ navigator.clipboard.writeText(pkg.install);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 1500);
+ }}
+ className="group flex cursor-pointer items-center gap-2 rounded-lg
border border-white/[0.08] bg-white/[0.03] px-3.5 py-2 transition-colors
hover:border-white/[0.15]"
+ >
+ <code className="font-mono text-xs
text-[#aaafb6]">{pkg.install}</code>
+ <svg className="h-3.5 w-3.5 shrink-0 text-[#636b75]
transition-colors group-hover:text-[#aaafb6]" fill="none" viewBox="0 0 24 24"
stroke="currentColor" strokeWidth={2}>
+ {copied ? (
+ <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4
4L19 7" />
+ ) : (
+ <path strokeLinecap="round" strokeLinejoin="round" d="M8 16H6a2
2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0
00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
+ )}
+ </svg>
+ </button>
+ <a
+ href={pkg.url}
+ target="_blank"
+ rel="noopener noreferrer"
+ className="text-xs text-[#ff9103]/80 no-underline transition-colors
hover:text-[#ff9103]"
+ >
+ {pkg.label} →
+ </a>
</div>
</div>
);