Skip to content

Commit 76dae04

Browse files
committed
Combine static examples approach with client Svelte component for handling example selection. To keep toggling logic inside OperationExample.astro component and do not spread it between components, for tethering it with controls Svelte component it uses event emitter, which is context specific for the OperationExamples component
1 parent 2c98eac commit 76dae04

File tree

10 files changed

+119
-185
lines changed

10 files changed

+119
-185
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"@tailwindcss/vite": "^4.0.3",
3434
"@vercel/analytics": "^1.4.1",
3535
"astro": "^5.2.5",
36+
"nanoevents": "^9.1.0",
3637
"sharp": "^0.33.5",
3738
"shiki": "^2.3.0",
3839
"starlight-openapi": "^0.12.0",

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/OpenAPI/operation/Operation.astro

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import Parameters from "../parameter/Parameters.astro";
99
import RequestBody from "../RequestBody.astro";
1010
import Responses from "../response/Responses.astro";
1111
import Security from "../security/Security.astro";
12-
// import OperationExampleSvelte from "./OperationExample.svelte";
13-
import OperationExamples from "./OperationExamples.astro";
12+
import OperationExamples from "./OperationExamples/OperationExamples.astro";
1413
import OperationDescription from "./OperationDescription.astro";
1514
import { ensureNonNullable } from "~/lib/ensureNonNullable";
1615
@@ -25,12 +24,6 @@ const { operation } = pathItemOperation;
2524
---
2625

2726
<Deprecated deprecated={operation.deprecated} />
28-
<!-- <OperationExampleSvelte
29-
client:load
30-
baseUrl="https://api.mainnet.aptoslabs.com"
31-
prefix={document.servers?.[0]?.url ?? ""}
32-
operationPath={pathItemOperation.path}
33-
/> -->
3427
<OperationExamples
3528
baseUrl="https://api.mainnet.aptoslabs.com"
3629
prefix={document.servers?.[0]?.url ?? ""}

src/components/OpenAPI/operation/OperationExample.svelte

Lines changed: 0 additions & 59 deletions
This file was deleted.

src/components/OpenAPI/operation/OperationExamples.astro

Lines changed: 0 additions & 115 deletions
This file was deleted.

src/components/OpenAPI/operation/OperationExample.astro renamed to src/components/OpenAPI/operation/OperationExamples/OperationExample.astro

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,37 @@ const codeLang = (() => {
3737
---
3838

3939
<div
40-
class="operation-example"
40+
data-operation-example
4141
data-active={isActive}
4242
data-target={target}
4343
data-client={client}
44+
aria-hidden={isActive}
4445
data-theme="github-dark-default"
4546
>
4647
<Code code={snippet} lang={codeLang} frame="none" />
4748
</div>
4849

4950
<style>
50-
.operation-example:not([data-active="true"]) {
51+
[data-operation-example]:not([data-active="true"]) {
5152
display: none;
5253
}
5354

54-
.operation-example :global(.expressive-code .frame pre) {
55+
[data-operation-example] :global(.expressive-code .frame pre) {
5556
background: var(--code-background);
5657
}
5758
</style>
59+
<script>
60+
import type { ClientId, TargetId } from "@scalar/snippetz";
61+
import { emitter } from "./events";
62+
63+
emitter.on("activateExample", activateExample);
64+
65+
function activateExample<T extends TargetId>(target: T, client: ClientId<T>) {
66+
document.querySelectorAll<HTMLDivElement>(`[data-operation-example]`).forEach((el) => {
67+
const isActive = el.dataset.target === target && el.dataset.client === client;
68+
69+
el.setAttribute("data-active", isActive ? "true" : "false");
70+
el.setAttribute("aria-hidden", isActive ? "false" : "true");
71+
});
72+
}
73+
</script>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
import { snippetz } from "@scalar/snippetz";
3+
import OperationExample, { type ExampleData } from "./OperationExample.astro";
4+
import OperationExamplesControls from "./OperationExamplesControls.svelte";
5+
import { INITIAL_TARGET, INITIAL_CLIENT } from "./constants";
6+
7+
type Props = ExampleData;
8+
9+
const example: Props = Astro.props;
10+
const targets = snippetz().clients();
11+
---
12+
13+
<div class="operation-examples not-content">
14+
<OperationExamplesControls
15+
client:load
16+
targets={targets}
17+
initialTarget={INITIAL_TARGET}
18+
initialClient={INITIAL_CLIENT}
19+
>
20+
{
21+
targets.flatMap((target) =>
22+
target.clients.map((client) => (
23+
<OperationExample
24+
example={example}
25+
target={target.key}
26+
client={client.client}
27+
isActive={target.key === INITIAL_TARGET && client.client === INITIAL_CLIENT}
28+
/>
29+
)),
30+
)
31+
}
32+
</OperationExamplesControls>
33+
</div>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<script lang="ts">
2+
import type { ClientId, Target, TargetId } from '@scalar/snippetz';
3+
import type { Snippet } from 'svelte';
4+
import { ensureNonNullable } from '~/lib/ensureNonNullable';
5+
import { emitter} from './events'
6+
7+
interface Props<T extends TargetId> {
8+
targets: Target[]
9+
initialTarget: T,
10+
initialClient: ClientId<T>,
11+
children: Snippet
12+
}
13+
14+
let { targets, initialTarget, initialClient, children }: Props<TargetId> = $props();
15+
let selectedTargetName = $state(initialTarget);
16+
let selectedClientName = $state(initialClient);
17+
let target = $derived(ensureNonNullable(targets.find((item) => item.key === selectedTargetName), "Target not found"));
18+
19+
$effect(() => {
20+
const updatedTarget = targets.find((item) => item.key === selectedTargetName);
21+
22+
if (updatedTarget) {
23+
selectedClientName = updatedTarget.default;
24+
}
25+
})
26+
27+
$effect(() => {
28+
emitter.emit("activateExample", selectedTargetName, selectedClientName);
29+
})
30+
</script>
31+
<div class:list={["flex items-center gap-2"]}>
32+
<select class={["border rounded"]} bind:value={selectedTargetName}>
33+
{#each targets as target}
34+
<option value={target.key} selected={target.key === selectedTargetName}>{target.title}</option>
35+
{/each}
36+
</select>
37+
<select class={["border rounded"]} bind:value={selectedClientName}>
38+
{#each target.clients as client}
39+
<option value={client.client} selected={client.client === selectedClientName}>{client.title}</option>
40+
{/each}
41+
</select>
42+
</div>
43+
<div>{@render children()}</div>
44+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import type { ClientId } from "@scalar/snippetz";
2+
3+
export const INITIAL_TARGET = "shell";
4+
export const INITIAL_CLIENT: ClientId<typeof INITIAL_TARGET> = "curl";
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { ClientId, TargetId } from "@scalar/snippetz";
2+
import { createNanoEvents } from "nanoevents";
3+
4+
interface ExamplesEvents {
5+
activateExample: <T extends TargetId>(target: T, client: ClientId<T>) => void;
6+
}
7+
8+
export const emitter = createNanoEvents<ExamplesEvents>();

0 commit comments

Comments
 (0)