Add
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { LabContent } from "~/components/labs/LabContent";
|
||||
@@ -36,4 +36,55 @@ describe("LabContent", () => {
|
||||
expect(screen.getByText("Tokenizer Playground")).toBeInTheDocument();
|
||||
expect(screen.getByText("Visualize token confidence locally")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("filters harness branches from a single Objective 2 selector", () => {
|
||||
render(
|
||||
<LabContent
|
||||
className="lab-content"
|
||||
html={[
|
||||
'<div class="lab-harness-chooser">',
|
||||
'<button type="button" class="lab-harness-card" data-harness-choice="opencode">OpenCode</button>',
|
||||
'<button type="button" class="lab-harness-card" data-harness-choice="kilocode">Kilo Code</button>',
|
||||
'<button type="button" class="lab-harness-card" data-harness-choice="droid">Factory Droid</button>',
|
||||
"</div>",
|
||||
'<section data-harness-branch="opencode"><h3>OpenCode Install</h3></section>',
|
||||
'<section data-harness-branch="kilocode"><h3>Kilo Code Install</h3></section>',
|
||||
'<section data-harness-branch="droid"><h3>Factory Droid Install</h3></section>',
|
||||
'<section data-harness-branch="opencode"><h3>OpenCode Config</h3></section>',
|
||||
'<section data-harness-branch="kilocode"><h3>Kilo Code Config</h3></section>',
|
||||
].join("")}
|
||||
/>,
|
||||
);
|
||||
|
||||
const openCodeInstall = screen.getByText("OpenCode Install").closest("section");
|
||||
const kiloCodeInstall = screen.getByText("Kilo Code Install").closest("section");
|
||||
const droidInstall = screen.getByText("Factory Droid Install").closest("section");
|
||||
const kiloCodeConfig = screen.getByText("Kilo Code Config").closest("section");
|
||||
|
||||
expect(openCodeInstall?.hidden).toBe(true);
|
||||
expect(kiloCodeInstall?.hidden).toBe(true);
|
||||
expect(droidInstall?.hidden).toBe(true);
|
||||
expect(kiloCodeConfig?.hidden).toBe(true);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Kilo Code" }));
|
||||
|
||||
expect(screen.getByRole("button", { name: "Kilo Code" })).toHaveAttribute(
|
||||
"aria-pressed",
|
||||
"true",
|
||||
);
|
||||
expect(openCodeInstall?.hidden).toBe(true);
|
||||
expect(kiloCodeInstall?.hidden).toBe(false);
|
||||
expect(droidInstall?.hidden).toBe(true);
|
||||
expect(kiloCodeConfig?.hidden).toBe(false);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Kilo Code" }));
|
||||
|
||||
expect(screen.getByRole("button", { name: "Kilo Code" })).toHaveAttribute(
|
||||
"aria-pressed",
|
||||
"false",
|
||||
);
|
||||
expect(openCodeInstall?.hidden).toBe(true);
|
||||
expect(kiloCodeInstall?.hidden).toBe(true);
|
||||
expect(droidInstall?.hidden).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -198,6 +198,64 @@ async function copyTextToClipboard(text: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function enhanceHarnessSelectors(root: HTMLElement) {
|
||||
const harnessButtons = Array.from(
|
||||
root.querySelectorAll<HTMLButtonElement>("button[data-harness-choice]"),
|
||||
);
|
||||
const harnessBranches = Array.from(
|
||||
root.querySelectorAll<HTMLElement>("[data-harness-branch]"),
|
||||
);
|
||||
|
||||
if (harnessButtons.length === 0 || harnessBranches.length === 0) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const supportedHarnesses = new Set(
|
||||
harnessButtons
|
||||
.map((button) => button.dataset.harnessChoice?.trim())
|
||||
.filter((value): value is string => Boolean(value)),
|
||||
);
|
||||
|
||||
let selectedHarness: string | null = null;
|
||||
|
||||
const syncHarnessSelection = () => {
|
||||
for (const button of harnessButtons) {
|
||||
const harnessId = button.dataset.harnessChoice?.trim() ?? "";
|
||||
const isSelected = selectedHarness !== null && harnessId === selectedHarness;
|
||||
button.setAttribute("aria-pressed", isSelected ? "true" : "false");
|
||||
button.dataset.selected = isSelected ? "true" : "false";
|
||||
}
|
||||
|
||||
for (const branch of harnessBranches) {
|
||||
const harnessId = branch.dataset.harnessBranch?.trim() ?? "";
|
||||
const shouldHide =
|
||||
selectedHarness === null || harnessId !== selectedHarness;
|
||||
branch.hidden = shouldHide;
|
||||
branch.setAttribute("aria-hidden", shouldHide ? "true" : "false");
|
||||
}
|
||||
};
|
||||
|
||||
syncHarnessSelection();
|
||||
|
||||
const handleHarnessClick = (event: Event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const button = target.closest<HTMLButtonElement>("button[data-harness-choice]");
|
||||
if (!button || !root.contains(button)) return;
|
||||
|
||||
const harnessId = button.dataset.harnessChoice?.trim() ?? "";
|
||||
if (!supportedHarnesses.has(harnessId)) return;
|
||||
|
||||
event.preventDefault();
|
||||
selectedHarness = selectedHarness === harnessId ? null : harnessId;
|
||||
syncHarnessSelection();
|
||||
};
|
||||
|
||||
root.addEventListener("click", handleHarnessClick);
|
||||
return () => {
|
||||
root.removeEventListener("click", handleHarnessClick);
|
||||
};
|
||||
}
|
||||
|
||||
export function LabContent({ className, html }: LabContentProps) {
|
||||
const containerRef = useRef<HTMLElement>(null);
|
||||
const [zoomedImage, setZoomedImage] = useState<ZoomedImageState | null>(null);
|
||||
@@ -273,6 +331,7 @@ export function LabContent({ className, html }: LabContentProps) {
|
||||
}
|
||||
|
||||
enhanceSettingsLists(root);
|
||||
const cleanupHarnessSelectors = enhanceHarnessSelectors(root);
|
||||
|
||||
const handleRootClick = (event: Event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
@@ -320,6 +379,7 @@ export function LabContent({ className, html }: LabContentProps) {
|
||||
|
||||
root.addEventListener("click", handleRootClick);
|
||||
return () => {
|
||||
cleanupHarnessSelectors();
|
||||
root.removeEventListener("click", handleRootClick);
|
||||
};
|
||||
}, [html]);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { getLabDocument, getLabSummaries } from "~/lib/labs";
|
||||
|
||||
describe("labs discovery", () => {
|
||||
it("returns the renumbered labs in order including the new Lab 5", () => {
|
||||
const labs = getLabSummaries();
|
||||
|
||||
expect(labs.map((lab) => lab.slug)).toEqual([
|
||||
"lab-1-visualization-in-transformerlab",
|
||||
"lab-2-quantization-tradeoffs",
|
||||
"lab-3-llama-cpp-and-ollama",
|
||||
"lab-4-oi-prompting",
|
||||
"lab-5-api-and-harnesses",
|
||||
"lab-6-embedding-and-chunking",
|
||||
"lab-7-dataset-generation-and-fine-tuning",
|
||||
"lab-8-evaluation-and-red-teaming",
|
||||
]);
|
||||
});
|
||||
|
||||
it("resolves the new Lab 5 document", () => {
|
||||
const lab = getLabDocument("lab-5-api-and-harnesses");
|
||||
|
||||
expect(lab).not.toBeNull();
|
||||
expect(lab?.title).toBe("Lab 5 - API & Harnesses");
|
||||
expect(lab?.fileName).toBe("lab-5-api-and-harnesses.md");
|
||||
});
|
||||
});
|
||||
@@ -417,6 +417,105 @@ ol {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-chooser {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.9rem;
|
||||
margin: 1rem 0 1.35rem;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.38rem;
|
||||
min-height: 100%;
|
||||
padding: 0.95rem 1rem;
|
||||
border: 1px solid #d9e4ed;
|
||||
border-radius: 16px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(244, 249, 253, 0.96)),
|
||||
radial-gradient(circle at top right, rgba(248, 156, 39, 0.12), transparent 32%);
|
||||
box-shadow: 0 12px 28px -28px rgba(15, 23, 42, 0.35);
|
||||
color: #18384f;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.lab-content button.lab-harness-card {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.lab-content a.lab-harness-card:hover,
|
||||
.lab-content button.lab-harness-card:hover {
|
||||
transform: translateY(-1px);
|
||||
border-color: #f1bd70;
|
||||
box-shadow: 0 20px 36px -30px rgba(15, 23, 42, 0.45);
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-card[aria-pressed="true"] {
|
||||
border-color: #cf7a08;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 251, 243, 0.98), rgba(255, 244, 227, 0.96)),
|
||||
radial-gradient(circle at top right, rgba(248, 156, 39, 0.18), transparent 32%);
|
||||
box-shadow: 0 20px 36px -30px rgba(114, 63, 8, 0.5);
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-card strong {
|
||||
color: #0f3d58;
|
||||
font-size: 1rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-card span {
|
||||
color: #486073;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-card__tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
border-radius: 999px;
|
||||
padding: 0.22rem 0.58rem;
|
||||
background: #e7f2fb;
|
||||
color: #0f5c8b;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-branch {
|
||||
margin: 1rem 0 1.4rem;
|
||||
padding: 1rem 1.1rem 1.1rem;
|
||||
border: 1px solid #dce7f0;
|
||||
border-left: 6px solid #0f5c8b;
|
||||
border-radius: 16px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(250, 252, 254, 0.98), rgba(244, 249, 252, 0.95)),
|
||||
radial-gradient(circle at top right, rgba(248, 156, 39, 0.08), transparent 26%);
|
||||
scroll-margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-branch__eyebrow {
|
||||
margin: 0 0 0.4rem;
|
||||
color: #9a5f00;
|
||||
font-size: 0.74rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-branch > h3 {
|
||||
margin: 0 0 0.45rem;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-branch > p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.lab-content hr {
|
||||
margin: 2rem 0 1.4rem;
|
||||
border-color: #d7dee6;
|
||||
@@ -1686,6 +1785,15 @@ ol {
|
||||
padding: 0.52rem 0.75rem;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-chooser {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.lab-content .lab-harness-card,
|
||||
.lab-content .lab-harness-branch {
|
||||
padding: 0.85rem 0.9rem;
|
||||
}
|
||||
|
||||
.lab-content ul.lab-settings-list .lab-setting-value {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user