Skip to content

Add open with processing to examples #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions scripts/updateExamples.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const updateExamples = async () => {
cwd: path.join(from, example.dirname)
});


for (let i = 0; i < pdes.length; i++) {
const pde = pdes[i];
fs.copySync(
Expand All @@ -91,6 +92,10 @@ const updateExamples = async () => {

for (let i = 0; i < dataFiles.length; i++) {
const dataFile = dataFiles[i];
fs.copySync(
path.join(from, example.dirname, dataFile),
path.join(to, example.dirname, dataFile)
)
fs.copySync(
path.join(from, example.dirname, dataFile),
path.join(
Expand Down
2 changes: 0 additions & 2 deletions src/components/CopyButton.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
.root {
position: absolute;
right: var(--gutter);
height: 32px;
padding: 6px 12px;
font-size: var(--text-small);
Expand Down
63 changes: 63 additions & 0 deletions src/components/OpenWithButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';

import ProcessingIcon from '../images/logo-processing.svg';

import * as css from './OpenWithButton.module.css';

const OpenWithButton = ({ pdes, dataFiles }) => {
const main = pdes[0]
const [sketchURL, setSketchURL] = useState(`processing://open?sketch=${stringToBase64(main.code)}`)

useEffect(() => {
let sketchURL = `pde://sketch/base64/${stringToBase64(main.code)}?pde=`
for (let pde of pdes) {
if (pde === main) continue
sketchURL += `${pde.name}:${stringToBase64(pde.code)},`
}
if (dataFiles.length > 0) {
let data = '&data=' + dataFiles.map(file => file.relativePath.split('/').pop() + ":" + window.location.protocol + "//" + window.location.host + file.publicURL).join(',')
sketchURL += data
}
setSketchURL(sketchURL)
}, [])
const [showInstructions, setShowInstructions] = useState(false)

useEffect(() => {
const handleClickOutside = (event) => {
if (showInstructions && !event.target.closest(`.${css.root}`)) {
setShowInstructions(false);
}
};

document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, [showInstructions]);

return (
<a
href={sketchURL}
type="button"
className={classnames(css.root)}
onClick={() => setShowInstructions(true)}
>
<ProcessingIcon /> {'Open In Processing'}
{showInstructions && (
<div className={classnames(css.instructions)}>
<h1>Opening Processing<span className={css.ellipsis}></span></h1>
<p>If nothing happens, <a href="https://www.processing.org/download/" target="_black">Download Processing</a> version 4.4.1 or later and try again.</p>
<p className={classnames(css.tooltipFootnote)}>Make sure Processing is installed and was opened at least once.</p>
</div>
)}
</a>
)
}

export default OpenWithButton;

function stringToBase64(str) {
if (typeof Buffer !== 'undefined') {
return Buffer.from(str).toString('base64');
}
return btoa(str)
}
94 changes: 94 additions & 0 deletions src/components/OpenWithButton.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
.root {
height: 32px;
padding: 6px 12px;
font-size: var(--text-small);
font-weight: bold;
color: var(--darkgray);
cursor: pointer;
fill: var(--darkgray);
position: relative;

& svg {
height: 12px;
width: auto;
}
}

.root:hover {
color: var(--darkergray);
fill: var(--darkergray);
}

.root:active {
color: var(--processing-blue-mid);
fill: var(--processing-blue-mid);
}

.instructions {
bottom: 100%;
margin-bottom: 16px;
left: auto;
right: 0;
position: absolute;
transform: none;
min-width: 24em;
max-width: 24em;
width: fit-content;
background-color: #555;
color: #fff;
text-align: left;
border-radius: 6px;
padding: 16px 10px 10px 25px;
transition: opacity 0.3s;
pointer-events: auto;
a {
color: var(--processing-blue-light);
text-decoration: underline;
&:hover {
color: white;
}
}
h1 {
color: #fff;
font-size: 2em;
margin: 0 0 0.3em 0;
font-weight: 500;
}
&::before {
content: "";
position: absolute;
top: 100%;
left: auto;
right: 20px;
margin-left: -10px;
border-width: 10px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
}

.tooltipFootnote {
color: var(--gray);
font-size: 0.9em;
}

@keyframes ellipsis {
10% {
content: " ";
}
25% {
content: " . ";
}
50% {
content: " .. ";
}
75% {
content: " ...";
}
}

.ellipsis::after {
display: inline-block;
animation: ellipsis 1.5s infinite;
content: " ...";
}
8 changes: 6 additions & 2 deletions src/components/Tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import classnames from 'classnames';

import Button from './Button';
import CopyButton from './CopyButton';
import OpenWithButton from './OpenWithButton';

import { useHighlight } from '../hooks';
import { escapeHtml } from '../utils';

import * as css from './Tabs.module.css';

const Tabs = ({ pdes, className }) => {
const Tabs = ({ pdes, className, dataFiles }) => {
const [active, setActive] = useState(pdes[0].name);

useHighlight();
Expand Down Expand Up @@ -40,7 +41,10 @@ const Tabs = ({ pdes, className }) => {
[css.activeCode]: pde.name === active
})}
key={key}>
<CopyButton text={pde.code} />
<div className={css.actions}>
<CopyButton text={pde.code} />
<OpenWithButton pdes={pdes} dataFiles={dataFiles} />
</div>
<pre className={css.codeBlock}>
<code
dangerouslySetInnerHTML={{
Expand Down
5 changes: 5 additions & 0 deletions src/components/Tabs.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@
padding-bottom: var(--gutter-double);
white-space: break-spaces;
}

.actions{
position: absolute;
right: var(--gutter);
}
23 changes: 23 additions & 0 deletions src/hooks/examples/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useStaticQuery, graphql } from "gatsby"

export const useExampleDataFiles = (sketchName) => {
const data = useStaticQuery(
graphql`
query GetExampleDataFiles {
allFile(
filter: {sourceInstanceName: {eq: "examples"}, name: {}, relativePath: {regex: "/data/"}}
) {
edges {
node {
relativePath
publicURL
}
}
}
}`
)
return data.allFile.edges
.map((edge) => edge.node)
.filter(node => node.relativePath.includes(sketchName))
;
}
5 changes: 4 additions & 1 deletion src/templates/examples/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import {
useRelatedExamples,
useTrail
} from '../../hooks/examples';
import { useExampleDataFiles } from '../../hooks/examples/data';

import * as css from '../../styles/templates/examples/example.module.css';
import * as grid from '../../styles/grid.module.css';


const ExampleTemplate = ({ data, pageContext }) => {
const [showSidebar, setShowSidebar] = useSidebar('examples');
const intl = useIntl();
Expand All @@ -35,6 +37,7 @@ const ExampleTemplate = ({ data, pageContext }) => {
const { image, allExamples, relatedImages, liveSketch } = data;

const example = usePreparedExample(data.example);
const dataFiles = useExampleDataFiles(name)
const pdes = usePdes(data.pdes.nodes, locale, name);
const examples = usePreparedExamples(allExamples.nodes, relatedImages.nodes);
const tree = useTree(examples);
Expand Down Expand Up @@ -117,7 +120,7 @@ const ExampleTemplate = ({ data, pageContext }) => {
/>
)}
</div>
<Tabs pdes={pdes} />
<Tabs pdes={pdes} dataFiles={dataFiles} />
<RelatedExamples
examples={relatedExamples}
heading={intl.formatMessage({ id: 'relatedExamples' })}
Expand Down