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
14 changes: 5 additions & 9 deletions src/components/CircleButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ type CircleButtonProps = {
onClick?: (ev: MouseEvent) => void;
ariaLabel: string;
children: Element | JSX.Element;
className?: string;
class?: string;
href?: string;
};

Expand All @@ -13,27 +13,23 @@ export const CircleButton = ({
ariaLabel,
children,
href,
className = "",
class: customClass = "",
}: CircleButtonProps) => {
const sharedClassName = `circle-button grid place-items-center w-[40px] h-[40px] rounded-full p-xs hover:border-type-white text-black hover:!bg-bg-black hover:text-type-white ${className}`;
const sharedClass = `circle-button grid place-items-center w-[40px] h-[40px] rounded-full p-xs hover:border-type-white text-black hover:!bg-bg-black hover:text-type-white ${customClass}`;
if (href) {
return (
<a
onClick={onClick}
aria-label={ariaLabel}
href={href}
className={sharedClassName}
class={sharedClass}
>
{children}
</a>
);
}
return (
<button
onClick={onClick}
aria-label={ariaLabel}
className={sharedClassName}
>
<button onClick={onClick} aria-label={ariaLabel} class={sharedClass}>
{children}
</button>
);
Expand Down
37 changes: 24 additions & 13 deletions src/components/CodeEmbed/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect, useRef } from "preact/hooks";
import { useLiveRegion } from '../hooks/useLiveRegion';
import { useLiveRegion } from "../hooks/useLiveRegion";
import CodeMirror, { EditorView } from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { cdnLibraryUrl, cdnSoundUrl } from "@/src/globals/globals";
Expand Down Expand Up @@ -38,14 +38,19 @@ export const CodeEmbed = (props) => {
);

let { previewWidth, previewHeight } = props;
const canvasMatch = /createCanvas\(\s*(\d+),\s*(\d+)\s*(?:,\s*(?:P2D|WEBGL)\s*)?\)/m.exec(initialCode);
const canvasMatch =
/createCanvas\(\s*(\d+),\s*(\d+)\s*(?:,\s*(?:P2D|WEBGL)\s*)?\)/m.exec(
initialCode,
);
if (canvasMatch) {
previewWidth = previewWidth || parseFloat(canvasMatch[1]);
previewHeight = previewHeight || parseFloat(canvasMatch[2]);
}

// Quick hack to make room for DOM that gets added below the canvas by default
const domMatch = /create(Button|Select|P|Div|Input|ColorPicker)/.exec(initialCode);
const domMatch = /create(Button|Select|P|Div|Input|ColorPicker)/.exec(
initialCode,
);
if (domMatch && previewHeight) {
previewHeight += 100;
}
Expand Down Expand Up @@ -87,15 +92,15 @@ export const CodeEmbed = (props) => {
}
}, []);

if (!rendered) return <div className="code-placeholder" />;
if (!rendered) return <div class="code-placeholder" />;

