Skip to content

Commit

Permalink
Contextual editing mode assists
Browse files Browse the repository at this point in the history
  • Loading branch information
UnsignedArduino committed Apr 24, 2024
1 parent 293cae2 commit c717bf6
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 67 deletions.
51 changes: 48 additions & 3 deletions src/components/Blog/Post/Comments.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import getElement from "@/scripts/Utils/Element";
import { ThemeContext } from "@/components/Navbar/ThemePicker";
import inContextualEditor from "@/scripts/Utils/In/ContextualEditingMode";

const REPO = "UnsignedArduino/Awesome-Arcade-Blog-Comments";

Expand All @@ -9,6 +10,9 @@ export default function Comments({
}: {
title: string;
}): React.ReactNode {
const inEditor = inContextualEditor();
const [showComments, setShowComments] = React.useState(!inEditor);

const theme = React.useContext(ThemeContext);
const [state, setState] = React.useState<
"loading" | "loaded" | "error" | null
Expand Down Expand Up @@ -39,11 +43,20 @@ export default function Comments({
}, []);

React.useEffect(() => {
const parent = getElement("comments-container");

if (!showComments) {
console.log("Comments hidden");
setState(null);
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
return;
}

console.log(`Loading comments widget for blog post ${title}`);
setState("loading");

const parent = getElement("comments-container");

const script = document.createElement("script");
script.src = "https://utteranc.es/client.js";
script.async = true;
Expand Down Expand Up @@ -78,10 +91,42 @@ export default function Comments({
parent.removeChild(parent.firstChild);
}
};
}, [title, theme]);
}, [title, theme, showComments]);

function onContextualEditingPostAssist(event: CustomEvent) {
if (event.detail === "showall") {
setShowComments(true);
} else if (event.detail === "hideall") {
setShowComments(false);
}
}

React.useEffect(() => {
window.document.documentElement.addEventListener(
"contextualeditingpostassist",
onContextualEditingPostAssist,
);

return () => {
window.document.documentElement.removeEventListener(
"contextualeditingpostassist",
onContextualEditingPostAssist,
);
};
}, []);

