Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/large-chicken-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@hyperbook/markdown": minor
"hyperbook-studio": minor
"hyperbook": minor
---

Add graphical output support to pyide. For example for pygame.
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Test packages
run: pnpm test
- name: Build packages
run: pnpm build
- name: Test packages
run: pnpm test
75 changes: 75 additions & 0 deletions packages/markdown/assets/directive-p5/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,80 @@ hyperbook.p5 = (function () {
return sketchCode;
};

function setupSplitter(elem, container, editorContainer, splitter) {
if (!container || !editorContainer || !splitter) return;

const minPanelSize = 120;

const getIsHorizontal = () =>
getComputedStyle(elem).flexDirection.startsWith("row");

const applySplitSize = (rawSize, isHorizontal) => {
const total = isHorizontal ? elem.clientWidth : elem.clientHeight;
const splitterSize = isHorizontal ? splitter.offsetWidth : splitter.offsetHeight;
const maxSize = Math.max(minPanelSize, total - splitterSize - minPanelSize);
const clamped = Math.max(minPanelSize, Math.min(rawSize, maxSize));
container.style.flex = `0 0 ${clamped}px`;
return clamped;
};

const applyStoredSplitSize = () => {
const isHorizontal = getIsHorizontal();
elem.classList.toggle("split-horizontal", isHorizontal);
elem.classList.toggle("split-vertical", !isHorizontal);
const key = isHorizontal ? "splitHorizontal" : "splitVertical";
const rawStored = Number(elem.dataset[key]);
if (!Number.isFinite(rawStored) || rawStored <= 0) {
container.style.flex = "";
return;
}
applySplitSize(rawStored, isHorizontal);
};

applyStoredSplitSize();

splitter.addEventListener("pointerdown", (event) => {
event.preventDefault();
splitter.setPointerCapture(event.pointerId);

const isHorizontal = getIsHorizontal();
const key = isHorizontal ? "splitHorizontal" : "splitVertical";
const startPointer = isHorizontal ? event.clientX : event.clientY;
const startSize = isHorizontal
? container.getBoundingClientRect().width
: container.getBoundingClientRect().height;

elem.classList.add("resizing");

const onPointerMove = (moveEvent) => {
const pointer = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
const delta = pointer - startPointer;
const size = applySplitSize(startSize + delta, isHorizontal);
elem.dataset[key] = String(Math.round(size));
};

const onPointerUp = () => {
elem.classList.remove("resizing");
splitter.removeEventListener("pointermove", onPointerMove);
splitter.removeEventListener("pointerup", onPointerUp);
splitter.removeEventListener("pointercancel", onPointerUp);
};

splitter.addEventListener("pointermove", onPointerMove);
splitter.addEventListener("pointerup", onPointerUp);
splitter.addEventListener("pointercancel", onPointerUp);
});

window.addEventListener("resize", applyStoredSplitSize);
}

function initElement(elem) {
if (elem.getAttribute("data-p5-initialized") === "true") return;
elem.setAttribute("data-p5-initialized", "true");

const container = elem.querySelector(".container");
const editorContainer = elem.querySelector(".editor-container");
const splitter = elem.querySelector(".splitter");
const editor = elem.getElementsByClassName("editor")[0];
/** @type {HTMLButtonElement} */
const update = elem.getElementsByClassName("update")[0];
Expand All @@ -38,6 +111,8 @@ hyperbook.p5 = (function () {
const resetEl = elem.getElementsByClassName("reset")[0];
const downloadEl = elem.getElementsByClassName("download")[0];

setupSplitter(elem, container, editorContainer, splitter);

if (frame) {
frame.srcdoc = frame.srcdoc.replaceAll(
"###ORIGIN###",
Expand Down
39 changes: 38 additions & 1 deletion packages/markdown/assets/directive-p5/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ code-input {

.directive-p5 .container {
width: 100%;
min-height: 120px;
min-width: 120px;
border: 1px solid var(--color-spacer);
border-radius: 8px;
overflow: hidden;
Expand All @@ -22,9 +24,44 @@ code-input {
width: 100%;
display: flex;
flex-direction: column;
min-height: 120px;
min-width: 120px;
height: 400px;
}

.directive-p5 .splitter {
background: var(--color-spacer);
border-radius: 999px;
flex-shrink: 0;
touch-action: none;
opacity: 0.45;
transition: opacity 0.15s ease-in-out;
}

.directive-p5 .splitter:hover {
opacity: 0.65;
}

.directive-p5.split-vertical .splitter {
width: 100%;
height: 4px;
cursor: row-resize;
}

.directive-p5.split-horizontal .splitter {
width: 4px;
height: 100%;
cursor: col-resize;
}

.directive-p5.resizing {
user-select: none;
}

.directive-p5.resizing .splitter {
opacity: 0.75;
}

.directive-p5 .editor {
width: 100%;
border: 1px solid var(--color-spacer);
Expand Down Expand Up @@ -79,7 +116,7 @@ code-input {
@media screen and (min-width: 1024px) {
.directive-p5:not(.standalone) {
flex-direction: row;
height: calc(100dvh - 128px);
height: calc(100dvh - 80px);
.container {
flex: 1;
height: 100% !important;
Expand Down
Loading
Loading