Publish Sophon Realtime calling tool protocol and latency guide
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import { builds, callModes, makeRecipe, toolSteps } from "./model.js";
|
||||
|
||||
const buildSelect = document.getElementById("build-select");
|
||||
const modeSelect = document.getElementById("mode-select");
|
||||
let currentBuild = "flash";
|
||||
let currentStep = 0;
|
||||
let currentPart = "startup";
|
||||
|
||||
function renderBuild() {
|
||||
const selected = builds[currentBuild];
|
||||
const flow = document.getElementById("build-flow");
|
||||
flow.replaceChildren();
|
||||
selected.flow.forEach((label, index) => {
|
||||
if (index) {
|
||||
const arrow = document.createElement("b");
|
||||
arrow.textContent = "→";
|
||||
arrow.setAttribute("aria-hidden", "true");
|
||||
flow.append(arrow);
|
||||
}
|
||||
const node = document.createElement("span");
|
||||
node.textContent = label;
|
||||
flow.append(node);
|
||||
});
|
||||
document.getElementById("build-detail").textContent = selected.detail;
|
||||
document.querySelectorAll("[data-build]").forEach((button) => {
|
||||
button.setAttribute(
|
||||
"aria-pressed",
|
||||
String(button.dataset.build === currentBuild),
|
||||
);
|
||||
});
|
||||
buildSelect.value = currentBuild;
|
||||
const previousMode = modeSelect.value;
|
||||
modeSelect.replaceChildren();
|
||||
for (const key of selected.modes) {
|
||||
const option = document.createElement("option");
|
||||
option.value = key;
|
||||
option.textContent = callModes[key].title;
|
||||
modeSelect.append(option);
|
||||
}
|
||||
modeSelect.value = selected.modes.includes(previousMode)
|
||||
? previousMode
|
||||
: selected.modes[0];
|
||||
renderRecipe();
|
||||
}
|
||||
|
||||
function renderRecipe() {
|
||||
const mode = callModes[modeSelect.value];
|
||||
document.getElementById("endpoint-kind").textContent = mode.kind;
|
||||
document.getElementById("endpoint-value").textContent = mode.endpoint;
|
||||
document.getElementById("endpoint-detail").textContent = mode.detail;
|
||||
document.getElementById("recipe-label").textContent =
|
||||
`${builds[currentBuild].title} · ${mode.title}`;
|
||||
document.getElementById("call-recipe").textContent = makeRecipe(
|
||||
currentBuild,
|
||||
modeSelect.value,
|
||||
)[currentPart];
|
||||
document.querySelectorAll("[data-part]").forEach((button) => {
|
||||
button.setAttribute(
|
||||
"aria-pressed",
|
||||
String(button.dataset.part === currentPart),
|
||||
);
|
||||
});
|
||||
document.getElementById("copy-status").textContent = "";
|
||||
}
|
||||
|
||||
function renderStep() {
|
||||
const selected = toolSteps[currentStep];
|
||||
document.getElementById("step-number").textContent = String(
|
||||
currentStep + 1,
|
||||
).padStart(2, "0");
|
||||
document.getElementById("step-title").textContent = selected.title;
|
||||
document.getElementById("step-explanation").textContent =
|
||||
selected.explanation;
|
||||
document.getElementById("step-code").textContent = selected.code;
|
||||
document.getElementById("step-progress").textContent =
|
||||
`${currentStep + 1} / ${toolSteps.length}`;
|
||||
document.getElementById("previous-step").disabled = currentStep === 0;
|
||||
document.getElementById("next-step").disabled =
|
||||
currentStep === toolSteps.length - 1;
|
||||
document.querySelectorAll("[data-step]").forEach((button) => {
|
||||
button.setAttribute(
|
||||
"aria-pressed",
|
||||
String(Number(button.dataset.step) === currentStep),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const stepList = document.getElementById("tool-steps");
|
||||
toolSteps.forEach((step, index) => {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.dataset.step = String(index);
|
||||
button.textContent = `${index + 1} ${step.title}`;
|
||||
button.addEventListener("click", () => {
|
||||
currentStep = index;
|
||||
renderStep();
|
||||
});
|
||||
stepList.append(button);
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-build]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
currentBuild = button.dataset.build;
|
||||
renderBuild();
|
||||
});
|
||||
});
|
||||
buildSelect.addEventListener("change", () => {
|
||||
currentBuild = buildSelect.value;
|
||||
renderBuild();
|
||||
});
|
||||
modeSelect.addEventListener("change", renderRecipe);
|
||||
document.querySelectorAll("[data-part]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
currentPart = button.dataset.part;
|
||||
renderRecipe();
|
||||
});
|
||||
});
|
||||
document.getElementById("previous-step").addEventListener("click", () => {
|
||||
currentStep -= 1;
|
||||
renderStep();
|
||||
});
|
||||
document.getElementById("next-step").addEventListener("click", () => {
|
||||
currentStep += 1;
|
||||
renderStep();
|
||||
});
|
||||
document.getElementById("copy-recipe").addEventListener("click", async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(
|
||||
document.getElementById("call-recipe").textContent,
|
||||
);
|
||||
document.getElementById("copy-status").textContent = "已复制调用示例。";
|
||||
} catch {
|
||||
document.getElementById("copy-status").textContent =
|
||||
"可以在上方代码中手动选择并复制。";
|
||||
}
|
||||
});
|
||||
|
||||
const themeButton = document.getElementById("theme-toggle");
|
||||
themeButton.addEventListener("click", () => {
|
||||
const theme =
|
||||
document.documentElement.dataset.theme === "dark" ? "light" : "dark";
|
||||
document.documentElement.dataset.theme = theme;
|
||||
themeButton.setAttribute(
|
||||
"aria-label",
|
||||
theme === "dark" ? "切换浅色主题" : "切换深色主题",
|
||||
);
|
||||
});
|
||||
|
||||
renderBuild();
|
||||
renderStep();
|
||||
Reference in New Issue
Block a user