return (
<>
{inEditor && (
<button
className="btn btn-sm btn-primary mb-2"
onClick={() => {
setShowComments(!showComments);
}}
>
{showComments ? "Hide" : "Show"} comments
</button>
)}
<div id="comments-container" />
{(() => {
switch (state) {
Expand Down
59 changes: 59 additions & 0 deletions src/components/Blog/Post/ContextualEditingMode/PostAssist.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from "react";
import inContextualEditor from "@/scripts/Utils/In/ContextualEditingMode";

export type ContextualEditingPostAssistEvents = "showall" | "hideall";

declare global {
interface HTMLElementEventMap {
contextualeditingpostassist: CustomEvent<ContextualEditingPostAssistEvents>;
}
}

export default function ContextualEditingPostAssist(): React.ReactNode {
const inEditor = inContextualEditor();

return (
<>
{inEditor && (
<div className="alert alert-info" role="alert">
<p>
In contextual editing mode. Extra buttons are given to show or hide
processor-heavy features during editing for performance.
</p>
<span>Dispatch event:</span>
<br />
<button
className="btn btn-sm btn-primary mt-2 me-2"
onClick={() => {
window.document.documentElement.dispatchEvent(
new CustomEvent<ContextualEditingPostAssistEvents>(
"contextualeditingpostassist",
{
detail: "showall",
},
),
);
}}
>
Show all
</button>
<button
className="btn btn-sm btn-primary mt-2 me-2"
onClick={() => {
window.document.documentElement.dispatchEvent(
new CustomEvent<ContextualEditingPostAssistEvents>(
"contextualeditingpostassist",
{
detail: "hideall",
},
),
);
}}
>
Hide all
</button>
</div>
)}
</>
);
}
2 changes: 2 additions & 0 deletions src/components/Blog/Post/Post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ShortAuthorRenderer,
} from "@/components/Blog/Elements";
import Comments from "@/components/Blog/Post/Comments";
import ContextualEditingPostAssist from "@/components/Blog/Post/ContextualEditingMode/PostAssist";

export default function BlogPost({
data,
Expand All @@ -29,6 +30,7 @@ export default function BlogPost({
</p>
<p>{data.post.description}</p>
<hr />
<ContextualEditingPostAssist />
<RichTextSectionRenderer content={data.post.body} />
{data.post.title !== "TESTING" ? (
<Comments title={data.post.title} />
Expand Down
108 changes: 85 additions & 23 deletions src/components/MakeCodeArcade/Blocks/BlockRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MakeCodeArcadeBlockRendererFunctionsContext } from "@/components/MakeCo
import { MakeCodeArcadeBlockRendererResult } from "@/components/MakeCodeArcade/Blocks/renderer";
import ClickableFigure from "@/components/Figure/ClickableFigure";
import cyrb53 from "@/scripts/Utils/Hash/CYRB53";
import inContextualEditor from "@/scripts/Utils/In/ContextualEditingMode";

export default function BlockRender({
js,
Expand All @@ -14,39 +15,100 @@ export default function BlockRender({
packageId?: string;
snippetMode?: boolean;
}): React.ReactNode {
const inEditor = inContextualEditor();

const functions = React.useContext(
MakeCodeArcadeBlockRendererFunctionsContext,
);
const [svg, setSVG] =
React.useState<MakeCodeArcadeBlockRendererResult | null>(null);
const [showBlocks, setShowBlocks] = React.useState(!inEditor);
const [isRendering, setIsRendering] = React.useState(false);

React.useEffect(() => {
setShowBlocks(false);
}, []);

React.useEffect(() => {
setSVG(null);
if (!showBlocks) {
return;
}
setIsRendering(true);
functions?.renderBlocksToSVG(js, packageId, snippetMode).then((result) => {
setSVG(result);
setIsRendering(false);
});
}, [functions, js, packageId, snippetMode]);

return svg ? (
<div className="mb-2">
{/* eslint-disable-next-line @next/next/no-img-element */}
{/*<Image src={svg.uri} width={svg.width} height={svg.height} alt={js} />*/}
<ClickableFigure
id={`0x${cyrb53(svg.uri).toString(16)}`}
src={svg.uri}
width={svg.width}
height={svg.height}
alt={`Block for ${js}`}
caption={
<>
Block for <code>{js}</code>
</>
}
/>
</div>
) : (
<ThemedSyntaxHighlighter language="js">
{"// Please wait, the block image is loading...\n" + js}
</ThemedSyntaxHighlighter>
}, [showBlocks, functions, js, packageId, snippetMode]);

function onContextualEditingPostAssist(event: CustomEvent) {
if (event.detail === "showall") {
setShowBlocks(true);
} else if (event.detail === "hideall") {
setShowBlocks(false);
}
}

React.useEffect(() => {
window.document.documentElement.addEventListener(
"contextualeditingpostassist",
onContextualEditingPostAssist,
);

return () => {
window.document.documentElement.removeEventListener(
"contextualeditingpostassist",
onContextualEditingPostAssist,
);
};
}, []);

return (
<>
{svg ? (
<div className="mb-2">
{/* eslint-disable-next-line @next/next/no-img-element */}
{/*<Image src={svg.uri} width={svg.width} height={svg.height} alt={js} />*/}
<ClickableFigure
id={`0x${cyrb53(svg.uri).toString(16)}`}
src={svg.uri}
width={svg.width}
height={svg.height}
alt={`Block for ${js}`}
caption={
<>
Block for <code>{js}</code>
</>
}
/>
</div>
) : (
<div className="mb-3">
<ThemedSyntaxHighlighter
language="js"
style={{ marginBottom: "0px" }}
>
{(isRendering
? "// Please wait, the blocks are loading...\n"
: inEditor && "// Click button below to show blocks\n") + js}
</ThemedSyntaxHighlighter>
</div>
)}
{inEditor && (
<button
className="btn btn-sm btn-primary mt-0 mb-2"
disabled={isRendering}
onClick={() => {
setShowBlocks(!showBlocks);
}}
>
{isRendering
? "Loading..."
: showBlocks
? "Hide blocks"
: "Show blocks"}
</button>
)}
</>
);
}
90 changes: 70 additions & 20 deletions src/components/MakeCodeArcade/Embed/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,82 @@
// noinspection XmlDeprecatedElement

import React from "react";
import inContextualEditor from "@/scripts/Utils/In/ContextualEditingMode";

export default function MakeCodeArcadeProjectEditor({
id,
}: {
id: string;
}): React.ReactNode {
const inEditor = inContextualEditor();

const [showEditor, setShowEditor] = React.useState(!inEditor);

function onContextualEditingPostAssist(event: CustomEvent) {
if (event.detail === "showall") {
setShowEditor(true);
} else if (event.detail === "hideall") {
setShowEditor(false);
}
}

React.useEffect(() => {
window.document.documentElement.addEventListener(
"contextualeditingpostassist",
onContextualEditingPostAssist,
);

return () => {
window.document.documentElement.removeEventListener(
"contextualeditingpostassist",
onContextualEditingPostAssist,
);
};
}, []);

return (
<div
className="mb-2"
style={{
position: "relative",
height: 0,
paddingBottom: "50vh",
overflow: "hidden",
}}
>
<iframe
<>
{inEditor && (
<>
<button
className="btn btn-sm btn-primary mb-2"
onClick={() => {
setShowEditor(!showEditor);
}}
>
{showEditor ? "Hide" : "Show"} editor
</button>
{!showEditor && (
<p>
<i>The blank space below is reserved for the editor.</i>
</p>
)}
</>
)}
<div
className="mb-2"
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "50vh",
position: "relative",
height: 0,
paddingBottom: "50vh",
overflow: "hidden",
}}
src={`https://arcade.makecode.com/#pub:${id}`}
frameBorder="0"
sandbox="allow-popups allow-forms allow-scripts allow-same-origin"
></iframe>
</div>
>
{showEditor && (
<iframe
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "50vh",
}}
src={`https://arcade.makecode.com/#pub:${id}`}
frameBorder="0"
sandbox="allow-popups allow-forms allow-scripts allow-same-origin"
/>
)}
</div>
</>
);
}
Loading

0 comments on commit c717bf6

Please sign in to comment.