return (
<div
className={`my-md flex w-full flex-col gap-[20px] overflow-hidden ${props.allowSideBySide ? "lg:flex-row" : ""} ${props.fullWidth ? "full-width" : ""}`}
class={`my-md flex w-full flex-col gap-[20px] overflow-hidden ${props.allowSideBySide ? "lg:flex-row" : ""} ${props.fullWidth ? "full-width" : ""}`}
>
{props.previewable ? (
<div
className={`ml-0 flex w-fit gap-[20px] ${largeSketch ? "flex-col" : (props.allowSideBySide ? "" : "flex-col lg:flex-row")}`}
class={`ml-0 flex w-fit gap-[20px] ${largeSketch ? "flex-col" : props.allowSideBySide ? "" : "flex-col lg:flex-row"}`}
>
<div>
<CodeFrame
Expand All @@ -105,19 +110,25 @@ export const CodeEmbed = (props) => {
base={props.base}
frameRef={codeFrameRef}
lazyLoad={props.lazyLoad}
scripts={props.includeSound ? [cdnLibraryUrl, cdnSoundUrl] :[cdnLibraryUrl]}
scripts={
props.includeSound
? [cdnLibraryUrl, cdnSoundUrl]
: [cdnLibraryUrl]
}
/>
</div>
<div className={`flex gap-2.5 ${largeSketch ? "flex-row" : "md:flex-row lg:flex-col"}`}>
<div
class={`flex gap-2.5 ${largeSketch ? "flex-row" : "md:flex-row lg:flex-col"}`}
>
<CircleButton
className="bg-bg-gray-40"
class="bg-bg-gray-40"
onClick={updateOrReRun}
ariaLabel="Run sketch"
>
<Icon kind="play" />
</CircleButton>
<CircleButton
className="bg-bg-gray-40"
class="bg-bg-gray-40"
onClick={() => {
setPreviewCodeString("");
announce("Sketch stopped");
Expand All @@ -129,7 +140,7 @@ export const CodeEmbed = (props) => {
</div>
</div>
) : null}
<div className="code-editor-container relative w-full">
<div class="code-editor-container relative w-full">
<CodeMirror
value={codeString}
theme="light"
Expand All @@ -155,7 +166,7 @@ export const CodeEmbed = (props) => {
(editorView.contentDOM.ariaLabel = "Code Editor")
}
/>
<div className="absolute right-0 top-0 flex flex-col gap-xs p-xs md:flex-row">
<div class="absolute right-0 top-0 flex flex-col gap-xs p-xs md:flex-row">
<CopyCodeButton textToCopy={codeString || initialCode} />
<CircleButton
onClick={() => {
Expand All @@ -164,7 +175,7 @@ export const CodeEmbed = (props) => {
announce("Code reset to initial value.");
}}
ariaLabel="Reset code to initial value"
className="bg-white text-black"
class="bg-white text-black"
>
<Icon kind="refresh" />
</CircleButton>
Expand Down
44 changes: 22 additions & 22 deletions src/components/CopyCodeButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'preact/hooks';
import { useLiveRegion } from '../hooks/useLiveRegion';
import { useState } from "preact/hooks";
import { useLiveRegion } from "../hooks/useLiveRegion";
import CircleButton from "../CircleButton";

interface CopyCodeButtonProps {
Expand All @@ -9,56 +9,56 @@ interface CopyCodeButtonProps {

export const CopyCodeButton = ({
textToCopy,
announceOnCopy = 'Code copied to clipboard'
announceOnCopy = "Code copied to clipboard",
}: CopyCodeButtonProps) => {
const [isCopied, setIsCopied] = useState(false);

const { ref: liveRegionRef, announce } = useLiveRegion<HTMLSpanElement>();

const copyTextToClipboard = async () => {
console.log('Copy button clicked');
console.log('Text to copy:', textToCopy);
console.log("Copy button clicked");
console.log("Text to copy:", textToCopy);

try {
console.log('Using Clipboard API');
console.log("Using Clipboard API");
await navigator.clipboard.writeText(textToCopy);
console.log('Text copied successfully');
console.log("Text copied successfully");

announce(announceOnCopy);

setIsCopied(true);
setTimeout(() => {
setIsCopied(false);
console.log('Copy state reset');
console.log("Copy state reset");
}, 2000);
} catch (err) {
console.error('Clipboard API copy failed:', err);
console.error("Clipboard API copy failed:", err);
}
};

return (
<>
<CircleButton
onClick={() => {
console.log('CircleButton clicked');
console.log("CircleButton clicked");
copyTextToClipboard();
}}
ariaLabel="Copy code to clipboard"
className={`bg-white ${isCopied ? 'text-green-600' : 'text-black'} transition-colors duration-200`}
class={`bg-white ${isCopied ? "text-green-600" : "text-black"} transition-colors duration-200`}
>
{isCopied ? (
<svg
width="18"
height="22"
viewBox="0 0 24 24"
fill="none"
<svg
width="18"
height="22"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M20 6L9 17L4 12"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
<path
d="M20 6L9 17L4 12"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
Expand Down Expand Up @@ -89,4 +89,4 @@ export const CopyCodeButton = ({
<span ref={liveRegionRef} aria-live="polite" class="sr-only" />
</>
);
};
};
22 changes: 9 additions & 13 deletions src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,37 +113,37 @@ export const Dropdown = ({
// Render the collapsed dropdown button
const renderCollapsedDropdown = () => (
<button
className={styles.selected}
class={styles.selected}
onClick={handleDropdownClick}
aria-haspopup="listbox"
aria-expanded={isOpen}
tabIndex={0}
>
<div className={styles.iconTop}>
<div class={styles.iconTop}>
<Icon kind={iconKind} />
</div>
<span>
{dropdownLabel ||
options.find((option) => isSelected(option))?.label ||
"Select..."}
</span>
<div className={styles.chevron}>
<div class={styles.chevron}>
<Icon kind="chevron-down" />
</div>
</button>
);

// Render the expanded dropdown options
const renderExpandedDropdown = () => (
<ul className={styles.options} role="listbox" tabIndex={-1}>
<ul class={styles.options} role="listbox" tabIndex={-1}>
{options.map((option, index) => (
<li
key={option.value}
className={styles.option}
class={styles.option}
role="option"
aria-selected={isSelected(option)}
>
<div className={styles.icon}>
<div class={styles.icon}>
<Icon
kind={
isSelected(option) ? "option-selected" : "option-unselected"
Expand All @@ -162,23 +162,19 @@ export const Dropdown = ({
</li>
))}
{variant === "radio" ? (
<button onClick={() => setIsOpen(false)} className={styles.chevron}>
<button onClick={() => setIsOpen(false)} class={styles.chevron}>
<Icon kind="chevron-up" />
</button>
) : (
<div className={styles.chevron}>
<div class={styles.chevron}>
<Icon kind="chevron-up" />
</div>
)}
</ul>
);

return (
<div
className={styles.container}
ref={dropdownRef}
onKeyDown={handleKeyDown}
>
<div class={styles.container} ref={dropdownRef} onKeyDown={handleKeyDown}>
{isOpen ? renderExpandedDropdown() : renderCollapsedDropdown()}
</div>
);
Expand Down
Loading
Loading